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
This commit is contained in:
parent
eeca7c7759
commit
3388f92e63
@ -3807,15 +3807,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
|
||||
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 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
|
||||
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 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
|
||||
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);
|
||||
|
@ -1413,11 +1413,7 @@ function NumberToString(radix) {
|
||||
|
||||
// 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 @@ function NumberValueOf() {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -67,8 +67,7 @@ var should_throw_on_null_and_undefined =
|
||||
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
|
||||
|
129
test/mjsunit/regress/regress-2443.js
Normal file
129
test/mjsunit/regress/regress-2443.js
Normal file
@ -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);
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user