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 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 }