Use proper flag for interface method invocation

This commit is contained in:
Mikhael Bogdanov
2017-01-10 16:40:23 +01:00
parent 0f2139f27d
commit 7f8acbb759
4 changed files with 59 additions and 5 deletions
@@ -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()
}
@@ -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)