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