[JS_IR] Forbid to inline constants during const lowering
This commit is contained in:
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineLamb
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.loops.ForLoopsLowering
|
import org.jetbrains.kotlin.backend.common.lower.loops.ForLoopsLowering
|
||||||
import org.jetbrains.kotlin.backend.common.lower.optimizations.FoldConstantLowering
|
import org.jetbrains.kotlin.backend.common.lower.optimizations.FoldConstantLowering
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.*
|
import org.jetbrains.kotlin.backend.common.phaser.*
|
||||||
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.calls.CallsLowering
|
import org.jetbrains.kotlin.ir.backend.js.lower.calls.CallsLowering
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.cleanup.CleanupLowering
|
import org.jetbrains.kotlin.ir.backend.js.lower.cleanup.CleanupLowering
|
||||||
@@ -836,11 +837,16 @@ private val jsSuspendArityStorePhase = makeDeclarationTransformerPhase(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val constEvaluationPhase = makeJsModulePhase(
|
val constEvaluationPhase = makeJsModulePhase(
|
||||||
{
|
{ context ->
|
||||||
ConstEvaluationLowering(
|
// We can't inline `const val`s because this lowering can mess up incremental compilation.
|
||||||
it,
|
// For example, if we inline some constant located in `lib` module then we are not going to track and update its value on change.
|
||||||
configuration = IrInterpreterConfiguration(printOnlyExceptionMessage = true, platform = JsPlatforms.defaultJsPlatform)
|
// 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)
|
||||||
},
|
},
|
||||||
name = "ConstEvaluationLowering",
|
name = "ConstEvaluationLowering",
|
||||||
description = "Evaluate functions that are marked as `IntrinsicConstEvaluation`",
|
description = "Evaluate functions that are marked as `IntrinsicConstEvaluation`",
|
||||||
|
|||||||
+2
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform
|
|||||||
* @param createNonCompileTimeObjects
|
* @param createNonCompileTimeObjects
|
||||||
* 'true' - interpreter will construct object and initialize its properties despite the fact it is not marked as compile time;
|
* 'true' - interpreter will construct object and initialize its properties despite the fact it is not marked as compile time;
|
||||||
* 'false' - interpreter will create a representation of empty object, that can be used to get const properties
|
* 'false' - interpreter will create a representation of empty object, that can be used to get const properties
|
||||||
|
* @param inlineConstVal tell the interpreter that value of const property can be inlined instead of getter call
|
||||||
*/
|
*/
|
||||||
// TODO maybe create some sort of builder
|
// TODO maybe create some sort of builder
|
||||||
data class IrInterpreterConfiguration(
|
data class IrInterpreterConfiguration(
|
||||||
@@ -23,4 +24,5 @@ data class IrInterpreterConfiguration(
|
|||||||
val createNonCompileTimeObjects: Boolean = false,
|
val createNonCompileTimeObjects: Boolean = false,
|
||||||
val printOnlyExceptionMessage: Boolean = false,
|
val printOnlyExceptionMessage: Boolean = false,
|
||||||
val collapseStackTraceFromJDK: Boolean = true,
|
val collapseStackTraceFromJDK: Boolean = true,
|
||||||
|
val inlineConstVal: Boolean = true,
|
||||||
)
|
)
|
||||||
|
|||||||
+2
@@ -6,12 +6,14 @@
|
|||||||
package org.jetbrains.kotlin.ir.interpreter.checker
|
package org.jetbrains.kotlin.ir.interpreter.checker
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
|
||||||
interface IrInterpreterChecker : IrElementVisitor<Boolean, IrInterpreterCheckerData>
|
interface IrInterpreterChecker : IrElementVisitor<Boolean, IrInterpreterCheckerData>
|
||||||
|
|
||||||
class IrInterpreterCheckerData(
|
class IrInterpreterCheckerData(
|
||||||
|
val irFile: IrFile,
|
||||||
val mode: EvaluationMode,
|
val mode: EvaluationMode,
|
||||||
val irBuiltIns: IrBuiltIns,
|
val irBuiltIns: IrBuiltIns,
|
||||||
val interpreterConfiguration: IrInterpreterConfiguration,
|
val interpreterConfiguration: IrInterpreterConfiguration,
|
||||||
|
|||||||
+15
-16
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.interpreter.isAccessToNotNullableObject
|
|||||||
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor.Companion.isEnumName
|
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor.Companion.isEnumName
|
||||||
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor.Companion.isKCallableNameCall
|
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor.Companion.isKCallableNameCall
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.fileOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.ir.util.statements
|
import org.jetbrains.kotlin.ir.util.statements
|
||||||
|
|
||||||
@@ -59,22 +59,20 @@ class IrInterpreterCommonChecker : IrInterpreterChecker {
|
|||||||
|
|
||||||
override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean {
|
override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean {
|
||||||
val owner = expression.symbol.owner
|
val owner = expression.symbol.owner
|
||||||
|
return when {
|
||||||
if (expression.dispatchReceiver.isAccessToNotNullableObject() && expression.isGetterToConstVal()) {
|
!data.interpreterConfiguration.inlineConstVal && expression.isGetterToConstVal() && data.irFile != owner.fileOrNull -> false
|
||||||
return visitBodyIfNeeded(owner, data)
|
expression.dispatchReceiver.isAccessToNotNullableObject() && expression.isGetterToConstVal() -> visitBodyIfNeeded(owner, data)
|
||||||
|
!data.mode.canEvaluateExpression(expression) || !data.mode.canEvaluateFunction(owner) -> false
|
||||||
|
expression.isKCallableNameCall(data.irBuiltIns) || expression.isEnumName() -> true
|
||||||
|
else -> {
|
||||||
|
val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, data) ?: true
|
||||||
|
val extensionReceiverComputable = expression.extensionReceiver?.accept(this, data) ?: true
|
||||||
|
dispatchReceiverComputable &&
|
||||||
|
extensionReceiverComputable &&
|
||||||
|
visitValueArguments(expression, data) &&
|
||||||
|
visitBodyIfNeeded(owner, data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.mode.canEvaluateExpression(expression)) return false
|
|
||||||
|
|
||||||
if (!data.mode.canEvaluateFunction(owner)) return false
|
|
||||||
|
|
||||||
if (expression.isKCallableNameCall(data.irBuiltIns) || expression.isEnumName()) return true
|
|
||||||
|
|
||||||
val dispatchReceiverComputable = expression.dispatchReceiver?.accept(this, data) ?: true
|
|
||||||
val extensionReceiverComputable = expression.extensionReceiver?.accept(this, data) ?: true
|
|
||||||
if (!visitValueArguments(expression, data)) return false
|
|
||||||
val bodyComputable = visitBodyIfNeeded(owner, data)
|
|
||||||
return dispatchReceiverComputable && extensionReceiverComputable && bodyComputable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitVariable(declaration: IrVariable, data: IrInterpreterCheckerData): Boolean {
|
override fun visitVariable(declaration: IrVariable, data: IrInterpreterCheckerData): Boolean {
|
||||||
@@ -176,6 +174,7 @@ class IrInterpreterCommonChecker : IrInterpreterChecker {
|
|||||||
return owner.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && owner.isStatic && owner.isFinal &&
|
return owner.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && owner.isStatic && owner.isFinal &&
|
||||||
(owner.type.isPrimitiveType() || owner.type.isStringClassType())
|
(owner.type.isPrimitiveType() || owner.type.isStringClassType())
|
||||||
}
|
}
|
||||||
|
|
||||||
return owner.asVisited {
|
return owner.asVisited {
|
||||||
when {
|
when {
|
||||||
// TODO fix later; used it here because java boolean resolves very strange,
|
// TODO fix later; used it here because java boolean resolves very strange,
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ internal abstract class IrConstTransformer(
|
|||||||
configuration: IrInterpreterConfiguration = interpreter.environment.configuration
|
configuration: IrInterpreterConfiguration = interpreter.environment.configuration
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return try {
|
return try {
|
||||||
this.accept(checker, IrInterpreterCheckerData(mode, interpreter.irBuiltIns, configuration))
|
this.accept(checker, IrInterpreterCheckerData(irFile, mode, interpreter.irBuiltIns, configuration))
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
if (suppressExceptions) {
|
if (suppressExceptions) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
Reference in New Issue
Block a user