001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.codegen.context;
018
019 import org.jetbrains.asm4.Type;
020 import org.jetbrains.jet.codegen.ExpressionCodegen;
021 import org.jetbrains.jet.codegen.StackValue;
022 import org.jetbrains.jet.codegen.binding.MutableClosure;
023 import org.jetbrains.jet.codegen.state.GenerationState;
024 import org.jetbrains.jet.lang.descriptors.*;
025 import org.jetbrains.jet.lang.resolve.java.JvmClassName;
026 import org.jetbrains.jet.lang.types.JetType;
027
028 import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_RECEIVER_FIELD;
029 import static org.jetbrains.jet.codegen.binding.CodegenBinding.classNameForAnonymousClass;
030 import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
031
032 public interface LocalLookup {
033 boolean lookupLocal(DeclarationDescriptor descriptor);
034
035 enum LocalLookupCase {
036 VAR {
037 @Override
038 public boolean isCase(DeclarationDescriptor d, GenerationState state) {
039 return (d instanceof VariableDescriptor) && !(d instanceof PropertyDescriptor);
040 }
041
042 @Override
043 public StackValue innerValue(
044 DeclarationDescriptor d,
045 LocalLookup localLookup,
046 GenerationState state,
047 MutableClosure closure, JvmClassName className
048 ) {
049 VariableDescriptor vd = (VariableDescriptor) d;
050
051 boolean idx = localLookup != null && localLookup.lookupLocal(vd);
052 if (!idx) return null;
053
054 Type sharedVarType = state.getTypeMapper().getSharedVarType(vd);
055 Type localType = state.getTypeMapper().mapType(vd);
056 Type type = sharedVarType != null ? sharedVarType : localType;
057
058 String fieldName = "$" + vd.getName();
059 StackValue innerValue = sharedVarType != null
060 ? StackValue.fieldForSharedVar(localType, className, fieldName)
061 : StackValue.field(type, className, fieldName, false);
062
063 closure.recordField(fieldName, type);
064 closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, type));
065
066 return innerValue;
067 }
068 },
069
070 LOCAL_NAMED_FUNCTION {
071 @Override
072 public boolean isCase(DeclarationDescriptor d, GenerationState state) {
073 return isLocalNamedFun(d);
074 }
075
076 @Override
077 public StackValue innerValue(
078 DeclarationDescriptor d,
079 LocalLookup localLookup,
080 GenerationState state,
081 MutableClosure closure,
082 JvmClassName className
083 ) {
084 FunctionDescriptor vd = (FunctionDescriptor) d;
085
086 boolean idx = localLookup != null && localLookup.lookupLocal(vd);
087 if (!idx) return null;
088
089 Type localType = classNameForAnonymousClass(state.getBindingContext(), vd).getAsmType();
090
091 String fieldName = "$" + vd.getName();
092 StackValue innerValue = StackValue.field(localType, className, fieldName, false);
093
094 closure.recordField(fieldName, localType);
095 closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, localType));
096
097 return innerValue;
098 }
099 },
100
101 RECEIVER {
102 @Override
103 public boolean isCase(DeclarationDescriptor d, GenerationState state) {
104 return d instanceof CallableDescriptor;
105 }
106
107 @Override
108 public StackValue innerValue(
109 DeclarationDescriptor d,
110 LocalLookup enclosingLocalLookup,
111 GenerationState state,
112 MutableClosure closure, JvmClassName className
113 ) {
114 if (closure.getEnclosingReceiverDescriptor() != d) return null;
115
116 JetType receiverType = ((CallableDescriptor) d).getReceiverParameter().getType();
117 Type type = state.getTypeMapper().mapType(receiverType);
118 StackValue innerValue = StackValue.field(type, className, CAPTURED_RECEIVER_FIELD, false);
119 closure.setCaptureReceiver();
120
121 return innerValue;
122 }
123
124 @Override
125 public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
126 CallableDescriptor descriptor = (CallableDescriptor) d.getDescriptor();
127 return StackValue.local(descriptor.getExpectedThisObject() != null ? 1 : 0, d.getType());
128 }
129 };
130
131 public abstract boolean isCase(DeclarationDescriptor d, GenerationState state);
132
133 public abstract StackValue innerValue(
134 DeclarationDescriptor d,
135 LocalLookup localLookup,
136 GenerationState state,
137 MutableClosure closure,
138 JvmClassName className
139 );
140
141 public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
142 int idx = expressionCodegen.lookupLocalIndex(d.getDescriptor());
143 assert idx != -1;
144
145 return StackValue.local(idx, d.getType());
146 }
147 }
148 }