Use CodegenContext to determine outer class & enclosing method

This commit is contained in:
Alexander Udalov
2015-02-11 00:38:44 +03:00
parent c417d984c4
commit 9b28e19551
8 changed files with 239 additions and 156 deletions
@@ -203,7 +203,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
@Override
protected void done() {
writeOuterClassAndEnclosingMethod(classDescriptor);
writeOuterClassAndEnclosingMethod();
super.done();
}
@@ -256,7 +256,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
//JVMS7: A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class.
if (isAnonymousObject(descriptor) || !(descriptor.getContainingDeclaration() instanceof ClassOrPackageFragmentDescriptor)) {
writeOuterClassAndEnclosingMethod(descriptor);
writeOuterClassAndEnclosingMethod();
}
}
@@ -20,10 +20,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import kotlin.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.context.ClassContext;
import org.jetbrains.kotlin.codegen.context.CodegenContext;
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
import org.jetbrains.kotlin.codegen.inline.NameGenerator;
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages;
@@ -37,11 +34,15 @@ import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.SpecialNames;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.storage.NotNullLazyValue;
import org.jetbrains.kotlin.types.ErrorUtils;
@@ -249,41 +250,47 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass));
}
protected void writeOuterClassAndEnclosingMethod(@NotNull ClassDescriptor descriptor) {
ClassDescriptor outerClass = findOuterClass(descriptor);
String outerClassName = outerClass != null
? typeMapper.mapClass(outerClass).getInternalName()
: PackagePartClassUtils.getPackagePartInternalName(element.getContainingJetFile());
FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
while (function != null && JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, function)) {
function = DescriptorUtils.getParentOfType(function, FunctionDescriptor.class);
protected void writeOuterClassAndEnclosingMethod() {
CodegenContext context = this.context.getParentContext();
while (context instanceof MethodContext && ((MethodContext) context).isInliningLambda()) {
// If this is a lambda which will be inlined, skip its MethodContext and enclosing ClosureContext
//noinspection ConstantConditions
context = context.getParentContext().getParentContext();
}
assert context != null : "Outermost context can't be null: " + this.context;
if (function != null) {
Method method = typeMapper.mapSignature(function).getAsmMethod();
v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor());
}
else {
v.visitOuterClass(outerClassName, null, null);
Type enclosingAsmType = computeOuterClass(context);
if (enclosingAsmType != null) {
Method method = computeEnclosingMethod(context);
v.visitOuterClass(
enclosingAsmType.getInternalName(),
method == null ? null : method.getName(),
method == null ? null : method.getDescriptor()
);
}
}
@Nullable
private ClassDescriptor findOuterClass(@NotNull ClassDescriptor classDescriptor) {
DeclarationDescriptor container = classDescriptor.getContainingDeclaration();
while (container != null) {
if (container instanceof ClassDescriptor) {
return (ClassDescriptor) container;
}
else if (CodegenBinding.isLocalFunOrLambda(container) &&
!JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, container)) {
return CodegenBinding.anonymousClassForFunction(bindingContext, (FunctionDescriptor) container);
}
container = container.getContainingDeclaration();
private Type computeOuterClass(@NotNull CodegenContext<?> context) {
CodegenContext<? extends ClassOrPackageFragmentDescriptor> outermost = context.getClassOrPackageParentContext();
if (outermost instanceof ClassContext) {
return typeMapper.mapType(((ClassContext) outermost).getContextDescriptor());
}
else if (outermost instanceof PackageContext && !(outermost instanceof PackageFacadeContext)) {
return PackagePartClassUtils.getPackagePartType(element.getContainingJetFile());
}
return null;
}
@Nullable
private Method computeEnclosingMethod(@NotNull CodegenContext context) {
if (context instanceof MethodContext) {
Method method = typeMapper.mapSignature(((MethodContext) context).getFunctionDescriptor()).getAsmMethod();
if (!method.getName().equals("<clinit>")) {
return method;
}
}
return null;
}
@@ -304,7 +311,9 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
SimpleFunctionDescriptorImpl clInit =
SimpleFunctionDescriptorImpl.create(descriptor, Annotations.EMPTY, Name.special("<clinit>"), SYNTHESIZED, NO_SOURCE);
clInit.initialize(null, null, Collections.<TypeParameterDescriptor>emptyList(),
Collections.<ValueParameterDescriptor>emptyList(), null, null, Visibilities.PRIVATE);
Collections.<ValueParameterDescriptor>emptyList(),
DescriptorUtilPackage.getModule(descriptor).getBuiltIns().getUnitType(),
null, Visibilities.PRIVATE);
this.clInit = new ExpressionCodegen(mv, new FrameMap(), Type.VOID_TYPE, context.intoFunction(clInit), state, this);
}
@@ -34,16 +34,21 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
private Label methodStartLabel;
private Label methodEndLabel;
// Note: in case of code inside property accessors, functionDescriptor will be that accessor,
// but CodegenContext#contextDescriptor will be the corresponding property
private final FunctionDescriptor functionDescriptor;
protected MethodContext(
@NotNull FunctionDescriptor contextDescriptor,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull OwnerKind contextKind,
@NotNull CodegenContext parentContext,
@Nullable MutableClosure closure,
boolean isInliningLambda
) {
super(JvmCodegenUtil.getDirectMember(contextDescriptor), contextKind, parentContext, closure,
super(JvmCodegenUtil.getDirectMember(functionDescriptor), contextKind, parentContext, closure,
parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null, null);
this.isInliningLambda = isInliningLambda;
this.functionDescriptor = functionDescriptor;
}
@NotNull
@@ -118,4 +123,8 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
return isInliningLambda;
}
@NotNull
public FunctionDescriptor getFunctionDescriptor() {
return functionDescriptor;
}
}