diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt index c58b948660a..1d268a70200 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESPECIAL import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESTATIC import org.jetbrains.org.objectweb.asm.Type @@ -35,7 +36,8 @@ class CallableMethod( private val invokeOpcode: Int, override val dispatchReceiverType: Type?, override val extensionReceiverType: Type?, - override val generateCalleeType: Type? + override val generateCalleeType: Type?, + private val isInterfaceMethod: Boolean = Opcodes.INVOKEINTERFACE == invokeOpcode ) : Callable { fun getValueParameters(): List = signature.valueParameters @@ -51,7 +53,13 @@ class CallableMethod( override fun genInvokeInstruction(v: InstructionAdapter) { - v.visitMethodInsn(invokeOpcode, owner.internalName, getAsmMethod().name, getAsmMethod().descriptor) + v.visitMethodInsn( + invokeOpcode, + owner.internalName, + getAsmMethod().name, + getAsmMethod().descriptor, + isInterfaceMethod + ) } fun genInvokeDefaultInstruction(v: InstructionAdapter) { @@ -61,7 +69,7 @@ class CallableMethod( val method = getAsmMethod() - if ("".equals(method.name)) { + if ("" == method.name) { v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.internalName, "", defaultMethodDesc, false) } else { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 83801272e7d..c54ad850ee8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -702,7 +702,7 @@ public class KotlinTypeMapper { JvmMethodSignature method = mapSignatureSkipGeneric(descriptor); Type owner = mapClass(((ClassConstructorDescriptor) descriptor).getContainingDeclaration()); String defaultImplDesc = mapDefaultMethod(descriptor, OwnerKind.IMPLEMENTATION).getDescriptor(); - return new CallableMethod(owner, owner, defaultImplDesc, method, INVOKESPECIAL, null, null, null); + return new CallableMethod(owner, owner, defaultImplDesc, method, INVOKESPECIAL, null, null, null, false); } if (descriptor instanceof LocalVariableAccessorDescriptor) { @@ -722,6 +722,7 @@ public class KotlinTypeMapper { FunctionDescriptor baseMethodDescriptor; int invokeOpcode; Type thisClass; + boolean isInterfaceMember = false; if (functionParent instanceof ClassDescriptor) { FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor); @@ -746,6 +747,7 @@ public class KotlinTypeMapper { invokeOpcode = INVOKESPECIAL; signature = mapSignatureSkipGeneric(functionDescriptor); owner = thisClass; + isInterfaceMember = true; } else { invokeOpcode = INVOKESTATIC; @@ -760,13 +762,16 @@ public class KotlinTypeMapper { CodegenUtilKt.isJvmStaticInObjectOrClass(functionDescriptor); if (isStaticInvocation) { invokeOpcode = INVOKESTATIC; + isInterfaceMember = currentIsInterface && currentOwner instanceof JavaClassDescriptor; } else if (isInterface) { invokeOpcode = INVOKEINTERFACE; + isInterfaceMember = true; } else { boolean isPrivateFunInvocation = Visibilities.isPrivate(functionDescriptor.getVisibility()); invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL; + isInterfaceMember = superCall && currentIsInterface; } FunctionDescriptor overriddenSpecialBuiltinFunction = @@ -777,6 +782,7 @@ public class KotlinTypeMapper { signature = mapSignatureSkipGeneric(functionToCall); + /*TODO: isInterfaceMember?*/ ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor ? declarationOwner : currentOwner; @@ -818,7 +824,8 @@ public class KotlinTypeMapper { return new CallableMethod( owner, ownerForDefaultImpl, defaultImplDesc, signature, invokeOpcode, - thisClass, receiverParameterType, calleeType); + thisClass, receiverParameterType, calleeType, + isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE ); } private boolean isJvm8Interface(@NotNull ClassDescriptor ownerForDefault) { diff --git a/compiler/testData/codegen/java8/box/jvm8/interfaceFlag/superCall.kt b/compiler/testData/codegen/java8/box/jvm8/interfaceFlag/superCall.kt new file mode 100644 index 00000000000..93625f9f8b4 --- /dev/null +++ b/compiler/testData/codegen/java8/box/jvm8/interfaceFlag/superCall.kt @@ -0,0 +1,24 @@ +// FILE: Simple.java + +public interface Simple { + default String test() { + return "O"; + } + + static String testStatic() { + return "K"; + } +} + +// FILE: main.kt +// JVM_TARGET: 1.8 +class TestClass : Simple { + override fun test(): String { + return super.test() + } +} + + +fun box(): String { + return TestClass().test() + Simple.testStatic() +} \ No newline at end of file diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java b/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java index 2f96b128a0d..b1d397857b0 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/codegen/BlackBoxWithJava8CodegenTestGenerated.java @@ -257,6 +257,21 @@ public class BlackBoxWithJava8CodegenTestGenerated extends AbstractBlackBoxCodeg doTest(fileName); } + @TestMetadata("compiler/testData/codegen/java8/box/jvm8/interfaceFlag") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InterfaceFlag extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInInterfaceFlag() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/java8/box/jvm8/interfaceFlag"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("superCall.kt") + public void testSuperCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/interfaceFlag/superCall.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/java8/box/jvm8/noDelegation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)