[JS IR] Fix inline functions call graph in IC

Add a dependency for inline function references,
 because in some cases the references may be inlined.

^KT-55144 Fixed
This commit is contained in:
Alexander Korepanov
2022-11-25 17:51:51 +01:00
committed by Space Team
parent c31705240a
commit d8ab9498ab
28 changed files with 237 additions and 11 deletions
@@ -53,9 +53,9 @@ internal class IdSignatureHashCalculator {
}
private inner class InlineFunctionCallGraphBuilder : IrElementVisitor<Unit, MutableSet<IrFunction>> {
var inlineFunctionCallDepth: Int = 0
override fun visitElement(element: IrElement, data: MutableSet<IrFunction>) = element.acceptChildren(this, data)
override fun visitElement(element: IrElement, data: MutableSet<IrFunction>) {
element.acceptChildren(this, data)
}
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: MutableSet<IrFunction>) {
if (declaration in inlineFunctionCallGraph) {
@@ -70,20 +70,13 @@ internal class IdSignatureHashCalculator {
val callee = expression.symbol.owner
if (callee.isInline) {
data += callee
inlineFunctionCallDepth += 1
}
expression.acceptChildren(this, data)
if (callee.isInline) {
inlineFunctionCallDepth -= 1
if (inlineFunctionCallDepth < 0) {
icError("inline function calls depth inconsistent")
}
}
}
override fun visitFunctionReference(expression: IrFunctionReference, data: MutableSet<IrFunction>) {
val reference = expression.symbol.owner
if (inlineFunctionCallDepth > 0 && reference.isInline) {
if (reference.isInline) {
// this if is fine, because fake overrides are not inlined as function reference calls even as inline function args
if (!reference.isFakeOverride) {
data += reference
@@ -190,6 +190,11 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest {
runTest("js/js.translator/testData/incremental/invalidation/inlineBecomeNonInline/");
}
@TestMetadata("inlineFunctionAsFunctionReference")
public void testInlineFunctionAsFunctionReference() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionAsFunctionReference/");
}
@TestMetadata("inlineFunctionAsParam")
public void testInlineFunctionAsParam() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionAsParam/");
@@ -255,6 +260,11 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest {
runTest("js/js.translator/testData/incremental/invalidation/nonInlineBecomeInline/");
}
@TestMetadata("privateDeclarationLeakThroughDefaultParam")
public void testPrivateDeclarationLeakThroughDefaultParam() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/privateDeclarationLeakThroughDefaultParam/");
}
@TestMetadata("privateInlineFunction1")
public void testPrivateInlineFunction1() throws Exception {
runTest("js/js.translator/testData/incremental/invalidation/privateInlineFunction1/");
@@ -0,0 +1,2 @@
inline fun bar() = "0"
@@ -0,0 +1 @@
inline fun bar() = "1"
@@ -0,0 +1 @@
inline fun bar() = "2"
@@ -0,0 +1,3 @@
inline fun foo(callableReference: () -> String = ::bar): String {
return callableReference()
}
@@ -0,0 +1,4 @@
inline fun foo(): String {
val callableReference: () -> String = ::bar
return (callableReference().toInt() + 1).toString()
}
@@ -0,0 +1,19 @@
STEP 0:
modifications:
U : l1.0.kt -> l1.kt
U : l2.0.kt -> l2.kt
added file: l1.kt, l2.kt
STEP 1:
modifications:
U : l1.1.kt -> l1.kt
modified ir: l1.kt
updated imports: l2.kt
STEP 2:
modifications:
U : l2.2.kt -> l2.kt
modified ir: l2.kt
STEP 3:
modifications:
U : l1.3.kt -> l1.kt
modified ir: l1.kt
updated imports: l2.kt
@@ -0,0 +1,7 @@
fun box(stepId: Int): String {
val x = foo().toInt()
if (x != stepId) {
return "Fail $x != $stepId"
}
return "OK"
}
@@ -0,0 +1,12 @@
STEP 0:
dependencies: lib1
added file: m.kt
STEP 1:
dependencies: lib1
updated imports: m.kt
STEP 2:
dependencies: lib1
modified ir: m.kt
STEP 3:
dependencies: lib1
updated imports: m.kt
@@ -0,0 +1,5 @@
MODULES: lib1, main
STEP 0..3:
libs: lib1, main
dirty js: lib1, main
@@ -0,0 +1,5 @@
private val prop = "0"
internal inline fun foo(lambda: () -> String = ::prop): String {
return lambda()
}
@@ -0,0 +1,5 @@
private val prop = "1"
internal inline fun foo(lambda: () -> String = ::prop): String {
return lambda()
}
@@ -0,0 +1,9 @@
private object Obj {
val x = "10"
}
private inline fun bar() = Obj.x
internal inline fun foo(lambda: () -> String = ::bar): String {
return lambda()
}
@@ -0,0 +1,9 @@
private object Obj {
val x = "11"
}
private inline fun bar() = Obj.x
internal inline fun foo(lambda: () -> String = ::bar): String {
return lambda()
}
@@ -0,0 +1,9 @@
private object Obj {
inline val x get() = "12"
}
private inline fun bar() = Obj.x
internal inline fun foo(lambda: () -> String = ::bar): String {
return lambda()
}
@@ -0,0 +1,9 @@
private object Obj {
inline val x get() = "13"
}
private inline fun bar() = Obj.x
internal inline fun foo(lambda: () -> String = ::bar): String {
return lambda()
}
@@ -0,0 +1,5 @@
private val prop get() = "2"
internal inline fun foo(lambda: () -> String = ::prop): String {
return lambda()
}
@@ -0,0 +1,5 @@
private fun prop() = "3"
internal inline fun foo(lambda: () -> String = ::prop): String {
return lambda()
}
@@ -0,0 +1,5 @@
private fun prop() = "3"
internal inline fun foo(lambda: () -> String = { "4" }): String {
return lambda()
}
@@ -0,0 +1,3 @@
internal inline fun foo(lambda: () -> String = { "5" }): String {
return lambda()
}
@@ -0,0 +1,5 @@
private inline fun prop() = "6"
internal inline fun foo(lambda: () -> String = ::prop): String {
return lambda()
}
@@ -0,0 +1,5 @@
private inline fun prop() = "7"
internal inline fun foo(lambda: () -> String = ::prop): String {
return lambda()
}
@@ -0,0 +1,9 @@
private object Obj {
val x = "8"
override fun toString() = x
}
internal inline fun foo(lambda: () -> String = { "$Obj" } ): String {
return lambda()
}
@@ -0,0 +1,9 @@
private object Obj {
val x = "9"
override fun toString() = x
}
internal inline fun foo(lambda: () -> String = { "$Obj" } ): String {
return lambda()
}
@@ -0,0 +1,7 @@
fun box(stepId: Int): String {
val x = foo().toInt()
if (x != stepId) {
return "Fail $x != $stepId"
}
return "OK"
}
@@ -0,0 +1,65 @@
STEP 0:
modifications:
U : f.0.kt -> f.kt
added file: m.kt, f.kt
STEP 1:
modifications:
U : f.1.kt -> f.kt
modified ir: f.kt
STEP 2:
modifications:
U : f.2.kt -> f.kt
modified ir: f.kt
STEP 3:
modifications:
U : f.3.kt -> f.kt
modified ir: f.kt
updated imports: m.kt
STEP 4:
modifications:
U : f.4.kt -> f.kt
modified ir: f.kt
updated imports: m.kt
STEP 5:
modifications:
U : f.5.kt -> f.kt
modified ir: f.kt
updated imports: m.kt
STEP 6:
modifications:
U : f.6.kt -> f.kt
modified ir: f.kt
updated imports: m.kt
STEP 7:
modifications:
U : f.7.kt -> f.kt
modified ir: f.kt
updated imports: m.kt
STEP 8:
modifications:
U : f.8.kt -> f.kt
modified ir: f.kt
updated imports: m.kt
STEP 9:
modifications:
U : f.9.kt -> f.kt
modified ir: f.kt
STEP 10:
modifications:
U : f.10.kt -> f.kt
modified ir: f.kt
updated imports: m.kt
STEP 11:
modifications:
U : f.11.kt -> f.kt
modified ir: f.kt
STEP 12:
modifications:
U : f.12.kt -> f.kt
modified ir: f.kt
updated imports: m.kt
STEP 13:
modifications:
U : f.13.kt -> f.kt
modified ir: f.kt
updated imports: m.kt
@@ -0,0 +1,5 @@
MODULES: main
STEP 0..13:
libs: main
dirty js: main