[JS IR BE] Support integer operation overflow
This commit is contained in:
@@ -143,6 +143,8 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val jsCompareTo = getInternalFunction("compareTo")
|
||||
val jsEquals = getInternalFunction("equals")
|
||||
|
||||
val jsImul = getInternalFunction("imul")
|
||||
|
||||
// Coroutines
|
||||
|
||||
val jsCoroutineContext = context.symbolTable.referenceSimpleFunction(context.coroutineContextProperty.getter!!)
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -233,6 +234,10 @@ object JsIrBuilder {
|
||||
fun buildTypeOperator(type: IrType, operator: IrTypeOperator, argument: IrExpression, toType: IrType, symbol: IrClassifierSymbol) =
|
||||
IrTypeOperatorCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, operator, toType, symbol, argument)
|
||||
|
||||
fun buildImplicitCast(value: IrExpression, toType: IrType) =
|
||||
JsIrBuilder.buildTypeOperator(toType, IrTypeOperator.IMPLICIT_CAST, value, toType, toType.classifierOrFail)
|
||||
|
||||
|
||||
fun buildNull(type: IrType) = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type)
|
||||
fun buildBoolean(type: IrType, v: Boolean) = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
|
||||
fun buildInt(type: IrType, v: Int) = IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
|
||||
@@ -267,6 +272,16 @@ fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMa
|
||||
}
|
||||
|
||||
// TODO extract to common place?
|
||||
|
||||
fun irCall(
|
||||
call: IrCall,
|
||||
newFunction: IrFunction,
|
||||
dispatchReceiverAsFirstArgument: Boolean = false,
|
||||
firstArgumentAsDispatchReceiver: Boolean = false
|
||||
): IrCall =
|
||||
irCall(call, newFunction.symbol, dispatchReceiverAsFirstArgument, firstArgumentAsDispatchReceiver)
|
||||
|
||||
|
||||
fun irCall(
|
||||
call: IrCall,
|
||||
newSymbol: IrFunctionSymbol,
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.types.isLong
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
class CallsLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val transformers = listOf(
|
||||
NumberOperatorCallsTransformer(context),
|
||||
NumberConversionCallsTransformer(context),
|
||||
DynamicCallsTransformer(context),
|
||||
EqualityAndComparisonCallsTransformer(context),
|
||||
PrimitiveContainerMemberCallTransformer(context),
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower.calls
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.irCall
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.ConversionNames
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class NumberConversionCallsTransformer(context: JsIrBackendContext) : CallsTransformer {
|
||||
private val intrinsics = context.intrinsics
|
||||
private val irBuiltIns = context.irBuiltIns
|
||||
|
||||
private val memberToTransformer = MemberToTransformer().apply {
|
||||
// Conversion rules are ported from NumberAndCharConversionFIF
|
||||
// TODO: Add Char and Number conversions
|
||||
|
||||
irBuiltIns.byteType.let {
|
||||
add(it, ConversionNames.TO_BYTE, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_DOUBLE, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_FLOAT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_INT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_SHORT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
|
||||
}
|
||||
|
||||
for (type in listOf(irBuiltIns.floatType, irBuiltIns.doubleType)) {
|
||||
add(type, ConversionNames.TO_BYTE, intrinsics.jsNumberToByte)
|
||||
add(type, ConversionNames.TO_DOUBLE, ::useDispatchReceiver)
|
||||
add(type, ConversionNames.TO_FLOAT, ::useDispatchReceiver)
|
||||
add(type, ConversionNames.TO_INT, intrinsics.jsNumberToInt)
|
||||
add(type, ConversionNames.TO_SHORT, intrinsics.jsNumberToShort)
|
||||
add(type, ConversionNames.TO_LONG, intrinsics.jsNumberToLong)
|
||||
}
|
||||
|
||||
irBuiltIns.intType.let {
|
||||
add(it, ConversionNames.TO_BYTE, intrinsics.jsToByte)
|
||||
add(it, ConversionNames.TO_DOUBLE, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_FLOAT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_INT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_SHORT, intrinsics.jsToShort)
|
||||
add(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
|
||||
}
|
||||
|
||||
irBuiltIns.shortType.let {
|
||||
add(it, ConversionNames.TO_BYTE, intrinsics.jsToByte)
|
||||
add(it, ConversionNames.TO_DOUBLE, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_FLOAT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_INT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_SHORT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
|
||||
}
|
||||
|
||||
for (type in arrayOf(irBuiltIns.byteType, irBuiltIns.intType)) {
|
||||
add(type, ConversionNames.TO_CHAR) {
|
||||
irCall(it, intrinsics.charClassSymbol.constructors.single(), dispatchReceiverAsFirstArgument = true)
|
||||
}
|
||||
}
|
||||
|
||||
for (type in arrayOf(irBuiltIns.floatType, irBuiltIns.doubleType)) {
|
||||
add(type, ConversionNames.TO_CHAR) {
|
||||
JsIrBuilder.buildCall(intrinsics.charClassSymbol.constructors.single()).apply {
|
||||
putValueArgument(0, irCall(it, intrinsics.jsNumberToInt, dispatchReceiverAsFirstArgument = true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add(irBuiltIns.charType, ConversionNames.TO_CHAR) { it.dispatchReceiver!! }
|
||||
}
|
||||
|
||||
override fun transformCall(call: IrCall): IrExpression {
|
||||
val function = call.symbol.owner
|
||||
function.dispatchReceiverParameter?.also {
|
||||
val key = SimpleMemberKey(it.type, function.name)
|
||||
memberToTransformer[key]?.also {
|
||||
return it(call)
|
||||
}
|
||||
}
|
||||
return call
|
||||
}
|
||||
|
||||
private fun useDispatchReceiver(call: IrCall): IrExpression {
|
||||
return JsIrBuilder.buildImplicitCast(call.dispatchReceiver!!, call.type)
|
||||
}
|
||||
}
|
||||
+107
-87
@@ -8,29 +8,29 @@ package org.jetbrains.kotlin.ir.backend.js.lower.calls
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.irCall
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.ConversionNames
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransformer {
|
||||
private val intrinsics = context.intrinsics
|
||||
private val irBuiltIns = context.irBuiltIns
|
||||
|
||||
private val primitiveNumbers =
|
||||
irBuiltIns.run { listOf(intType, shortType, byteType, floatType, doubleType) }
|
||||
private fun buildInt(v: Int) = JsIrBuilder.buildInt(irBuiltIns.intType, v)
|
||||
|
||||
private val memberToTransformer = MemberToTransformer().apply {
|
||||
|
||||
val primitiveNumbers =
|
||||
irBuiltIns.run { listOf(intType, shortType, byteType, floatType, doubleType) }
|
||||
|
||||
for (type in primitiveNumbers) {
|
||||
add(type, OperatorNames.UNARY_PLUS, intrinsics.jsUnaryPlus)
|
||||
add(type, OperatorNames.UNARY_MINUS, intrinsics.jsUnaryMinus)
|
||||
add(type, OperatorNames.UNARY_MINUS, ::transformUnaryMinus)
|
||||
}
|
||||
|
||||
add(irBuiltIns.stringType, OperatorNames.ADD, intrinsics.jsPlus)
|
||||
@@ -52,87 +52,23 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
|
||||
add(it, OperatorNames.XOR, intrinsics.jsBitXor)
|
||||
}
|
||||
|
||||
// Conversion rules are ported from NumberAndCharConversionFIF
|
||||
// TODO: Add Char and Number conversions
|
||||
|
||||
irBuiltIns.byteType.let {
|
||||
add(it, ConversionNames.TO_BYTE, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_DOUBLE, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_FLOAT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_INT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_SHORT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
|
||||
}
|
||||
|
||||
for (type in listOf(irBuiltIns.floatType, irBuiltIns.doubleType)) {
|
||||
add(type, ConversionNames.TO_BYTE, intrinsics.jsNumberToByte)
|
||||
add(type, ConversionNames.TO_DOUBLE, ::useDispatchReceiver)
|
||||
add(type, ConversionNames.TO_FLOAT, ::useDispatchReceiver)
|
||||
add(type, ConversionNames.TO_INT, intrinsics.jsNumberToInt)
|
||||
add(type, ConversionNames.TO_SHORT, intrinsics.jsNumberToShort)
|
||||
add(type, ConversionNames.TO_LONG, intrinsics.jsNumberToLong)
|
||||
}
|
||||
|
||||
irBuiltIns.intType.let {
|
||||
add(it, ConversionNames.TO_BYTE, intrinsics.jsToByte)
|
||||
add(it, ConversionNames.TO_DOUBLE, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_FLOAT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_INT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_SHORT, intrinsics.jsToShort)
|
||||
add(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
|
||||
}
|
||||
|
||||
irBuiltIns.shortType.let {
|
||||
add(it, ConversionNames.TO_BYTE, intrinsics.jsToByte)
|
||||
add(it, ConversionNames.TO_DOUBLE, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_FLOAT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_INT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_SHORT, ::useDispatchReceiver)
|
||||
add(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
|
||||
}
|
||||
|
||||
for (type in primitiveNumbers) {
|
||||
add(type, Name.identifier("rangeTo"), ::transformRangeTo)
|
||||
}
|
||||
|
||||
for (type in primitiveNumbers) {
|
||||
// TODO: use increment and decrement when it's possible
|
||||
add(type, OperatorNames.INC) {
|
||||
irCall(it, intrinsics.jsPlus.symbol, dispatchReceiverAsFirstArgument = true).apply {
|
||||
putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, 1))
|
||||
}
|
||||
}
|
||||
add(type, OperatorNames.DEC) {
|
||||
irCall(it, intrinsics.jsMinus.symbol, dispatchReceiverAsFirstArgument = true).apply {
|
||||
putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, 1))
|
||||
}
|
||||
}
|
||||
add(type, OperatorNames.INC, ::transformIncrement)
|
||||
add(type, OperatorNames.DEC, ::transformDecrement)
|
||||
}
|
||||
|
||||
for (type in primitiveNumbers) {
|
||||
add(type, OperatorNames.ADD, withLongCoercion(intrinsics.jsPlus))
|
||||
add(type, OperatorNames.SUB, withLongCoercion(intrinsics.jsMinus))
|
||||
add(type, OperatorNames.MUL, withLongCoercion(intrinsics.jsMult))
|
||||
add(type, OperatorNames.DIV, withLongCoercion(intrinsics.jsDiv))
|
||||
add(type, OperatorNames.MOD, withLongCoercion(intrinsics.jsMod))
|
||||
add(type, OperatorNames.REM, withLongCoercion(intrinsics.jsMod))
|
||||
add(type, OperatorNames.ADD, withLongCoercion(::transformAdd))
|
||||
add(type, OperatorNames.SUB, withLongCoercion(::transformSub))
|
||||
add(type, OperatorNames.MUL, withLongCoercion(::transformMul))
|
||||
add(type, OperatorNames.DIV, withLongCoercion(::transformDiv))
|
||||
add(type, OperatorNames.MOD, withLongCoercion(::transformRem))
|
||||
add(type, OperatorNames.REM, withLongCoercion(::transformRem))
|
||||
}
|
||||
|
||||
for (type in arrayOf(irBuiltIns.byteType, irBuiltIns.intType)) {
|
||||
add(type, ConversionNames.TO_CHAR) {
|
||||
irCall(it, intrinsics.charClassSymbol.constructors.single(), dispatchReceiverAsFirstArgument = true)
|
||||
}
|
||||
}
|
||||
|
||||
for (type in arrayOf(irBuiltIns.floatType, irBuiltIns.doubleType)) {
|
||||
add(type, ConversionNames.TO_CHAR) {
|
||||
JsIrBuilder.buildCall(intrinsics.charClassSymbol.constructors.single()).apply {
|
||||
putValueArgument(0, irCall(it, intrinsics.jsNumberToInt, dispatchReceiverAsFirstArgument = true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add(irBuiltIns.charType, ConversionNames.TO_CHAR) { it.dispatchReceiver!! }
|
||||
}
|
||||
|
||||
override fun transformCall(call: IrCall): IrExpression {
|
||||
@@ -146,10 +82,6 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
|
||||
return call
|
||||
}
|
||||
|
||||
private fun useDispatchReceiver(call: IrCall): IrExpression {
|
||||
return call.dispatchReceiver!!
|
||||
}
|
||||
|
||||
private fun transformRangeTo(call: IrCall): IrExpression {
|
||||
if (call.valueArgumentsCount != 1) return call
|
||||
return with(call.symbol.owner.valueParameters[0].type) {
|
||||
@@ -163,7 +95,83 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
|
||||
}
|
||||
}
|
||||
|
||||
private fun withLongCoercion(intrinsic: IrSimpleFunction): (IrCall) -> IrExpression = { call ->
|
||||
private fun irBinaryOp(
|
||||
call: IrCall,
|
||||
intrinsic: IrFunction,
|
||||
toInt32: Boolean = false
|
||||
): IrExpression {
|
||||
val newCall = irCall(call, intrinsic, dispatchReceiverAsFirstArgument = true)
|
||||
if (toInt32)
|
||||
return toInt32(newCall)
|
||||
return newCall
|
||||
}
|
||||
|
||||
class BinaryOp(call: IrCall) {
|
||||
val function = call.symbol.owner
|
||||
val name = function.name
|
||||
val lhs = function.dispatchReceiverParameter!!.type
|
||||
val rhs = function.valueParameters[0].type
|
||||
val result = function.returnType
|
||||
|
||||
fun canAddOrSubOverflow() =
|
||||
result.isInt() && (lhs.isInt() || rhs.isInt())
|
||||
}
|
||||
|
||||
private fun transformAdd(call: IrCall) =
|
||||
irBinaryOp(call, intrinsics.jsPlus, toInt32 = BinaryOp(call).canAddOrSubOverflow())
|
||||
|
||||
private fun transformSub(call: IrCall) =
|
||||
irBinaryOp(call, intrinsics.jsMinus, toInt32 = BinaryOp(call).canAddOrSubOverflow())
|
||||
|
||||
private fun transformMul(call: IrCall) = BinaryOp(call).run {
|
||||
when {
|
||||
result.isInt() -> when {
|
||||
|
||||
lhs.isInt() && rhs.isInt() ->
|
||||
irBinaryOp(call, intrinsics.jsImul.owner)
|
||||
|
||||
else ->
|
||||
irBinaryOp(call, intrinsics.jsMult, toInt32 = true)
|
||||
}
|
||||
|
||||
else -> irBinaryOp(call, intrinsics.jsMult, toInt32 = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformDiv(call: IrCall) =
|
||||
irBinaryOp(call, intrinsics.jsDiv, toInt32 = BinaryOp(call).result.isInt())
|
||||
|
||||
private fun transformRem(call: IrCall) =
|
||||
irBinaryOp(call, intrinsics.jsMod)
|
||||
|
||||
private fun transformIncrement(call: IrCall) =
|
||||
transformCrement(call, intrinsics.jsPlus)
|
||||
|
||||
private fun transformDecrement(call: IrCall) =
|
||||
transformCrement(call, intrinsics.jsMinus)
|
||||
|
||||
private fun transformCrement(call: IrCall, correspondingBinaryOp: IrFunction): IrExpression {
|
||||
val operation = irCall(call, correspondingBinaryOp.symbol, dispatchReceiverAsFirstArgument = true).apply {
|
||||
putValueArgument(1, buildInt(1))
|
||||
}
|
||||
|
||||
return convertResultToPrimitiveType(operation, call.type)
|
||||
}
|
||||
|
||||
private fun transformUnaryMinus(call: IrCall) =
|
||||
convertResultToPrimitiveType(
|
||||
irCall(call, intrinsics.jsUnaryMinus, dispatchReceiverAsFirstArgument = true),
|
||||
call.type
|
||||
)
|
||||
|
||||
private fun convertResultToPrimitiveType(e: IrExpression, type: IrType) = when {
|
||||
type.isInt() -> toInt32(e)
|
||||
type.isByte() -> intrinsics.jsNumberToByte.call(e)
|
||||
type.isShort() -> intrinsics.jsNumberToShort.call(e)
|
||||
else -> e
|
||||
}
|
||||
|
||||
private fun withLongCoercion(default: (IrCall) -> IrExpression): (IrCall) -> IrExpression = { call ->
|
||||
assert(call.valueArgumentsCount == 1)
|
||||
val arg = call.getValueArgument(0)!!
|
||||
|
||||
@@ -211,8 +219,20 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
|
||||
// LHS is Long => use as is
|
||||
call
|
||||
} else {
|
||||
irCall(call, intrinsic.symbol, dispatchReceiverAsFirstArgument = true)
|
||||
default(call)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun IrFunctionSymbol.call(vararg arguments: IrExpression) =
|
||||
JsIrBuilder.buildCall(this, owner.returnType).apply {
|
||||
for ((idx, arg) in arguments.withIndex()) {
|
||||
putValueArgument(idx, arg)
|
||||
}
|
||||
}
|
||||
|
||||
private fun toInt32(e: IrExpression) =
|
||||
JsIrBuilder.buildCall(intrinsics.jsBitOr.symbol, irBuiltIns.intType).apply {
|
||||
putValueArgument(0, e)
|
||||
putValueArgument(1, buildInt(0))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -279,7 +279,7 @@ class StateMachineBuilder(
|
||||
if (expression is IrReturnableBlock) processReturnableBlock(expression) else super.visitBlock(expression)
|
||||
|
||||
private fun implicitCast(value: IrExpression, toType: IrType) =
|
||||
JsIrBuilder.buildTypeOperator(toType, IrTypeOperator.IMPLICIT_CAST, value, toType, toType.classifierOrFail)
|
||||
JsIrBuilder.buildImplicitCast(value, toType)
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
super.visitCall(expression)
|
||||
|
||||
+7
@@ -140,4 +140,11 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
// TODO check when w/o else branch and empty when
|
||||
return expression.toJsNode(this, context, ::JsConditional)!!
|
||||
}
|
||||
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: JsGenerationContext): JsExpression {
|
||||
return when (expression.operator) {
|
||||
IrTypeOperator.IMPLICIT_CAST -> expression.argument.accept(this, data)
|
||||
else -> throw IllegalStateException("All type operator calls except IMPLICIT_CAST should be lowered at this point")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
fun box(): String {
|
||||
val i1: Int = Int.MAX_VALUE
|
||||
val i2 = i1 + 1
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
fun box(): String {
|
||||
val a: Long = 2147483647 + 1
|
||||
if (a != -2147483648L) return "fail: in this case we should add to ints and than cast the result to long - overflow expected"
|
||||
|
||||
+5
@@ -6404,6 +6404,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/number/longUnaryOperations.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("mixedTypesOverflow.kt")
|
||||
public void testMixedTypesOverflow() throws Exception {
|
||||
runTest("js/js.translator/testData/box/number/mixedTypesOverflow.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("mulInt32.kt")
|
||||
public void testMulInt32() throws Exception {
|
||||
runTest("js/js.translator/testData/box/number/mulInt32.kt");
|
||||
|
||||
+5
@@ -6404,6 +6404,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/number/longUnaryOperations.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("mixedTypesOverflow.kt")
|
||||
public void testMixedTypesOverflow() throws Exception {
|
||||
runTest("js/js.translator/testData/box/number/mixedTypesOverflow.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("mulInt32.kt")
|
||||
public void testMulInt32() throws Exception {
|
||||
runTest("js/js.translator/testData/box/number/mulInt32.kt");
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1282
|
||||
package foo
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1266
|
||||
|
||||
// MODULE: lib1
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1293
|
||||
package foo
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1280
|
||||
package foo
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1282
|
||||
package foo
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1284
|
||||
package foo
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1281
|
||||
package foo
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1284
|
||||
package foo
|
||||
|
||||
fun box(): String {
|
||||
val byteOne = 1.toByte()
|
||||
val shortOne = 1.toShort()
|
||||
var v: Int
|
||||
|
||||
v = maxInt() + byteOne
|
||||
if (v != minInt()) return "fail1: $v"
|
||||
|
||||
v = minInt() - byteOne
|
||||
if (v != maxInt()) return "fail2: $v"
|
||||
|
||||
v = maxInt() + shortOne
|
||||
if (v != minInt()) return "fail3: $v"
|
||||
|
||||
v = minInt() - shortOne
|
||||
if (v != maxInt()) return "fail4: $v"
|
||||
|
||||
v = maxInt() * Byte.MAX_VALUE
|
||||
if (v != 2147483521) return "fail5: $v"
|
||||
|
||||
v = maxInt() * Short.MAX_VALUE
|
||||
if (v != 2147450881) return "fail6: $v"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun minInt() = Int.MIN_VALUE
|
||||
fun maxInt() = Int.MAX_VALUE
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1289
|
||||
package foo
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1289
|
||||
package foo
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.js
|
||||
|
||||
// TODO: Polyfill
|
||||
fun imul(a: dynamic, b: dynamic) =
|
||||
js("((a & 0xffff0000) * (b & 0xffff) + (a & 0xffff) * (b | 0)) | 0")
|
||||
Reference in New Issue
Block a user