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