Use proper flag for interface method invocation
This commit is contained in:
@@ -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<JvmMethodParameterSignature> =
|
||||
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 ("<init>".equals(method.name)) {
|
||||
if ("<init>" == method.name) {
|
||||
v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.internalName, "<init>", defaultMethodDesc, false)
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
+15
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user