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 kotlin.Function0;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.codegen.*;
023 import org.jetbrains.jet.codegen.binding.MutableClosure;
024 import org.jetbrains.jet.codegen.state.GenerationState;
025 import org.jetbrains.jet.codegen.state.JetTypeMapper;
026 import org.jetbrains.jet.lang.descriptors.*;
027 import org.jetbrains.jet.lang.resolve.BindingContext;
028 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
029 import org.jetbrains.jet.lang.types.JetType;
030 import org.jetbrains.jet.storage.LockBasedStorageManager;
031 import org.jetbrains.jet.storage.NullableLazyValue;
032 import org.jetbrains.org.objectweb.asm.Type;
033
034 import java.util.*;
035
036 import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_THIS_FIELD;
037 import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityAccessFlag;
038 import static org.jetbrains.jet.codegen.binding.CodegenBinding.anonymousClassForFunction;
039 import static org.jetbrains.jet.codegen.binding.CodegenBinding.canHaveOuter;
040 import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
041 import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED;
042
043 public abstract class CodegenContext<T extends DeclarationDescriptor> {
044 public static final CodegenContext STATIC = new RootContext();
045
046 private final T contextDescriptor;
047 private final OwnerKind contextKind;
048 private final CodegenContext parentContext;
049 private final ClassDescriptor thisDescriptor;
050 public final MutableClosure closure;
051 private final LocalLookup enclosingLocalLookup;
052
053 private Map<DeclarationDescriptor, DeclarationDescriptor> accessors;
054 private Map<DeclarationDescriptor, CodegenContext> childContexts;
055 private NullableLazyValue<StackValue.Field> lazyOuterExpression;
056
057 public CodegenContext(
058 @NotNull T contextDescriptor,
059 @NotNull OwnerKind contextKind,
060 @Nullable CodegenContext parentContext,
061 @Nullable MutableClosure closure,
062 @Nullable ClassDescriptor thisDescriptor,
063 @Nullable LocalLookup expressionCodegen
064 ) {
065 this.contextDescriptor = contextDescriptor;
066 this.contextKind = contextKind;
067 this.parentContext = parentContext;
068 this.closure = closure;
069 this.thisDescriptor = thisDescriptor;
070 this.enclosingLocalLookup = expressionCodegen;
071
072 if (parentContext != null) {
073 parentContext.addChild(this);
074 }
075 }
076
077 @NotNull
078 public final ClassDescriptor getThisDescriptor() {
079 if (thisDescriptor == null) {
080 throw new UnsupportedOperationException("Context doesn't have a \"this\": " + this);
081 }
082 return thisDescriptor;
083 }
084
085 public final boolean hasThisDescriptor() {
086 return thisDescriptor != null;
087 }
088
089 @NotNull
090 @SuppressWarnings("unchecked")
091 public CodegenContext<? extends ClassOrPackageFragmentDescriptor> getClassOrPackageParentContext() {
092 CodegenContext<?> context = this;
093 while (true) {
094 if (context.getContextDescriptor() instanceof ClassOrPackageFragmentDescriptor) {
095 return (CodegenContext) context;
096 }
097 context = context.getParentContext();
098 assert context != null : "Context which is not top-level has no parent: " + this;
099 }
100 }
101
102 /**
103 * This method returns not null only if context descriptor corresponds to method or function which has receiver
104 */
105 @Nullable
106 public final CallableDescriptor getCallableDescriptorWithReceiver() {
107 if (contextDescriptor instanceof CallableDescriptor) {
108 CallableDescriptor callableDescriptor = (CallableDescriptor) getContextDescriptor();
109 return callableDescriptor.getExtensionReceiverParameter() != null ? callableDescriptor : null;
110 }
111 return null;
112 }
113
114 public StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter) {
115 return getOuterExpression(prefix, ignoreNoOuter, true);
116 }
117
118 private StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter, boolean captureThis) {
119 if (lazyOuterExpression == null || lazyOuterExpression.invoke() == null) {
120 if (!ignoreNoOuter) {
121 throw new UnsupportedOperationException("Don't know how to generate outer expression for " + getContextDescriptor());
122 }
123 return null;
124 }
125 if (captureThis) {
126 if (closure == null) {
127 throw new IllegalStateException("Can't capture this for context without closure: " + getContextDescriptor());
128 }
129 closure.setCaptureThis();
130 }
131 return StackValue.changeReceiverForFieldAndSharedVar(lazyOuterExpression.invoke(), prefix);
132 }
133
134 @NotNull
135 public T getContextDescriptor() {
136 return contextDescriptor;
137 }
138
139 @NotNull
140 public OwnerKind getContextKind() {
141 return contextKind;
142 }
143
144 @NotNull
145 public PackageContext intoPackagePart(@NotNull PackageFragmentDescriptor descriptor, Type packagePartType) {
146 return new PackageContext(descriptor, this, packagePartType);
147 }
148
149 @NotNull
150 public FieldOwnerContext intoPackageFacade(@NotNull Type delegateTo, @NotNull PackageFragmentDescriptor descriptor) {
151 return new PackageFacadeContext(descriptor, this, delegateTo);
152 }
153
154 @NotNull
155 public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
156 return new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
157 }
158
159 @NotNull
160 public ClassContext intoAnonymousClass(@NotNull ClassDescriptor descriptor, @NotNull ExpressionCodegen codegen, @NotNull OwnerKind ownerKind) {
161 return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, this, codegen);
162 }
163
164 @NotNull
165 public MethodContext intoFunction(FunctionDescriptor descriptor) {
166 return new MethodContext(descriptor, getContextKind(), this, null, false);
167 }
168
169 @NotNull
170 public MethodContext intoInlinedLambda(FunctionDescriptor descriptor) {
171 return new MethodContext(descriptor, getContextKind(), this, null, true);
172 }
173
174 @NotNull
175 public ConstructorContext intoConstructor(@NotNull ConstructorDescriptor descriptor) {
176 return new ConstructorContext(descriptor, getContextKind(), this, closure);
177 }
178
179 // SCRIPT: generate into script, move to ScriptingUtil
180 @NotNull
181 public ScriptContext intoScript(
182 @NotNull ScriptDescriptor script,
183 @NotNull List<ScriptDescriptor> earlierScripts,
184 @NotNull ClassDescriptor classDescriptor
185 ) {
186 return new ScriptContext(script, earlierScripts, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure);
187 }
188
189 @NotNull
190 public CodegenContext intoClosure(
191 @NotNull FunctionDescriptor funDescriptor,
192 @NotNull LocalLookup localLookup,
193 @NotNull JetTypeMapper typeMapper
194 ) {
195 ClassDescriptor classDescriptor = anonymousClassForFunction(typeMapper.getBindingContext(), funDescriptor);
196 return new ClosureContext(typeMapper, funDescriptor, classDescriptor, this, localLookup);
197 }
198
199 @Nullable
200 public CodegenContext getParentContext() {
201 return parentContext;
202 }
203
204 public ClassDescriptor getEnclosingClass() {
205 CodegenContext cur = getParentContext();
206 while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) {
207 cur = cur.getParentContext();
208 }
209
210 return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor();
211 }
212
213 @Nullable
214 public CodegenContext findParentContextWithDescriptor(DeclarationDescriptor descriptor) {
215 CodegenContext c = this;
216 while (c != null) {
217 if (c.getContextDescriptor() == descriptor) break;
218 c = c.getParentContext();
219 }
220 return c;
221 }
222
223 @NotNull
224 public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor) {
225 return getAccessor(descriptor, false, null);
226 }
227
228 @NotNull
229 public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor, boolean isForBackingFieldInOuterClass, @Nullable JetType delegateType) {
230 if (accessors == null) {
231 accessors = new LinkedHashMap<DeclarationDescriptor, DeclarationDescriptor>();
232 }
233 descriptor = descriptor.getOriginal();
234 DeclarationDescriptor accessor = accessors.get(descriptor);
235 if (accessor != null) {
236 assert !isForBackingFieldInOuterClass ||
237 accessor instanceof AccessorForPropertyBackingFieldInOuterClass : "There is already exists accessor with isForBackingFieldInOuterClass = false in this context";
238 return accessor;
239 }
240
241 int accessorIndex = accessors.size();
242 if (descriptor instanceof SimpleFunctionDescriptor || descriptor instanceof ConstructorDescriptor) {
243 accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessorIndex);
244 }
245 else if (descriptor instanceof PropertyDescriptor) {
246 if (isForBackingFieldInOuterClass) {
247 accessor = new AccessorForPropertyBackingFieldInOuterClass((PropertyDescriptor) descriptor, contextDescriptor,
248 accessorIndex, delegateType);
249 } else {
250 accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessorIndex);
251 }
252 }
253 else {
254 throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
255 }
256 accessors.put(descriptor, accessor);
257 return accessor;
258 }
259
260 public abstract boolean isStatic();
261
262 protected void initOuterExpression(@NotNull final JetTypeMapper typeMapper, @NotNull final ClassDescriptor classDescriptor) {
263 lazyOuterExpression = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue(new Function0<StackValue.Field>() {
264 @Override
265 public StackValue.Field invoke() {
266 ClassDescriptor enclosingClass = getEnclosingClass();
267 if (enclosingClass == null) return null;
268
269 return canHaveOuter(typeMapper.getBindingContext(), classDescriptor)
270 ? StackValue.field(typeMapper.mapType(enclosingClass), typeMapper.mapType(classDescriptor),
271 CAPTURED_THIS_FIELD, false, StackValue.LOCAL_0)
272 : null;
273 }
274 });
275 }
276
277 public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
278 StackValue myOuter = null;
279 if (closure != null) {
280 EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d);
281 if (answer != null) {
282 return StackValue.changeReceiverForFieldAndSharedVar(answer.getInnerValue(), result);
283 }
284
285 for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
286 if (aCase.isCase(d)) {
287 Type classType = state.getTypeMapper().mapType(getThisDescriptor());
288 StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
289 if (innerValue == null) {
290 break;
291 }
292 else {
293 return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result);
294 }
295 }
296 }
297
298 myOuter = getOuterExpression(result, ignoreNoOuter, false);
299 result = myOuter;
300 }
301
302 StackValue resultValue;
303 if (myOuter != null && getEnclosingClass() == d) {
304 resultValue = result;
305 } else {
306 resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
307 }
308
309 if (myOuter != null && resultValue != null && !isStaticField(resultValue)) {
310 closure.setCaptureThis();
311 }
312 return resultValue;
313 }
314
315 @NotNull
316 public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() {
317 return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors;
318 }
319
320 @NotNull
321 public PropertyDescriptor accessiblePropertyDescriptor(PropertyDescriptor propertyDescriptor) {
322 return (PropertyDescriptor) accessibleDescriptorIfNeeded(propertyDescriptor, true);
323 }
324
325 @NotNull
326 public FunctionDescriptor accessibleFunctionDescriptor(FunctionDescriptor fd) {
327 return (FunctionDescriptor) accessibleDescriptorIfNeeded(fd, true);
328 }
329
330 public void recordSyntheticAccessorIfNeeded(@NotNull FunctionDescriptor fd, @NotNull BindingContext bindingContext) {
331 if (fd instanceof ConstructorDescriptor || needSyntheticAccessorInBindingTrace(fd, bindingContext)) {
332 accessibleDescriptorIfNeeded(fd, false);
333 }
334 }
335
336 public void recordSyntheticAccessorIfNeeded(@NotNull PropertyDescriptor propertyDescriptor, @NotNull BindingContext typeMapper) {
337 if (needSyntheticAccessorInBindingTrace(propertyDescriptor, typeMapper)) {
338 accessibleDescriptorIfNeeded(propertyDescriptor, false);
339 }
340 }
341
342 private static boolean needSyntheticAccessorInBindingTrace(
343 @NotNull CallableMemberDescriptor descriptor,
344 @NotNull BindingContext bindingContext
345 ) {
346 return Boolean.TRUE.equals(bindingContext.get(BindingContext.NEED_SYNTHETIC_ACCESSOR, descriptor));
347 }
348
349 private static int getAccessFlags(@NotNull CallableMemberDescriptor descriptor) {
350 int flag = getVisibilityAccessFlag(descriptor);
351 if (descriptor instanceof PropertyDescriptor) {
352 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
353
354 PropertySetterDescriptor setter = propertyDescriptor.getSetter();
355 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
356
357 flag |= (getter == null ? 0 : getVisibilityAccessFlag(getter)) |
358 (setter == null ? 0 : getVisibilityAccessFlag(setter));
359 }
360 return flag;
361 }
362
363 @NotNull
364 private MemberDescriptor accessibleDescriptorIfNeeded(CallableMemberDescriptor descriptor, boolean fromOutsideContext) {
365 CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
366 int flag = getAccessFlags(unwrappedDescriptor);
367 if ((flag & ACC_PRIVATE) == 0 && (flag & ACC_PROTECTED) == 0) {
368 return descriptor;
369 }
370
371 CodegenContext descriptorContext = null;
372 if (!fromOutsideContext || getClassOrPackageParentContext().getContextDescriptor() != descriptor.getContainingDeclaration()) {
373 DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
374 boolean isClassObjectMember = DescriptorUtils.isClassObject(enclosed);
375 //go upper
376 if (hasThisDescriptor() && (enclosed != getThisDescriptor() || !fromOutsideContext)) {
377 CodegenContext currentContext = this;
378 while (currentContext != null) {
379 if (currentContext.getContextDescriptor() == enclosed) {
380 descriptorContext = currentContext;
381 break;
382 }
383
384 //accessors for private members in class object for call from class
385 if (isClassObjectMember && currentContext instanceof ClassContext) {
386 ClassContext classContext = (ClassContext) currentContext;
387 CodegenContext classObject = classContext.getClassObjectContext();
388 if (classObject != null && classObject.getContextDescriptor() == enclosed) {
389 descriptorContext = classObject;
390 break;
391 }
392 }
393
394 currentContext = currentContext.getParentContext();
395 }
396 }
397 }
398
399 if (descriptorContext == null) {
400 return descriptor;
401 }
402
403 if ((flag & ACC_PROTECTED) != 0) {
404 PackageFragmentDescriptor unwrappedDescriptorPackage =
405 DescriptorUtils.getParentOfType(unwrappedDescriptor, PackageFragmentDescriptor.class, false);
406 PackageFragmentDescriptor contextDescriptorPackage =
407 DescriptorUtils.getParentOfType(descriptorContext.getContextDescriptor(), PackageFragmentDescriptor.class, false);
408
409 boolean inSamePackage = contextDescriptorPackage != null && unwrappedDescriptorPackage != null &&
410 unwrappedDescriptorPackage.getFqName().equals(contextDescriptorPackage.getFqName());
411 if (inSamePackage) {
412 return descriptor;
413 }
414 }
415
416 return (MemberDescriptor) descriptorContext.getAccessor(descriptor);
417 }
418
419 private void addChild(@NotNull CodegenContext child) {
420 if (shouldAddChild(child)) {
421 if (childContexts == null) {
422 childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
423 }
424 DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
425 childContexts.put(childContextDescriptor, child);
426 }
427 }
428
429 protected boolean shouldAddChild(@NotNull CodegenContext child) {
430 DeclarationDescriptor childContextDescriptor = child.contextDescriptor;
431 if (childContextDescriptor instanceof ClassDescriptor) {
432 ClassKind kind = ((ClassDescriptor) childContextDescriptor).getKind();
433 return kind == ClassKind.CLASS_OBJECT;
434 }
435 return false;
436 }
437
438 @Nullable
439 public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
440 return childContexts == null ? null : childContexts.get(child);
441 }
442
443 private static boolean isStaticField(@NotNull StackValue value) {
444 return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
445 }
446 }