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