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