Commit 3388f92e authored by yangguo@chromium.org's avatar yangguo@chromium.org

Fix spec violations in methods of Number.prototype.

R=svenpanne@chromium.org
BUG=v8:2443

Review URL: https://chromiumcodereview.appspot.com/11465005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13160 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent eeca7c77
...@@ -3807,15 +3807,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) { ...@@ -3807,15 +3807,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(value, 0); 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); CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2IChecked(f_number); int f = FastD2IChecked(f_number);
RUNTIME_ASSERT(f >= 0); RUNTIME_ASSERT(f >= 0);
...@@ -3832,15 +3823,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) { ...@@ -3832,15 +3823,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(value, 0); 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); CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2IChecked(f_number); int f = FastD2IChecked(f_number);
RUNTIME_ASSERT(f >= -1 && f <= 20); RUNTIME_ASSERT(f >= -1 && f <= 20);
...@@ -3857,15 +3839,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) { ...@@ -3857,15 +3839,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
CONVERT_DOUBLE_ARG_CHECKED(value, 0); 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); CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
int f = FastD2IChecked(f_number); int f = FastD2IChecked(f_number);
RUNTIME_ASSERT(f >= 1 && f <= 21); RUNTIME_ASSERT(f >= 1 && f <= 21);
......
...@@ -1413,11 +1413,7 @@ function NumberToString(radix) { ...@@ -1413,11 +1413,7 @@ function NumberToString(radix) {
// ECMA-262 section 15.7.4.3 // ECMA-262 section 15.7.4.3
function NumberToLocaleString() { function NumberToLocaleString() {
if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { return NumberToString();
throw MakeTypeError("called_on_null_or_undefined",
["Number.prototype.toLocaleString"]);
}
return this.toString();
} }
...@@ -1434,50 +1430,76 @@ function NumberValueOf() { ...@@ -1434,50 +1430,76 @@ function NumberValueOf() {
// ECMA-262 section 15.7.4.5 // ECMA-262 section 15.7.4.5
function NumberToFixed(fractionDigits) { 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); var f = TO_INTEGER(fractionDigits);
if (f < 0 || f > 20) { if (f < 0 || f > 20) {
throw new $RangeError("toFixed() digits argument must be between 0 and 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", if (NUMBER_IS_NAN(x)) return "NaN";
["Number.prototype.toFixed"]); if (x == 1/0) return "Infinity";
} if (x == -1/0) return "-Infinity";
var x = ToNumber(this);
return %NumberToFixed(x, f); return %NumberToFixed(x, f);
} }
// ECMA-262 section 15.7.4.6 // ECMA-262 section 15.7.4.6
function NumberToExponential(fractionDigits) { function NumberToExponential(fractionDigits) {
var f = -1; var x = this;
if (!IS_UNDEFINED(fractionDigits)) { if (!IS_NUMBER(this)) {
f = TO_INTEGER(fractionDigits); if (!IS_NUMBER_WRAPPER(this)) {
if (f < 0 || f > 20) { throw MakeTypeError("incompatible_method_receiver",
throw new $RangeError( ["Number.prototype.toExponential", this]);
"toExponential() argument must be between 0 and 20");
} }
// Get the value of this number in case it's an object.
x = %_ValueOf(this);
} }
if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { var f = IS_UNDEFINED(fractionDigits) ? void 0 : TO_INTEGER(fractionDigits);
throw MakeTypeError("called_on_null_or_undefined",
["Number.prototype.toExponential"]); 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); return %NumberToExponential(x, f);
} }
// ECMA-262 section 15.7.4.7 // ECMA-262 section 15.7.4.7
function NumberToPrecision(precision) { function NumberToPrecision(precision) {
if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { var x = this;
throw MakeTypeError("called_on_null_or_undefined", if (!IS_NUMBER(this)) {
["Number.prototype.toPrecision"]); 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)); if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
var p = TO_INTEGER(precision); 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) { if (p < 1 || p > 21) {
throw new $RangeError("toPrecision() argument must be between 1 and 21"); throw new $RangeError("toPrecision() argument must be between 1 and 21");
} }
var x = ToNumber(this);
return %NumberToPrecision(x, p); return %NumberToPrecision(x, p);
} }
......
...@@ -67,8 +67,7 @@ var should_throw_on_null_and_undefined = ...@@ -67,8 +67,7 @@ var should_throw_on_null_and_undefined =
String.prototype.toLocaleLowerCase, String.prototype.toLocaleLowerCase,
String.prototype.toUpperCase, String.prototype.toUpperCase,
String.prototype.toLocaleUpperCase, String.prototype.toLocaleUpperCase,
String.prototype.trim, String.prototype.trim];
Number.prototype.toLocaleString];
// Non generic natives do not work on any input other than the specific // 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 // type, but since this change will allow call to be invoked with undefined
......
// 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);
...@@ -27,8 +27,12 @@ ...@@ -27,8 +27,12 @@
// See http://crbug.com/18639 // See http://crbug.com/18639
toString = toString; try {
__defineGetter__("z", (0).toLocaleString); toString = toString;
z; __defineGetter__("z", (0).toLocaleString);
z; z;
((0).toLocaleString)(); z;
((0).toLocaleString)();
} catch (e) {
assertInstanceof(e, TypeError);
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment