diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt index 170fdf380e3..7c2853f49c7 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irString import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrFileSymbol @@ -45,4 +46,8 @@ interface CommonBackendContext : BackendContext, LoggingContext { classSymbolMap: MutableMap, functionSymbolMap: MutableMap ) {} + + fun isSideEffectFree(call: IrCall): Boolean { + return false + } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index b45bab06a28..b93cffdf60a 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -644,3 +644,42 @@ private fun computeAllOverridden(function: IrSimpleFunction, result: MutableSet< } } } + +// TODO: support more cases like built-in operator call and so on +fun IrExpression?.isPure( + anyVariable: Boolean, + checkFields: Boolean = true, + context: CommonBackendContext? = null +): Boolean { + if (this == null) return true + + fun IrExpression.isPureImpl(): Boolean { + return when (this) { + is IrConst<*> -> true + is IrGetValue -> { + if (anyVariable) return true + val valueDeclaration = symbol.owner + if (valueDeclaration is IrVariable) !valueDeclaration.isVar + else true + } + is IrCall -> context?.isSideEffectFree(this) ?: false + is IrGetObjectValue -> type.isUnit() + else -> false + } + } + + if (isPureImpl()) return true + + if (!checkFields) return false + + if (this is IrGetField) { + if (!symbol.owner.isFinal) { + if (!anyVariable) { + return false + } + } + return receiver.isPure(anyVariable) + } + + return false +} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/PropertyAccessorInlineLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/PropertyAccessorInlineLowering.kt index 4e44e216030..8c522da87fb 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/PropertyAccessorInlineLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/PropertyAccessorInlineLowering.kt @@ -19,7 +19,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.isEffectivelyExternal -import org.jetbrains.kotlin.ir.util.isPure +import org.jetbrains.kotlin.backend.common.ir.isPure import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index db6049bc50b..82526557d9d 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol import org.jetbrains.kotlin.ir.types.* @@ -58,6 +59,9 @@ class JsIrBackendContext( override var inVerbosePhase: Boolean = false + override fun isSideEffectFree(call: IrCall): Boolean = + call.symbol in intrinsics.primitiveToLiteralConstructor.values + val devMode = configuration[JSConfigurationKeys.DEVELOPER_MODE] ?: false val errorPolicy = configuration[JSConfigurationKeys.ERROR_TOLERANCE_POLICY] ?: ErrorTolerancePolicy.DEFAULT @@ -131,6 +135,7 @@ class JsIrBackendContext( private val COROUTINE_CONTEXT_NAME = Name.identifier("coroutineContext") private val COROUTINE_IMPL_NAME = Name.identifier("CoroutineImpl") private val CONTINUATION_NAME = Name.identifier("Continuation") + // TODO: what is more clear way reference this getter? private val CONTINUATION_CONTEXT_GETTER_NAME = Name.special("") @@ -262,15 +267,29 @@ class JsIrBackendContext( val coroutineGetContext: IrSimpleFunctionSymbol get() { val contextGetter = - continuationClass.owner.declarations.filterIsInstance().atMostOne { it.name == CONTINUATION_CONTEXT_GETTER_NAME } - ?: continuationClass.owner.declarations.filterIsInstance().atMostOne { it.name == CONTINUATION_CONTEXT_PROPERTY_NAME }?.getter!! + continuationClass.owner.declarations.filterIsInstance() + .atMostOne { it.name == CONTINUATION_CONTEXT_GETTER_NAME } + ?: continuationClass.owner.declarations.filterIsInstance() + .atMostOne { it.name == CONTINUATION_CONTEXT_PROPERTY_NAME }?.getter!! return contextGetter.symbol } val coroutineGetContextJs get() = ir.symbols.coroutineGetContext - val coroutineEmptyContinuation = symbolTable.referenceProperty(getProperty(FqName.fromSegments(listOf("kotlin", "coroutines", "js", "internal", "EmptyContinuation")))) + val coroutineEmptyContinuation = symbolTable.referenceProperty( + getProperty( + FqName.fromSegments( + listOf( + "kotlin", + "coroutines", + "js", + "internal", + "EmptyContinuation" + ) + ) + ) + ) val coroutineContextProperty: PropertyDescriptor get() { @@ -283,7 +302,8 @@ class JsIrBackendContext( val newThrowableSymbol = symbolTable.referenceSimpleFunction(getJsInternalFunction("newThrowable")) val extendThrowableSymbol = symbolTable.referenceSimpleFunction(getJsInternalFunction("extendThrowable")) - val setPropertiesToThrowableInstanceSymbol = symbolTable.referenceSimpleFunction(getJsInternalFunction("setPropertiesToThrowableInstance")) + val setPropertiesToThrowableInstanceSymbol = + symbolTable.referenceSimpleFunction(getJsInternalFunction("setPropertiesToThrowableInstance")) val throwISEsymbol = symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_ISE"))).single()) val throwIAEsymbol = symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_IAE"))).single()) @@ -314,7 +334,8 @@ class JsIrBackendContext( val defaultThrowableCtor by lazy2 { throwableConstructors.single { !it.owner.isPrimary && it.owner.valueParameters.size == 0 } } val kpropertyBuilder = getFunctions(FqName("kotlin.js.getPropertyCallableRef")).single().let { symbolTable.referenceSimpleFunction(it) } - val klocalDelegateBuilder = getFunctions(FqName("kotlin.js.getLocalDelegateReference")).single().let { symbolTable.referenceSimpleFunction(it) } + val klocalDelegateBuilder = + getFunctions(FqName("kotlin.js.getLocalDelegateReference")).single().let { symbolTable.referenceSimpleFunction(it) } private fun referenceOperators(): Map> { val primitiveIrSymbols = irBuiltIns.primitiveIrTypes.map { it.classifierOrFail as IrClassSymbol } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt index 7f790cee076..08dfdce5d4f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.util.isPure +import org.jetbrains.kotlin.backend.common.ir.isPure import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* @@ -519,7 +519,7 @@ class BlockDecomposerTransformer( compositesLeft == 0 -> value index == 0 && dontDetachFirstArgument -> value value == null -> value - value.isPure(false) -> value + value.isPure(anyVariable = false, context = context) -> value else -> { // TODO: do not wrap if value is pure (const, variable, etc) val irVar = makeTempVar(value.type, value) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt index c1576b1c85a..781ccda36ee 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder import org.jetbrains.kotlin.ir.backend.js.utils.prependFunctionCall -import org.jetbrains.kotlin.ir.util.isPure +import org.jetbrains.kotlin.backend.common.ir.isPure import org.jetbrains.kotlin.ir.builders.declarations.addFunction import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.declarations.* diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt index 314ad29428b..c67af92c254 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.util.isPure +import org.jetbrains.kotlin.backend.common.ir.isPure import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/cleanup/CleanupLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/cleanup/CleanupLowering.kt index 4311218d931..a22cfd14bf4 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/cleanup/CleanupLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/cleanup/CleanupLowering.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.lower.cleanup import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.util.isPure +import org.jetbrains.kotlin.backend.common.ir.isPure import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.types.isNothing diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt index b4f60caf748..2d15f4993bd 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.util.isPure +import org.jetbrains.kotlin.backend.common.ir.isPure import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt index 715d25e3aea..7a94da077ef 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.wasm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.ir.isPure import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.backend.common.lower.at import org.jetbrains.kotlin.backend.common.lower.createIrBuilder diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index aea264701db..81e8d7f41e3 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -558,39 +558,4 @@ val IrFunction.originalFunction: IrFunction get() = (this as? IrAttributeContainer)?.attributeOwnerId as? IrFunction ?: this val IrProperty.originalProperty: IrProperty - get() = attributeOwnerId as? IrProperty ?: this - -// TODO: support more cases like built-in operator call and so on - -fun IrExpression?.isPure(anyVariable: Boolean, checkFields: Boolean = true): Boolean { - if (this == null) return true - - fun IrExpression.isPureImpl(): Boolean { - return when (this) { - is IrConst<*> -> true - is IrGetValue -> { - if (anyVariable) return true - val valueDeclaration = symbol.owner - if (valueDeclaration is IrVariable) !valueDeclaration.isVar - else true - } - is IrGetObjectValue -> type.isUnit() - else -> false - } - } - - if (isPureImpl()) return true - - if (!checkFields) return false - - if (this is IrGetField) { - if (!symbol.owner.isFinal) { - if (!anyVariable) { - return false - } - } - return receiver.isPure(anyVariable) - } - - return false -} + get() = attributeOwnerId as? IrProperty ?: this \ No newline at end of file