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