Upgrade Number constructor to ES6.

Add missing constants, predicates and functions to the Number
constructor to have it offer what ES6 now specifies.

That is, extend it with:

 * isInteger(), isSafeInteger()
 * parseInt(), parseFloat()
 * EPSILON, MIN_SAFE_INTEGER, MAX_SAFE_INTEGER

LOG=N
R=mstarzinger@chromium.org
BUG=v8:3082

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

Patch from Sigbjorn Finne <sigbjornf@opera.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18480 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2014-01-08 09:09:49 +00:00
parent b712779479
commit 127c660eab
5 changed files with 146 additions and 26 deletions

View File

@ -79,6 +79,21 @@ function InstallGetterSetter(object, name, getter, setter) {
}
// Helper function for installing constant properties on objects.
function InstallConstants(object, constants) {
if (constants.length >= 4) {
%OptimizeObjectForAddingMultipleProperties(object, constants.length >> 1);
}
var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
for (var i = 0; i < constants.length; i += 2) {
var name = constants[i];
var k = constants[i + 1];
%SetProperty(object, name, k, attributes);
}
%ToFastProperties(object);
}
// Prevents changes to the prototype of a built-in function.
// The "prototype" property of the function object is made non-configurable,
// and the prototype object is made non-extensible. The latter prevents
@ -1624,12 +1639,29 @@ function NumberIsFinite(number) {
}
// Harmony isInteger
function NumberIsInteger(number) {
return NumberIsFinite(number) && TO_INTEGER(number) == number;
}
// Harmony isNaN.
function NumberIsNaN(number) {
return IS_NUMBER(number) && NUMBER_IS_NAN(number);
}
// Harmony isSafeInteger
function NumberIsSafeInteger(number) {
if (NumberIsFinite(number)) {
var integral = TO_INTEGER(number);
if (integral == number)
return MathAbs(integral) <= $Number.MAX_SAFE_INTEGER;
}
return false;
}
// ----------------------------------------------------------------------------
function SetUpNumber() {
@ -1642,32 +1674,24 @@ function SetUpNumber() {
// Set up the constructor property on the Number prototype object.
%SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
%OptimizeObjectForAddingMultipleProperties($Number, 5);
// ECMA-262 section 15.7.3.1.
%SetProperty($Number,
"MAX_VALUE",
1.7976931348623157e+308,
DONT_ENUM | DONT_DELETE | READ_ONLY);
InstallConstants($Number, $Array(
// ECMA-262 section 15.7.3.1.
"MAX_VALUE", 1.7976931348623157e+308,
// ECMA-262 section 15.7.3.2.
"MIN_VALUE", 5e-324,
// ECMA-262 section 15.7.3.3.
"NaN", NAN,
// ECMA-262 section 15.7.3.4.
"NEGATIVE_INFINITY", -INFINITY,
// ECMA-262 section 15.7.3.5.
"POSITIVE_INFINITY", INFINITY,
// ECMA-262 section 15.7.3.2.
%SetProperty($Number, "MIN_VALUE", 5e-324,
DONT_ENUM | DONT_DELETE | READ_ONLY);
// --- Harmony constants (no spec refs until settled.)
// ECMA-262 section 15.7.3.3.
%SetProperty($Number, "NaN", NAN, DONT_ENUM | DONT_DELETE | READ_ONLY);
// ECMA-262 section 15.7.3.4.
%SetProperty($Number,
"NEGATIVE_INFINITY",
-INFINITY,
DONT_ENUM | DONT_DELETE | READ_ONLY);
// ECMA-262 section 15.7.3.5.
%SetProperty($Number,
"POSITIVE_INFINITY",
INFINITY,
DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Number);
"MAX_SAFE_INTEGER", %_MathPow(2, 53) - 1,
"MIN_SAFE_INTEGER", -%_MathPow(2, 53) + 1,
"EPSILON", %_MathPow(2, -52)
));
// Set up non-enumerable functions on the Number prototype object.
InstallFunctions($Number.prototype, DONT_ENUM, $Array(
@ -1678,9 +1702,15 @@ function SetUpNumber() {
"toExponential", NumberToExponential,
"toPrecision", NumberToPrecision
));
// Harmony Number constructor additions
InstallFunctions($Number, DONT_ENUM, $Array(
"isFinite", NumberIsFinite,
"isNaN", NumberIsNaN
"isInteger", NumberIsInteger,
"isNaN", NumberIsNaN,
"isSafeInteger", NumberIsSafeInteger,
"parseInt", GlobalParseInt,
"parseFloat", GlobalParseFloat
));
}

View File

@ -60,15 +60,19 @@ function test() {
testFloor(0, 0.49999999999999994);
testFloor(0, 0.5);
testFloor(0, 0.7);
testFloor(0, 1.0 - Number.EPSILON);
testFloor(-1, -0.1);
testFloor(-1, -0.49999999999999994);
testFloor(-1, -0.5);
testFloor(-1, -0.7);
testFloor(1, 1);
testFloor(1, 1.1);
testFloor(1, 1.0 + Number.EPSILON);
testFloor(1, 1.5);
testFloor(1, 1.7);
testFloor(-1, -1);
testFloor(-1, -1 + Number.EPSILON);
testFloor(-2, -1 - Number.EPSILON);
testFloor(-2, -1.1);
testFloor(-2, -1.5);
testFloor(-2, -1.7);

View File

@ -80,6 +80,15 @@ testRound(-9007199254740990, -9007199254740990);
testRound(-9007199254740991, -9007199254740991);
testRound(Number.MAX_VALUE, Number.MAX_VALUE);
testRound(-Number.MAX_VALUE, -Number.MAX_VALUE);
testRound(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
testRound(Number.MAX_SAFE_INTEGER + 1, Number.MAX_SAFE_INTEGER + 1);
testRound(Number.MAX_SAFE_INTEGER + 2, Number.MAX_SAFE_INTEGER + 2);
testRound(Number.MAX_SAFE_INTEGER + 3, Number.MAX_SAFE_INTEGER + 3);
testRound(Number.MAX_SAFE_INTEGER + 4, Number.MAX_SAFE_INTEGER + 4);
testRound(Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
testRound(Number.MIN_SAFE_INTEGER - 1, Number.MIN_SAFE_INTEGER - 1);
testRound(Number.MIN_SAFE_INTEGER - 2, Number.MIN_SAFE_INTEGER - 2);
testRound(Number.MIN_SAFE_INTEGER - 3, Number.MIN_SAFE_INTEGER - 3);
testRound(536870911, 536870910.5);
testRound(536870911, 536870911);

View File

@ -25,11 +25,16 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test Harmony Number.isFinite() and Number.isNaN() functions.
// Test number predicates that Harmony adds to the Number constructor:
// isFinite(), isNaN(), isInteger(), isSafeInteger().
assertTrue(Number.isFinite(0));
assertTrue(Number.isFinite(Number.MIN_VALUE));
assertTrue(Number.isFinite(Number.MAX_VALUE));
assertTrue(Number.isFinite(Number.MIN_SAFE_INTEGER));
assertTrue(Number.isFinite(Number.MIN_SAFE_INTEGER - 13));
assertTrue(Number.isFinite(Number.MAX_SAFE_INTEGER));
assertTrue(Number.isFinite(Number.MAX_SAFE_INTEGER + 23));
assertFalse(Number.isFinite(Number.NaN));
assertFalse(Number.isFinite(Number.POSITIVE_INFINITY));
assertFalse(Number.isFinite(Number.NEGATIVE_INFINITY));
@ -45,9 +50,12 @@ assertFalse(Number.isFinite(undefined));
assertFalse(Number.isNaN(0));
assertFalse(Number.isNaN(Number.MIN_VALUE));
assertFalse(Number.isNaN(Number.MAX_VALUE));
assertFalse(Number.isNaN(Number.MIN_SAFE_INTEGER - 13));
assertFalse(Number.isNaN(Number.MAX_SAFE_INTEGER + 23));
assertTrue(Number.isNaN(Number.NaN));
assertFalse(Number.isNaN(Number.POSITIVE_INFINITY));
assertFalse(Number.isNaN(Number.NEGATIVE_INFINITY));
assertFalse(Number.isNaN(Number.EPSILON));
assertFalse(Number.isNaN(new Number(0)));
assertFalse(Number.isNaN(1/0));
assertFalse(Number.isNaN(-1/0));
@ -56,3 +64,63 @@ assertFalse(Number.isNaN([]));
assertFalse(Number.isNaN("s"));
assertFalse(Number.isNaN(null));
assertFalse(Number.isNaN(undefined));
assertFalse(Number.isInteger({}));
assertFalse(Number.isInteger([]));
assertFalse(Number.isInteger("s"));
assertFalse(Number.isInteger(null));
assertFalse(Number.isInteger(undefined));
assertFalse(Number.isInteger(new Number(2)));
assertTrue(Number.isInteger(0));
assertFalse(Number.isInteger(Number.MIN_VALUE));
assertTrue(Number.isInteger(Number.MAX_VALUE));
assertTrue(Number.isInteger(Number.MIN_SAFE_INTEGER));
assertTrue(Number.isInteger(Number.MIN_SAFE_INTEGER - 13));
assertTrue(Number.isInteger(Number.MAX_SAFE_INTEGER));
assertTrue(Number.isInteger(Number.MAX_SAFE_INTEGER + 23));
assertFalse(Number.isInteger(Number.NaN));
assertFalse(Number.isInteger(Number.POSITIVE_INFINITY));
assertFalse(Number.isInteger(Number.NEGATIVE_INFINITY));
assertFalse(Number.isInteger(1/0));
assertFalse(Number.isInteger(-1/0));
assertFalse(Number.isInteger(Number.EPSILON));
assertFalse(Number.isSafeInteger({}));
assertFalse(Number.isSafeInteger([]));
assertFalse(Number.isSafeInteger("s"));
assertFalse(Number.isSafeInteger(null));
assertFalse(Number.isSafeInteger(undefined));
assertFalse(Number.isSafeInteger(new Number(2)));
assertTrue(Number.isSafeInteger(0));
assertTrue(Number.isSafeInteger(Number.MIN_SAFE_INTEGER));
assertFalse(Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 13));
assertTrue(Number.isSafeInteger(Number.MIN_SAFE_INTEGER + 13));
assertTrue(Number.isSafeInteger(Number.MAX_SAFE_INTEGER));
assertFalse(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 23));
assertTrue(Number.isSafeInteger(Number.MAX_SAFE_INTEGER - 23));
assertFalse(Number.isSafeInteger(Number.MIN_VALUE));
assertFalse(Number.isSafeInteger(Number.MAX_VALUE));
assertFalse(Number.isSafeInteger(Number.NaN));
assertFalse(Number.isSafeInteger(Number.POSITIVE_INFINITY));
assertFalse(Number.isSafeInteger(Number.NEGATIVE_INFINITY));
assertFalse(Number.isSafeInteger(1/0));
assertFalse(Number.isSafeInteger(-1/0));
assertFalse(Number.isSafeInteger(Number.EPSILON));
var near_upper = Math.pow(2, 52);
assertTrue(Number.isSafeInteger(near_upper));
assertFalse(Number.isSafeInteger(2 * near_upper));
assertTrue(Number.isSafeInteger(2 * near_upper - 1));
assertTrue(Number.isSafeInteger(2 * near_upper - 2));
assertFalse(Number.isSafeInteger(2 * near_upper + 1));
assertFalse(Number.isSafeInteger(2 * near_upper + 2));
assertFalse(Number.isSafeInteger(2 * near_upper + 7));
var near_lower = -near_upper;
assertTrue(Number.isSafeInteger(near_lower));
assertFalse(Number.isSafeInteger(2 * near_lower));
assertTrue(Number.isSafeInteger(2 * near_lower + 1));
assertTrue(Number.isSafeInteger(2 * near_lower + 2));
assertFalse(Number.isSafeInteger(2 * near_lower - 1));
assertFalse(Number.isSafeInteger(2 * near_lower - 2));
assertFalse(Number.isSafeInteger(2 * near_lower - 7));

View File

@ -114,3 +114,12 @@ assertEquals(state, "throwingString");
state = null;
try { parseInt(throwingString, throwingRadix); } catch (e) {}
assertEquals(state, "throwingString");
// And finally, check that the Harmony additions to the Number
// constructor is available:
assertTrue("parseInt" in Number);
assertTrue("parseFloat" in Number);
assertSame( Number.parseInt, parseInt);
assertSame(Number.parseFloat, parseFloat);
assertEquals(Number.parseFloat('0.1'), parseFloat('0.1'));
assertEquals(Number.parseInt('0xea'), parseInt('0xEA'));