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 import org.jetbrains.jet.lang.resolve.java.JvmClassName; 033 034 import java.util.Collections; 035 import java.util.HashMap; 036 import java.util.Map; 037 038 import static org.jetbrains.asm4.Opcodes.ACC_PRIVATE; 039 import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_THIS_FIELD; 040 import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityAccessFlag; 041 import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; 042 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; 043 044 public abstract class CodegenContext<T extends DeclarationDescriptor> { 045 046 public static final CodegenContext STATIC = new RootContext(); 047 048 @NotNull 049 private final T contextDescriptor; 050 051 @NotNull 052 private final OwnerKind contextKind; 053 054 @Nullable 055 private final CodegenContext parentContext; 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, OwnerKind.NAMESPACE); 153 } 154 155 @NotNull 156 public FieldOwnerContext intoNamespacePart(@NotNull JvmClassName delegateTo, @NotNull NamespaceDescriptor descriptor) { 157 return new NamespaceContext(descriptor, this, new OwnerKind.StaticDelegateKind(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 CodegenContext 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.getJvmInternalName(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 StackValue innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, state.getBindingContext().get(FQN, getThisDescriptor())); 299 if (innerValue == null) { 300 break; 301 } 302 else { 303 return result == null ? innerValue : StackValue.composed(result, innerValue); 304 } 305 } 306 } 307 308 StackValue outer = getOuterExpression(null, ignoreNoOuter); 309 result = result == null || outer == null ? outer : StackValue.composed(result, outer); 310 } 311 312 return parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null; 313 } 314 315 @NotNull 316 public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() { 317 return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors; 318 } 319 320 @NotNull 321 public PropertyDescriptor accessiblePropertyDescriptor(PropertyDescriptor propertyDescriptor) { 322 return (PropertyDescriptor) accessibleDescriptorIfNeeded(propertyDescriptor, true); 323 } 324 325 @NotNull 326 public FunctionDescriptor accessibleFunctionDescriptor(FunctionDescriptor fd) { 327 return (FunctionDescriptor) accessibleDescriptorIfNeeded(fd, true); 328 } 329 330 @NotNull 331 public void recordSyntheticAccessorIfNeeded(@NotNull FunctionDescriptor fd, @NotNull JetTypeMapper typeMapper) { 332 if (fd instanceof ConstructorDescriptor || needSyntheticAccessorInBindingTrace(fd, typeMapper)) { 333 accessibleDescriptorIfNeeded(fd, false); 334 } 335 } 336 337 @NotNull 338 public void recordSyntheticAccessorIfNeeded(PropertyDescriptor propertyDescriptor, JetTypeMapper typeMapper) { 339 if (needSyntheticAccessorInBindingTrace(propertyDescriptor, typeMapper)) { 340 accessibleDescriptorIfNeeded(propertyDescriptor, false); 341 } 342 } 343 344 private boolean needSyntheticAccessorInBindingTrace(@NotNull CallableMemberDescriptor descriptor, @NotNull JetTypeMapper typeMapper) { 345 Boolean result = typeMapper.getBindingContext().get(BindingContext.NEED_SYNTHETIC_ACCESSOR, descriptor); 346 return result == null ? false : result.booleanValue(); 347 } 348 349 @NotNull 350 private int getAccessFlags(CallableMemberDescriptor descriptor) { 351 int flag = getVisibilityAccessFlag(descriptor); 352 if (descriptor instanceof PropertyDescriptor) { 353 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; 354 355 PropertySetterDescriptor setter = propertyDescriptor.getSetter(); 356 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 357 358 flag |= (getter == null ? 0 : getVisibilityAccessFlag(getter)) | 359 (setter == null ? 0 : getVisibilityAccessFlag(setter)); 360 } 361 return flag; 362 } 363 364 @NotNull 365 private MemberDescriptor accessibleDescriptorIfNeeded(CallableMemberDescriptor descriptor, boolean fromOutsideContext) { 366 int flag = getAccessFlags(descriptor); 367 if ((flag & ACC_PRIVATE) == 0) { 368 return descriptor; 369 } 370 371 CodegenContext descriptorContext = null; 372 if (!fromOutsideContext || getClassOrNamespaceDescriptor() != descriptor.getContainingDeclaration()) { 373 DeclarationDescriptor enclosed = descriptor.getContainingDeclaration(); 374 boolean isClassObjectMember = DescriptorUtils.isClassObject(enclosed); 375 //go upper 376 if (hasThisDescriptor() && (enclosed != getThisDescriptor() || !fromOutsideContext)) { 377 CodegenContext currentContext = this; 378 while (currentContext != null) { 379 if (currentContext.getContextDescriptor() == enclosed) { 380 descriptorContext = currentContext; 381 break; 382 } 383 384 //accessors for private members in class object for call from class 385 if (isClassObjectMember && currentContext instanceof ClassContext) { 386 ClassContext classContext = (ClassContext) currentContext; 387 CodegenContext classObject = classContext.getClassObjectContext(); 388 if (classObject != null && classObject.getContextDescriptor() == enclosed) { 389 descriptorContext = classObject; 390 break; 391 } 392 } 393 394 currentContext = currentContext.getParentContext(); 395 } 396 } 397 } 398 399 return (MemberDescriptor) (descriptorContext != null ? descriptorContext.getAccessor(descriptor) : descriptor); 400 } 401 402 private void addChild(@NotNull CodegenContext child) { 403 if (shouldAddChild(child)) { 404 if (childContexts == null) { 405 childContexts = new HashMap<DeclarationDescriptor, CodegenContext>(); 406 } 407 DeclarationDescriptor childContextDescriptor = child.getContextDescriptor(); 408 childContexts.put(childContextDescriptor, child); 409 } 410 } 411 412 protected boolean shouldAddChild(@NotNull CodegenContext child) { 413 DeclarationDescriptor childContextDescriptor = child.contextDescriptor; 414 if (childContextDescriptor instanceof ClassDescriptor) { 415 ClassKind kind = ((ClassDescriptor) childContextDescriptor).getKind(); 416 return kind == ClassKind.CLASS_OBJECT; 417 } 418 return false; 419 } 420 421 @Nullable 422 public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) { 423 return childContexts == null ? null : childContexts.get(child); 424 } 425 }