IR: Align Interface Defaults with Old Backend

Change the treatment of default implementations on interfaces in JVM
compatibility mode. Previously, the IR backend moved the actual
default implementation to the DefaultImpls class, and then bridged to
it from the interface default. The old backend did the reverse, at the
cost of an additional accessor, in order to gain better binary
compatibility properties. See #2612 for discussion.

The accessor needs to call a specific implementation, so must be
performed through an `invokespecial`. We trick the
SyntheticAccessorLowering into doing this for us, by marking the
bridging call as a super call. We do this in want of an explicit
`invokespecial` Ir Node.

InterfaceDefaultCallsPhase previously assumed the old behaviour of the
IR backend (that calls to default implementations, e.g. `foo$default`
should target `DefaultImpls.foo$default`). But now the bridge to
foo$default resides on `DefaultImpls` already, causing that pass to
create a recursive loop. We cut that loop with a simple check.
This commit is contained in:
Kristoffer Andersen
2019-11-05 15:37:43 +01:00
committed by max-kammerer
parent b5de625350
commit d1c2862e27
15 changed files with 187 additions and 92 deletions

View File

@@ -1,5 +1,4 @@
// !JVM_DEFAULT_MODE: compatibility
// IGNORE_BACKEND: JVM_IR
// JVM_TARGET: 1.8
// FULL_JDK
@@ -10,7 +9,7 @@ interface KInterface {
}
}
// 1 INVOKESTATIC KInterface.access\$test\$jd
// 1 INVOKESTATIC KInterface.access\$test\$
// 1 INVOKESTATIC KInterface.test\$default
// from $default

View File

@@ -0,0 +1,22 @@
// !JVM_DEFAULT_MODE: compatibility
// JVM_TARGET: 1.8
interface A {
@JvmDefault
fun foo() = "FAIL"
}
interface Left : A { }
interface Right : A {
@JvmDefault
override fun foo() = "OK"
}
interface C : Left, Right {}
fun box(): String {
val x = object : C {}
return x.foo()
}
// 0 INVOKESTATIC .*\$DefaultImpls\.foo

View File

@@ -1,5 +1,4 @@
// !JVM_DEFAULT_MODE: compatibility
// IGNORE_BACKEND: JVM_IR
// JVM_TARGET: 1.8
interface KInterface {
@@ -13,8 +12,8 @@ interface KInterface2 : KInterface {
}
// 1 INVOKESTATIC KInterface2.access\$test2\$jd
// 1 INVOKESTATIC KInterface.access\$test2\$jd
// 1 INVOKESTATIC KInterface2.access\$test2\$
// 1 INVOKESTATIC KInterface.access\$test2\$
// 1 INVOKESPECIAL KInterface2.test2
// 1 INVOKESPECIAL KInterface.test2

View File

@@ -1,5 +1,4 @@
// !JVM_DEFAULT_MODE: compatibility
// IGNORE_BACKEND: JVM_IR
// JVM_TARGET: 1.8
interface KInterface {
@@ -14,11 +13,11 @@ interface KInterface2 : KInterface {
abstract override fun test2(): String
}
// 1 INVOKESTATIC KInterface.access\$test2\$jd
// +
// 0 INVOKESTATIC KInterface2.access\$test2\$jd
// =
// 1 INVOKESTATIC
// 1 INVOKESPECIAL KInterface.test2
// 0 INVOKESPECIAL KInterface2.test2
// 1 INVOKESTATIC KInterface.access\$test2\$
// +
// 0 INVOKESTATIC KInterface2.access\$test2\$
// =
// 1 INVOKESTATIC KInterface

View File

@@ -1,5 +1,4 @@
// !JVM_DEFAULT_MODE: compatibility
// IGNORE_BACKEND: JVM_IR
// JVM_TARGET: 1.8
interface KInterface {
@@ -14,10 +13,10 @@ interface KInterface2 : KInterface {
}
// 1 INVOKESTATIC KInterface2.access\$getBar\$jd
// 1 INVOKESTATIC KInterface2.access\$setBar\$jd
// 1 INVOKESTATIC KInterface.access\$getBar\$jd
// 1 INVOKESTATIC KInterface.access\$setBar\$jd
// 1 INVOKESTATIC KInterface2.access\$getBar\$
// 1 INVOKESTATIC KInterface2.access\$setBar\$
// 1 INVOKESTATIC KInterface.access\$getBar\$
// 1 INVOKESTATIC KInterface.access\$setBar\$
// 1 INVOKESPECIAL KInterface2.getBar
// 1 INVOKESPECIAL KInterface2.setBar