Bug 657013 - Remove the old JSON parser. r=njn
authorJeff Walden <jwalden@mit.edu>
Fri, 13 May 2011 14:27:07 -0700
changeset 70065 4833e6d0d43911e017f2f459dd85ee47e847d867
parent 70064 c2315c604e7c3123c38ad7752a9f758382236864
child 70066 ff8cadbdad81acce9c23cac8078be3e9983e4d9e
push idunknown
push userunknown
push dateunknown
reviewersnjn
bugs657013
milestone6.0a1
Bug 657013 - Remove the old JSON parser. r=njn
js/src/jsobj.cpp
js/src/json.cpp
js/src/json.h
js/src/jsonparser.cpp
js/src/jsonparser.h
js/src/jspubtd.h
js/src/jsversion.h
js/src/tests/ecma_5/JSON/jstests.list
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1177,38 +1177,24 @@ EvalKernel(JSContext *cx, const CallArgs
 
     /*
      * If the eval string starts with '(' and ends with ')', it may be JSON.
      * Try the JSON parser first because it's much faster.  If the eval string
      * isn't JSON, JSON parsing will probably fail quickly, so little time
      * will be lost.
      */
     if (length > 2 && chars[0] == '(' && chars[length - 1] == ')') {
-#if USE_OLD_AND_BUSTED_JSON_PARSER
-        Value tmp;
-        JSONParser *jp = js_BeginJSONParse(cx, &tmp, /* suppressErrors = */true);
-        if (jp != NULL) {
-            /* Run JSON-parser on string inside ( and ). */
-            bool ok = js_ConsumeJSONText(cx, jp, chars + 1, length - 2);
-            ok &= js_FinishJSONParse(cx, jp, NullValue());
-            if (ok) {
-                call.rval() = tmp;
-                return true;
-            }
-#else
-        JSONSourceParser parser(cx, chars + 1, length - 2, JSONSourceParser::StrictJSON,
-                                JSONSourceParser::NoError);
+        JSONParser parser(cx, chars + 1, length - 2, JSONParser::StrictJSON, JSONParser::NoError);
         Value tmp;
         if (!parser.parse(&tmp))
             return false;
         if (!tmp.isUndefined()) {
             call.rval() = tmp;
             return true;
         }
-#endif
     }
 
     /*
      * Direct calls to eval are supposed to see the caller's |this|. If we
      * haven't wrapped that yet, do so now, before we make a copy of it for
      * the eval code to use.
      */
     if (evalType == DIRECT_EVAL && !ComputeThis(cx, caller))
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -67,45 +67,16 @@
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable:4351)
-#endif
-
-struct JSONParser
-{
-    JSONParser(JSContext *cx)
-     : hexChar(), numHex(), statep(), stateStack(), rootVal(), objectStack(),
-       objectKey(cx), buffer(cx), suppressErrors(false)
-    {}
-
-    /* Used while handling \uNNNN in strings */
-    jschar hexChar;
-    uint8 numHex;
-
-    JSONParserState *statep;
-    JSONParserState stateStack[JSON_MAX_DEPTH];
-    Value *rootVal;
-    JSObject *objectStack;
-    js::Vector<jschar, 8> objectKey;
-    js::Vector<jschar, 8> buffer;
-    bool suppressErrors;
-};
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
 Class js_JSONClass = {
     js_JSON_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_JSON),
     PropertyStub,        /* addProperty */
     PropertyStub,        /* delProperty */
     PropertyStub,        /* getProperty */
     StrictPropertyStub,  /* setProperty */
     EnumerateStub,
@@ -791,28 +762,16 @@ js_Stringify(JSContext *cx, Value *vp, J
     if (!PreprocessValue(cx, wrapper, emptyId, vp, &scx))
         return false;
     if (IsFilteredValue(*vp))
         return true;
 
     return Str(cx, *vp, &scx);
 }
 
-// helper to determine whether a character could be part of a number
-static JSBool IsNumChar(jschar c)
-{
-    return ((c <= '9' && c >= '0') || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E');
-}
-
-static JSBool HandleDataString(JSContext *cx, JSONParser *jp);
-static JSBool HandleDataKeyString(JSContext *cx, JSONParser *jp);
-static JSBool HandleDataNumber(JSContext *cx, JSONParser *jp);
-static JSBool HandleDataKeyword(JSContext *cx, JSONParser *jp);
-static JSBool PopState(JSContext *cx, JSONParser *jp);
-
 /* ES5 15.12.2 Walk. */
 static bool
 Walk(JSContext *cx, JSObject *holder, jsid name, const Value &reviver, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     /* Step 1. */
     Value val;
@@ -905,24 +864,16 @@ Walk(JSContext *cx, JSObject *holder, js
     args[1] = val;
 
     if (!Invoke(cx, args))
         return false;
     *vp = args.rval();
     return true;
 }
 
-static JSBool
-JSONParseError(JSONParser *jp, JSContext *cx)
-{
-    if (!jp->suppressErrors)
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE, "syntax error");
-    return JS_FALSE;
-}
-
 static bool
 Revive(JSContext *cx, const Value &reviver, Value *vp)
 {
 
     JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!obj)
         return false;
 
@@ -930,601 +881,36 @@ Revive(JSContext *cx, const Value &reviv
     if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
                              *vp, NULL, NULL, JSPROP_ENUMERATE)) {
         return false;
     }
 
     return Walk(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), reviver, vp);
 }
 
-JSONParser *
-js_BeginJSONParse(JSContext *cx, Value *rootVal, bool suppressErrors /*= false*/)
-{
-    if (!cx)
-        return NULL;
-
-    JSObject *arr = NewDenseEmptyArray(cx);
-    if (!arr)
-        return NULL;
-
-    JSONParser *jp = cx->new_<JSONParser>(cx);
-    if (!jp)
-        return NULL;
-
-    jp->objectStack = arr;
-    if (!JS_AddNamedObjectRoot(cx, &jp->objectStack, "JSON parse stack"))
-        goto bad;
-
-    jp->statep = jp->stateStack;
-    *jp->statep = JSON_PARSE_STATE_INIT;
-    jp->rootVal = rootVal;
-    jp->suppressErrors = suppressErrors;
-
-    return jp;
-
-bad:
-    js_FinishJSONParse(cx, jp, NullValue());
-    return NULL;
-}
-
-bool
-js_FinishJSONParse(JSContext *cx, JSONParser *jp, const Value &reviver)
-{
-    if (!jp)
-        return true;
-
-    JSBool early_ok = JS_TRUE;
-
-    // Check for unprocessed primitives at the root. This doesn't happen for
-    // strings because a closing quote triggers value processing.
-    if ((jp->statep - jp->stateStack) == 1) {
-        if (*jp->statep == JSON_PARSE_STATE_KEYWORD) {
-            early_ok = HandleDataKeyword(cx, jp);
-            if (early_ok)
-                PopState(cx, jp);
-        } else if (*jp->statep == JSON_PARSE_STATE_NUMBER) {
-            early_ok = HandleDataNumber(cx, jp);
-            if (early_ok)
-                PopState(cx, jp);
-        }
-    }
-
-    // This internal API is infallible, in spite of its JSBool return type.
-    js_RemoveRoot(cx->runtime, &jp->objectStack);
-
-    bool ok = *jp->statep == JSON_PARSE_STATE_FINISHED;
-    Value *vp = jp->rootVal;
-
-    if (!early_ok) {
-        ok = false;
-    } else if (!ok) {
-        JSONParseError(jp, cx);
-    } else if (js_IsCallable(reviver)) {
-        ok = Revive(cx, reviver, vp);
-    }
-
-    cx->delete_(jp);
-
-    return ok;
-}
-
 namespace js {
 
 JSBool
 ParseJSONWithReviver(JSContext *cx, const jschar *chars, size_t length, const Value &reviver,
                      Value *vp, DecodingMode decodingMode /* = STRICT */)
 {
-#if USE_OLD_AND_BUSTED_JSON_PARSER
-    JSONParser *jp = js_BeginJSONParse(cx, vp);
-    if (!jp)
-        return false;
-    JSBool ok = js_ConsumeJSONText(cx, jp, chars, length, decodingMode);
-    ok &= !!js_FinishJSONParse(cx, jp, reviver);
-    return ok;
-#else
     /* 15.12.2 steps 2-3. */
-    JSONSourceParser parser(cx, chars, length,
-                            decodingMode == STRICT
-                            ? JSONSourceParser::StrictJSON
-                            : JSONSourceParser::LegacyJSON);
+    JSONParser parser(cx, chars, length,
+                      decodingMode == STRICT ? JSONParser::StrictJSON : JSONParser::LegacyJSON);
     if (!parser.parse(vp))
         return false;
 
     /* 15.12.2 steps 4-5. */
     if (js_IsCallable(reviver))
         return Revive(cx, reviver, vp);
     return true;
-#endif
 }
 
 } /* namespace js */
 
-static JSBool
-PushState(JSContext *cx, JSONParser *jp, JSONParserState state)
-{
-    if (*jp->statep == JSON_PARSE_STATE_FINISHED) {
-        // extra input
-        return JSONParseError(jp, cx);
-    }
-
-    jp->statep++;
-    if ((uint32)(jp->statep - jp->stateStack) >= JS_ARRAY_LENGTH(jp->stateStack)) {
-        // too deep
-        return JSONParseError(jp, cx);
-    }
-
-    *jp->statep = state;
-
-    return JS_TRUE;
-}
-
-static JSBool
-PopState(JSContext *cx, JSONParser *jp)
-{
-    jp->statep--;
-    if (jp->statep < jp->stateStack) {
-        jp->statep = jp->stateStack;
-        return JSONParseError(jp, cx);
-    }
-
-    if (*jp->statep == JSON_PARSE_STATE_INIT)
-        *jp->statep = JSON_PARSE_STATE_FINISHED;
-
-    return JS_TRUE;
-}
-
-static JSBool
-PushValue(JSContext *cx, JSONParser *jp, JSObject *parent, const Value &value)
-{
-    JSBool ok;
-    if (parent->isArray()) {
-        jsuint len;
-        ok = js_GetLengthProperty(cx, parent, &len);
-        if (ok) {
-            jsid index;
-            if (!IndexToId(cx, len, &index))
-                return JS_FALSE;
-            ok = parent->defineProperty(cx, index, value, NULL, NULL, JSPROP_ENUMERATE);
-        }
-    } else {
-        ok = JS_DefineUCProperty(cx, parent, jp->objectKey.begin(),
-                                 jp->objectKey.length(), Jsvalify(value),
-                                 NULL, NULL, JSPROP_ENUMERATE);
-        jp->objectKey.clear();
-    }
-
-    return ok;
-}
-
-static JSBool
-PushObject(JSContext *cx, JSONParser *jp, JSObject *obj)
-{
-    jsuint len;
-    if (!js_GetLengthProperty(cx, jp->objectStack, &len))
-        return JS_FALSE;
-    if (len >= JSON_MAX_DEPTH)
-        return JSONParseError(jp, cx);
-
-    AutoObjectRooter tvr(cx, obj);
-    Value v = ObjectOrNullValue(obj);
-
-    // Check if this is the root object
-    if (len == 0) {
-        *jp->rootVal = v;
-        // This property must be enumerable to keep the array dense
-        if (!jp->objectStack->defineProperty(cx, INT_TO_JSID(0), *jp->rootVal,
-                                             NULL, NULL, JSPROP_ENUMERATE)) {
-            return JS_FALSE;
-        }
-        return JS_TRUE;
-    }
-
-    Value p;
-    if (!jp->objectStack->getProperty(cx, INT_TO_JSID(len - 1), &p))
-        return JS_FALSE;
-
-    JSObject *parent = &p.toObject();
-    if (!PushValue(cx, jp, parent, v))
-        return JS_FALSE;
-
-    // This property must be enumerable to keep the array dense
-    if (!jp->objectStack->defineProperty(cx, INT_TO_JSID(len), v,
-                                         NULL, NULL, JSPROP_ENUMERATE)) {
-        return JS_FALSE;
-    }
-
-    return JS_TRUE;
-}
-
-static JSBool
-OpenObject(JSContext *cx, JSONParser *jp)
-{
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
-    if (!obj)
-        return JS_FALSE;
-
-    return PushObject(cx, jp, obj);
-}
-
-static JSBool
-OpenArray(JSContext *cx, JSONParser *jp)
-{
-    // Add an array to an existing array or object
-    JSObject *arr = NewDenseEmptyArray(cx);
-    if (!arr)
-        return JS_FALSE;
-
-    return PushObject(cx, jp, arr);
-}
-
-static JSBool
-CloseObject(JSContext *cx, JSONParser *jp)
-{
-    jsuint len;
-    if (!js_GetLengthProperty(cx, jp->objectStack, &len))
-        return JS_FALSE;
-    if (!js_SetLengthProperty(cx, jp->objectStack, len - 1))
-        return JS_FALSE;
-
-    return JS_TRUE;
-}
-
-static JSBool
-CloseArray(JSContext *cx, JSONParser *jp)
-{
-    return CloseObject(cx, jp);
-}
-
-static JSBool
-PushPrimitive(JSContext *cx, JSONParser *jp, const Value &value)
-{
-    AutoValueRooter tvr(cx, value);
-
-    jsuint len;
-    if (!js_GetLengthProperty(cx, jp->objectStack, &len))
-        return JS_FALSE;
-
-    if (len > 0) {
-        Value o;
-        if (!jp->objectStack->getProperty(cx, INT_TO_JSID(len - 1), &o))
-            return JS_FALSE;
-
-        return PushValue(cx, jp, &o.toObject(), value);
-    }
-
-    // root value must be primitive
-    *jp->rootVal = value;
-    return JS_TRUE;
-}
-
-static JSBool
-HandleNumber(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len)
-{
-    const jschar *ep;
-    double val;
-    if (!js_strtod(cx, buf, buf + len, &ep, &val))
-        return JS_FALSE;
-    if (ep != buf + len) {
-        // bad number input
-        return JSONParseError(jp, cx);
-    }
-
-    return PushPrimitive(cx, jp, NumberValue(val));
-}
-
-static JSBool
-HandleString(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len)
-{
-    JSString *str = js_NewStringCopyN(cx, buf, len);
-    if (!str)
-        return JS_FALSE;
-
-    return PushPrimitive(cx, jp, StringValue(str));
-}
-
-static JSBool
-HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len)
-{
-    const KeywordInfo *ki = FindKeyword(buf, len);
-    if (!ki || ki->tokentype != TOK_PRIMARY) {
-        // bad keyword
-        return JSONParseError(jp, cx);
-    }
-
-    Value keyword;
-    if (buf[0] == 'n') {
-        keyword.setNull();
-    } else if (buf[0] == 't') {
-        keyword.setBoolean(true);
-    } else if (buf[0] == 'f') {
-        keyword.setBoolean(false);
-    } else {
-        return JSONParseError(jp, cx);
-    }
-
-    return PushPrimitive(cx, jp, keyword);
-}
-
-static JSBool
-HandleDataString(JSContext *cx, JSONParser *jp)
-{
-    JSBool ok = HandleString(cx, jp, jp->buffer.begin(), jp->buffer.length());
-    if (ok)
-        jp->buffer.clear();
-    return ok;
-}
-
-static JSBool
-HandleDataKeyString(JSContext *cx, JSONParser *jp)
-{
-    JSBool ok = jp->objectKey.append(jp->buffer.begin(), jp->buffer.end());
-    if (ok)
-        jp->buffer.clear();
-    return ok;
-}
-
-static JSBool
-HandleDataNumber(JSContext *cx, JSONParser *jp)
-{
-    JSBool ok = HandleNumber(cx, jp, jp->buffer.begin(), jp->buffer.length());
-    if (ok)
-        jp->buffer.clear();
-    return ok;
-}
-
-static JSBool
-HandleDataKeyword(JSContext *cx, JSONParser *jp)
-{
-    JSBool ok = HandleKeyword(cx, jp, jp->buffer.begin(), jp->buffer.length());
-    if (ok)
-        jp->buffer.clear();
-    return ok;
-}
-
-JSBool
-js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len,
-                   DecodingMode decodingMode)
-{
-    CHECK_REQUEST(cx);
-
-    if (*jp->statep == JSON_PARSE_STATE_INIT) {
-        PushState(cx, jp, JSON_PARSE_STATE_VALUE);
-    }
-
-    for (uint32 i = 0; i < len; i++) {
-        jschar c = data[i];
-        switch (*jp->statep) {
-          case JSON_PARSE_STATE_ARRAY_INITIAL_VALUE:
-            if (c == ']') {
-                if (!PopState(cx, jp))
-                    return JS_FALSE;
-                JS_ASSERT(*jp->statep == JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT);
-                if (!CloseArray(cx, jp) || !PopState(cx, jp))
-                    return JS_FALSE;
-                break;
-            }
-            // fall through if non-empty array or whitespace
-
-          case JSON_PARSE_STATE_VALUE:
-            if (c == '"') {
-                *jp->statep = JSON_PARSE_STATE_STRING;
-                break;
-            }
-
-            if (IsNumChar(c)) {
-                *jp->statep = JSON_PARSE_STATE_NUMBER;
-                if (!jp->buffer.append(c))
-                    return JS_FALSE;
-                break;
-            }
-
-            if (JS7_ISLET(c)) {
-                *jp->statep = JSON_PARSE_STATE_KEYWORD;
-                if (!jp->buffer.append(c))
-                    return JS_FALSE;
-                break;
-            }
-
-            if (c == '{') {
-                *jp->statep = JSON_PARSE_STATE_OBJECT_AFTER_PAIR;
-                if (!OpenObject(cx, jp) || !PushState(cx, jp, JSON_PARSE_STATE_OBJECT_INITIAL_PAIR))
-                    return JS_FALSE;
-            } else if (c == '[') {
-                *jp->statep = JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT;
-                if (!OpenArray(cx, jp) || !PushState(cx, jp, JSON_PARSE_STATE_ARRAY_INITIAL_VALUE))
-                    return JS_FALSE;
-            } else if (JS_ISXMLSPACE(c)) {
-                // nothing to do
-            } else if (decodingMode == LEGACY && c == ']') {
-                if (!PopState(cx, jp))
-                    return JS_FALSE;
-                JS_ASSERT(*jp->statep == JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT);
-                if (!CloseArray(cx, jp) || !PopState(cx, jp))
-                    return JS_FALSE;
-            } else {
-                return JSONParseError(jp, cx);
-            }
-            break;
-
-          case JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT:
-            if (c == ',') {
-                if (!PushState(cx, jp, JSON_PARSE_STATE_VALUE))
-                    return JS_FALSE;
-            } else if (c == ']') {
-                if (!CloseArray(cx, jp) || !PopState(cx, jp))
-                    return JS_FALSE;
-            } else if (!JS_ISXMLSPACE(c)) {
-                return JSONParseError(jp, cx);
-            }
-            break;
-
-          case JSON_PARSE_STATE_OBJECT_AFTER_PAIR:
-            if (c == ',') {
-                if (!PushState(cx, jp, JSON_PARSE_STATE_OBJECT_PAIR))
-                    return JS_FALSE;
-            } else if (c == '}') {
-                if (!CloseObject(cx, jp) || !PopState(cx, jp))
-                    return JS_FALSE;
-            } else if (!JS_ISXMLSPACE(c)) {
-                return JSONParseError(jp, cx);
-            }
-            break;
-
-          case JSON_PARSE_STATE_OBJECT_INITIAL_PAIR:
-            if (c == '}') {
-                if (!PopState(cx, jp))
-                    return JS_FALSE;
-                JS_ASSERT(*jp->statep == JSON_PARSE_STATE_OBJECT_AFTER_PAIR);
-                if (!CloseObject(cx, jp) || !PopState(cx, jp))
-                    return JS_FALSE;
-                break;
-            }
-            // fall through if non-empty object or whitespace
-
-          case JSON_PARSE_STATE_OBJECT_PAIR:
-            if (c == '"') {
-                // we want to be waiting for a : when the string has been read
-                *jp->statep = JSON_PARSE_STATE_OBJECT_IN_PAIR;
-                if (!PushState(cx, jp, JSON_PARSE_STATE_STRING))
-                    return JS_FALSE;
-            } else if (JS_ISXMLSPACE(c)) {
-                // nothing to do
-            } else if (decodingMode == LEGACY && c == '}') {
-                if (!PopState(cx, jp))
-                    return JS_FALSE;
-                JS_ASSERT(*jp->statep == JSON_PARSE_STATE_OBJECT_AFTER_PAIR);
-                if (!CloseObject(cx, jp) || !PopState(cx, jp))
-                    return JS_FALSE;
-            } else {
-                return JSONParseError(jp, cx);
-            }
-            break;
-
-          case JSON_PARSE_STATE_OBJECT_IN_PAIR:
-            if (c == ':') {
-                *jp->statep = JSON_PARSE_STATE_VALUE;
-            } else if (!JS_ISXMLSPACE(c)) {
-                return JSONParseError(jp, cx);
-            }
-            break;
-
-          case JSON_PARSE_STATE_STRING:
-            if (c == '"') {
-                if (!PopState(cx, jp))
-                    return JS_FALSE;
-                if (*jp->statep == JSON_PARSE_STATE_OBJECT_IN_PAIR) {
-                    if (!HandleDataKeyString(cx, jp))
-                        return JS_FALSE;
-                } else {
-                    if (!HandleDataString(cx, jp))
-                        return JS_FALSE;
-                }
-            } else if (c == '\\') {
-                *jp->statep = JSON_PARSE_STATE_STRING_ESCAPE;
-            } else if (c <= 0x1F) {
-                // The JSON lexical grammer does not allow a JSONStringCharacter to be
-                // any of the Unicode characters U+0000 thru U+001F (control characters).
-                return JSONParseError(jp, cx);
-            } else {
-                if (!jp->buffer.append(c))
-                    return JS_FALSE;
-            }
-            break;
-
-          case JSON_PARSE_STATE_STRING_ESCAPE:
-            switch (c) {
-              case '"':
-              case '\\':
-              case '/':
-                break;
-              case 'b' : c = '\b'; break;
-              case 'f' : c = '\f'; break;
-              case 'n' : c = '\n'; break;
-              case 'r' : c = '\r'; break;
-              case 't' : c = '\t'; break;
-              default :
-                if (c == 'u') {
-                    jp->numHex = 0;
-                    jp->hexChar = 0;
-                    *jp->statep = JSON_PARSE_STATE_STRING_HEX;
-                    continue;
-                } else {
-                    return JSONParseError(jp, cx);
-                }
-            }
-
-            if (!jp->buffer.append(c))
-                return JS_FALSE;
-            *jp->statep = JSON_PARSE_STATE_STRING;
-            break;
-
-          case JSON_PARSE_STATE_STRING_HEX:
-            if (('0' <= c) && (c <= '9')) {
-                jp->hexChar = (jp->hexChar << 4) | (c - '0');
-            } else if (('a' <= c) && (c <= 'f')) {
-                jp->hexChar = (jp->hexChar << 4) | (c - 'a' + 0x0a);
-            } else if (('A' <= c) && (c <= 'F')) {
-                jp->hexChar = (jp->hexChar << 4) | (c - 'A' + 0x0a);
-            } else {
-                return JSONParseError(jp, cx);
-            }
-
-            if (++(jp->numHex) == 4) {
-                if (!jp->buffer.append(jp->hexChar))
-                    return JS_FALSE;
-                jp->hexChar = 0;
-                jp->numHex = 0;
-                *jp->statep = JSON_PARSE_STATE_STRING;
-            }
-            break;
-
-          case JSON_PARSE_STATE_KEYWORD:
-            if (JS7_ISLET(c)) {
-                if (!jp->buffer.append(c))
-                    return JS_FALSE;
-            } else {
-                // this character isn't part of the keyword, process it again
-                i--;
-                if (!PopState(cx, jp))
-                    return JS_FALSE;
-
-                if (!HandleDataKeyword(cx, jp))
-                    return JS_FALSE;
-            }
-            break;
-
-          case JSON_PARSE_STATE_NUMBER:
-            if (IsNumChar(c)) {
-                if (!jp->buffer.append(c))
-                    return JS_FALSE;
-            } else {
-                // this character isn't part of the number, process it again
-                i--;
-                if (!PopState(cx, jp))
-                    return JS_FALSE;
-                if (!HandleDataNumber(cx, jp))
-                    return JS_FALSE;
-            }
-            break;
-
-          case JSON_PARSE_STATE_FINISHED:
-            if (!JS_ISXMLSPACE(c)) {
-                // extra input
-                return JSONParseError(jp, cx);
-            }
-            break;
-
-          default:
-            JS_NOT_REACHED("Invalid JSON parser state");
-        }
-    }
-
-    return JS_TRUE;
-}
-
 #if JS_HAS_TOSOURCE
 static JSBool
 json_toSource(JSContext *cx, uintN argc, Value *vp)
 {
     vp->setString(CLASS_ATOM(cx, JSON));
     return JS_TRUE;
 }
 #endif
--- a/js/src/json.h
+++ b/js/src/json.h
@@ -52,69 +52,16 @@ extern JSObject *
 js_InitJSONClass(JSContext *cx, JSObject *obj);
 
 extern JSBool
 js_Stringify(JSContext *cx, js::Value *vp, JSObject *replacer, js::Value space,
              js::StringBuffer &sb);
 
 extern JSBool js_TryJSON(JSContext *cx, js::Value *vp);
 
-/* JSON parsing states; most permit leading whitespace. */
-enum JSONParserState {
-    /* Start of string. */
-    JSON_PARSE_STATE_INIT,
-
-    /* JSON fully processed, expecting only trailing whitespace. */
-    JSON_PARSE_STATE_FINISHED,
-
-    /* Start of JSON value. */
-    JSON_PARSE_STATE_VALUE,
-
-    /* Start of first key/value pair in object, or at }. */
-    JSON_PARSE_STATE_OBJECT_INITIAL_PAIR,
-
-    /* Start of subsequent key/value pair in object, after delimiting comma. */
-    JSON_PARSE_STATE_OBJECT_PAIR,
-
-    /* At : in key/value pair in object. */
-    JSON_PARSE_STATE_OBJECT_IN_PAIR,
-
-    /* Immediately after key/value pair in object: at , or }. */
-    JSON_PARSE_STATE_OBJECT_AFTER_PAIR,
-
-    /* Start of first element of array or at ]. */
-    JSON_PARSE_STATE_ARRAY_INITIAL_VALUE,
-
-    /* Immediately after element in array: at , or ]. */
-    JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT,
-
-
-    /* The following states allow no leading whitespace. */
-
-    /* Within string literal. */
-    JSON_PARSE_STATE_STRING,
-
-    /* At first character after \ in string literal. */
-    JSON_PARSE_STATE_STRING_ESCAPE,
-
-    /* Within numbers in \uXXXX in string literal. */
-    JSON_PARSE_STATE_STRING_HEX,
-
-    /* Within numeric literal. */
-    JSON_PARSE_STATE_NUMBER,
-
-    /* Handling keywords (only null/true/false pass validity post-check). */
-    JSON_PARSE_STATE_KEYWORD
-};
-
-struct JSONParser;
-
-extern JSONParser *
-js_BeginJSONParse(JSContext *cx, js::Value *rootVal, bool suppressErrors = false);
-
 /* Aargh, Windows. */
 #ifdef STRICT
 #undef STRICT
 #endif
 #ifdef LEGACY
 #undef LEGACY
 #endif
 
@@ -122,23 +69,16 @@ js_BeginJSONParse(JSContext *cx, js::Val
  * The type of JSON decoding to perform.  Strict decoding is to-the-spec;
  * legacy decoding accepts a few non-JSON syntaxes historically accepted by the
  * implementation.  (Full description of these deviations is deliberately
  * omitted.)  New users should use strict decoding rather than legacy decoding,
  * as legacy decoding might be removed at a future time.
  */
 enum DecodingMode { STRICT, LEGACY };
 
-extern JS_FRIEND_API(JSBool)
-js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len,
-                   DecodingMode decodingMode = STRICT);
-
-extern bool
-js_FinishJSONParse(JSContext *cx, JSONParser *jp, const js::Value &reviver);
-
 namespace js {
 
 extern JS_FRIEND_API(JSBool)
 ParseJSONWithReviver(JSContext *cx, const jschar *chars, size_t length, const Value &filter,
                      Value *vp, DecodingMode decodingMode = STRICT);
 
 } /* namespace js */
 
--- a/js/src/jsonparser.cpp
+++ b/js/src/jsonparser.cpp
@@ -43,31 +43,31 @@
 #include "jsonparser.h"
 
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
 using namespace js;
 
 void
-JSONSourceParser::error(const char *msg)
+JSONParser::error(const char *msg)
 {
     if (errorHandling == RaiseError)
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE, msg);
 }
 
 bool
-JSONSourceParser::errorReturn()
+JSONParser::errorReturn()
 {
     return errorHandling == NoError;
 }
 
-template<JSONSourceParser::StringType ST>
-JSONSourceParser::Token
-JSONSourceParser::readString()
+template<JSONParser::StringType ST>
+JSONParser::Token
+JSONParser::readString()
 {
     JS_ASSERT(current < end);
     JS_ASSERT(*current == '"');
 
     /*
      * JSONString:
      *   /^"([^\u0000-\u001F"\\]|\\(["/\\bfnrt]|u[0-9a-fA-F]{4}))*"$/
      */
@@ -81,17 +81,17 @@ JSONSourceParser::readString()
      * Optimization: if the source contains no escaped characters, create the
      * string directly from the source text.
      */
     RangeCheckedPointer<const jschar> start = current;
     for (; current < end; current++) {
         if (*current == '"') {
             size_t length = current - start;
             current++;
-            JSFlatString *str = (ST == JSONSourceParser::PropertyName)
+            JSFlatString *str = (ST == JSONParser::PropertyName)
                                 ? js_AtomizeChars(cx, start, length)
                                 : js_NewStringCopyN(cx, start, length);
             if (!str)
                 return token(OOM);
             return stringToken(str);
         }
 
         if (*current == '\\')
@@ -113,17 +113,17 @@ JSONSourceParser::readString()
         if (start < current && !buffer.append(start, current))
             return token(OOM);
 
         if (current >= end)
             break;
 
         jschar c = *current++;
         if (c == '"') {
-            JSFlatString *str = (ST == JSONSourceParser::PropertyName)
+            JSFlatString *str = (ST == JSONParser::PropertyName)
                                 ? buffer.finishAtom()
                                 : buffer.finishString();
             if (!str)
                 return token(OOM);
             return stringToken(str);
         }
 
         if (c != '\\') {
@@ -176,18 +176,18 @@ JSONSourceParser::readString()
                 break;
         }
     } while (current < end);
 
     error("unterminated string");
     return token(Error);
 }
 
-JSONSourceParser::Token
-JSONSourceParser::readNumber()
+JSONParser::Token
+JSONParser::readNumber()
 {
     JS_ASSERT(current < end);
     JS_ASSERT(JS7_ISDEC(*current) || *current == '-');
 
     /*
      * JSONNumber:
      *   /^-?(0|[1-9][0-9]+)(\.[0-9]+)?([eE][\+\-]?[0-9]+)?$/
      */
@@ -271,18 +271,18 @@ JSONSourceParser::readNumber()
 }
 
 static inline bool
 IsJSONWhitespace(jschar c)
 {
     return c == '\t' || c == '\r' || c == '\n' || c == ' ';
 }
 
-JSONSourceParser::Token
-JSONSourceParser::advance()
+JSONParser::Token
+JSONParser::advance()
 {
     while (current < end && IsJSONWhitespace(*current))
         current++;
     if (current >= end) {
         error("unexpected end of data");
         return token(Error);
     }
 
@@ -352,18 +352,18 @@ JSONSourceParser::advance()
         return token(Colon);
 
       default:
         error("unexpected character");
         return token(Error);
     }
 }
 
-JSONSourceParser::Token
-JSONSourceParser::advanceAfterObjectOpen()
+JSONParser::Token
+JSONParser::advanceAfterObjectOpen()
 {
     JS_ASSERT(current[-1] == '{');
 
     while (current < end && IsJSONWhitespace(*current))
         current++;
     if (current >= end) {
         error("end of data while reading object contents");
         return token(Error);
@@ -403,18 +403,18 @@ AssertPastValue(const jschar *current)
                current[-4] == 'a' &&
                current[-5] == 'f') ||
               current[-1] == '}' ||
               current[-1] == ']' ||
               current[-1] == '"' ||
               JS7_ISDEC(current[-1]));
 }
 
-JSONSourceParser::Token
-JSONSourceParser::advanceAfterArrayElement()
+JSONParser::Token
+JSONParser::advanceAfterArrayElement()
 {
     AssertPastValue(current);
 
     while (current < end && IsJSONWhitespace(*current))
         current++;
     if (current >= end) {
         error("end of data when ',' or ']' was expected");
         return token(Error);
@@ -429,18 +429,18 @@ JSONSourceParser::advanceAfterArrayEleme
         current++;
         return token(ArrayClose);
     }
 
     error("expected ',' or ']' after array element");
     return token(Error);
 }
 
-JSONSourceParser::Token
-JSONSourceParser::advancePropertyName()
+JSONParser::Token
+JSONParser::advancePropertyName()
 {
     JS_ASSERT(current[-1] == ',');
 
     while (current < end && IsJSONWhitespace(*current))
         current++;
     if (current >= end) {
         error("end of data when property name was expected");
         return token(Error);
@@ -461,18 +461,18 @@ JSONSourceParser::advancePropertyName()
         current++;
         return token(ObjectClose);
     }
 
     error("expected double-quoted property name");
     return token(Error);
 }
 
-JSONSourceParser::Token
-JSONSourceParser::advancePropertyColon()
+JSONParser::Token
+JSONParser::advancePropertyColon()
 {
     JS_ASSERT(current[-1] == '"');
 
     while (current < end && IsJSONWhitespace(*current))
         current++;
     if (current >= end) {
         error("end of data after property name when ':' was expected");
         return token(Error);
@@ -482,18 +482,18 @@ JSONSourceParser::advancePropertyColon()
         current++;
         return token(Colon);
     }
 
     error("expected ':' after property name in object");
     return token(Error);
 }
 
-JSONSourceParser::Token
-JSONSourceParser::advanceAfterProperty()
+JSONParser::Token
+JSONParser::advanceAfterProperty()
 {
     AssertPastValue(current);
 
     while (current < end && IsJSONWhitespace(*current))
         current++;
     if (current >= end) {
         error("end of data after property value in object");
         return token(Error);
@@ -509,23 +509,23 @@ JSONSourceParser::advanceAfterProperty()
         return token(ObjectClose);
     }
 
     error("expected ',' or '}' after property value in object");
     return token(Error);
 }
 
 /*
- * This enum is local to JSONSourceParser::parse, below, but ISO C++98 doesn't
- * allow templates to depend on local types.  Boo-urns!
+ * This enum is local to JSONParser::parse, below, but ISO C++98 doesn't allow
+ * templates to depend on local types.  Boo-urns!
  */
 enum ParserState { FinishArrayElement, FinishObjectMember, JSONValue };
 
 bool
-JSONSourceParser::parse(Value *vp)
+JSONParser::parse(Value *vp)
 {
     Vector<ParserState> stateStack(cx);
     AutoValueVector valueStack(cx);
 
     *vp = UndefinedValue();
 
     Token token;
     ParserState state = JSONValue;
--- a/js/src/jsonparser.h
+++ b/js/src/jsonparser.h
@@ -42,22 +42,19 @@
 #define jsonparser_h___
 
 #include "jscntxt.h"
 #include "jsstr.h"
 #include "jstl.h"
 #include "jsvalue.h"
 
 /*
- * This class should be JSONParser, but the old JSON parser uses that name, so
- * until we remove the old parser the class name will be overlong.
- *
  * NB: This class must only be used on the stack as it contains a js::Value.
  */
-class JSONSourceParser
+class JSONParser
 {
   public:
     enum ErrorHandling { RaiseError, NoError };
     enum ParsingMode { StrictJSON, LegacyJSON };
 
   private:
     /* Data members */
 
@@ -83,19 +80,19 @@ class JSONSourceParser
     /* Public API */
 
     /*
      * Create a parser for the provided JSON data.  The parser will accept
      * certain legacy, non-JSON syntax if decodingMode is LegacyJSON.
      * Description of this syntax is deliberately omitted: new code should only
      * use strict JSON parsing.
      */
-    JSONSourceParser(JSContext *cx, const jschar *data, size_t length,
-                     ParsingMode parsingMode = StrictJSON,
-                     ErrorHandling errorHandling = RaiseError)
+    JSONParser(JSContext *cx, const jschar *data, size_t length,
+               ParsingMode parsingMode = StrictJSON,
+               ErrorHandling errorHandling = RaiseError)
       : cx(cx),
         current(data, data, length),
         end(data + length, data, length),
         parsingMode(parsingMode),
         errorHandling(errorHandling)
 #ifdef DEBUG
       , lastToken(Error)
 #endif
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -156,17 +156,16 @@ typedef struct JSPropertyDescriptor JSPr
 typedef struct JSPropertySpec    JSPropertySpec;
 typedef struct JSObjectMap       JSObjectMap;
 typedef struct JSRuntime         JSRuntime;
 typedef struct JSStackFrame      JSStackFrame;
 typedef struct JSXDRState        JSXDRState;
 typedef struct JSExceptionState  JSExceptionState;
 typedef struct JSLocaleCallbacks JSLocaleCallbacks;
 typedef struct JSSecurityCallbacks JSSecurityCallbacks;
-typedef struct JSONParser        JSONParser;
 typedef struct JSCompartment     JSCompartment;
 typedef struct JSCrossCompartmentCall JSCrossCompartmentCall;
 typedef struct JSStructuredCloneWriter JSStructuredCloneWriter;
 typedef struct JSStructuredCloneReader JSStructuredCloneReader;
 typedef struct JSStructuredCloneCallbacks JSStructuredCloneCallbacks;
 
 #ifdef __cplusplus
 typedef class JSWrapper          JSWrapper;
--- a/js/src/jsversion.h
+++ b/js/src/jsversion.h
@@ -214,18 +214,8 @@
 /* Feature-test macro for evolving destructuring support. */
 #define JS_HAS_DESTRUCTURING_SHORTHAND  (JS_HAS_DESTRUCTURING == 2)
 
 /*
  * Feature for Object.prototype.__{define,lookup}{G,S}etter__ legacy support;
  * support likely to be made opt-in at some future time.
  */
 #define OLD_GETTER_SETTER_METHODS       1
-
-/*
- * Embedders: don't change this: it's a bake-until-ready hack only!
- *
- * NB: Changing this value requires adjusting the pass/fail state of a handful
- *     of tests in ecma_5/JSON/ which the old parser implemented incorrectly.
- *     Also make sure to rename JSONSourceParser to just JSONParser when the
- *     old parser is removed completely.
- */
-#define USE_OLD_AND_BUSTED_JSON_PARSER 0
--- a/js/src/tests/ecma_5/JSON/jstests.list
+++ b/js/src/tests/ecma_5/JSON/jstests.list
@@ -1,19 +1,22 @@
 url-prefix ../../jsreftest.html?test=ecma_5/JSON/
 script cyclic-stringify.js
 script small-codepoints.js
 script parse.js
 script parse-arguments.js
 script parse-crockford-01.js
+script parse-number-syntax.js
+script parse-octal-syntax-error.js
 script parse-primitives.js
 script parse-reviver.js
 script parse-reviver-array-delete.js
 script parse-syntax-errors-01.js
 script parse-syntax-errors-02.js
+script parse-syntax-errors-03.js
 script stringify.js
 script stringify-boxed-primitives.js
 script stringify-call-replacer-once.js
 script stringify-call-toJSON-once.js
 script stringify-dropping-elements.js
 script stringify-gap.js
 script stringify-ignore-noncallable-toJSON.js
 script stringify-missing-arguments.js
@@ -23,16 +26,8 @@ script stringify-replacer.js
 script stringify-replacer-array-duplicated-element.js
 script stringify-replacer-array-edgecase-jsid-elements.js
 script stringify-replacer-array-hijinks.js
 script stringify-replacer-array-skipped-element.js
 script stringify-replacer-with-array-indexes.js
 script stringify-special-escapes.js
 script stringify-toJSON-arguments.js
 script trailing-comma.js
-
-# These tests pass with the new parser but fail with the old one.  If you're
-# changing which parser is used, you'll need to change these test declarations
-# accordingly.  (And if you're removing the old parser, re-alphabetize these
-# tests into the list above.)
-script parse-number-syntax.js
-script parse-octal-syntax-error.js
-script parse-syntax-errors-03.js