Back out 567f16dd81f3, an existing test is bad, and by appearances poisoning of Boolean.prototype, Number.prototype, and String.prototype will make it hard to quickly fix. r=the O in ROYGBIV
authorJeff Walden <jwalden@mit.edu>
Tue, 11 Jan 2011 16:29:09 -0600
changeset 60558 039f81de26e57580d52004ad7203f246cabd24d6
parent 60557 39bac86bb16810fa727a514f3ec34e93530c31ce
child 60559 18e064a4bb68b6de1337a25ee13b98e9940a967c
push id18037
push usercleary@mozilla.com
push dateFri, 14 Jan 2011 17:42:55 +0000
treeherdermozilla-central@4e0501a0c5e5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersthe
milestone2.0b9pre
backs out567f16dd81f377718d0a948c150b3b8331fb64e5
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Back out 567f16dd81f3, an existing test is bad, and by appearances poisoning of Boolean.prototype, Number.prototype, and String.prototype will make it hard to quickly fix. r=the O in ROYGBIV
js/src/jsnum.cpp
js/src/json.cpp
js/src/jsstr.cpp
js/src/tests/ecma_5/JSON/jstests.list
js/src/tests/ecma_5/JSON/stringify-boxed-primitives.js
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -939,16 +939,17 @@ JS_DEFINE_TRCINFO_2(num_toString,
 
 static JSFunctionSpec number_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,       num_toSource,          0, 0),
 #endif
     JS_TN(js_toString_str,       num_toString,          1, 0, &num_toString_trcinfo),
     JS_FN(js_toLocaleString_str, num_toLocaleString,    0, 0),
     JS_FN(js_valueOf_str,        js_num_valueOf,        0, 0),
+    JS_FN(js_toJSON_str,         js_num_valueOf,        0, 0),
     JS_FN("toFixed",             num_toFixed,           1, 0),
     JS_FN("toExponential",       num_toExponential,     1, 0),
     JS_FN("toPrecision",         num_toPrecision,       1, 0),
     JS_FS_END
 };
 
 /* NB: Keep this in synch with number_constants[]. */
 enum nc_slot {
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -485,104 +485,79 @@ CallReplacerFunction(JSContext *cx, jsid
                                   2, Jsvalify(vec), Jsvalify(vp))) {
             return JS_FALSE;
         }
     }
 
     return JS_TRUE;
 }
 
-/* ES5 15.12.3 Str. */
 static JSBool
 Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, Value *vp, bool callReplacer)
 {
-    JS_CHECK_RECURSION(cx, return false);
+    JS_CHECK_RECURSION(cx, return JS_FALSE);
 
-    /*
-     * This method implements the Str algorithm in ES5 15.12.3, but we move
-     * property retrieval into the caller to stream the stringification process
-     * and avoid constantly copying strings.
-     */
+    if (vp->isObject() && !js_TryJSON(cx, vp))
+        return JS_FALSE;
 
-    /* Step 2. */
-    if (vp->isObject() && !js_TryJSON(cx, vp))
-        return false;
+    if (callReplacer && !CallReplacerFunction(cx, id, holder, scx, vp))
+        return JS_FALSE;
 
-    /* Step 3. */
-    if (callReplacer && !CallReplacerFunction(cx, id, holder, scx, vp))
-        return false;
-
-    /* Step 4. */
+    // catches string and number objects with no toJSON
     if (vp->isObject()) {
         JSObject *obj = &vp->toObject();
         Class *clasp = obj->getClass();
-        if (clasp == &js_NumberClass) {
-            double d;
-            if (!ValueToNumber(cx, *vp, &d))
-                return false;
-            vp->setNumber(d);
-        } else if (clasp == &js_StringClass) {
-            JSString *str = js_ValueToString(cx, *vp);
-            if (!str)
-                return false;
-            vp->setString(str);
-        } else if (clasp == &js_BooleanClass) {
+        if (clasp == &js_StringClass || clasp == &js_NumberClass)
             *vp = obj->getPrimitiveThis();
-        }
     }
 
-    /* Step 8. */
     if (vp->isString()) {
         JSString *str = vp->toString();
         size_t length = str->length();
         const jschar *chars = str->getChars(cx);
         if (!chars)
-            return false;
+            return JS_FALSE;
         return write_string(cx, scx->cb, chars, length);
     }
 
-    /* Step 5. */
-    if (vp->isNull())
+    if (vp->isNull()) {
         return js_AppendLiteral(scx->cb, "null");
+    }
 
-    /* Steps 6-7. */
     if (vp->isBoolean()) {
         return vp->toBoolean() ? js_AppendLiteral(scx->cb, "true")
                                : js_AppendLiteral(scx->cb, "false");
     }
 
-    /* Step 9. */
     if (vp->isNumber()) {
         if (vp->isDouble()) {
             jsdouble d = vp->toDouble();
             if (!JSDOUBLE_IS_FINITE(d))
                 return js_AppendLiteral(scx->cb, "null");
         }
 
         JSCharBuffer cb(cx);
         if (!js_NumberValueToCharBuffer(cx, *vp, cb))
-            return false;
+            return JS_FALSE;
 
         return scx->cb.append(cb.begin(), cb.length());
     }
 
-    /* Step 10. */
     if (vp->isObject() && !IsFunctionObject(*vp) && !IsXML(*vp)) {
         JSBool ok;
 
         scx->depth++;
         ok = (JS_IsArrayObject(cx, &vp->toObject()) ? JA : JO)(cx, vp, scx);
         scx->depth--;
 
         return ok;
     }
 
-    /* Step 11. */
     vp->setUndefined();
-    return true;
+    return JS_TRUE;
 }
 
 JSBool
 js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, const Value &space,
              JSCharBuffer &cb)
 {
     StringifyContext scx(cx, cb, replacer);
     if (!scx.initializeGap(cx, space) || !scx.initializeStack())
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -3057,16 +3057,17 @@ static JSFunctionSpec string_methods[] =
 #if JS_HAS_TOSOURCE
     JS_FN("quote",             str_quote,             0,JSFUN_GENERIC_NATIVE),
     JS_FN(js_toSource_str,     str_toSource,          0,0),
 #endif
 
     /* Java-like methods. */
     JS_FN(js_toString_str,     js_str_toString,       0,0),
     JS_FN(js_valueOf_str,      js_str_toString,       0,0),
+    JS_FN(js_toJSON_str,       js_str_toString,       0,0),
     JS_FN("substring",         str_substring,         2,JSFUN_GENERIC_NATIVE),
     JS_FN("toLowerCase",       str_toLowerCase,       0,JSFUN_GENERIC_NATIVE),
     JS_FN("toUpperCase",       str_toUpperCase,       0,JSFUN_GENERIC_NATIVE),
     JS_FN("charAt",            js_str_charAt,         1,JSFUN_GENERIC_NATIVE),
     JS_FN("charCodeAt",        js_str_charCodeAt,     1,JSFUN_GENERIC_NATIVE),
     JS_FN("indexOf",           str_indexOf,           1,JSFUN_GENERIC_NATIVE),
     JS_FN("lastIndexOf",       str_lastIndexOf,       1,JSFUN_GENERIC_NATIVE),
     JS_FN("trim",              str_trim,              0,JSFUN_GENERIC_NATIVE),
--- a/js/src/tests/ecma_5/JSON/jstests.list
+++ b/js/src/tests/ecma_5/JSON/jstests.list
@@ -1,6 +1,5 @@
 url-prefix ../../jsreftest.html?test=ecma_5/JSON/
 script cyclic-stringify.js
 script small-codepoints.js
 script trailing-comma.js
 script stringify-gap.js
-script stringify-boxed-primitives.js
deleted file mode 100644
--- a/js/src/tests/ecma_5/JSON/stringify-boxed-primitives.js
+++ /dev/null
@@ -1,127 +0,0 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-var gTestfile = 'stringify-boxed-primitives.js';
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 584909;
-var summary = "Stringification of Boolean/String/Number objects";
-
-print(BUGNUMBER + ": " + summary);
-
-/**************
- * BEGIN TEST *
- **************/
-
-function redefine(obj, prop, fun)
-{
-  var desc =
-    { value: fun, writable: true, configurable: true, enumerable: false };
-  Object.defineProperty(obj, prop, desc);
-}
-
-assertEq(JSON.stringify(new Boolean(false)), "false");
-
-assertEq(JSON.stringify(new Number(5)), "5");
-
-assertEq(JSON.stringify(new String("foopy")), '"foopy"');
-
-
-var numToString = Number.prototype.toString;
-var numValueOf = Number.prototype.valueOf;
-var objToString = Object.prototype.toString;
-var objValueOf = Object.prototype.valueOf;
-var boolToString = Boolean.prototype.toString;
-var boolValueOf = Boolean.prototype.valueOf;
-
-redefine(Boolean.prototype, "toString", function() { return 17; });
-assertEq(JSON.stringify(new Boolean(false)), "false")
-delete Boolean.prototype.toString;
-assertEq(JSON.stringify(new Boolean(false)), "false");
-delete Object.prototype.toString;
-assertEq(JSON.stringify(new Boolean(false)), "false");
-delete Boolean.prototype.valueOf;
-assertEq(JSON.stringify(new Boolean(false)), "false");
-delete Object.prototype.valueOf;
-assertEq(JSON.stringify(new Boolean(false)), "false");
-
-
-redefine(Boolean.prototype, "toString", boolToString);
-redefine(Boolean.prototype, "valueOf", boolValueOf);
-redefine(Object.prototype, "toString", objToString);
-redefine(Object.prototype, "valueOf", objValueOf);
-
-redefine(Number.prototype, "toString", function() { return 42; });
-assertEq(JSON.stringify(new Number(5)), "5");
-redefine(Number.prototype, "valueOf", function() { return 17; });
-assertEq(JSON.stringify(new Number(5)), "17");
-delete Number.prototype.toString;
-assertEq(JSON.stringify(new Number(5)), "17");
-delete Number.prototype.valueOf;
-assertEq(JSON.stringify(new Number(5)), "null"); // isNaN(Number("[object Number]"))
-delete Object.prototype.toString;
-try
-{
-  JSON.stringify(new Number(5));
-  throw new Error("didn't throw");
-}
-catch (e)
-{
-  assertEq(e instanceof TypeError, true,
-           "ToNumber failure, should throw TypeError");
-}
-delete Object.prototype.valueOf;
-try
-{
-  JSON.stringify(new Number(5));
-  throw new Error("didn't throw");
-}
-catch (e)
-{
-  assertEq(e instanceof TypeError, true,
-           "ToNumber failure, should throw TypeError");
-}
-
-
-redefine(Number.prototype, "toString", numToString);
-redefine(Number.prototype, "valueOf", numValueOf);
-redefine(Object.prototype, "toString", objToString);
-redefine(Object.prototype, "valueOf", objValueOf);
-
-
-redefine(String.prototype, "valueOf", function() { return 17; });
-assertEq(JSON.stringify(new String(5)), '"5"');
-redefine(String.prototype, "toString", function() { return 42; });
-assertEq(JSON.stringify(new String(5)), '"42"');
-delete String.prototype.toString;
-assertEq(JSON.stringify(new String(5)), '"[object String]"');
-delete Object.prototype.toString;
-assertEq(JSON.stringify(new String(5)), '"17"');
-delete String.prototype.valueOf;
-try
-{
-  JSON.stringify(new String(5));
-  throw new Error("didn't throw");
-}
-catch (e)
-{
-  assertEq(e instanceof TypeError, true,
-           "ToString failure, should throw TypeError");
-}
-delete Object.prototype.valueOf;
-try
-{
-  JSON.stringify(new String(5));
-  throw new Error("didn't throw");
-}
-catch (e)
-{
-  assertEq(e instanceof TypeError, true,
-           "ToString failure, should throw TypeError");
-}
-
-/******************************************************************************/
-
-if (typeof reportCompare === "function")
-  reportCompare(true, true);
-
-print("All tests passed!");