From b20f0968fac01d6336beae55e30fdffbcad2fbcb Mon Sep 17 00:00:00 2001 From: "lrn@chromium.org" Date: Thu, 16 Dec 2010 12:49:55 +0000 Subject: [PATCH] Change DefaultString and DefaultNumber to match the spec required behavior. Previously it did two reads of the .toString and .valueOf properties where only one was allowed. Review URL: http://codereview.chromium.org/5950001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6047 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/runtime.js | 20 ++++--- test/mjsunit/object-toprimitive.js | 104 +++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 test/mjsunit/object-toprimitive.js diff --git a/src/runtime.js b/src/runtime.js index f2c8d6b..28a38ca 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -594,13 +594,15 @@ function IsPrimitive(x) { // ECMA-262, section 8.6.2.6, page 28. function DefaultNumber(x) { - if (IS_FUNCTION(x.valueOf)) { - var v = x.valueOf(); + var valueOf = x.valueOf; + if (IS_FUNCTION(valueOf)) { + var v = %_CallFunction(x, valueOf); if (%IsPrimitive(v)) return v; } - if (IS_FUNCTION(x.toString)) { - var s = x.toString(); + var toString = x.toString; + if (IS_FUNCTION(toString)) { + var s = %_CallFunction(x, toString); if (%IsPrimitive(s)) return s; } @@ -610,13 +612,15 @@ function DefaultNumber(x) { // ECMA-262, section 8.6.2.6, page 28. function DefaultString(x) { - if (IS_FUNCTION(x.toString)) { - var s = x.toString(); + var toString = x.toString; + if (IS_FUNCTION(toString)) { + var s = %_CallFunction(x, toString); if (%IsPrimitive(s)) return s; } - if (IS_FUNCTION(x.valueOf)) { - var v = x.valueOf(); + var valueOf = x.valueOf; + if (IS_FUNCTION(valueOf)) { + var v = %_CallFunction(x, valueOf); if (%IsPrimitive(v)) return v; } diff --git a/test/mjsunit/object-toprimitive.js b/test/mjsunit/object-toprimitive.js new file mode 100644 index 0000000..3a67ced --- /dev/null +++ b/test/mjsunit/object-toprimitive.js @@ -0,0 +1,104 @@ +// Copyright 2010 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. + +// Test the ToPrimitive internal function used by ToNumber/ToString. +// Does it [[Get]] and [[Call]] the object's toString and valueOf properties +// correctly. Specifically, does it call [[Get]] only once per property. + +var o1 = { toString: function() { return 42; }, + valueOf: function() { return "37"; } }; +var n1 = Number(o1); +var s1 = String(o1); +assertTrue(typeof n1 == "number"); +assertTrue(typeof s1 == "string"); + +var trace = []; +var valueOfValue = 42; +var toStringValue = "foo"; +function traceValueOf () { + trace.push("vo"); + return valueOfValue; +}; +function traceToString() { + trace.push("ts"); + return toStringValue; +}; +var valueOfFunc = traceValueOf; +var toStringFunc = traceToString; + +var ot = { get toString() { trace.push("gts"); + return toStringFunc; }, + get valueOf() { trace.push("gvo"); + return valueOfFunc; } +}; + +var nt = Number(ot); +assertEquals(42, nt); +assertEquals(["gvo","vo"], trace); + +trace = []; +var st = String(ot); +assertEquals("foo", st); +assertEquals(["gts","ts"], trace); + +trace = []; +valueOfValue = ["not primitive"]; +var nt = Number(ot); +assertEquals(Number("foo"), nt); +assertEquals(["gvo", "vo", "gts", "ts"], trace); + +trace = []; +valueOfValue = 42; +toStringValue = ["not primitive"]; +var st = String(ot); +assertEquals(String(42), st); +assertEquals(["gts", "ts", "gvo", "vo"], trace); + +trace = []; +valueOfValue = ["not primitive"]; +assertThrows("Number(ot)", TypeError); +assertEquals(["gvo", "vo", "gts", "ts"], trace); + + +toStringFunc = "not callable"; +trace = []; +valueOfValue = 42; +var st = String(ot); +assertEquals(String(42), st); +assertEquals(["gts", "gvo", "vo"], trace); + +valueOfFunc = "not callable"; +trace = []; +assertThrows("String(ot)", TypeError); +assertEquals(["gts", "gvo"], trace); + +toStringFunc = traceToString; +toStringValue = "87"; +trace = []; +var nt = Number(ot); +assertEquals(87, nt); +assertEquals(["gvo", "gts", "ts"], trace); -- 2.7.4