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.KotlinType;
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.types.expressions.ExpressionTypingUtils.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 VariableDescriptor delegateVariableDescriptor = state.getBindingContext().get(LOCAL_VARIABLE_DELEGATE, vd);
059 Type sharedVarType = state.getTypeMapper().getSharedVarType(vd);
060 Type localType = state.getTypeMapper().mapType(delegateVariableDescriptor != null ? delegateVariableDescriptor : vd);
061 Type type = sharedVarType != null ? sharedVarType : localType;
062
063 String fieldName = "$" + vd.getName();
064 StackValue.Local thiz = StackValue.LOCAL_0;
065
066 StackValue.StackValueWithSimpleReceiver innerValue;
067 EnclosedValueDescriptor enclosedValueDescriptor;
068 if (sharedVarType != null) {
069 StackValue.Field wrapperValue = StackValue.receiverWithRefWrapper(localType, classType, fieldName, thiz, vd);
070 innerValue = StackValue.fieldForSharedVar(localType, classType, fieldName, wrapperValue);
071 enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, wrapperValue, type);
072 }
073 else {
074 innerValue = StackValue.field(type, classType, fieldName, false, thiz, vd);
075 enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type);
076 }
077
078 closure.recordField(fieldName, type);
079 closure.captureVariable(enclosedValueDescriptor);
080
081 return innerValue;
082 }
083 },
084
085 LOCAL_NAMED_FUNCTION {
086 @Override
087 public boolean isCase(DeclarationDescriptor d) {
088 return isLocalFunction(d);
089 }
090
091 @Override
092 public StackValue.StackValueWithSimpleReceiver innerValue(
093 DeclarationDescriptor d,
094 LocalLookup localLookup,
095 GenerationState state,
096 MutableClosure closure,
097 Type classType
098 ) {
099 FunctionDescriptor vd = (FunctionDescriptor) d;
100
101 boolean idx = localLookup != null && localLookup.lookupLocal(vd);
102 if (!idx) return null;
103
104 BindingContext bindingContext = state.getBindingContext();
105 Type localType = asmTypeForAnonymousClass(bindingContext, vd);
106
107 MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_CALLABLE, vd));
108 if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
109 // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
110 // (instead of passing this instance to the constructor and storing as a field)
111 return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true, StackValue.LOCAL_0, vd);
112 }
113
114 String fieldName = "$" + vd.getName();
115 StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false,
116 StackValue.LOCAL_0, vd);
117
118 closure.recordField(fieldName, localType);
119 closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
120
121 return innerValue;
122 }
123 },
124
125 RECEIVER {
126 @Override
127 public boolean isCase(DeclarationDescriptor d) {
128 return d instanceof ReceiverParameterDescriptor;
129 }
130
131 @Override
132 public StackValue.StackValueWithSimpleReceiver innerValue(
133 DeclarationDescriptor d,
134 LocalLookup enclosingLocalLookup,
135 GenerationState state,
136 MutableClosure closure,
137 Type classType
138 ) {
139 if (closure.getEnclosingReceiverDescriptor() != d) {
140 return null;
141 }
142
143 KotlinType receiverType = closure.getEnclosingReceiverDescriptor().getType();
144 Type type = state.getTypeMapper().mapType(receiverType);
145 StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false,
146 StackValue.LOCAL_0, d);
147 closure.setCaptureReceiver();
148
149 return innerValue;
150 }
151
152 @NotNull
153 @Override
154 public StackValue outerValue(@NotNull EnclosedValueDescriptor d, @NotNull ExpressionCodegen codegen) {
155 CallableDescriptor descriptor = (CallableDescriptor) d.getDescriptor();
156 return StackValue.local(descriptor.getDispatchReceiverParameter() != null ? 1 : 0, d.getType());
157 }
158 };
159
160 public abstract boolean isCase(DeclarationDescriptor d);
161
162 public abstract StackValue.StackValueWithSimpleReceiver innerValue(
163 DeclarationDescriptor d,
164 LocalLookup localLookup,
165 GenerationState state,
166 MutableClosure closure,
167 Type classType
168 );
169
170 @NotNull
171 public StackValue outerValue(@NotNull EnclosedValueDescriptor d, @NotNull ExpressionCodegen codegen) {
172 DeclarationDescriptor declarationDescriptor = d.getDescriptor();
173 int idx = codegen.lookupLocalIndex(declarationDescriptor);
174 if (idx >= 0) {
175 return StackValue.local(idx, d.getType());
176 }
177 else {
178 assert declarationDescriptor != null : "No declaration descriptor for " + d;
179 StackValue capturedValue = codegen.findCapturedValue(declarationDescriptor);
180 assert capturedValue != null : "Unresolved captured value for " + d;
181 return capturedValue;
182 }
183 }
184 }
185 }