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 }