提交 446c4c0a 编写于 作者: A Alexey Andreev

JS: provide overflow behaviour for int binary operations (see KT-7733)

上级 24d5bdd6
......@@ -5999,6 +5999,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("intOverflow.kt")
public void testIntOverflow() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/number/intOverflow.kt");
doTest(fileName);
}
@TestMetadata("kt2342.kt")
public void testKt2342() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/number/kt2342.kt");
......
......@@ -465,6 +465,10 @@ public final class Namer {
return sb.toString();
}
public static JsNameRef imul() {
return pureFqn("imul", kotlinObject());
}
public static boolean requiresEscaping(@NotNull String name) {
// TODO: remove if there is existing implementation of this method
// TODO: handle JavaScript keywords
......
......@@ -22,12 +22,14 @@ import com.google.common.collect.ImmutableMap;
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsInvocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.js.patterns.DescriptorPredicate;
import org.jetbrains.kotlin.js.patterns.NamePredicate;
import org.jetbrains.kotlin.js.translate.context.Namer;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.RangeToIntrinsic;
......@@ -61,13 +63,13 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
}
}
@NotNull
private static final BinaryOperationIntrinsicBase INTEGER_DIVISION_INTRINSIC = new BinaryOperationIntrinsicBase() {
private static final BinaryOperationIntrinsicBase INT_MULTIPLICATION_INTRINSIC = new BinaryOperationIntrinsicBase() {
@NotNull
@Override
public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) {
JsBinaryOperation div = new JsBinaryOperation(JsBinaryOperator.DIV, left, right);
return JsAstUtils.toInt32(div);
public JsExpression doApply(
@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context
) {
return new JsInvocation(Namer.imul(), left, right);
}
};
......@@ -91,6 +93,10 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
@NotNull
private static final NamePredicate BINARY_OPERATIONS = new NamePredicate(OperatorNameConventions.BINARY_OPERATION_NAMES);
private static final DescriptorPredicate INT_BINARY_OPERATIONS = pattern("Int.plus|minus|div(Int)");
private static final DescriptorPredicate SIMPLE_INT_MULTIPLICATION = pattern("Byte|Short.times(Byte|Short)");
private static final DescriptorPredicate INT_DIVISION = pattern("Byte|Short|Int.div(Byte|Short|Int)");
private static final DescriptorPredicate PRIMITIVE_NUMBERS_BINARY_OPERATIONS =
pattern(NamePredicate.PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS, BINARY_OPERATIONS);
......@@ -102,6 +108,7 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
);
private static final DescriptorPredicate BOOLEAN_OPERATIONS = pattern("Boolean.or|and|xor");
private static final DescriptorPredicate STRING_PLUS = pattern("String.plus");
private static final DescriptorPredicate INT_MULTIPLICATION = pattern("Int.times(Int)");
private static final DescriptorPredicate CHAR_RANGE_TO = pattern("Char.rangeTo(Char)");
private static final DescriptorPredicate NUMBER_RANGE_TO = pattern("Byte|Short|Int.rangeTo(Byte|Short|Int)");
......@@ -139,9 +146,8 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
return null;
}
if (pattern("Int|Short|Byte.div(Int|Short|Byte)").apply(descriptor)) {
return INTEGER_DIVISION_INTRINSIC;
if (INT_MULTIPLICATION.apply(descriptor)) {
return INT_MULTIPLICATION_INTRINSIC;
}
if (NUMBER_RANGE_TO.apply(descriptor)) {
return new RangeToIntrinsic(descriptor);
......@@ -153,6 +159,9 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
}
}
JsBinaryOperator operator = getOperator(descriptor);
if (INT_BINARY_OPERATIONS.apply(descriptor) || SIMPLE_INT_MULTIPLICATION.apply(descriptor) || INT_DIVISION.apply(descriptor)) {
return new IntBinaryOperationFunctionIntrinsic(operator);
}
BinaryOperationIntrinsicBase result = new PrimitiveBinaryOperationFunctionIntrinsic(operator);
if (pattern("Char.plus|minus(Int)").apply(descriptor)) {
......@@ -196,6 +205,18 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
}
}
private static class IntBinaryOperationFunctionIntrinsic extends PrimitiveBinaryOperationFunctionIntrinsic {
private IntBinaryOperationFunctionIntrinsic(@NotNull JsBinaryOperator operator) {
super(operator);
}
@NotNull
@Override
public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) {
return JsAstUtils.toInt32(super.doApply(left, right, context));
}
}
private static class CharAndIntBinaryOperationFunctionIntrinsic extends BinaryOperationIntrinsicBase {
@NotNull
......
package foo
// CHECK_CONTAINS_NO_CALLS: multiplyInline
// CHECK_CONTAINS_NO_CALLS: multiplyInline except=imul
// CHECK_NOT_CALLED: runNoinline
internal inline fun multiply(a: Int, b: Int) = a * b
......
package foo
// CHECK_CONTAINS_NO_CALLS: squareMultipliedByTwo
// CHECK_CONTAINS_NO_CALLS: squareMultipliedByTwo except=imul
internal inline fun inline1(a: Int): Int {
return a
......
package foo
// CHECK_CONTAINS_NO_CALLS: squareMultipliedByTwo
// CHECK_CONTAINS_NO_CALLS: squareMultipliedByTwo except=imul
internal inline fun inline1(a: Int): Int {
return a
......
package foo
// CHECK_CONTAINS_NO_CALLS: multiplyNoInline
// CHECK_CONTAINS_NO_CALLS: multiplyNoInline except=imul
internal inline fun multiply(a: Int, b: Int): Int {
return a * b
......
package foo
// CHECK_CONTAINS_NO_CALLS: maxBySquare
// CHECK_CONTAINS_NO_CALLS: maxBySquare except=imul
internal data class Result(var value: Int = 0, var invocationCount: Int = 0)
......
package foo
// CHECK_CONTAINS_NO_CALLS: test
// CHECK_CONTAINS_NO_CALLS: test except=imul
// CHECK_VARS_COUNT: function=test count=0
// A copy of stdlib run function.
......
package foo
fun bigValue() = 0x7FFFFFFC
fun mediumValue() = 0x12345
fun box(): String {
var v = bigValue() + 1
if (v != 0x7FFFFFFD) return "fail1: $v"
v = bigValue() + 8
if (v != -0x7FFFFFFC) return "fail2: $v"
v = mediumValue() * 0x23456
if (v != -2112496338) return "fail3: $v"
v = bigValue() * bigValue()
if (v != 16) return "fail4: $v"
return "OK"
}
\ No newline at end of file
......@@ -313,4 +313,11 @@
Kotlin.kotlinModuleMetadata = function (abiVersion, moduleName, data) {
};
Kotlin.imul = Math.imul || function (a, b) {
var ah = (a >>> 16) & 0xffff;
var al = a & 0xffff;
var bh = (b >>> 16) & 0xffff;
var bl = b & 0xffff;
return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0) | 0);
};
})();
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册