001 /*
002 * Copyright 2010-2015 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.kotlin.codegen.context;
018
019 import kotlin.jvm.functions.Function0;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.kotlin.codegen.*;
023 import org.jetbrains.kotlin.codegen.binding.MutableClosure;
024 import org.jetbrains.kotlin.codegen.state.GenerationState;
025 import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
026 import org.jetbrains.kotlin.descriptors.*;
027 import org.jetbrains.kotlin.resolve.BindingContext;
028 import org.jetbrains.kotlin.resolve.DescriptorUtils;
029 import org.jetbrains.kotlin.storage.LockBasedStorageManager;
030 import org.jetbrains.kotlin.storage.NullableLazyValue;
031 import org.jetbrains.kotlin.types.JetType;
032 import org.jetbrains.org.objectweb.asm.Type;
033
034 import java.util.*;
035
036 import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityAccessFlag;
037 import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
038 import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED;
039
040 public abstract class CodegenContext<T extends DeclarationDescriptor> {
041 public static final CodegenContext STATIC = new RootContext();
042
043 private final T contextDescriptor;
044 private final OwnerKind contextKind;
045 private final CodegenContext parentContext;
046 private final ClassDescriptor thisDescriptor;
047 public final MutableClosure closure;
048 private final LocalLookup enclosingLocalLookup;
049 private final NullableLazyValue<StackValue.Field> outerExpression;
050
051 private Map<DeclarationDescriptor, DeclarationDescriptor> accessors;
052 private Map<DeclarationDescriptor, CodegenContext> childContexts;
053
054 public CodegenContext(
055 @NotNull T contextDescriptor,
056 @NotNull OwnerKind contextKind,
057 @Nullable CodegenContext parentContext,
058 @Nullable MutableClosure closure,
059 @Nullable ClassDescriptor thisDescriptor,
060 @Nullable LocalLookup localLookup
061 ) {
062 this.contextDescriptor = contextDescriptor;
063 this.contextKind = contextKind;
064 this.parentContext = parentContext;
065 this.closure = closure;
066 this.thisDescriptor = thisDescriptor;
067 this.enclosingLocalLookup = localLookup;
068 this.outerExpression = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue(new Function0<StackValue.Field>() {
069 @Override
070 public StackValue.Field invoke() {
071 return computeOuterExpression();
072 }
073 });
074
075 if (parentContext != null) {
076 parentContext.addChild(this);
077 }
078 }
079
080 @NotNull
081 public final ClassDescriptor getThisDescriptor() {
082 if (thisDescriptor == null) {
083 throw new UnsupportedOperationException("Context doesn't have a \"this\": " + this);
084 }
085 return thisDescriptor;
086 }
087
088 public final boolean hasThisDescriptor() {
089 return thisDescriptor != null;
090 }
091
092 @NotNull
093 @SuppressWarnings("unchecked")
094 public CodegenContext<? extends ClassOrPackageFragmentDescriptor> getClassOrPackageParentContext() {
095 CodegenContext<?> context = this;
096 while (true) {
097 if (context.getContextDescriptor() instanceof ClassOrPackageFragmentDescriptor) {
098 return (CodegenContext) context;
099 }
100 context = context.getParentContext();
101 assert context != null : "Context which is not top-level has no parent: " + this;
102 }
103 }
104
105 /**
106 * This method returns not null only if context descriptor corresponds to method or function which has receiver
107 */
108 @Nullable
109 public final CallableDescriptor getCallableDescriptorWithReceiver() {
110 if (contextDescriptor instanceof CallableDescriptor) {
111 CallableDescriptor callableDescriptor = (CallableDescriptor) getContextDescriptor();
112 return callableDescriptor.getExtensionReceiverParameter() != null ? callableDescriptor : null;
113 }
114 return null;
115 }
116
117 public StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter) {
118 return getOuterExpression(prefix, ignoreNoOuter, true);
119 }
120
121 private StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter, boolean captureThis) {
122 if (outerExpression.invoke() == null) {
123 if (!ignoreNoOuter) {
124 throw new UnsupportedOperationException("Don't know how to generate outer expression for " + getContextDescriptor());
125 }
126 return null;
127 }
128 if (captureThis) {
129 if (closure == null) {
130 throw new IllegalStateException("Can't capture this for context without closure: " + getContextDescriptor());
131 }
132 closure.setCaptureThis();
133 }
134 return StackValue.changeReceiverForFieldAndSharedVar(outerExpression.invoke(), prefix);
135 }
136
137 @NotNull
138 public T getContextDescriptor() {
139 return contextDescriptor;
140 }
141
142 @NotNull
143 public OwnerKind getContextKind() {
144 return contextKind;
145 }
146
147 @NotNull
148 public PackageContext intoPackagePart(@NotNull PackageFragmentDescriptor descriptor, Type packagePartType) {
149 return new PackageContext(descriptor, this, packagePartType);
150 }
151
152 @NotNull
153 public FieldOwnerContext intoPackageFacade(@NotNull Type delegateTo, @NotNull PackageFragmentDescriptor descriptor) {
154 return new PackageFacadeContext(descriptor, this, delegateTo);
155 }
156
157 @NotNull
158 public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
159 return new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
160 }
161
162 @NotNull
163 public ClassContext intoAnonymousClass(@NotNull ClassDescriptor descriptor, @NotNull ExpressionCodegen codegen, @NotNull OwnerKind ownerKind) {
164 return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, this, codegen);
165 }
166
167 @NotNull
168 public MethodContext intoFunction(FunctionDescriptor descriptor) {
169 return new MethodContext(descriptor, getContextKind(), this, null, false);
170 }
171
172 @NotNull
173 public MethodContext intoInlinedLambda(FunctionDescriptor descriptor) {
174 return new MethodContext(descriptor, getContextKind(), this, null, true);
175 }
176
177 @NotNull
178 public ConstructorContext intoConstructor(@NotNull ConstructorDescriptor descriptor) {
179 return new ConstructorContext(descriptor, getContextKind(), this, closure);
180 }
181
182 // SCRIPT: generate into script, move to ScriptingUtil
183 @NotNull
184 public ScriptContext intoScript(
185 @NotNull ScriptDescriptor script,
186 @NotNull List<ScriptDescriptor> earlierScripts,
187 @NotNull ClassDescriptor classDescriptor
188 ) {
189 return new ScriptContext(script, earlierScripts, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure);
190 }
191
192 @NotNull
193 public ClosureContext intoClosure(
194 @NotNull FunctionDescriptor funDescriptor,
195 @NotNull LocalLookup localLookup,
196 @NotNull JetTypeMapper typeMapper
197 ) {
198 return new ClosureContext(typeMapper, funDescriptor, this, localLookup);
199 }
200
201 @Nullable
202 public CodegenContext getParentContext() {
203 return parentContext;
204 }
205
206 public ClassDescriptor getEnclosingClass() {
207 CodegenContext cur = getParentContext();
208 while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) {
209 cur = cur.getParentContext();
210 }
211
212 return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor();
213 }
214
215 @Nullable
216 public CodegenContext findParentContextWithDescriptor(DeclarationDescriptor descriptor) {
217 CodegenContext c = this;
218 while (c != null) {
219 if (c.getContextDescriptor() == descriptor) break;
220 c = c.getParentContext();
221 }
222 return c;
223 }
224
225 @NotNull
226 public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor) {
227 return getAccessor(descriptor, false, null);
228 }
229
230 @NotNull
231 public DeclarationDescriptor getAccessor(@NotNull DeclarationDescriptor descriptor, boolean isForBackingFieldInOuterClass, @Nullable JetType delegateType) {
232 if (accessors == null) {
233 accessors = new LinkedHashMap<DeclarationDescriptor, DeclarationDescriptor>();
234 }
235 descriptor = descriptor.getOriginal();
236 DeclarationDescriptor accessor = accessors.get(descriptor);
237 if (accessor != null) {
238 assert !isForBackingFieldInOuterClass ||
239 accessor instanceof AccessorForPropertyBackingFieldInOuterClass : "There is already exists accessor with isForBackingFieldInOuterClass = false in this context";
240 return accessor;
241 }
242
243 int accessorIndex = accessors.size();
244 if (descriptor instanceof SimpleFunctionDescriptor || descriptor instanceof ConstructorDescriptor) {
245 accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessorIndex);
246 }
247 else if (descriptor instanceof PropertyDescriptor) {
248 if (isForBackingFieldInOuterClass) {
249 accessor = new AccessorForPropertyBackingFieldInOuterClass((PropertyDescriptor) descriptor, contextDescriptor,
250 accessorIndex, delegateType);
251 } else {
252 accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessorIndex);
253 }
254 }
255 else {
256 throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
257 }
258 accessors.put(descriptor, accessor);
259 return accessor;
260 }
261
262 @Nullable
263 protected StackValue.Field computeOuterExpression() {
264 return null;
265 }
266
267 public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
268 StackValue myOuter = null;
269 if (closure != null) {
270 EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d);
271 if (answer != null) {
272 return StackValue.changeReceiverForFieldAndSharedVar(answer.getInnerValue(), result);
273 }
274
275 for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
276 if (aCase.isCase(d)) {
277 Type classType = state.getTypeMapper().mapType(getThisDescriptor());
278 StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
279 if (innerValue == null) {
280 break;
281 }
282 else {
283 return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result);
284 }
285 }
286 }
287
288 myOuter = getOuterExpression(result, ignoreNoOuter, false);
289 result = myOuter;
290 }
291
292 StackValue resultValue;
293 if (myOuter != null && getEnclosingClass() == d) {
294 resultValue = result;
295 } else {
296 resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
297 }
298
299 if (myOuter != null && resultValue != null && !isStaticField(resultValue)) {
300 closure.setCaptureThis();
301 }
302 return resultValue;
303 }
304
305 @NotNull
306 public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() {
307 return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors;
308 }
309
310 @NotNull
311 public PropertyDescriptor accessiblePropertyDescriptor(PropertyDescriptor propertyDescriptor) {
312 return (PropertyDescriptor) accessibleDescriptorIfNeeded(propertyDescriptor, true);
313 }
314
315 @NotNull
316 public FunctionDescriptor accessibleFunctionDescriptor(FunctionDescriptor fd) {
317 return (FunctionDescriptor) accessibleDescriptorIfNeeded(fd, true);
318 }
319
320 public void recordSyntheticAccessorIfNeeded(@NotNull FunctionDescriptor fd, @NotNull BindingContext bindingContext) {
321 if (fd instanceof ConstructorDescriptor || needSyntheticAccessorInBindingTrace(fd, bindingContext)) {
322 accessibleDescriptorIfNeeded(fd, false);
323 }
324 }
325
326 public void recordSyntheticAccessorIfNeeded(@NotNull PropertyDescriptor propertyDescriptor, @NotNull BindingContext typeMapper) {
327 if (needSyntheticAccessorInBindingTrace(propertyDescriptor, typeMapper)) {
328 accessibleDescriptorIfNeeded(propertyDescriptor, false);
329 }
330 }
331
332 private static boolean needSyntheticAccessorInBindingTrace(
333 @NotNull CallableMemberDescriptor descriptor,
334 @NotNull BindingContext bindingContext
335 ) {
336 return Boolean.TRUE.equals(bindingContext.get(BindingContext.NEED_SYNTHETIC_ACCESSOR, descriptor));
337 }
338
339 private static int getAccessFlags(@NotNull CallableMemberDescriptor descriptor) {
340 int flag = getVisibilityAccessFlag(descriptor);
341 if (descriptor instanceof PropertyDescriptor) {
342 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
343
344 PropertySetterDescriptor setter = propertyDescriptor.getSetter();
345 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
346
347 flag |= (getter == null ? 0 : getVisibilityAccessFlag(getter)) |
348 (setter == null ? 0 : getVisibilityAccessFlag(setter));
349 }
350 return flag;
351 }
352
353 @NotNull
354 private MemberDescriptor accessibleDescriptorIfNeeded(CallableMemberDescriptor descriptor, boolean fromOutsideContext) {
355 CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
356 int flag = getAccessFlags(unwrappedDescriptor);
357 if ((flag & ACC_PRIVATE) == 0 && (flag & ACC_PROTECTED) == 0) {
358 return descriptor;
359 }
360
361 CodegenContext descriptorContext = null;
362 if (!fromOutsideContext || getClassOrPackageParentContext().getContextDescriptor() != descriptor.getContainingDeclaration()) {
363 DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
364 boolean isCompanionObjectMember = DescriptorUtils.isCompanionObject(enclosed);
365 //go upper
366 if (hasThisDescriptor() && (enclosed != getThisDescriptor() || !fromOutsideContext)) {
367 CodegenContext currentContext = this;
368 while (currentContext != null) {
369 if (currentContext.getContextDescriptor() == enclosed) {
370 descriptorContext = currentContext;
371 break;
372 }
373
374 //accessors for private members in companion object for call from class
375 if (isCompanionObjectMember && currentContext instanceof ClassContext) {
376 ClassContext classContext = (ClassContext) currentContext;
377 CodegenContext companionObjectContext = classContext.getCompanionObjectContext();
378 if (companionObjectContext != null && companionObjectContext.getContextDescriptor() == enclosed) {
379 descriptorContext = companionObjectContext;
380 break;
381 }
382 }
383
384 currentContext = currentContext.getParentContext();
385 }
386 }
387 }
388
389 if (descriptorContext == null) {
390 return descriptor;
391 }
392
393 if ((flag & ACC_PROTECTED) != 0) {
394 PackageFragmentDescriptor unwrappedDescriptorPackage =
395 DescriptorUtils.getParentOfType(unwrappedDescriptor, PackageFragmentDescriptor.class, false);
396 PackageFragmentDescriptor contextDescriptorPackage =
397 DescriptorUtils.getParentOfType(descriptorContext.getContextDescriptor(), PackageFragmentDescriptor.class, false);
398
399 boolean inSamePackage = contextDescriptorPackage != null && unwrappedDescriptorPackage != null &&
400 unwrappedDescriptorPackage.getFqName().equals(contextDescriptorPackage.getFqName());
401 if (inSamePackage) {
402 return descriptor;
403 }
404 }
405
406 return (MemberDescriptor) descriptorContext.getAccessor(descriptor);
407 }
408
409 private void addChild(@NotNull CodegenContext child) {
410 if (shouldAddChild(child)) {
411 if (childContexts == null) {
412 childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
413 }
414 DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
415 childContexts.put(childContextDescriptor, child);
416 }
417 }
418
419 protected boolean shouldAddChild(@NotNull CodegenContext child) {
420 return DescriptorUtils.isCompanionObject(child.contextDescriptor);
421 }
422
423 @Nullable
424 public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
425 return childContexts == null ? null : childContexts.get(child);
426 }
427
428 private static boolean isStaticField(@NotNull StackValue value) {
429 return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
430 }
431 }