From 67fec3265b3ebf8d5cc80e99993821198d3ab721 Mon Sep 17 00:00:00 2001 From: "erik.corry@gmail.com" Date: Tue, 7 Jul 2009 08:55:55 +0000 Subject: [PATCH] Fix the order in which ToNumber is called for some Math functions. Avoid divisions when doing Math.min(0, 0). https://bugs.webkit.org/show_bug.cgi?id=26978 has been filed to fix inconsistencies between JSC and V8. Review URL: http://codereview.chromium.org/149188 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2367 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/math.js | 22 +++++---- test/mjsunit/to_number_order.js | 102 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 test/mjsunit/to_number_order.js diff --git a/src/math.js b/src/math.js index d12927e..db75cb2 100644 --- a/src/math.js +++ b/src/math.js @@ -68,10 +68,12 @@ function MathAtan(x) { } // ECMA 262 - 15.8.2.5 -function MathAtan2(x, y) { - if (!IS_NUMBER(x)) x = ToNumber(x); +// The naming of y and x matches the spec, as does the order in which +// ToNumber (valueOf) is called. +function MathAtan2(y, x) { if (!IS_NUMBER(y)) y = ToNumber(y); - return %Math_atan2(x, y); + if (!IS_NUMBER(x)) x = ToNumber(x); + return %Math_atan2(y, x); } // ECMA 262 - 15.8.2.6 @@ -117,11 +119,12 @@ function MathLog(x) { // ECMA 262 - 15.8.2.11 function MathMax(arg1, arg2) { // length == 2 var r = -$Infinity; - for (var i = %_ArgumentsLength() - 1; i >= 0; --i) { + var length = %_ArgumentsLength(); + for (var i = 0; i < length; i++) { var n = ToNumber(%_Arguments(i)); if (NUMBER_IS_NAN(n)) return n; - // Make sure +0 is consider greater than -0. - if (n > r || (n === 0 && r === 0 && (1 / n) > (1 / r))) r = n; + // Make sure +0 is considered greater than -0. + if (n > r || (r === 0 && n === 0 && !%_IsSmi(r))) r = n; } return r; } @@ -129,11 +132,12 @@ function MathMax(arg1, arg2) { // length == 2 // ECMA 262 - 15.8.2.12 function MathMin(arg1, arg2) { // length == 2 var r = $Infinity; - for (var i = %_ArgumentsLength() - 1; i >= 0; --i) { + var length = %_ArgumentsLength(); + for (var i = 0; i < length; i++) { var n = ToNumber(%_Arguments(i)); if (NUMBER_IS_NAN(n)) return n; - // Make sure -0 is consider less than +0. - if (n < r || (n === 0 && r === 0 && (1 / n) < (1 / r))) r = n; + // Make sure -0 is considered less than +0. + if (n < r || (r === 0 && n === 0 && !%_IsSmi(n))) r = n; } return r; } diff --git a/test/mjsunit/to_number_order.js b/test/mjsunit/to_number_order.js new file mode 100644 index 0000000..9227fd4 --- /dev/null +++ b/test/mjsunit/to_number_order.js @@ -0,0 +1,102 @@ +var x = ""; +var v = new Object(); +var w = new Object(); +var vv = function() { x += "hest"; return 1; } +var ww = function() { x += "fisk"; return 2; } +v.valueOf = vv; +w.valueOf = ww; +assertEquals(1, Math.min(v,w)); +assertEquals("hestfisk", x, "min"); + +x = ""; +assertEquals(2, Math.max(v,w)); +assertEquals("hestfisk", x, "max"); + +x = ""; +assertEquals(Math.atan2(1, 2), Math.atan2(v, w)); +// JSC says fiskhest. +assertEquals("hestfisk", x, "atan2"); + +x = ""; +assertEquals(1, Math.pow(v, w)); +assertEquals("hestfisk", x, "pow"); + +var year = { valueOf: function() { x += 1; return 2007; } }; +var month = { valueOf: function() { x += 2; return 2; } }; +var date = { valueOf: function() { x += 3; return 4; } }; +var hours = { valueOf: function() { x += 4; return 13; } }; +var minutes = { valueOf: function() { x += 5; return 50; } }; +var seconds = { valueOf: function() { x += 6; return 0; } }; +var ms = { valueOf: function() { x += 7; return 999; } }; + +x = ""; +new Date(year, month, date, hours, minutes, seconds, ms); +// JSC fails this one: Returns 12345671234567. +assertEquals("1234567", x, "Date"); + +x = ""; +Date(year, month, date, hours, minutes, seconds, ms); +assertEquals("", x, "Date not constructor"); + +x = ""; +Date.UTC(year, month, date, hours, minutes, seconds, ms); +// JSC fails this one: Returns 12345671234567. +assertEquals("1234567", x, "Date.UTC"); + +x = ""; +new Date().setSeconds(seconds, ms); +assertEquals("67", x, "Date.UTC"); + +x = ""; +new Date().setSeconds(seconds, ms); +assertEquals("67", x, "Date.setSeconds"); + +x = ""; +new Date().setUTCSeconds(seconds, ms); +assertEquals("67", x, "Date.setUTCSeconds"); + +x = ""; +new Date().setMinutes(minutes, seconds, ms); +assertEquals("567", x, "Date.setMinutes"); + +x = ""; +new Date().setUTCMinutes(minutes, seconds, ms); +assertEquals("567", x, "Date.setUTCMinutes"); + +x = ""; +new Date().setHours(hours, minutes, seconds, ms); +assertEquals("4567", x, "Date.setHours"); + +x = ""; +new Date().setUTCHours(hours, minutes, seconds, ms); +assertEquals("4567", x, "Date.setUTCHours"); + +x = ""; +new Date().setDate(date, hours, minutes, seconds, ms); +assertEquals("3", x, "Date.setDate"); + +x = ""; +new Date().setUTCDate(date, hours, minutes, seconds, ms); +assertEquals("3", x, "Date.setUTCDate"); + +x = ""; +new Date().setMonth(month, date, hours, minutes, seconds, ms); +assertEquals("23", x, "Date.setMonth"); + +x = ""; +new Date().setUTCMonth(month, date, hours, minutes, seconds, ms); +assertEquals("23", x, "Date.setUTCMonth"); + +x = ""; +new Date().setFullYear(year, month, date, hours, minutes, seconds, ms); +assertEquals("123", x, "Date.setFullYear"); + +x = ""; +new Date().setUTCFullYear(year, month, date, hours, minutes, seconds, ms); +assertEquals("123", x, "Date.setUTCFullYear"); + +var a = { valueOf: function() { x += "hest"; return 97; } }; +var b = { valueOf: function() { x += "fisk"; return 98; } }; +assertEquals("ab", String.fromCharCode(a, b), "String.fromCharCode"); + +print("ok"); -- 2.7.4