Fix for https://youtrack.jetbrains.com/issue/KT-35940 + test
The bug was not taking into account implicit runtime DFG edges generated by associated objects in devirtualization analysis
This commit is contained in:
+17
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.common.push
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.irBlock
|
import org.jetbrains.kotlin.backend.common.lower.irBlock
|
||||||
import org.jetbrains.kotlin.backend.konan.*
|
import org.jetbrains.kotlin.backend.konan.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -257,6 +258,22 @@ internal object Devirtualization {
|
|||||||
} else {
|
} else {
|
||||||
// String is implicitly created as argument of <main>.
|
// String is implicitly created as argument of <main>.
|
||||||
addInstantiatingClass(symbolTable.mapType(context.irBuiltIns.stringType))
|
addInstantiatingClass(symbolTable.mapType(context.irBuiltIns.stringType))
|
||||||
|
|
||||||
|
// Conservatively assume each associated object could be instantiated.
|
||||||
|
context.irModule!!.acceptChildrenVoid(object: IrElementVisitorVoid {
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass) {
|
||||||
|
context.getLayoutBuilder(declaration).associatedObjects.values.forEach {
|
||||||
|
assert (it.kind == ClassKind.OBJECT) { "An object expected but was ${it.dump()}" }
|
||||||
|
addInstantiatingClass(symbolTable.mapType(it.defaultType))
|
||||||
|
}
|
||||||
|
super.visitClass(declaration)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
// Traverse call graph from the roots.
|
// Traverse call graph from the roots.
|
||||||
rootSet.forEach { dfs(it, it.returnParameter.type) }
|
rootSet.forEach { dfs(it, it.returnParameter.type) }
|
||||||
|
|||||||
@@ -45,14 +45,23 @@ object Baz
|
|||||||
fun testGlobalOptimizations1() {
|
fun testGlobalOptimizations1() {
|
||||||
val i1 = I1ImplHolder::class.findAssociatedObject<Associated1>()!! as I1
|
val i1 = I1ImplHolder::class.findAssociatedObject<Associated1>()!! as I1
|
||||||
assertEquals(42, i1.foo())
|
assertEquals(42, i1.foo())
|
||||||
|
val c = C(null)
|
||||||
|
i1.bar(c)
|
||||||
|
assertEquals("zzz", c.list!![0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class C(var list: List<String>?)
|
||||||
|
|
||||||
private interface I1 {
|
private interface I1 {
|
||||||
fun foo(): Int
|
fun foo(): Int
|
||||||
|
fun bar(c: C)
|
||||||
}
|
}
|
||||||
|
|
||||||
private object I1Impl : I1 {
|
private object I1Impl : I1 {
|
||||||
override fun foo() = 42
|
override fun foo() = 42
|
||||||
|
override fun bar(c: C) {
|
||||||
|
c.list = mutableListOf("zzz")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Associated1(I1Impl::class)
|
@Associated1(I1Impl::class)
|
||||||
|
|||||||
Reference in New Issue
Block a user