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