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