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