diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index a575f123661..8c202e40e1d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -22,6 +22,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import kotlin.jvm.functions.Function1; +import kotlin.text.StringsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.backend.common.bridges.Bridge; @@ -672,7 +673,7 @@ public class FunctionCodegen { } else { mv.visitCode(); - generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen); + generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen, defaultMethod); endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor)); } @@ -693,7 +694,8 @@ public class FunctionCodegen { @NotNull MethodVisitor mv, @NotNull DefaultParameterValueLoader loadStrategy, @Nullable KtNamedFunction function, - @NotNull MemberCodegen parentCodegen + @NotNull MemberCodegen parentCodegen, + @NotNull Method defaultMethod ) { GenerationState state = parentCodegen.state; JvmMethodSignature signature = state.getTypeMapper().mapSignature(functionDescriptor, methodContext.getContextKind()); @@ -705,6 +707,9 @@ public class FunctionCodegen { CallGenerator generator = codegen.getOrCreateCallGeneratorForDefaultImplBody(functionDescriptor, function); + InstructionAdapter iv = new InstructionAdapter(mv); + genDefaultSuperCallCheckIfNeeded(iv, defaultMethod); + loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator); List mappedParameters = signature.getValueParameters(); @@ -714,8 +719,6 @@ public class FunctionCodegen { capturedArgumentsCount++; } - InstructionAdapter iv = new InstructionAdapter(mv); - int maskIndex = 0; List valueParameters = functionDescriptor.getValueParameters(); for (int index = 0; index < valueParameters.size(); index++) { @@ -748,6 +751,22 @@ 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; + } + 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)); + iv.visitLabel(end); + } + private void generateOldDefaultForFun( Method newDefaultMethod, JvmDeclarationOrigin origin, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 103d2d04262..b4efec26291 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -247,7 +247,7 @@ public class InlineCodegen extends CallGenerator { implementationOwner.getInternalName()); FunctionCodegen.generateDefaultImplBody( methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, - inliningFunction, parentCodegen + inliningFunction, parentCodegen, asmMethod ); smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings()); } diff --git a/compiler/testData/codegen/boxWithStdlib/defaultArguments/superCallCheck.kt b/compiler/testData/codegen/boxWithStdlib/defaultArguments/superCallCheck.kt new file mode 100644 index 00000000000..39beae3d570 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/defaultArguments/superCallCheck.kt @@ -0,0 +1,26 @@ + +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) + + if (result != 0) return "fail 1: $result" + + var failed = false + try { + method.invoke(null, -1, 1, "fail") + } catch(e: Exception) { + val cause = e.cause + if (cause is java.lang.UnsupportedOperationException && + cause.message!!.startsWith("Super calls")) { + failed = true + } + } + + return if (!failed) "fail" else "OK" +} diff --git a/compiler/testData/codegen/bytecodeText/argumentOrder/argumentReorderWithDefault.kt b/compiler/testData/codegen/bytecodeText/argumentOrder/argumentReorderWithDefault.kt index 3f473f2eabb..1c8466b4d5c 100644 --- a/compiler/testData/codegen/bytecodeText/argumentOrder/argumentReorderWithDefault.kt +++ b/compiler/testData/codegen/bytecodeText/argumentOrder/argumentReorderWithDefault.kt @@ -8,6 +8,6 @@ class A { return "OK" } } -// Test argument reordering when call site argument order differs from declaration one -// 18 LOAD +// Test argument reordering when call site argument order differs from declaration one: 18 + 1 for super call check +// 19 LOAD // 5 STORE \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/argumentOrder/sameOrderWithDefault.kt b/compiler/testData/codegen/bytecodeText/argumentOrder/sameOrderWithDefault.kt index 16cf9b37519..f1ebaaa675e 100644 --- a/compiler/testData/codegen/bytecodeText/argumentOrder/sameOrderWithDefault.kt +++ b/compiler/testData/codegen/bytecodeText/argumentOrder/sameOrderWithDefault.kt @@ -7,6 +7,6 @@ class A { return "OK" } } -// Test there is no argument reordering when call site argument order same as declaration one -// 15 LOAD +// Test there is no argument reordering when call site argument order same as declaration one: 15 + 1 for super call check +// 16 LOAD // 2 STORE \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/noSuperCheckInDefaultConstuctor.kt b/compiler/testData/codegen/bytecodeText/noSuperCheckInDefaultConstuctor.kt new file mode 100644 index 00000000000..ac8c55c839f --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/noSuperCheckInDefaultConstuctor.kt @@ -0,0 +1,3 @@ +class A (i: Int = 0) + +// 0 ATHROW \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 597fc1d6dfe..7a7ed32813d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -233,6 +233,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } + @TestMetadata("noSuperCheckInDefaultConstuctor.kt") + public void testNoSuperCheckInDefaultConstuctor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/noSuperCheckInDefaultConstuctor.kt"); + doTest(fileName); + } + @TestMetadata("noWrapperForMethodReturningPrimitive.kt") public void testNoWrapperForMethodReturningPrimitive() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/noWrapperForMethodReturningPrimitive.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 032979d892d..0f6577f31fe 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -1450,6 +1450,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("superCallCheck.kt") + public void testSuperCallCheck() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/defaultArguments/superCallCheck.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/defaultArguments/constructor") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)