diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 8380f335363..656c3ae85e4 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -849,13 +849,9 @@ private val jsSuspendArityStorePhase = makeDeclarationTransformerPhase( val constEvaluationPhase = makeJsModulePhase( { context -> - // We can't inline `const val`s because this lowering can mess up incremental compilation. - // For example, if we inline some constant located in `lib` module then we are not going to track and update its value on change. - // The only usages of `const val`s that we allow to inline are the ones that are located at the same file as declaration. val configuration = IrInterpreterConfiguration( printOnlyExceptionMessage = true, platform = JsPlatforms.defaultJsPlatform, - inlineConstVal = false ) ConstEvaluationLowering(context, configuration = configuration) }, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt index 7fb71b03239..10181bd90ff 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/HashCalculatorForIC.kt @@ -73,6 +73,12 @@ private class HashCalculatorForIC { updateForEach(annotationContainer.annotations, ::update) } + fun updateProperty(irProperty: IrProperty) { + if (irProperty.isConst) { + irProperty.backingField?.initializer?.let(::update) + } + } + fun updateSymbol(symbol: IrSymbol) { update(symbol.toString()) @@ -107,12 +113,11 @@ private class HashCalculatorForIC { update(functionParam.defaultValue?.let { 1 } ?: 0) } } - (symbol.owner as? IrAnnotationContainer)?.let(::updateAnnotationContainer) - (symbol.owner as? IrProperty)?.let { irProperty -> - if (irProperty.isConst) { - irProperty.backingField?.initializer?.let(::update) - } + (symbol.owner as? IrSimpleFunction)?.let { irSimpleFunction -> + irSimpleFunction.correspondingPropertySymbol?.owner?.let(::updateProperty) } + (symbol.owner as? IrAnnotationContainer)?.let(::updateAnnotationContainer) + (symbol.owner as? IrProperty)?.let(::updateProperty) } inline fun updateForEach(collection: Collection, f: (T) -> Unit) { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IdSignatureHashCalculator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IdSignatureHashCalculator.kt index 3d5ac963065..979ddb1b7c3 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IdSignatureHashCalculator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IdSignatureHashCalculator.kt @@ -6,10 +6,7 @@ package org.jetbrains.kotlin.ir.backend.js.ic import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.IrDeclaration -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrFunctionReference import org.jetbrains.kotlin.ir.symbols.IrSymbol @@ -26,15 +23,26 @@ internal class IdSignatureHashCalculator(private val icHasher: ICHasher) { private val idSignatureHashes = hashMapOf() private val fileAnnotationHashes = hashMapOf() + private val constantHashes = hashMapOf() private val inlineFunctionFlatHashes = hashMapOf() - private val inlineFunctionDepends = hashMapOf>() + private data class InlineFunctionDependencies( + val usedInlineFunctions: LinkedHashSet, + val usedConstants: LinkedHashSet, + ) + + private val inlineFunctionDepends = hashMapOf() private val IrFile.annotationsHash: ICHash get() = fileAnnotationHashes.getOrPut(this) { icHasher.calculateIrAnnotationContainerHash(this) } + private val IrProperty.constantHash: ICHash + get() = constantHashes.getOrPut(this) { + icHasher.calculateIrSymbolHash(symbol) + } + private val IrFunction.inlineFunctionFlatHash: ICHash get() = inlineFunctionFlatHashes.getOrPut(this) { val function = if (isFakeOverride && this is IrSimpleFunction) resolveFakeOverrideOrFail() else this @@ -42,9 +50,10 @@ internal class IdSignatureHashCalculator(private val icHasher: ICHasher) { ICHash(symbol.calculateSymbolHash().hash.combineWith(flatHash.hash)) } - private val IrFunction.inlineDepends: Collection + private val IrFunction.inlineDepends: InlineFunctionDependencies get() = inlineFunctionDepends.getOrPut(this) { val usedInlineFunctions = linkedSetOf() + val usedConstants = linkedSetOf() acceptVoid(object : IrElementVisitorVoid { override fun visitElement(element: IrElement) { @@ -56,6 +65,10 @@ internal class IdSignatureHashCalculator(private val icHasher: ICHasher) { if (callee.isInline) { usedInlineFunctions += callee } + val correspondingProperty = callee.correspondingPropertySymbol?.owner + if (correspondingProperty?.isConst == true) { + usedConstants += correspondingProperty + } expression.acceptChildrenVoid(this) } @@ -71,7 +84,7 @@ internal class IdSignatureHashCalculator(private val icHasher: ICHasher) { } }) - usedInlineFunctions + InlineFunctionDependencies(usedInlineFunctions, usedConstants) } private fun IrSymbol.calculateSymbolHash(): ICHash { @@ -94,12 +107,16 @@ internal class IdSignatureHashCalculator(private val icHasher: ICHasher) { val newDependsStack = transitiveDepends.toMutableList() while (newDependsStack.isNotEmpty()) { - newDependsStack.removeLast().inlineDepends.forEach { inlineFunction -> + val (usedInlineFunctions, usedConstants) = newDependsStack.removeLast().inlineDepends + for (inlineFunction in usedInlineFunctions) { if (transitiveDepends.add(inlineFunction)) { newDependsStack += inlineFunction transitiveHash = ICHash(transitiveHash.hash.combineWith(inlineFunction.inlineFunctionFlatHash.hash)) } } + for (constant in usedConstants) { + transitiveHash = ICHash(transitiveHash.hash.combineWith(constant.constantHash.hash)) + } } return transitiveHash diff --git a/js/js.translator/testData/incremental/invalidation/constVals/main/module.fir.info b/js/js.translator/testData/incremental/invalidation/constVals/main/module.fir.info deleted file mode 100644 index 97de44f5c94..00000000000 --- a/js/js.translator/testData/incremental/invalidation/constVals/main/module.fir.info +++ /dev/null @@ -1,12 +0,0 @@ -STEP 0: - dependencies: lib1, lib2 - added file: m.kt -STEP 1: - dependencies: lib1, lib2 - updated imports: m.kt -STEP 2: - dependencies: lib1, lib2 - modified ir: m.kt -STEP 3: - dependencies: lib1, lib2 - updated imports: m.kt diff --git a/js/js.translator/testData/incremental/invalidation/constVals/main/module.info b/js/js.translator/testData/incremental/invalidation/constVals/main/module.info index d5d8f7eb364..97de44f5c94 100644 --- a/js/js.translator/testData/incremental/invalidation/constVals/main/module.info +++ b/js/js.translator/testData/incremental/invalidation/constVals/main/module.info @@ -3,8 +3,10 @@ STEP 0: added file: m.kt STEP 1: dependencies: lib1, lib2 + updated imports: m.kt STEP 2: dependencies: lib1, lib2 modified ir: m.kt STEP 3: dependencies: lib1, lib2 + updated imports: m.kt diff --git a/js/js.translator/testData/incremental/invalidation/constVals/project.fir.info b/js/js.translator/testData/incremental/invalidation/constVals/project.fir.info deleted file mode 100644 index 993a334fe0f..00000000000 --- a/js/js.translator/testData/incremental/invalidation/constVals/project.fir.info +++ /dev/null @@ -1,10 +0,0 @@ -MODULES: lib1, lib2, main - -STEP 0: - libs: lib1, lib2, main - dirty js modules: lib1, lib2, main - dirty js files: lib1/l1, lib2/l2, main/m, main/m.export, main -STEP 1..3: - libs: lib1, lib2, main - dirty js modules: lib1, lib2, main - dirty js files: lib1/l1, lib2/l2, main/m diff --git a/js/js.translator/testData/incremental/invalidation/constVals/project.info b/js/js.translator/testData/incremental/invalidation/constVals/project.info index dfd281f8e17..993a334fe0f 100644 --- a/js/js.translator/testData/incremental/invalidation/constVals/project.info +++ b/js/js.translator/testData/incremental/invalidation/constVals/project.info @@ -4,15 +4,7 @@ STEP 0: libs: lib1, lib2, main dirty js modules: lib1, lib2, main dirty js files: lib1/l1, lib2/l2, main/m, main/m.export, main -STEP 1: - libs: lib1, lib2, main - dirty js modules: lib1, lib2 - dirty js files: lib1/l1, lib2/l2 -STEP 2: +STEP 1..3: libs: lib1, lib2, main dirty js modules: lib1, lib2, main dirty js files: lib1/l1, lib2/l2, main/m -STEP 3: - libs: lib1, lib2, main - dirty js modules: lib1, lib2 - dirty js files: lib1/l1, lib2/l2