Bug 663338 - parseInt was wrong for very small doubles. r=jandem
This commit is contained in:
26
js/src/jit-test/tests/basic/bug663338.js
Normal file
26
js/src/jit-test/tests/basic/bug663338.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
assertEq(parseInt(1.0e-7, 10), 1);
|
||||||
|
assertEq(parseInt(-1.0e-7, 10), -1);
|
||||||
|
|
||||||
|
assertEq(parseInt(9e-8, 10), 9);
|
||||||
|
assertEq(parseInt(-9e-8, 10), -9);
|
||||||
|
|
||||||
|
assertEq(parseInt(1.5e-8, 10), 1);
|
||||||
|
assertEq(parseInt(-1.5e-8, 10), -1);
|
||||||
|
|
||||||
|
assertEq(parseInt(1.0e-6, 10), 0);
|
||||||
|
|
||||||
|
assertEq(parseInt(0, 10), 0);
|
||||||
|
assertEq(parseInt(-0, 10), 0);
|
||||||
|
|
||||||
|
assertEq(parseInt('0', 10), 0);
|
||||||
|
assertEq(parseInt('-0', 10), -0);
|
||||||
|
|
||||||
|
/* this is not very hacky, but we try to get a double value of 0, instead of int */
|
||||||
|
assertEq(parseInt(Math.asin(0), 10), 0);
|
||||||
|
assertEq(parseInt(Math.asin(-0), 10), 0);
|
||||||
@@ -391,30 +391,22 @@ ParseIntStringHelper(JSContext *cx, const jschar *ws, const jschar *end, int may
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jsdouble
|
|
||||||
ParseIntDoubleHelper(jsdouble d)
|
|
||||||
{
|
|
||||||
JS_ASSERT(-1e21 < d && d < 1e21);
|
|
||||||
if (d > 0)
|
|
||||||
return floor(d);
|
|
||||||
if (d < 0)
|
|
||||||
return -floor(-d);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See ECMA 15.1.2.2. */
|
/* See ECMA 15.1.2.2. */
|
||||||
static JSBool
|
static JSBool
|
||||||
num_parseInt(JSContext *cx, uintN argc, Value *vp)
|
num_parseInt(JSContext *cx, uintN argc, Value *vp)
|
||||||
{
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
/* Fast paths and exceptional cases. */
|
/* Fast paths and exceptional cases. */
|
||||||
if (argc == 0) {
|
if (args.length() == 0) {
|
||||||
vp->setDouble(js_NaN);
|
args.rval().setDouble(js_NaN);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 1 || (vp[3].isInt32() && (vp[3].toInt32() == 0 || vp[3].toInt32() == 10))) {
|
if (args.length() == 1 ||
|
||||||
if (vp[2].isInt32()) {
|
(args[1].isInt32() && (args[1].toInt32() == 0 || args[1].toInt32() == 10))) {
|
||||||
*vp = vp[2];
|
if (args[0].isInt32()) {
|
||||||
|
args.rval() = args[0];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -424,30 +416,42 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
|
|||||||
*
|
*
|
||||||
* To preserve this behaviour, we can't use the fast-path when string >
|
* To preserve this behaviour, we can't use the fast-path when string >
|
||||||
* 1e21, or else the result would be |NeM|.
|
* 1e21, or else the result would be |NeM|.
|
||||||
|
*
|
||||||
|
* The same goes for values smaller than 1.0e-6, because the string would be in
|
||||||
|
* the form of "Ne-M".
|
||||||
*/
|
*/
|
||||||
if (vp[2].isDouble() &&
|
if (args[0].isDouble()) {
|
||||||
vp[2].toDouble() > -1.0e21 &&
|
double d = args[0].toDouble();
|
||||||
vp[2].toDouble() < 1.0e21) {
|
if (1.0e-6 < d && d < 1.0e21) {
|
||||||
vp->setNumber(ParseIntDoubleHelper(vp[2].toDouble()));
|
args.rval().setNumber(floor(d));
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
if (-1.0e21 < d && d < -1.0e-6) {
|
||||||
|
args.rval().setNumber(-floor(-d));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (d == 0.0) {
|
||||||
|
args.rval().setInt32(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 1. */
|
/* Step 1. */
|
||||||
JSString *inputString = js_ValueToString(cx, vp[2]);
|
JSString *inputString = js_ValueToString(cx, args[0]);
|
||||||
if (!inputString)
|
if (!inputString)
|
||||||
return false;
|
return false;
|
||||||
vp[2].setString(inputString);
|
args[0].setString(inputString);
|
||||||
|
|
||||||
/* 15.1.2.2 steps 6-8. */
|
/* 15.1.2.2 steps 6-8. */
|
||||||
bool stripPrefix = true;
|
bool stripPrefix = true;
|
||||||
int32_t radix = 0;
|
int32 radix = 0;
|
||||||
if (argc > 1) {
|
if (args.length() > 1) {
|
||||||
if (!ValueToECMAInt32(cx, vp[3], &radix))
|
if (!ValueToECMAInt32(cx, args[1], &radix))
|
||||||
return false;
|
return false;
|
||||||
if (radix != 0) {
|
if (radix != 0) {
|
||||||
if (radix < 2 || radix > 36) {
|
if (radix < 2 || radix > 36) {
|
||||||
vp->setDouble(js_NaN);
|
args.rval().setDouble(js_NaN);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (radix != 16)
|
if (radix != 16)
|
||||||
@@ -466,7 +470,7 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Step 15. */
|
/* Step 15. */
|
||||||
vp->setNumber(number);
|
args.rval().setNumber(number);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user