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.jet.codegen.JvmCodegenUtil;
020 import org.jetbrains.org.objectweb.asm.Type;
021 import org.jetbrains.jet.codegen.ExpressionCodegen;
022 import org.jetbrains.jet.codegen.StackValue;
023 import org.jetbrains.jet.codegen.binding.MutableClosure;
024 import org.jetbrains.jet.codegen.state.GenerationState;
025 import org.jetbrains.jet.lang.descriptors.*;
026 import org.jetbrains.jet.lang.resolve.BindingContext;
027 import org.jetbrains.jet.lang.resolve.java.JvmAbi;
028 import org.jetbrains.jet.lang.types.JetType;
029
030 import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_RECEIVER_FIELD;
031 import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
032
033 public interface LocalLookup {
034 boolean lookupLocal(DeclarationDescriptor descriptor);
035
036 enum LocalLookupCase {
037 VAR {
038 @Override
039 public boolean isCase(DeclarationDescriptor d) {
040 return d instanceof VariableDescriptor && !(d instanceof PropertyDescriptor);
041 }
042
043 @Override
044 public StackValue innerValue(
045 DeclarationDescriptor d,
046 LocalLookup localLookup,
047 GenerationState state,
048 MutableClosure closure,
049 Type classType
050 ) {
051 VariableDescriptor vd = (VariableDescriptor) d;
052
053 boolean idx = localLookup != null && localLookup.lookupLocal(vd);
054 if (!idx) return null;
055
056 Type sharedVarType = state.getTypeMapper().getSharedVarType(vd);
057 Type localType = state.getTypeMapper().mapType(vd);
058 Type type = sharedVarType != null ? sharedVarType : localType;
059
060 String fieldName = "$" + vd.getName();
061 StackValue innerValue = sharedVarType != null
062 ? StackValue.fieldForSharedVar(localType, classType, fieldName)
063 : StackValue.field(type, classType, fieldName, false);
064
065 closure.recordField(fieldName, type);
066 closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, type));
067
068 return innerValue;
069 }
070 },
071
072 LOCAL_NAMED_FUNCTION {
073 @Override
074 public boolean isCase(DeclarationDescriptor d) {
075 return isLocalNamedFun(d);
076 }
077
078 @Override
079 public StackValue innerValue(
080 DeclarationDescriptor d,
081 LocalLookup localLookup,
082 GenerationState state,
083 MutableClosure closure,
084 Type classType
085 ) {
086 FunctionDescriptor vd = (FunctionDescriptor) d;
087
088 boolean idx = localLookup != null && localLookup.lookupLocal(vd);
089 if (!idx) return null;
090
091 BindingContext bindingContext = state.getBindingContext();
092 Type localType = asmTypeForAnonymousClass(bindingContext, vd);
093
094 MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_FUNCTION, vd));
095 if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
096 // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
097 // (instead of passing this instance to the constructor and storing as a field)
098 return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true);
099 }
100
101 String fieldName = "$" + vd.getName();
102 StackValue innerValue = StackValue.field(localType, classType, fieldName, false);
103
104 closure.recordField(fieldName, localType);
105 closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
106
107 return innerValue;
108 }
109 },
110
111 RECEIVER {
112 @Override
113 public boolean isCase(DeclarationDescriptor d) {
114 return d instanceof CallableDescriptor;
115 }
116
117 @Override
118 public StackValue innerValue(
119 DeclarationDescriptor d,
120 LocalLookup enclosingLocalLookup,
121 GenerationState state,
122 MutableClosure closure,
123 Type classType
124 ) {
125 if (closure.getEnclosingReceiverDescriptor() != d) return null;
126
127 JetType receiverType = ((CallableDescriptor) d).getReceiverParameter().getType();
128 Type type = state.getTypeMapper().mapType(receiverType);
129 StackValue innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false);
130 closure.setCaptureReceiver();
131
132 return innerValue;
133 }
134
135 @Override
136 public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
137 CallableDescriptor descriptor = (CallableDescriptor) d.getDescriptor();
138 return StackValue.local(descriptor.getExpectedThisObject() != null ? 1 : 0, d.getType());
139 }
140 };
141
142 public abstract boolean isCase(DeclarationDescriptor d);
143
144 public abstract StackValue innerValue(
145 DeclarationDescriptor d,
146 LocalLookup localLookup,
147 GenerationState state,
148 MutableClosure closure,
149 Type classType
150 );
151
152 public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
153 int idx = expressionCodegen.lookupLocalIndex(d.getDescriptor());
154 assert idx != -1;
155
156 return StackValue.local(idx, d.getType());
157 }
158 }
159 }