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 }