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.MutableClosure; 024 import org.jetbrains.jet.codegen.state.GenerationState; 025 import org.jetbrains.jet.codegen.state.JetTypeMapper; 026 import org.jetbrains.jet.lang.descriptors.*; 027 import org.jetbrains.jet.lang.resolve.BindingContext; 028 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 029 import org.jetbrains.jet.lang.types.JetType; 030 import org.jetbrains.jet.storage.LockBasedStorageManager; 031 import org.jetbrains.jet.storage.NullableLazyValue; 032 import org.jetbrains.org.objectweb.asm.Type; 033 034 import java.util.Collections; 035 import java.util.HashMap; 036 import java.util.List; 037 import java.util.Map; 038 039 import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_THIS_FIELD; 040 import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityAccessFlag; 041 import static org.jetbrains.jet.codegen.binding.CodegenBinding.anonymousClassForFunction; 042 import static org.jetbrains.jet.codegen.binding.CodegenBinding.canHaveOuter; 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.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 (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, @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 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 abstract boolean isStatic(); 264 265 protected void initOuterExpression(@NotNull final JetTypeMapper typeMapper, @NotNull final ClassDescriptor classDescriptor) { 266 lazyOuterExpression = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue(new Function0<StackValue>() { 267 @Override 268 public StackValue invoke() { 269 ClassDescriptor enclosingClass = getEnclosingClass(); 270 if (enclosingClass == null) return null; 271 272 return canHaveOuter(typeMapper.getBindingContext(), classDescriptor) 273 ? StackValue.field(typeMapper.mapType(enclosingClass), typeMapper.mapType(classDescriptor), 274 CAPTURED_THIS_FIELD, false) 275 : null; 276 } 277 }); 278 } 279 280 public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) { 281 StackValue myOuter = null; 282 if (closure != null) { 283 EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d); 284 if (answer != null) { 285 StackValue innerValue = answer.getInnerValue(); 286 return result == null ? innerValue : StackValue.composed(result, innerValue); 287 } 288 289 for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) { 290 if (aCase.isCase(d)) { 291 Type classType = state.getTypeMapper().mapType(getThisDescriptor()); 292 StackValue innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType); 293 if (innerValue == null) { 294 break; 295 } 296 else { 297 return result == null ? innerValue : composedOrStatic(result, innerValue); 298 } 299 } 300 } 301 302 myOuter = getOuterExpression(null, ignoreNoOuter, false); 303 result = result == null || myOuter == null ? myOuter : StackValue.composed(result, myOuter); 304 } 305 306 StackValue resultValue; 307 if (myOuter != null && getEnclosingClass() == d) { 308 resultValue = result; 309 } else { 310 resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null; 311 } 312 313 if (myOuter != null && resultValue != null && !isStaticField(resultValue)) { 314 closure.setCaptureThis(); 315 } 316 return resultValue; 317 } 318 319 @NotNull 320 public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() { 321 return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors; 322 } 323 324 @NotNull 325 public PropertyDescriptor accessiblePropertyDescriptor(PropertyDescriptor propertyDescriptor) { 326 return (PropertyDescriptor) accessibleDescriptorIfNeeded(propertyDescriptor, true); 327 } 328 329 @NotNull 330 public FunctionDescriptor accessibleFunctionDescriptor(FunctionDescriptor fd) { 331 return (FunctionDescriptor) accessibleDescriptorIfNeeded(fd, true); 332 } 333 334 public void recordSyntheticAccessorIfNeeded(@NotNull FunctionDescriptor fd, @NotNull BindingContext bindingContext) { 335 if (fd instanceof ConstructorDescriptor || needSyntheticAccessorInBindingTrace(fd, bindingContext)) { 336 accessibleDescriptorIfNeeded(fd, false); 337 } 338 } 339 340 public void recordSyntheticAccessorIfNeeded(@NotNull PropertyDescriptor propertyDescriptor, @NotNull BindingContext typeMapper) { 341 if (needSyntheticAccessorInBindingTrace(propertyDescriptor, typeMapper)) { 342 accessibleDescriptorIfNeeded(propertyDescriptor, false); 343 } 344 } 345 346 private static boolean needSyntheticAccessorInBindingTrace( 347 @NotNull CallableMemberDescriptor descriptor, 348 @NotNull BindingContext bindingContext 349 ) { 350 return Boolean.TRUE.equals(bindingContext.get(BindingContext.NEED_SYNTHETIC_ACCESSOR, descriptor)); 351 } 352 353 private static int getAccessFlags(@NotNull CallableMemberDescriptor descriptor) { 354 int flag = getVisibilityAccessFlag(descriptor); 355 if (descriptor instanceof PropertyDescriptor) { 356 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; 357 358 PropertySetterDescriptor setter = propertyDescriptor.getSetter(); 359 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 360 361 flag |= (getter == null ? 0 : getVisibilityAccessFlag(getter)) | 362 (setter == null ? 0 : getVisibilityAccessFlag(setter)); 363 } 364 return flag; 365 } 366 367 @NotNull 368 private MemberDescriptor accessibleDescriptorIfNeeded(CallableMemberDescriptor descriptor, boolean fromOutsideContext) { 369 CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor); 370 int flag = getAccessFlags(unwrappedDescriptor); 371 if ((flag & ACC_PRIVATE) == 0 && (flag & ACC_PROTECTED) == 0) { 372 return descriptor; 373 } 374 375 CodegenContext descriptorContext = null; 376 if (!fromOutsideContext || getClassOrPackageParentContext().getContextDescriptor() != descriptor.getContainingDeclaration()) { 377 DeclarationDescriptor enclosed = descriptor.getContainingDeclaration(); 378 boolean isClassObjectMember = DescriptorUtils.isClassObject(enclosed); 379 //go upper 380 if (hasThisDescriptor() && (enclosed != getThisDescriptor() || !fromOutsideContext)) { 381 CodegenContext currentContext = this; 382 while (currentContext != null) { 383 if (currentContext.getContextDescriptor() == enclosed) { 384 descriptorContext = currentContext; 385 break; 386 } 387 388 //accessors for private members in class object for call from class 389 if (isClassObjectMember && currentContext instanceof ClassContext) { 390 ClassContext classContext = (ClassContext) currentContext; 391 CodegenContext classObject = classContext.getClassObjectContext(); 392 if (classObject != null && classObject.getContextDescriptor() == enclosed) { 393 descriptorContext = classObject; 394 break; 395 } 396 } 397 398 currentContext = currentContext.getParentContext(); 399 } 400 } 401 } 402 403 if (descriptorContext == null) { 404 return descriptor; 405 } 406 407 if ((flag & ACC_PROTECTED) != 0) { 408 PackageFragmentDescriptor unwrappedDescriptorPackage = 409 DescriptorUtils.getParentOfType(unwrappedDescriptor, PackageFragmentDescriptor.class, false); 410 PackageFragmentDescriptor contextDescriptorPackage = 411 DescriptorUtils.getParentOfType(descriptorContext.getContextDescriptor(), PackageFragmentDescriptor.class, false); 412 413 boolean inSamePackage = contextDescriptorPackage != null && unwrappedDescriptorPackage != null && 414 unwrappedDescriptorPackage.getFqName().equals(contextDescriptorPackage.getFqName()); 415 if (inSamePackage) { 416 return descriptor; 417 } 418 } 419 420 return (MemberDescriptor) descriptorContext.getAccessor(descriptor); 421 } 422 423 private void addChild(@NotNull CodegenContext child) { 424 if (shouldAddChild(child)) { 425 if (childContexts == null) { 426 childContexts = new HashMap<DeclarationDescriptor, CodegenContext>(); 427 } 428 DeclarationDescriptor childContextDescriptor = child.getContextDescriptor(); 429 childContexts.put(childContextDescriptor, child); 430 } 431 } 432 433 protected boolean shouldAddChild(@NotNull CodegenContext child) { 434 DeclarationDescriptor childContextDescriptor = child.contextDescriptor; 435 if (childContextDescriptor instanceof ClassDescriptor) { 436 ClassKind kind = ((ClassDescriptor) childContextDescriptor).getKind(); 437 return kind == ClassKind.CLASS_OBJECT; 438 } 439 return false; 440 } 441 442 @Nullable 443 public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) { 444 return childContexts == null ? null : childContexts.get(child); 445 } 446 447 @NotNull 448 private static StackValue composedOrStatic(@NotNull StackValue prefix, @NotNull StackValue suffix) { 449 if (isStaticField(suffix)) { 450 return suffix; 451 } 452 return StackValue.composed(prefix, suffix); 453 } 454 455 private static boolean isStaticField(@NotNull StackValue value) { 456 return value instanceof StackValue.Field && ((StackValue.Field) value).isStatic; 457 } 458 }