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);