Fixes obo error in javascript int checking.

R=srdjan@google.com

Review URL: https://codereview.chromium.org//21876005

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@25733 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
zra@google.com 2013-08-02 16:06:45 +00:00
parent 7451cf3add
commit f60d2f6df4
5 changed files with 46 additions and 54 deletions

View file

@ -99,7 +99,7 @@ class _IntegerImplementation {
final int EQUAL = 0, LESS = -1, GREATER = 1;
if (other is double) {
// TODO(floitsch): the following locals should be 'const'.
int MAX_EXACT_INT_TO_DOUBLE = 9007199254740991; // 2^53 - 1.
int MAX_EXACT_INT_TO_DOUBLE = 9007199254740992; // 2^53.
int MIN_EXACT_INT_TO_DOUBLE = -MAX_EXACT_INT_TO_DOUBLE;
double d = other;
if (d.isInfinite) {

View file

@ -2151,20 +2151,15 @@ void CheckStackOverflowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
static void Emit54BitOverflowCheck(FlowGraphCompiler* compiler,
Label* overflow,
Register result) {
static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler,
Label* overflow,
Register result) {
if (FLAG_throw_on_javascript_int_overflow) {
ASSERT(overflow != NULL);
__ movq(TMP, result); // result is a tagged Smi.
// Bits 55...64 must be all 0 or all 1. (It would be bit 54, but result
// is tagged.)
__ shlq(result, Immediate(64 - 55));
__ sarq(result, Immediate(64 - 55));
__ cmpq(result, TMP);
__ j(NOT_EQUAL, overflow); // 54-bit overflow.
__ cmpq(result, Immediate(-0x1FFFFFFFFFFFFFLL - 1));
__ j(EQUAL, overflow); // The most negative 54-bit int is also disallowed.
__ cmpq(result, Immediate(-0x20000000000000));
__ j(LESS, overflow);
__ cmpq(result, Immediate(0x20000000000000));
__ j(GREATER, overflow);
}
}
@ -2208,7 +2203,7 @@ static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
// Shift for result now we know there is no overflow.
__ shlq(left, Immediate(value));
}
Emit54BitOverflowCheck(compiler, deopt, result);
EmitJavascriptOverflowCheck(compiler, deopt, result);
return;
}
@ -2238,7 +2233,7 @@ static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
__ SmiUntag(right);
__ shlq(left, right);
}
Emit54BitOverflowCheck(compiler, deopt, result);
EmitJavascriptOverflowCheck(compiler, deopt, result);
return;
}
@ -2289,7 +2284,7 @@ static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
// Shift for result now we know there is no overflow.
__ shlq(left, right);
}
Emit54BitOverflowCheck(compiler, deopt, result);
EmitJavascriptOverflowCheck(compiler, deopt, result);
}
@ -2488,7 +2483,7 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
UNREACHABLE();
break;
}
Emit54BitOverflowCheck(compiler, deopt, result);
EmitJavascriptOverflowCheck(compiler, deopt, result);
return;
} // locs()->in(1).IsConstant().
@ -2531,7 +2526,7 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
UNREACHABLE();
break;
}
Emit54BitOverflowCheck(compiler, deopt, result);
EmitJavascriptOverflowCheck(compiler, deopt, result);
return;
} // locs()->in(1).IsStackSlot().
@ -2661,7 +2656,7 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
UNREACHABLE();
break;
}
Emit54BitOverflowCheck(compiler, deopt, result);
EmitJavascriptOverflowCheck(compiler, deopt, result);
}
@ -3839,7 +3834,7 @@ void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
kDeoptUnaryOp);
__ negq(value);
__ j(OVERFLOW, deopt);
Emit54BitOverflowCheck(compiler, deopt, value);
EmitJavascriptOverflowCheck(compiler, deopt, value);
break;
}
case Token::kBIT_NOT:
@ -3900,7 +3895,7 @@ void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ shlq(temp, Immediate(1));
__ j(OVERFLOW, &do_call, Assembler::kNearJump);
__ SmiTag(result);
Emit54BitOverflowCheck(compiler, &do_call, result);
EmitJavascriptOverflowCheck(compiler, &do_call, result);
__ jmp(&done);
__ Bind(&do_call);
ASSERT(instance_call()->HasICData());
@ -3946,7 +3941,7 @@ void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ shlq(temp, Immediate(1));
__ j(OVERFLOW, deopt);
__ SmiTag(result);
Emit54BitOverflowCheck(compiler, deopt, result);
EmitJavascriptOverflowCheck(compiler, deopt, result);
}

View file

@ -11407,7 +11407,7 @@ RawInteger* Integer::New(const String& str, Heap::Space space) {
// This is called from LiteralToken::New() in the parser, so we can't
// raise an exception for 54-bit overflow here. Instead we do it in
// raise an exception for javascript overflow here. Instead we do it in
// Parser::CurrentIntegerLiteral(), which is the point in the parser where
// integer literals escape, so we can call Parser::ErrorMsg().
RawInteger* Integer::NewCanonical(const String& str) {
@ -11427,13 +11427,10 @@ RawInteger* Integer::NewCanonical(const String& str) {
}
// dart2js represents integers as double precision floats. It does this using
// a sign bit and 53 fraction bits. This gives us the range
// -2^54 - 1 ... 2^54 - 1, i.e. the same as a 54-bit signed integer
// without the most negative number. Thus, here we check if the value is
// a 54-bit signed integer and not -2^54
static bool Is54BitNoMinInt(int64_t value) {
return (Utils::IsInt(54, value)) && (value != (-0x1FFFFFFFFFFFFFLL - 1));
// dart2js represents integers as double precision floats, which can represent
// anything in the range -2^53 ... 2^53.
static bool IsJavascriptInt(int64_t value) {
return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
}
@ -11441,7 +11438,7 @@ RawInteger* Integer::New(int64_t value, Heap::Space space) {
if ((value <= Smi::kMaxValue) && (value >= Smi::kMinValue)) {
return Smi::New(value);
}
if (FLAG_throw_on_javascript_int_overflow && !Is54BitNoMinInt(value)) {
if (FLAG_throw_on_javascript_int_overflow && !IsJavascriptInt(value)) {
const Integer &i = Integer::Handle(Mint::New(value));
ThrowJavascriptIntegerOverflow(i);
}
@ -11482,7 +11479,7 @@ int Integer::CompareWith(const Integer& other) const {
// Returns true if the signed Integer does not fit into a
// Javascript (54-bit) integer.
// Javascript integer.
bool Integer::CheckJavascriptIntegerOverflow() const {
// Always overflow if the value doesn't fit into an int64_t.
int64_t value = 1ULL << 63;
@ -11500,7 +11497,7 @@ bool Integer::CheckJavascriptIntegerOverflow() const {
value = BigintOperations::ToInt64(big_value);
}
}
return !Is54BitNoMinInt(value);
return !IsJavascriptInt(value);
}

View file

@ -8,11 +8,11 @@
import "package:expect/expect.dart";
int literals() {
var okay_literal = 0x1FFFFFFFFFFFFF;
var too_big_literal = 0x20000000000000; /// 01: compile-time error
var okay_literal = 0x20000000000000;
var too_big_literal = 0x20000000000001; /// 01: compile-time error
return okay_literal;
}
main() {
Expect.equals(0x1FFFFFFFFFFFFF, literals());
Expect.equals(0x20000000000000, literals());
}

View file

@ -29,12 +29,12 @@ int integer_shift() {
int max_add_throws() {
return 0x1FFFFFFFFFFFFF + 1;
return 0x20000000000000 + 1;
}
int min_sub_throws() {
return -0x1FFFFFFFFFFFFF - 1;
return -0x20000000000000 - 1;
}
@ -45,12 +45,12 @@ int negate() {
int max_literal() {
return 0x1FFFFFFFFFFFFF;
return 0x20000000000000;
}
int min_literal() {
var min_literal = -0x1FFFFFFFFFFFFF;
var min_literal = -0x20000000000000;
return min_literal;
}
@ -60,21 +60,21 @@ bool isJavascriptIntError(e) =>
e is Error && "$e".startsWith("Javascript Integer Overflow:");
main() {
Expect.equals(0x1FFFFFFFFFFFFF, max_literal());
Expect.equals(-0x1FFFFFFFFFFFFF, min_literal());
Expect.equals(0x20000000000000, max_literal());
Expect.equals(-0x20000000000000, min_literal());
// Run the tests once before optimizations.
dti_arg = 1.9e16;
dti_arg = 1.9e17;
Expect.throws(double_to_int, isJavascriptIntError);
ia_arg1 = (1 << 52);
ia_arg2 = (1 << 52);
ia_arg1 = (1 << 53);
ia_arg2 = (1 << 53);
Expect.throws(integer_add, isJavascriptIntError);
n_arg = -0x1FFFFFFFFFFFFF;
Expect.equals(0x1FFFFFFFFFFFFF, negate());
n_arg = -0x20000000000000;
Expect.equals(0x20000000000000, negate());
is_arg = (1 << 52);
is_arg = (1 << 53);
Expect.throws(integer_shift, isJavascriptIntError);
Expect.throws(max_add_throws, isJavascriptIntError);
@ -101,17 +101,17 @@ main() {
}
// The optimized functions should now deoptimize and throw the error.
dti_arg = 1.9e16;
dti_arg = 1.9e17;
Expect.throws(double_to_int, isJavascriptIntError);
ia_arg1 = (1 << 52);
ia_arg2 = (1 << 52);
ia_arg1 = (1 << 53);
ia_arg2 = (1 << 53);
Expect.throws(integer_add, isJavascriptIntError);
n_arg = -0x1FFFFFFFFFFFFF;
Expect.equals(0x1FFFFFFFFFFFFF, negate());
n_arg = -0x20000000000000;
Expect.equals(0x20000000000000, negate());
is_arg = (1 << 52);
is_arg = (1 << 53);
Expect.throws(integer_shift, isJavascriptIntError);
Expect.throws(max_add_throws, isJavascriptIntError);