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