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 jet.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 FieldOwnerContext intoPackagePart(@NotNull PackageFragmentDescriptor descriptor) { 163 return new PackageContext(descriptor, this); 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); 184 } 185 186 @NotNull 187 public ConstructorContext intoConstructor(@Nullable ConstructorDescriptor descriptor, @Nullable MutableClosure closure) { 188 if (descriptor == null) { 189 descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Annotations.EMPTY, true) 190 .initialize(Collections.<TypeParameterDescriptor>emptyList(), Collections.<ValueParameterDescriptor>emptyList(), 191 Visibilities.PUBLIC); 192 } 193 return new ConstructorContext(descriptor, getContextKind(), this, closure); 194 } 195 196 @NotNull 197 public ScriptContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) { 198 return new ScriptContext(script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure); 199 } 200 201 @NotNull 202 public CodegenContext intoClosure( 203 @NotNull FunctionDescriptor funDescriptor, 204 @NotNull LocalLookup localLookup, 205 @NotNull JetTypeMapper typeMapper 206 ) { 207 ClassDescriptor classDescriptor = anonymousClassForFunction(typeMapper.getBindingContext(), funDescriptor); 208 return new ClosureContext(typeMapper, funDescriptor, classDescriptor, this, localLookup); 209 } 210 211 @NotNull 212 public FrameMap prepareFrame(@NotNull JetTypeMapper typeMapper) { 213 FrameMap frameMap = new FrameMap(); 214 215 if (getContextKind() != OwnerKind.PACKAGE) { 216 frameMap.enterTemp(OBJECT_TYPE); // 0 slot for this 217 } 218 219 CallableDescriptor receiverDescriptor = getCallableDescriptorWithReceiver(); 220 if (receiverDescriptor != null) { 221 //noinspection ConstantConditions 222 Type type = typeMapper.mapType(receiverDescriptor.getReceiverParameter().getType()); 223 frameMap.enterTemp(type); // Next slot for receiver 224 } 225 226 return frameMap; 227 } 228 229 @Nullable 230 public CodegenContext getParentContext() { 231 return parentContext; 232 } 233 234 public ClassDescriptor getEnclosingClass() { 235 CodegenContext cur = getParentContext(); 236 while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) { 237 cur = cur.getParentContext(); 238 } 239 240 return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor(); 241 } 242 243 @Nullable 244 public CodegenContext findParentContextWithDescriptor(DeclarationDescriptor descriptor) { 245 CodegenContext c = this; 246 while (c != null) { 247 if (c.getContextDescriptor() == descriptor) break; 248 c = c.getParentContext(); 249 } 250 return c; 251 } 252 253 @NotNull 254 public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor) { 255 return getAccessor(descriptor, false, null); 256 } 257 258 @NotNull 259 public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor, boolean isForBackingFieldInOuterClass, @Nullable JetType delegateType) { 260 if (accessors == null) { 261 accessors = new HashMap<DeclarationDescriptor, DeclarationDescriptor>(); 262 } 263 descriptor = descriptor.getOriginal(); 264 DeclarationDescriptor accessor = accessors.get(descriptor); 265 if (accessor != null) { 266 assert !isForBackingFieldInOuterClass || 267 accessor instanceof AccessorForPropertyBackingFieldInOuterClass : "There is already exists accessor with isForBackingFieldInOuterClass = false in this context"; 268 return accessor; 269 } 270 271 int accessorIndex = accessors.size(); 272 if (descriptor instanceof SimpleFunctionDescriptor || descriptor instanceof ConstructorDescriptor) { 273 accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessorIndex); 274 } 275 else if (descriptor instanceof PropertyDescriptor) { 276 if (isForBackingFieldInOuterClass) { 277 accessor = new AccessorForPropertyBackingFieldInOuterClass((PropertyDescriptor) descriptor, contextDescriptor, 278 accessorIndex, delegateType); 279 } else { 280 accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessorIndex); 281 } 282 } 283 else { 284 throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor); 285 } 286 accessors.put(descriptor, accessor); 287 return accessor; 288 } 289 290 public StackValue getReceiverExpression(JetTypeMapper typeMapper) { 291 assert getCallableDescriptorWithReceiver() != null; 292 @SuppressWarnings("ConstantConditions") 293 Type asmType = typeMapper.mapType(getCallableDescriptorWithReceiver().getReceiverParameter().getType()); 294 return hasThisDescriptor() ? StackValue.local(1, asmType) : StackValue.local(0, asmType); 295 } 296 297 public abstract boolean isStatic(); 298 299 protected void initOuterExpression(@NotNull final JetTypeMapper typeMapper, @NotNull final ClassDescriptor classDescriptor) { 300 lazyOuterExpression = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue(new Function0<StackValue>() { 301 @Override 302 public StackValue invoke() { 303 ClassDescriptor enclosingClass = getEnclosingClass(); 304 return enclosingClass != null && canHaveOuter(typeMapper.getBindingContext(), classDescriptor) 305 ? StackValue.field(typeMapper.mapType(enclosingClass), 306 CodegenBinding.getAsmType(typeMapper.getBindingTrace(), classDescriptor), 307 CAPTURED_THIS_FIELD, 308 false) 309 : null; 310 } 311 }); 312 } 313 314 public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) { 315 StackValue myOuter = null; 316 if (closure != null) { 317 EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d); 318 if (answer != null) { 319 StackValue innerValue = answer.getInnerValue(); 320 return result == null ? innerValue : StackValue.composed(result, innerValue); 321 } 322 323 for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) { 324 if (aCase.isCase(d)) { 325 Type classType = state.getBindingContext().get(ASM_TYPE, getThisDescriptor()); 326 StackValue innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType); 327 if (innerValue == null) { 328 break; 329 } 330 else { 331 return result == null ? innerValue : StackValue.composed(result, innerValue); 332 } 333 } 334 } 335 336 myOuter = getOuterExpression(null, ignoreNoOuter, false); 337 result = result == null || myOuter == null ? myOuter : StackValue.composed(result, myOuter); 338 } 339 340 StackValue resultValue; 341 if (myOuter != null && getEnclosingClass() == d) { 342 resultValue = result; 343 } else { 344 resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null; 345 } 346 347 if (myOuter != null && resultValue != null) { 348 closure.setCaptureThis(); 349 } 350 return resultValue; 351 } 352 353 @NotNull 354 public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() { 355 return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors; 356 } 357 358 @NotNull 359 public PropertyDescriptor accessiblePropertyDescriptor(PropertyDescriptor propertyDescriptor) { 360 return (PropertyDescriptor) accessibleDescriptorIfNeeded(propertyDescriptor, true); 361 } 362 363 @NotNull 364 public FunctionDescriptor accessibleFunctionDescriptor(FunctionDescriptor fd) { 365 return (FunctionDescriptor) accessibleDescriptorIfNeeded(fd, true); 366 } 367 368 public void recordSyntheticAccessorIfNeeded(@NotNull FunctionDescriptor fd, @NotNull BindingContext bindingContext) { 369 if (fd instanceof ConstructorDescriptor || needSyntheticAccessorInBindingTrace(fd, bindingContext)) { 370 accessibleDescriptorIfNeeded(fd, false); 371 } 372 } 373 374 public void recordSyntheticAccessorIfNeeded(@NotNull PropertyDescriptor propertyDescriptor, @NotNull BindingContext typeMapper) { 375 if (needSyntheticAccessorInBindingTrace(propertyDescriptor, typeMapper)) { 376 accessibleDescriptorIfNeeded(propertyDescriptor, false); 377 } 378 } 379 380 private static boolean needSyntheticAccessorInBindingTrace( 381 @NotNull CallableMemberDescriptor descriptor, 382 @NotNull BindingContext bindingContext 383 ) { 384 return Boolean.TRUE.equals(bindingContext.get(BindingContext.NEED_SYNTHETIC_ACCESSOR, descriptor)); 385 } 386 387 private static int getAccessFlags(@NotNull CallableMemberDescriptor descriptor) { 388 int flag = getVisibilityAccessFlag(descriptor); 389 if (descriptor instanceof PropertyDescriptor) { 390 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; 391 392 PropertySetterDescriptor setter = propertyDescriptor.getSetter(); 393 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 394 395 flag |= (getter == null ? 0 : getVisibilityAccessFlag(getter)) | 396 (setter == null ? 0 : getVisibilityAccessFlag(setter)); 397 } 398 return flag; 399 } 400 401 @NotNull 402 private MemberDescriptor accessibleDescriptorIfNeeded(CallableMemberDescriptor descriptor, boolean fromOutsideContext) { 403 int flag = getAccessFlags(descriptor); 404 if ((flag & ACC_PRIVATE) == 0) { 405 return descriptor; 406 } 407 408 CodegenContext descriptorContext = null; 409 if (!fromOutsideContext || getClassOrPackageDescriptor() != 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 return (MemberDescriptor) (descriptorContext != null ? descriptorContext.getAccessor(descriptor) : descriptor); 437 } 438 439 private void addChild(@NotNull CodegenContext child) { 440 if (shouldAddChild(child)) { 441 if (childContexts == null) { 442 childContexts = new HashMap<DeclarationDescriptor, CodegenContext>(); 443 } 444 DeclarationDescriptor childContextDescriptor = child.getContextDescriptor(); 445 childContexts.put(childContextDescriptor, child); 446 } 447 } 448 449 protected boolean shouldAddChild(@NotNull CodegenContext child) { 450 DeclarationDescriptor childContextDescriptor = child.contextDescriptor; 451 if (childContextDescriptor instanceof ClassDescriptor) { 452 ClassKind kind = ((ClassDescriptor) childContextDescriptor).getKind(); 453 return kind == ClassKind.CLASS_OBJECT; 454 } 455 return false; 456 } 457 458 @Nullable 459 public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) { 460 return childContexts == null ? null : childContexts.get(child); 461 } 462 }