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 }