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