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
This commit is contained in:
@@ -918,7 +918,7 @@ public class FunctionCodegen {
|
|||||||
CallGenerator generator = codegen.getOrCreateCallGeneratorForDefaultImplBody(functionDescriptor, function);
|
CallGenerator generator = codegen.getOrCreateCallGeneratorForDefaultImplBody(functionDescriptor, function);
|
||||||
|
|
||||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||||
genDefaultSuperCallCheckIfNeeded(iv, defaultMethod);
|
genDefaultSuperCallCheckIfNeeded(iv, functionDescriptor, defaultMethod);
|
||||||
|
|
||||||
loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator);
|
loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator);
|
||||||
|
|
||||||
@@ -961,19 +961,23 @@ public class FunctionCodegen {
|
|||||||
iv.areturn(signature.getReturnType());
|
iv.areturn(signature.getReturnType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void genDefaultSuperCallCheckIfNeeded(@NotNull InstructionAdapter iv, @NotNull Method defaultMethod) {
|
private static void genDefaultSuperCallCheckIfNeeded(
|
||||||
String defaultMethodName = defaultMethod.getName();
|
@NotNull InstructionAdapter iv, @NotNull FunctionDescriptor descriptor, @NotNull Method defaultMethod
|
||||||
if ("<init>".equals(defaultMethodName)) {
|
) {
|
||||||
return;
|
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();
|
Label end = new Label();
|
||||||
int handleIndex = (Type.getArgumentsAndReturnSizes(defaultMethod.getDescriptor()) >> 2) - 2; /*-1 for this, and -1 for handle*/
|
int handleIndex = (Type.getArgumentsAndReturnSizes(defaultMethod.getDescriptor()) >> 2) - 2; /*-1 for this, and -1 for handle*/
|
||||||
iv.load(handleIndex, OBJECT_TYPE);
|
iv.load(handleIndex, OBJECT_TYPE);
|
||||||
iv.ifnull(end);
|
iv.ifnull(end);
|
||||||
AsmUtil.genThrow(iv,
|
AsmUtil.genThrow(
|
||||||
"java/lang/UnsupportedOperationException",
|
iv, "java/lang/UnsupportedOperationException",
|
||||||
"Super calls with default arguments not supported in this target, function: " +
|
"Super calls with default arguments not supported in this target, function: " + descriptor.getName().asString()
|
||||||
StringsKt.substringBeforeLast(defaultMethodName, JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, defaultMethodName));
|
);
|
||||||
iv.visitLabel(end);
|
iv.visitLabel(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,25 +3,25 @@
|
|||||||
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun def(i: Int = 0): Int {
|
open class MyClass {
|
||||||
return i;
|
fun def(i: Int = 0): Int {
|
||||||
|
return i
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box():String {
|
fun box():String {
|
||||||
val clazz = Class.forName("SuperCallCheckKt")
|
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)
|
||||||
val method = clazz.getMethod("def\$default", Int::class.java, Int::class.java, Any::class.java)
|
|
||||||
val result = method.invoke(null, -1, 1, null)
|
|
||||||
|
|
||||||
if (result != 0) return "fail 1: $result"
|
if (result != 0) return "fail 1: $result"
|
||||||
|
|
||||||
var failed = false
|
var failed = false
|
||||||
try {
|
try {
|
||||||
method.invoke(null, -1, 1, "fail")
|
method.invoke(null, MyClass(), -1, 1, "fail")
|
||||||
} catch(e: Exception) {
|
}
|
||||||
|
catch(e: Exception) {
|
||||||
val cause = e.cause
|
val cause = e.cause
|
||||||
if (cause is java.lang.UnsupportedOperationException &&
|
if (cause is UnsupportedOperationException && cause.message!!.startsWith("Super calls")) {
|
||||||
cause.message!!.startsWith("Super calls")) {
|
|
||||||
failed = true
|
failed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -8,6 +8,7 @@ class A {
|
|||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Test argument reordering when call site argument order differs from declaration one: 18 + 1 for super call check
|
|
||||||
// 13 LOAD
|
// Test argument reordering when call site argument order differs from declaration one
|
||||||
|
// 12 LOAD
|
||||||
// 5 STORE
|
// 5 STORE
|
||||||
+3
-2
@@ -7,6 +7,7 @@ class A {
|
|||||||
return "OK"
|
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
|
// Test there is no argument reordering when call site argument order same as declaration one
|
||||||
|
// 9 LOAD
|
||||||
// 2 STORE
|
// 2 STORE
|
||||||
@@ -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
|
||||||
@@ -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
|
|
||||||
|
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
class A {
|
open class A {
|
||||||
inline fun test(a: Int = 1, b: Long = 1L, c: String = "123") {
|
inline fun test(a: Int = 1, b: Long = 1L, c: String = "123") {
|
||||||
val d = 1
|
val d = 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")
|
@TestMetadata("compiler/testData/codegen/bytecodeText/directInvoke")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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);
|
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")
|
@TestMetadata("inlineDefaultBodyInClass.kt")
|
||||||
public void testInlineDefaultBodyInClass() throws Exception {
|
public void testInlineDefaultBodyInClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBodyInClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/jackAndJill/inlineDefaultBodyInClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user