From b4051c45775232c976d81e8fcab793c49f5a9568 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 23 Dec 2016 18:24:26 +0300 Subject: [PATCH] Do not generate unnecessary super-call checks for functions with defaults Such check should only be generated for a function in an open class #KT-11962 Fixed --- .../kotlin/codegen/FunctionCodegen.java | 24 +++++++++++-------- .../box/defaultArguments/superCallCheck.kt | 20 ++++++++-------- .../argumentReorderWithDefault.kt | 7 +++--- .../argumentOrder/sameOrderWithDefault.kt | 7 +++--- .../bytecodeText/defaultArguments/kt11962.kt | 17 +++++++++++++ .../jackAndJill/inlineDefaultBody.kt | 13 ---------- .../jackAndJill/inlineDefaultBodyInClass.kt | 2 +- .../codegen/BytecodeTextTestGenerated.java | 21 +++++++++++----- 8 files changed, 65 insertions(+), 46 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeText/defaultArguments/kt11962.kt delete mode 100644 compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBody.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index b9bc0288fd0..39632678a0a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -918,7 +918,7 @@ public class FunctionCodegen { CallGenerator generator = codegen.getOrCreateCallGeneratorForDefaultImplBody(functionDescriptor, function); InstructionAdapter iv = new InstructionAdapter(mv); - genDefaultSuperCallCheckIfNeeded(iv, defaultMethod); + genDefaultSuperCallCheckIfNeeded(iv, functionDescriptor, defaultMethod); loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator); @@ -961,19 +961,23 @@ public class FunctionCodegen { iv.areturn(signature.getReturnType()); } - private static void genDefaultSuperCallCheckIfNeeded(@NotNull InstructionAdapter iv, @NotNull Method defaultMethod) { - String defaultMethodName = defaultMethod.getName(); - if ("".equals(defaultMethodName)) { - return; - } + private static void genDefaultSuperCallCheckIfNeeded( + @NotNull InstructionAdapter iv, @NotNull FunctionDescriptor descriptor, @NotNull Method defaultMethod + ) { + if (descriptor instanceof ConstructorDescriptor) return; + + DeclarationDescriptor container = descriptor.getContainingDeclaration(); + if (!(container instanceof ClassDescriptor)) return; + if (((ClassDescriptor) container).getModality() == Modality.FINAL) return; + Label end = new Label(); int handleIndex = (Type.getArgumentsAndReturnSizes(defaultMethod.getDescriptor()) >> 2) - 2; /*-1 for this, and -1 for handle*/ iv.load(handleIndex, OBJECT_TYPE); iv.ifnull(end); - AsmUtil.genThrow(iv, - "java/lang/UnsupportedOperationException", - "Super calls with default arguments not supported in this target, function: " + - StringsKt.substringBeforeLast(defaultMethodName, JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, defaultMethodName)); + AsmUtil.genThrow( + iv, "java/lang/UnsupportedOperationException", + "Super calls with default arguments not supported in this target, function: " + descriptor.getName().asString() + ); iv.visitLabel(end); } diff --git a/compiler/testData/codegen/box/defaultArguments/superCallCheck.kt b/compiler/testData/codegen/box/defaultArguments/superCallCheck.kt index a00d10aaea6..0d939974c2a 100644 --- a/compiler/testData/codegen/box/defaultArguments/superCallCheck.kt +++ b/compiler/testData/codegen/box/defaultArguments/superCallCheck.kt @@ -3,25 +3,25 @@ // WITH_RUNTIME -fun def(i: Int = 0): Int { - return i; +open class MyClass { + fun def(i: Int = 0): Int { + return i + } } fun box():String { - val clazz = Class.forName("SuperCallCheckKt") - - val method = clazz.getMethod("def\$default", Int::class.java, Int::class.java, Any::class.java) - val result = method.invoke(null, -1, 1, null) + val method = MyClass::class.java.getMethod("def\$default", MyClass::class.java, Int::class.java, Int::class.java, Any::class.java) + val result = method.invoke(null, MyClass(), -1, 1, null) if (result != 0) return "fail 1: $result" var failed = false try { - method.invoke(null, -1, 1, "fail") - } catch(e: Exception) { + method.invoke(null, MyClass(), -1, 1, "fail") + } + catch(e: Exception) { val cause = e.cause - if (cause is java.lang.UnsupportedOperationException && - cause.message!!.startsWith("Super calls")) { + if (cause is UnsupportedOperationException && cause.message!!.startsWith("Super calls")) { failed = true } } diff --git a/compiler/testData/codegen/bytecodeText/argumentOrder/argumentReorderWithDefault.kt b/compiler/testData/codegen/bytecodeText/argumentOrder/argumentReorderWithDefault.kt index 9e8f05bd9e0..8cec4579499 100644 --- a/compiler/testData/codegen/bytecodeText/argumentOrder/argumentReorderWithDefault.kt +++ b/compiler/testData/codegen/bytecodeText/argumentOrder/argumentReorderWithDefault.kt @@ -8,6 +8,7 @@ class A { return "OK" } } -// Test argument reordering when call site argument order differs from declaration one: 18 + 1 for super call check -// 13 LOAD -// 5 STORE \ No newline at end of file + +// Test argument reordering when call site argument order differs from declaration one +// 12 LOAD +// 5 STORE diff --git a/compiler/testData/codegen/bytecodeText/argumentOrder/sameOrderWithDefault.kt b/compiler/testData/codegen/bytecodeText/argumentOrder/sameOrderWithDefault.kt index bc80dfd8f74..971d79fa3ca 100644 --- a/compiler/testData/codegen/bytecodeText/argumentOrder/sameOrderWithDefault.kt +++ b/compiler/testData/codegen/bytecodeText/argumentOrder/sameOrderWithDefault.kt @@ -7,6 +7,7 @@ class A { return "OK" } } -// Test there is no argument reordering when call site argument order same as declaration one: 15 + 1 for super call check -// 10 LOAD -// 2 STORE \ No newline at end of file + +// Test there is no argument reordering when call site argument order same as declaration one +// 9 LOAD +// 2 STORE diff --git a/compiler/testData/codegen/bytecodeText/defaultArguments/kt11962.kt b/compiler/testData/codegen/bytecodeText/defaultArguments/kt11962.kt new file mode 100644 index 00000000000..e95b0d2036e --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/defaultArguments/kt11962.kt @@ -0,0 +1,17 @@ +// KT-11962 Super call with default parameters check is generated for top-level function + +fun foo(x: Int = 1) { } + +class FinalClass { + fun bar(x: Int = 2) { } +} + +object Object { + fun baz(x: Int = 3) { } +} + +fun test() { + fun local(x: Int = 4) { } +} + +// 0 ATHROW diff --git a/compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBody.kt b/compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBody.kt deleted file mode 100644 index 3799f94a720..00000000000 --- a/compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBody.kt +++ /dev/null @@ -1,13 +0,0 @@ -inline fun test(a: Int = 1, b: Long = 1L, c: String = "123") { - val d = 1 -} - -// -// 1 test\$default\(IJLjava/lang/String;ILjava/lang/Object;\)V\s+L0 -// 1 LOCALVARIABLE a I L0 L8 0 -// 1 LOCALVARIABLE b J L0 L8 1 -// 1 LOCALVARIABLE c Ljava/lang/String; L0 L8 3 -// 1 LOCALVARIABLE \$i\$f\$test I L5 L8 4 -// 1 LOCALVARIABLE d I L7 L8 5 - - diff --git a/compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBodyInClass.kt b/compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBodyInClass.kt index e787c21516e..ab1bc1185b9 100644 --- a/compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBodyInClass.kt +++ b/compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBodyInClass.kt @@ -1,4 +1,4 @@ -class A { +open class A { inline fun test(a: Int = 1, b: Long = 1L, c: String = "123") { val d = 1 } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index fefc2dd9855..ee891eac802 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -966,6 +966,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { } } + @TestMetadata("compiler/testData/codegen/bytecodeText/defaultArguments") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DefaultArguments extends AbstractBytecodeTextTest { + public void testAllFilesPresentInDefaultArguments() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/defaultArguments"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("kt11962.kt") + public void testKt11962() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/kt11962.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/directInvoke") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -1283,12 +1298,6 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/jackAndJill"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } - @TestMetadata("inlineDefaultBody.kt") - public void testInlineDefaultBody() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBody.kt"); - doTest(fileName); - } - @TestMetadata("inlineDefaultBodyInClass.kt") public void testInlineDefaultBodyInClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBodyInClass.kt");