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