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