From 2f3ad476be2d527604caf3e41b44f520dd74cdab Mon Sep 17 00:00:00 2001 From: Alexander Korepanov Date: Thu, 7 Apr 2022 14:51:21 +0300 Subject: [PATCH] [JS IR] Ignore fake override calls in IC Fake overrides don't have a signature and can't be assiciated with klib index, therefore they can't be tracked with incremental cache invalidation logic. Should be fixed after KT-51896. --- .../ir/backend/js/ic/InlineGraphTracker.kt | 15 +++++-- .../InvalidationTestGenerated.java | 5 +++ .../invalidation/fakeOverride/lib1/l1.kt | 7 ++++ .../fakeOverride/lib1/l1.kt.1.txt | 7 ++++ .../fakeOverride/lib1/l1.kt.2.txt | 7 ++++ .../fakeOverride/lib1/module.info | 13 +++++++ .../invalidation/fakeOverride/lib2/l2.kt | 4 ++ .../fakeOverride/lib2/module.info | 5 +++ .../invalidation/fakeOverride/main/m.kt | 39 +++++++++++++++++++ .../fakeOverride/main/module.info | 5 +++ .../invalidation/fakeOverride/project.info | 8 ++++ 11 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt create mode 100644 js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt.1.txt create mode 100644 js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt.2.txt create mode 100644 js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/fakeOverride/lib2/l2.kt create mode 100644 js/js.translator/testData/incremental/invalidation/fakeOverride/lib2/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/fakeOverride/main/m.kt create mode 100644 js/js.translator/testData/incremental/invalidation/fakeOverride/main/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/fakeOverride/project.info diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/InlineGraphTracker.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/InlineGraphTracker.kt index c743d63243e..eb6127249fe 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/InlineGraphTracker.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/InlineGraphTracker.kt @@ -63,7 +63,10 @@ class InlineFunctionHashBuilder( override fun visitCall(expression: IrCall, data: MutableSet) { val callee = expression.symbol.owner if (callee.isInline) { - data += callee + // TODO: do not ignore fake overides after KT-51896 + if (!callee.isFakeOverride) { + data += callee + } inlineFunctionCallDepth += 1 } expression.acceptChildren(this, data) @@ -78,7 +81,10 @@ class InlineFunctionHashBuilder( override fun visitFunctionReference(expression: IrFunctionReference, data: MutableSet) { val reference = expression.symbol.owner if (inlineFunctionCallDepth > 0 && reference.isInline) { - data += reference + // this if is fine, because fake overrides are not inlined as function reference calls even as inline function args + if (!reference.isFakeOverride) { + data += reference + } } expression.acceptChildren(this, data) } @@ -135,12 +141,13 @@ class InlineFunctionHashBuilder( val usedInlineFunctions = mutableMapOf() it.value.forEach { edges -> edges.forEach { callee -> + // TODO: do not ignore fake overides after KT-51896 if (!callee.isFakeOverride) { - val signature = callee.symbol.signature // ?: error("Expecting signature for ${callee.render()}") + val signature = callee.symbol.signature if (signature?.visibleCrossFile == true) { val calleeHash = computedHashed[callee] ?: hashProvider.hashForExternalFunction(callee) - ?: error("Internal error: No has found for ${callee.render()}") + ?: error("Internal error: No hash found for ${callee.render()}") usedInlineFunctions[signature] = calleeHash } } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/InvalidationTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/InvalidationTestGenerated.java index 8c0fc829e52..02afca7457e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/InvalidationTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/InvalidationTestGenerated.java @@ -50,6 +50,11 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest { runTest("js/js.translator/testData/incremental/invalidation/crossModuleReferences/"); } + @TestMetadata("fakeOverride") + public void testFakeOverride() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/fakeOverride/"); + } + @TestMetadata("fastPath1") public void testFastPath1() throws Exception { runTest("js/js.translator/testData/incremental/invalidation/fastPath1/"); diff --git a/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt new file mode 100644 index 00000000000..8d3e4ddca8e --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt @@ -0,0 +1,7 @@ +abstract class ClassA { + inline fun Any.castTo(): T? = this as? T + abstract fun test1(): String? + abstract fun test2(): String? + + inline fun fakeOverrideFunction() = 0 +} diff --git a/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt.1.txt b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt.1.txt new file mode 100644 index 00000000000..b87856c3c22 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt.1.txt @@ -0,0 +1,7 @@ +abstract class ClassA { + inline fun Any.castTo(): T? = (this as? T) ?: "OTHER ${this as? Int}" as T + abstract fun test1(): String? + abstract fun test2(): String? + + inline fun fakeOverrideFunction() = 0 +} diff --git a/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt.2.txt b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt.2.txt new file mode 100644 index 00000000000..49993880881 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/l1.kt.2.txt @@ -0,0 +1,7 @@ +abstract class ClassA { + inline fun Any.castTo(): T? = (this as? T) ?: "OTHER ${this as? Int}" as T + abstract fun test1(): String? + abstract fun test2(): String? + + inline fun fakeOverrideFunction() = 2 +} diff --git a/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/module.info b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/module.info new file mode 100644 index 00000000000..3f9847a3248 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib1/module.info @@ -0,0 +1,13 @@ +STEP 0: + dependencies: stdlib + dirty: l1.kt +STEP 1: + dependencies: stdlib + modifications: + U : l1.kt.1.txt -> l1.kt + dirty: l1.kt +STEP 2: + dependencies: stdlib + modifications: + U : l1.kt.2.txt -> l1.kt + dirty: l1.kt diff --git a/js/js.translator/testData/incremental/invalidation/fakeOverride/lib2/l2.kt b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib2/l2.kt new file mode 100644 index 00000000000..b9b1f98562f --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib2/l2.kt @@ -0,0 +1,4 @@ +class ClassB: ClassA() { + override fun test1() = "ClassB::test1".castTo() + override fun test2() = 1.castTo() +} diff --git a/js/js.translator/testData/incremental/invalidation/fakeOverride/lib2/module.info b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib2/module.info new file mode 100644 index 00000000000..df048187d3b --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/fakeOverride/lib2/module.info @@ -0,0 +1,5 @@ +STEP 0: + dependencies: stdlib, lib1 + dirty: l2.kt +STEP 1..2: + dependencies: stdlib, lib1 diff --git a/js/js.translator/testData/incremental/invalidation/fakeOverride/main/m.kt b/js/js.translator/testData/incremental/invalidation/fakeOverride/main/m.kt new file mode 100644 index 00000000000..db615f2beb3 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/fakeOverride/main/m.kt @@ -0,0 +1,39 @@ +inline fun callIt(f: () -> Int) = f() + +fun box(stepId: Int): String { + val a = object : ClassA() { + override fun test1() = "object::test1".castTo() + override fun test2() = 2.castTo() + } + + val b = ClassB() + + if (a.test1() != "object::test1") return "Fail 1" + if (b.test1() != "ClassB::test1") return "Fail 2" + + when (stepId) { + 0 -> { + if (a.test2() != null) return "Fail 0-1" + if (b.test2() != null) return "Fail 0-2" + + if (a.fakeOverrideFunction() != 0) return "Fail 0-3" + if (b.fakeOverrideFunction() != 0) return "Fail 0-4" + + if (callIt(a::fakeOverrideFunction) != 0) return "Fail 0-5" + if (callIt(b::fakeOverrideFunction) != 0) return "Fail 0-6" + } + 1 -> { + if (a.test2() != null) return "Fail 1-1" // TODO: test2() must return "OTHER 2", should be fixed in KT-51896 + if (b.test2() != null) return "Fail 1-2" // TODO: test2() must return "OTHER 1", should be fixed in KT-51896 + } + 2 -> { + if (a.fakeOverrideFunction() != 0) return "Fail 2-1" // TODO: fakeOverrideFunction() must return 2, should be fixed in KT-51896 + if (b.fakeOverrideFunction() != 0) return "Fail 2-2" // TODO: fakeOverrideFunction() must return 2, should be fixed in KT-51896 + + if (callIt(a::fakeOverrideFunction) != 2) return "Fail 2-3" + if (callIt(b::fakeOverrideFunction) != 2) return "Fail 2-4" + } + else -> return "Unknown" + } + return "OK" +} diff --git a/js/js.translator/testData/incremental/invalidation/fakeOverride/main/module.info b/js/js.translator/testData/incremental/invalidation/fakeOverride/main/module.info new file mode 100644 index 00000000000..370aa51ea53 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/fakeOverride/main/module.info @@ -0,0 +1,5 @@ +STEP 0: + dependencies: stdlib, lib1, lib2 + dirty: m.kt +STEP 1..2: + dependencies: stdlib, lib1, lib2 diff --git a/js/js.translator/testData/incremental/invalidation/fakeOverride/project.info b/js/js.translator/testData/incremental/invalidation/fakeOverride/project.info new file mode 100644 index 00000000000..df4f6445441 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/fakeOverride/project.info @@ -0,0 +1,8 @@ +MODULES: lib1, lib2, main + +STEP 0: + libs: lib1, lib2, main + dirty js: stdlib, lib1, lib2, main +STEP 1..2: + libs: lib1, lib2, main + dirty js: lib1