From 20dc3438a2e474b5bccafa1ba1238f778bee9910 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 19 Jan 2015 19:54:36 +0300 Subject: [PATCH] Fix generation of InnerClasses/EnclosingMethod attributes Generate InnerClasses for each outer class and each direct inner class in all inheritors of MemberCodegen, i.e. for classes, objects, lambdas, local classes, etc. Also skip lambdas which will be inlined when calculating outer class for EnclosingMethod #KT-5447 Fixed #KT-5478 Fixed --- .../org/jetbrains/kotlin/codegen/AsmUtil.java | 11 ++-- .../kotlin/codegen/ClassBodyCodegen.java | 6 +++ .../kotlin/codegen/ClosureCodegen.java | 9 +++- .../codegen/ImplementationBodyCodegen.java | 44 +-------------- .../kotlin/codegen/JvmCodegenUtil.java | 12 +++++ .../kotlin/codegen/MemberCodegen.java | 54 +++++++++++++++++-- .../codegen/binding/CodegenBinding.java | 13 ++--- 7 files changed, 92 insertions(+), 57 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 9d0031157f1..ebae72eb131 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.JetFile; +import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage; @@ -61,6 +62,7 @@ import java.util.Map; import java.util.Set; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface; +import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; @@ -863,15 +865,16 @@ public class AsmUtil { @NotNull DeclarationDescriptor originalDescriptor, @NotNull JetTypeMapper typeMapper ) { + BindingContext bindingContext = typeMapper.getBindingContext(); + DeclarationDescriptor container = classDescriptor.getContainingDeclaration(); while (container != null) { if (container instanceof ClassDescriptor) { return typeMapper.mapClass((ClassDescriptor) container).getInternalName(); } - else if (CodegenBinding.isLocalFunOrLambda(container)) { - ClassDescriptor descriptor = - CodegenBinding.anonymousClassForFunction(typeMapper.getBindingContext(), (FunctionDescriptor) container); - return typeMapper.mapClass(descriptor).getInternalName(); + else if (CodegenBinding.isLocalFunOrLambda(container) && + !JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, container)) { + return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) container).getInternalName(); } container = container.getContainingDeclaration(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java index 0e76b45a8d3..fcc1c540482 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java @@ -128,4 +128,10 @@ public abstract class ClassBodyCodegen extends MemberCodegen { } return Collections.emptyList(); } + + @Nullable + @Override + protected ClassDescriptor classForInnerClassRecord() { + return DescriptorUtils.isTopLevelDeclaration(descriptor) ? null : descriptor; + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index e157a8c8f43..add1a01dcfe 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -146,7 +146,12 @@ public class ClosureCodegen extends MemberCodegen { superInterfaceAsmTypes ); v.visitSource(element.getContainingFile().getName(), null); + } + @Nullable + @Override + protected ClassDescriptor classForInnerClassRecord() { + return JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, funDescriptor) ? null : classDescriptor; } @Override @@ -204,7 +209,7 @@ public class ClosureCodegen extends MemberCodegen { @Override protected void done() { - AsmUtil.writeOuterClassAndEnclosingMethod(classDescriptor, funDescriptor, typeMapper, v); + writeOuterClassAndEnclosingMethod(classDescriptor, funDescriptor, typeMapper, v); super.done(); } @@ -297,7 +302,7 @@ public class ClosureCodegen extends MemberCodegen { int k = 1; for (FieldInfo fieldInfo : args) { - k = AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, k, iv); + k = genAssignInstanceFieldFromParam(fieldInfo, k, iv); } iv.load(0, superClassAsmType); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 87d6d0892e2..2f20cb2e4eb 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -69,7 +69,8 @@ import java.util.*; import static org.jetbrains.kotlin.codegen.AsmUtil.*; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*; -import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*; +import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass; +import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.isLocalNamedFun; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.classDescriptorToDeclaration; import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration; @@ -209,10 +210,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { writeEnclosingMethod(); - writeOuterClasses(); - - writeInnerClasses(); - AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor, null); generateReflectionObjectFieldIfNeeded(); @@ -265,43 +262,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } - private void writeInnerClasses() { - Collection result = bindingContext.get(INNER_CLASSES, descriptor); - if (result != null) { - for (ClassDescriptor innerClass : result) { - writeInnerClass(innerClass); - } - } - } - - private void writeOuterClasses() { - // JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information - // for each enclosing class and for each immediate member - DeclarationDescriptor inner = descriptor; - while (true) { - if (inner == null || isTopLevelDeclaration(inner)) { - break; - } - if (inner instanceof ClassDescriptor) { - writeInnerClass((ClassDescriptor) inner); - } - inner = inner.getContainingDeclaration(); - } - } - - private void writeInnerClass(@NotNull ClassDescriptor innerClass) { - DeclarationDescriptor containing = innerClass.getContainingDeclaration(); - String outerClassInternalName = - containing instanceof ClassDescriptor ? typeMapper.mapClass((ClassDescriptor) containing).getInternalName() : null; - - String innerName = isClassObject(innerClass) - ? JvmAbi.CLASS_OBJECT_CLASS_NAME - : innerClass.getName().isSpecial() ? null : innerClass.getName().asString(); - - String innerClassInternalName = typeMapper.mapClass(innerClass).getInternalName(); - v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass)); - } - @NotNull private JvmClassSignature signature() { BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index 896d78716d1..9e73ca400dc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; import kotlin.Function1; import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; @@ -34,9 +35,13 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass; import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass; import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider; import org.jetbrains.kotlin.psi.JetFile; +import org.jetbrains.kotlin.psi.JetFunctionLiteral; +import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression; import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilPackage; +import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; +import org.jetbrains.kotlin.resolve.InlineDescriptorUtils; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor; import org.jetbrains.kotlin.types.JetType; @@ -224,4 +229,11 @@ public class JvmCodegenUtil { ? ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty() : descriptor; } + + public static boolean isLambdaWhichWillBeInlined(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) { + PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor); + return declaration instanceof JetFunctionLiteral && + declaration.getParent() instanceof JetFunctionLiteralExpression && + InlineDescriptorUtils.isInlineLambda((JetFunctionLiteralExpression) declaration.getParent(), bindingContext, false); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index ae1433da07e..976afe1c2d5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -48,14 +48,14 @@ import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.org.objectweb.asm.commons.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; +import static org.jetbrains.kotlin.codegen.AsmUtil.calculateInnerClassAccessFlags; import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive; import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED; import static org.jetbrains.kotlin.descriptors.SourceElement.NO_SOURCE; import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE; +import static org.jetbrains.kotlin.resolve.DescriptorUtils.isClassObject; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin; import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.TraitImpl; @@ -73,6 +73,7 @@ public abstract class MemberCodegen parentCodegen; private final ReifiedTypeParametersUsages reifiedTypeParametersUsages = new ReifiedTypeParametersUsages(); + protected final Collection innerClasses = new LinkedHashSet(); protected ExpressionCodegen clInit; private NameGenerator inlineNameGenerator; @@ -120,12 +121,19 @@ public abstract class MemberCodegen codegen = this; codegen != null; codegen = codegen.getParentCodegen()) { + ClassDescriptor outerClass = codegen.classForInnerClassRecord(); + if (outerClass != null) { + innerClasses.add(outerClass); + } + } + } + + for (ClassDescriptor innerClass : innerClasses) { + writeInnerClass(innerClass); + } + } + + private void writeInnerClass(@NotNull ClassDescriptor innerClass) { + DeclarationDescriptor containing = innerClass.getContainingDeclaration(); + String outerClassInternalName = + containing instanceof ClassDescriptor ? typeMapper.mapClass((ClassDescriptor) containing).getInternalName() : null; + + String innerName = isClassObject(innerClass) + ? JvmAbi.CLASS_OBJECT_CLASS_NAME + : innerClass.getName().isSpecial() ? null : innerClass.getName().asString(); + + String innerClassInternalName = typeMapper.mapClass(innerClass).getInternalName(); + v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass)); + } + @NotNull public NameGenerator getInlineNameGenerator() { if (inlineNameGenerator == null) { @@ -403,4 +446,9 @@ public abstract class MemberCodegen getParentCodegen() { return parentCodegen; } + + @Override + public String toString() { + return context.toString(); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java index b892fd96125..f86c6d79717 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java @@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.codegen.JvmCodegenUtil; import org.jetbrains.kotlin.codegen.SamType; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping; @@ -60,8 +61,8 @@ public class CodegenBinding { public static final WritableSlice SAM_VALUE = Slices.createSimpleSlice(); - public static final WritableSlice MAPPING_FOR_WHEN_BY_ENUM = Slices. - sliceBuilder().build(); + public static final WritableSlice MAPPING_FOR_WHEN_BY_ENUM = + Slices.sliceBuilder().build(); public static final WritableSlice> MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE = Slices.>sliceBuilder().build(); @@ -169,9 +170,9 @@ public class CodegenBinding { trace.record(ASM_TYPE, classDescriptor, asmType); trace.record(CLOSURE, classDescriptor, closure); - //TEMPORARY EAT INNER CLASS INFO FOR FUNCTION LITERALS - //TODO: we should understand that lambda/closure would be inlined and don't generate inner class record - if (enclosing != null && !(element instanceof JetFunctionLiteral)) { + // Note: at the moment this is needed for light classes only + // TODO: refactor this out + if (enclosing != null && !JvmCodegenUtil.isLambdaWhichWillBeInlined(trace.getBindingContext(), classDescriptor)) { recordInnerClass(trace, enclosing, classDescriptor); } } @@ -183,7 +184,7 @@ public class CodegenBinding { ) { Collection innerClasses = bindingTrace.get(INNER_CLASSES, outer); if (innerClasses == null) { - innerClasses = new ArrayList(); + innerClasses = new ArrayList(1); bindingTrace.record(INNER_CLASSES, outer, innerClasses); } innerClasses.add(inner);