From 1497c19dc91b707e40ddb631acd13b89958d4c74 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Sun, 5 Aug 2018 05:24:26 +0300 Subject: [PATCH] Do not generate useless methods inside wrapper for inline class Fix for test data (inlineFunctionInsideInlineClassesBox.kt) is needed to avoid check about "no inline functions". This check has two steps: first, names of inline functions from the metadata are loaded, then these names are checked that they are presented for physical methods in the classfile. Because now there are no physical methods in the classfile, we can't pass the second check, therefore this fix is needed. #KT-24872 Fixed --- .../kotlin/codegen/FunctionCodegen.java | 21 +++++++++++++++---- .../inlineFunctionInsideInlineClassesBox.kt | 2 ++ .../companionObjectInsideInlineClass.txt | 1 - .../computablePropertiesInsideInlineClass.txt | 2 -- .../shapeOfInlineClassWithPrimitive.txt | 3 --- .../callMemberMethodsInsideInlineClass.kt | 6 +++--- ...tualCallsOfInlineFunctionsOfInlineClass.kt | 8 +++---- 7 files changed, 26 insertions(+), 17 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 981a5045fbc..9f2fc37b99f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -196,6 +196,10 @@ public class FunctionCodegen { return; } + if (!shouldGenerateMethodInsideInlineClass(origin, functionDescriptor, contextKind, containingDeclaration)) { + return; + } + boolean hasSpecialBridge = hasSpecialBridgeMethod(functionDescriptor); JvmMethodGenericSignature jvmSignature = strategy.mapMethodSignature(functionDescriptor, typeMapper, contextKind, hasSpecialBridge); Method asmMethod = jvmSignature.getAsmMethod(); @@ -255,7 +259,7 @@ public class FunctionCodegen { origin, functionDescriptor, methodContext, strategy, mv, jvmSignature, asmMethod, flags, staticInCompanionObject ); } - else if (shouldDelegateMethodBodyToInlineClass(origin, functionDescriptor, contextKind, containingDeclaration, bindingContext)) { + else if (canDelegateMethodBodyToInlineClass(origin, functionDescriptor, contextKind, containingDeclaration)) { generateMethodInsideInlineClassWrapper(origin, functionDescriptor, (ClassDescriptor) containingDeclaration, mv, typeMapper); } else { @@ -277,12 +281,21 @@ public class FunctionCodegen { return v.newMethod(origin, access, name, desc, signature, exceptions); } - private static boolean shouldDelegateMethodBodyToInlineClass( + private static boolean shouldGenerateMethodInsideInlineClass( @NotNull JvmDeclarationOrigin origin, @NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind contextKind, - @NotNull DeclarationDescriptor containingDeclaration, - @NotNull BindingContext bindingContext + @NotNull DeclarationDescriptor containingDeclaration + ) { + return !canDelegateMethodBodyToInlineClass(origin, functionDescriptor, contextKind, containingDeclaration) || + !functionDescriptor.getOverriddenDescriptors().isEmpty(); + } + + private static boolean canDelegateMethodBodyToInlineClass( + @NotNull JvmDeclarationOrigin origin, + @NotNull FunctionDescriptor functionDescriptor, + @NotNull OwnerKind contextKind, + @NotNull DeclarationDescriptor containingDeclaration ) { // special kind / function if (contextKind == OwnerKind.ERASED_INLINE_CLASS) return false; diff --git a/compiler/testData/codegen/boxInline/inlineClasses/inlineFunctionInsideInlineClassesBox.kt b/compiler/testData/codegen/boxInline/inlineClasses/inlineFunctionInsideInlineClassesBox.kt index 819412bf417..f8ddd877767 100644 --- a/compiler/testData/codegen/boxInline/inlineClasses/inlineFunctionInsideInlineClassesBox.kt +++ b/compiler/testData/codegen/boxInline/inlineClasses/inlineFunctionInsideInlineClassesBox.kt @@ -11,6 +11,8 @@ inline class A(val x: Int) { inline fun result(other: A): String = if (other.x == x) "OK" else "fail" } +inline fun stub() {} + // FILE: 2.kt import test.* diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/companionObjectInsideInlineClass.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/companionObjectInsideInlineClass.txt index b29d85b411d..57a51ba002d 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/companionObjectInsideInlineClass.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/companionObjectInsideInlineClass.txt @@ -27,7 +27,6 @@ public final class Foo { public method equals(p0: java.lang.Object): boolean public final method getX(): int public method hashCode(): int - public final method inInlineClass(): void public method toString(): java.lang.String public final method unbox(): int } diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/computablePropertiesInsideInlineClass.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/computablePropertiesInsideInlineClass.txt index b248450aba2..3717a0419a4 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/computablePropertiesInsideInlineClass.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/computablePropertiesInsideInlineClass.txt @@ -14,8 +14,6 @@ public final class Foo { private final field x: int public method (p0: int): void public method equals(p0: java.lang.Object): boolean - public final method getAsThis(): int - public final method getProp(): int public final method getX(): int public method hashCode(): int public method toString(): java.lang.String diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrimitive.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrimitive.txt index eba35f9bf13..1c9f4750644 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrimitive.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrimitive.txt @@ -14,12 +14,9 @@ public final static class Foo$Erased { public final class Foo { private final field l: long public method (p0: long): void - public final method empty(): void public method equals(p0: java.lang.Object): boolean - public final method extension(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: java.lang.String): void public final method getL(): long public method hashCode(): int - public final method param(p0: double): void public method toString(): java.lang.String public final method unbox(): long } diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt index 5c2780010fb..e9b32168813 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt @@ -12,7 +12,7 @@ inline class Foo(val x: Int) { } } -// 2 INVOKESTATIC Foo\$Erased.empty \(I\)V -// 2 INVOKESTATIC Foo\$Erased.withParam \(ILjava/lang/String;\)V -// 2 INVOKESTATIC Foo\$Erased.withInlineClassParam \(II\)V +// 1 INVOKESTATIC Foo\$Erased.empty \(I\)V +// 1 INVOKESTATIC Foo\$Erased.withParam \(ILjava/lang/String;\)V +// 1 INVOKESTATIC Foo\$Erased.withInlineClassParam \(II\)V // 5 INVOKEVIRTUAL \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt index 632a1c0b06e..7613aa5572a 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt @@ -1,7 +1,7 @@ // !LANGUAGE: +InlineClasses inline class Foo(val x: Int) { - inline fun inlineInc(): Foo = Foo(x + 1) // one actual call inside wrapper class Foo + inline fun inlineInc(): Foo = Foo(x + 1) fun notInlineInc(): Foo = Foo(x + 1) fun foo() { @@ -11,8 +11,8 @@ inline class Foo(val x: Int) { fun test(f: Foo) { f.inlineInc().inlineInc().inlineInc() - f.notInlineInc() // one here, one inside wrapper class Foo + f.notInlineInc() // one here } -// 1 INVOKESTATIC Foo\$Erased.inlineInc -// 2 INVOKESTATIC Foo\$Erased.notInlineInc +// 0 INVOKESTATIC Foo\$Erased.inlineInc +// 1 INVOKESTATIC Foo\$Erased.notInlineInc