Revision: 13160
Author: [email protected]
Date: Fri Dec 7 02:20:35 2012
Log: Fix spec violations in methods of Number.prototype.
[email protected]
BUG=v8:2443
Review URL: https://chromiumcodereview.appspot.com/11465005
http://code.google.com/p/v8/source/detail?r=13160
Added:
/branches/bleeding_edge/test/mjsunit/regress/regress-2443.js
Modified:
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/v8natives.js
/branches/bleeding_edge/test/mjsunit/function-call.js
/branches/bleeding_edge/test/mjsunit/regress/regress-crbug-18639.js
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-2443.js Fri Dec 7
02:20:35 2012
@@ -0,0 +1,129 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Number.prototype methods on non-Numbers.
+
+assertThrows(function() { Number.prototype.toExponential.call({}) },
+ TypeError);
+
+assertThrows(function() { Number.prototype.toPrecision.call({}) },
+ TypeError);
+
+assertThrows(function() { Number.prototype.toFixed.call({}) },
+ TypeError);
+
+assertThrows(function() { Number.prototype.toString.call({}) },
+ TypeError);
+
+assertThrows(function() { Number.prototype.toLocaleString.call({}) },
+ TypeError);
+
+assertThrows(function() { Number.prototype.ValueOf.call({}) },
+ TypeError);
+
+
+// Call on Number objects with custom valueOf method.
+
+var x_obj = new Number(1);
+x_obj.valueOf = function() { assertUnreachable(); };
+
+assertEquals("1.00e+0",
+ Number.prototype.toExponential.call(x_obj, 2));
+
+assertEquals("1.0",
+ Number.prototype.toPrecision.call(x_obj, 2));
+
+assertEquals("1.00",
+ Number.prototype.toFixed.call(x_obj, 2));
+
+// Call on primitive numbers.
+assertEquals("1.00e+0",
+ Number.prototype.toExponential.call(1, 2));
+
+assertEquals("1.0",
+ Number.prototype.toPrecision.call(1, 2));
+
+assertEquals("1.00",
+ Number.prototype.toFixed.call(1, 2));
+
+
+// toExponential and toPrecision does following steps in order
+// 1) convert the argument using ToInteger
+// 2) check for non-finite receiver, on which it returns,
+// 3) check argument range and throw exception if out of range.
+// Note that the the last two steps are reversed for toFixed.
+// Luckily, the receiver is expected to be a number or number
+// wrapper, so that getting its value is not observable.
+
+var f_flag = false;
+var f_obj = { valueOf: function() { f_flag = true; return 1000; } };
+
+assertEquals("NaN",
+ Number.prototype.toExponential.call(NaN, f_obj));
+assertTrue(f_flag);
+
+f_flag = false;
+assertEquals("Infinity",
+ Number.prototype.toExponential.call(1/0, f_obj));
+assertTrue(f_flag);
+
+f_flag = false;
+assertEquals("-Infinity",
+ Number.prototype.toExponential.call(-1/0, f_obj));
+assertTrue(f_flag);
+
+f_flag = false;
+assertEquals("NaN",
+ Number.prototype.toPrecision.call(NaN, f_obj));
+assertTrue(f_flag);
+
+f_flag = false;
+assertEquals("Infinity",
+ Number.prototype.toPrecision.call(1/0, f_obj));
+assertTrue(f_flag);
+
+f_flag = false;
+assertEquals("-Infinity",
+ Number.prototype.toPrecision.call(-1/0, f_obj));
+assertTrue(f_flag);
+
+// The odd man out: toFixed.
+
+f_flag = false;
+assertThrows(function() { Number.prototype.toFixed.call(NaN, f_obj) },
+ RangeError);
+assertTrue(f_flag);
+
+f_flag = false;
+assertThrows(function() { Number.prototype.toFixed.call(1/0, f_obj) },
+ RangeError);
+assertTrue(f_flag);
+
+f_flag = false;
+assertThrows(function() { Number.prototype.toFixed.call(-1/0, f_obj) },
+ RangeError);
+assertTrue(f_flag);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Fri Dec 7 00:55:06 2012
+++ /branches/bleeding_edge/src/runtime.cc Fri Dec 7 02:20:35 2012
@@ -3807,15 +3807,6 @@
ASSERT(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
- if (isnan(value)) {
- return *isolate->factory()->nan_symbol();
- }
- if (isinf(value)) {
- if (value < 0) {
- return *isolate->factory()->minus_infinity_symbol();
- }
- return *isolate->factory()->infinity_symbol();
- }
CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2IChecked(f_number);
RUNTIME_ASSERT(f >= 0);
@@ -3832,15 +3823,6 @@
ASSERT(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
- if (isnan(value)) {
- return *isolate->factory()->nan_symbol();
- }
- if (isinf(value)) {
- if (value < 0) {
- return *isolate->factory()->minus_infinity_symbol();
- }
- return *isolate->factory()->infinity_symbol();
- }
CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2IChecked(f_number);
RUNTIME_ASSERT(f >= -1 && f <= 20);
@@ -3857,15 +3839,6 @@
ASSERT(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
- if (isnan(value)) {
- return *isolate->factory()->nan_symbol();
- }
- if (isinf(value)) {
- if (value < 0) {
- return *isolate->factory()->minus_infinity_symbol();
- }
- return *isolate->factory()->infinity_symbol();
- }
CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2IChecked(f_number);
RUNTIME_ASSERT(f >= 1 && f <= 21);
=======================================
--- /branches/bleeding_edge/src/v8natives.js Fri Nov 16 01:32:39 2012
+++ /branches/bleeding_edge/src/v8natives.js Fri Dec 7 02:20:35 2012
@@ -1413,11 +1413,7 @@
// ECMA-262 section 15.7.4.3
function NumberToLocaleString() {
- if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
- throw MakeTypeError("called_on_null_or_undefined",
- ["Number.prototype.toLocaleString"]);
- }
- return this.toString();
+ return NumberToString();
}
@@ -1434,50 +1430,76 @@
// ECMA-262 section 15.7.4.5
function NumberToFixed(fractionDigits) {
+ var x = this;
+ if (!IS_NUMBER(this)) {
+ if (!IS_NUMBER_WRAPPER(this)) {
+ throw MakeTypeError("incompatible_method_receiver",
+ ["Number.prototype.toFixed", this]);
+ }
+ // Get the value of this number in case it's an object.
+ x = %_ValueOf(this);
+ }
var f = TO_INTEGER(fractionDigits);
+
if (f < 0 || f > 20) {
throw new $RangeError("toFixed() digits argument must be between 0 and
20");
}
- if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
- throw MakeTypeError("called_on_null_or_undefined",
- ["Number.prototype.toFixed"]);
- }
- var x = ToNumber(this);
+
+ if (NUMBER_IS_NAN(x)) return "NaN";
+ if (x == 1/0) return "Infinity";
+ if (x == -1/0) return "-Infinity";
+
return %NumberToFixed(x, f);
}
// ECMA-262 section 15.7.4.6
function NumberToExponential(fractionDigits) {
- var f = -1;
- if (!IS_UNDEFINED(fractionDigits)) {
- f = TO_INTEGER(fractionDigits);
- if (f < 0 || f > 20) {
- throw new $RangeError(
- "toExponential() argument must be between 0 and 20");
+ var x = this;
+ if (!IS_NUMBER(this)) {
+ if (!IS_NUMBER_WRAPPER(this)) {
+ throw MakeTypeError("incompatible_method_receiver",
+ ["Number.prototype.toExponential", this]);
}
+ // Get the value of this number in case it's an object.
+ x = %_ValueOf(this);
}
- if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
- throw MakeTypeError("called_on_null_or_undefined",
- ["Number.prototype.toExponential"]);
+ var f = IS_UNDEFINED(fractionDigits) ? void 0 :
TO_INTEGER(fractionDigits);
+
+ if (NUMBER_IS_NAN(x)) return "NaN";
+ if (x == 1/0) return "Infinity";
+ if (x == -1/0) return "-Infinity";
+
+ if (IS_UNDEFINED(f)) {
+ f = -1; // Signal for runtime function that f is not defined.
+ } else if (f < 0 || f > 20) {
+ throw new $RangeError("toExponential() argument must be between 0 and
20");
}
- var x = ToNumber(this);
return %NumberToExponential(x, f);
}
// ECMA-262 section 15.7.4.7
function NumberToPrecision(precision) {
- if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
- throw MakeTypeError("called_on_null_or_undefined",
- ["Number.prototype.toPrecision"]);
+ var x = this;
+ if (!IS_NUMBER(this)) {
+ if (!IS_NUMBER_WRAPPER(this)) {
+ throw MakeTypeError("incompatible_method_receiver",
+ ["Number.prototype.toPrecision", this]);
+ }
+ // Get the value of this number in case it's an object.
+ x = %_ValueOf(this);
}
if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
var p = TO_INTEGER(precision);
+
+ if (NUMBER_IS_NAN(x)) return "NaN";
+ if (x == 1/0) return "Infinity";
+ if (x == -1/0) return "-Infinity";
+
if (p < 1 || p > 21) {
throw new $RangeError("toPrecision() argument must be between 1 and
21");
}
- var x = ToNumber(this);
return %NumberToPrecision(x, p);
}
=======================================
--- /branches/bleeding_edge/test/mjsunit/function-call.js Wed Nov 14
01:14:47 2012
+++ /branches/bleeding_edge/test/mjsunit/function-call.js Fri Dec 7
02:20:35 2012
@@ -67,8 +67,7 @@
String.prototype.toLocaleLowerCase,
String.prototype.toUpperCase,
String.prototype.toLocaleUpperCase,
- String.prototype.trim,
- Number.prototype.toLocaleString];
+ String.prototype.trim];
// Non generic natives do not work on any input other than the specific
// type, but since this change will allow call to be invoked with undefined
=======================================
--- /branches/bleeding_edge/test/mjsunit/regress/regress-crbug-18639.js Tue
Dec 7 03:01:02 2010
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-crbug-18639.js Fri
Dec 7 02:20:35 2012
@@ -27,8 +27,12 @@
// See http://crbug.com/18639
-toString = toString;
-__defineGetter__("z", (0).toLocaleString);
-z;
-z;
-((0).toLocaleString)();
+try {
+ toString = toString;
+ __defineGetter__("z", (0).toLocaleString);
+ z;
+ z;
+ ((0).toLocaleString)();
+} catch (e) {
+ assertInstanceof(e, TypeError);
+}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev