[JS IR] Allow constant inlining in JS IR
Fixed the incremental compilation issue, which had prevented enabling const inlining during constant evaluation and folding a constant expression with JS code. ^KT-62425
This commit is contained in:
committed by
Space Team
parent
629e0628d6
commit
188cdf2f98
@@ -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)
|
||||
},
|
||||
|
||||
+10
-5
@@ -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 <T> updateForEach(collection: Collection<T>, f: (T) -> Unit) {
|
||||
|
||||
+25
-8
@@ -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<IdSignature, ICHash>()
|
||||
|
||||
private val fileAnnotationHashes = hashMapOf<IrFile, ICHash>()
|
||||
private val constantHashes = hashMapOf<IrProperty, ICHash>()
|
||||
private val inlineFunctionFlatHashes = hashMapOf<IrFunction, ICHash>()
|
||||
|
||||
private val inlineFunctionDepends = hashMapOf<IrFunction, LinkedHashSet<IrFunction>>()
|
||||
private data class InlineFunctionDependencies(
|
||||
val usedInlineFunctions: LinkedHashSet<IrFunction>,
|
||||
val usedConstants: LinkedHashSet<IrProperty>,
|
||||
)
|
||||
|
||||
private val inlineFunctionDepends = hashMapOf<IrFunction, InlineFunctionDependencies>()
|
||||
|
||||
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<IrFunction>
|
||||
private val IrFunction.inlineDepends: InlineFunctionDependencies
|
||||
get() = inlineFunctionDepends.getOrPut(this) {
|
||||
val usedInlineFunctions = linkedSetOf<IrFunction>()
|
||||
val usedConstants = linkedSetOf<IrProperty>()
|
||||
|
||||
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
|
||||
|
||||
-12
@@ -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
|
||||
@@ -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
|
||||
|
||||
-10
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user