Back out Robert Sayre's patch from bug 408838 due to test failures (changeset 2fe3cb0c9f7c).
authorReed Loden <reed@reedloden.com>
Wed, 01 Oct 2008 03:22:30 -0500
changeset 20057 14287b704747bdd8e0e6d6380ded995578f1c526
parent 20048 2fe3cb0c9f7cbc62855c11463636d0753b67d215
child 20058 63b0791327aba7fd27f6080a8e66ba1e1c837b03
push id2610
push userreed@reedloden.com
push dateWed, 01 Oct 2008 08:23:03 +0000
treeherdermozilla-central@63b0791327ab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs408838
milestone1.9.1b1pre
Back out Robert Sayre's patch from bug 408838 due to test failures (changeset 2fe3cb0c9f7c).
dom/public/idl/json/nsIJSON.idl
dom/src/json/nsJSON.cpp
dom/src/json/nsJSON.h
dom/src/json/test/json2.js
dom/src/json/test/unit/head_json.js
dom/src/json/test/unit/test_encode.js
js/src/Makefile.in
js/src/Makefile.ref
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsatom.cpp
js/src/jsatom.h
js/src/json.cpp
js/src/json.h
js/src/jsproto.tbl
js/src/jspubtd.h
--- a/dom/public/idl/json/nsIJSON.idl
+++ b/dom/public/idl/json/nsIJSON.idl
@@ -43,20 +43,24 @@ interface nsIOutputStream;
 interface nsIScriptGlobalObject;
 
 /**
  * Encode and decode JSON text.
  */
 [scriptable, uuid(45464c36-efde-4cb5-8e00-07480533ff35)]
 interface nsIJSON : nsISupports
 {
-  AString encode(/* in JSObject value */);
+  AString encode(/* in JSObject value,
+                 /* [optional] in JSObject whitelist */);
 
   void encodeToStream(in nsIOutputStream stream,
                       in string charset,
                       in boolean writeBOM
-                      /* in JSObject value */);
+                      /* in JSObject value,
+                      /* [optional] in JSObject optFilter */);
 
-  void /* JSObject */ decode(in AString str);
+  void /* JSObject */ decode(in AString str
+                             /* , [optional] in JSObject whitelist */);
 
   void /* JSObject */ decodeFromStream(in nsIInputStream stream,
-                                       in long contentLength);
+                                       in long contentLength
+                                       /*[optional] in JSObject optFilter */);
 };
--- a/dom/src/json/nsJSON.cpp
+++ b/dom/src/json/nsJSON.cpp
@@ -57,18 +57,16 @@
 #include "nsXPCOMStrings.h"
 #include "nsNetUtil.h"
 #include "nsContentUtils.h"
 #include "nsCRTGlue.h"
 #include "nsAutoPtr.h"
 
 static const char kXPConnectServiceCID[] = "@mozilla.org/js/xpc/XPConnect;1";
 
-#define JSON_STREAM_BUFSIZE 1024
-
 NS_INTERFACE_MAP_BEGIN(nsJSON)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSON)
   NS_INTERFACE_MAP_ENTRY(nsIJSON)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsJSON)
 NS_IMPL_RELEASE(nsJSON)
 
@@ -178,27 +176,16 @@ nsJSON::EncodeToStream(nsIOutputStream *
   rv = EncodeInternal(&writer);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = bufferedStream->Flush();
 
   return rv;
 }
 
-static JSBool
-WriteCallback(const jschar *buf, uint32 len, void *data)
-{
-  nsJSONWriter *writer = static_cast<nsJSONWriter*>(data);
-  nsresult rv =  writer->Write((const PRUnichar*)buf, (PRUint32)len);
-  if (NS_FAILED(rv))
-    return JS_FALSE;
-
-  return JS_TRUE;
-}
-
 nsresult
 nsJSON::EncodeInternal(nsJSONWriter *writer)
 {
   nsresult rv;
   nsIXPConnect *xpc = nsContentUtils::XPConnect();
   if (!xpc)
     return NS_ERROR_FAILURE;
 
@@ -229,32 +216,238 @@ nsJSON::EncodeInternal(nsJSONWriter *wri
 
   if (argc <= firstArg ||
       !(JSVAL_IS_OBJECT(argv[firstArg]) &&
         (inputObj = JSVAL_TO_OBJECT(argv[firstArg])))) {
     // return if it's not something we can deal with
     return NS_ERROR_INVALID_ARG;
   }
 
+  JSObject *whitelist = nsnull;
+
+  // If there's a second argument here, it should be an array.
+  if (argc >= firstArg + 2 &&
+      !(JSVAL_IS_OBJECT(argv[firstArg + 1]) &&
+        (whitelist = JSVAL_TO_OBJECT(argv[firstArg + 1])) &&
+        JS_IsArrayObject(cx, whitelist))) {
+     whitelist = nsnull; // bogus whitelists are ignored
+  }
+
   jsval *vp = &argv[firstArg];
-  JSBool ok = JS_TryJSON(cx, vp);
+
+  JSBool ok = ToJSON(cx, vp);
   JSType type;
   if (!(ok && !JSVAL_IS_PRIMITIVE(*vp) &&
         (type = JS_TypeOfValue(cx, *vp)) != JSTYPE_FUNCTION &&
         type != JSTYPE_XML)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  ok = JS_Stringify(cx, vp, NULL, &WriteCallback, writer);
-  if (!ok)
-    return NS_ERROR_FAILURE;
-    
-  return NS_OK;
+  return EncodeObject(cx, vp, writer, whitelist, 0);
 }
 
+// N.B: vp must be rooted.
+nsresult
+nsJSON::EncodeObject(JSContext *cx, jsval *vp, nsJSONWriter *writer,
+                     JSObject *whitelist, PRUint32 depth)
+{
+  NS_ENSURE_ARG(vp);
+  NS_ENSURE_ARG(writer);
+
+  if (depth > JSON_MAX_DEPTH) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv;
+  JSObject *obj = JSVAL_TO_OBJECT(*vp);
+  JSBool isArray = JS_IsArrayObject(cx, obj);
+  PRUnichar output = PRUnichar(isArray ? '[' : '{');
+  rv = writer->Write(&output, 1);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  JSBool ok = JS_TRUE;
+  JSObject *iterObj = nsnull;
+  jsint i = 0;
+  jsuint length = 0;
+
+  if (isArray) {
+    ok = JS_GetArrayLength(cx, obj, &length);
+    if (!ok)
+      return NS_ERROR_FAILURE;
+  } else {
+    ok = js_ValueToIterator(cx, JSITER_ENUMERATE, vp);
+    if (!ok)
+      return NS_ERROR_FAILURE;
+
+    iterObj = JSVAL_TO_OBJECT(*vp);
+  }
+
+  jsval outputValue = JSVAL_VOID;
+  JSAutoTempValueRooter tvr(cx, 1, &outputValue);
+
+  jsval key;
+  PRBool memberWritten = PR_FALSE;
+  do {
+    outputValue = JSVAL_VOID;
+
+    if (isArray) {
+      if ((jsuint)i >= length)
+        break;
+
+      ok = JS_GetElement(cx, obj, i++, &outputValue);
+    } else {
+      ok = js_CallIteratorNext(cx, iterObj, &key);
+      if (!ok)
+        break;
+      if (key == JSVAL_HOLE)
+        break;
+
+      JSString *ks;
+      if (JSVAL_IS_STRING(key)) {
+        ks = JSVAL_TO_STRING(key);
+      } else {
+        ks = JS_ValueToString(cx, key);
+        if (!ks) {
+          ok = JS_FALSE;
+          break;
+        }
+      }
+
+      ok = JS_GetUCProperty(cx, obj, JS_GetStringChars(ks),
+                            JS_GetStringLength(ks), &outputValue);
+    }
+
+    if (!ok)
+      break;
+
+    // if this is an array, holes are transmitted as null
+    if (isArray && outputValue == JSVAL_VOID) {
+      outputValue = JSVAL_NULL;
+    } else if (JSVAL_IS_OBJECT(outputValue)) {
+      ok = ToJSON(cx, &outputValue);
+      if (!ok)
+        break;
+    }
+    
+    // elide undefined values
+    if (outputValue == JSVAL_VOID)
+      continue;
+
+    // output a comma unless this is the first member to write
+    if (memberWritten) {
+      output = PRUnichar(',');
+      rv = writer->Write(&output, 1);
+    }
+    memberWritten = PR_TRUE;
+    
+    JSType type = JS_TypeOfValue(cx, outputValue);
+
+    // Can't encode these types, so drop them
+    if (type == JSTYPE_FUNCTION || type == JSTYPE_XML)
+      break;
+ 
+    // Be careful below, this string is weakly rooted.
+    JSString *s;
+ 
+    // If this isn't an array, we need to output a key
+    if (!isArray) {
+      nsAutoString keyOutput;
+      s = JS_ValueToString(cx, key);
+      if (!s) {
+        ok = JS_FALSE;
+        break;
+      }
+
+      rv = writer->WriteString((PRUnichar*)JS_GetStringChars(s),
+                               JS_GetStringLength(s));
+      if (NS_FAILED(rv))
+        break;
+      output = PRUnichar(':');
+      rv = writer->Write(&output, 1);
+      if (NS_FAILED(rv))
+        break;
+    }
+
+    if (!JSVAL_IS_PRIMITIVE(outputValue)) {
+      // recurse
+      rv = EncodeObject(cx, &outputValue, writer, whitelist, depth + 1);
+      if (NS_FAILED(rv))
+        break;
+    } else {
+      nsAutoString valueOutput;
+      s = JS_ValueToString(cx, outputValue);
+      if (!s) {
+        ok = JS_FALSE;
+        break;
+      }
+
+      if (type == JSTYPE_STRING) {
+        rv = writer->WriteString((PRUnichar*)JS_GetStringChars(s),
+                                 JS_GetStringLength(s));
+        continue;
+      }
+
+      if (type == JSTYPE_NUMBER) {
+        if (JSVAL_IS_DOUBLE(outputValue)) {
+          jsdouble d = *JSVAL_TO_DOUBLE(outputValue);
+          if (!JSDOUBLE_IS_FINITE(d))
+            valueOutput.Append(NS_LITERAL_STRING("null"));
+          else
+            valueOutput.Append((PRUnichar*)JS_GetStringChars(s));
+        } else {
+          valueOutput.Append((PRUnichar*)JS_GetStringChars(s));
+        }
+      } else if (type == JSTYPE_BOOLEAN) {
+        valueOutput.Append((PRUnichar*)JS_GetStringChars(s));
+      } else if (JSVAL_IS_NULL(outputValue)) {
+        valueOutput.Append(NS_LITERAL_STRING("null"));
+      } else {
+        rv = NS_ERROR_FAILURE; // encoding error
+        break;
+      }
+
+      rv = writer->Write(valueOutput.get(), valueOutput.Length());
+    }
+
+  } while (NS_SUCCEEDED(rv));
+
+  if (iterObj) {
+    // Always close the iterator, but make sure not to stomp on OK
+    ok &= js_CloseIterator(cx, *vp);
+    if (!ok)
+      rv = NS_ERROR_FAILURE; // encoding error or propagate? FIXME: Bug 408838.
+  }
+
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  output = PRUnichar(isArray ? ']' : '}');
+  rv = writer->Write(&output, 1);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return rv;
+}
+
+JSBool
+nsJSON::ToJSON(JSContext *cx, jsval *vp)
+{
+  // Now we check to see whether the return value implements toJSON()
+  JSBool ok = JS_TRUE;
+  const char *toJSON = "toJSON";
+
+  if (!JSVAL_IS_PRIMITIVE(*vp)) {
+    JSObject *obj = JSVAL_TO_OBJECT(*vp);
+    jsval toJSONVal = nsnull;
+    ok = JS_GetProperty(cx, obj, toJSON, &toJSONVal);
+    if (ok && JS_TypeOfValue(cx, toJSONVal) == JSTYPE_FUNCTION) {
+      ok = JS_CallFunctionValue(cx, obj, toJSONVal, 0, nsnull, vp);
+    }
+  }
+
+  return ok;
+}
 
 nsJSONWriter::nsJSONWriter() : mStream(nsnull),
                                mBuffer(nsnull),
                                mBufferCount(0),
                                mDidWrite(PR_FALSE),
                                mEncoder(nsnull)
 {
 }
@@ -285,36 +478,84 @@ nsJSONWriter::SetCharset(const char* aCh
     rv = mEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Signal,
                                           nsnull, nsnull);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return rv;
 }
 
+static const PRUnichar quote = PRUnichar('"');
+static const PRUnichar backslash = PRUnichar('\\');
+static const PRUnichar unicodeEscape[] = {'\\', 'u', '0', '0', '\0'};
+
+nsresult
+nsJSONWriter::WriteString(const PRUnichar *aBuffer, PRUint32 aLength)
+{
+  nsresult rv;
+  rv = Write(&quote, 1);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRUint32 mark = 0;
+  PRUint32 i;
+  for (i = 0; i < aLength; ++i) {
+    if (aBuffer[i] == quote || aBuffer[i] == backslash) {
+      rv = Write(&aBuffer[mark], i - mark);
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = Write(&backslash, 1);
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = Write(&aBuffer[i], 1);
+      NS_ENSURE_SUCCESS(rv, rv);
+      mark = i + 1;
+    } else if (aBuffer[i] <= 31 || aBuffer[i] == 127) {
+      rv = Write(&aBuffer[mark], i - mark);
+      NS_ENSURE_SUCCESS(rv, rv);
+      nsAutoString unicode;
+      unicode.Append(unicodeEscape);
+      nsAutoString charCode;
+      charCode.AppendInt(aBuffer[i], 16);
+      if (charCode.Length() == 1)
+        unicode.Append('0');
+      unicode.Append(charCode);
+      rv = Write(unicode.get(), unicode.Length());
+      NS_ENSURE_SUCCESS(rv, rv);
+      mark = i + 1;
+    }
+  }
+
+  if (mark < aLength) {
+    rv = Write(&aBuffer[mark], aLength - mark);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = Write(&quote, 1);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return rv;
+}
+
 nsresult
 nsJSONWriter::Write(const PRUnichar *aBuffer, PRUint32 aLength)
 {
   if (mStream) {
     return WriteToStream(mStream, mEncoder, aBuffer, aLength);
   }
 
   if (!mDidWrite) {
-    mBuffer = new PRUnichar[JSON_STREAM_BUFSIZE];
+    mBuffer = new PRUnichar[JSON_PARSER_BUFSIZE];
     if (!mBuffer)
       return NS_ERROR_OUT_OF_MEMORY;
     mDidWrite = PR_TRUE;
   }
 
-  if (JSON_STREAM_BUFSIZE <= aLength + mBufferCount) {
+  if (JSON_PARSER_BUFSIZE <= aLength + mBufferCount) {
     mOutputString.Append(mBuffer, mBufferCount);
     mBufferCount = 0;
   }
 
-  if (JSON_STREAM_BUFSIZE <= aLength) {
+  if (JSON_PARSER_BUFSIZE <= aLength) {
     // we know mBufferCount is 0 because we know we hit the if above
     mOutputString.Append(aBuffer, aLength);
   } else {
     memcpy(&mBuffer[mBufferCount], aBuffer, aLength * sizeof(PRUnichar));
     mBufferCount += aLength;
   }
 
   return NS_OK;
@@ -477,67 +718,79 @@ NS_NewJSON(nsISupports* aOuter, REFNSIID
     return NS_ERROR_OUT_OF_MEMORY;
 
   NS_ADDREF(json);
   *aResult = json;
 
   return NS_OK;
 }
 
+
+static void
+trace_json_stack(JSTracer *trc, JSTempValueRooter *tvr)
+{
+  nsJSONObjectStack *tmp = static_cast<nsJSONObjectStack *>(tvr);
+
+  for (PRUint32 i = 0; i < tmp->Length(); ++i) {
+    JS_CALL_OBJECT_TRACER(trc, tmp->ElementAt(i),
+                          "JSON decoder stack member");
+  }
+}
+
 nsJSONListener::nsJSONListener(JSContext *cx, jsval *rootVal,
                                PRBool needsConverter)
-  : mNeedsConverter(needsConverter), 
-    mJSONParser(nsnull),
+  : mHexChar(0),
+    mNumHex(0),
     mCx(cx),
-    mRootVal(rootVal)
+    mRootVal(rootVal),
+    mNeedsConverter(needsConverter),
+    mStatep(mStateStack)
 {
+  NS_ASSERTION(mCx, "Must have a JSContext");
+  *mStatep = JSON_PARSE_STATE_INIT;
+  JS_PUSH_TEMP_ROOT_TRACE(cx, trace_json_stack, &mObjectStack);
 }
 
 nsJSONListener::~nsJSONListener()
 {
-  Cleanup();
+  JS_POP_TEMP_ROOT(mCx, &mObjectStack);
 }
 
 NS_INTERFACE_MAP_BEGIN(nsJSONListener)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsJSONListener)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsJSONListener)
 NS_IMPL_RELEASE(nsJSONListener)
 
 NS_IMETHODIMP
 nsJSONListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
 {
+  mHexChar = 0;
+  mNumHex = 0;
   mSniffBuffer.Truncate();
   mDecoder = nsnull;
-  mJSONParser = JS_BeginJSONParse(mCx, mRootVal);
-  if (!mJSONParser)
-    return NS_ERROR_FAILURE;
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJSONListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
                               nsresult aStatusCode)
 {
   nsresult rv;
 
   // This can happen with short UTF-8 messages
   if (!mSniffBuffer.IsEmpty()) {
     rv = ProcessBytes(mSniffBuffer.get(), mSniffBuffer.Length());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  JSBool ok = JS_FinishJSONParse(mCx, mJSONParser);
-  mJSONParser = nsnull;
-
-  if (!ok)
+  if (!mObjectStack.IsEmpty() || *mStatep != JSON_PARSE_STATE_FINISHED)
     return NS_ERROR_FAILURE;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJSONListener::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
                                 nsIInputStream *aStream,
@@ -551,17 +804,17 @@ nsJSONListener::OnDataAvailable(nsIReque
     PRUint32 readCount = (aLength < 4) ? aLength : 4;
     rv = NS_ConsumeStream(aStream, readCount, mSniffBuffer);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (mSniffBuffer.Length() < 4)
       return NS_OK;
   }
   
-  char buffer[JSON_STREAM_BUFSIZE];
+  char buffer[JSON_PARSER_BUFSIZE];
   unsigned long bytesRemaining = aLength - mSniffBuffer.Length();
   while (bytesRemaining) {
     unsigned int bytesRead;
     rv = aStream->Read(buffer,
                        PR_MIN(sizeof(buffer), bytesRemaining),
                        &bytesRead);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = ProcessBytes(buffer, bytesRead);
@@ -643,28 +896,462 @@ nsJSONListener::ConsumeConverted(const c
   rv = mDecoder->Convert(aBuffer, &srcLen, ustr, &unicharLength);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = Consume(ustr.get(), unicharLength);
 
   return rv;
 }
 
-void nsJSONListener::Cleanup()
+nsresult
+nsJSONListener::PopState()
 {
-  if (mJSONParser)
-    JS_FinishJSONParse(mCx, mJSONParser);
-  mJSONParser = nsnull;
-}
-
-nsresult
-nsJSONListener::Consume(const PRUnichar* aBuffer, PRUint32 aByteLength)
-{
-  if (!mJSONParser)
+  mStatep--;
+  if (mStatep < mStateStack) {
+    mStatep = mStateStack;
     return NS_ERROR_FAILURE;
-
-  if (!JS_ConsumeJSONText(mCx, mJSONParser, (jschar*) aBuffer, aByteLength)) {
-    Cleanup();
-    return NS_ERROR_FAILURE;
+  } else if (*mStatep == JSON_PARSE_STATE_INIT) {
+    *mStatep = JSON_PARSE_STATE_FINISHED;
   }
 
   return NS_OK;
 }
+
+nsresult
+nsJSONListener::PushState(JSONParserState state)
+{
+  if (*mStatep == JSON_PARSE_STATE_FINISHED)
+    return NS_ERROR_FAILURE; // extra input
+
+  mStatep++;
+  if ((uint32)(mStatep - mStateStack) >= JS_ARRAY_LENGTH(mStateStack))
+    return NS_ERROR_FAILURE; // too deep
+
+  *mStatep = state;
+
+  return NS_OK;
+}
+
+nsresult
+nsJSONListener::Consume(const PRUnichar *data, PRUint32 len)
+{
+  nsresult rv;
+  PRUint32 i;
+
+  // we'll try to avoid string munging during parsing
+  PRUnichar buf[JSON_PARSER_BUFSIZE + 1];
+  PRUint32 bufIndex = 0;
+
+#define PUSHCHAR(_c)                         \
+if (bufIndex == JSON_PARSER_BUFSIZE) {       \
+  mStringBuffer.Append(buf, bufIndex);       \
+  bufIndex = 0;                              \
+}                                            \
+buf[bufIndex] = _c;                          \
+bufIndex++;
+
+  if (*mStatep == JSON_PARSE_STATE_INIT) {
+    PushState(JSON_PARSE_STATE_OBJECT_VALUE);
+  }
+
+  for (i = 0; i < len; i++) {
+    PRUnichar c = data[i];
+
+    switch (*mStatep) {
+      case JSON_PARSE_STATE_VALUE :
+        if (c == ']') {
+          // empty array
+          rv = PopState();
+          NS_ENSURE_SUCCESS(rv, rv);
+          if (*mStatep != JSON_PARSE_STATE_ARRAY) {
+            return NS_ERROR_FAILURE; // unexpected char
+          }
+          rv = this->CloseArray();
+          NS_ENSURE_SUCCESS(rv, rv);
+          rv = PopState();
+          NS_ENSURE_SUCCESS(rv, rv);
+          break;
+        } else if (c == '}') {
+          // we should only find these in OBJECT_KEY state
+          return NS_ERROR_FAILURE; // unexpected failure
+        } else if (c == '"') {
+          *mStatep = JSON_PARSE_STATE_STRING;
+          break;
+        } else if (IsNumChar(c)) {
+          *mStatep = JSON_PARSE_STATE_NUMBER;
+          PUSHCHAR(c);
+          break;
+        } else if (NS_IsAsciiAlpha(c)) {
+          *mStatep = JSON_PARSE_STATE_KEYWORD;
+          PUSHCHAR(c);
+          break;
+        } 
+        // fall through in case the value is an object or array
+      case JSON_PARSE_STATE_OBJECT_VALUE :
+        if (c == '{') {
+          *mStatep = JSON_PARSE_STATE_OBJECT;
+          rv = this->OpenObject();
+          NS_ENSURE_SUCCESS(rv, rv);
+          rv = PushState(JSON_PARSE_STATE_OBJECT_PAIR);
+          NS_ENSURE_SUCCESS(rv, rv);
+        } else if (c == '[') {
+          *mStatep = JSON_PARSE_STATE_ARRAY;
+          rv = this->OpenArray();
+          NS_ENSURE_SUCCESS(rv, rv);
+          rv = PushState(JSON_PARSE_STATE_VALUE);
+          NS_ENSURE_SUCCESS(rv, rv);
+        } else if (!NS_IsAsciiWhitespace(c)) {
+          return NS_ERROR_FAILURE; // unexpected
+        }
+        break;
+      case JSON_PARSE_STATE_OBJECT :
+        if (c == '}') {
+          rv = this->CloseObject();
+          NS_ENSURE_SUCCESS(rv, rv);
+          rv = PopState();
+          NS_ENSURE_SUCCESS(rv, rv);
+        } else if (c == ',') {
+          rv = PushState(JSON_PARSE_STATE_OBJECT_PAIR);
+          NS_ENSURE_SUCCESS(rv, rv);
+        } else if (c == ']') {
+          return NS_ERROR_FAILURE; // unexpected
+        } else if (!NS_IsAsciiWhitespace(c)) {
+          return NS_ERROR_FAILURE; // unexpected
+        }
+        break;
+      case JSON_PARSE_STATE_ARRAY :
+        if (c == ']') {
+          rv = this->CloseArray();
+          NS_ENSURE_SUCCESS(rv, rv);
+          rv = PopState();
+          NS_ENSURE_SUCCESS(rv, rv);
+        } else if (c == ',') {
+          rv = PushState(JSON_PARSE_STATE_VALUE);
+          NS_ENSURE_SUCCESS(rv, rv);
+        } else if (!NS_IsAsciiWhitespace(c)) {
+          return NS_ERROR_FAILURE; // unexpected
+        }
+        break;
+      case JSON_PARSE_STATE_OBJECT_PAIR :
+        if (c == '"') {
+          // we want to be waiting for a : when the string has been read
+          *mStatep = JSON_PARSE_STATE_OBJECT_IN_PAIR;
+          PushState(JSON_PARSE_STATE_STRING);
+        } else if (c == '}') {
+          rv = this->CloseObject();
+          NS_ENSURE_SUCCESS(rv, rv);
+          // pop off the object_pair state
+          rv = PopState();
+          NS_ENSURE_SUCCESS(rv, rv);
+          // pop off the object state
+          rv = PopState();
+          NS_ENSURE_SUCCESS(rv, rv);
+        } else if (c == ']' || !NS_IsAsciiWhitespace(c)) {
+          return NS_ERROR_FAILURE; // unexpected
+        }
+        break;
+      case JSON_PARSE_STATE_OBJECT_IN_PAIR:
+        if (c == ':') {
+          *mStatep = JSON_PARSE_STATE_VALUE;
+        } else if (!NS_IsAsciiWhitespace(c)) {
+          return NS_ERROR_FAILURE; // unexpected
+        }
+        break;
+      case JSON_PARSE_STATE_STRING:
+        if (c == '"') {
+          rv = PopState();
+          NS_ENSURE_SUCCESS(rv, rv);
+          buf[bufIndex] = nsnull;
+          if (*mStatep == JSON_PARSE_STATE_OBJECT_IN_PAIR) {
+            rv = HandleData(JSON_DATA_KEYSTRING, buf, bufIndex);
+          } else {
+            rv = HandleData(JSON_DATA_STRING, buf, bufIndex);
+          }
+          bufIndex = 0;
+          NS_ENSURE_SUCCESS(rv, rv);
+        } else if (c == '\\') {
+          *mStatep = JSON_PARSE_STATE_STRING_ESCAPE;
+        } else {
+          PUSHCHAR(c);
+        }
+        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') {
+              mNumHex = 0;
+              mHexChar = 0;
+              *mStatep = JSON_PARSE_STATE_STRING_HEX;
+              continue;
+            } else {
+              return NS_ERROR_FAILURE; // unexpected
+            }
+        }
+
+        PUSHCHAR(c);
+        *mStatep = JSON_PARSE_STATE_STRING;
+        break;
+      case JSON_PARSE_STATE_STRING_HEX:
+        if (('0' <= c) && (c <= '9')) {
+          mHexChar = (mHexChar << 4) | (c - '0');
+        } else if (('a' <= c) && (c <= 'f')) {
+          mHexChar = (mHexChar << 4) | (c - 'a' + 0x0a);
+        } else if (('A' <= c) && (c <= 'F')) {
+          mHexChar = (mHexChar << 4) | (c - 'A' + 0x0a);
+        } else {
+          return NS_ERROR_FAILURE; // unexpected
+        }
+
+        if (++(mNumHex) == 4) {
+          PUSHCHAR(mHexChar);
+          mHexChar = 0;
+          mNumHex = 0;
+          *mStatep = JSON_PARSE_STATE_STRING;
+        }
+        break;
+      case JSON_PARSE_STATE_KEYWORD:
+        if (NS_IsAsciiAlpha(c)) {
+          PUSHCHAR(c);
+        } else {
+          // this character isn't part of the keyword, process it again
+          i--;
+          rv = PopState();
+          NS_ENSURE_SUCCESS(rv, rv);
+          buf[bufIndex] = nsnull;
+          rv = HandleData(JSON_DATA_KEYWORD, buf, bufIndex);
+          bufIndex = 0;
+          NS_ENSURE_SUCCESS(rv, rv);
+        }
+        break;
+      case JSON_PARSE_STATE_NUMBER:
+        if (IsNumChar(c)) {
+          PUSHCHAR(c);
+        } else {
+          // this character isn't part of the number, process it again
+          i--;
+          rv = PopState();
+          NS_ENSURE_SUCCESS(rv, rv);
+          buf[bufIndex] = nsnull;
+          rv = HandleData(JSON_DATA_NUMBER, buf, bufIndex);
+          bufIndex = 0;
+          NS_ENSURE_SUCCESS(rv, rv);
+        }
+        break;
+      case JSON_PARSE_STATE_FINISHED:
+        if (!NS_IsAsciiWhitespace(c)) {
+          return NS_ERROR_FAILURE; // extra input
+        }
+        break;
+      default:
+        NS_NOTREACHED("Invalid JSON parser state");
+      }
+    }
+
+#undef PUSH_CHAR
+
+    // Preserve partially consumed data for the next call to Consume
+    // This can happen when a primitive spans a stream buffer
+    if (bufIndex != 0) {
+      mStringBuffer.Append(buf, bufIndex);
+    }
+
+    return NS_OK;
+}
+
+nsresult
+nsJSONListener::PushValue(JSObject *aParent, jsval aValue)
+{
+  JSAutoTempValueRooter tvr(mCx, 1, &aValue);
+  
+  JSBool ok;
+  if (JS_IsArrayObject(mCx, aParent)) {
+    jsuint len;
+    ok = JS_GetArrayLength(mCx, aParent, &len);
+    if (ok) {
+      ok = JS_SetElement(mCx, aParent, len, &aValue);
+    }
+  } else {
+    ok = JS_DefineUCProperty(mCx, aParent, (jschar *) mObjectKey.get(),
+                             mObjectKey.Length(), aValue,
+                             NULL, NULL, JSPROP_ENUMERATE);
+  }
+
+  return ok ? NS_OK : NS_ERROR_FAILURE;
+}
+
+nsresult
+nsJSONListener::PushObject(JSObject *aObj)
+{
+  if (mObjectStack.Length() >= JSON_MAX_DEPTH)
+    return NS_ERROR_FAILURE; // decoding error
+
+  // Check if this is the root object
+  if (mObjectStack.IsEmpty()) {
+    *mRootVal = OBJECT_TO_JSVAL(aObj);
+    if (!mObjectStack.AppendElement(aObj))
+      return NS_ERROR_OUT_OF_MEMORY;
+    return NS_OK;
+  }
+
+  nsresult rv;
+  JSObject *parent = mObjectStack.ElementAt(mObjectStack.Length() - 1);
+  rv = PushValue(parent, OBJECT_TO_JSVAL(aObj));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!mObjectStack.AppendElement(aObj))
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  return rv;
+}
+
+nsresult
+nsJSONListener::OpenObject()
+{
+  JSObject *obj = JS_NewObject(mCx, NULL, NULL, NULL);
+  if (!obj)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  return PushObject(obj);
+}
+
+nsresult
+nsJSONListener::OpenArray()
+{
+  // Add an array to an existing array or object
+  JSObject *arr = JS_NewArrayObject(mCx, 0, NULL);
+  if (!arr)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  return PushObject(arr);
+}
+
+nsresult
+nsJSONListener::CloseObject()
+{
+  if (!mObjectStack.SetLength(mObjectStack.Length() - 1))
+    return NS_ERROR_FAILURE;
+
+  return NS_OK;
+}
+
+nsresult
+nsJSONListener::CloseArray()
+{
+  return this->CloseObject();
+}
+
+nsresult
+nsJSONListener::HandleData(JSONDataType aType, const PRUnichar *aBuf,
+                           PRUint32 aLength)
+{
+  nsresult rv = NS_OK;
+  PRUint32 len;
+  const PRUnichar *buf;
+  PRBool needsTruncate = PR_FALSE;
+
+  if (mStringBuffer.IsEmpty()) {
+    buf = aBuf;
+    len = aLength;
+  } else {
+    needsTruncate = PR_TRUE;
+    mStringBuffer.Append(aBuf, aLength);
+    buf = mStringBuffer.get();
+    len = mStringBuffer.Length();
+  }
+
+  switch (aType) {
+    case JSON_DATA_STRING:
+      rv = HandleString(buf, len);
+      break;
+
+    case JSON_DATA_KEYSTRING:
+      mObjectKey = nsDependentString(buf, len);
+      rv = NS_OK;
+      break;
+
+    case JSON_DATA_NUMBER:
+      rv = HandleNumber(buf, len);
+      break;
+
+    case JSON_DATA_KEYWORD:
+      rv = HandleKeyword(buf, len);
+      break;
+
+    default:
+      NS_NOTREACHED("Should have a JSON data type");
+  }
+
+  if (needsTruncate)
+    mStringBuffer.Truncate();
+
+  return rv;
+}
+
+nsresult
+nsJSONListener::HandleString(const PRUnichar *aBuf, PRUint32 aLength)
+{
+  JSObject *obj = mObjectStack.ElementAt(mObjectStack.Length() - 1);
+  JSString *str = JS_NewUCStringCopyN(mCx, 
+                                      reinterpret_cast<const jschar*> (aBuf),
+                                      aLength);
+  if (!str)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  return PushValue(obj, STRING_TO_JSVAL(str));
+}
+
+nsresult
+nsJSONListener::HandleNumber(const PRUnichar *aBuf, PRUint32 aLength)
+{
+  nsresult rv;
+  JSObject *obj = mObjectStack.ElementAt(mObjectStack.Length() - 1);
+
+  char *estr;
+  int err;
+  double val =
+    JS_strtod(NS_ConvertUTF16toUTF8(nsDependentString(aBuf, aLength)).get(),
+              &estr, &err);
+  if (err == JS_DTOA_ENOMEM) {
+    rv = NS_ERROR_OUT_OF_MEMORY;
+  } else if (err || *estr) {
+    rv = NS_ERROR_FAILURE; // decode error
+  } else {
+    // ok
+    jsval numVal;
+    if (JS_NewNumberValue(mCx, val, &numVal)) {
+      rv = PushValue(obj, numVal);
+    } else {
+      rv = NS_ERROR_FAILURE; // decode error
+    }
+  }
+
+  return rv;
+}
+
+nsresult
+nsJSONListener::HandleKeyword(const PRUnichar *aBuf, PRUint32 aLength)
+{
+  nsAutoString buf;
+  buf.Append(aBuf, aLength);
+
+  JSObject *obj = mObjectStack.ElementAt(mObjectStack.Length() - 1);
+  jsval keyword;
+  if (buf.Equals(NS_LITERAL_STRING("null"))) {
+    keyword = JSVAL_NULL;
+  } else if (buf.Equals(NS_LITERAL_STRING("true"))) {
+    keyword = JSVAL_TRUE;
+  } else if (buf.Equals(NS_LITERAL_STRING("false"))) {
+    keyword = JSVAL_FALSE;
+  } else {
+    return NS_ERROR_FAILURE;
+  }
+
+  return PushValue(obj, keyword);
+}
--- a/dom/src/json/nsJSON.h
+++ b/dom/src/json/nsJSON.h
@@ -35,37 +35,40 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsJSON_h__
 #define nsJSON_h__
 
 #include "jsprvtd.h"
-#include "jsapi.h"
 #include "nsIJSON.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIOutputStream.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsIRequestObserver.h"
 #include "nsIStreamListener.h"
 #include "nsTArray.h"
 
 class nsIURI;
 
+#define JSON_MAX_DEPTH  2048
+#define JSON_PARSER_BUFSIZE 1024
+
 class NS_STACK_CLASS nsJSONWriter
 {
 public:
   nsJSONWriter();
   nsJSONWriter(nsIOutputStream *aStream);
   virtual ~nsJSONWriter();
   nsresult SetCharset(const char *aCharset);
   nsCOMPtr<nsIOutputStream> mStream;
+  nsresult WriteString(const PRUnichar* aBuffer, PRUint32);
   nsresult Write(const PRUnichar *aBuffer, PRUint32 aLength);
   nsString mOutputString;
   PRBool DidWrite();
   void FlushBuffer();
 
 protected:
   PRUnichar *mBuffer;
   PRUint32 mBufferCount;
@@ -81,42 +84,109 @@ class nsJSON : public nsIJSON
 public:
   nsJSON();
   virtual ~nsJSON();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIJSON
 
 protected:
+  JSBool   ToJSON(JSContext *cx, jsval *vp);
+  nsresult EncodeObject(JSContext *cx, jsval *vp, nsJSONWriter *writer,
+                        JSObject *whitelist, PRUint32 depth);
   nsresult EncodeInternal(nsJSONWriter *writer);
   nsresult DecodeInternal(nsIInputStream *aStream,
                           PRInt32 aContentLength,
                           PRBool aNeedsConverter);
   nsCOMPtr<nsIURI> mURI;
 };
 
 NS_IMETHODIMP
 NS_NewJSON(nsISupports* aOuter, REFNSIID aIID, void** aResult);
 
+enum JSONParserState {
+    JSON_PARSE_STATE_INIT,
+    JSON_PARSE_STATE_OBJECT_VALUE,
+    JSON_PARSE_STATE_VALUE,
+    JSON_PARSE_STATE_OBJECT,
+    JSON_PARSE_STATE_OBJECT_PAIR,
+    JSON_PARSE_STATE_OBJECT_IN_PAIR,
+    JSON_PARSE_STATE_ARRAY,
+    JSON_PARSE_STATE_STRING,
+    JSON_PARSE_STATE_STRING_ESCAPE,
+    JSON_PARSE_STATE_STRING_HEX,
+    JSON_PARSE_STATE_NUMBER,
+    JSON_PARSE_STATE_KEYWORD,
+    JSON_PARSE_STATE_FINISHED
+};
+
+enum JSONDataType {
+  JSON_DATA_STRING,
+  JSON_DATA_KEYSTRING,
+  JSON_DATA_NUMBER,
+  JSON_DATA_KEYWORD
+};
+
+class nsJSONObjectStack : public nsTArray<JSObject *>,
+                          public JSTempValueRooter
+{
+};
+
 class nsJSONListener : public nsIStreamListener
 {
 public:
   nsJSONListener(JSContext *cx, jsval *rootVal, PRBool needsConverter);
   virtual ~nsJSONListener();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
 
 protected:
-  PRBool mNeedsConverter;
-  JSONParser *mJSONParser;
+
+  /* Used while handling \uNNNN in strings */
+  PRUnichar mHexChar;
+  PRUint8 mNumHex;
+
   JSContext *mCx;
   jsval *mRootVal;
+  PRBool mNeedsConverter;
   nsCOMPtr<nsIUnicodeDecoder> mDecoder;
+  JSONParserState *mStatep;
+  JSONParserState mStateStack[JSON_MAX_DEPTH];
+  nsString mStringBuffer;
   nsCString mSniffBuffer;
+
+  nsresult PushState(JSONParserState state);
+  nsresult PopState();
   nsresult ProcessBytes(const char* aBuffer, PRUint32 aByteLength);
   nsresult ConsumeConverted(const char* aBuffer, PRUint32 aByteLength);
   nsresult Consume(const PRUnichar *data, PRUint32 len);
-  void Cleanup();
+
+  // helper to determine whether a character could be part of a number
+  PRBool IsNumChar(PRUnichar c) 
+  {
+    if ((c <= '9' && c >= '0') ||
+        c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E')
+      return PR_TRUE;
+
+    return PR_FALSE;
+  }
+
+  // These handle parsed tokens. Could be split to separate interface.
+  nsJSONObjectStack mObjectStack;
+
+  nsresult PushValue(JSObject *aParent, jsval aValue);
+  nsresult PushObject(JSObject *aObj);
+  nsresult OpenObject();
+  nsresult CloseObject();
+  nsresult OpenArray();
+  nsresult CloseArray();
+
+  nsresult HandleData(JSONDataType aType, const PRUnichar *aBuf,
+                      PRUint32 aLength);
+  nsresult HandleString(const PRUnichar *aBuf, PRUint32 aLength);
+  nsresult HandleNumber(const PRUnichar *aBuf, PRUint32 aLength);
+  nsresult HandleKeyword(const PRUnichar *aBuf, PRUint32 aLength);
+  nsString mObjectKey;
 };
 
 #endif
--- a/dom/src/json/test/json2.js
+++ b/dom/src/json/test/json2.js
@@ -63,19 +63,19 @@
 
     Use your own copy. It is extremely unwise to load third party
     code into your pages.
 */
 
 /*jslint evil: true */
 /*extern JSON */
 
-if (!this.crockfordJSON) {
+if (!this.JSON) {
 
-    crockfordJSON = function () {
+    JSON = function () {
 
         function f(n) {    // Format integers to have at least two digits.
             return n < 10 ? '0' + n : n;
         }
 
         Date.prototype.toJSON = function () {
 
 // Eventually, this method will be based on the date.toISOString method.
--- a/dom/src/json/test/unit/head_json.js
+++ b/dom/src/json/test/unit/head_json.js
@@ -10,10 +10,10 @@ var outputDir = Cc["@mozilla.org/file/lo
 outputDir.initWithFile(workingDir);
 outputDir.append(outputName);
 
 if (!outputDir.exists()) {
   outputDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
 } else if (!outputDir.isDirectory()) {
   do_throw(outputName + " is not a directory?")
 }
-var crockfordJSON = null;
+var JSON = null;
 do_import_script("dom/src/json/test/json2.js");
--- a/dom/src/json/test/unit/test_encode.js
+++ b/dom/src/json/test/unit/test_encode.js
@@ -105,17 +105,17 @@ function getTestPairs() {
 
 function testStringEncode() {
   // test empty arg
   do_check_eq(null, nativeJSON.encode());
 
   var pairs = getTestPairs();
   for each(pair in pairs) {
     var nativeResult = nativeJSON.encode(pair[1]);
-    var crockfordResult = crockfordJSON.stringify(pair[1]);
+    var crockfordResult = JSON.stringify(pair[1]);
     do_check_eq(pair[0], nativeResult);
     
     // Don't follow json2.js handling of non-objects
     if (pair[1] && (typeof pair[1] == "object")) {
       do_check_eq(crockfordResult, nativeResult);
     }
   }
 }
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -135,17 +135,16 @@ CPPSRCS		= \
 		jsinvoke.cpp \
 		jsiter.cpp \
 		jslock.cpp \
 		jslog2.cpp \
 		jslong.cpp \
 		jsmath.cpp \
 		jsnum.cpp \
 		jsobj.cpp \
-		json.cpp \
 		jsopcode.cpp \
 		jsparse.cpp \
 		jsprf.cpp \
 		jsregexp.cpp \
 		jsscan.cpp \
 		jsscope.cpp \
 		jsscript.cpp \
 		jsstr.cpp \
@@ -183,17 +182,16 @@ EXPORTS		= \
 		jshash.h \
 		jsinterp.h \
 		jsiter.h \
 		jslock.h \
 		jslong.h \
 		jsmath.h \
 		jsnum.h \
 		jsobj.h \
-		json.h \
 		jsopcode.tbl \
 		jsopcode.h \
 		jsotypes.h \
 		jsparse.h \
 		jsprf.h \
 		jsproto.tbl \
 		jsprvtd.h \
 		jspubtd.h \
--- a/js/src/Makefile.ref
+++ b/js/src/Makefile.ref
@@ -183,18 +183,17 @@ JS_HFILES =		\
 	jsgc.h		\
 	jsinterp.h	\
 	jsiter.h	\
 	jslibmath.h	\
 	jslock.h	\
 	jsmath.h	\
 	jsnum.h		\
 	jsobj.h		\
-	json.h		\
-	jsopcode.h	\
+	jsopcode.h      \
 	jsparse.h	\
 	jsarena.h	\
 	jsclist.h	\
 	jsdhash.h	\
 	jsdtoa.h	\
 	jshash.h	\
 	jslong.h	\
 	jstypes.h	\
@@ -283,17 +282,16 @@ JS_CPPFILES =		\
 	jsinvoke.cpp    \
 	jsiter.cpp	\
 	jslock.cpp	\
 	jslog2.cpp	\
 	jslong.cpp	\
 	jsmath.cpp	\
 	jsnum.cpp	\
 	jsobj.cpp	\
-	json.cpp	\
 	jsopcode.cpp	\
 	jsparse.cpp	\
 	jsprf.cpp	\
 	jsregexp.cpp	\
 	jsscan.cpp	\
 	jsscope.cpp	\
 	jsscript.cpp	\
 	jsstr.cpp	\
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -64,17 +64,16 @@
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsmath.h"
 #include "jsnum.h"
-#include "json.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsparse.h"
 #include "jsregexp.h"
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
@@ -1346,17 +1345,16 @@ JS_InitStandardClasses(JSContext *cx, JS
     /* Initialize the rest of the standard objects and functions. */
     return js_InitArrayClass(cx, obj) &&
            js_InitBlockClass(cx, obj) &&
            js_InitBooleanClass(cx, obj) &&
            js_InitCallClass(cx, obj) &&
            js_InitExceptionClasses(cx, obj) &&
            js_InitMathClass(cx, obj) &&
            js_InitNumberClass(cx, obj) &&
-           js_InitJSONClass(cx, obj) &&
            js_InitRegExpClass(cx, obj) &&
            js_InitStringClass(cx, obj) &&
            js_InitEval(cx, obj) &&
 #if JS_HAS_SCRIPT_OBJECT
            js_InitScriptClass(cx, obj) &&
 #endif
 #if JS_HAS_XML_SUPPORT
            js_InitXMLClasses(cx, obj) &&
@@ -1430,17 +1428,16 @@ static JSStdName standard_class_atoms[] 
     {js_InitQNameClass,                 EAGER_ATOM_AND_EXT_CLASP(QName)},
 #endif
 #if JS_HAS_FILE_OBJECT
     {js_InitFileClass,                  EAGER_ATOM_AND_CLASP(File)},
 #endif
 #if JS_HAS_GENERATORS
     {js_InitIteratorClasses,            EAGER_ATOM_AND_CLASP(StopIteration)},
 #endif
-    {js_InitJSONClass,                  EAGER_ATOM_AND_CLASP(JSON)},
     {NULL,                              0, NULL, NULL}
 };
 
 /*
  * Table of top-level function and constant names and their init functions.
  * If you add a "standard" global function or property, remember to update
  * this table.
  */
@@ -5521,52 +5518,16 @@ JS_DecodeBytes(JSContext *cx, const char
 }
 
 JS_PUBLIC_API(char *)
 JS_EncodeString(JSContext *cx, JSString *str)
 {
     return js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
 }
 
-JS_PUBLIC_API(JSBool)
-JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, 
-             JSONWriteCallback callback, void *data)
-{
-    CHECK_REQUEST(cx);
-    return js_Stringify(cx, vp, replacer, callback, data, 0);
-}
-
-JS_PUBLIC_API(JSBool)
-JS_TryJSON(JSContext *cx, jsval *vp)
-{
-    CHECK_REQUEST(cx);
-    return js_TryJSON(cx, vp);
-}
-
-JS_PUBLIC_API(JSONParser *)
-JS_BeginJSONParse(JSContext *cx, jsval *vp)
-{
-    CHECK_REQUEST(cx);
-    return js_BeginJSONParse(cx, vp);
-}
-
-JS_PUBLIC_API(JSBool)
-JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
-{
-    CHECK_REQUEST(cx);
-    return js_ConsumeJSONText(cx, jp, data, len);
-}
-
-JS_PUBLIC_API(JSBool)
-JS_FinishJSONParse(JSContext *cx, JSONParser *jp)
-{
-    CHECK_REQUEST(cx);
-    return js_FinishJSONParse(cx, jp);
-}
-
 /*
  * The following determines whether C Strings are to be treated as UTF-8
  * or ISO-8859-1.  For correct operation, it must be set prior to the
  * first call to JS_NewRuntime.
  */
 #ifndef JS_C_STRINGS_ARE_UTF8
 JSBool js_CStringsAreUTF8 = JS_FALSE;
 #endif
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2391,47 +2391,16 @@ JS_DecodeBytes(JSContext *cx, const char
 /*
  * A variation on JS_EncodeCharacters where a null terminated string is
  * returned that you are expected to call JS_free on when done.
  */
 JS_PUBLIC_API(char *)
 JS_EncodeString(JSContext *cx, JSString *str);
 
 /************************************************************************/
-/*
- * JSON functions
- */
-typedef JSBool (* JSONWriteCallback)(const jschar *buf, uint32 len, void *data);
-
-/*
- * JSON.stringify as specificed by ES3.1 (draft)
- */
-JS_PUBLIC_API(JSBool)
-JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, 
-             JSONWriteCallback callback, void *data);
-
-/*
- * Retrieve a toJSON function. If found, set vp to its result.
- */
-JS_PUBLIC_API(JSBool)
-JS_TryJSON(JSContext *cx, jsval *vp);
-
-/*
- * JSON.parse as specificed by ES3.1 (draft)
- */
-JS_PUBLIC_API(JSONParser *)
-JS_BeginJSONParse(JSContext *cx, jsval *vp);
-
-JS_PUBLIC_API(JSBool)
-JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len);
-
-JS_PUBLIC_API(JSBool)
-JS_FinishJSONParse(JSContext *cx, JSONParser *jp);
-
-/************************************************************************/
 
 /*
  * Locale specific string conversion and error message callbacks.
  */
 struct JSLocaleCallbacks {
     JSLocaleToUpperCase     localeToUpperCase;
     JSLocaleToLowerCase     localeToLowerCase;
     JSLocaleCompare         localeCompare;
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -121,17 +121,16 @@ const char *const js_common_atom_names[]
     js_proto_str,               /* protoAtom                    */
     js_set_str,                 /* setAtom                      */
     js_setter_str,              /* setterAtom                   */
     js_stack_str,               /* stackAtom                    */
     js_toLocaleString_str,      /* toLocaleStringAtom           */
     js_toSource_str,            /* toSourceAtom                 */
     js_toString_str,            /* toStringAtom                 */
     js_valueOf_str,             /* valueOfAtom                  */
-    js_toJSON_str,              /* toJSONAtom                   */
     "(void 0)",                 /* void0Atom                    */
 
 #if JS_HAS_XML_SUPPORT
     js_etago_str,               /* etagoAtom                    */
     js_namespace_str,           /* namespaceAtom                */
     js_ptagc_str,               /* ptagcAtom                    */
     js_qualifier_str,           /* qualifierAtom                */
     js_space_str,               /* spaceAtom                    */
@@ -181,17 +180,16 @@ const char js_proto_str[]           = "_
 const char js_setter_str[]          = "setter";
 const char js_set_str[]             = "set";
 const char js_stack_str[]           = "stack";
 const char js_toSource_str[]        = "toSource";
 const char js_toString_str[]        = "toString";
 const char js_toLocaleString_str[]  = "toLocaleString";
 const char js_undefined_str[]       = "undefined";
 const char js_valueOf_str[]         = "valueOf";
-const char js_toJSON_str[]          = "toJSON";
 
 #if JS_HAS_XML_SUPPORT
 const char js_etago_str[]           = "</";
 const char js_namespace_str[]       = "namespace";
 const char js_ptagc_str[]           = "/>";
 const char js_qualifier_str[]       = "::";
 const char js_space_str[]           = " ";
 const char js_stago_str[]           = "<";
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -197,17 +197,16 @@ struct JSAtomState {
     JSAtom              *protoAtom;
     JSAtom              *setAtom;
     JSAtom              *setterAtom;
     JSAtom              *stackAtom;
     JSAtom              *toLocaleStringAtom;
     JSAtom              *toSourceAtom;
     JSAtom              *toStringAtom;
     JSAtom              *valueOfAtom;
-    JSAtom              *toJSONAtom;
     JSAtom              *void0Atom;
 
 #if JS_HAS_XML_SUPPORT
     JSAtom              *etagoAtom;
     JSAtom              *namespaceAtom;
     JSAtom              *ptagcAtom;
     JSAtom              *qualifierAtom;
     JSAtom              *spaceAtom;
@@ -333,17 +332,16 @@ extern const char   js_stago_str[];
 extern const char   js_star_str[];
 extern const char   js_starQualifier_str[];
 extern const char   js_tagc_str[];
 extern const char   js_toSource_str[];
 extern const char   js_toString_str[];
 extern const char   js_toLocaleString_str[];
 extern const char   js_undefined_str[];
 extern const char   js_valueOf_str[];
-extern const char   js_toJSON_str[];
 extern const char   js_xml_str[];
 
 #ifdef NARCISSUS
 extern const char   js_call_str[];
 extern const char   js_construct_str[];
 extern const char   js_hasInstance_str[];
 extern const char   js_ExecutionContext_str[];
 extern const char   js_current_str[];
deleted file mode 100644
--- a/js/src/json.cpp
+++ /dev/null
@@ -1,917 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is SpiderMonkey JSON.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Robert Sayre <sayrer@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-
-#include "jsapi.h"
-#include "jsarena.h"
-#include "jsarray.h"
-#include "jsatom.h"
-#include "jsbool.h"
-#include "jscntxt.h"
-#include "jsdtoa.h"
-#include "jsinterp.h"
-#include "jsiter.h"
-#include "jsnum.h"
-#include "jsobj.h"
-#include "jsprf.h"
-#include "jsscan.h"
-#include "jsstr.h"
-#include "jstypes.h"
-#include "jsutil.h"
-
-#include "json.h"
-
-JSClass js_JSONClass = {
-    js_JSON_str,
-    JSCLASS_HAS_CACHED_PROTO(JSProto_JSON),
-    JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
-    JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub,
-    JSCLASS_NO_OPTIONAL_MEMBERS
-};
-
-JSBool
-js_json_parse(JSContext *cx, uintN argc, jsval *vp)
-{
-    JSString *s;
-    jsval *argv = vp + 2;
-
-    // Must throw an Error if there isn't a first arg
-    if (!JS_ConvertArguments(cx, argc, argv, "s", &s))
-        return JS_FALSE;
-
-    JSBool ok;  
-    JSONParser *jp = js_BeginJSONParse(cx, vp);
-    if (!jp)
-        ok = JS_FALSE;
-
-    if (ok) {
-        ok = js_ConsumeJSONText(cx, jp, JS_GetStringChars(s), JS_GetStringLength(s));
-        ok  &= js_FinishJSONParse(cx, jp);
-    }
-
-    if (!ok)
-        JS_ReportError(cx, "Error parsing JSON.");
-
-    return ok;
-}
-
-struct StringifyClosure
-{
-    StringifyClosure(JSContext *aCx, jsval *str) : cx(aCx), s(str)
-    {
-    }
-
-    JSContext *cx;
-    jsval *s;
-};
-
-static
-JSBool WriteCallback(const jschar *buf, uint32 len, void *data)
-{
-    StringifyClosure *sc = static_cast<StringifyClosure*>(data);
-    JSString *s1 = JSVAL_TO_STRING(*sc->s);
-    JSString *s2 = JS_NewUCStringCopyN(sc->cx, buf, len);
-    if (!s2)
-        return JS_FALSE;
-
-    s1 = js_ConcatStrings(sc->cx, s1, s2);
-    if (!s1)
-        return JS_FALSE;
-
-    *sc->s = STRING_TO_JSVAL(s1);
-    return JS_TRUE;
-}
-
-JSBool
-js_json_stringify(JSContext *cx, uintN argc, jsval *vp)
-{
-    JSObject *obj;
-    jsval *argv = vp + 2;
-    
-    // Must throw an Error if there isn't a first arg
-    if (!JS_ConvertArguments(cx, argc, argv, "o", &obj))
-        return JS_FALSE;
-
-    // Only use objects and arrays as the root for now
-    jsval v = OBJECT_TO_JSVAL(obj);
-    JSBool ok = js_TryJSON(cx, &v);
-    JSType type;
-    if (!(ok && !JSVAL_IS_PRIMITIVE(v) &&
-          (type = JS_TypeOfValue(cx, v)) != JSTYPE_FUNCTION &&
-          type != JSTYPE_XML)) {
-        JS_ReportError(cx, "Invalid argument.");
-        return JS_FALSE;
-    }
-    
-    JSString *s = JS_NewStringCopyN(cx, "", 0);
-    if (!s)
-        ok = JS_FALSE;
-
-    if (ok) {
-        jsval sv = STRING_TO_JSVAL(s);
-        StringifyClosure sc(cx, &sv);
-        JSAutoTempValueRooter tvr(cx, 1, sc.s); 
-        ok = js_Stringify(cx, &v, NULL, &WriteCallback, &sc, 0);
-        *vp = *sc.s;
-    }
-
-    return ok;
-}
-
-JSBool
-js_TryJSON(JSContext *cx, jsval *vp)
-{
-    // Checks whether the return value implements toJSON()
-    JSBool ok = JS_TRUE;
-    
-    if (!JSVAL_IS_PRIMITIVE(*vp)) {
-        JSObject *obj = JSVAL_TO_OBJECT(*vp);
-        ok = js_TryMethod(cx, obj, cx->runtime->atomState.toJSONAtom, 0, NULL, vp);
-    }
-    
-    return ok;
-}
-
-
-static const jschar quote = jschar('"');
-static const jschar backslash = jschar('\\');
-static const jschar unicodeEscape[] = {'\\', 'u', '0', '0'};
-
-static JSBool
-write_string(JSContext *cx, JSONWriteCallback callback, void *data, const jschar *buf, uint32 len)
-{
-    if (!callback(&quote, 1, data))
-        return JS_FALSE;
-
-    uint32 mark = 0;
-    uint32 i;
-    for (i = 0; i < len; ++i) {
-        if (buf[i] == quote || buf[i] == backslash) {
-            if (!callback(&buf[mark], i - mark, data) || !callback(&backslash, 1, data) ||
-                !callback(&buf[i], 1, data)) {
-                return JS_FALSE;
-            }
-            mark = i + 1;
-        } else if (buf[i] <= 31 || buf[i] == 127) {
-            if (!callback(&buf[mark], i - mark, data) || !callback(unicodeEscape, 4, data))
-                return JS_FALSE;
-            char ubuf[10];
-            unsigned int len = JS_snprintf(ubuf, sizeof(ubuf), "%.2x", buf[i]);
-            JS_ASSERT(len == 2);
-            // TODO: don't allocate a JSString just to inflate (js_InflateStringToBuffer on static?)
-            JSString *us = JS_NewString(cx, ubuf, len);
-            if (!callback(JS_GetStringChars(us), len, data))
-                return JS_FALSE;
-            mark = i + 1;
-        }
-    }
-
-    if (mark < len && !callback(&buf[mark], len - mark, data))
-        return JS_FALSE;
-
-    if (!callback(&quote, 1, data))
-        return JS_FALSE;
-
-    return JS_TRUE;
-}
-
-JSBool
-js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
-             JSONWriteCallback callback, void *data, uint32 depth)
-{
-    if (depth > JSON_MAX_DEPTH)
-        return JS_FALSE; /* encoding error */
-
-    JSBool ok = JS_TRUE;
-    JSObject *obj = JSVAL_TO_OBJECT(*vp);
-    JSBool isArray = JS_IsArrayObject(cx, obj);
-    jschar output = jschar(isArray ? '[' : '{');
-    if (!callback(&output, 1, data))
-        return JS_FALSE;
-    
-    JSObject *iterObj = NULL;
-    jsint i = 0;
-    jsuint length = 0;
-
-    if (isArray) {
-        if (!JS_GetArrayLength(cx, obj, &length))
-            return JS_FALSE;
-    } else {
-        if (!js_ValueToIterator(cx, JSITER_ENUMERATE, vp))
-            return JS_FALSE;
-        iterObj = JSVAL_TO_OBJECT(*vp);
-    }
-
-    jsval outputValue = JSVAL_VOID;
-    JSAutoTempValueRooter tvr(cx, 1, &outputValue);
-
-    jsval key;
-    JSBool memberWritten = JS_FALSE;
-    do {
-        outputValue = JSVAL_VOID;
-
-        if (isArray) {
-            if ((jsuint)i >= length)
-                break;
-            ok = JS_GetElement(cx, obj, i++, &outputValue);
-        } else {
-            ok = js_CallIteratorNext(cx, iterObj, &key);
-            if (!ok)
-                break;
-            if (key == JSVAL_HOLE)
-                break;
-
-            JSString *ks;
-            if (JSVAL_IS_STRING(key)) {
-                ks = JSVAL_TO_STRING(key);
-            } else {
-                ks = JS_ValueToString(cx, key);
-                if (!ks) {
-                    ok = JS_FALSE;
-                    break;
-                }
-            }
-
-            ok = JS_GetUCProperty(cx, obj, JS_GetStringChars(ks),
-                                  JS_GetStringLength(ks), &outputValue);
-        }
-
-        if (!ok)
-            break;
-
-        // if this is an array, holes are transmitted as null
-        if (isArray && outputValue == JSVAL_VOID) {
-            outputValue = JSVAL_NULL;
-        } else if (JSVAL_IS_OBJECT(outputValue)) {
-            ok = js_TryJSON(cx, &outputValue);
-            if (!ok)
-                break;
-        }
-
-        // elide undefined values
-        if (outputValue == JSVAL_VOID)
-            continue;
-
-        // output a comma unless this is the first member to write
-        if (memberWritten) {
-            output = jschar(',');
-            ok = callback(&output, 1, data);
-        if (!ok)
-                break;
-        }
-        memberWritten = JS_TRUE;
-
-        JSType type = JS_TypeOfValue(cx, outputValue);
-
-        // Can't encode these types, so drop them
-        if (type == JSTYPE_FUNCTION || type == JSTYPE_XML)
-            break;
-
-        // Be careful below, this string is weakly rooted.
-        JSString *s;
-
-        // If this isn't an array, we need to output a key
-        if (!isArray) {
-            s = JS_ValueToString(cx, key);
-            if (!s) {
-                ok = JS_FALSE;
-                break;
-            }
-
-            ok = write_string(cx, callback, data, JS_GetStringChars(s), JS_GetStringLength(s));
-            if (!ok)
-                break;
-
-            output = jschar(':');
-            ok = callback(&output, 1, data);
-            if (!ok)
-                break;
-        }
-
-        if (!JSVAL_IS_PRIMITIVE(outputValue)) {
-            // recurse
-          ok = js_Stringify(cx, &outputValue, replacer, callback, data, depth + 1);
-        } else {
-            JSString *outputString;
-            s = JS_ValueToString(cx, outputValue);
-            if (!s) {
-                ok = JS_FALSE;
-                break;
-            }
-
-            if (type == JSTYPE_STRING) {
-                ok = write_string(cx, callback, data, JS_GetStringChars(s), JS_GetStringLength(s));
-                if (!ok)
-                    break;
-                
-                continue;
-            }
-
-            if (type == JSTYPE_NUMBER) {
-                if (JSVAL_IS_DOUBLE(outputValue)) {
-                    jsdouble d = *JSVAL_TO_DOUBLE(outputValue);
-                    if (!JSDOUBLE_IS_FINITE(d))
-                        outputString = JS_NewStringCopyN(cx, "null", 4);
-                    else
-                        outputString = s;
-                } else {
-                    outputString = s;
-                }
-            } else if (type == JSTYPE_BOOLEAN) {
-                outputString = s;
-            } else if (JSVAL_IS_NULL(outputValue)) {
-                outputString = JS_NewStringCopyN(cx, "null", 4);
-            } else {
-                ok = JS_FALSE; // encoding error
-                break;
-            }
-
-            ok = callback(JS_GetStringChars(outputString), JS_GetStringLength(outputString), data);
-        }
-    } while (ok);
-
-    if (iterObj) {
-        // Always close the iterator, but make sure not to stomp on OK
-        ok &= js_CloseIterator(cx, *vp);
-        // encoding error or propagate? FIXME: Bug 408838.
-    }
-
-    if (!ok) {
-        JS_ReportError(cx, "Error during JSON encoding.");
-        return JS_FALSE;
-    }
-
-    output = jschar(isArray ? ']' : '}');
-    ok = callback(&output, 1, data);
-
-    return ok;
-}
-
-// 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');
-}
-
-JSONParser *
-js_BeginJSONParse(JSContext *cx, jsval *rootVal)
-{
-    if (!cx)
-        return NULL;
-
-    JSObject *arr = JS_NewArrayObject(cx, 0, NULL);
-    if (!arr)
-        return NULL;
-
-    JSONParser *jp = (JSONParser*) JS_malloc(cx, sizeof(JSONParser));
-    if (!jp)
-        return NULL;        
-    jp->buffer = NULL;
-
-    jp->objectStack = arr;
-    if (!JS_AddRoot(cx, jp->objectStack))
-        goto bad;
-
-    jp->hexChar = 0;
-    jp->numHex = 0;
-    jp->statep = jp->stateStack;
-    *jp->statep = JSON_PARSE_STATE_INIT;
-    jp->rootVal = rootVal;
-    jp->objectKey = NULL;
-    jp->buffer = (JSStringBuffer*) JS_malloc(cx, sizeof(JSStringBuffer));
-    if (!jp->buffer)
-        goto bad;
-    js_InitStringBuffer(jp->buffer);
-
-    return jp;
-bad:
-    JS_free(cx, jp->buffer);
-    JS_free(cx, jp);
-    return NULL;
-}
-
-JSBool
-js_FinishJSONParse(JSContext *cx, JSONParser *jp)
-{
-    if (!jp)
-        return JS_TRUE;
-
-    if (jp->buffer)
-        js_FinishStringBuffer(jp->buffer);
-    
-    JS_free(cx, jp->buffer);
-    if (!JS_RemoveRoot(cx, jp->objectStack))
-        return JS_FALSE;
-    JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED;
-    JS_free(cx, jp);
-
-    return ok;
-}
-
-
-static JSBool
-PushState(JSONParser *jp, JSONParserState state)
-{
-    if (*jp->statep == JSON_PARSE_STATE_FINISHED)
-        return JS_FALSE; // extra input
-
-    jp->statep++;
-    if ((uint32)(jp->statep - jp->stateStack) >= JS_ARRAY_LENGTH(jp->stateStack))
-        return JS_FALSE; // too deep
-
-    *jp->statep = state;
-
-    return JS_TRUE;
-}
-
-static JSBool
-PopState(JSONParser *jp)
-{
-    jp->statep--;
-    if (jp->statep < jp->stateStack) {
-        jp->statep = jp->stateStack;
-        return JS_FALSE;
-    } 
-
-    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, jsval value)
-{
-    JSAutoTempValueRooter tvr(cx, 1, &value);
-  
-    JSBool ok;
-    if (OBJ_IS_ARRAY(cx, parent)) {
-        jsuint len;
-        ok = JS_GetArrayLength(cx, parent, &len);
-        if (ok)
-            ok = JS_SetElement(cx, parent, len, &value);
-    } else {
-        ok = JS_DefineUCProperty(cx, parent, JS_GetStringChars(jp->objectKey),
-                                 JS_GetStringLength(jp->objectKey), value,
-                                 NULL, NULL, JSPROP_ENUMERATE);
-    }
-
-    return ok;
-}
-
-static JSBool
-PushObject(JSContext *cx, JSONParser *jp, JSObject *obj)
-{
-    jsuint len;
-    if (!JS_GetArrayLength(cx, jp->objectStack, &len))
-        return JS_FALSE;
-    if (len >= JSON_MAX_DEPTH)
-        return JS_FALSE; // decoding error
-
-    jsval v = OBJECT_TO_JSVAL(obj);
-
-    // Check if this is the root object
-    if (len == 0) {
-        *jp->rootVal = v;        
-        if (!JS_SetElement(cx, jp->objectStack, 0, jp->rootVal))
-            return JS_FALSE;
-        return JS_TRUE;
-    }
-
-    jsval p;
-    if (!JS_GetElement(cx, jp->objectStack, len - 1, &p))
-        return JS_FALSE;
-    JS_ASSERT(JSVAL_IS_OBJECT(p));
-    JSObject *parent = JSVAL_TO_OBJECT(p);
-    if (!PushValue(cx, jp, parent, OBJECT_TO_JSVAL(obj)))
-        return JS_FALSE;
-
-    if (!JS_SetElement(cx, jp->objectStack, len, &v))
-        return JS_FALSE;
-
-    return JS_TRUE;
-}
-
-static JSBool
-OpenObject(JSContext *cx, JSONParser *jp)
-{
-    JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
-    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 = JS_NewArrayObject(cx, 0, NULL);
-    if (!arr)
-        return JS_FALSE;
-
-    return PushObject(cx, jp, arr);
-}
-
-static JSBool
-CloseObject(JSContext *cx, JSONParser *jp)
-{
-    jsuint len;
-    if (!JS_GetArrayLength(cx, jp->objectStack, &len))
-        return JS_FALSE;
-    if (!JS_SetArrayLength(cx, jp->objectStack, len - 1))
-        return JS_FALSE;
-
-    return JS_TRUE;
-}
-
-static JSBool
-CloseArray(JSContext *cx, JSONParser *jp)
-{
-  return CloseObject(cx, jp);
-}
-
-static JSBool
-HandleNumber(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len)
-{
-    JSBool ok;
-    jsuint length;
-    if (!JS_GetArrayLength(cx, jp->objectStack, &length))
-        return JS_FALSE;
-
-    jsval o;
-    if (!JS_GetElement(cx, jp->objectStack, length - 1, &o))
-        return JS_FALSE;
-    JS_ASSERT(JSVAL_IS_OBJECT(o));
-    JSObject *obj = JSVAL_TO_OBJECT(o);
-
-    const jschar *ep;
-    double val;    
-    if (!js_strtod(cx, buf, buf + len, &ep, &val) || ep != buf + len)
-        return JS_FALSE;
-
-    jsval numVal;
-    if (JS_NewNumberValue(cx, val, &numVal))
-        ok = PushValue(cx, jp, obj, numVal);
-    else
-        ok = JS_FALSE; // decode error
-
-    return ok;
-}
-
-static JSBool
-HandleString(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len)
-{
-    jsuint length;
-    if (!JS_GetArrayLength(cx, jp->objectStack, &length))
-        return JS_FALSE;
-
-    jsval o;
-    if (!JS_GetElement(cx, jp->objectStack, length - 1, &o))
-        return JS_FALSE;
-    JS_ASSERT(JSVAL_IS_OBJECT(o));
-    JSObject *obj = JSVAL_TO_OBJECT(o);
-
-    JSString *str = JS_NewUCStringCopyN(cx, buf, len);
-    if (!str)
-        return JS_FALSE;
-
-    return PushValue(cx, jp, obj, STRING_TO_JSVAL(str));
-}
-
-static JSBool
-HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len)
-{
-    jsval keyword;
-    JSTokenType tt = js_CheckKeyword(buf, len);
-    if (tt != TOK_PRIMARY)
-        return JS_FALSE;
-
-    if (buf[0] == 'n')
-        keyword = JSVAL_NULL;
-    else if (buf[0] == 't')
-        keyword = JSVAL_TRUE;
-    else if (buf[0] == 'f')
-        keyword = JSVAL_FALSE;
-    else
-        return JS_FALSE;
-
-    jsuint length;
-    if (!JS_GetArrayLength(cx, jp->objectStack, &length))
-        return JS_FALSE;
-
-    jsval o;
-    if (!JS_GetElement(cx, jp->objectStack, length - 1, &o))
-        return JS_FALSE;
-    JS_ASSERT(JSVAL_IS_OBJECT(o));
-    JSObject *obj = JSVAL_TO_OBJECT(o);
-
-    return PushValue(cx, jp, obj, keyword);
-}
-
-static JSBool
-HandleData(JSContext *cx, JSONParser *jp, JSONDataType type, const jschar *buf, uint32 len)
-{
-  JSBool ok = JS_FALSE;
-
-  switch (type) {
-    case JSON_DATA_STRING:
-      ok = HandleString(cx, jp, buf, len);
-      break;
-
-    case JSON_DATA_KEYSTRING:
-      jp->objectKey = JS_NewUCStringCopyN(cx, buf, len);
-      ok = JS_TRUE;
-      break;
-
-    case JSON_DATA_NUMBER:
-      ok = HandleNumber(cx, jp, buf, len);
-      break;
-
-    case JSON_DATA_KEYWORD:
-      ok = HandleKeyword(cx, jp, buf, len);
-      break;
-
-    default:
-      JS_NOT_REACHED("Should have a JSON data type");
-  }
-
-  js_FinishStringBuffer(jp->buffer);
-  js_InitStringBuffer(jp->buffer);
-
-  return ok;
-}
-
-JSBool
-js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
-{
-    uint32 i;
-
-    if (*jp->statep == JSON_PARSE_STATE_INIT) {
-        PushState(jp, JSON_PARSE_STATE_OBJECT_VALUE);
-    }
-
-    for (i = 0; i < len; i++) {        
-        jschar c = data[i];
-        switch (*jp->statep) {
-            case JSON_PARSE_STATE_VALUE :
-                if (c == ']') {
-                    // empty array
-                    if (!PopState(jp))
-                        return JS_FALSE;
-                    if (*jp->statep != JSON_PARSE_STATE_ARRAY) 
-                        return JS_FALSE; // unexpected char
-                    if (!CloseArray(cx, jp) || !PopState(jp))
-                        return JS_FALSE;
-                    break;
-                }
-
-                if (c == '}') {
-                    // we should only find these in OBJECT_KEY state
-                    return JS_FALSE; // unexpected failure
-                }
-
-                if (c == '"') {
-                    *jp->statep = JSON_PARSE_STATE_STRING;
-                    break;
-                } 
-
-                if (IsNumChar(c)) {
-                    *jp->statep = JSON_PARSE_STATE_NUMBER;
-                    js_AppendChar(jp->buffer, c);
-                    break;
-                }
-
-                if (JS7_ISLET(c)) {
-                    *jp->statep = JSON_PARSE_STATE_KEYWORD;
-                    js_AppendChar(jp->buffer, c);
-                    break;
-                }
-
-            // fall through in case the value is an object or array
-            case JSON_PARSE_STATE_OBJECT_VALUE :
-                if (c == '{') {
-                  *jp->statep = JSON_PARSE_STATE_OBJECT;
-                  if (!OpenObject(cx, jp) || !PushState(jp, JSON_PARSE_STATE_OBJECT_PAIR))
-                      return JS_FALSE;
-                } else if (c == '[') {
-                  *jp->statep = JSON_PARSE_STATE_ARRAY;
-                  if (!OpenArray(cx, jp) || !PushState(jp, JSON_PARSE_STATE_VALUE))
-                      return JS_FALSE;
-                } else if (!JS_ISXMLSPACE(c)) {
-                  return JS_FALSE; // unexpected
-                }
-                break;
-
-            case JSON_PARSE_STATE_OBJECT :
-                if (c == '}') {                    
-                    if (!CloseObject(cx, jp) || !PopState(jp))
-                        return JS_FALSE;
-                } else if (c == ',') {
-                    if (!PushState(jp, JSON_PARSE_STATE_OBJECT_PAIR))
-                        return JS_FALSE;
-                } else if (c == ']' || !JS_ISXMLSPACE(c)) {
-                    return JS_FALSE; // unexpected
-                }
-                break;
-
-            case JSON_PARSE_STATE_ARRAY :
-                if (c == ']') {
-                    if (!CloseArray(cx, jp) || !PopState(jp))
-                        return JS_FALSE;
-                } else if (c == ',') {
-                    if (!PushState(jp, JSON_PARSE_STATE_VALUE))
-                        return JS_FALSE;
-                } else if (!JS_ISXMLSPACE(c)) {
-                    return JS_FALSE; // unexpected
-                }
-                break;
-            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(jp, JSON_PARSE_STATE_STRING))
-                        return JS_FALSE;
-                } else if (c == '}') {
-                    // pop off the object pair state and the object state
-                    if (!CloseObject(cx, jp) || !PopState(jp) || !PopState(jp))
-                        return JS_FALSE;
-                } else if (c == ']' || !JS_ISXMLSPACE(c)) {
-                  return JS_FALSE; // unexpected
-                }
-                break;
-            case JSON_PARSE_STATE_OBJECT_IN_PAIR:
-                if (c == ':') {
-                    *jp->statep = JSON_PARSE_STATE_VALUE;
-                } else if (!JS_ISXMLSPACE(c)) {
-                    return JS_FALSE; // unexpected
-                }
-                break;
-            case JSON_PARSE_STATE_STRING:
-                if (c == '"') {
-                    if (!PopState(jp))
-                        return JS_FALSE;
-                    JSONDataType jdt;
-                    if (*jp->statep == JSON_PARSE_STATE_OBJECT_IN_PAIR) {
-                        jdt = JSON_DATA_KEYSTRING;
-                    } else {
-                        jdt = JSON_DATA_STRING;
-                    }
-                    if (!HandleData(cx, jp, jdt, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
-                        return JS_FALSE;
-                } else if (c == '\\') {
-                    *jp->statep = JSON_PARSE_STATE_STRING_ESCAPE;
-                } else {
-                    js_AppendChar(jp->buffer, c);
-                }
-                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 JS_FALSE; // unexpected
-                        }
-                }
-
-                js_AppendChar(jp->buffer, c);
-                *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 JS_FALSE; // unexpected
-
-                if (++(jp->numHex) == 4) {
-                    js_AppendChar(jp->buffer, jp->hexChar);
-                    jp->hexChar = 0;
-                    jp->numHex = 0;
-                    *jp->statep = JSON_PARSE_STATE_STRING;
-                }
-                break;
-            case JSON_PARSE_STATE_KEYWORD:
-                if (JS7_ISLET(c)) {
-                    js_AppendChar(jp->buffer, c);
-                } else {
-                    // this character isn't part of the keyword, process it again
-                    i--;
-                    if(!PopState(jp))
-                        return JS_FALSE;
-                
-                    if (!HandleData(cx, jp, JSON_DATA_KEYWORD, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
-                        return JS_FALSE;
-                }
-                break;
-            case JSON_PARSE_STATE_NUMBER:
-                if (IsNumChar(c)) {
-                    js_AppendChar(jp->buffer, c);
-                } else {
-                    // this character isn't part of the number, process it again
-                    i--;
-                    if(!PopState(jp))
-                        return JS_FALSE;
-                    if (!HandleData(cx, jp, JSON_DATA_NUMBER, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
-                        return JS_FALSE;
-                }
-                break;
-            case JSON_PARSE_STATE_FINISHED:
-                if (!JS_ISXMLSPACE(c))
-                  return JS_FALSE; // extra input
-
-                break;
-            default:
-                JS_NOT_REACHED("Invalid JSON parser state");
-      }
-    }
-
-    return JS_TRUE;
-}
-
-#if JS_HAS_TOSOURCE
-static JSBool
-json_toSource(JSContext *cx, uintN argc, jsval *vp)
-{
-    *vp = ATOM_KEY(CLASS_ATOM(cx, JSON));
-    return JS_TRUE;
-}
-#endif
-
-static JSFunctionSpec json_static_methods[] = {
-#if JS_HAS_TOSOURCE
-    JS_FN(js_toSource_str,  json_toSource,      0, 0),
-#endif
-    JS_FN("parse",          js_json_parse,      0, 0),
-    JS_FN("stringify",      js_json_stringify,  0, 0),
-    JS_FS_END
-};
-
-JSObject *
-js_InitJSONClass(JSContext *cx, JSObject *obj)
-{
-    JSObject *JSON;
-
-    JSON = JS_NewObject(cx, &js_JSONClass, NULL, obj);
-    if (!JSON)
-        return NULL;
-    if (!JS_DefineProperty(cx, obj, js_JSON_str, OBJECT_TO_JSVAL(JSON),
-                           JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE))
-        return NULL;
-
-    if (!JS_DefineFunctions(cx, JSON, json_static_methods))
-        return NULL;
-
-    return JSON;
-}
deleted file mode 100644
--- a/js/src/json.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is SpiderMonkey JSON.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Robert Sayre <sayrer@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef json_h___
-#define json_h___
-/*
- * JS JSON functions.
- */
-
-#define JSON_MAX_DEPTH  2048
-#define JSON_PARSER_BUFSIZE 1024
-
-JS_BEGIN_EXTERN_C
-
-extern JSClass js_JSONClass;
-
-extern JSObject *
-js_InitJSONClass(JSContext *cx, JSObject *obj);
-
-extern JSBool
-js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
-             JSONWriteCallback callback, void *data, uint32 depth);
-
-extern JSBool js_TryJSON(JSContext *cx, jsval *vp);
-
-enum JSONParserState {
-    JSON_PARSE_STATE_INIT,
-    JSON_PARSE_STATE_OBJECT_VALUE,
-    JSON_PARSE_STATE_VALUE,
-    JSON_PARSE_STATE_OBJECT,
-    JSON_PARSE_STATE_OBJECT_PAIR,
-    JSON_PARSE_STATE_OBJECT_IN_PAIR,
-    JSON_PARSE_STATE_ARRAY,
-    JSON_PARSE_STATE_STRING,
-    JSON_PARSE_STATE_STRING_ESCAPE,
-    JSON_PARSE_STATE_STRING_HEX,
-    JSON_PARSE_STATE_NUMBER,
-    JSON_PARSE_STATE_KEYWORD,
-    JSON_PARSE_STATE_FINISHED
-};
-
-enum JSONDataType {
-    JSON_DATA_STRING,
-    JSON_DATA_KEYSTRING,
-    JSON_DATA_NUMBER,
-    JSON_DATA_KEYWORD
-};
-
-struct JSONParser {
-    /* Used while handling \uNNNN in strings */
-    jschar hexChar;
-    uint8 numHex;
-
-    JSONParserState *statep;
-    JSONParserState stateStack[JSON_MAX_DEPTH];
-    jsval *rootVal;
-    JSString *objectKey;
-    JSStringBuffer *buffer;
-    JSObject *objectStack;
-};
-
-extern JSONParser *
-js_BeginJSONParse(JSContext *cx, jsval *rootVal);
-
-extern JSBool
-js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len);
-
-extern JSBool
-js_FinishJSONParse(JSContext *cx, JSONParser *jp);
-
-JS_END_EXTERN_C
-
-#endif /* json_h___ */
--- a/js/src/jsproto.tbl
+++ b/js/src/jsproto.tbl
@@ -111,17 +111,16 @@ JS_PROTO(URIError,              24,     
 JS_PROTO(Generator,             25,     GENERATOR_INIT)
 JS_PROTO(Iterator,              26,     js_InitIteratorClasses)
 JS_PROTO(StopIteration,         27,     js_InitIteratorClasses)
 JS_PROTO(UnusedProto28,         28,     js_InitNullClass)
 JS_PROTO(File,                  29,     FILE_INIT)
 JS_PROTO(Block,                 30,     js_InitBlockClass)
 JS_PROTO(XMLFilter,             31,     XMLFILTER_INIT)
 JS_PROTO(NoSuchMethod,          32,     NO_SUCH_METHOD_INIT)
-JS_PROTO(JSON,                  33,     js_InitJSONClass)
 
 #undef SCRIPT_INIT
 #undef XML_INIT
 #undef NAMESPACE_INIT
 #undef QNAME_INIT
 #undef ANYNAME_INIT
 #undef ATTRIBUTE_INIT
 #undef GENERATOR_INIT
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -149,17 +149,16 @@ typedef struct JSRuntime         JSRunti
 typedef struct JSRuntime         JSTaskState;   /* XXX deprecated name */
 typedef struct JSScript          JSScript;
 typedef struct JSStackFrame      JSStackFrame;
 typedef struct JSString          JSString;
 typedef struct JSXDRState        JSXDRState;
 typedef struct JSExceptionState  JSExceptionState;
 typedef struct JSLocaleCallbacks JSLocaleCallbacks;
 typedef struct JSSecurityCallbacks JSSecurityCallbacks;
-typedef struct JSONParser        JSONParser;
 
 /* JSClass (and JSObjectOps where appropriate) function pointer typedefs. */
 
 /*
  * Add, delete, get or set a property named by id in obj.  Note the jsval id
  * type -- id may be a string (Unicode property identifier) or an int (element
  * index).  The *vp out parameter, on success, is the new property value after
  * an add, get, or set.  After a successful delete, *vp is JSVAL_FALSE iff