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.JvmMethodParameterKind
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
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.INVOKESPECIAL
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESTATIC
|
import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESTATIC
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
@@ -35,7 +36,8 @@ class CallableMethod(
|
|||||||
private val invokeOpcode: Int,
|
private val invokeOpcode: Int,
|
||||||
override val dispatchReceiverType: Type?,
|
override val dispatchReceiverType: Type?,
|
||||||
override val extensionReceiverType: Type?,
|
override val extensionReceiverType: Type?,
|
||||||
override val generateCalleeType: Type?
|
override val generateCalleeType: Type?,
|
||||||
|
private val isInterfaceMethod: Boolean = Opcodes.INVOKEINTERFACE == invokeOpcode
|
||||||
) : Callable {
|
) : Callable {
|
||||||
fun getValueParameters(): List<JvmMethodParameterSignature> =
|
fun getValueParameters(): List<JvmMethodParameterSignature> =
|
||||||
signature.valueParameters
|
signature.valueParameters
|
||||||
@@ -51,7 +53,13 @@ class CallableMethod(
|
|||||||
|
|
||||||
|
|
||||||
override fun genInvokeInstruction(v: InstructionAdapter) {
|
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) {
|
fun genInvokeDefaultInstruction(v: InstructionAdapter) {
|
||||||
@@ -61,7 +69,7 @@ class CallableMethod(
|
|||||||
|
|
||||||
val method = getAsmMethod()
|
val method = getAsmMethod()
|
||||||
|
|
||||||
if ("<init>".equals(method.name)) {
|
if ("<init>" == method.name) {
|
||||||
v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.internalName, "<init>", defaultMethodDesc, false)
|
v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.internalName, "<init>", defaultMethodDesc, false)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -702,7 +702,7 @@ public class KotlinTypeMapper {
|
|||||||
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor);
|
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor);
|
||||||
Type owner = mapClass(((ClassConstructorDescriptor) descriptor).getContainingDeclaration());
|
Type owner = mapClass(((ClassConstructorDescriptor) descriptor).getContainingDeclaration());
|
||||||
String defaultImplDesc = mapDefaultMethod(descriptor, OwnerKind.IMPLEMENTATION).getDescriptor();
|
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) {
|
if (descriptor instanceof LocalVariableAccessorDescriptor) {
|
||||||
@@ -722,6 +722,7 @@ public class KotlinTypeMapper {
|
|||||||
FunctionDescriptor baseMethodDescriptor;
|
FunctionDescriptor baseMethodDescriptor;
|
||||||
int invokeOpcode;
|
int invokeOpcode;
|
||||||
Type thisClass;
|
Type thisClass;
|
||||||
|
boolean isInterfaceMember = false;
|
||||||
|
|
||||||
if (functionParent instanceof ClassDescriptor) {
|
if (functionParent instanceof ClassDescriptor) {
|
||||||
FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
|
FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
|
||||||
@@ -746,6 +747,7 @@ public class KotlinTypeMapper {
|
|||||||
invokeOpcode = INVOKESPECIAL;
|
invokeOpcode = INVOKESPECIAL;
|
||||||
signature = mapSignatureSkipGeneric(functionDescriptor);
|
signature = mapSignatureSkipGeneric(functionDescriptor);
|
||||||
owner = thisClass;
|
owner = thisClass;
|
||||||
|
isInterfaceMember = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
invokeOpcode = INVOKESTATIC;
|
invokeOpcode = INVOKESTATIC;
|
||||||
@@ -760,13 +762,16 @@ public class KotlinTypeMapper {
|
|||||||
CodegenUtilKt.isJvmStaticInObjectOrClass(functionDescriptor);
|
CodegenUtilKt.isJvmStaticInObjectOrClass(functionDescriptor);
|
||||||
if (isStaticInvocation) {
|
if (isStaticInvocation) {
|
||||||
invokeOpcode = INVOKESTATIC;
|
invokeOpcode = INVOKESTATIC;
|
||||||
|
isInterfaceMember = currentIsInterface && currentOwner instanceof JavaClassDescriptor;
|
||||||
}
|
}
|
||||||
else if (isInterface) {
|
else if (isInterface) {
|
||||||
invokeOpcode = INVOKEINTERFACE;
|
invokeOpcode = INVOKEINTERFACE;
|
||||||
|
isInterfaceMember = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
boolean isPrivateFunInvocation = Visibilities.isPrivate(functionDescriptor.getVisibility());
|
boolean isPrivateFunInvocation = Visibilities.isPrivate(functionDescriptor.getVisibility());
|
||||||
invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
|
invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
|
||||||
|
isInterfaceMember = superCall && currentIsInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionDescriptor overriddenSpecialBuiltinFunction =
|
FunctionDescriptor overriddenSpecialBuiltinFunction =
|
||||||
@@ -777,6 +782,7 @@ public class KotlinTypeMapper {
|
|||||||
|
|
||||||
signature = mapSignatureSkipGeneric(functionToCall);
|
signature = mapSignatureSkipGeneric(functionToCall);
|
||||||
|
|
||||||
|
/*TODO: isInterfaceMember?*/
|
||||||
ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor
|
ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor
|
||||||
? declarationOwner
|
? declarationOwner
|
||||||
: currentOwner;
|
: currentOwner;
|
||||||
@@ -818,7 +824,8 @@ public class KotlinTypeMapper {
|
|||||||
|
|
||||||
return new CallableMethod(
|
return new CallableMethod(
|
||||||
owner, ownerForDefaultImpl, defaultImplDesc, signature, invokeOpcode,
|
owner, ownerForDefaultImpl, defaultImplDesc, signature, invokeOpcode,
|
||||||
thisClass, receiverParameterType, calleeType);
|
thisClass, receiverParameterType, calleeType,
|
||||||
|
isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isJvm8Interface(@NotNull ClassDescriptor ownerForDefault) {
|
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);
|
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")
|
@TestMetadata("compiler/testData/codegen/java8/box/jvm8/noDelegation")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user