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