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