[JS IR BE] Eliminate identical IrElements duplicates
This commit is contained in:
+8
-2
@@ -19,10 +19,16 @@ import org.jetbrains.kotlin.ir.types.isUnit
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
class UnitMaterializationLowering(context: BackendContext): FileLoweringPass {
|
||||
class UnitMaterializationLowering(context: BackendContext) : FileLoweringPass {
|
||||
|
||||
private val unitType = context.irBuiltIns.unitType
|
||||
private val unitValue = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, unitType, unitType.classifierOrFail as IrClassSymbol)
|
||||
private val unitValue
|
||||
get() = IrGetObjectValueImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
unitType,
|
||||
unitType.classifierOrFail as IrClassSymbol
|
||||
)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
|
||||
+4
-4
@@ -79,19 +79,19 @@ class BlockDecomposerLowering(context: JsIrBackendContext) : DeclarationContaine
|
||||
}
|
||||
}
|
||||
|
||||
class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransformerVoid() {
|
||||
class BlockDecomposerTransformer(private val context: JsIrBackendContext) : IrElementTransformerVoid() {
|
||||
private lateinit var function: IrFunction
|
||||
private var tmpVarCounter: Int = 0
|
||||
|
||||
private val statementTransformer = StatementTransformer()
|
||||
private val expressionTransformer = ExpressionTransformer()
|
||||
|
||||
private val constTrue = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
private val constFalse = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
|
||||
private val constTrue get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
private val constFalse get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
|
||||
private val nothingType = context.irBuiltIns.nothingNType
|
||||
|
||||
private val unitType = context.irBuiltIns.unitType
|
||||
private val unitValue = JsIrBuilder.buildGetObjectValue(unitType, context.symbolTable.referenceClass(context.builtIns.unit))
|
||||
private val unitValue get() = JsIrBuilder.buildGetObjectValue(unitType, context.symbolTable.referenceClass(context.builtIns.unit))
|
||||
|
||||
private val unreachableFunction = context.intrinsics.unreachable
|
||||
private val booleanNotSymbol = context.irBuiltIns.booleanNotSymbol
|
||||
|
||||
+9
-9
@@ -43,9 +43,9 @@ data class CallableReferenceKey(
|
||||
|
||||
// TODO: generate $metadata$ property and fill it with corresponding KFunction/KProperty interface
|
||||
class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val callableNameConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KCALLABLE_NAME)
|
||||
private val getterConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_GET)
|
||||
private val setterConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_SET)
|
||||
private val callableNameConst get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KCALLABLE_NAME)
|
||||
private val getterConst get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_GET)
|
||||
private val setterConst get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_SET)
|
||||
private val callableToFactoryFunction = context.callableReferencesCache
|
||||
|
||||
private val newDeclarations = mutableListOf<IrDeclaration>()
|
||||
@@ -327,13 +327,13 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
|
||||
//
|
||||
val cacheName = "${factoryFunction.name}_${Namer.KCALLABLE_CACHE_SUFFIX}"
|
||||
val type = factoryFunction.returnType
|
||||
val irNull = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
|
||||
val cacheVar = JsIrBuilder.buildVar(type, factoryFunction.parent, cacheName, true, initializer = irNull)
|
||||
val irNull = { JsIrBuilder.buildNull(context.irBuiltIns.nothingNType) }
|
||||
val cacheVar = JsIrBuilder.buildVar(type, factoryFunction.parent, cacheName, true, initializer = irNull())
|
||||
|
||||
val irCacheValue = JsIrBuilder.buildGetValue(cacheVar.symbol)
|
||||
val irCacheValue = { JsIrBuilder.buildGetValue(cacheVar.symbol) }
|
||||
val irIfCondition = JsIrBuilder.buildCall(context.irBuiltIns.eqeqSymbol).apply {
|
||||
putValueArgument(0, irCacheValue)
|
||||
putValueArgument(1, irNull)
|
||||
putValueArgument(0, irCacheValue())
|
||||
putValueArgument(1, irNull())
|
||||
}
|
||||
val irSetCache =
|
||||
JsIrBuilder.buildSetVariable(cacheVar.symbol, JsIrBuilder.buildGetValue(varSymbol), context.irBuiltIns.unitType)
|
||||
@@ -344,7 +344,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
|
||||
val irThenBranch = JsIrBuilder.buildBlock(context.irBuiltIns.unitType, thenStatements)
|
||||
val irIfNode = JsIrBuilder.buildIfElse(context.irBuiltIns.unitType, irIfCondition, irThenBranch)
|
||||
statements += irIfNode
|
||||
returnValue = irCacheValue
|
||||
returnValue = irCacheValue()
|
||||
returnStatements = listOf(cacheVar)
|
||||
} else {
|
||||
statements += bodyStatements
|
||||
|
||||
+6
-6
@@ -51,7 +51,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
*/
|
||||
|
||||
class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
val litTrue = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
val litTrue get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
val unitType = context.irBuiltIns.unitType
|
||||
val nothingType = context.irBuiltIns.nothingType
|
||||
|
||||
@@ -70,7 +70,7 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
|
||||
val commonType = mergeTypes(aTry.catches.map { it.catchParameter.type })
|
||||
|
||||
val pendingExceptionDeclaration = JsIrBuilder.buildVar(commonType, data, "\$p")
|
||||
val pendingException = JsIrBuilder.buildGetValue(pendingExceptionDeclaration.symbol)
|
||||
val pendingException = { JsIrBuilder.buildGetValue(pendingExceptionDeclaration.symbol) }
|
||||
|
||||
val branches = mutableListOf<IrBranch>()
|
||||
|
||||
@@ -81,9 +81,9 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
|
||||
val typeSymbol = type.classifierOrNull
|
||||
val castedPendingException = {
|
||||
if (type !is IrDynamicType)
|
||||
buildImplicitCast(pendingException, type, typeSymbol!!)
|
||||
buildImplicitCast(pendingException(), type, typeSymbol!!)
|
||||
else
|
||||
pendingException
|
||||
pendingException()
|
||||
}
|
||||
|
||||
val catchBody = catch.result.transform(object : IrElementTransformer<IrValueSymbol> {
|
||||
@@ -98,14 +98,14 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
|
||||
branches += IrElseBranchImpl(catch.startOffset, catch.endOffset, litTrue, catchBody)
|
||||
break
|
||||
} else {
|
||||
val typeCheck = buildIsCheck(pendingException, type, typeSymbol!!)
|
||||
val typeCheck = buildIsCheck(pendingException(), type, typeSymbol!!)
|
||||
branches += IrBranchImpl(catch.startOffset, catch.endOffset, typeCheck, catchBody)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (commonType !is IrDynamicType) {
|
||||
val throwStatement = JsIrBuilder.buildThrow(nothingType, pendingException)
|
||||
val throwStatement = JsIrBuilder.buildThrow(nothingType, pendingException())
|
||||
branches += IrElseBranchImpl(litTrue, JsIrBuilder.buildBlock(nothingType, listOf(throwStatement)))
|
||||
}
|
||||
|
||||
|
||||
+16
-16
@@ -40,9 +40,9 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
|
||||
private val propertySetter = context.intrinsics.jsSetJSField.symbol
|
||||
private val eqeqeqSymbol = context.irBuiltIns.eqeqSymbol
|
||||
|
||||
private val messageName = JsIrBuilder.buildString(stringType, "message")
|
||||
private val causeName = JsIrBuilder.buildString(stringType, "cause")
|
||||
private val nameName = JsIrBuilder.buildString(stringType, "name")
|
||||
private val messageName get() = JsIrBuilder.buildString(stringType, "message")
|
||||
private val causeName get() = JsIrBuilder.buildString(stringType, "cause")
|
||||
private val nameName get() = JsIrBuilder.buildString(stringType, "name")
|
||||
|
||||
private val throwableClass = context.symbolTable.referenceClass(
|
||||
context.getClass(JsIrBackendContext.KOTLIN_PACKAGE_FQN.child(Name.identifier("Throwable")))
|
||||
@@ -121,15 +121,15 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
|
||||
}
|
||||
|
||||
private fun extractConstructorParameters(expression: IrFunctionAccessExpression): Pair<IrExpression, IrExpression> {
|
||||
val nullValue = IrConstImpl.constNull(expression.startOffset, expression.endOffset, nothingNType)
|
||||
val nullValue = { IrConstImpl.constNull(expression.startOffset, expression.endOffset, nothingNType) }
|
||||
return when {
|
||||
expression.valueArgumentsCount == 0 -> Pair(nullValue, nullValue)
|
||||
expression.valueArgumentsCount == 0 -> Pair(nullValue(), nullValue())
|
||||
expression.valueArgumentsCount == 2 -> expression.run { Pair(getValueArgument(0)!!, getValueArgument(1)!!) }
|
||||
else -> {
|
||||
val arg = expression.getValueArgument(0)!!
|
||||
when {
|
||||
arg.type.makeNotNull().isThrowable() -> Pair(nullValue, arg)
|
||||
else -> Pair(arg, nullValue)
|
||||
arg.type.makeNotNull().isThrowable() -> Pair(nullValue(), arg)
|
||||
else -> Pair(arg, nullValue())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,7 +229,7 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
|
||||
}
|
||||
|
||||
val klass = successor.klass
|
||||
val receiver = IrGetValueImpl(expression.startOffset, expression.endOffset, klass.thisReceiver!!.symbol)
|
||||
val receiver = { IrGetValueImpl(expression.startOffset, expression.endOffset, klass.thisReceiver!!.symbol) }
|
||||
|
||||
val fillStatements = fillThrowableInstance(expression, receiver, messageArg, causeArg)
|
||||
|
||||
@@ -240,21 +240,21 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
|
||||
|
||||
private fun fillThrowableInstance(
|
||||
expression: IrFunctionAccessExpression,
|
||||
receiver: IrExpression,
|
||||
receiver: () -> IrExpression,
|
||||
messageArg: IrExpression,
|
||||
causeArg: IrExpression
|
||||
): List<IrStatement> {
|
||||
|
||||
val setMessage = expression.run {
|
||||
IrSetFieldImpl(startOffset, endOffset, successor.message.symbol, receiver, messageArg, unitType)
|
||||
IrSetFieldImpl(startOffset, endOffset, successor.message.symbol, receiver(), messageArg, unitType)
|
||||
}
|
||||
|
||||
val setCause = expression.run {
|
||||
IrSetFieldImpl(startOffset, endOffset, successor.cause.symbol, receiver, causeArg, unitType)
|
||||
IrSetFieldImpl(startOffset, endOffset, successor.cause.symbol, receiver(), causeArg, unitType)
|
||||
}
|
||||
|
||||
val setStackTrace = IrCallImpl(expression.startOffset, expression.endOffset, unitType, captureStackFunction).apply {
|
||||
putValueArgument(0, receiver)
|
||||
putValueArgument(0, receiver())
|
||||
}
|
||||
|
||||
return listOf(setMessage, setCause, setStackTrace)
|
||||
@@ -264,10 +264,10 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
|
||||
expression: IrFunctionAccessExpression,
|
||||
parent: IrDeclarationParent
|
||||
): Triple<IrExpression, IrExpression, List<IrStatement>> {
|
||||
val nullValue = IrConstImpl.constNull(expression.startOffset, expression.endOffset, nothingNType)
|
||||
val nullValue = { IrConstImpl.constNull(expression.startOffset, expression.endOffset, nothingNType) }
|
||||
// Wrap parameters into variables to keep original evaluation order
|
||||
return when {
|
||||
expression.valueArgumentsCount == 0 -> Triple(nullValue, nullValue, emptyList())
|
||||
expression.valueArgumentsCount == 0 -> Triple(nullValue(), nullValue(), emptyList())
|
||||
expression.valueArgumentsCount == 2 -> {
|
||||
val msg = expression.getValueArgument(0)!!
|
||||
val cus = expression.getValueArgument(1)!!
|
||||
@@ -276,7 +276,7 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
|
||||
|
||||
val check = JsIrBuilder.buildCall(eqeqeqSymbol, booleanType).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(irValM.symbol))
|
||||
putValueArgument(1, nullValue)
|
||||
putValueArgument(1, nullValue())
|
||||
}
|
||||
|
||||
val msgElvis = JsIrBuilder.buildIfElse(
|
||||
@@ -292,7 +292,7 @@ class ThrowableSuccessorsLowering(context: JsIrBackendContext) : FileLoweringPas
|
||||
val argValue = JsIrBuilder.buildGetValue(irVal.symbol)
|
||||
when {
|
||||
arg.type.makeNotNull().isThrowable() -> Triple(safeCallToString(irVal), argValue, listOf(irVal))
|
||||
else -> Triple(argValue, nullValue, listOf(irVal))
|
||||
else -> Triple(argValue, nullValue(), listOf(irVal))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+47
-46
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
@@ -31,13 +32,13 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
|
||||
class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val unit = context.irBuiltIns.unitType
|
||||
private val unitValue = JsIrBuilder.buildGetObjectValue(unit, unit.classifierOrFail as IrClassSymbol)
|
||||
private val unitValue get() = JsIrBuilder.buildGetObjectValue(unit, unit.classifierOrFail as IrClassSymbol)
|
||||
|
||||
private val lit24 = JsIrBuilder.buildInt(context.irBuiltIns.intType, 24)
|
||||
private val lit16 = JsIrBuilder.buildInt(context.irBuiltIns.intType, 16)
|
||||
private val lit24 get() = JsIrBuilder.buildInt(context.irBuiltIns.intType, 24)
|
||||
private val lit16 get() = JsIrBuilder.buildInt(context.irBuiltIns.intType, 16)
|
||||
|
||||
private val byteMask = JsIrBuilder.buildInt(context.irBuiltIns.intType, 0xFF)
|
||||
private val shortMask = JsIrBuilder.buildInt(context.irBuiltIns.intType, 0xFFFF)
|
||||
private val byteMask get() = JsIrBuilder.buildInt(context.irBuiltIns.intType, 0xFF)
|
||||
private val shortMask get() = JsIrBuilder.buildInt(context.irBuiltIns.intType, 0xFFFF)
|
||||
|
||||
private val calculator = JsIrArithBuilder(context)
|
||||
|
||||
@@ -56,14 +57,14 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val typeOfIntrinsicSymbol = context.intrinsics.jsTypeOf.symbol
|
||||
private val jsClassIntrinsicSymbol = context.intrinsics.jsClass
|
||||
|
||||
private val stringMarker = JsIrBuilder.buildString(context.irBuiltIns.stringType, "string")
|
||||
private val booleanMarker = JsIrBuilder.buildString(context.irBuiltIns.stringType, "boolean")
|
||||
private val functionMarker = JsIrBuilder.buildString(context.irBuiltIns.stringType, "function")
|
||||
private val numberMarker = JsIrBuilder.buildString(context.irBuiltIns.stringType, "number")
|
||||
private val stringMarker get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, "string")
|
||||
private val booleanMarker get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, "boolean")
|
||||
private val functionMarker get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, "function")
|
||||
private val numberMarker get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, "number")
|
||||
|
||||
private val litTrue: IrExpression = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
private val litFalse: IrExpression = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
|
||||
private val litNull: IrExpression = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
|
||||
private val litTrue: IrExpression get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
private val litFalse: IrExpression get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
|
||||
private val litNull: IrExpression get() = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
|
||||
@@ -96,9 +97,9 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
val newStatements = mutableListOf<IrStatement>()
|
||||
|
||||
val argument = cacheValue(expression.argument, newStatements, declaration)
|
||||
val irNullCheck = nullCheck(argument)
|
||||
val irNullCheck = nullCheck(argument())
|
||||
|
||||
newStatements += JsIrBuilder.buildIfElse(expression.typeOperand, irNullCheck, JsIrBuilder.buildCall(throwNPE), argument)
|
||||
newStatements += JsIrBuilder.buildIfElse(expression.typeOperand, irNullCheck, JsIrBuilder.buildCall(throwNPE), argument())
|
||||
|
||||
return expression.run { IrCompositeImpl(startOffset, endOffset, typeOperand, null, newStatements) }
|
||||
}
|
||||
@@ -117,12 +118,13 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
val newStatements = mutableListOf<IrStatement>()
|
||||
|
||||
val argument = cacheValue(expression.argument, newStatements, declaration)
|
||||
|
||||
val check = generateTypeCheck(argument, toType)
|
||||
|
||||
newStatements += JsIrBuilder.buildIfElse(toType, check, argument, failResult)
|
||||
newStatements += JsIrBuilder.buildIfElse(toType, check, argument(), failResult)
|
||||
|
||||
return expression.run { IrCompositeImpl(startOffset, endOffset, toType, null, newStatements) }
|
||||
return expression.run {
|
||||
IrCompositeImpl(startOffset, endOffset, toType, null, newStatements)
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerImplicitCast(expression: IrTypeOperatorCall) = expression.run {
|
||||
@@ -155,18 +157,19 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
assert((expression.operator == IrTypeOperator.NOT_INSTANCEOF) == inverted)
|
||||
|
||||
val toType = expression.typeOperand
|
||||
val isCopyRequired = expression.argument.type.isNullable() && advancedCheckRequired(toType.makeNotNull())
|
||||
val newStatements = mutableListOf<IrStatement>()
|
||||
|
||||
val argument =
|
||||
if (isCopyRequired) cacheValue(expression.argument, newStatements, declaration) else expression.argument
|
||||
val argument = cacheValue(expression.argument, newStatements, declaration)
|
||||
val check = generateTypeCheck(argument, toType)
|
||||
val result = if (inverted) calculator.not(check) else check
|
||||
|
||||
return if (isCopyRequired) {
|
||||
newStatements += result
|
||||
IrCompositeImpl(expression.startOffset, expression.endOffset, toType, null, newStatements)
|
||||
} else result
|
||||
newStatements += result
|
||||
return IrCompositeImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
context.irBuiltIns.booleanType,
|
||||
null,
|
||||
newStatements
|
||||
)
|
||||
}
|
||||
|
||||
private fun nullCheck(value: IrExpression) = JsIrBuilder.buildCall(eqeq).apply {
|
||||
@@ -178,40 +181,41 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
value: IrExpression,
|
||||
newStatements: MutableList<IrStatement>,
|
||||
declaration: IrDeclarationParent
|
||||
): IrExpression {
|
||||
): () -> IrExpressionWithCopy {
|
||||
val varDeclaration = JsIrBuilder.buildVar(value.type, declaration, initializer = value)
|
||||
newStatements += varDeclaration
|
||||
return JsIrBuilder.buildGetValue(varDeclaration.symbol)
|
||||
return { JsIrBuilder.buildGetValue(varDeclaration.symbol) }
|
||||
}
|
||||
|
||||
private fun generateTypeCheck(argument: IrExpression, toType: IrType): IrExpression {
|
||||
private fun generateTypeCheck(argument: () -> IrExpressionWithCopy, toType: IrType): IrExpression {
|
||||
|
||||
// TODO: Fix unbound symbols (in inline)
|
||||
toType.classifierOrNull?.apply {
|
||||
if (!isBound) {
|
||||
return argument
|
||||
return argument()
|
||||
}
|
||||
}
|
||||
|
||||
val toNotNullable = toType.makeNotNull()
|
||||
val instanceCheck = generateTypeCheckNonNull(argument, toNotNullable)
|
||||
val isFromNullable = argument.type.isNullable()
|
||||
val argumentInstance = argument()
|
||||
val instanceCheck = generateTypeCheckNonNull(argumentInstance, toNotNullable)
|
||||
val isFromNullable = argumentInstance.type.isNullable()
|
||||
val isToNullable = toType.isNullable()
|
||||
val isNativeCheck = !advancedCheckRequired(toNotNullable)
|
||||
|
||||
return when {
|
||||
!isFromNullable -> instanceCheck // ! -> *
|
||||
isToNullable -> calculator.run { oror(nullCheck(argument), instanceCheck) } // * -> ?
|
||||
isToNullable -> calculator.run { oror(nullCheck(argument()), instanceCheck) } // * -> ?
|
||||
else -> if (isNativeCheck) instanceCheck else calculator.run {
|
||||
andand(
|
||||
not(nullCheck(argument)),
|
||||
not(nullCheck(argument())),
|
||||
instanceCheck
|
||||
)
|
||||
} // ? -> !
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateTypeCheckNonNull(argument: IrExpression, toType: IrType): IrExpression {
|
||||
private fun generateTypeCheckNonNull(argument: IrExpressionWithCopy, toType: IrType): IrExpression {
|
||||
assert(!toType.isMarkedNullable())
|
||||
return when {
|
||||
toType.isAny() -> generateIsObjectCheck(argument)
|
||||
@@ -232,7 +236,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
putValueArgument(0, argument)
|
||||
}
|
||||
|
||||
private fun generateTypeCheckWithTypeParameter(argument: IrExpression, toType: IrType): IrExpression {
|
||||
private fun generateTypeCheckWithTypeParameter(argument: IrExpressionWithCopy, toType: IrType): IrExpression {
|
||||
val typeParameterSymbol =
|
||||
(toType.classifierOrNull as? IrTypeParameterSymbol) ?: error("expected type parameter, but $toType")
|
||||
|
||||
@@ -244,9 +248,8 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
val typeParameter = typeParameterSymbol.owner
|
||||
|
||||
assert(!typeParameter.isReified) { "reified parameters have to be lowered before" }
|
||||
|
||||
return typeParameter.superTypes.fold(litTrue) { r, t ->
|
||||
val check = generateTypeCheckNonNull(argument, t.makeNotNull())
|
||||
val check = generateTypeCheckNonNull(argument.copy(), t.makeNotNull())
|
||||
calculator.and(r, check)
|
||||
}
|
||||
}
|
||||
@@ -314,25 +317,23 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
val isNullable = expression.argument.type.isNullable()
|
||||
val toType = expression.typeOperand
|
||||
|
||||
fun maskOp(arg: IrExpression, mask: IrExpression, shift: IrExpression) = calculator.run {
|
||||
shr(shl(and(arg, mask), shift), shift)
|
||||
fun maskOp(arg: IrExpression, mask: IrExpression, shift: IrExpressionWithCopy) = calculator.run {
|
||||
shr(shl(and(arg, mask), shift), shift.copy())
|
||||
}
|
||||
|
||||
val newStatements = mutableListOf<IrStatement>()
|
||||
|
||||
val argument =
|
||||
if (isNullable) cacheValue(expression.argument, newStatements, declaration) else expression.argument
|
||||
val argument = cacheValue(expression.argument, newStatements, declaration)
|
||||
|
||||
val casted = when {
|
||||
toType.isByte() -> maskOp(argument, byteMask, lit24)
|
||||
toType.isShort() -> maskOp(argument, shortMask, lit16)
|
||||
toType.isByte() -> maskOp(argument(), byteMask, lit24)
|
||||
toType.isShort() -> maskOp(argument(), shortMask, lit16)
|
||||
toType.isLong() -> JsIrBuilder.buildCall(context.intrinsics.jsToLong).apply {
|
||||
putValueArgument(0, argument)
|
||||
putValueArgument(0, argument())
|
||||
}
|
||||
else -> error("Unreachable execution (coercion to non-Integer type")
|
||||
}
|
||||
|
||||
newStatements += if (isNullable) JsIrBuilder.buildIfElse(toType, nullCheck(argument), litNull, casted) else casted
|
||||
newStatements += if (isNullable) JsIrBuilder.buildIfElse(toType, nullCheck(argument()), litNull, casted) else casted
|
||||
|
||||
return expression.run { IrCompositeImpl(startOffset, endOffset, toType, null, newStatements) }
|
||||
}
|
||||
|
||||
+1
-1
@@ -943,7 +943,7 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo
|
||||
}
|
||||
}
|
||||
|
||||
function.transform(LiveLocalsTransformer(localToPropertyMap, JsIrBuilder.buildGetValue(thisReceiver), unit), null)
|
||||
function.transform(LiveLocalsTransformer(localToPropertyMap, { JsIrBuilder.buildGetValue(thisReceiver) } , unit), null)
|
||||
}
|
||||
|
||||
private fun computeLivenessAtSuspensionPoints(body: IrBody): Map<IrCall, List<IrValueDeclaration>> {
|
||||
|
||||
+4
-4
@@ -147,19 +147,19 @@ class SuspendedTerminatorsCollector(suspendableNodes: MutableSet<IrElement>) : S
|
||||
|
||||
class LiveLocalsTransformer(
|
||||
private val localMap: Map<IrValueSymbol, IrFieldSymbol>,
|
||||
private val receiver: IrExpression,
|
||||
private val receiver: () -> IrExpression,
|
||||
private val unitType: IrType
|
||||
) :
|
||||
IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val field = localMap[expression.symbol] ?: return expression
|
||||
return expression.run { IrGetFieldImpl(startOffset, endOffset, field, type, receiver, origin) }
|
||||
return expression.run { IrGetFieldImpl(startOffset, endOffset, field, type, receiver(), origin) }
|
||||
}
|
||||
|
||||
override fun visitSetVariable(expression: IrSetVariable): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
val field = localMap[expression.symbol] ?: return expression
|
||||
return expression.run { IrSetFieldImpl(startOffset, endOffset, field, receiver, value, unitType, origin) }
|
||||
return expression.run { IrSetFieldImpl(startOffset, endOffset, field, receiver(), value, unitType, origin) }
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable): IrStatement {
|
||||
@@ -167,7 +167,7 @@ class LiveLocalsTransformer(
|
||||
val field = localMap[declaration.symbol] ?: return declaration
|
||||
val initializer = declaration.initializer
|
||||
return if (initializer != null) {
|
||||
declaration.run { IrSetFieldImpl(startOffset, endOffset, field, receiver, initializer, unitType) }
|
||||
declaration.run { IrSetFieldImpl(startOffset, endOffset, field, receiver(), initializer, unitType) }
|
||||
} else {
|
||||
JsIrBuilder.buildComposite(declaration.type)
|
||||
}
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ private class ReturnableBlockTransformer(
|
||||
return super.visitDeclaration(declaration, data)
|
||||
}
|
||||
|
||||
private val constFalse = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
|
||||
private val constFalse get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression, data: ReturnableBlockLoweringContext): IrExpression {
|
||||
if (expression !is IrReturnableBlock) return super.visitContainerExpression(expression, data)
|
||||
|
||||
@@ -28,6 +28,6 @@ interface IrExpression : IrStatement, IrVarargElement {
|
||||
}
|
||||
|
||||
interface IrExpressionWithCopy : IrExpression {
|
||||
fun copy(): IrExpression
|
||||
fun copy(): IrExpressionWithCopy
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user