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.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.resolve.BindingContext; 028 import org.jetbrains.kotlin.resolve.DescriptorUtils; 029 import org.jetbrains.kotlin.storage.LockBasedStorageManager; 030 import org.jetbrains.kotlin.storage.NullableLazyValue; 031 import org.jetbrains.kotlin.types.JetType; 032 import org.jetbrains.org.objectweb.asm.Type; 033 034 import java.util.*; 035 036 import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityAccessFlag; 037 import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE; 038 import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED; 039 040 public abstract class CodegenContext<T extends DeclarationDescriptor> { 041 public static final CodegenContext STATIC = new RootContext(); 042 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, DeclarationDescriptor> accessors; 052 private Map<DeclarationDescriptor, CodegenContext> childContexts; 053 054 public CodegenContext( 055 @NotNull T contextDescriptor, 056 @NotNull OwnerKind contextKind, 057 @Nullable CodegenContext parentContext, 058 @Nullable MutableClosure closure, 059 @Nullable ClassDescriptor thisDescriptor, 060 @Nullable LocalLookup localLookup 061 ) { 062 this.contextDescriptor = contextDescriptor; 063 this.contextKind = contextKind; 064 this.parentContext = parentContext; 065 this.closure = closure; 066 this.thisDescriptor = thisDescriptor; 067 this.enclosingLocalLookup = localLookup; 068 this.outerExpression = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue(new Function0<StackValue.Field>() { 069 @Override 070 public StackValue.Field invoke() { 071 return computeOuterExpression(); 072 } 073 }); 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.getExtensionReceiverParameter() != 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 (outerExpression.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 StackValue.changeReceiverForFieldAndSharedVar(outerExpression.invoke(), prefix); 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, @NotNull OwnerKind ownerKind) { 164 return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, 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 ClosureContext intoClosure( 194 @NotNull FunctionDescriptor funDescriptor, 195 @NotNull LocalLookup localLookup, 196 @NotNull JetTypeMapper typeMapper 197 ) { 198 return new ClosureContext(typeMapper, funDescriptor, this, localLookup); 199 } 200 201 @Nullable 202 public CodegenContext getParentContext() { 203 return parentContext; 204 } 205 206 public ClassDescriptor getEnclosingClass() { 207 CodegenContext cur = getParentContext(); 208 while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) { 209 cur = cur.getParentContext(); 210 } 211 212 return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor(); 213 } 214 215 @Nullable 216 public CodegenContext findParentContextWithDescriptor(DeclarationDescriptor descriptor) { 217 CodegenContext c = this; 218 while (c != null) { 219 if (c.getContextDescriptor() == descriptor) break; 220 c = c.getParentContext(); 221 } 222 return c; 223 } 224 225 @NotNull 226 public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor) { 227 return getAccessor(descriptor, false, null); 228 } 229 230 @NotNull 231 public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor, boolean isForBackingFieldInOuterClass, @Nullable JetType delegateType) { 232 if (accessors == null) { 233 accessors = new LinkedHashMap<DeclarationDescriptor, DeclarationDescriptor>(); 234 } 235 descriptor = descriptor.getOriginal(); 236 DeclarationDescriptor accessor = accessors.get(descriptor); 237 if (accessor != null) { 238 assert !isForBackingFieldInOuterClass || 239 accessor instanceof AccessorForPropertyBackingFieldInOuterClass : "There is already exists accessor with isForBackingFieldInOuterClass = false in this context"; 240 return accessor; 241 } 242 243 int accessorIndex = accessors.size(); 244 if (descriptor instanceof SimpleFunctionDescriptor || descriptor instanceof ConstructorDescriptor) { 245 accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessorIndex); 246 } 247 else if (descriptor instanceof PropertyDescriptor) { 248 if (isForBackingFieldInOuterClass) { 249 accessor = new AccessorForPropertyBackingFieldInOuterClass((PropertyDescriptor) descriptor, contextDescriptor, 250 accessorIndex, delegateType); 251 } else { 252 accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessorIndex); 253 } 254 } 255 else { 256 throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor); 257 } 258 accessors.put(descriptor, accessor); 259 return accessor; 260 } 261 262 @Nullable 263 protected StackValue.Field computeOuterExpression() { 264 return null; 265 } 266 267 public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) { 268 StackValue myOuter = null; 269 if (closure != null) { 270 EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d); 271 if (answer != null) { 272 return StackValue.changeReceiverForFieldAndSharedVar(answer.getInnerValue(), result); 273 } 274 275 for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) { 276 if (aCase.isCase(d)) { 277 Type classType = state.getTypeMapper().mapType(getThisDescriptor()); 278 StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType); 279 if (innerValue == null) { 280 break; 281 } 282 else { 283 return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result); 284 } 285 } 286 } 287 288 myOuter = getOuterExpression(result, ignoreNoOuter, false); 289 result = myOuter; 290 } 291 292 StackValue resultValue; 293 if (myOuter != null && getEnclosingClass() == d) { 294 resultValue = result; 295 } else { 296 resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null; 297 } 298 299 if (myOuter != null && resultValue != null && !isStaticField(resultValue)) { 300 closure.setCaptureThis(); 301 } 302 return resultValue; 303 } 304 305 @NotNull 306 public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() { 307 return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors; 308 } 309 310 @NotNull 311 public PropertyDescriptor accessiblePropertyDescriptor(PropertyDescriptor propertyDescriptor) { 312 return (PropertyDescriptor) accessibleDescriptorIfNeeded(propertyDescriptor, true); 313 } 314 315 @NotNull 316 public FunctionDescriptor accessibleFunctionDescriptor(FunctionDescriptor fd) { 317 return (FunctionDescriptor) accessibleDescriptorIfNeeded(fd, true); 318 } 319 320 public void recordSyntheticAccessorIfNeeded(@NotNull FunctionDescriptor fd, @NotNull BindingContext bindingContext) { 321 if (fd instanceof ConstructorDescriptor || needSyntheticAccessorInBindingTrace(fd, bindingContext)) { 322 accessibleDescriptorIfNeeded(fd, false); 323 } 324 } 325 326 public void recordSyntheticAccessorIfNeeded(@NotNull PropertyDescriptor propertyDescriptor, @NotNull BindingContext typeMapper) { 327 if (needSyntheticAccessorInBindingTrace(propertyDescriptor, typeMapper)) { 328 accessibleDescriptorIfNeeded(propertyDescriptor, false); 329 } 330 } 331 332 private static boolean needSyntheticAccessorInBindingTrace( 333 @NotNull CallableMemberDescriptor descriptor, 334 @NotNull BindingContext bindingContext 335 ) { 336 return Boolean.TRUE.equals(bindingContext.get(BindingContext.NEED_SYNTHETIC_ACCESSOR, descriptor)); 337 } 338 339 private static int getAccessFlags(@NotNull CallableMemberDescriptor descriptor) { 340 int flag = getVisibilityAccessFlag(descriptor); 341 if (descriptor instanceof PropertyDescriptor) { 342 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; 343 344 PropertySetterDescriptor setter = propertyDescriptor.getSetter(); 345 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 346 347 flag |= (getter == null ? 0 : getVisibilityAccessFlag(getter)) | 348 (setter == null ? 0 : getVisibilityAccessFlag(setter)); 349 } 350 return flag; 351 } 352 353 @NotNull 354 private MemberDescriptor accessibleDescriptorIfNeeded(CallableMemberDescriptor descriptor, boolean fromOutsideContext) { 355 CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor); 356 int flag = getAccessFlags(unwrappedDescriptor); 357 if ((flag & ACC_PRIVATE) == 0 && (flag & ACC_PROTECTED) == 0) { 358 return descriptor; 359 } 360 361 CodegenContext descriptorContext = null; 362 if (!fromOutsideContext || getClassOrPackageParentContext().getContextDescriptor() != descriptor.getContainingDeclaration()) { 363 DeclarationDescriptor enclosed = descriptor.getContainingDeclaration(); 364 boolean isCompanionObjectMember = DescriptorUtils.isCompanionObject(enclosed); 365 //go upper 366 if (hasThisDescriptor() && (enclosed != getThisDescriptor() || !fromOutsideContext)) { 367 CodegenContext currentContext = this; 368 while (currentContext != null) { 369 if (currentContext.getContextDescriptor() == enclosed) { 370 descriptorContext = currentContext; 371 break; 372 } 373 374 //accessors for private members in companion object for call from class 375 if (isCompanionObjectMember && currentContext instanceof ClassContext) { 376 ClassContext classContext = (ClassContext) currentContext; 377 CodegenContext companionObjectContext = classContext.getCompanionObjectContext(); 378 if (companionObjectContext != null && companionObjectContext.getContextDescriptor() == enclosed) { 379 descriptorContext = companionObjectContext; 380 break; 381 } 382 } 383 384 currentContext = currentContext.getParentContext(); 385 } 386 } 387 } 388 389 if (descriptorContext == null) { 390 return descriptor; 391 } 392 393 if ((flag & ACC_PROTECTED) != 0) { 394 PackageFragmentDescriptor unwrappedDescriptorPackage = 395 DescriptorUtils.getParentOfType(unwrappedDescriptor, PackageFragmentDescriptor.class, false); 396 PackageFragmentDescriptor contextDescriptorPackage = 397 DescriptorUtils.getParentOfType(descriptorContext.getContextDescriptor(), PackageFragmentDescriptor.class, false); 398 399 boolean inSamePackage = contextDescriptorPackage != null && unwrappedDescriptorPackage != null && 400 unwrappedDescriptorPackage.getFqName().equals(contextDescriptorPackage.getFqName()); 401 if (inSamePackage) { 402 return descriptor; 403 } 404 } 405 406 return (MemberDescriptor) descriptorContext.getAccessor(descriptor); 407 } 408 409 private void addChild(@NotNull CodegenContext child) { 410 if (shouldAddChild(child)) { 411 if (childContexts == null) { 412 childContexts = new HashMap<DeclarationDescriptor, CodegenContext>(); 413 } 414 DeclarationDescriptor childContextDescriptor = child.getContextDescriptor(); 415 childContexts.put(childContextDescriptor, child); 416 } 417 } 418 419 protected boolean shouldAddChild(@NotNull CodegenContext child) { 420 return DescriptorUtils.isCompanionObject(child.contextDescriptor); 421 } 422 423 @Nullable 424 public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) { 425 return childContexts == null ? null : childContexts.get(child); 426 } 427 428 private static boolean isStaticField(@NotNull StackValue value) { 429 return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut; 430 } 431 }