Merge mozilla central and tracemonkey.
authorChris Leary <cdleary@mozilla.com>
Mon, 11 Apr 2011 20:38:35 -0700
changeset 67953 d208845094bfd3bb5b02b3de50752cb9c1a26596
parent 67893 f9c427576ca9ae7eff9f06ab8767197804753c8b (current diff)
parent 67952 7885a2b49faf3adca39187146e5bcac4e9554b49 (diff)
child 67954 3ac2e9681421f3348f482832579dbb66be9fc431
child 67967 7dcd0d16cc08a6781f6487c74d1f46e6b55120da
child 67968 b583111a88aa562215eb4f47668d3f94fc09a8f3
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.2a1pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla central and tracemonkey.
dom/src/json/test/unit/fail1.json
dom/src/json/test/unit/fail10.json
dom/src/json/test/unit/fail11.json
dom/src/json/test/unit/fail12.json
dom/src/json/test/unit/fail13.json
dom/src/json/test/unit/fail14.json
dom/src/json/test/unit/fail15.json
dom/src/json/test/unit/fail16.json
dom/src/json/test/unit/fail17.json
dom/src/json/test/unit/fail18.json
dom/src/json/test/unit/fail19.json
dom/src/json/test/unit/fail2.json
dom/src/json/test/unit/fail20.json
dom/src/json/test/unit/fail21.json
dom/src/json/test/unit/fail22.json
dom/src/json/test/unit/fail23.json
dom/src/json/test/unit/fail24.json
dom/src/json/test/unit/fail25.json
dom/src/json/test/unit/fail26.json
dom/src/json/test/unit/fail27.json
dom/src/json/test/unit/fail28.json
dom/src/json/test/unit/fail29.json
dom/src/json/test/unit/fail3.json
dom/src/json/test/unit/fail30.json
dom/src/json/test/unit/fail31.json
dom/src/json/test/unit/fail32.json
dom/src/json/test/unit/fail33.json
dom/src/json/test/unit/fail34.json
dom/src/json/test/unit/fail4.json
dom/src/json/test/unit/fail5.json
dom/src/json/test/unit/fail6.json
dom/src/json/test/unit/fail7.json
dom/src/json/test/unit/fail8.json
dom/src/json/test/unit/fail9.json
dom/src/json/test/unit/head_json.js
dom/src/json/test/unit/json2.js
dom/src/json/test/unit/pass1.json
dom/src/json/test/unit/pass3.json
dom/src/json/test/unit/test_decode.js
dom/src/json/test/unit/test_decode_primitives.js
dom/src/json/test/unit/test_dropping_elements_in_stringify.js
dom/src/json/test/unit/test_encode_primitives.js
dom/src/json/test/unit/test_encoding_errors.js
dom/src/json/test/unit/test_long_input.js
dom/src/json/test/unit/test_replacer.js
dom/src/json/test/unit/test_reviver.js
dom/src/json/test/unit/test_syntax_errors.js
dom/src/json/test/unit/test_wrappers.js
js/src/jswince.asm
--- a/chrome/src/nsChromeRegistryChrome.cpp
+++ b/chrome/src/nsChromeRegistryChrome.cpp
@@ -886,23 +886,16 @@ nsChromeRegistryChrome::ManifestContent(
     return;
 
   entry->baseURI = resolved;
 
   if (platform)
     entry->flags |= PLATFORM_PACKAGE;
   if (contentaccessible)
     entry->flags |= CONTENT_ACCESSIBLE;
-  if (cx.GetXPConnect()) {
-    nsCAutoString urlp("chrome://");
-    urlp.Append(package);
-    urlp.Append('/');
-
-    cx.GetXPConnect()->FlagSystemFilenamePrefix(urlp.get(), true);
-  }
 }
 
 void
 nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno,
                                        char *const * argv, bool platform,
                                        bool contentaccessible)
 {
   char* package = argv[0];
--- a/config/find_OOM_errors.py
+++ b/config/find_OOM_errors.py
@@ -65,17 +65,17 @@ def run(args, stdin=None):
     sys.exit(-1)
 
   stdout, stderr = stdout_worker.all, stderr_worker.all
   result = (stdout, stderr, proc.returncode)
   return result
 
 def get_js_files():
   (out, err, exit) = run('find ../jit-test/tests -name "*.js"')
-  if (err, exit) == ("", 0):
+  if (err, exit) != ("", 0):
     sys.exit("Wrong directory, run from an objdir")
   return out.split()
 
 
 
 #####################################################################
 # Blacklisting
 #####################################################################
@@ -186,35 +186,35 @@ whitelist.add(r"('', 'out of memory\nout
 
 #####################################################################
 # Program
 #####################################################################
 
 # Options
 parser = OptionParser(usage=usage)
 parser.add_option("-r", "--regression", action="store", metavar="REGRESSION_COUNT", help=help,
-                  type="int", dest="regression", default=0) # TODO: support a value of zero, eventually
+                  type="int", dest="regression", default=None)
                   
 (OPTIONS, args) = parser.parse_args()
 
 
-if OPTIONS.regression:
+if OPTIONS.regression != None:
   # TODO: This should be expanded as we get a better hang of the OOM problems.
   # For now, we'll just check that the number of OOMs in one short file does not
   # increase.
   files = ["../jit-test/tests/arguments/args-createontrace.js"]
 else:
   files = get_js_files()
 
   # Use a command-line arg to reduce the set of files
   if len (args):
     files = [f for f in files if f.find(args[0]) != -1]
 
 
-if OPTIONS.regression:
+if OPTIONS.regression == None:
   # Don't use a logfile, this is automated for tinderbox.
   log = file("../OOM_log", "w")
 
 
 num_failures = 0
 for f in files:
 
   # Run it once to establish boundaries
@@ -224,28 +224,30 @@ for f in files:
   max = int(max)
   
   # OOMs don't recover well for the first 20 allocations or so.
   # TODO: revisit this.
   for i in range(20, max): 
 
     if OPTIONS.regression == None:
       print "Testing allocation %d/%d in %s" % (i,max,f)
+    else:
+      sys.stdout.write('.') # something short for tinderbox, no space or \n
 
     command = (command_template + ' -A %d') % (f, i)
     out, err, exit = run(command)
 
     # Success (5 is SM's exit code for controlled errors)
     if exit == 5 and err.find("out of memory") != -1:
       continue
 
     # Failure
     else:
 
-      if OPTIONS.regression:
+      if OPTIONS.regression != None:
         # Just count them
         num_failures += 1
         continue
 
       #########################################################################
       # The regression tests ends above. The rest of this is for running  the
       # script manually.
       #########################################################################
@@ -309,22 +311,23 @@ for f in files:
 
       log.write ("\n")
 
       log.write ("Valgrind info:\n" + vout)
       log.write ("\n")
       log.write ("\n")
       log.flush()
 
-  if not OPTIONS.regression == None:
+  if OPTIONS.regression == None:
     count_lines()
 
+print '\n',
 
 # Do the actual regression check
-if OPTIONS.regression:
+if OPTIONS.regression != None:
   expected_num_failures = OPTIONS.regression
 
   if num_failures != expected_num_failures:
 
     print "TEST-UNEXPECTED-FAIL |",
     if num_failures > expected_num_failures:
       print "More out-of-memory errors were found (%s) than expected (%d). This probably means an allocation site has been added without a NULL-check. If this is unavoidable, you can account for it by updating Makefile.in." % (num_failures, expected_num_failures),
     else:
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -248,23 +248,21 @@ nsFrameMessageManager::SendSyncMessage()
       JSObject* dataArray = JS_NewArrayObject(ctx, len, NULL);
       NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
 
       for (PRUint32 i = 0; i < len; ++i) {
         if (!retval[i].Length())
           continue;
 
         jsval ret = JSVAL_VOID;
-        JSONParser* parser = JS_BeginJSONParse(ctx, &ret);
-        JSBool ok = JS_ConsumeJSONText(ctx, parser, (jschar*)retval[i].get(),
-                                       (uint32)retval[i].Length());
-        ok = JS_FinishJSONParse(ctx, parser, JSVAL_NULL) && ok;
-        if (ok) {
-          NS_ENSURE_TRUE(JS_SetElement(ctx, dataArray, i, &ret), NS_ERROR_OUT_OF_MEMORY);
+        if (!JS_ParseJSON(ctx, (jschar*)retval[i].get(),
+                          (uint32)retval[i].Length(), &ret)) {
+          return NS_ERROR_UNEXPECTED;
         }
+        NS_ENSURE_TRUE(JS_SetElement(ctx, dataArray, i, &ret), NS_ERROR_OUT_OF_MEMORY);
       }
 
       jsval* retvalPtr;
       ncc->GetRetValPtr(&retvalPtr);
       *retvalPtr = OBJECT_TO_JSVAL(dataArray);
       ncc->SetReturnValueWasSet(PR_TRUE);
     }
   }
@@ -375,25 +373,19 @@ nsFrameMessageManager::ReceiveMessage(ns
           aObjectsArray = JS_NewArrayObject(ctx, 0, NULL);
           if (!aObjectsArray) {
             return NS_ERROR_OUT_OF_MEMORY;
           }
         }
 
         jsval json = JSVAL_NULL;
         if (!aJSON.IsEmpty()) {
-          JSONParser* parser = JS_BeginJSONParse(ctx, &json);
-          if (parser) {
-            JSBool ok = JS_ConsumeJSONText(ctx, parser,
-                                           (jschar*)nsString(aJSON).get(),
-                                           (uint32)aJSON.Length());
-            ok = JS_FinishJSONParse(ctx, parser, JSVAL_NULL) && ok;
-            if (!ok) {
-              json = JSVAL_NULL;
-            }
+          if (!JS_ParseJSON(ctx, (jschar*)nsString(aJSON).get(),
+                            (uint32)aJSON.Length(), &json)) {
+            json = JSVAL_NULL;
           }
         }
         JSString* jsMessage =
           JS_NewUCStringCopyN(ctx,
                               reinterpret_cast<const jschar *>(nsString(aMessage).get()),
                               aMessage.Length());
         NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY);
         JS_DefineProperty(ctx, param, "target", targetv, NULL, NULL, JSPROP_ENUMERATE);
@@ -662,17 +654,16 @@ nsFrameScriptExecutor::LoadFrameScriptIn
       // Need to scope JSAutoRequest to happen after Push but before Pop,
       // at least for now. See bug 584673.
       JSAutoRequest ar(mCx);
       JSObject* global = nsnull;
       mGlobal->GetJSObject(&global);
       if (global) {
         JSPrincipals* jsprin = nsnull;
         mPrincipal->GetJSPrincipals(mCx, &jsprin);
-        nsContentUtils::XPConnect()->FlagSystemFilenamePrefix(url.get(), PR_TRUE);
 
         uint32 oldopts = JS_GetOptions(mCx);
         JS_SetOptions(mCx, oldopts | JSOPTION_NO_SCRIPT_RVAL);
 
         JSObject* scriptObj =
           JS_CompileUCScriptForPrincipals(mCx, nsnull, jsprin,
                                          (jschar*)dataString.get(),
                                           dataString.Length(),
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -309,21 +309,19 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
       }
     } // if there's no document, we don't have to do anything.
 
     rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mExpr = expr;
 
-    nsIPrincipal *prin = aWindow->GetPrincipal();
-
     // Get the calling location.
     const char *filename;
-    if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo, prin)) {
+    if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
       mFileName.Assign(filename);
     }
   } else if (funobj) {
     rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mFunObj = funobj;
 
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -57,53 +57,30 @@
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 
 JSBool
 nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
-                              PRUint32* aLineno, nsIPrincipal* aPrincipal)
+                              PRUint32* aLineno)
 {
   // Get the current filename and line number
   JSStackFrame* frame = nsnull;
   JSScript* script = nsnull;
   do {
     frame = ::JS_FrameIterator(aContext, &frame);
 
     if (frame) {
       script = ::JS_GetFrameScript(aContext, frame);
     }
   } while (frame && !script);
 
   if (script) {
-    // If aPrincipals is non-null then our caller is asking us to ensure
-    // that the filename we return does not have elevated privileges.
-    if (aPrincipal) {
-      uint32 flags = JS_GetScriptFilenameFlags(script);
-
-      // Use the principal for the filename if it shouldn't be receiving
-      // implicit XPCNativeWrappers.
-      PRBool system;
-      if (flags & JSFILENAME_PROTECTED) {
-        nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager();
-
-        if (NS_FAILED(ssm->IsSystemPrincipal(aPrincipal, &system)) || !system) {
-          JSPrincipals* jsprins;
-          aPrincipal->GetJSPrincipals(aContext, &jsprins);
-
-          *aFilename = jsprins->codebase;
-          *aLineno = 0;
-          JSPRINCIPALS_DROP(aContext, jsprins);
-          return JS_TRUE;
-        }
-      }
-    }
-
     const char* filename = ::JS_GetScriptFilename(aContext, script);
 
     if (filename) {
       PRUint32 lineno = 0;
       jsbytecode* bytecode = ::JS_GetFramePC(aContext, frame);
 
       if (bytecode) {
         lineno = ::JS_PCToLineNumber(aContext, script, bytecode);
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -53,17 +53,17 @@ class nsIDOMEventListener;
 class nsIScriptContext;
 class nsIScriptGlobalObject;
 class nsIPrincipal;
 
 class nsJSUtils
 {
 public:
   static JSBool GetCallingLocation(JSContext* aContext, const char* *aFilename,
-                                   PRUint32* aLineno, nsIPrincipal* aPrincipal);
+                                   PRUint32* aLineno);
 
   static nsIScriptGlobalObject *GetStaticScriptGlobal(JSContext* aContext,
                                                       JSObject* aObj);
 
   static nsIScriptContext *GetStaticScriptContext(JSContext* aContext,
                                                   JSObject* aObj);
 
   static nsIScriptGlobalObject *GetDynamicScriptGlobal(JSContext *aContext);
--- a/dom/src/json/nsJSON.cpp
+++ b/dom/src/json/nsJSON.cpp
@@ -419,29 +419,18 @@ nsJSON::DecodeFromStream(nsIInputStream 
   return DecodeInternal(aStream, aContentLength, PR_TRUE);
 }
 
 NS_IMETHODIMP
 nsJSON::DecodeToJSVal(const nsAString &str, JSContext *cx, jsval *result)
 {
   JSAutoRequest ar(cx);
 
-  JSONParser *parser = JS_BeginJSONParse(cx, result);
-  NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
-
-  JSBool ok = JS_ConsumeJSONText(cx, parser,
-                                 (jschar*)PromiseFlatString(str).get(),
-                                 (uint32)str.Length());
-
-  // Since we've called JS_BeginJSONParse, we have to call JS_FinishJSONParse,
-  // even if JS_ConsumeJSONText fails.  But if either fails, we'll report an
-  // error.
-  ok &= JS_FinishJSONParse(cx, parser, JSVAL_NULL);
-
-  if (!ok) {
+  if (!JS_ParseJSON(cx, (jschar*)PromiseFlatString(str).get(),
+                    (uint32)str.Length(), result)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsJSON::DecodeInternal(nsIInputStream *aStream,
@@ -553,30 +542,19 @@ nsJSON::LegacyDecodeFromStream(nsIInputS
   return DecodeInternal(aStream, aContentLength, PR_TRUE, LEGACY);
 }
 
 NS_IMETHODIMP
 nsJSON::LegacyDecodeToJSVal(const nsAString &str, JSContext *cx, jsval *result)
 {
   JSAutoRequest ar(cx);
 
-  JSONParser *parser = JS_BeginJSONParse(cx, result);
-  NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
-
-  JSBool ok = js_ConsumeJSONText(cx, parser,
-                                 (jschar*)PromiseFlatString(str).get(),
-                                 (uint32)str.Length(),
-                                 LEGACY);
-
-  // Since we've called JS_BeginJSONParse, we have to call JS_FinishJSONParse,
-  // even if js_ConsumeJSONText fails.  But if either fails, we'll report an
-  // error.
-  ok &= JS_FinishJSONParse(cx, parser, JSVAL_NULL);
-
-  if (!ok) {
+  if (!js::ParseJSONWithReviver(cx, (jschar*)PromiseFlatString(str).get(),
+                                (uint32)str.Length(), js::NullValue(),
+                                js::Valueify(result), LEGACY)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 nsresult
 NS_NewJSON(nsISupports* aOuter, REFNSIID aIID, void** aResult)
@@ -590,68 +568,63 @@ NS_NewJSON(nsISupports* aOuter, REFNSIID
 
   return NS_OK;
 }
 
 nsJSONListener::nsJSONListener(JSContext *cx, jsval *rootVal,
                                PRBool needsConverter,
                                DecodingMode mode /* = STRICT */)
   : mNeedsConverter(needsConverter), 
-    mJSONParser(nsnull),
     mCx(cx),
     mRootVal(rootVal),
     mDecodingMode(mode)
 {
 }
 
 nsJSONListener::~nsJSONListener()
 {
-  Cleanup();
 }
 
 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)
 {
   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, JSVAL_NULL);
-  mJSONParser = nsnull;
-
-  if (!ok)
-    return NS_ERROR_FAILURE;
-
-  return NS_OK;
+  const jschar* chars = reinterpret_cast<const jschar*>(mBufferedChars.Elements());
+  JSBool ok = js::ParseJSONWithReviver(mCx, chars,
+                                       (uint32) mBufferedChars.Length(),
+                                       js::NullValue(), js::Valueify(mRootVal),
+                                       mDecodingMode);
+  mBufferedChars.TruncateLength(0);
+  return ok ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsJSONListener::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
                                 nsIInputStream *aStream,
                                 PRUint32 aOffset, PRUint32 aLength)
 {
   PRUint32 contentLength;
@@ -738,39 +711,28 @@ nsresult
 nsJSONListener::ConsumeConverted(const char* aBuffer, PRUint32 aByteLength)
 {
   nsresult rv;
   PRInt32 unicharLength = 0;
   PRInt32 srcLen = aByteLength;
 
   rv = mDecoder->GetMaxLength(aBuffer, srcLen, &unicharLength);
   NS_ENSURE_SUCCESS(rv, rv);
-  nsAutoArrayPtr<PRUnichar> ustr(new PRUnichar[unicharLength]);
-  NS_ENSURE_TRUE(ustr, NS_ERROR_OUT_OF_MEMORY);
-  rv = mDecoder->Convert(aBuffer, &srcLen, ustr, &unicharLength);
-  NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = Consume(ustr.get(), unicharLength);
-
-  return rv;
-}
-
-void nsJSONListener::Cleanup()
-{
-  if (mJSONParser)
-    JS_FinishJSONParse(mCx, mJSONParser, JSVAL_NULL);
-  mJSONParser = nsnull;
+  PRUnichar* endelems = mBufferedChars.AppendElements(unicharLength);
+  PRInt32 preLength = unicharLength;
+  rv = mDecoder->Convert(aBuffer, &srcLen, endelems, &unicharLength);
+  if (NS_FAILED(rv))
+    return rv;
+  NS_ABORT_IF_FALSE(preLength >= unicharLength, "GetMaxLength lied");
+  if (preLength > unicharLength)
+    mBufferedChars.TruncateLength(mBufferedChars.Length() - (preLength - unicharLength));
+  return NS_OK;
 }
 
 nsresult
 nsJSONListener::Consume(const PRUnichar* aBuffer, PRUint32 aByteLength)
 {
-  if (!mJSONParser)
+  if (!mBufferedChars.AppendElements(aBuffer, aByteLength))
     return NS_ERROR_FAILURE;
 
-  if (!js_ConsumeJSONText(mCx, mJSONParser, (jschar*) aBuffer, aByteLength,
-                          mDecodingMode)) {
-    Cleanup();
-    return NS_ERROR_FAILURE;
-  }
-
   return NS_OK;
 }
--- a/dom/src/json/nsJSON.h
+++ b/dom/src/json/nsJSON.h
@@ -106,21 +106,20 @@ public:
   virtual ~nsJSONListener();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
 
 protected:
   PRBool mNeedsConverter;
-  JSONParser *mJSONParser;
   JSContext *mCx;
   jsval *mRootVal;
   nsCOMPtr<nsIUnicodeDecoder> mDecoder;
   nsCString mSniffBuffer;
+  nsTArray<PRUnichar> mBufferedChars;
   DecodingMode mDecodingMode;
   nsresult ProcessBytes(const char* aBuffer, PRUint32 aByteLength);
   nsresult ConsumeConverted(const char* aBuffer, PRUint32 aByteLength);
   nsresult Consume(const PRUnichar *data, PRUint32 len);
-  void Cleanup();
 };
 
 #endif
rename from dom/src/json/test/unit/pass3.json
rename to dom/src/json/test/unit/decodeFromStream-01.json
deleted file mode 100644
--- a/dom/src/json/test/unit/fail1.json
+++ /dev/null
@@ -1,1 +0,0 @@
-"Unterminated string literal
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail10.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Extra value after close": true} "misplaced quoted value"
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail11.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Illegal expression": 1 + 2}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail12.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Illegal invocation": alert()}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail13.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Numbers cannot have leading zeroes": 013}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail14.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Numbers cannot be hex": 0x14}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail15.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["Illegal backslash escape: \x15"]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail16.json
+++ /dev/null
@@ -1,1 +0,0 @@
-[\naked]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail17.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["Illegal backslash escape: \017"]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail18.json
+++ /dev/null
@@ -1,1 +0,0 @@
-[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail19.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Missing colon" null}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail2.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["Unclosed array"
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail20.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Double colon":: null}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail21.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Comma instead of colon", null}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail22.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["Colon instead of comma": false]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail23.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["Bad value", truth]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail24.json
+++ /dev/null
@@ -1,1 +0,0 @@
-['single quote']
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail25.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["	tab	character	in	string	"]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail26.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["tab\   character\   in\  string\  "]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail27.json
+++ /dev/null
@@ -1,2 +0,0 @@
-["line
-break"]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail28.json
+++ /dev/null
@@ -1,2 +0,0 @@
-["line\
-break"]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail29.json
+++ /dev/null
@@ -1,1 +0,0 @@
-[0e]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail3.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{unquoted_key: "keys must be quoted"}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail30.json
+++ /dev/null
@@ -1,1 +0,0 @@
-[0e+]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail31.json
+++ /dev/null
@@ -1,1 +0,0 @@
-[0e+-1]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail32.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Comma instead if closing brace": true,
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail33.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["mismatch"}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail34.json
+++ /dev/null
@@ -1,1 +0,0 @@
-0{
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail4.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["extra comma",]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail5.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["double extra comma",,]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail6.json
+++ /dev/null
@@ -1,1 +0,0 @@
-[   , "<-- missing value"]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail7.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["Comma after the close"],
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail8.json
+++ /dev/null
@@ -1,1 +0,0 @@
-["Extra close"]]
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/fail9.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"Extra comma": true,}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/head_json.js
+++ /dev/null
@@ -1,19 +0,0 @@
-var Ci = Components.interfaces;
-var Cc = Components.classes;
-
-var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
-var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
-var workingDir = dirSvc.get("TmpD", Ci.nsIFile);
-
-var outputName = "json-test-output";
-var outputDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
-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;
-load("json2.js");
deleted file mode 100644
--- a/dom/src/json/test/unit/json2.js
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
-    http://www.JSON.org/json2.js
-    2008-11-19
-
-    Public Domain.
-
-    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
-
-    See http://www.JSON.org/js.html
-
-    This file creates a global JSON object containing two methods: stringify
-    and parse.
-
-        JSON.stringify(value, replacer, space)
-            value       any JavaScript value, usually an object or array.
-
-            replacer    an optional parameter that determines how object
-                        values are stringified for objects. It can be a
-                        function or an array of strings.
-
-            space       an optional parameter that specifies the indentation
-                        of nested structures. If it is omitted, the text will
-                        be packed without extra whitespace. If it is a number,
-                        it will specify the number of spaces to indent at each
-                        level. If it is a string (such as '\t' or '&nbsp;'),
-                        it contains the characters used to indent at each level.
-
-            This method produces a JSON text from a JavaScript value.
-
-            When an object value is found, if the object contains a toJSON
-            method, its toJSON method will be called and the result will be
-            stringified. A toJSON method does not serialize: it returns the
-            value represented by the name/value pair that should be serialized,
-            or undefined if nothing should be serialized. The toJSON method
-            will be passed the key associated with the value, and this will be
-            bound to the object holding the key.
-
-            For example, this would serialize Dates as ISO strings.
-
-                Date.prototype.toJSON = function (key) {
-                    function f(n) {
-                        // Format integers to have at least two digits.
-                        return n < 10 ? '0' + n : n;
-                    }
-
-                    return this.getUTCFullYear()   + '-' +
-                         f(this.getUTCMonth() + 1) + '-' +
-                         f(this.getUTCDate())      + 'T' +
-                         f(this.getUTCHours())     + ':' +
-                         f(this.getUTCMinutes())   + ':' +
-                         f(this.getUTCSeconds())   + 'Z';
-                };
-
-            You can provide an optional replacer method. It will be passed the
-            key and value of each member, with this bound to the containing
-            object. The value that is returned from your method will be
-            serialized. If your method returns undefined, then the member will
-            be excluded from the serialization.
-
-            If the replacer parameter is an array of strings, then it will be
-            used to select the members to be serialized. It filters the results
-            such that only members with keys listed in the replacer array are
-            stringified.
-
-            Values that do not have JSON representations, such as undefined or
-            functions, will not be serialized. Such values in objects will be
-            dropped; in arrays they will be replaced with null. You can use
-            a replacer function to replace those with JSON values.
-            JSON.stringify(undefined) returns undefined.
-
-            The optional space parameter produces a stringification of the
-            value that is filled with line breaks and indentation to make it
-            easier to read.
-
-            If the space parameter is a non-empty string, then that string will
-            be used for indentation. If the space parameter is a number, then
-            the indentation will be that many spaces.
-
-            Example:
-
-            text = JSON.stringify(['e', {pluribus: 'unum'}]);
-            // text is '["e",{"pluribus":"unum"}]'
-
-
-            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
-            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
-
-            text = JSON.stringify([new Date()], function (key, value) {
-                return this[key] instanceof Date ?
-                    'Date(' + this[key] + ')' : value;
-            });
-            // text is '["Date(---current time---)"]'
-
-
-        JSON.parse(text, reviver)
-            This method parses a JSON text to produce an object or array.
-            It can throw a SyntaxError exception.
-
-            The optional reviver parameter is a function that can filter and
-            transform the results. It receives each of the keys and values,
-            and its return value is used instead of the original value.
-            If it returns what it received, then the structure is not modified.
-            If it returns undefined then the member is deleted.
-
-            Example:
-
-            // Parse the text. Values that look like ISO date strings will
-            // be converted to Date objects.
-
-            myData = JSON.parse(text, function (key, value) {
-                var a;
-                if (typeof value === 'string') {
-                    a =
-/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
-                    if (a) {
-                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
-                            +a[5], +a[6]));
-                    }
-                }
-                return value;
-            });
-
-            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
-                var d;
-                if (typeof value === 'string' &&
-                        value.slice(0, 5) === 'Date(' &&
-                        value.slice(-1) === ')') {
-                    d = new Date(value.slice(5, -1));
-                    if (d) {
-                        return d;
-                    }
-                }
-                return value;
-            });
-
-
-    This is a reference implementation. You are free to copy, modify, or
-    redistribute.
-
-    This code should be minified before deployment.
-    See http://javascript.crockford.com/jsmin.html
-
-    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
-    NOT CONTROL.
-*/
-
-/*jslint evil: true */
-
-/*global JSON */
-
-/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
-    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
-    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
-    lastIndex, length, parse, prototype, push, replace, slice, stringify,
-    test, toJSON, toString, valueOf
-*/
-
-// Create a JSON object only if one does not already exist. We create the
-// methods in a closure to avoid creating global variables.
-
-if (!this.crockfordJSON) {
-    crockfordJSON = {};
-    crockfordJSON.window = this;
-}
-(function () {
-
-    function f(n) {
-        // Format integers to have at least two digits.
-        return n < 10 ? '0' + n : n;
-    }
-
-    if (typeof Date.prototype.toJSON !== 'function') {
-
-        Date.prototype.toJSON = function (key) {
-
-            return this.getUTCFullYear()   + '-' +
-                 f(this.getUTCMonth() + 1) + '-' +
-                 f(this.getUTCDate())      + 'T' +
-                 f(this.getUTCHours())     + ':' +
-                 f(this.getUTCMinutes())   + ':' +
-                 f(this.getUTCSeconds())   + 'Z';
-        };
-
-        String.prototype.toJSON =
-        Number.prototype.toJSON =
-        Boolean.prototype.toJSON = function (key) {
-            return this.valueOf();
-        };
-    }
-
-    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
-        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
-        gap,
-        indent,
-        meta = {    // table of character substitutions
-            '\b': '\\b',
-            '\t': '\\t',
-            '\n': '\\n',
-            '\f': '\\f',
-            '\r': '\\r',
-            '"' : '\\"',
-            '\\': '\\\\'
-        },
-        rep;
-
-
-    function quote(string) {
-
-// If the string contains no control characters, no quote characters, and no
-// backslash characters, then we can safely slap some quotes around it.
-// Otherwise we must also replace the offending characters with safe escape
-// sequences.
-
-        escapable.lastIndex = 0;
-        return escapable.test(string) ?
-            '"' + string.replace(escapable, function (a) {
-                var c = meta[a];
-                return typeof c === 'string' ? c :
-                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
-            }) + '"' :
-            '"' + string + '"';
-    }
-
-
-    function str(key, holder) {
-
-// Produce a string from holder[key].
-
-        var i,          // The loop counter.
-            k,          // The member key.
-            v,          // The member value.
-            length,
-            mind = gap,
-            partial,
-            value = holder[key];
-
-// If the value has a toJSON method, call it to obtain a replacement value.
-
-        if (value && typeof value === 'object' &&
-                typeof value.toJSON === 'function') {
-            value = value.toJSON(key);
-        }
-
-// If we were called with a replacer function, then call the replacer to
-// obtain a replacement value.
-
-        if (typeof rep === 'function') {
-            value = rep.call(holder, key, value);
-        }
-
-// What happens next depends on the value's type.
-
-        switch (typeof value) {
-        case 'string':
-            return quote(value);
-
-        case 'number':
-
-// JSON numbers must be finite. Encode non-finite numbers as null.
-
-            return isFinite(value) ? String(value) : 'null';
-
-        case 'boolean':
-        case 'null':
-
-// If the value is a boolean or null, convert it to a string. Note:
-// typeof null does not produce 'null'. The case is included here in
-// the remote chance that this gets fixed someday.
-
-            return String(value);
-
-// If the type is 'object', we might be dealing with an object or an array or
-// null.
-
-        case 'object':
-
-// Due to a specification blunder in ECMAScript, typeof null is 'object',
-// so watch out for that case.
-
-            if (!value) {
-                return 'null';
-            }
-
-// Make an array to hold the partial results of stringifying this object value.
-
-            gap += indent;
-            partial = [];
-
-// Is the value an array?
-
-            if (Object.prototype.toString.apply(value) === '[object Array]') {
-
-// The value is an array. Stringify every element. Use null as a placeholder
-// for non-JSON values.
-
-                length = value.length;
-                for (i = 0; i < length; i += 1) {
-                    partial[i] = str(i, value) || 'null';
-                }
-
-// Join all of the elements together, separated with commas, and wrap them in
-// brackets.
-
-                v = partial.length === 0 ? '[]' :
-                    gap ? '[\n' + gap +
-                            partial.join(',\n' + gap) + '\n' +
-                                mind + ']' :
-                          '[' + partial.join(',') + ']';
-                gap = mind;
-                return v;
-            }
-
-// If the replacer is an array, use it to select the members to be stringified.
-
-            if (rep && typeof rep === 'object') {
-                length = rep.length;
-                for (i = 0; i < length; i += 1) {
-                    k = rep[i];
-                    if (typeof k === 'string') {
-                        v = str(k, value);
-                        if (v) {
-                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
-                        }
-                    }
-                }
-            } else {
-
-// Otherwise, iterate through all of the keys in the object.
-
-                for (k in value) {
-                    if (Object.hasOwnProperty.call(value, k)) {
-                        v = str(k, value);
-                        if (v) {
-                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
-                        }
-                    }
-                }
-            }
-
-// Join all of the member texts together, separated with commas,
-// and wrap them in braces.
-
-            v = partial.length === 0 ? '{}' :
-                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
-                        mind + '}' : '{' + partial.join(',') + '}';
-            gap = mind;
-            return v;
-        }
-    }
-
-// If the JSON object does not yet have a stringify method, give it one.
-
-    if (typeof crockfordJSON.stringify !== 'function') {
-        crockfordJSON.stringify = function (value, replacer, space) {
-
-// The stringify method takes a value and an optional replacer, and an optional
-// space parameter, and returns a JSON text. The replacer can be a function
-// that can replace values, or an array of strings that will select the keys.
-// A default replacer method can be provided. Use of the space parameter can
-// produce text that is more easily readable.
-
-            var i;
-            gap = '';
-            indent = '';
-
-// If the space parameter is a number, make an indent string containing that
-// many spaces.
-
-            if (typeof space === 'number') {
-                for (i = 0; i < space; i += 1) {
-                    indent += ' ';
-                }
-
-// If the space parameter is a string, it will be used as the indent string.
-
-            } else if (typeof space === 'string') {
-                indent = space;
-            }
-
-// If there is a replacer, it must be a function or an array.
-// Otherwise, throw an error.
-
-            rep = replacer;
-            if (replacer && typeof replacer !== 'function' &&
-                    (typeof replacer !== 'object' ||
-                     typeof replacer.length !== 'number')) {
-                throw new Error('JSON.stringify');
-            }
-
-// Make a fake root object containing our value under the key of ''.
-// Return the result of stringifying the value.
-
-            return str('', {'': value});
-        };
-    }
-
-
-// If the JSON object does not yet have a parse method, give it one.
-
-    if (typeof crockfordJSON.parse !== 'function') {
-        crockfordJSON.parse = function (text, reviver) {
-
-// The parse method takes a text and an optional reviver function, and returns
-// a JavaScript value if the text is a valid JSON text.
-
-            var j;
-
-            function walk(holder, key) {
-
-// The walk method is used to recursively walk the resulting structure so
-// that modifications can be made.
-
-                var k, v, value = holder[key];
-                if (value && typeof value === 'object') {
-                    for (k in value) {
-                        if (Object.hasOwnProperty.call(value, k)) {
-                            v = walk(value, k);
-                            if (v !== undefined) {
-                                value[k] = v;
-                            } else {
-                                delete value[k];
-                            }
-                        }
-                    }
-                }
-                return reviver.call(holder, key, value);
-            }
-
-
-// Parsing happens in four stages. In the first stage, we replace certain
-// Unicode characters with escape sequences. JavaScript handles many characters
-// incorrectly, either silently deleting them, or treating them as line endings.
-
-            cx.lastIndex = 0;
-            if (cx.test(text)) {
-                text = text.replace(cx, function (a) {
-                    return '\\u' +
-                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
-                });
-            }
-
-// In the second stage, we run the text against regular expressions that look
-// for non-JSON patterns. We are especially concerned with '()' and 'new'
-// because they can cause invocation, and '=' because it can cause mutation.
-// But just to be safe, we want to reject all unexpected forms.
-
-// We split the second stage into 4 regexp operations in order to work around
-// crippling inefficiencies in IE's and Safari's regexp engines. First we
-// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
-// replace all simple value tokens with ']' characters. Third, we delete all
-// open brackets that follow a colon or comma or that begin the text. Finally,
-// we look to see that the remaining characters are only whitespace or ']' or
-// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
-
-            if (/^[\],:{}\s]*$/.
-test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
-replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
-replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-
-// In the third stage we use the eval function to compile the text into a
-// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
-// in JavaScript: it can begin a block or an object literal. We wrap the text
-// in parens to eliminate the ambiguity.
-
-                j = eval('(' + text + ')');
-
-// In the optional fourth stage, we recursively walk the new structure, passing
-// each name/value pair to a reviver function for possible transformation.
-
-                return typeof reviver === 'function' ?
-                    walk({'': j}, '') : j;
-            }
-
-// If the text is not JSON parseable, then a SyntaxError is thrown.
-
-            throw new SyntaxError('JSON.parse');
-        };
-    }
-})();
deleted file mode 100644
--- a/dom/src/json/test/unit/pass1.json
+++ /dev/null
@@ -1,58 +0,0 @@
-[
-    "JSON Test Pattern pass1",
-    {"object with 1 member":["array with 1 element"]},
-    {},
-    [],
-    -42,
-    true,
-    false,
-    null,
-    {
-        "integer": 1234567890,
-        "real": -9876.543210,
-        "e": 0.123456789e-12,
-        "E": 1.234567890E+34,
-        "":  23456789012E66,
-        "zero": 0,
-        "one": 1,
-        "space": " ",
-        "quote": "\"",
-        "backslash": "\\",
-        "controls": "\b\f\n\r\t",
-        "slash": "/ & \/",
-        "alpha": "abcdefghijklmnopqrstuvwyz",
-        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
-        "digit": "0123456789",
-        "0123456789": "digit",
-        "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
-        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
-        "true": true,
-        "false": false,
-        "null": null,
-        "array":[  ],
-        "object":{  },
-        "address": "50 St. James Street",
-        "url": "http://www.JSON.org/",
-        "comment": "// /* <!-- --",
-        "# -- --> */": " ",
-        " s p a c e d " :[1,2 , 3
-
-,
-
-4 , 5        ,          6           ,7        ],"compact":[1,2,3,4,5,6,7],
-        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
-        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
-        "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
-: "A key can be any string"
-    },
-    0.5 ,98.6
-,
-99.44
-,
-
-1066,
-1e1,
-0.1e1,
-1e-1,
-1e00,2e+00,2e-00
-,"rosebud"]
rename from dom/src/json/test/unit/test_decode.js
rename to dom/src/json/test/unit/test_decodeFromStream.js
--- a/dom/src/json/test/unit/test_decode.js
+++ b/dom/src/json/test/unit/test_decodeFromStream.js
@@ -1,196 +1,26 @@
-function decode_strings() {
-  // empty object
-  var x = nativeJSON.decode("{}");
-  do_check_eq(typeof x, "object");
-
-  // empty array
-  x = nativeJSON.decode("[]");
-  do_check_eq(typeof x, "object");
-  do_check_eq(x.length, 0);
-  do_check_eq(x.constructor, Array);
-
-  // one element array
-  x = nativeJSON.decode("[[]]");
-  do_check_eq(typeof x, "object");
-  do_check_eq(x.length, 1);
-  do_check_eq(x.constructor, Array);
-  do_check_eq(x[0].constructor, Array);
+var Ci = Components.interfaces;
+var Cc = Components.classes;
 
-  // multiple arrays
-  x = nativeJSON.decode("[[],[],[]]");
-  do_check_eq(typeof x, "object");
-  do_check_eq(x.length, 3);
-  do_check_eq(x.constructor, Array);
-  do_check_eq(x[0].constructor, Array);
-  do_check_eq(x[1].constructor, Array);
-  do_check_eq(x[2].constructor, Array);
-
-  // array key/value
-  x = nativeJSON.decode('{"foo":[]}');
-  do_check_eq(typeof x, "object");
-  do_check_eq(typeof x.foo, "object");
-  do_check_eq(x.foo.constructor, Array);
-  x = nativeJSON.decode('{"foo":[], "bar":[]}');
-  do_check_eq(typeof x, "object");
-  do_check_eq(typeof x.foo, "object");
-  do_check_eq(x.foo.constructor, Array);
-  do_check_eq(typeof x.bar, "object");
-  do_check_eq(x.bar.constructor, Array);
+var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
 
-  // nesting
-  x = nativeJSON.decode('{"foo":[{}]}');
-  do_check_eq(x.foo.constructor, Array);
-  do_check_eq(x.foo.length, 1);
-  do_check_eq(typeof x.foo[0], "object");
-  x = nativeJSON.decode('{"foo":[{"foo":[{"foo":{}}]}]}');
-  do_check_eq(x.foo[0].foo[0].foo.constructor, Object);
-  x = nativeJSON.decode('{"foo":[{"foo":[{"foo":[]}]}]}');
-  do_check_eq(x.foo[0].foo[0].foo.constructor, Array);
-
-  // strings
-  x = nativeJSON.decode('{"foo":"bar"}');
-  do_check_eq(x.foo, "bar");
-  x = nativeJSON.decode('["foo", "bar", "baz"]');
-  do_check_eq(x[0], "foo");
-  do_check_eq(x[1], "bar");
-  do_check_eq(x[2], "baz");
-
-  // numbers
-  x = nativeJSON.decode('{"foo":5.5, "bar":5}');
-  do_check_eq(x.foo, 5.5);
-  do_check_eq(x.bar, 5);
-  
-  // keywords
-  x = nativeJSON.decode('{"foo": true, "bar":false, "baz":null}');
-  do_check_eq(x.foo, true);
-  do_check_eq(x.bar, false);
-  do_check_eq(x.baz, null);
-  
-  // short escapes
-  x = nativeJSON.decode('{"foo": "\\"", "bar":"\\\\", "baz":"\\b","qux":"\\f", "quux":"\\n", "quuux":"\\r","quuuux":"\\t"}');
-  do_check_eq(x.foo, '"');
-  do_check_eq(x.bar, '\\');
-  do_check_eq(x.baz, '\b');
-  do_check_eq(x.qux, '\f');
-  do_check_eq(x.quux, "\n");
-  do_check_eq(x.quuux, "\r");
-  do_check_eq(x.quuuux, "\t");
-
-  // unicode escape
-  x = nativeJSON.decode('{"foo":"hmm\\u006dmm"}');
-  do_check_eq("hmm\u006dmm", x.foo);
-
-  x = nativeJSON.decode('{"JSON Test Pattern pass3": {"The outermost value": "must be an object or array.","In this test": "It is an object." }}');
-}
-
-function test_files() {
-  function read_file(path) {
-    try {
+function run_test()
+{
+  function read_file(path)
+  {
+    try
+    {
       var f = do_get_file(path);
       var istream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
       istream.init(f, -1, -1, false);
-      var x = nativeJSON.decodeFromStream(istream, istream.available());
-    } finally {
+      return nativeJSON.decodeFromStream(istream, istream.available());
+    }
+    finally
+    {
       istream.close();
     }
-    return x;
   }
 
-  var x = read_file("pass3.json");
+  var x = read_file("decodeFromStream-01.json");
   do_check_eq(x["JSON Test Pattern pass3"]["The outermost value"], "must be an object or array.");
   do_check_eq(x["JSON Test Pattern pass3"]["In this test"], "It is an object.");
-
-  x = read_file("pass1.json");
-  do_check_eq(x[0], "JSON Test Pattern pass1");
-  do_check_eq(x[1]["object with 1 member"][0], "array with 1 element");
-  do_check_eq(x[2].constructor, Object);
-  do_check_eq(x[3].constructor, Array);
-  do_check_eq(x[4], -42);
-  do_check_eq(x[5], true);
-  do_check_eq(x[6], false);
-  do_check_eq(x[7], null);
-  do_check_eq(x[8].constructor, Object);
-  do_check_eq(x[8]["integer"], 1234567890);
-  do_check_eq(x[8]["real"], -9876.543210);
-  do_check_eq(x[8]["e"], 0.123456789e-12);
-  do_check_eq(x[8]["E"], 1.234567890E+34);
-  do_check_eq(x[8][""], 23456789012E66);
-  do_check_eq(x[8]["zero"], 0);
-  do_check_eq(x[8]["one"], 1);
-  do_check_eq(x[8]["space"], " ");
-  do_check_eq(x[8]["quote"], "\"");
-  do_check_eq(x[8]["backslash"], "\\");
-  do_check_eq(x[8]["controls"], "\b\f\n\r\t");
-  do_check_eq(x[8]["slash"], "/ & /");
-  do_check_eq(x[8]["alpha"], "abcdefghijklmnopqrstuvwyz");
-  do_check_eq(x[8]["ALPHA"], "ABCDEFGHIJKLMNOPQRSTUVWYZ");
-  do_check_eq(x[8]["digit"], "0123456789");
-  do_check_eq(x[8]["0123456789"], "digit");
-  do_check_eq(x[8]["special"], "`1~!@#$%^&*()_+-={':[,]}|;.</>?");
-  do_check_eq(x[8]["hex"], "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A");
-  do_check_eq(x[8]["true"], true);
-  do_check_eq(x[8]["false"], false);
-  do_check_eq(x[8]["null"], null);
-  do_check_eq(x[8]["array"].length, 0);
-  do_check_eq(x[8]["object"].constructor, Object);
-  do_check_eq(x[8]["address"], "50 St. James Street");
-  do_check_eq(x[8]["url"], "http://www.JSON.org/");
-  do_check_eq(x[8]["comment"], "// /* <!-- --");
-  do_check_eq(x[8]["# -- --> */"], " ");
-  do_check_eq(x[8][" s p a c e d "].length, 7);
-  do_check_eq(x[8]["compact"].length, 7);
-  do_check_eq(x[8]["jsontext"], "{\"object with 1 member\":[\"array with 1 element\"]}");
-  do_check_eq(x[8]["quotes"], "&#34; \u0022 %22 0x22 034 &#x22;");
-  do_check_eq(x[8]["\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"], "A key can be any string");
-  do_check_eq(x[9], 0.5);
-  do_check_eq(x[10], 98.6);
-  do_check_eq(x[11], 99.44);
-  do_check_eq(x[12], 1066);
-  do_check_eq(x[13], 1e1);
-  do_check_eq(x[14], 0.1e1);
-  do_check_eq(x[15], 1e-1);
-  do_check_eq(x[16], 1e00);
-  do_check_eq(x[17], 2e+00);
-  do_check_eq(x[18], 2e-00);
-  do_check_eq(x[19], "rosebud");
-  
-  // test invalid input
-  //
-  // We allow some minor JSON infractions, like trailing commas
-  // Those are special-cased below, leaving the original sequence
-  // of failure's from Crockford intact.
-  //
-  // Section 4 of RFC 4627 allows this tolerance.
-  //
-  for (var i = 1; i <= 34; ++i) {
-    var path = "fail" + i + ".json";
-    try {
-      dump(path +"\n");
-      x = read_file(path);
-      if (i == 13) {
-        // {"Numbers cannot have leading zeroes": 013}
-        do_check_eq(x["Numbers cannot have leading zeroes"], 13);
-      } else if (i == 18) {
-        // [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
-        var t = x[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0];
-        do_check_eq(t, "Too deep");
-      } else {
-
-        do_throw("UNREACHED");
-
-      }
-
-    } catch (ex) {
-      // expected from parsing invalid JSON
-      if (i == 13 || i == 18) {
-        do_throw("Unexpected pass in " + path);
-      }
-    }
-  }
-  
 }
-
-function run_test() {
-  decode_strings();
-  test_files();
-}
rename from dom/src/json/test/unit/test_long_input.js
rename to dom/src/json/test/unit/test_decode_long_input.js
--- a/dom/src/json/test/unit/test_long_input.js
+++ b/dom/src/json/test/unit/test_decode_long_input.js
@@ -1,9 +1,13 @@
 // This tests breaking long input across parser buffers
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
 
 var x = {"Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
 "2Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
 "3Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
 "6Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
 "7Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
 "8Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
 "9Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
@@ -16,13 +20,13 @@ var x = {"Lorem ipsum his ponderum delic
 "16Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
 "17Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix.":"Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.",
 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz":"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
 }
 
 var y = nativeJSON.encode(x);
 var z = nativeJSON.decode(y);
 
-function run_test() {
-  for (var i in x) {
-   do_check_eq(x[i], z[i]);
-  }
+function run_test()
+{
+  for (var i in x)
+    do_check_eq(x[i], z[i]);
 }
deleted file mode 100644
--- a/dom/src/json/test/unit/test_decode_primitives.js
+++ /dev/null
@@ -1,88 +0,0 @@
-function parse_primitives() {
-
-  print("parse object");
-  // check an empty object, just for sanity
-  var emptyObject = "{}";
-  var x = nativeJSON.decode(emptyObject);
-  do_check_eq(typeof x, "object");
-  print("parse object 2");
-  
-  x = JSON.parse(emptyObject);
-  do_check_eq(typeof x, "object");
-  
-  print("parse object 3");
-  x = crockfordJSON.parse(emptyObject);
-  do_check_eq(typeof x, "object");
-
-  // booleans and null
-  print("parse bool");
-  x = JSON.parse("true");
-  do_check_eq(typeof x, "boolean");
-  do_check_eq(x, true);
-  
-  print("parse bool with space")
-  x = JSON.parse("true          ");
-  do_check_eq(typeof x, "boolean");
-  do_check_eq(x, true);
-  
-  print("parse false");
-  x = JSON.parse("false");
-  do_check_eq(typeof x, "boolean");
-  do_check_eq(x, false);
-  
-  print("parse null");
-  x = JSON.parse("           null           ");
-  do_check_eq(typeof x, "object");
-  do_check_eq(x, null);
-  
-  // numbers
-  print("parse numbers")
-  x = JSON.parse("1234567890");
-  do_check_eq(typeof x, "number");
-  do_check_eq(x, 1234567890);
-  
-  x = JSON.parse("-9876.543210");
-  do_check_eq(typeof x, "number");
-  do_check_eq(x, -9876.543210);
-  
-  x = JSON.parse("0.123456789e-12");
-  do_check_eq(typeof x, "number");
-  do_check_eq(x, 0.123456789e-12);
-  
-  x = JSON.parse("1.234567890E+34");
-  do_check_eq(typeof x, "number");
-  do_check_eq(x, 1.234567890E+34);
-
-  x = JSON.parse("      23456789012E66          \r\r\r\r      \n\n\n\n ");
-  do_check_eq(typeof x, "number");
-  do_check_eq(x, 23456789012E66);
- 
-  // strings
-  x = crockfordJSON.parse('"foo"');
-  do_check_eq(typeof x, "string");
-  do_check_eq(x, "foo");
-  x = JSON.parse('"foo"');
-  do_check_eq(typeof x, "string");
-  do_check_eq(x, "foo");
-  
-  x = JSON.parse('"\\r\\n"');
-  do_check_eq(typeof x, "string");
-  do_check_eq(x, "\r\n");
-  
-  x = JSON.parse('"\\uabcd\uef4A"');
-  do_check_eq(typeof x, "string");
-  do_check_eq(x, "\uabcd\uef4A");
-
-  x = JSON.parse('"\\uabcd"');
-  do_check_eq(typeof x, "string");
-  do_check_eq(x, "\uabcd");
-
-  x = JSON.parse('"\\f"');
-  do_check_eq(typeof x, "string");
-  do_check_eq(x, "\f");
-
-}
-
-function run_test() {
-  parse_primitives();
-}
deleted file mode 100644
--- a/dom/src/json/test/unit/test_dropping_elements_in_stringify.js
+++ /dev/null
@@ -1,11 +0,0 @@
-var w = {foo: 123};
-var x = {foo: 123, bar: function () {}};
-var y = {foo: 123, bar: function () {}, baz: 123};
-var z = {foo: 123, bar: <x><y></y></x>, baz: 123};
-
-function run_test() {
-  do_check_eq('{"foo":123}', JSON.stringify(w));
-  do_check_eq('{"foo":123}', JSON.stringify(x));
-  do_check_eq('{"foo":123,"baz":123}', JSON.stringify(y));
-  do_check_eq('{"foo":123,"baz":123}', JSON.stringify(z));
-}
--- a/dom/src/json/test/unit/test_encode.js
+++ b/dom/src/json/test/unit/test_encode.js
@@ -1,116 +1,41 @@
+var Ci = Components.interfaces;
+var Cc = Components.classes;
 
-// returns a list of [string, object] pairs to test encoding
-function getTestPairs() {
-  var testPairs = [
-    ["{}", {}],
-    ["[]", []],
-    ['{"foo":"bar"}', {"foo":"bar"}],
-    ['{"null":null}', {"null":null}],
-    ['{"five":5}', {"five":5}],
-    ['{"five":5,"six":6}', {"five":5, "six":6}],
-    ['{"x":{"y":"z"}}', {"x":{"y":"z"}}],
-    ['{"w":{"x":{"y":"z"}}}', {"w":{"x":{"y":"z"}}}],
-    ['[1,2,3]', [1,2,3]],
-    ['{"w":{"x":{"y":[1,2,3]}}}', {"w":{"x":{"y":[1,2,3]}}}],
-    ['{"false":false}', {"false":false}],
-    ['{"true":true}', {"true":true}],
-    ['{"child has two members":{"this":"one","2":"and this one"}}',
-     {"child has two members": {"this":"one", 2:"and this one"}}],
-    ['{"x":{"a":"b","c":{"y":"z"},"f":"g"}}',
-     {"x":{"a":"b","c":{"y":"z"},"f":"g"}}],
-    ['{"x":[1,{"y":"z"},3]}', {"x":[1,{"y":"z"},3]}],
-    ['["hmm"]', [new String("hmm")]],
-    ['[true]', [new Boolean(true)]],
-    ['[42]', [new Number(42)]],
-    ['["1978-09-13T12:24:34.023Z"]', [new Date(Date.UTC(1978, 8, 13, 12, 24, 34, 23))]],
-    ['[1,null,3]',[1,,3]],
-    [null, function test(){}],
-    [null, dump],
-    ['{"mm\\\"mm":"hmm"}',{"mm\"mm":"hmm"}],
-    ['{"mm\\\"mm\\\"mm":"hmm"}',{"mm\"mm\"mm":"hmm"}],
-    ['{"\\\"":"hmm"}',{'"':"hmm"}],
-    ['{"\\\\":"hmm"}',{'\\':"hmm"}],
-    ['{"mmm\\\\mmm":"hmm"}',{'mmm\\mmm':"hmm"}],
-    ['{"mmm\\\\mmm\\\\mmm":"hmm"}',{'mmm\\mmm\\mmm':"hmm"}],
-    ['{"mm\\u000bmm":"hmm"}',{"mm\u000bmm":"hmm"}],
-    ['{"mm\\u0000mm":"hmm"}',{"mm\u0000mm":"hmm"}]
-  ];
+var nativeJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
 
-  var x = {"free":"variable"}
-  testPairs.push(['{"free":"variable"}', x]);
-  testPairs.push(['{"y":{"free":"variable"}}', {"y":x}]);
-
-  // array prop
-  var x = {
-    a: [1,2,3]
-  }
-  testPairs.push(['{"a":[1,2,3]}', x])
+var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
+var workingDir = dirSvc.get("TmpD", Ci.nsIFile);
 
-  var y = {
-    foo: function(hmm) { return hmm; }
-  }
-  testPairs.push(['{"y":{}}',{"y":y}]);
-
-  // test toJSON
-  var hmm = {
-    toJSON: function() { return {"foo":"bar"}}
-  }
-  testPairs.push(['{"hmm":{"foo":"bar"}}', {"hmm":hmm}]);
-  testPairs.push(['{"foo":"bar"}', hmm]); // on the root
-
-  // toJSON on prototype
-  var Y = function() {
-    this.d = "e";
-  }
-  Y.prototype = {
-    not:"there?",
-    toJSON: function() { return {"foo":"bar"}}
-  };
-  var y = new Y();
-  testPairs.push(['{"foo":"bar"}', y.toJSON()]);
-  testPairs.push(['{"foo":"bar"}', y]);
+var outputName = "json-test-output";
+var outputDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+outputDir.initWithFile(workingDir);
+outputDir.append(outputName);
 
-  // return undefined from toJSON
-  var hmm = {
-    toJSON: function() { return; }
-  }
-  testPairs.push(['{}', {"hmm":hmm}]);
-
-  // array with named prop
-  var x= new Array();
-  x[0] = 1;
-  x.foo = "bar";
-  //testPairs.push(['[1]', x]);
-
-  // prototype
-  var X = function() { this.foo = "b" }
-  X.prototype = {c:"d"}
-  var y = new X();
-  testPairs.push(['{"foo":"b"}', y]);
-
-  // useless roots will be dropped
-  testPairs.push([null, null]);
-  testPairs.push([null, ""]);
-  testPairs.push([null, undefined]);
-  testPairs.push([null, 5]);
-
-  return testPairs;
+if (!outputDir.exists()) {
+  outputDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
+} else if (!outputDir.isDirectory()) {
+  do_throw(outputName + " is not a directory?")
 }
 
-function testStringEncode() {
-  // test empty arg
-  do_check_eq(null, nativeJSON.encode());
+function testStringEncode()
+{
+  do_check_eq(nativeJSON.encode(), null);
 
-  var pairs = getTestPairs();
-  for each(pair in pairs) {
-    var nativeResult = nativeJSON.encode(pair[1]);
-    do_check_eq(pair[0], nativeResult);
-  }
+  // useless roots are dropped
+  do_check_eq(nativeJSON.encode(null), null);
+  do_check_eq(nativeJSON.encode(""), null);
+  do_check_eq(nativeJSON.encode(undefined), null);
+  do_check_eq(nativeJSON.encode(5), null);
+  do_check_eq(nativeJSON.encode(function(){}), null);
+  do_check_eq(nativeJSON.encode(dump), null);
+
+  // All other testing should occur in js/src/tests/ecma_5/JSON/ using
+  // the otherwise-exactly-identical JSON.stringify.
 }
 
 function testOutputStreams() {
   function writeToFile(obj, charset, writeBOM) {
     var jsonFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
     jsonFile.initWithFile(outputDir);
     jsonFile.append("test.json");
     jsonFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
@@ -119,18 +44,31 @@ function testOutputStreams() {
       stream.init(jsonFile, 0x04 | 0x08 | 0x20, 0600, 0); // write, create, truncate
       nativeJSON.encodeToStream(stream, charset, writeBOM, obj);
     } finally {
       stream.close();
     }
     return jsonFile;
   }
 
-  var pairs = getTestPairs();
-  for each(pair in pairs) {
+  var pairs = [
+    ["{}", {}],
+    ['{"foo":"bar"}', {"foo":"bar"}],
+    ['{"null":null}', {"null":null}],
+    ['{"five":5}', {"five":5}],
+    ['{"true":true}', {"true":true}],
+    ['{"x":{"y":"z"}}', {"x":{"y":"z"}}],
+    ['{"w":{"x":{"y":"z"}}}', {"w":{"x":{"y":"z"}}}],
+    ["[]", []],
+    ['[1,2,3]', [1,2,3]],
+    ['[1,null,3]',[1,,3]],
+  ];
+  for (var i = 0; i < pairs.length; i++)
+  {
+    var pair = pairs[i];
     if (pair[1] && (typeof pair[1] == "object")) {
       var utf8File = writeToFile(pair[1], "UTF-8", false);
       var utf16LEFile = writeToFile(pair[1], "UTF-16LE", false);
       var utf16BEFile = writeToFile(pair[1], "UTF-16BE", false);
 
       // all ascii with no BOMs, so this will work
       do_check_eq(utf16LEFile.fileSize / 2, utf8File.fileSize);
       do_check_eq(utf16LEFile.fileSize, utf16BEFile.fileSize);
@@ -152,18 +90,22 @@ function testOutputStreams() {
 function throwingToJSON() {
   var a = {
     "b": 1,
     "c": 2,
     toJSON: function() { throw("uh oh"); }
   }
   try {
     var y = nativeJSON.encode(a);
-  } catch (ex) {}
+    throw "didn't throw";
+  } catch (ex) {
+    do_check_eq(ex, "uh oh");
+  }
 }
 
-function run_test() {
+function run_test()
+{
   testStringEncode();
   throwingToJSON();
   
   testOutputStreams();
   
 }
deleted file mode 100644
--- a/dom/src/json/test/unit/test_encode_primitives.js
+++ /dev/null
@@ -1,34 +0,0 @@
-function stringify_primitives() {
-  // sanity
-  var x = JSON.stringify({});
-  do_check_eq(x, "{}");
-
-  // booleans and null
-  x = JSON.stringify(true);
-  do_check_eq(x, "true");
-
-  x = JSON.stringify(false);
-  do_check_eq(x, "false");
-
-  x = JSON.stringify(new Boolean(false));
-  do_check_eq(x, "false");
-
-  x = JSON.stringify(null);
-  do_check_eq(x, "null");
-
-  x = JSON.stringify(1234);
-  do_check_eq(x, "1234");
-
-  x = JSON.stringify(new Number(1234));
-  do_check_eq(x, "1234");
-
-  x = JSON.stringify("asdf");
-  do_check_eq(x, '"asdf"');
-
-  x = JSON.stringify(new String("asdf"));
-  do_check_eq(x, '"asdf"');
-}
-
-function run_test() {
-  stringify_primitives();
-}
deleted file mode 100644
--- a/dom/src/json/test/unit/test_encoding_errors.js
+++ /dev/null
@@ -1,27 +0,0 @@
-function tooDeep() {
-  var arr = [];
-  var root = [arr];
-  var tail;
-  for (var i = 0; i < 5000; i++) {
-    tail = [];
-    arr.push(tail);
-    arr = tail;
-  }
-  JSON.stringify(root);
-}
-
-function run_test() {
-  do_check_eq(undefined, JSON.stringify(undefined));
-  do_check_eq(undefined, JSON.stringify(function(){}));
-  do_check_eq(undefined, JSON.stringify(<x><y></y></x>));
-
-  var ok = false;
-  try {
-    tooDeep();
-  } catch (e) {
-    do_check_true(e instanceof Error);
-    ok = true;
-  }
-  do_check_true(ok);
-}
-
deleted file mode 100644
--- a/dom/src/json/test/unit/test_replacer.js
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * These return* functions are used by the
- * replacer tests taken from bug 512447
- */
-function returnObjectFor1(k, v) {
-    if (k == "1")
-        return {};
-    return v;
-}
-function returnArrayFor1(k, v) {
-    if (k == "1")
-        return [];
-    return v;
-}
-function returnNullFor1(k, v) {
-    if (k == "1")
-        return null;
-    return v;
-}
-function returnStringForUndefined(k, v) {
-    if (v === undefined)
-        return "undefined value";
-    return v;
-}
-function returnCycleObjectFor1(k, v) {
-    if (k == "1")
-        return object;
-    return v;
-}
-function returnCycleArrayFor1(k, v) {
-    if (k == "1")
-        return array;
-    return v;
-}
-
-function run_test() {
-  var x = JSON.stringify({key:2},function(k,v){return k?undefined:v;})
-  do_check_eq("{}", x);
-  
-  var x = JSON.stringify(["hmm", "hmm"],function(k,v){return k!==""?undefined:v;})
-  do_check_eq("[null,null]", x);
-  
-  var foo = ["hmm"];
-  function censor(k, v) {
-    if (v !== foo)
-      return "XXX";
-    return v;
-  }
-  var x = JSON.stringify(foo, censor);
-  do_check_eq(x, '["XXX"]');
-
-  foo = ["bar", ["baz"], "qux"];
-  var x = JSON.stringify(foo, censor);
-  do_check_eq(x, '["XXX","XXX","XXX"]');
-
-  function censor2(k, v) {
-    if (typeof(v) == "string")
-      return "XXX";
-    return v;
-  }
-
-  foo = ["bar", ["baz"], "qux"];
-  var x = JSON.stringify(foo, censor2);
-  do_check_eq(x, '["XXX",["XXX"],"XXX"]');
-
-  foo = {bar: 42, qux: 42, quux: 42};
-  var x = JSON.stringify(foo, ["bar"]);
-  do_check_eq(x, '{"bar":42}');
-
-  foo = {bar: {bar: 42, schmoo:[]}, qux: 42, quux: 42};
-  var x = JSON.stringify(foo, ["bar", "schmoo"]);
-  do_check_eq(x, '{"bar":{"bar":42,"schmoo":[]}}');
-
-  var x = JSON.stringify(foo, null, "");
-  do_check_eq(x, '{"bar":{"bar":42,"schmoo":[]},"qux":42,"quux":42}');
-
-  var x = JSON.stringify(foo, null, "  ");
-  do_check_eq(x, '{\n  "bar": {\n    "bar": 42,\n    "schmoo": []\n  },\n  "qux": 42,\n  "quux": 42\n}');
-
-  foo = {bar:{bar:{}}}
-  var x = JSON.stringify(foo, null, "  ");
-  do_check_eq(x, '{\n  "bar": {\n    "bar": {}\n  }\n}');
-  
-  var x = JSON.stringify({x:1,arr:[1]}, function (k,v) { return typeof v === 'number' ? 3 : v; });
-  do_check_eq(x, '{"x":3,"arr":[3]}');
-
-  foo = ['e'];
-  var x = JSON.stringify(foo, null, '\t');
-  do_check_eq(x, '[\n\t"e"\n]');
-
-  foo = {0:0, 1:1, 2:2, 3:undefined};
-  var x = JSON.stringify(foo, returnObjectFor1);
-  do_check_eq(x, '{"0":0,"1":{},"2":2}');
-
-  var x = JSON.stringify(foo, returnArrayFor1);
-  do_check_eq(x, '{"0":0,"1":[],"2":2}');
-
-  var x = JSON.stringify(foo, returnNullFor1);
-  do_check_eq(x, '{"0":0,"1":null,"2":2}');
-
-  var x = JSON.stringify(foo, returnStringForUndefined);
-  do_check_eq(x, '{"0":0,"1":1,"2":2,"3":"undefined value"}');
-
-  var thrown = false;
-  try {
-    var x = JSON.stringify(foo, returnCycleObjectFor1);
-  } catch (e) {
-    thrown = true;
-  }
-  do_check_eq(thrown, true);
-
-  var thrown = false;
-  try {
-    var x = JSON.stringify(foo, returnCycleArrayFor1);
-  } catch (e) {
-    thrown = true;
-  }
-  do_check_eq(thrown, true);
-
-  var thrown = false;
-  foo = [0, 1, 2, undefined];
-  try {
-    var x = JSON.stringify(foo, returnCycleObjectFor1);
-  } catch (e) {
-    thrown = true;
-  }
-  do_check_eq(thrown, true);
-}
-
deleted file mode 100644
--- a/dom/src/json/test/unit/test_reviver.js
+++ /dev/null
@@ -1,36 +0,0 @@
-function doubler(k, v) {
-  do_check_true("string" == typeof k);
-
-  if ((typeof v) == "number")
-    return 2 * v;
-
-  return v;
-}
-
-function run_test() {
-  var x = JSON.parse('{"a":5,"b":6}', doubler);
-  do_check_true(x.hasOwnProperty('a'));
-  do_check_true(x.hasOwnProperty('b'));
-  do_check_eq(x.a, 10);
-  do_check_eq(x.b, 12);
-
-  x = JSON.parse('[3, 4, 5]', doubler);
-  do_check_eq(x[0], 6);
-  do_check_eq(x[1], 8);
-  do_check_eq(x[2], 10);
-
-  // make sure reviver isn't called after a failed parse
-  var called = false;
-  function dontCallMe(k, v) {
-    called = true;
-  }
-
-  try {
-    x = JSON.parse('{{{{{{{}}}}', dontCallMe);
-  } catch (e) {
-    if (! (e instanceof SyntaxError))
-      throw("wrong exception");
-  }
-
-  do_check_false(called);
-}
deleted file mode 100644
--- a/dom/src/json/test/unit/test_syntax_errors.js
+++ /dev/null
@@ -1,28 +0,0 @@
-function checkForSyntaxErrors(s) {
-  var crockfordErrored = false;
-  try {
-    crockfordJSON.parse(s)
-  } catch (e) {
-    var crockfordErrored = true;
-    do_check_true(e instanceof crockfordJSON.window.SyntaxError);
-  }
-  do_check_true(crockfordErrored);
-  
-  var JSONErrored = false;
-  try {
-    JSON.parse(s)
-  } catch (e) {
-    var JSONErrored = true;
-    do_check_true(e instanceof SyntaxError);
-  }
-  do_check_true(JSONErrored);
-}
-
-function run_test() {
-  checkForSyntaxErrors("{}...");
-  checkForSyntaxErrors('{"foo": truBBBB}');
-  checkForSyntaxErrors('{foo: truBBBB}');
-  checkForSyntaxErrors('{"foo": undefined}');
-  checkForSyntaxErrors('{"foo": ]');
-  checkForSyntaxErrors('{"foo');
-}
\ No newline at end of file
deleted file mode 100644
--- a/dom/src/json/test/unit/test_wrappers.js
+++ /dev/null
@@ -1,190 +0,0 @@
-
-// returns a list of [string, object] pairs to test encoding
-function getTestPairs() {
-  var testPairs = [
-    ["{}", {}],
-    ["[]", []],
-    ['{"foo":"bar"}', {"foo":"bar"}],
-    ['{"null":null}', {"null":null}],
-    ['{"five":5}', {"five":5}],
-    ['{"five":5,"six":6}', {"five":5, "six":6}],
-    ['{"x":{"y":"z"}}', {"x":{"y":"z"}}],
-    ['{"w":{"x":{"y":"z"}}}', {"w":{"x":{"y":"z"}}}],
-    ['[1,2,3]', [1,2,3]],
-    ['{"w":{"x":{"y":[1,2,3]}}}', {"w":{"x":{"y":[1,2,3]}}}],
-    ['{"false":false}', {"false":false}],
-    ['{"true":true}', {"true":true}],
-    ['{"child has two members":{"this":"one","2":"and this one"}}',
-     {"child has two members": {"this":"one", 2:"and this one"}}],
-    ['{"x":{"a":"b","c":{"y":"z"},"f":"g"}}',
-     {"x":{"a":"b","c":{"y":"z"},"f":"g"}}],
-    ['{"x":[1,{"y":"z"},3]}', {"x":[1,{"y":"z"},3]}],
-    ['["hmm"]', [new String("hmm")]],
-    ['[true]', [new Boolean(true)]],
-    ['[42]', [new Number(42)]],
-    ['["1978-09-13T12:24:34.023Z"]', [new Date(Date.UTC(1978, 8, 13, 12, 24, 34, 23))]],
-    ['[1,null,3]',[1,,3]],
-    ['{"mm\\\"mm":"hmm"}',{"mm\"mm":"hmm"}],
-    ['{"mm\\\"mm\\\"mm":"hmm"}',{"mm\"mm\"mm":"hmm"}],
-    ['{"\\\"":"hmm"}',{'"':"hmm"}],
-    ['{"\\\\":"hmm"}',{'\\':"hmm"}],
-    ['{"mmm\\\\mmm":"hmm"}',{'mmm\\mmm':"hmm"}],
-    ['{"mmm\\\\mmm\\\\mmm":"hmm"}',{'mmm\\mmm\\mmm':"hmm"}],
-    ['{"mm\\u000bmm":"hmm"}',{"mm\u000bmm":"hmm"}],
-    ['{"mm\\u0000mm":"hmm"}',{"mm\u0000mm":"hmm"}]
-  ];
-
-  var x = {"free":"variable"}
-  testPairs.push(['{"free":"variable"}', x]);
-  testPairs.push(['{"y":{"free":"variable"}}', {"y":x}]);
-
-  // array prop
-  var x = {
-    a: [1,2,3]
-  }
-  testPairs.push(['{"a":[1,2,3]}', x])
-
-  var y = {
-    foo: function(hmm) { return hmm; }
-  }
-  testPairs.push(['{"y":{}}',{"y":y}]);
-
-  // test toJSON
-  var hmm = {
-    toJSON: function() { return {"foo":"bar"}}
-  }
-  testPairs.push(['{"hmm":{"foo":"bar"}}', {"hmm":hmm}]);
-  testPairs.push(['{"foo":"bar"}', hmm]); // on the root
-
-  // toJSON on prototype
-  var Y = function() {
-    this.not = "there?";
-    this.d = "e";
-  }
-  Y.prototype = {
-    not:"there?",
-    toJSON: function() { return {"foo":"bar"}}
-  };
-  var y = new Y();
-  testPairs.push(['{"foo":"bar"}', y.toJSON()]);
-  testPairs.push(['{"foo":"bar"}', y]);
-
-  // return undefined from toJSON
-  var hmm = {
-    toJSON: function() { return; }
-  }
-  testPairs.push(['{}', {"hmm":hmm}]);
-
-  // array with named prop
-  var x= new Array();
-  x[0] = 1;
-  x.foo = "bar";
-  testPairs.push(['[1]', x]);
-
-  // prototype
-  var X = function() { this.a = "b" }
-  X.prototype = {c:"d"}
-  var y = new X();
-  testPairs.push(['{"a":"b"}', y]);
-
-  return testPairs;
-}
-
-function testStringEncode() {
-  var pairs = getTestPairs();
-  for each(pair in pairs) {
-    print(pair)
-    var nativeResult = JSON.stringify(pair[1]);
-    do_check_eq(pair[0], nativeResult);
-  }
-}
-
-function decode_strings() {
-  // empty object
-  var x = JSON.parse("{}");
-  do_check_eq(typeof x, "object");
-
-  // empty array
-  x = JSON.parse("[]");
-  do_check_eq(typeof x, "object");
-  do_check_eq(x.length, 0);
-  do_check_eq(x.constructor, Array);
-
-  // one element array
-  x = JSON.parse("[[]]");
-  do_check_eq(typeof x, "object");
-  do_check_eq(x.length, 1);
-  do_check_eq(x.constructor, Array);
-  do_check_eq(x[0].constructor, Array);
-
-  // multiple arrays
-  x = JSON.parse("[[],[],[]]");
-  do_check_eq(typeof x, "object");
-  do_check_eq(x.length, 3);
-  do_check_eq(x.constructor, Array);
-  do_check_eq(x[0].constructor, Array);
-  do_check_eq(x[1].constructor, Array);
-  do_check_eq(x[2].constructor, Array);
-
-  // array key/value
-  x = JSON.parse('{"foo":[]}');
-  do_check_eq(typeof x, "object");
-  do_check_eq(typeof x.foo, "object");
-  do_check_eq(x.foo.constructor, Array);
-  x = JSON.parse('{"foo":[], "bar":[]}');
-  do_check_eq(typeof x, "object");
-  do_check_eq(typeof x.foo, "object");
-  do_check_eq(x.foo.constructor, Array);
-  do_check_eq(typeof x.bar, "object");
-  do_check_eq(x.bar.constructor, Array);
-
-  // nesting
-  x = JSON.parse('{"foo":[{}]}');
-  do_check_eq(x.foo.constructor, Array);
-  do_check_eq(x.foo.length, 1);
-  do_check_eq(typeof x.foo[0], "object");
-  x = JSON.parse('{"foo":[{"foo":[{"foo":{}}]}]}');
-  do_check_eq(x.foo[0].foo[0].foo.constructor, Object);
-  x = JSON.parse('{"foo":[{"foo":[{"foo":[]}]}]}');
-  do_check_eq(x.foo[0].foo[0].foo.constructor, Array);
-
-  // strings
-  x = JSON.parse('{"foo":"bar"}');
-  do_check_eq(x.foo, "bar");
-  x = JSON.parse('["foo", "bar", "baz"]');
-  do_check_eq(x[0], "foo");
-  do_check_eq(x[1], "bar");
-  do_check_eq(x[2], "baz");
-
-  // numbers
-  x = JSON.parse('{"foo":5.5, "bar":5}');
-  do_check_eq(x.foo, 5.5);
-  do_check_eq(x.bar, 5);
-  
-  // keywords
-  x = JSON.parse('{"foo": true, "bar":false, "baz":null}');
-  do_check_eq(x.foo, true);
-  do_check_eq(x.bar, false);
-  do_check_eq(x.baz, null);
-  
-  // short escapes
-  x = JSON.parse('{"foo": "\\"", "bar":"\\\\", "baz":"\\b","qux":"\\f", "quux":"\\n", "quuux":"\\r","quuuux":"\\t"}');
-  do_check_eq(x.foo, '"');
-  do_check_eq(x.bar, '\\');
-  do_check_eq(x.baz, '\b');
-  do_check_eq(x.qux, '\f');
-  do_check_eq(x.quux, "\n");
-  do_check_eq(x.quuux, "\r");
-  do_check_eq(x.quuuux, "\t");
-
-  // unicode escape
-  x = JSON.parse('{"foo":"hmm\\u006dmm"}');
-  do_check_eq("hmm\u006dmm", x.foo);
-
-  x = JSON.parse('{"JSON Test Pattern pass3": {"The outermost value": "must be an object or array.","In this test": "It is an object." }}');
-}
-
-function run_test() {
-  testStringEncode();
-  decode_strings();
-}
--- a/dom/src/threads/nsDOMWorkerTimeout.cpp
+++ b/dom/src/threads/nsDOMWorkerTimeout.cpp
@@ -165,17 +165,17 @@ nsDOMWorkerTimeout::ExpressionCallback::
   JSBool ok = mExpression.Hold(rt);
   CONSTRUCTOR_ENSURE_TRUE(ok, *aRv);
 
   mExpression = aArgv[0];
 
   // Get the calling location.
   const char* fileName;
   PRUint32 lineNumber;
-  if (nsJSUtils::GetCallingLocation(aCx, &fileName, &lineNumber, nsnull)) {
+  if (nsJSUtils::GetCallingLocation(aCx, &fileName, &lineNumber)) {
     mFileName.Assign(fileName);
     mLineNumber = lineNumber;
   }
 
   *aRv = NS_OK;
 }
 
 nsDOMWorkerTimeout::ExpressionCallback::~ExpressionCallback()
--- a/js/jsd/idl/jsdIDebuggerService.idl
+++ b/js/jsd/idl/jsdIDebuggerService.idl
@@ -71,18 +71,18 @@ interface jsdIContext;
 interface jsdIStackFrame;
 interface jsdIScript;
 interface jsdIValue;
 interface jsdIObject;
 interface jsdIProperty;
 interface jsdIActivationCallback;
 
 /**
- * Debugger service.  It's not a good idea to have more than one active client of
- * the debugger service.
+ * Debugger service. It is not a good idea to have more than one active client
+ * of the debugger service.
  */
 [scriptable, uuid(aa232c7f-855f-4488-a92c-6f89adc668cc)]
 interface jsdIDebuggerService : nsISupports
 {
     /** Internal use only. */
     [noscript] readonly attribute JSDContext        JSDContext;
 
     /**
@@ -111,21 +111,21 @@ interface jsdIDebuggerService : nsISuppo
     attribute jsdIExecutionHook interruptHook;
     /**
      * Called when an exception is thrown (even if it will be caught.)
      */
     attribute jsdIExecutionHook throwHook;
     /**
      * Called before and after a toplevel script is evaluated.
      */
-    attribute jsdICallHook topLevelHook;
+    attribute jsdICallHook      topLevelHook;
     /**
      * Called before and after a function is called.
      */
-    attribute jsdICallHook functionHook;
+    attribute jsdICallHook      functionHook;
 
 
     /**
      * VERSION_* values must be kept in sync with the JSVersion enumeration in
      * jspubtd.h.
      */
 
     /**
@@ -146,46 +146,46 @@ interface jsdIDebuggerService : nsISuppo
      */
 
     /**
      * Link native frames in call stacks.
      */
     const unsigned long ENABLE_NATIVE_FRAMES     = 0x01;
     /**
      * Normally, if a script has a 0 in JSD_SCRIPT_PROFILE_BIT it is included in
-     * profile data, otherwise it is not profiled.  Setting the
+     * profile data, otherwise it is not profiled. Setting the
      * PROFILE_WHEN_SET flag reverses this convention.
      */
     const unsigned long PROFILE_WHEN_SET         = 0x02;
     /**
      * Normally, when the script in the top frame of a thread state has a 1 in
-     * JSD_SCRIPT_DEBUG_BIT, the execution hook is ignored.  Setting the
+     * JSD_SCRIPT_DEBUG_BIT, the execution hook is ignored. Setting the
      * DEBUG_WHEN_SET flag reverses this convention.
      */
     const unsigned long DEBUG_WHEN_SET           = 0x04;
     /**
      * When this flag is set the internal call hook will collect profile data.
      */
     const unsigned long COLLECT_PROFILE_DATA     = 0x08;
     /**
      * When this flag is set, stack frames that are disabled for debugging
      * will not appear in the call stack chain.
      */
     const unsigned long HIDE_DISABLED_FRAMES     = 0x10;
     /**
      * When this flag is set, the debugger will only check the
-     * JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame.  This
+     * JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This
      * makes it possible to stop in an enabled frame which was called from
      * a stack that contains a disabled frame.
      *
      * When this flag is *not* set, any stack that contains a disabled frame
      * will not be debugged (the execution hook will not be invoked.)
      *
      * This only applies when the reason for calling the hook would have
-     * been TYPE_INTERRUPTED or TYPE_THROW.  TYPE_BREAKPOINT,
+     * been TYPE_INTERRUPTED or TYPE_THROW. TYPE_BREAKPOINT,
      * TYPE_DEBUG_REQUESTED, and TYPE_DEBUGGER_KEYWORD always stop, regardless
      * of this setting, as long as the top frame is not disabled.
      *
      * If HIDE_DISABLED_FRAMES is set, this is effectively set as well.
      */
     const unsigned long MASK_TOP_FRAME_ONLY     = 0x20;
     /**
      * This flag has been retired, do not re-use. It previously provided a hook
@@ -207,38 +207,38 @@ interface jsdIDebuggerService : nsISuppo
      */
     readonly attribute unsigned long implementationMinor;
     /**
      * Free form AUTF8String identifier for implementation.
      */
     readonly attribute AUTF8String implementationString;
     
     /**
-     * |true| if the debugger service has been turned on.  This does not
+     * |true| if the debugger service has been turned on. This does not
      * necessarily mean another app is actively using the service, as the 
      * autostart pref may have turned the service on.
      */
     readonly attribute boolean isOn;
 
 
     /**
      * Synchronous activation of the debugger is no longer supported,
      * and will throw an exception.
      */
-    void on ();
+    void on();
 
     /**
-     * Turn on the debugger.  This function should only be called from JavaScript
-     * code.  The debugger will be enabled on the runtime the call is made on,
-     * as determined by nsIXPCNativeCallContext.
+     * Turn on the debugger. This function should only be called from
+     * JavaScript code. The debugger will be enabled on the runtime the call is
+     * made on, as determined by nsIXPCNativeCallContext.
      *
-     * The debugger will be activated asynchronously, because there can be no JS
-     * on the stack when code is to be re-compiled for debug mode.
+     * The debugger will be activated asynchronously, because there can be no
+     * JS on the stack when code is to be re-compiled for debug mode.
      */
-    void asyncOn (in jsdIActivationCallback callback);
+    void asyncOn(in jsdIActivationCallback callback);
     
     /**
      * Called by nsIXPConnect after it's had a chance to recompile for
      * debug mode.
      */
     [noscript] void activateDebugger(in JSRuntime rt);
 
     /**
@@ -247,32 +247,30 @@ interface jsdIDebuggerService : nsISuppo
     [noscript] void deactivateDebugger();
 
     /**
      * Recompile all active scripts in the runtime for debugMode.
      */
     [noscript] void recompileForDebugMode(in JSContext cx, in JSCompartment comp, in PRBool mode);
 
     /**
-     * Turn the debugger off.  This will invalidate all of your jsdIEphemeral
-     * derived objects, and clear all of your breakpoints.  In theory you
-     * should be able to turn the debugger back on at some later time without
-     * any problems.
+     * Turn the debugger off. This will invalidate all of your jsdIEphemeral
+     * derived objects, and clear all of your breakpoints.
      */
     void off ();
 
     /**
      * Peek at the current pause depth of the debugger.
      *
      * @return depth Number of pause() calls still waiting to be unPause()d.
      */
     readonly attribute unsigned long pauseDepth;
     /**
-     * Temporarily disable the debugger.  Hooks will not be called while the
-     * debugger is paused.  Multiple calls to pause will increase the "pause
+     * Temporarily disable the debugger. Hooks will not be called while the
+     * debugger is paused. Multiple calls to pause will increase the "pause
      * depth", and equal number of unPause calles must be made to resume
      * normal debugging.
      *
      * @return depth Number of times pause has been called since the debugger
      *               has been unpaused.
      */
     unsigned long pause();
     /**
@@ -288,279 +286,279 @@ interface jsdIDebuggerService : nsISuppo
     void GC();
     
     /**
      * Clear profile data for all scripts.
      */
     void clearProfileData();
     
     /**
-     * Adds an execution hook filter.  These filters are consulted each time one
-     * of the jsdIExecutionHooks is about to be called.  Filters are matched in
-     * a first in, first compared fashion.  The first filter to match determines
-     * whether or not the hook is called.  Use swapFilter to reorder existing
+     * Adds an execution hook filter. These filters are consulted each time one
+     * of the jsdIExecutionHooks is about to be called. Filters are matched in
+     * a first in, first compared fashion. The first filter to match determines
+     * whether or not the hook is called. Use swapFilter to reorder existing
      * filters, and removeFilter to remove them.
      *
      * If |filter| is already present this method throws NS_ERROR_INVALID_ARG.
      *
      * @param filter Object representing the filter to add.
-     * @param after  Insert |filter| after this one.  Pass null to insert at
+     * @param after  Insert |filter| after this one. Pass null to insert at
      *               the beginning.
      */
-    void insertFilter (in jsdIFilter filter, in jsdIFilter after);
+    void insertFilter(in jsdIFilter filter, in jsdIFilter after);
     /**
      * Same as insertFilter, except always add to the end of the list.
      */
-    void appendFilter (in jsdIFilter filter);
+    void appendFilter(in jsdIFilter filter);
     /**
      * Remove a filter.
      *
      * If |filter| is not present this method throws NS_ERROR_INVALID_ARG.
      *
-     * @param filter Object representing the filter to remove.  Must be the exact
+     * @param filter Object representing the filter to remove. Must be the exact
      * object passed to addFilter, not just a new object with the same
      * properties.
      */
-    void removeFilter (in jsdIFilter filter);
+    void removeFilter(in jsdIFilter filter);
     /**
      * Swap position of two filters.
      * 
      * If |filter_a| is not present, this method throws NS_ERROR_INVALID_ARG.
      * If |filter_b| is not present, filter_a is replaced by filter_b.
      * If |filter_a| == |filter_b|, then filter is refreshed.
      */
-    void swapFilters (in jsdIFilter filter_a, in jsdIFilter filter_b);
+    void swapFilters(in jsdIFilter filter_a, in jsdIFilter filter_b);
     /**
-     * Enumerate registered filters.  This routine refreshes each filter before
-     * passing them on to the enumeration function.  Calling this with a null
+     * Enumerate registered filters. This routine refreshes each filter before
+     * passing them on to the enumeration function. Calling this with a null
      * |enumerator| is equivalent to jsdIService::refreshFilters.
      *
      * @param enumerator jsdIFilterEnumerator instance to be called back for the
      *                   enumeration.
      */
-    void enumerateFilters (in jsdIFilterEnumerator enumerator);
+    void enumerateFilters(in jsdIFilterEnumerator enumerator);
     /**
      * Force the debugger to resync its internal filter cache with the
-     * actual values in the jsdIFilter objects.  To refresh a single filter
-     * use jsdIService::swapFilters.  This method is equivalent to
+     * actual values in the jsdIFilter objects. To refresh a single filter
+     * use jsdIService::swapFilters. This method is equivalent to
      * jsdIService::enumerateFilters with a null enumerator.
      */
-    void refreshFilters ();
+    void refreshFilters();
     /**
      * Clear the list of filters.
      */
     void clearFilters();
 
     /**
      * Enumerate all known contexts.
      */
-    void enumerateContexts (in jsdIContextEnumerator enumerator);
+    void enumerateContexts(in jsdIContextEnumerator enumerator);
     
     /**
-     * Enumerate all scripts the debugger knows about.  Any scripts created
+     * Enumerate all scripts the debugger knows about. Any scripts created
      * before you turned the debugger on, or after turning the debugger off
      * will not be available unless the autostart perf is set.
      *
      * @param enumerator jsdIScriptEnumerator instance to be called back for
      *                   the enumeration.
      */
-    void enumerateScripts (in jsdIScriptEnumerator enumerator);
+    void enumerateScripts(in jsdIScriptEnumerator enumerator);
     /**
      * Clear all breakpoints in all scripts.
      */
-    void clearAllBreakpoints ();
+    void clearAllBreakpoints();
 
     /**
      * When called from JavaScript, this method returns the jsdIValue wrapper
-     * for the given value.  If a wrapper does not exist one will be created.
+     * for the given value. If a wrapper does not exist one will be created.
      * When called from another language this method returns an xpconnect
      * defined error code.
      */
-    jsdIValue wrapValue (/*in jsvalue value*/);
+    jsdIValue wrapValue(/*in jsvalue value*/);
 
     /**
      * The same as above but to be called from C++.
      */
-    [noscript] jsdIValue wrapJSValue (in jsval value);
+    [noscript] jsdIValue wrapJSValue(in jsval value);
     
-    /* XXX these two routines are candidates for refactoring.  The only problem
+    /* XXX these two routines are candidates for refactoring. The only problem
      * is that it is not clear where and how they should land.
      */
 
     /**
      * Push a new network queue, and enter a new UI event loop.
      * @param callback jsdINestCallback instance to be called back after the
      *                 network queue has been pushed, but before the
      *                 UI loop starts.
      * @return depth returns the current number of times the event loop has been
-     *               nested.  your code can use it for sanity checks.
+     *               nested. your code can use it for sanity checks.
      */
-    unsigned long enterNestedEventLoop (in jsdINestCallback callback);
+    unsigned long enterNestedEventLoop(in jsdINestCallback callback);
     /**
      * Exit the current nested event loop after the current iteration completes,
      * and pop the network event queue.
      *
      * @return depth returns the current number of times the event loop has been
-     *               nested.  your code can use it for sanity checks.
+     *               nested. your code can use it for sanity checks.
      */
-    unsigned long exitNestedEventLoop ();
+    unsigned long exitNestedEventLoop();
 
     /**
      * Output dump of JS heap.
      *
      * @param fileName Filename to dump the heap into.
      */
-    void dumpHeap (in AUTF8String fileName);
+    void dumpHeap(in AUTF8String fileName);
 };
 
 /* callback interfaces */
 
 /**
  * Object representing a pattern of global object and/or url the debugger should
- * ignore.  The debugger service itself will not modify properties of these
+ * ignore. The debugger service itself will not modify properties of these
  * objects.
  */
 [scriptable, uuid(0c9189d9-4287-47a4-bca6-6ed65aaf737f)]
 interface jsdIFilter : nsISupports
 {
     /**
      * These two bytes of the flags attribute are reserved for interpretation
-     * by the jsdService implementation.  You can do what you like with the
+     * by the jsdService implementation. You can do what you like with the
      * remaining flags.
      */
     const unsigned long FLAG_RESERVED_MASK = 0xFF;
     /**
      * Filters without this flag set are ignored.
      */
     const unsigned long FLAG_ENABLED       = 0x01;
     /**
      * Filters with this flag set are "pass" filters, they allow matching hooks
-     * to continue.  Filters without this flag block matching hooks.
+     * to continue. Filters without this flag block matching hooks.
      */
     const unsigned long FLAG_PASS          = 0x02;
 
     /**
      * FLAG_* values from above, OR'd together.
      */
     attribute unsigned long flags;
     
     /**
-     * An nsISupports version of the global object to be filtered.  A null glob
-     * matches all hooks.  This attribute must be QI'able to the
+     * An nsISupports version of the global object to be filtered. A null glob
+     * matches all hooks. This attribute must be QI'able to the
      * (non-scriptable) nsIScriptGlobalObject interface.
      *
      * The jsdIService caches this value internally, so if it changes you must
      * swap the filter with itself using jsdIService::swapFilters.
      */
     attribute nsISupports globalObject;
     
     /**
-     * String representing the url pattern to be filtered.  Supports limited
-     * glob matching, at the beginning and end of the pattern only.  For example,
+     * String representing the url pattern to be filtered. Supports limited
+     * glob matching, at the beginning and end of the pattern only. For example,
      * "chrome://venkman*" filters all urls that start with chrome/venkman,
      * "*.cgi" filters all cgi's, and "http://myserver/utils.js" filters only
-     * the utils.js file on "myserver".   A null urlPattern matches all urls.
+     * the utils.js file on "myserver". A null urlPattern matches all urls.
      *
      * The jsdIService caches this value internally, to if it changes you must
      * swap the filter with itself using jsdIService::swapFilters.
      */
     attribute AUTF8String urlPattern;
 
     /**
-     * Line number for the start of this filter.  Line numbers are one based.
+     * Line number for the start of this filter. Line numbers are one based.
      * Assigning a 0 to this attribute will tell the debugger to ignore the
      * entire file.
      */
     attribute unsigned long startLine;
 
     /**
-     * Line number for the end of this filter.  Line numbers are one based.
+     * Line number for the end of this filter. Line numbers are one based.
      * Assigning a 0 to this attribute will tell the debugger to ignore from
      * |startLine| to the end of the file.
      */
     attribute unsigned long endLine;
 };
 
 /**
  * Notify client code that debugMode has been activated.
  */
 [scriptable, function, uuid(6da7f5fb-3a84-4abe-9e23-8b2045960732)]
 interface jsdIActivationCallback : nsISupports
 {
-    void onDebuggerActivated ();
+    void onDebuggerActivated();
 };
 
 /**
  * Pass an instance of one of these to jsdIDebuggerService::enterNestedEventLoop.
  */
 [scriptable, function, uuid(88bea60f-9b5d-4b39-b08b-1c3a278782c6)]
 interface jsdINestCallback : nsISupports
 {
     /**
      * This method will be called after pre-nesting work has completed, such
      * as pushing the js context and network event queue, but before the new
      * event loop starts.
      */
-    void onNest ();
+    void onNest();
 };
 
 /**
  * Pass an instance of one of these to jsdIDebuggerService::enumerateFilters.
  */
 [scriptable, function, uuid(e391ba85-9379-4762-b387-558e38db730f)]
 interface jsdIFilterEnumerator : nsISupports
 {
     /**
      * The enumerateFilter method will be called once for every filter the
      * debugger knows about.
      */
-    void enumerateFilter (in jsdIFilter filter);
+    void enumerateFilter(in jsdIFilter filter);
 };
 
 /**
  * Pass an instance of one of these to jsdIDebuggerService::enumerateScripts.
  */
 [scriptable, function, uuid(4eef60c2-9bbc-48fa-b196-646a832c6c81)]
 interface jsdIScriptEnumerator : nsISupports
 {
     /**
      * The enumerateScript method will be called once for every script the
      * debugger knows about.
      */
-    void enumerateScript (in jsdIScript script);
+    void enumerateScript(in jsdIScript script);
 };
 
 /**
  * Pass an instance of one of these to jsdIDebuggerService::enumerateContexts.
  */
 [scriptable, function, uuid(57d18286-550c-4ca9-ac33-56f12ebba91e)]
 interface jsdIContextEnumerator : nsISupports
 {
     /**
      * The enumerateContext method will be called once for every context
      * currently in use.
      */
-    void enumerateContext (in jsdIContext executionContext);
+    void enumerateContext(in jsdIContext executionContext);
 };
 
 /**
  * Set jsdIDebuggerService::scriptHook to an instance of one of these.
  */
 [scriptable, uuid(bb722893-0f63-45c5-b547-7a0947c7b6b6)]
 interface jsdIScriptHook : nsISupports
 {
     /**
      * Called when scripts are created.
      */
-    void onScriptCreated (in jsdIScript script);
+    void onScriptCreated(in jsdIScript script);
     /**
-     * Called when the JavaScript engine destroys a script.  The jsdIScript
+     * Called when the JavaScript engine destroys a script. The jsdIScript
      * object passed in will already be invalidated.
      */
-    void onScriptDestroyed (in jsdIScript script);
+    void onScriptDestroyed(in jsdIScript script);
 };
 
 /**
  * Hook instances of this interface up to the
  * jsdIDebuggerService::functionHook and toplevelHook properties.
  */
 [scriptable, function, uuid(3eff1314-7ae3-4cf8-833b-c33c24a55633)]
 interface jsdICallHook : nsISupports
@@ -586,17 +584,17 @@ interface jsdICallHook : nsISupports
      * Function is returning.
      */
     const unsigned long TYPE_FUNCTION_RETURN = 3;
     
     /**
      * Called before the JavaScript engine executes a top level script or calls
      * a function.
      */
-    void onCall (in jsdIStackFrame frame, in unsigned long type);
+    void onCall(in jsdIStackFrame frame, in unsigned long type);
 };
 
 [scriptable, function, uuid(e6b45eee-d974-4d85-9d9e-f5a67218deb4)]
 interface jsdIErrorHook : nsISupports
 {
     /**
      * REPORT_* values must be kept in sync with JSREPORT_* #defines in
      * jsapi.h
@@ -615,23 +613,23 @@ interface jsdIErrorHook : nsISupports
      */
     const unsigned long REPORT_EXCEPTION = 0x02;
     /**
      * Report is due to strict mode.
      */
     const unsigned long REPORT_STRICT    = 0x04;
 
     /**
-     * Called when the JavaScript engine encounters an error.  Return |true|
+     * Called when the JavaScript engine encounters an error. Return |true|
      * to pass the error along, |false| to invoke the debugHook.
      */
-    boolean onError (in AUTF8String message, in AUTF8String fileName,
-                     in unsigned long line, in unsigned long pos,
-                     in unsigned long flags, in unsigned long errnum,
-                     in jsdIValue exc);
+    boolean onError(in AUTF8String message, in AUTF8String fileName,
+                    in unsigned long line, in unsigned long pos,
+                    in unsigned long flags, in unsigned long errnum,
+                    in jsdIValue exc);
 };
 
 /**
  * Hook instances of this interface up to the
  * jsdIDebuggerService::breakpointHook, debuggerHook, errorHook, interruptHook,
  * and throwHook properties.
  */
 [scriptable, function, uuid(3a722496-9d78-4f0a-a797-293d9e8cb8d2)]
@@ -663,25 +661,25 @@ interface jsdIExecutionHook : nsISupport
     const unsigned long TYPE_THROW            = 4;
 
     /**
      * RETURN_* values must be kept in sync with JSD_HOOK_RETURN_* #defines in
      * jsdebug.h.
      */
 
     /**
-     * Indicates unrecoverable error processing the hook.  This will cause
+     * Indicates unrecoverable error processing the hook. This will cause
      * the script being executed to be aborted without raising a JavaScript
      * exception.
      */
     const unsigned long RETURN_HOOK_ERROR     = 0;
     /**
-     * Continue processing normally.  This is the "do nothing special" return
-     * value for all hook types *except* TYPE_THROW.  Returning RETURN_CONTINUE
-     * from TYPE_THROW cause the exception to be ignored.  Return
+     * Continue processing normally. This is the "do nothing special" return
+     * value for all hook types *except* TYPE_THROW. Returning RETURN_CONTINUE
+     * from TYPE_THROW cause the exception to be ignored. Return
      * RETURN_CONTINUE_THROW to continue exception processing from TYPE_THROW
      * hooks.
      */
     const unsigned long RETURN_CONTINUE       = 1;
     /**
      * Same effect as RETURN_HOOK_ERROR.
      */
     const unsigned long RETURN_ABORT          = 2;
@@ -703,43 +701,43 @@ interface jsdIExecutionHook : nsISupport
      * @param type  One of the jsdIExecutionHook::TYPE_ constants.
      * @param val   in  - Current exception (if any) when this method is called.
      *              out - If you return RETURN_THROW_WITH_VAL, value to be
      *                    thrown.
      *                    If you return RETURN_RET_WITH_VAL, value to return.
      *                    All other return values, not significant.
      * @retval      One of the jsdIExecutionHook::RETURN_* constants.
      */
-    unsigned long onExecute (in jsdIStackFrame frame, 
-                             in unsigned long type, inout jsdIValue val);
+    unsigned long onExecute(in jsdIStackFrame frame, 
+                            in unsigned long type, inout jsdIValue val);
 };
 
 /**
  * Objects which inherit this interface may go away, with (jsdIScript) or
- * without (all others) notification.  These objects are generally wrappers
+ * without (all others) notification. These objects are generally wrappers
  * around JSD structures that go away when you call jsdService::Off().
  */
 [scriptable, uuid(46f1e23e-1dd2-11b2-9ceb-8285f2e95e69)]
 interface jsdIEphemeral : nsISupports
 {
     /**
-     * |true| if this object is still valid.  If not, many or all of the methods
+     * |true| if this object is still valid. If not, many or all of the methods
      * and/or properties of the inheritor may no longer be callable.
      */
     readonly attribute boolean isValid;
     /**
      * Mark this instance as invalid.
      */
     [noscript] void invalidate(); 
 };    
 
 /* handle objects */
 
 /**
- * Context object.  Only context's which are also nsISupports objects can be
+ * Context object. Only context's which are also nsISupports objects can be
  * reflected by this interface.
  */
 [scriptable, uuid(3e5c934d-6863-4d81-96f5-76a3b962fc2b)]
 interface jsdIContext : jsdIEphemeral
 {
     /* Internal use only. */
     [noscript] readonly attribute JSContext   JSContext;
 
@@ -756,17 +754,17 @@ interface jsdIContext : jsdIEphemeral
      */
     const long OPT_WERR        = 0x02;
     /**
      * Makes eval() use the last object on its 'obj' param's scope chain as the
      * ECMA 'variables object'.
      */
     const long OPT_VAROBJFIX   = 0x04;
     /**
-     * Private data for this object is an nsISupports object.  Attempting to
+     * Private data for this object is an nsISupports object. Attempting to
      * alter this bit will result in an NS_ERROR_ILLEGAL_VALUE.
      */
     const long OPT_ISUPPORTS   = 0x08;
     /**
      * OPT_* values above, OR'd together.
      */
     attribute unsigned long          options;
 
@@ -794,28 +792,28 @@ interface jsdIContext : jsdIEphemeral
 
     /**
      * Top of the scope chain for this context.
      */
     readonly attribute jsdIValue     globalObject;
 
     /**
      * |true| if this context should be allowed to run scripts, |false|
-     * otherwise.  This attribute is only valid for contexts which implement
-     * nsIScriptContext.  Setting or getting this attribute on any other
+     * otherwise. This attribute is only valid for contexts which implement
+     * nsIScriptContext. Setting or getting this attribute on any other
      * context will throw a NS_ERROR_NO_INTERFACE exception.
      */
     attribute boolean                scriptsEnabled;
 };
 
 /**
- * Stack frame objects.  These are only valid inside the jsdIExecutionHook which
- * gave it to you.  After you return from that handler the bottom frame, and any
+ * Stack frame objects. These are only valid inside the jsdIExecutionHook which
+ * gave it to you. After you return from that handler the bottom frame, and any
  * frame you found attached through it, are invalidated via the jsdIEphemeral
- * interface.  Once a jsdIStackFrame has been invalidated all method and
+ * interface. Once a jsdIStackFrame has been invalidated all method and
  * property accesses will throw a NS_ERROR_NOT_AVAILABLE exception.
  */
 [scriptable, uuid(0633ca73-105e-4e8e-bcc5-13405d61754a)]
 interface jsdIStackFrame : jsdIEphemeral
 {
     /** Internal use only. */
     [noscript] readonly attribute JSDContext        JSDContext;
     /** Internal use only. */
@@ -867,28 +865,28 @@ interface jsdIStackFrame : jsdIEphemeral
     readonly attribute jsdIValue      scope;
     /**
      * |this| object for this stack frame.
      */
     readonly attribute jsdIValue      thisValue;
     /**
      * Evaluate arbitrary JavaScript in this stack frame.
      * @param bytes    Script to be evaluated.
-     * @param fileName Filename to compile this script under.  This is the
+     * @param fileName Filename to compile this script under. This is the
      *                 filename you'll see in error messages, etc.
-     * @param line     Starting line number for this script.  One based.
+     * @param line     Starting line number for this script. One based.
      * @retval         Result of evaluating the script.
      */
-    boolean eval (in AString bytes, in AUTF8String fileName,
-                  in unsigned long line, out jsdIValue result);
+    boolean eval(in AString bytes, in AUTF8String fileName,
+                 in unsigned long line, out jsdIValue result);
     
 };
 
 /**
- * Script object.  In JavaScript engine terms, there's a single script for each
+ * Script object. In JavaScript engine terms, there's a single script for each
  * function, and one for the top level script.
  */
 [scriptable, uuid(e7935220-7def-4c8e-832f-fbc948a97490)]
 interface jsdIScript : jsdIEphemeral
 {
     /** Internal use only. */
     [noscript] readonly attribute JSDContext JSDContext;
     /** Internal use only. */
@@ -897,29 +895,29 @@ interface jsdIScript : jsdIEphemeral
     /**
      * Last version set on this context.
      * Scripts typically select this with the "language" attribute.
      * See the VERSION_* consts on jsdIDebuggerService.
      */
     readonly attribute long          version;
 
     /**
-     * Tag value guaranteed unique among jsdIScript objects.  Useful as a
+     * Tag value guaranteed unique among jsdIScript objects. Useful as a
      * hash key in script.
      */
     readonly attribute unsigned long tag;
 
     /**
      * FLAG_* values need to be kept in sync with JSD_SCRIPT_* #defines in
      * jsdebug.h.
      */
 
     /**
      * Determines whether or not to collect profile information for this
-     * script.  The context flag FLAG_PROFILE_WHEN_SET decides the logic.
+     * script. The context flag FLAG_PROFILE_WHEN_SET decides the logic.
      */
     const unsigned long FLAG_PROFILE = 0x01;
     /**
      * Determines whether or not to ignore breakpoints, etc. in this script.
      * The context flag JSD_DEBUG_WHEN_SET decides the logic.
      */
     const unsigned long FLAG_DEBUG   = 0x02;
     
@@ -931,17 +929,17 @@ interface jsdIScript : jsdIEphemeral
     /**
      * Filename given for this script when it was compiled.
      * This data is copied from the underlying structure when the jsdIScript
      * instance is created and is therefore available even after the script is
      * invalidated.
      */
     readonly attribute AUTF8String   fileName;
     /**
-     * Function name for this script.  "anonymous" for unnamed functions (or
+     * Function name for this script. "anonymous" for unnamed functions (or
      * a function actually named anonymous), empty for top level scripts.
      * This data is copied from the underlying structure when the jsdIScript
      * instance is created and is therefore available even after the script is
      * invalidated.
      */
     readonly attribute AUTF8String   functionName;
     /**
      * The names of the arguments for this function; empty if this is
@@ -1015,49 +1013,49 @@ interface jsdIScript : jsdIEphemeral
     
     const unsigned long PCMAP_SOURCETEXT  = 1; /* map to actual source text    */
     const unsigned long PCMAP_PRETTYPRINT = 2; /* map to pretty printed source */
 
     /**
      * Get the closest line number to a given PC.
      * The |pcmap| argument specifies which pc to source line map to use.
      */
-    unsigned long pcToLine (in unsigned long pc, in unsigned long pcmap);
+    unsigned long pcToLine(in unsigned long pc, in unsigned long pcmap);
     /**
      * Get the first PC associated with a line.
      * The |pcmap| argument specifies which pc to source line map to use.
      */
-    unsigned long lineToPc (in unsigned long line, in unsigned long pcmap);
+    unsigned long lineToPc(in unsigned long line, in unsigned long pcmap);
     /**
      * Determine is a particular line is executable, like checking that
      * lineToPc == pcToLine, except in one call.
      * The |pcmap| argument specifies which pc to source line map to use.
      */
-    boolean isLineExecutable (in unsigned long line, in unsigned long pcmap);
+    boolean isLineExecutable(in unsigned long line, in unsigned long pcmap);
     /**
      * Set a breakpoint at a PC in this script.
      */
-    void setBreakpoint (in unsigned long pc);
+    void setBreakpoint(in unsigned long pc);
     /**
      * Clear a breakpoint at a PC in this script.
      */
-    void clearBreakpoint (in unsigned long pc);
+    void clearBreakpoint(in unsigned long pc);
     /**
      * Clear all breakpoints set in this script.
      */
-    void clearAllBreakpoints ();
+    void clearAllBreakpoints();
     /**
      * Call interrupt hook at least once per source line
      */
-    void enableSingleStepInterrupts (in PRBool mode);
+    void enableSingleStepInterrupts(in PRBool mode);
 };
 
 /**
- * Value objects.  Represents typeless JavaScript values (jsval in SpiderMonkey
- * terminology.)  These are valid until the debugger is turned off.  Holding a
+ * Value objects. Represents typeless JavaScript values (jsval in SpiderMonkey
+ * terminology.)  These are valid until the debugger is turned off. Holding a
  * jsdIValue adds a root for the underlying JavaScript value, so don't keep it
  * if you don't need to.
  */
 [scriptable, uuid(fd1311f7-096c-44a3-847b-9d478c8176c3)]
 interface jsdIValue : jsdIEphemeral
 {
     /** Internal use only. */
     [noscript] readonly attribute JSDContext JSDContext;
@@ -1106,85 +1104,85 @@ interface jsdIValue : jsdIEphemeral
      */
     readonly attribute jsdIValue     jsPrototype;
     /**
      * Parent value if this value represents an object, null if the value is not
      * an object or the object has no parent.
      */    
     readonly attribute jsdIValue     jsParent;
     /**
-     * Class name if this value represents an object.  Empty AUTF8String if the value
+     * Class name if this value represents an object. Empty AUTF8String if the value
      * is not an object.
      */
     readonly attribute AUTF8String   jsClassName;
     /**
-     * Constructor name if this value represents an object.  Empty AUTF8String if the
+     * Constructor name if this value represents an object. Empty AUTF8String if the
      * value is not an object.
      */
     readonly attribute jsdIValue     jsConstructor;
     /**
-     * Function name if this value represents a function.  Empty AUTF8String if the
+     * Function name if this value represents a function. Empty AUTF8String if the
      * value is not a function.
      */
     readonly attribute AUTF8String   jsFunctionName;
     
     /**
-     * Value if interpreted as a boolean.  Converts if necessary.
+     * Value if interpreted as a boolean. Converts if necessary.
      */
-    readonly attribute boolean    booleanValue;
+    readonly attribute boolean       booleanValue;
     /**
-     * Value if interpreted as a double.  Converts if necessary.
+     * Value if interpreted as a double. Converts if necessary.
      */
-    readonly attribute double     doubleValue;
+    readonly attribute double        doubleValue;
     /**
-     * Value if interpreted as an integer.  Converts if necessary.
+     * Value if interpreted as an integer. Converts if necessary.
      */
-    readonly attribute long       intValue;
+    readonly attribute long          intValue;
     /**
      * Value if interpreted as an object.
      */
-    readonly attribute jsdIObject objectValue;
+    readonly attribute jsdIObject    objectValue;
     /**
-     * Value if interpreted as a AUTF8String.  Converts if necessary.
+     * Value if interpreted as a AUTF8String. Converts if necessary.
      */
-    readonly attribute AUTF8String     stringValue;
+    readonly attribute AUTF8String   stringValue;
 
     /**
-     * Number of properties.  0 if the value is not an object, or the value is
+     * Number of properties. 0 if the value is not an object, or the value is
      * an object but has no properties.
      */
     readonly attribute long propertyCount;
     
     /**
-     * Retrieves all properties if this value represents an object.  If this
+     * Retrieves all properties if this value represents an object. If this
      * value is not an object a 0 element array is returned.
      * @param propArray Array of jsdIProperty values for this value.
      * @param length    Size of array.
      */
-    void getProperties ([array, size_is(length)] out jsdIProperty propArray,
-                        out unsigned long length);
+    void getProperties([array, size_is(length)] out jsdIProperty propArray,
+                       out unsigned long length);
     /**
-     * Retrieves a single property from the value.  Only valid if the value
+     * Retrieves a single property from the value. Only valid if the value
      * represents an object.
      * @param name Name of the property to retrieve.
      * @retval     jsdIProperty for the requested property name or null if no
      *             property exists for the requested name.
      */
-    jsdIProperty getProperty (in AUTF8String name);
+    jsdIProperty getProperty(in AUTF8String name);
 
     /**
-     * jsdIValues are wrappers around JavaScript engine structures.  Much of the
-     * data is copied instead of shared.  The refresh method is used to resync
+     * jsdIValues are wrappers around JavaScript engine structures. Much of the
+     * data is copied instead of shared. The refresh method is used to resync
      * the jsdIValue with the underlying structure.
      */
     void refresh();
 
     /**
      * When called from JavaScript, this method returns the JavaScript value
-     * wrapped by this jsdIValue.  The calling script is free to use the result
+     * wrapped by this jsdIValue. The calling script is free to use the result
      * as it would any other JavaScript value.
      * When called from another language this method returns an xpconnect
      * defined error code.
      */
     void getWrappedValue();
 
     /**
      * If this is a function value, return its associated jsdIScript.
@@ -1194,17 +1192,17 @@ interface jsdIValue : jsdIEphemeral
 };
 
 /**
  * Properties specific to values which are also objects.
  * XXX We don't add roots for these yet, so make sure you hold on to the
  * jsdIValue from whence your jsdIObject instance came for at least as long as
  * you hold the jsdIObject.
  * XXX Maybe the jsClassName, jsConstructorName, and property related attribute/
- * functions from jsdIValue should move to this interface.  We could inherit from
+ * functions from jsdIValue should move to this interface. We could inherit from
  * jsdIValue or use interface flattening or something.
  */
 [scriptable, uuid(87d86308-7a27-4255-b23c-ce2394f02473)]
 interface jsdIObject : nsISupports
 {
     /** Internal use only. */
     [noscript] readonly attribute JSDContext JSDContext;
     /** Internal use only. */
@@ -1230,17 +1228,17 @@ interface jsdIObject : nsISupports
     readonly attribute unsigned long constructorLine;
     /**
      * jsdIValue for this object.
      */
     readonly attribute jsdIValue     value;
 };
 
 /**
- * Representation of a property of an object.  When an instance is invalid, all
+ * Representation of a property of an object. When an instance is invalid, all
  * method and property access will result in a NS_UNAVAILABLE error.
  */
 [scriptable, uuid(09332485-1419-42bc-ba1f-070815ed4b82)]
 interface jsdIProperty : jsdIEphemeral
 {
     /** Internal use only. */
     [noscript] readonly attribute JSDContext  JSDContext;
     /** Internal use only. */
@@ -1274,30 +1272,9 @@ interface jsdIProperty : jsdIEphemeral
     /** jsdIValue representing the alias for this property. */
     readonly attribute jsdIValue     alias;
     /** name for this property. */
     readonly attribute jsdIValue     name;
     /** value of this property. */
     readonly attribute jsdIValue     value;
     /** slot number if this property is a local variable or parameter. */
     readonly attribute unsigned long varArgSlot;
-
 };
-
-/*
-[scriptable, uuid(a47adad2-1dd1-11b2-b9e9-8e67a47beca5)]
-interface jsdISourceText : nsISupports
-{};
-
-[scriptable, uuid(b6d1c006-1dd1-11b2-b9d8-b4d1ccfb74d8)]
-interface jsdIThreadState : nsISupports
-{
-    [noscript] readonly attribute JSDContext     JSDContext;
-    [noscript] readonly attribute JSDThreadState JSDThreadState;
-    
-    readonly attribute unsigned long  frameCount;
-    readonly attribute jsdIStackFrame topFrame;
-    
-    attribute jsdIValue pendingException;
-};
-
-*/
-
--- a/js/jsd/jsd_val.c
+++ b/js/jsd/jsd_val.c
@@ -675,17 +675,17 @@ jsd_GetValueFunction(JSDContext* jsdc, J
 {
     JSObject *obj;
     JSFunction *fun;
     JSCrossCompartmentCall *call = NULL;
     if (!JSVAL_IS_OBJECT(jsdval->val))
         return NULL;
     if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
         return NULL;
-    obj = JS_UnwrapObject(jsdc->dumbContext, obj);
+    obj = JS_UnwrapObject(obj);
 
     call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
     if (!call)
         return NULL;
     fun = JS_ValueToFunction(jsdc->dumbContext, OBJECT_TO_JSVAL(obj));
     JS_LeaveCrossCompartmentCall(call);
 
     return fun;
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -54,19 +54,18 @@ ifdef JS_NATIVE_EDITLINE
 DIRS += editline
 endif
 
 # editline needs to get built before the shell
 ifndef JS_DISABLE_SHELL
 DIRS += shell
 endif
 
-# FIXME: bug 515383 covers getting these working on wince
-# bug 530688 covers Android
-ifneq (,$(filter-out WINCE ANDROID,$(OS_ARCH)))
+# FIXME: bug 530688 covers getting these working on Android
+ifneq (,$(filter-out ANDROID,$(OS_ARCH)))
 ifdef ENABLE_TESTS
 DIRS += jsapi-tests
 endif
 endif
 
 ifdef ENABLE_TESTS
 DIRS += tests
 endif
@@ -83,17 +82,16 @@ ifdef INTEL_CXX
 # icc gets special optimize flags
 ifdef MOZ_PROFILE_GENERATE
 MODULE_OPTIMIZE_FLAGS = -O0
 else
 MODULE_OPTIMIZE_FLAGS = -O2 -ip
 endif
 else # not INTEL_CXX
 
-#FAIL_ON_WARNINGS = 1
 MODULE_OPTIMIZE_FLAGS = -O3 -fstrict-aliasing -fno-stack-protector
 
 # We normally want -fomit-frame-pointer, but we want an explicit
 # -fno-omit-frame-pointer if we're using a sampling profiler.
 ifndef MOZ_PROFILING
 MODULE_OPTIMIZE_FLAGS += -fomit-frame-pointer
 else
 MODULE_OPTIMIZE_FLAGS += -fno-omit-frame-pointer
@@ -153,16 +151,17 @@ CPPSRCS		= \
 		jsiter.cpp \
 		jslock.cpp \
 		jslog2.cpp \
 		jsmath.cpp \
 		jsnativestack.cpp \
 		jsnum.cpp \
 		jsobj.cpp \
 		json.cpp \
+		jsonparser.cpp \
 		jsopcode.cpp \
 		jsparse.cpp \
 		jsproxy.cpp \
 		jsprf.cpp \
 		jsprobes.cpp \
 		jspropertycache.cpp \
 		jspropertytree.cpp \
 		jsreflect.cpp \
@@ -210,19 +209,21 @@ INSTALLED_HEADERS = \
 		jscompartment.h \
 		jshash.h \
 		jsinterp.h \
 		jsinttypes.h \
 		jsiter.h \
 		jslock.h \
 		jslong.h \
 		jsmath.h \
+		jsnum.h \
 		jsobj.h \
 		jsobjinlines.h \
 		json.h \
+		jsonparser.h \
 		jsopcode.tbl \
 		jsopcode.h \
 		jsopcodeinlines.h \
 		jsotypes.h \
 		jsparse.h \
 		jsproxy.h \
 		jsprf.h \
 		jsprobes.h \
@@ -309,23 +310,16 @@ CPPSRCS += \
 		RegAlloc.cpp   \
 		avmplus.cpp    \
 		Native$(NANOJIT_ARCH).cpp \
 		jsbuiltins.cpp \
 		VMPI.cpp       \
 		Writer.cpp     \
 		$(NULL)
 
-ifdef WINCE
-# don't need -c
-AS_DASH_C_FLAG =
-ASFLAGS += -arch 6
-ASFILES += jswince.asm
-endif
-
 endif # ENABLE_TRACEJIT
 ifdef ENABLE_METHODJIT
 
 ###############################################
 # BEGIN include sources for the method JIT
 #
 VPATH += 	$(srcdir)/methodjit
 
@@ -496,25 +490,25 @@ VPATH += $(srcdir)/perf
 INSTALLED_HEADERS += jsperf.h
 CPPSRCS += jsperf.cpp
 ifdef HAVE_LINUX_PERF_EVENT_H
 CPPSRCS += pm_linux.cpp
 else
 CPPSRCS += pm_stub.cpp
 endif
 
-ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH)))
+ifeq (,$(filter-out WINNT,$(OS_ARCH)))
 INSTALLED_HEADERS += jscpucfg.h
 endif
 
 EXPORTS = $(INSTALLED_HEADERS)
 
 DASH_R		= -r
 
-ifneq (,$(filter OS2 WINCE WINNT,$(OS_ARCH)))
+ifneq (,$(filter OS2 WINNT,$(OS_ARCH)))
 SDK_LIBRARY = $(IMPORT_LIBRARY)
 else
 SDK_LIBRARY = $(SHARED_LIBRARY)
 endif
 
 include $(topsrcdir)/config/config.mk
 
 EXTRA_DSO_LDOPTS += $(NSPR_LIBS)
@@ -538,17 +532,17 @@ ifneq ($(OS_ARCH),Darwin)
 DTRACE_PROBE_OBJ = $(LIBRARY_NAME)-dtrace.$(OBJ_SUFFIX)
 endif
 MOZILLA_DTRACE_SRC = $(srcdir)/javascript-trace.d
 endif
 
 default::
 
 ifneq (,$(CROSS_COMPILE)$(filter-out WINNT OS2,$(OS_ARCH)))
-ifneq (,$(filter-out SYMBIAN WINCE,$(OS_ARCH)))
+ifneq (,$(filter-out SYMBIAN,$(OS_ARCH)))
 # nsinstall doesn't get built until we enter config/ in the exports phase,
 # so we'll have to manually ensure it gets built here if we want to use
 # $(EXPORTS)
 export:: config/nsinstall$(HOST_BIN_SUFFIX)
 $(PUBLIC) $(SDK_PUBLIC): config/nsinstall$(HOST_BIN_SUFFIX)
 
 config/nsinstall$(HOST_BIN_SUFFIX): $(srcdir)/config/nsinstall.c $(srcdir)/config/pathsub.c
 	$(MAKE) -C config/ nsinstall$(HOST_BIN_SUFFIX)
@@ -562,65 +556,64 @@ ifdef JS_HAS_CTYPES
 # in the right order.
 export::
 		$(call SUBMAKE,,ctypes/libffi)
 
 distclean clean::
 		$(call SUBMAKE,$@,ctypes/libffi)
 endif
 
-ifdef MOZ_SYNC_BUILD_FILES
 # Because the SpiderMonkey can be distributed and built independently
 # of the Mozilla source tree, it contains its own copies of many of
 # the files used by the top-level Mozilla build process, from the
 # 'config' and 'build' subtrees.
 #
 # To make it simpler to keep the copies in sync, we follow the policy
 # that the SpiderMonkey copies must always be exact copies of those in
 # the containing Mozilla tree.  If you've made a change in one, it
 # belongs in the other as well.  If the change isn't right for both
 # places, then that's something to bring up with the other developers.
 #
 # Some files are reasonable to diverge; for  example,
 # js/config/autoconf.mk.in doesn't need most of the stuff in
 # config/autoconf.mk.in.
-check-sync-dirs = $(PYTHON) $(srcdir)/config/check-sync-dirs.py
-check::
-	$(check-sync-dirs) $(srcdir)/config $(MOZ_SYNC_BUILD_FILES)/config
-	$(check-sync-dirs) $(srcdir)/build $(MOZ_SYNC_BUILD_FILES)/build
+check-sync-dirs-cmd = $(PYTHON) $(srcdir)/config/check-sync-dirs.py
+check-sync-dirs:
+	$(check-sync-dirs-cmd) $(srcdir)/config $(MOZ_SYNC_BUILD_FILES)/config
+	$(check-sync-dirs-cmd) $(srcdir)/build $(MOZ_SYNC_BUILD_FILES)/build
 
-check-valgrind::
-	$(check-sync-dirs) $(srcdir)/config $(MOZ_SYNC_BUILD_FILES)/config
-	$(check-sync-dirs) $(srcdir)/build $(MOZ_SYNC_BUILD_FILES)/build
+ifdef MOZ_SYNC_BUILD_FILES
+check:: check-sync-dirs
 endif
 
 # The "find any vanilla new/new[] calls" script is tailored to Linux, so
 # only run it there.  That should be enough to catch any such calls that
 # creep in.
+check-vanilla-new:
+	$(srcdir)/config/find_vanilla_new_calls $(LIBRARY)
+
 ifeq ($(OS_ARCH),Linux)
-check::
-	$(srcdir)/config/find_vanilla_new_calls $(LIBRARY)
+check:: check-vanilla-new
 endif
 
 # Help ensure that the number of OOM errors in SpiderMonkey doesn't increase.
 # If the number of OOM errors changes, update the number below. We intend this
 # number to go down over time, by fixing OOMs.
-ifdef DEBUG
 check-ooms:
 	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/config/find_OOM_errors.py --regression 125
 
-check:: check-ooms
+ifeq ($(MOZ_DEBUG),1)
+#check:: check-ooms
 endif
 
 ## Prevent regressing in our deprecation of non-preferred memory management functions.
 # We use all the files in the distribution so that different configurations
 # don't give different results. We skip the contents of objdirs using |find|
 # (it can't be done with %-expansion, because the files we want to skip aren't
 # in the vpath).
-ifneq ($(OS_ARCH),WINNT) # FIXME: this should be made work on Windows too.
 ALL_FILES=$(shell find $(srcdir) \( -name "*.cpp" -o -name "*.h" \) -not -path "*/dist/*")
 check-malloc-function-usage: $(filter-out %jsutil.h %jscntxt.h, $(ALL_FILES))
 
 	# js_malloc and friends are only used by other memory managers, and should
 	# never be used elsewhere directly.
 	$(srcdir)/config/check_source_count.py "\bjs_malloc\b" 0 \
 		"in Makefile.in" "cx->malloc_ or rt->malloc_" $^
 	$(srcdir)/config/check_source_count.py "\bjs_calloc\b" 0 \
@@ -630,32 +623,55 @@ check-malloc-function-usage: $(filter-ou
 	$(srcdir)/config/check_source_count.py "\bjs_free\b" 0 \
 		"in Makefile.in" "cx->free_" $^
 
 	# We desire these numbers to go down, not up. See "User guide to memory
 	# management within SpiderMonkey" in jsutil.h.
 	$(srcdir)/config/check_source_count.py OffTheBooks:: 54 \
 		"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
 	# This should go to zero, if possible.
-	$(srcdir)/config/check_source_count.py UnwantedForeground:: 36 \
+	$(srcdir)/config/check_source_count.py UnwantedForeground:: 35 \
 		"in Makefile.in" "{cx,rt}->{free_,delete_,array_delete}" $^
 
+ifneq ($(OS_ARCH),WINNT) # FIXME: this should be made work on Windows too.
 check:: check-malloc-function-usage
 endif
 
-ifndef WINCE
 JITFLAGS = ,m,j,mj,mjp,am,amj,amjp,amd
-check::
+check-jit-test::
 	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
 	        --no-slow --no-progress --tinderbox --jitflags=$(JITFLAGS) $(DIST)/bin/js$(BIN_SUFFIX)
 
-check-valgrind::
+check-jit-test-valgrind::
 	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
 	        --valgrind --no-slow --no-progress --tinderbox --jitflags=$(JITFLAGS) $(DIST)/bin/js$(BIN_SUFFIX)
-endif
+
+
+# jstests doesn't have a --jitflags option, so we need to loop, updating the
+# exit code (RC) after each invocation.
+# FIXME: MethodJIT doesn't work for 1 test case (bug 644393), so
+# --no-extensions is set to skip that test. Remove as soon as possible.
+check-jstests:
+	RC=0; \
+	for f in `echo "$(JITFLAGS)" | tr ',' '\n'`; \
+		do \
+			$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/tests/jstests.py \
+				--tinderbox --no-progress \
+				--no-extensions \
+				--timeout 300 \
+				--args="`echo $$f | sed 's/\(.\)/ -\1/g'`" \
+				$(DIST)/bin/js$(BIN_SUFFIX); \
+			RC=$$(( $$RC || $$?)); \
+		done; \
+	exit $$RC
+
+
+check:: check-jit-test
+#check:: check-jstests
+check-valgrind:: check-jit-test-valgrind
 
 DIST_GARBAGE = config.cache config.log config.status \
    config/autoconf.mk \
    unallmakefiles js-config js-config.h js-confdefs.h
 
 distclean::
 	cat unallmakefiles | $(XARGS) rm -f
 	$(RM) $(DIST_GARBAGE)
@@ -705,17 +721,17 @@ endif
 
 ifdef MOZ_VTUNE
 CXXFLAGS += -IC:/Program\ Files/Intel/VTune/Analyzer/Include
 EXTRA_DSO_LDOPTS += C:/Program\ Files/Intel/VTune/Analyzer/Lib/VtuneApi.lib
 LIBS +=  C:/Program\ Files/Intel/VTune/Analyzer/Lib/VtuneApi.lib
 endif
 
 # HP-UX does not require the extra linking of "-lm"
-ifeq (,$(filter HP-UX WINNT WINCE OS2,$(OS_ARCH)))
+ifeq (,$(filter HP-UX WINNT OS2,$(OS_ARCH)))
 EXTRA_LIBS	+= -lm
 endif
 
 # Prevent floating point errors caused by VC++ optimizations
 ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_)
 ifeq (,$(filter-out 1200 1300 1310,$(_MSC_VER)))
 CFLAGS += -Op
 else
@@ -814,26 +830,21 @@ jsdtoa.o: jsdtoa.cpp Makefile.in
 endif
 
 export:: jsautocfg.h
 
 ifeq (,$(CROSS_COMPILE)$(GNU_CC)$(filter-out WINNT,$(OS_ARCH)))
 jsautocfg.h:
 	$(TOUCH) $@
 else
-ifeq ($(OS_ARCH),WINCE)
-jsautocfg.h:
-	$(TOUCH) $@
-else
 jsautocfg.h: jscpucfg$(HOST_BIN_SUFFIX)
 	@$(RM) $@ jsautocfg.tmp
 	./jscpucfg > jsautocfg.tmp
 	mv jsautocfg.tmp $@
 endif
-endif
 
 # jscpucfg is a strange target
 # Needs to be built with the host compiler but needs to include
 # the mdcpucfg for the target so it needs the appropriate target defines
 ifdef HOST_NSPR_MDCPUCFG
 HOST_CXX := $(HOST_CXX) -DMDCPUCFG=$(TARGET_NSPR_MDCPUCFG)
 HOST_CXXFLAGS := $(patsubst -DXP_%,,$(HOST_CXXFLAGS))
 endif
@@ -848,24 +859,19 @@ ifneq ($(OS_TARGET),NTO)
 # QNX's compiler apparently can't build a binary directly from a source file.
 jscpucfg.o: jscpucfg.cpp Makefile.in
 	$(HOST_CXX) $(HOST_CXXFLAGS) -c $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) -o $@ $<
 
 jscpucfg: jscpucfg.o
 	$(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) -o $@ $<
 endif
 else
-ifeq ($(OS_ARCH),WINCE)
-jscpucfg$(HOST_BIN_SUFFIX):
-	echo no need to build jscpucfg $<
-else
 jscpucfg$(HOST_BIN_SUFFIX): jscpucfg.cpp Makefile.in
 	$(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) $(HOST_OUTOPTION)$@ $<
 endif
-endif
 
 # Compute the linker flags that programs linking against SpiderMonkey should
 # pass to get SpiderMonkey and its dependencies, beyond just the -L and -l
 # for the SpiderMonkey library itself.
 # - EXTRA_DSO_LDOPTS includes the NSPR -L and -l flags.
 # - OS_LIBS includes libraries selected by the configure script.
 # - EXTRA_LIBS includes libraries selected by this Makefile.
 JS_CONFIG_LIBS=$(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) 
--- a/js/src/config/autoconf.mk.in
+++ b/js/src/config/autoconf.mk.in
@@ -137,16 +137,17 @@ OS_LDFLAGS	= @LDFLAGS@
 OS_COMPILE_CFLAGS = $(OS_CPPFLAGS) @COMPILE_CFLAGS@
 OS_COMPILE_CXXFLAGS = $(OS_CPPFLAGS) @COMPILE_CXXFLAGS@
 
 OS_INCLUDES	= $(NSPR_CFLAGS)
 OS_LIBS		= @LIBS@
 ACDEFINES	= @MOZ_DEFINES@
 
 WARNINGS_AS_ERRORS = @WARNINGS_AS_ERRORS@
+FAIL_ON_WARNINGS = @FAIL_ON_WARNINGS@
 
 MOZ_OPTIMIZE	= @MOZ_OPTIMIZE@
 MOZ_OPTIMIZE_FLAGS = @MOZ_OPTIMIZE_FLAGS@
 MOZ_OPTIMIZE_LDFLAGS = @MOZ_OPTIMIZE_LDFLAGS@
 MOZ_OPTIMIZE_SIZE_TWEAK = @MOZ_OPTIMIZE_SIZE_TWEAK@
 
 MOZ_RTTI_FLAGS_ON = @_MOZ_RTTI_FLAGS_ON@
 MOZ_EXCEPTIONS_FLAGS_ON = @_MOZ_EXCEPTIONS_FLAGS_ON@
--- a/js/src/config/find_OOM_errors.py
+++ b/js/src/config/find_OOM_errors.py
@@ -65,17 +65,17 @@ def run(args, stdin=None):
     sys.exit(-1)
 
   stdout, stderr = stdout_worker.all, stderr_worker.all
   result = (stdout, stderr, proc.returncode)
   return result
 
 def get_js_files():
   (out, err, exit) = run('find ../jit-test/tests -name "*.js"')
-  if (err, exit) == ("", 0):
+  if (err, exit) != ("", 0):
     sys.exit("Wrong directory, run from an objdir")
   return out.split()
 
 
 
 #####################################################################
 # Blacklisting
 #####################################################################
@@ -186,35 +186,35 @@ whitelist.add(r"('', 'out of memory\nout
 
 #####################################################################
 # Program
 #####################################################################
 
 # Options
 parser = OptionParser(usage=usage)
 parser.add_option("-r", "--regression", action="store", metavar="REGRESSION_COUNT", help=help,
-                  type="int", dest="regression", default=0) # TODO: support a value of zero, eventually
+                  type="int", dest="regression", default=None)
                   
 (OPTIONS, args) = parser.parse_args()
 
 
-if OPTIONS.regression:
+if OPTIONS.regression != None:
   # TODO: This should be expanded as we get a better hang of the OOM problems.
   # For now, we'll just check that the number of OOMs in one short file does not
   # increase.
   files = ["../jit-test/tests/arguments/args-createontrace.js"]
 else:
   files = get_js_files()
 
   # Use a command-line arg to reduce the set of files
   if len (args):
     files = [f for f in files if f.find(args[0]) != -1]
 
 
-if OPTIONS.regression:
+if OPTIONS.regression == None:
   # Don't use a logfile, this is automated for tinderbox.
   log = file("../OOM_log", "w")
 
 
 num_failures = 0
 for f in files:
 
   # Run it once to establish boundaries
@@ -224,28 +224,30 @@ for f in files:
   max = int(max)
   
   # OOMs don't recover well for the first 20 allocations or so.
   # TODO: revisit this.
   for i in range(20, max): 
 
     if OPTIONS.regression == None:
       print "Testing allocation %d/%d in %s" % (i,max,f)
+    else:
+      sys.stdout.write('.') # something short for tinderbox, no space or \n
 
     command = (command_template + ' -A %d') % (f, i)
     out, err, exit = run(command)
 
     # Success (5 is SM's exit code for controlled errors)
     if exit == 5 and err.find("out of memory") != -1:
       continue
 
     # Failure
     else:
 
-      if OPTIONS.regression:
+      if OPTIONS.regression != None:
         # Just count them
         num_failures += 1
         continue
 
       #########################################################################
       # The regression tests ends above. The rest of this is for running  the
       # script manually.
       #########################################################################
@@ -309,22 +311,23 @@ for f in files:
 
       log.write ("\n")
 
       log.write ("Valgrind info:\n" + vout)
       log.write ("\n")
       log.write ("\n")
       log.flush()
 
-  if not OPTIONS.regression == None:
+  if OPTIONS.regression == None:
     count_lines()
 
+print '\n',
 
 # Do the actual regression check
-if OPTIONS.regression:
+if OPTIONS.regression != None:
   expected_num_failures = OPTIONS.regression
 
   if num_failures != expected_num_failures:
 
     print "TEST-UNEXPECTED-FAIL |",
     if num_failures > expected_num_failures:
       print "More out-of-memory errors were found (%s) than expected (%d). This probably means an allocation site has been added without a NULL-check. If this is unavoidable, you can account for it by updating Makefile.in." % (num_failures, expected_num_failures),
     else:
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4778,16 +4778,27 @@ MOZ_ARG_DISABLE_BOOL(warnings-as-errors,
 [  --disable-warnings-as-errors
                           Disable treating of warnings as errors],
     MOZ_DISABLE_WARNINGS_AS_ERRORS=1,
     MOZ_DISABLE_WARNINGS_AS_ERRORS= )
 if test "$MOZ_DISABLE_WARNINGS_AS_ERRORS"; then
    WARNINGS_AS_ERRORS=''
 fi
 
+dnl ========================================================
+dnl = Enable treating compile warnings as errors
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(sm-fail-on-warnings,
+[  --enable-sm-fail-on-warnings
+                          Enable warnings as errors],
+    FAIL_ON_WARNINGS=1,
+    FAIL_ON_WARNINGS= )
+
+AC_SUBST(FAIL_ON_WARNINGS)
+
 dnl = Enable trace malloc
 dnl ========================================================
 NS_TRACE_MALLOC=${MOZ_TRACE_MALLOC}
 MOZ_ARG_ENABLE_BOOL(trace-malloc,
 [  --enable-trace-malloc   Enable malloc tracing],
     NS_TRACE_MALLOC=1,
     NS_TRACE_MALLOC= )
 if test "$NS_TRACE_MALLOC"; then
@@ -5992,19 +6003,16 @@ if test "$JS_HAS_CTYPES"; then
   if test "$MOZ_DEBUG"; then
     ac_configure_args="$ac_configure_args --enable-debug"
   fi
   if test "$DSO_PIC_CFLAGS"; then
     ac_configure_args="$ac_configure_args --with-pic"
   fi
   if test "$CROSS_COMPILE"; then
     case "$target" in
-    *-mingw*)
-      ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\" CC=\"$CC\""
-      ;;
     *-android*)
       CFLAGS="$ANDROID_CFLAGS"
       CPPFLAGS="$ANDROID_CPPFLAGS"
       LDFLAGS="$ANDROID_LDFLAGS"
 
       export AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS CFLAGS LDFLAGS
 
       ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\""
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -210,16 +210,23 @@ def check_output(out, err, rc, allow_oom
 
     if rc != 0:
         # Allow a non-zero exit code if we want to allow OOM, but only if we
         # actually got OOM.
         return allow_oom and ': out of memory' in err
 
     return True
 
+def print_tinderbox(label, test, message=None):
+    jitflags = " ".join(test.jitflags)
+    result = "%s | jit_test.py %-15s| %s" % (label, jitflags, test.path)
+    if message:
+        result += ": " + message
+    print result
+
 def run_tests(tests, test_dir, lib_dir):
     pb = None
     if not OPTIONS.hide_progress and not OPTIONS.show_cmd:
         try:
             from progressbar import ProgressBar
             pb = ProgressBar('', len(tests), 16)
         except ImportError:
             pass
@@ -233,34 +240,33 @@ def run_tests(tests, test_dir, lib_dir):
             ok, out, err, code = run_test(test, lib_dir)
             doing = 'after %s'%test.path
 
             if not ok:
                 failures.append([ test, out, err, code ])
 
             if OPTIONS.tinderbox:
                 if ok:
-                    print('TEST-PASS | jit_test.py | %s'%test.path)
+                    print_tinderbox("TEST-PASS", test);
                 else:
                     lines = [ _ for _ in out.split('\n') + err.split('\n')
                               if _ != '' ]
                     if len(lines) >= 1:
                         msg = lines[-1]
                     else:
                         msg = ''
-                    print('TEST-UNEXPECTED-FAIL | jit_test.py | %s: %s'%
-                          (test.path, msg))
+                    print_tinderbox("TEST-UNEXPECTED-FAIL", test, msg);
 
             n = i + 1
             if pb:
                 pb.label = '[%4d|%4d|%4d]'%(n - len(failures), len(failures), n)
                 pb.update(n)
         complete = True
     except KeyboardInterrupt:
-        print('TEST-UNEXPECTED_FAIL | jit_test.py | %s'%test.path)
+        print_tinderbox("TEST-UNEXPECTED-FAIL", test);
 
     if pb:
         pb.finish()
 
     if failures:
         if OPTIONS.write_failures:
             try:
                 out = open(OPTIONS.write_failures, 'w')
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -302,17 +302,17 @@ MSG_DEF(JSMSG_NON_LIST_XML_METHOD,    21
 MSG_DEF(JSMSG_BAD_DELETE_OPERAND,     220, 0, JSEXN_REFERENCEERR, "invalid delete operand")
 MSG_DEF(JSMSG_BAD_INCOP_OPERAND,      221, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
 MSG_DEF(JSMSG_UNEXPECTED_TYPE,        222, 2, JSEXN_TYPEERR, "{0} is {1}")
 MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK,  223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block")
 MSG_DEF(JSMSG_BAD_OBJECT_INIT,        224, 0, JSEXN_SYNTAXERR, "invalid object initializer")
 MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS,   225, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties")
 MSG_DEF(JSMSG_EVAL_ARITY,             226, 0, JSEXN_TYPEERR, "eval accepts only one parameter")
 MSG_DEF(JSMSG_MISSING_FUN_ARG,        227, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
-MSG_DEF(JSMSG_JSON_BAD_PARSE,         228, 0, JSEXN_SYNTAXERR, "JSON.parse")
+MSG_DEF(JSMSG_JSON_BAD_PARSE,         228, 1, JSEXN_SYNTAXERR, "JSON.parse: {0}")
 MSG_DEF(JSMSG_JSON_BAD_STRINGIFY,     229, 0, JSEXN_ERR, "JSON.stringify")
 MSG_DEF(JSMSG_XDR_CLOSURE_WRAPPER,    230, 1, JSEXN_INTERNALERR, "can't XDR closure wrapper for function {0}")
 MSG_DEF(JSMSG_NOT_NONNULL_OBJECT,     231, 0, JSEXN_TYPEERR, "value is not a non-null object")
 MSG_DEF(JSMSG_DEPRECATED_OCTAL,       232, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated")
 MSG_DEF(JSMSG_STRICT_CODE_WITH,       233, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements")
 MSG_DEF(JSMSG_DUPLICATE_PROPERTY,     234, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal")
 MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 235, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated")
 MSG_DEF(JSMSG_DEPRECATED_ASSIGN,      236, 1, JSEXN_SYNTAXERR, "assignment to {0} is deprecated")
--- a/js/src/jsapi-tests/Makefile.in
+++ b/js/src/jsapi-tests/Makefile.in
@@ -62,40 +62,48 @@ CPPSRCS = \
   testFuncCallback.cpp \
   testGCChunkAlloc.cpp \
   testGetPropertyDefault.cpp \
   testIntString.cpp \
   testLookup.cpp \
   testLooselyEqual.cpp \
   testNewObject.cpp \
   testOps.cpp \
+  testParseJSON.cpp \
   testPropCache.cpp \
-  testRegExpInstanceProperties.cpp \
   testResolveRecursion.cpp \
   testSameValue.cpp \
   testScriptObject.cpp \
   testSetProperty.cpp \
   testStringBuffer.cpp \
   testThreadGC.cpp \
   testThreads.cpp \
   testTrap.cpp \
   testUTF8.cpp \
   testVersion.cpp \
   testXDR.cpp \
   testCustomIterator.cpp \
   $(NULL)
 
+# Disabled: an entirely unrelated test seems to cause this to fail.  Moreover,
+# given the test's dependence on interactions between the compiler, the GC, and
+# conservative stack scanning, the fix isn't obvious: more investigation
+# needed.
+#CPPSRCS += \
+#  testRegExpInstanceProperties.cpp \
+#  $(NULL)
+
 DEFINES         += -DEXPORT_JS_API
 
+# Some platforms that have stdint.h include it in system headers.  So
+# to reliably get limit macros defined, we'd always have to define the
+# one below before including any header, but that's obscure and
+# fragile, so we do it here.
+DEFINES         += -D__STDC_LIMIT_MACROS
+
 LIBS      = $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX) $(NSPR_LIBS)
 
 LOCAL_INCLUDES += -I$(topsrcdir) -I..
 
-ifdef _MSC_VER
-ifdef WINCE
-WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup
-endif
-endif
-
 include $(topsrcdir)/config/rules.mk
 
 check::
 	$(wildcard $(RUN_TEST_PROGRAM)) $(DIST)/bin/jsapi-tests$(BIN_SUFFIX)
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testParseJSON.cpp
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ */
+
+#include <limits>
+#include <math.h>
+
+#include "tests.h"
+#include "jsstr.h"
+
+class AutoInflatedString {
+    JSContext * const cx;
+    jschar *chars_;
+    size_t length_;
+
+  public:
+    AutoInflatedString(JSContext *cx) : cx(cx), chars_(NULL), length_(0) { }
+    ~AutoInflatedString() {
+        JS_free(cx, chars_);
+    }
+
+    template<size_t N> void operator=(const char (&str)[N]) {
+        length_ = N - 1;
+        chars_ = js_InflateString(cx, str, &length_);
+        if (!chars_)
+            abort();
+    }
+
+    const jschar *chars() const { return chars_; }
+    size_t length() const { return length_; }
+};
+
+template<size_t N> JSFlatString *
+NewString(JSContext *cx, const jschar (&chars)[N])
+{
+    return js_NewStringCopyN(cx, chars, N);
+}
+
+BEGIN_TEST(testParseJSON_success)
+{
+    // Primitives
+    CHECK(TryParse(cx, "true", JSVAL_TRUE));
+    CHECK(TryParse(cx, "false", JSVAL_FALSE));
+    CHECK(TryParse(cx, "null", JSVAL_NULL));
+    CHECK(TryParse(cx, "0", INT_TO_JSVAL(0)));
+    CHECK(TryParse(cx, "1", INT_TO_JSVAL(1)));
+    CHECK(TryParse(cx, "-1", INT_TO_JSVAL(-1)));
+    CHECK(TryParse(cx, "1", DOUBLE_TO_JSVAL(1)));
+    CHECK(TryParse(cx, "1.75", DOUBLE_TO_JSVAL(1.75)));
+    CHECK(TryParse(cx, "9e9", DOUBLE_TO_JSVAL(9e9)));
+    CHECK(TryParse(cx, "9e99999", DOUBLE_TO_JSVAL(std::numeric_limits<jsdouble>::infinity())));
+
+    JSFlatString *str;
+
+    const jschar emptystr[] = { '\0' };
+    str = js_NewStringCopyN(cx, emptystr, 0);
+    CHECK(str);
+    CHECK(TryParse(cx, "\"\"", STRING_TO_JSVAL(str)));
+
+    const jschar nullstr[] = { '\0' };
+    str = NewString(cx, nullstr);
+    CHECK(str);
+    CHECK(TryParse(cx, "\"\\u0000\"", STRING_TO_JSVAL(str)));
+
+    const jschar backstr[] = { '\b' };
+    str = NewString(cx, backstr);
+    CHECK(str);
+    CHECK(TryParse(cx, "\"\\b\"", STRING_TO_JSVAL(str)));
+    CHECK(TryParse(cx, "\"\\u0008\"", STRING_TO_JSVAL(str)));
+
+    const jschar newlinestr[] = { '\n', };
+    str = NewString(cx, newlinestr);
+    CHECK(str);
+    CHECK(TryParse(cx, "\"\\n\"", STRING_TO_JSVAL(str)));
+    CHECK(TryParse(cx, "\"\\u000A\"", STRING_TO_JSVAL(str)));
+
+
+    // Arrays
+    jsval v, v2;
+    JSObject *obj;
+
+    CHECK(Parse(cx, "[]", &v));
+    CHECK(!JSVAL_IS_PRIMITIVE(v));
+    obj = JSVAL_TO_OBJECT(v);
+    CHECK(JS_IsArrayObject(cx, obj));
+    CHECK(JS_GetProperty(cx, obj, "length", &v2));
+    CHECK_SAME(v2, JSVAL_ZERO);
+
+    CHECK(Parse(cx, "[1]", &v));
+    CHECK(!JSVAL_IS_PRIMITIVE(v));
+    obj = JSVAL_TO_OBJECT(v);
+    CHECK(JS_IsArrayObject(cx, obj));
+    CHECK(JS_GetProperty(cx, obj, "0", &v2));
+    CHECK_SAME(v2, JSVAL_ONE);
+    CHECK(JS_GetProperty(cx, obj, "length", &v2));
+    CHECK_SAME(v2, JSVAL_ONE);
+
+
+    // Objects
+    CHECK(Parse(cx, "{}", &v));
+    CHECK(!JSVAL_IS_PRIMITIVE(v));
+    obj = JSVAL_TO_OBJECT(v);
+    CHECK(!JS_IsArrayObject(cx, obj));
+
+    CHECK(Parse(cx, "{ \"f\": 17 }", &v));
+    CHECK(!JSVAL_IS_PRIMITIVE(v));
+    obj = JSVAL_TO_OBJECT(v);
+    CHECK(!JS_IsArrayObject(cx, obj));
+    CHECK(JS_GetProperty(cx, obj, "f", &v2));
+    CHECK_SAME(v2, INT_TO_JSVAL(17));
+
+    return true;
+}
+
+template<size_t N> inline bool
+Parse(JSContext *cx, const char (&input)[N], jsval *vp)
+{
+    AutoInflatedString str(cx);
+    str = input;
+    CHECK(JS_ParseJSON(cx, str.chars(), str.length(), vp));
+    return true;
+}
+
+template<size_t N> inline bool
+TryParse(JSContext *cx, const char (&input)[N], const jsval &expected)
+{
+    AutoInflatedString str(cx);
+    jsval v;
+    str = input;
+    CHECK(JS_ParseJSON(cx, str.chars(), str.length(), &v));
+    CHECK_SAME(v, expected);
+    return true;
+}
+END_TEST(testParseJSON_success)
+
+BEGIN_TEST(testParseJSON_error)
+{
+    CHECK(Error(cx, "["));
+    CHECK(Error(cx, "[,]"));
+    CHECK(Error(cx, "[1,]"));
+    CHECK(Error(cx, "{a:2}"));
+    CHECK(Error(cx, "{\"a\":2,}"));
+    CHECK(Error(cx, "]"));
+    CHECK(Error(cx, "'bad string'"));
+    CHECK(Error(cx, "\""));
+    CHECK(Error(cx, "{]"));
+    CHECK(Error(cx, "[}"));
+    return true;
+}
+
+template<size_t N> inline bool
+Error(JSContext *cx, const char (&input)[N])
+{
+    AutoInflatedString str(cx);
+    jsval dummy;
+    str = input;
+    CHECK(!JS_ParseJSON(cx, str.chars(), str.length(), &dummy));
+    JS_ClearPendingException(cx);
+    return true;
+}
+END_TEST(testParseJSON_error)
+
+static JSBool
+Censor(JSContext *cx, uintN argc, jsval *vp)
+{
+    JS_ASSERT(argc == 2);
+#ifdef DEBUG
+    jsval *argv = JS_ARGV(cx, vp);
+    JS_ASSERT(JSVAL_IS_STRING(argv[0]));
+#endif
+    JS_SET_RVAL(cx, vp, JSVAL_NULL);
+    return true;
+}
+
+BEGIN_TEST(testParseJSON_reviver)
+{
+    JSFunction *fun = JS_NewFunction(cx, Censor, 0, 0, global, "censor");
+    CHECK(fun);
+
+    jsval filter = OBJECT_TO_JSVAL(JS_GetFunctionObject(fun));
+
+    CHECK(TryParse(cx, "true", filter));
+    CHECK(TryParse(cx, "false", filter));
+    CHECK(TryParse(cx, "null", filter));
+    CHECK(TryParse(cx, "1", filter));
+    CHECK(TryParse(cx, "1.75", filter));
+    CHECK(TryParse(cx, "[]", filter));
+    CHECK(TryParse(cx, "[1]", filter));
+    CHECK(TryParse(cx, "{}", filter));
+    return true;
+}
+
+template<size_t N> inline bool
+TryParse(JSContext *cx, const char (&input)[N], jsval filter)
+{
+    AutoInflatedString str(cx);
+    jsval v;
+    str = input;
+    CHECK(JS_ParseJSONWithReviver(cx, str.chars(), str.length(), filter, &v));
+    CHECK_SAME(v, JSVAL_NULL);
+    return true;
+}
+END_TEST(testParseJSON_reviver)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -131,20 +131,20 @@ class AutoVersionAPI
 
   public:
     explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
       : cx(cx),
         oldDefaultVersion(cx->getDefaultVersion()),
         oldHasVersionOverride(cx->isVersionOverridden()),
         oldVersionOverride(oldHasVersionOverride ? cx->findVersion() : JSVERSION_UNKNOWN)
 #ifdef DEBUG
-        , oldCompileOptions(cx->getCompileOptions()) 
+        , oldCompileOptions(cx->getCompileOptions())
 #endif
     {
-        /* 
+        /*
          * Note: ANONFUNFIX in newVersion is ignored for backwards
          * compatibility, must be set via JS_SetOptions. (Because of this, we
          * inherit the current ANONFUNFIX setting from the options.
          */
         VersionSetAnonFunFix(&newVersion, OptionsHasAnonFunFix(cx->getCompileOptions()));
         this->newVersion = newVersion;
         cx->clearVersionOverride();
         cx->setDefaultVersion(newVersion);
@@ -1228,17 +1228,17 @@ JS_EnterCrossCompartmentCallScript(JSCon
     CHECK_REQUEST(cx);
 
     JS_ASSERT(target);
     JSObject *scriptObject = target->u.object;
     if (!scriptObject) {
         SwitchToCompartment sc(cx, target->compartment);
         scriptObject = JS_NewGlobalObject(cx, &dummy_class);
         if (!scriptObject)
-            return NULL;        
+            return NULL;
     }
     return JS_EnterCrossCompartmentCall(cx, scriptObject);
 }
 
 JS_PUBLIC_API(void)
 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
 {
     AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
@@ -1271,17 +1271,17 @@ bool
 AutoEnterScriptCompartment::enter(JSContext *cx, JSScript *target)
 {
     JS_ASSERT(!call);
     if (cx->compartment == target->compartment) {
         call = reinterpret_cast<JSCrossCompartmentCall*>(1);
         return true;
     }
     call = JS_EnterCrossCompartmentCallScript(cx, target);
-    return call != NULL;    
+    return call != NULL;
 }
 
 } /* namespace JS */
 
 JS_PUBLIC_API(void *)
 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
 {
     CHECK_REQUEST(cx);
@@ -2927,18 +2927,28 @@ JS_GetClass(JSObject *obj)
     return Jsvalify(obj->getClass());
 }
 #endif
 
 JS_PUBLIC_API(JSBool)
 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
 {
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj);
-    return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
+#ifdef DEBUG
+    if (argv) {
+        assertSameCompartment(cx, obj);
+        assertSameCompartment(cx, JSValueArray(argv - 2, 2));
+    }
+#endif
+    if (!obj || obj->getJSClass() != clasp) {
+        if (argv)
+            ReportIncompatibleMethod(cx, Valueify(argv - 2), Valueify(clasp));
+        return false;
+    }
+    return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
 {
     assertSameCompartment(cx, obj, v);
     return HasInstance(cx, obj, Valueify(&v), bp);
 }
@@ -2954,17 +2964,17 @@ JS_SetPrivate(JSContext *cx, JSObject *o
 {
     obj->setPrivate(data);
     return true;
 }
 
 JS_PUBLIC_API(void *)
 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
 {
-    if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)))
+    if (!JS_InstanceOf(cx, obj, clasp, argv))
         return NULL;
     return obj->getPrivate();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetPrototype(JSContext *cx, JSObject *obj)
 {
     JSObject *proto;
@@ -4707,17 +4717,17 @@ CompileFileHelper(JSContext *cx, JSObjec
                                      cx->findVersion());
     cx->free_(buf);
     if (!script)
         return NULL;
 
     JSObject *scriptObj = js_NewScriptObject(cx, script);
     if (!scriptObj)
         js_DestroyScript(cx, script);
-    
+
     return scriptObj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
 
@@ -4736,17 +4746,17 @@ JS_CompileFile(JSContext *cx, JSObject *
                 break;
             }
         }
 
         scriptObj = CompileFileHelper(cx, obj, NULL, filename, fp);
         if (fp != stdin)
             fclose(fp);
     } while (false);
-    
+
     LAST_FRAME_CHECKS(cx, scriptObj);
     return scriptObj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename,
                                   FILE *file, JSPrincipals *principals)
 {
@@ -5608,16 +5618,32 @@ JS_PUBLIC_API(JSBool)
 JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, reviver);
     return js_FinishJSONParse(cx, jp, Valueify(reviver));
 }
 
 JS_PUBLIC_API(JSBool)
+JS_ParseJSON(JSContext *cx, const jschar *chars, uint32 len, jsval *vp)
+{
+    CHECK_REQUEST(cx);
+
+    return ParseJSONWithReviver(cx, chars, len, NullValue(), Valueify(vp));
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32 len, jsval reviver, jsval *vp)
+{
+    CHECK_REQUEST(cx);
+
+    return ParseJSONWithReviver(cx, chars, len, Valueify(reviver), Valueify(vp));
+}
+
+JS_PUBLIC_API(JSBool)
 JS_ReadStructuredClone(JSContext *cx, const uint64 *buf, size_t nbytes,
                        uint32 version, jsval *vp,
                        const JSStructuredCloneCallbacks *optionalCallbacks,
                        void *closure)
 {
     if (version > JS_STRUCTURED_CLONE_VERSION) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
         return false;
@@ -6150,17 +6176,17 @@ JS_PUBLIC_API(void)
 JS_SetGCZeal(JSContext *cx, uint8 zeal)
 {
     cx->runtime->gcZeal = zeal;
 }
 #endif
 
 /************************************************************************/
 
-#if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
+#if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN)
 
 #include "jswin.h"
 
 /*
  * Initialization routine for the JS DLL.
  */
 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3304,16 +3304,22 @@ 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, jsval reviver);
 
+JS_PUBLIC_API(JSBool)
+JS_ParseJSON(JSContext *cx, const jschar *chars, uint32 len, jsval *vp);
+
+JS_PUBLIC_API(JSBool)
+JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32 len, jsval reviver, jsval *vp);
+
 /************************************************************************/
 
 /* API for the HTML5 internal structured cloning algorithm. */
 
 /* The maximum supported structured-clone serialization format version. */
 #define JS_STRUCTURED_CLONE_VERSION 1
 
 struct JSStructuredCloneCallbacks {
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -167,17 +167,17 @@ js_StringIsIndex(JSLinearString *str, js
         {
             *indexp = index;
             return true;
         }
     }
     return false;
 }
 
-static bool 
+static bool
 ValueToLength(JSContext *cx, Value* vp, jsuint* plength)
 {
     if (vp->isInt32()) {
         int32_t i = vp->toInt32();
         if (i < 0)
             goto error;
 
         *plength = (jsuint)(i);
@@ -298,25 +298,25 @@ JSObject::willBeSparseDenseArray(uintN r
     JS_ASSERT(isDenseArray());
     JS_ASSERT(requiredCapacity > MIN_SPARSE_INDEX);
 
     uintN cap = numSlots();
     JS_ASSERT(requiredCapacity >= cap);
 
     if (requiredCapacity >= JSObject::NSLOTS_LIMIT)
         return true;
-    
+
     uintN minimalDenseCount = requiredCapacity / 4;
     if (newElementsHint >= minimalDenseCount)
         return false;
     minimalDenseCount -= newElementsHint;
 
     if (minimalDenseCount > cap)
         return true;
-    
+
     Value *elems = getDenseArrayElements();
     for (uintN i = 0; i < cap; i++) {
         if (!elems[i].isMagic(JS_ARRAY_HOLE) && !--minimalDenseCount)
             return false;
     }
     return true;
 }
 
@@ -480,17 +480,17 @@ SetArrayElement(JSContext *cx, JSObject 
     return obj->setProperty(cx, idr.id(), &tmp, true);
 }
 
 #ifdef JS_TRACER
 JSBool JS_FASTCALL
 js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
 {
 #ifdef DEBUG
-    Class *origObjClasp = obj->clasp; 
+    Class *origObjClasp = obj->clasp;
 #endif
     jsuint u = jsuint(i);
     JSBool ret = (obj->ensureDenseArrayElements(cx, u, 1) == JSObject::ED_OK);
 
     /* Partially check the CallInfo's storeAccSet is correct. */
     JS_ASSERT(obj->clasp == origObjClasp);
     return ret;
 }
@@ -1095,232 +1095,282 @@ JSObject::makeDenseArraySlow(JSContext *
      * will create an emptyShape whose class is &js_SlowArrayClass, to ensure
      * that delegating instances can share shapes in the tree rooted at the
      * proto's empty shape.
      */
     clasp = &js_SlowArrayClass;
     return true;
 }
 
-/* Transfer ownership of buffer to returned string. */
-static inline JSBool
-BufferToString(JSContext *cx, StringBuffer &sb, Value *rval)
+#if JS_HAS_TOSOURCE
+class ArraySharpDetector
 {
-    JSString *str = sb.finishString();
-    if (!str)
-        return false;
-    rval->setString(str);
-    return true;
-}
-
-#if JS_HAS_TOSOURCE
+    JSContext *cx;
+    jschar *chars;
+    JSHashEntry *he;
+    bool sharp;
+
+  public:
+    ArraySharpDetector(JSContext *cx)
+      : cx(cx),
+        chars(NULL),
+        he(NULL),
+        sharp(false)
+    {}
+
+    bool init(JSObject *obj) {
+        he = js_EnterSharpObject(cx, obj, NULL, &chars);
+        if (!he)
+            return false;
+        sharp = IS_SHARP(he);
+        return true;
+    }
+
+    bool initiallySharp() const {
+        JS_ASSERT_IF(sharp, hasSharpChars());
+        return sharp;
+    }
+
+    void makeSharp() {
+        MAKE_SHARP(he);
+    }
+
+    bool hasSharpChars() const {
+        return chars != NULL;
+    }
+
+    jschar *takeSharpChars() {
+        jschar *ret = chars;
+        chars = NULL;
+        return ret;
+    }
+
+    ~ArraySharpDetector() {
+        if (chars)
+            cx->free_(chars);
+        if (he && !sharp)
+            js_LeaveSharpObject(cx, NULL);
+    }
+};
+
 static JSBool
 array_toSource(JSContext *cx, uintN argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
-    if (!obj->isSlowArray() && !InstanceOf(cx, obj, &js_ArrayClass, vp + 2))
+    if (!obj->isArray()) {
+        ReportIncompatibleMethod(cx, vp, &js_ArrayClass);
         return false;
-
-    /* Find joins or cycles in the reachable object graph. */
-    jschar *sharpchars;
-    JSHashEntry *he = js_EnterSharpObject(cx, obj, NULL, &sharpchars);
-    if (!he)
+    }
+
+    ArraySharpDetector detector(cx);
+    if (!detector.init(obj))
         return false;
-    bool initiallySharp = IS_SHARP(he);
-
-    /* After this point, all paths exit through the 'out' label. */
-    MUST_FLOW_THROUGH("out");
-    bool ok = false;
-
-    /*
-     * This object will take responsibility for the jschar buffer until the
-     * buffer is transferred to the returned JSString.
-     */
+
     StringBuffer sb(cx);
 
-    /* Cycles/joins are indicated by sharp objects. */
 #if JS_HAS_SHARP_VARS
-    if (IS_SHARP(he)) {
-        JS_ASSERT(sharpchars != 0);
-        sb.replaceRawBuffer(sharpchars, js_strlen(sharpchars));
+    if (detector.initiallySharp()) {
+        jschar *chars = detector.takeSharpChars();
+        sb.replaceRawBuffer(chars, js_strlen(chars));
         goto make_string;
-    } else if (sharpchars) {
-        MAKE_SHARP(he);
-        sb.replaceRawBuffer(sharpchars, js_strlen(sharpchars));
+    } else if (detector.hasSharpChars()) {
+        detector.makeSharp();
+        jschar *chars = detector.takeSharpChars();
+        sb.replaceRawBuffer(chars, js_strlen(chars));
     }
 #else
-    if (IS_SHARP(he)) {
+    if (detector.initiallySharp()) {
         if (!sb.append("[]"))
-            goto out;
-        cx->free_(sharpchars);
+            return false;
         goto make_string;
     }
 #endif
 
     if (!sb.append('['))
-        goto out;
+        return false;
 
     jsuint length;
     if (!js_GetLengthProperty(cx, obj, &length))
-        goto out;
+        return false;
 
     for (jsuint index = 0; index < length; index++) {
-        /* Use vp to locally root each element value. */
         JSBool hole;
+        Value tmp;
         if (!JS_CHECK_OPERATION_LIMIT(cx) ||
-            !GetElement(cx, obj, index, &hole, vp)) {
-            goto out;
+            !GetElement(cx, obj, index, &hole, &tmp)) {
+            return false;
         }
 
         /* Get element's character string. */
         JSString *str;
         if (hole) {
             str = cx->runtime->emptyString;
         } else {
-            str = js_ValueToSource(cx, *vp);
+            str = js_ValueToSource(cx, tmp);
             if (!str)
-                goto out;
+                return false;
         }
-        vp->setString(str);
-
-        const jschar *chars = str->getChars(cx);
-        if (!chars)
-            goto out;
 
         /* Append element to buffer. */
-        if (!sb.append(chars, chars + str->length()))
-            goto out;
+        if (!sb.append(str))
+            return false;
         if (index + 1 != length) {
             if (!sb.append(", "))
-                goto out;
+                return false;
         } else if (hole) {
             if (!sb.append(','))
-                goto out;
+                return false;
         }
     }
 
     /* Finalize the buffer. */
     if (!sb.append(']'))
-        goto out;
+        return false;
 
   make_string:
-    if (!BufferToString(cx, sb, vp))
-        goto out;
-
-    ok = true;
-
-  out:
-    if (!initiallySharp)
-        js_LeaveSharpObject(cx, NULL);
-    return ok;
+    JSString *str = sb.finishString();
+    if (!str)
+        return false;
+
+    JS_SET_RVAL(cx, vp, StringValue(str));
+    return true;
 }
 #endif
 
+class AutoArrayCycleDetector
+{
+    JSContext *cx;
+    JSObject *obj;
+    uint32 genBefore;
+    BusyArraysSet::AddPtr hashPointer;
+    bool cycle;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+  public:
+    AutoArrayCycleDetector(JSContext *cx, JSObject *obj JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : cx(cx),
+        obj(obj),
+        cycle(true)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+
+    bool init()
+    {
+        BusyArraysSet &set = cx->busyArrays;
+        hashPointer = set.lookupForAdd(obj);
+        if (!hashPointer) {
+            if (!set.add(hashPointer, obj))
+                return false;
+            cycle = false;
+            genBefore = set.generation();
+        }
+        return true;
+    }
+
+    ~AutoArrayCycleDetector()
+    {
+        if (!cycle) {
+            if (genBefore == cx->busyArrays.generation())
+                cx->busyArrays.remove(hashPointer);
+            else
+                cx->busyArrays.remove(obj);
+        }
+    }
+
+    bool foundCycle() { return cycle; }
+
+  protected:
+};
+
 static JSBool
 array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
                    JSString *sepstr, Value *rval)
 {
     JS_CHECK_RECURSION(cx, return false);
 
-    /* Get characters to use for the separator. */
     static const jschar comma = ',';
     const jschar *sep;
     size_t seplen;
     if (sepstr) {
         seplen = sepstr->length();
         sep = sepstr->getChars(cx);
         if (!sep)
             return false;
     } else {
         sep = &comma;
         seplen = 1;
     }
 
-    /*
-     * Use HashTable entry as the cycle indicator. On first visit, create the
-     * entry, and, when leaving, remove the entry.
-     */
-    BusyArraysMap::AddPtr hashp = cx->busyArrays.lookupForAdd(obj);
-    uint32 genBefore;
-    if (!hashp) {
-        /* Not in hash table, so not a cycle. */
-        if (!cx->busyArrays.add(hashp, obj))
-            return false;
-        genBefore = cx->busyArrays.generation();
-    } else {
-        /* Cycle, so return empty string. */
+    AutoArrayCycleDetector detector(cx, obj);
+    if (!detector.init())
+        return false;
+
+    if (detector.foundCycle()) {
         rval->setString(cx->runtime->atomState.emptyAtom);
         return true;
     }
 
-    AutoObjectRooter tvr(cx, obj);
-
-    /* After this point, all paths exit through the 'out' label. */
-    MUST_FLOW_THROUGH("out");
-    bool ok = false;
-
-    /*
-     * This object will take responsibility for the jschar buffer until the
-     * buffer is transferred to the returned JSString.
-     */
-    StringBuffer sb(cx);
-
     jsuint length;
     if (!js_GetLengthProperty(cx, obj, &length))
-        goto out;
-
-    for (jsuint index = 0; index < length; index++) {
-        /* Use rval to locally root each element value. */
-        JSBool hole;
-        if (!JS_CHECK_OPERATION_LIMIT(cx) ||
-            !GetElement(cx, obj, index, &hole, rval)) {
-            goto out;
+        return false;
+
+    StringBuffer sb(cx);
+
+    if (!locale && !seplen && obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj)) {
+        /* Elements beyond 'capacity' are 'undefined' and thus can be ignored. */
+        Value *beg = obj->getDenseArrayElements();
+        Value *end = beg + Min(length, obj->getDenseArrayCapacity());
+        for (Value *vp = beg; vp != end; ++vp) {
+            if (!JS_CHECK_OPERATION_LIMIT(cx))
+                return false;
+
+            if (!vp->isMagic(JS_ARRAY_HOLE) && !vp->isNullOrUndefined()) {
+                if (!ValueToStringBuffer(cx, *vp, sb))
+                    return false;
+            }
         }
-
-        /* Get element's character string. */
-        if (!(hole || rval->isNullOrUndefined())) {
-            if (locale) {
-                /* Work on obj.toLocalString() instead. */
-                JSObject *robj;
-
-                if (!js_ValueToObjectOrNull(cx, *rval, &robj))
-                    goto out;
-                rval->setObjectOrNull(robj);
-                JSAtom *atom = cx->runtime->atomState.toLocaleStringAtom;
-                if (!js_TryMethod(cx, robj, atom, 0, NULL, rval))
-                    goto out;
+    } else {
+        for (jsuint index = 0; index < length; index++) {
+            if (!JS_CHECK_OPERATION_LIMIT(cx))
+                return false;
+
+            JSBool hole;
+            if (!GetElement(cx, obj, index, &hole, rval))
+                return false;
+
+            if (!hole && !rval->isNullOrUndefined()) {
+                if (locale) {
+                    JSObject *robj = ToObject(cx, rval);
+                    if (!robj)
+                        return false;
+                    jsid id = ATOM_TO_JSID(cx->runtime->atomState.toLocaleStringAtom);
+                    if (!robj->callMethod(cx, id, 0, NULL, rval))
+                        return false;
+                }
+                if (!ValueToStringBuffer(cx, *rval, sb))
+                    return false;
             }
 
-            if (!ValueToStringBuffer(cx, *rval, sb))
-                goto out;
-        }
-
-        /* Append the separator. */
-        if (index + 1 != length) {
-            if (!sb.append(sep, seplen))
-                goto out;
+            if (index + 1 != length) {
+                if (!sb.append(sep, seplen))
+                    return false;
+            }
         }
     }
 
-    /* Finalize the buffer. */
-    if (!BufferToString(cx, sb, rval))
-        goto out;
-
-    ok = true;
-
-  out:
-    if (genBefore == cx->busyArrays.generation())
-        cx->busyArrays.remove(hashp);
-    else
-        cx->busyArrays.remove(obj);
-    return ok;
+    JSString *str = sb.finishString();
+    if (!str)
+        return false;
+    rval->setString(str);
+    return true;
 }
 
 /* ES5 15.4.4.2. NB: The algorithm here differs from the one in ES3. */
 static JSBool
 array_toString(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
@@ -1480,17 +1530,17 @@ array_reverse(JSContext *cx, uintN argc,
         return false;
     vp->setObject(*obj);
 
     do {
         if (!obj->isDenseArray())
             break;
         if (js_PrototypeHasIndexedProperties(cx, obj))
             break;
-        
+
         /* An empty array or an array with no elements is already reversed. */
         if (len == 0 || obj->getDenseArrayCapacity() == 0)
             return true;
 
         /*
          * It's actually surprisingly complicated to reverse an array due to the
          * orthogonality of array length and array capacity while handling
          * leading and trailing holes correctly.  Reversing seems less likely to
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -358,20 +358,18 @@ js_FinishAtomState(JSRuntime *rt)
     if (!state->atoms.initialized()) {
         /*
          * We are called with uninitialized state when JS_NewRuntime fails and
          * calls JS_DestroyRuntime on a partially initialized runtime.
          */
         return;
     }
 
-    for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
-        JSString *str = AtomEntryToKey(r.front());
-        js_FinalizeStringRT(rt, str);
-    }
+    for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront())
+        AtomEntryToKey(r.front())->finalize(rt);
 
 #ifdef JS_THREADSAFE
     js_FinishLock(&state->lock);
 #endif
 }
 
 JSBool
 js_InitCommonAtoms(JSContext *cx)
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -43,16 +43,17 @@
  * JS atom table.
  */
 #include <stddef.h>
 #include "jsversion.h"
 #include "jsapi.h"
 #include "jsprvtd.h"
 #include "jshash.h"
 #include "jshashtable.h"
+#include "jsnum.h"
 #include "jspubtd.h"
 #include "jsstr.h"
 #include "jslock.h"
 #include "jsvalue.h"
 
 #define ATOM_PINNED     0x1       /* atom is pinned against GC */
 #define ATOM_INTERNED   0x2       /* pinned variant for JS_Intern* API */
 #define ATOM_NOCOPY     0x4       /* don't copy atom string bytes */
@@ -109,16 +110,26 @@ IdToValue(jsid id)
 }
 
 static JS_ALWAYS_INLINE jsval
 IdToJsval(jsid id)
 {
     return Jsvalify(IdToValue(id));
 }
 
+static JS_ALWAYS_INLINE JSString *
+IdToString(JSContext *cx, jsid id)
+{
+    if (JSID_IS_STRING(id))
+        return JSID_TO_STRING(id);
+    if (JS_LIKELY(JSID_IS_INT(id)))
+        return js_IntToString(cx, JSID_TO_INT(id));
+    return js_ValueToString(cx, IdToValue(id));
+}
+
 }
 
 #if JS_BYTES_PER_WORD == 4
 # define ATOM_HASH(atom)          ((JSHashNumber)(atom) >> 2)
 #elif JS_BYTES_PER_WORD == 8
 # define ATOM_HASH(atom)          (((JSHashNumber)(jsuword)(atom) >> 3) ^     \
                                    (JSHashNumber)((jsuword)(atom) >> 32))
 #else
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -103,22 +103,16 @@
 #   define MAP_ANONYMOUS 0
 #  endif
 # endif
 #endif
 
 using namespace js;
 using namespace js::gc;
 
-static const size_t ARENA_HEADER_SIZE_HACK = 40;
-static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK;
-
-static void
-FreeContext(JSContext *cx);
-
 #ifdef DEBUG
 JS_REQUIRES_STACK bool
 StackSegment::contains(const JSStackFrame *fp) const
 {
     JS_ASSERT(inContext());
     JSStackFrame *start;
     JSStackFrame *stop;
     if (isActive()) {
@@ -146,16 +140,31 @@ StackSegment::computeNextFrame(JSStackFr
 
     JSStackFrame *next = getCurrentFrame();
     JSStackFrame *prev;
     while ((prev = next->prev()) != fp)
         next = prev;
     return next;
 }
 
+StackSpace::StackSpace()
+  : base(NULL),
+#ifdef XP_WIN
+    commitEnd(NULL),
+#endif
+    end(NULL),
+    currentSegment(NULL),
+#ifdef DEBUG
+    invokeSegment(NULL),
+    invokeFrame(NULL),
+#endif
+    invokeArgEnd(NULL)
+{
+}
+
 bool
 StackSpace::init()
 {
     void *p;
 #ifdef XP_WIN
     p = VirtualAlloc(NULL, CAPACITY_BYTES, MEM_RESERVE, PAGE_READWRITE);
     if (!p)
         return false;
@@ -177,19 +186,20 @@ StackSpace::init()
     if (p == MAP_FAILED)
         return false;
     base = reinterpret_cast<Value *>(p);
     end = base + CAPACITY_VALS;
 #endif
     return true;
 }
 
-void
-StackSpace::finish()
+StackSpace::~StackSpace()
 {
+    if (!base)
+        return;
 #ifdef XP_WIN
     VirtualFree(base, (commitEnd - base) * sizeof(Value), MEM_DECOMMIT);
     VirtualFree(base, 0, MEM_RELEASE);
 #elif defined(XP_OS2)
     DosFreeMem(base);
 #else
 #ifdef SOLARIS
     munmap((caddr_t)base, CAPACITY_BYTES);
@@ -503,100 +513,71 @@ AllFramesIter::operator++()
         curcs = curcs->getPreviousInMemory();
         curfp = curcs ? curcs->getCurrentFrame() : NULL;
     } else {
         curfp = curfp->prev();
     }
     return *this;
 }
 
-bool
-JSThreadData::init()
-{
-#ifdef DEBUG
-    /* The data must be already zeroed. */
-    for (size_t i = 0; i != sizeof(*this); ++i)
-        JS_ASSERT(reinterpret_cast<uint8*>(this)[i] == 0);
+namespace js {
+
+ThreadData::ThreadData()
+  : interruptFlags(0),
+#ifdef JS_THREADSAFE
+    requestDepth(0),
 #endif
-    if (!stackSpace.init())
-        return false;
-    dtoaState = js_NewDtoaState();
-    if (!dtoaState) {
-        finish();
-        return false;
-    }
-    nativeStackBase = GetNativeStackBase();
-
 #ifdef JS_TRACER
-    /* Set the default size for the code cache to 16MB. */
-    maxCodeCacheBytes = 16 * 1024 * 1024;
+    onTraceCompartment(NULL),
+    recordingCompartment(NULL),
+    profilingCompartment(NULL),
+    maxCodeCacheBytes(DEFAULT_JIT_CACHE_SIZE),
 #endif
-
-    return true;
+    waiveGCQuota(false),
+    dtoaState(NULL),
+    nativeStackBase(GetNativeStackBase()),
+    pendingProxyOperation(NULL)
+{
 }
 
-void
-JSThreadData::finish()
+ThreadData::~ThreadData()
 {
     if (dtoaState)
         js_DestroyDtoaState(dtoaState);
+}
 
-    js_FinishGSNCache(&gsnCache);
-    propertyCache.~PropertyCache();
-    stackSpace.finish();
+bool
+ThreadData::init()
+{
+    return stackSpace.init() && !!(dtoaState = js_NewDtoaState());
 }
 
 void
-JSThreadData::mark(JSTracer *trc)
+ThreadData::triggerOperationCallback(JSRuntime *rt)
 {
-    stackSpace.mark(trc);
-}
-
-void
-JSThreadData::purge(JSContext *cx)
-{
-    js_PurgeGSNCache(&gsnCache);
-
-    /* FIXME: bug 506341. */
-    propertyCache.purge(cx);
-}
+    /*
+     * Use JS_ATOMIC_SET and JS_ATOMIC_INCREMENT in the hope that it ensures
+     * the write will become immediately visible to other processors polling
+     * the flag.  Note that we only care about visibility here, not read/write
+     * ordering: this field can only be written with the GC lock held.
+     */
+    if (interruptFlags)
+        return;
+    JS_ATOMIC_SET(&interruptFlags, 1);
 
 #ifdef JS_THREADSAFE
-
-static JSThread *
-NewThread(void *id)
-{
-    JS_ASSERT(js_CurrentThreadId() == id);
-    JSThread *thread = (JSThread *) OffTheBooks::calloc_(sizeof(JSThread));
-    if (!thread)
-        return NULL;
-    JS_INIT_CLIST(&thread->contextList);
-    thread->id = id;
-    if (!thread->data.init()) {
-        Foreground::free_(thread);
-        return NULL;
-    }
-    return thread;
+    /* rt->interruptCounter does not reflect suspended threads. */
+    if (requestDepth != 0)
+        JS_ATOMIC_INCREMENT(&rt->interruptCounter);
+#endif
 }
 
-static void
-DestroyThread(JSThread *thread)
-{
-    /* The thread must have zero contexts. */
-    JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
+} /* namespace js */
 
-    /*
-     * The conservative GC scanner should be disabled when the thread leaves
-     * the last request.
-     */
-    JS_ASSERT(!thread->data.conservativeGC.hasStackToScan());
-
-    thread->data.finish();
-    Foreground::free_(thread);
-}
+#ifdef JS_THREADSAFE
 
 JSThread *
 js_CurrentThread(JSRuntime *rt)
 {
     void *id = js_CurrentThreadId();
     JS_LOCK_GC(rt);
 
     /*
@@ -613,24 +594,27 @@ js_CurrentThread(JSRuntime *rt)
         /*
          * If thread has no contexts, it might be left over from a previous
          * thread with the same id but a different stack address.
          */
         if (JS_CLIST_IS_EMPTY(&thread->contextList))
             thread->data.nativeStackBase = GetNativeStackBase();
     } else {
         JS_UNLOCK_GC(rt);
-        thread = NewThread(id);
-        if (!thread)
+
+        thread = OffTheBooks::new_<JSThread>(id);
+        if (!thread || !thread->init()) {
+            Foreground::delete_(thread);
             return NULL;
+        }
         JS_LOCK_GC(rt);
         js_WaitForGC(rt);
         if (!rt->threads.relookupOrAdd(p, id, thread)) {
             JS_UNLOCK_GC(rt);
-            DestroyThread(thread);
+            Foreground::delete_(thread);
             return NULL;
         }
 
         /* Another thread cannot add an entry for the current thread id. */
         JS_ASSERT(p->value == thread);
     }
     JS_ASSERT(thread->id == id);
 
@@ -663,17 +647,17 @@ js_ClearContextThread(JSContext *cx)
 {
     JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
     JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);
     cx->thread = NULL;
 }
 
 #endif /* JS_THREADSAFE */
 
-JSThreadData *
+ThreadData *
 js_CurrentThreadData(JSRuntime *rt)
 {
 #ifdef JS_THREADSAFE
     JSThread *thread = js_CurrentThread(rt);
     if (!thread)
         return NULL;
 
     return &thread->data;
@@ -681,65 +665,61 @@ js_CurrentThreadData(JSRuntime *rt)
     return &rt->threadData;
 #endif
 }
 
 JSBool
 js_InitThreads(JSRuntime *rt)
 {
 #ifdef JS_THREADSAFE
-    if (!rt->threads.init(4))
-        return false;
+    return rt->threads.init(4);
 #else
-    if (!rt->threadData.init())
-        return false;
+    return rt->threadData.init();
 #endif
-    return true;
 }
 
 void
 js_FinishThreads(JSRuntime *rt)
 {
 #ifdef JS_THREADSAFE
     if (!rt->threads.initialized())
         return;
     for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
         JSThread *thread = r.front().value;
-        JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
-        DestroyThread(thread);
+        Foreground::delete_(thread);
     }
     rt->threads.clear();
-#else
-    rt->threadData.finish();
 #endif
 }
 
 void
 js_PurgeThreads(JSContext *cx)
 {
 #ifdef JS_THREADSAFE
     for (JSThread::Map::Enum e(cx->runtime->threads);
          !e.empty();
          e.popFront()) {
         JSThread *thread = e.front().value;
 
         if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
             JS_ASSERT(cx->thread != thread);
-
-            DestroyThread(thread);
+            Foreground::delete_(thread);
             e.removeFront();
         } else {
             thread->data.purge(cx);
         }
     }
 #else
     cx->runtime->threadData.purge(cx);
 #endif
 }
 
+static const size_t ARENA_HEADER_SIZE_HACK = 40;
+static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK;
+
 JSContext *
 js_NewContext(JSRuntime *rt, size_t stackChunkSize)
 {
     JSContext *cx;
     JSBool ok, first;
     JSContextCallback cxCallback;
 
     /*
@@ -764,23 +744,23 @@ js_NewContext(JSRuntime *rt, size_t stac
     JS_InitArenaPool(&cx->tempPool, "temp", TEMP_POOL_CHUNK_SIZE, sizeof(jsdouble),
                      &cx->scriptStackQuota);
     JS_InitArenaPool(&cx->regExpPool, "regExp", TEMP_POOL_CHUNK_SIZE, sizeof(int),
                      &cx->scriptStackQuota);
 
     JS_ASSERT(cx->resolveFlags == 0);
 
     if (!cx->busyArrays.init()) {
-        FreeContext(cx);
+        Foreground::delete_(cx);
         return NULL;
     }
 
 #ifdef JS_THREADSAFE
     if (!js_InitContextThread(cx)) {
-        FreeContext(cx);
+        Foreground::delete_(cx);
         return NULL;
     }
 #endif
 
     /*
      * Here the GC lock is still held after js_InitContextThread took it and
      * the GC is not running on another thread.
      */
@@ -1102,45 +1082,16 @@ js_DestroyContext(JSContext *cx, JSDestr
 #endif
     js_ClearContextThread(cx);
     JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
 #endif
 #ifdef JS_METER_DST_OFFSET_CACHING
     cx->dstOffsetCache.dumpStats();
 #endif
     JS_UNLOCK_GC(rt);
-    FreeContext(cx);
-}
-
-static void
-FreeContext(JSContext *cx)
-{
-#ifdef JS_THREADSAFE
-    JS_ASSERT(!cx->thread);
-#endif
-
-    /* Free the stuff hanging off of cx. */
-    VOUCH_DOES_NOT_REQUIRE_STACK();
-    JS_FinishArenaPool(&cx->tempPool);
-    JS_FinishArenaPool(&cx->regExpPool);
-
-    if (cx->lastMessage)
-        cx->free_(cx->lastMessage);
-
-    /* Remove any argument formatters. */
-    JSArgumentFormatMap *map = cx->argumentFormatMap;
-    while (map) {
-        JSArgumentFormatMap *temp = map;
-        map = map->next;
-        cx->free_(temp);
-    }
-
-    JS_ASSERT(!cx->resolvingList);
-
-    /* Finally, free cx itself. */
     Foreground::delete_(cx);
 }
 
 JSContext *
 js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
 {
     JSContext *cx = *iterp;
 
@@ -1715,17 +1666,17 @@ js_GetErrorMessage(void *userRef, const 
         return &js_ErrorFormatString[errorNumber];
     return NULL;
 }
 
 JSBool
 js_InvokeOperationCallback(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
-    JSThreadData *td = JS_THREAD_DATA(cx);
+    ThreadData *td = JS_THREAD_DATA(cx);
 
     JS_ASSERT_REQUEST_DEPTH(cx);
     JS_ASSERT(td->interruptFlags != 0);
 
     /*
      * Reset the callback counter first, then run GC and yield. If another
      * thread is racing us here we will accumulate another callback request
      * which will be serviced at the next opportunity.
@@ -1794,17 +1745,17 @@ void
 TriggerOperationCallback(JSContext *cx)
 {
     /*
      * We allow for cx to come from another thread. Thus we must deal with
      * possible JS_ClearContextThread calls when accessing cx->thread. But we
      * assume that the calling thread is in a request so JSThread cannot be
      * GC-ed.
      */
-    JSThreadData *td;
+    ThreadData *td;
 #ifdef JS_THREADSAFE
     JSThread *thread = cx->thread;
     if (!thread)
         return;
     td = &thread->data;
 #else
     td = JS_THREAD_DATA(cx);
 #endif
@@ -1910,16 +1861,41 @@ DSTOffsetCache::DSTOffsetCache()
 JSContext::JSContext(JSRuntime *rt)
   : hasVersionOverride(false),
     runtime(rt),
     compartment(NULL),
     regs(NULL),
     busyArrays()
 {}
 
+JSContext::~JSContext()
+{
+#ifdef JS_THREADSAFE
+    JS_ASSERT(!thread);
+#endif
+
+    /* Free the stuff hanging off of cx. */
+    VOUCH_DOES_NOT_REQUIRE_STACK();
+    JS_FinishArenaPool(&tempPool);
+    JS_FinishArenaPool(&regExpPool);
+
+    if (lastMessage)
+        Foreground::free_(lastMessage);
+
+    /* Remove any argument formatters. */
+    JSArgumentFormatMap *map = argumentFormatMap;
+    while (map) {
+        JSArgumentFormatMap *temp = map;
+        map = map->next;
+        Foreground::free_(temp);
+    }
+
+    JS_ASSERT(!resolvingList);
+}
+
 void
 JSContext::resetCompartment()
 {
     JSObject *scopeobj;
     if (hasfp()) {
         scopeobj = &fp()->scopeChain();
     } else {
         scopeobj = globalObject;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -69,45 +69,16 @@
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
 #pragma warning(push)
 #pragma warning(disable:4355) /* Silence warning about "this" used in base member initializer list */
 #endif
 
-/*
- * js_GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
- * given pc in a script. We use the script->code pointer to tag the cache,
- * instead of the script address itself, so that source notes are always found
- * by offset from the bytecode with which they were generated.
- */
-typedef struct JSGSNCache {
-    jsbytecode      *code;
-    JSDHashTable    table;
-#ifdef JS_GSNMETER
-    uint32          hits;
-    uint32          misses;
-    uint32          fills;
-    uint32          purges;
-# define GSN_CACHE_METER(cache,cnt) (++(cache)->cnt)
-#else
-# define GSN_CACHE_METER(cache,cnt) /* nothing */
-#endif
-} JSGSNCache;
-
-#define js_FinishGSNCache(cache) js_PurgeGSNCache(cache)
-
-extern void
-js_PurgeGSNCache(JSGSNCache *cache);
-
-/* These helper macros take a cx as parameter and operate on its GSN cache. */
-#define JS_PURGE_GSN_CACHE(cx)      js_PurgeGSNCache(&JS_GSN_CACHE(cx))
-#define JS_METER_GSN_CACHE(cx,cnt)  GSN_CACHE_METER(&JS_GSN_CACHE(cx), cnt)
-
 /* Forward declarations of nanojit types. */
 namespace nanojit {
 
 class Assembler;
 class CodeAlloc;
 class Fragment;
 template<typename K> struct DefaultHash;
 template<typename K, typename V, typename H> class HashMap;
@@ -493,17 +464,17 @@ class DummyFrameGuard : public FrameGuar
 
 /* See StackSpace::pushGeneratorFrame. */
 class GeneratorFrameGuard : public FrameGuard
 {};
 
 /*
  * Stack layout
  *
- * Each JSThreadData has one associated StackSpace object which allocates all
+ * Each ThreadData has one associated StackSpace object which allocates all
  * segments for the thread. StackSpace performs all such allocations in a
  * single, fixed-size buffer using a specific layout scheme that allows some
  * associations between segments, frames, and slots to be implicit, rather
  * than explicitly stored as pointers. To maintain useful invariants, stack
  * space is not given out arbitrarily, but rather allocated/deallocated for
  * specific purposes. The use cases currently supported are: calling a function
  * with arguments (e.g. Invoke), executing a script (e.g. Execute), inline
  * interpreter calls, and pushing "dummy" frames for bookkeeping purposes. See
@@ -643,19 +614,20 @@ class StackSpace
      *
      * Worst case, if an average size script (<=9 slots) over recurses, it'll
      * effectively be the same as having increased the old inline call count
      * to <= 5,000.
      */
     static const size_t STACK_QUOTA    = (VALUES_PER_STACK_FRAME + 18) *
                                          JS_MAX_INLINE_CALL_COUNT;
 
-    /* Kept as a member of JSThreadData; cannot use constructor/destructor. */
+    StackSpace();
+    ~StackSpace();
+
     bool init();
-    void finish();
 
 #ifdef DEBUG
     template <class T>
     bool contains(T *t) const {
         char *v = (char *)t;
         JS_ASSERT(size_t(-1) - uintptr_t(t) >= sizeof(T));
         return v >= (char *)base && v + sizeof(T) <= (char *)end;
     }
@@ -802,46 +774,64 @@ public:
 
     JSStackFrame *fp() const { return curfp; }
 
 private:
     StackSegment *curcs;
     JSStackFrame *curfp;
 };
 
-} /* namespace js */
-
-#ifdef DEBUG
-# define FUNCTION_KIND_METER_LIST(_)                                          \
-                        _(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar),  \
-                        _(flat), _(badfunarg),                                \
-                        _(joinedsetmethod), _(joinedinitmethod),              \
-                        _(joinedreplace), _(joinedsort), _(joinedmodulepat),  \
-                        _(mreadbarrier), _(mwritebarrier), _(mwslotbarrier),  \
-                        _(unjoined), _(indynamicscope)
-# define identity(x)    x
-
-struct JSFunctionMeter {
-    int32 FUNCTION_KIND_METER_LIST(identity);
+/*
+ * GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
+ * given pc in a script. We use the script->code pointer to tag the cache,
+ * instead of the script address itself, so that source notes are always found
+ * by offset from the bytecode with which they were generated.
+ */
+struct GSNCache {
+    typedef HashMap<jsbytecode *,
+                    jssrcnote *,
+                    PointerHasher<jsbytecode *, 0>,
+                    SystemAllocPolicy> Map;
+
+    jsbytecode      *code;
+    Map             map;
+#ifdef JS_GSNMETER
+    struct Stats {
+        uint32          hits;
+        uint32          misses;
+        uint32          fills;
+        uint32          purges;
+
+        Stats() : hits(0), misses(0), fills(0), purges(0) { }
+    };
+
+    Stats           stats;
+#endif
+
+    GSNCache() : code(NULL) { }
+
+    void purge();
 };
-
-# undef identity
-
-# define JS_FUNCTION_METER(cx,x) JS_RUNTIME_METER((cx)->runtime, functionMeter.x)
-#else
-# define JS_FUNCTION_METER(cx,x) ((void)0)
-#endif
-
-
-struct JSPendingProxyOperation {
-    JSPendingProxyOperation *next;
-    JSObject *object;
+ 
+inline GSNCache *
+GetGSNCache(JSContext *cx);
+
+struct PendingProxyOperation {
+    PendingProxyOperation   *next;
+    JSObject                *object;
 };
 
-struct JSThreadData {
+struct ThreadData {
+    /*
+     * If non-zero, we were been asked to call the operation callback as soon
+     * as possible.  If the thread has an active request, this contributes
+     * towards rt->interruptCounter.
+     */
+    volatile int32      interruptFlags;
+
 #ifdef JS_THREADSAFE
     /* The request depth for this thread. */
     unsigned            requestDepth;
 #endif
 
 #ifdef JS_TRACER
     /*
      * During trace execution (or during trace recording or
@@ -849,68 +839,74 @@ struct JSThreadData {
      * execution on this thread. At other times, they are NULL.  If a
      * thread tries to execute/record/profile one trace while another
      * is still running, the initial one will abort. Therefore, we
      * only need to track one at a time.
      */
     JSCompartment       *onTraceCompartment;
     JSCompartment       *recordingCompartment;
     JSCompartment       *profilingCompartment;
- #endif
-
-    /*
-     * If non-zero, we were been asked to call the operation callback as soon
-     * as possible.  If the thread has an active request, this contributes
-     * towards rt->interruptCounter.
-     */
-    volatile int32      interruptFlags;
+
+    /* Maximum size of the tracer's code cache before we start flushing. */
+    uint32              maxCodeCacheBytes;
+
+    static const uint32 DEFAULT_JIT_CACHE_SIZE = 16 * 1024 * 1024;
+#endif
 
     /* Keeper of the contiguous stack used by all contexts in this thread. */
-    js::StackSpace      stackSpace;
+    StackSpace          stackSpace;
 
     /*
      * Flag indicating that we are waiving any soft limits on the GC heap
      * because we want allocations to be infallible (except when we hit OOM).
      */
     bool                waiveGCQuota;
 
     /*
      * The GSN cache is per thread since even multi-cx-per-thread embeddings
      * do not interleave js_GetSrcNote calls.
      */
-    JSGSNCache          gsnCache;
+    GSNCache            gsnCache;
 
     /* Property cache for faster call/get/set invocation. */
-    js::PropertyCache   propertyCache;
-
-#ifdef JS_TRACER
-    /* Maximum size of the tracer's code cache before we start flushing. */
-    uint32              maxCodeCacheBytes;
-#endif
+    PropertyCache       propertyCache;
 
     /* State used by dtoa.c. */
     DtoaState           *dtoaState;
 
     /* Base address of the native stack for the current thread. */
     jsuword             *nativeStackBase;
 
     /* List of currently pending operations on proxies. */
-    JSPendingProxyOperation *pendingProxyOperation;
-
-    js::ConservativeGCThreadData conservativeGC;
+    PendingProxyOperation *pendingProxyOperation;
+
+    ConservativeGCThreadData conservativeGC;
+
+    ThreadData();
+    ~ThreadData();
 
     bool init();
-    void finish();
-    void mark(JSTracer *trc);
-    void purge(JSContext *cx);
+    
+    void mark(JSTracer *trc) {
+        stackSpace.mark(trc);
+    }
+
+    void purge(JSContext *cx) {
+        gsnCache.purge();
+
+        /* FIXME: bug 506341. */
+        propertyCache.purge(cx);
+    }
 
     /* This must be called with the GC lock held. */
-    inline void triggerOperationCallback(JSRuntime *rt);
+    void triggerOperationCallback(JSRuntime *rt);
 };
 
+} /* namespace js */
+
 #ifdef JS_THREADSAFE
 
 /*
  * Structure uniquely representing a thread.  It holds thread-private data
  * that can be accessed without a global lock.
  */
 struct JSThread {
     typedef js::HashMap<void *,
@@ -927,17 +923,36 @@ struct JSThread {
     /* Number of JS_SuspendRequest calls withot JS_ResumeRequest. */
     unsigned            suspendCount;
 
 # ifdef DEBUG
     unsigned            checkRequestDepth;
 # endif
 
     /* Factored out of JSThread for !JS_THREADSAFE embedding in JSRuntime. */
-    JSThreadData        data;
+    js::ThreadData      data;
+
+    JSThread(void *id)
+      : id(id),
+        suspendCount(0)
+# ifdef DEBUG
+      , checkRequestDepth(0)
+# endif        
+    {
+        JS_INIT_CLIST(&contextList);
+    }
+
+    ~JSThread() {
+        /* The thread must have zero contexts. */
+        JS_ASSERT(JS_CLIST_IS_EMPTY(&contextList));
+    }
+
+    bool init() {
+        return data.init();
+    }
 };
 
 #define JS_THREAD_DATA(cx)      (&(cx)->thread->data)
 
 extern JSThread *
 js_CurrentThread(JSRuntime *rt);
 
 /*
@@ -951,16 +966,37 @@ js_InitContextThread(JSContext *cx);
 /*
  * On entrance the GC lock must be held and it will be held on exit.
  */
 extern void
 js_ClearContextThread(JSContext *cx);
 
 #endif /* JS_THREADSAFE */
 
+#ifdef DEBUG
+# define FUNCTION_KIND_METER_LIST(_)                                          \
+                        _(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar),  \
+                        _(flat), _(badfunarg),                                \
+                        _(joinedsetmethod), _(joinedinitmethod),              \
+                        _(joinedreplace), _(joinedsort), _(joinedmodulepat),  \
+                        _(mreadbarrier), _(mwritebarrier), _(mwslotbarrier),  \
+                        _(unjoined), _(indynamicscope)
+# define identity(x)    x
+
+struct JSFunctionMeter {
+    int32 FUNCTION_KIND_METER_LIST(identity);
+};
+
+# undef identity
+
+# define JS_FUNCTION_METER(cx,x) JS_RUNTIME_METER((cx)->runtime, functionMeter.x)
+#else
+# define JS_FUNCTION_METER(cx,x) ((void)0)
+#endif
+
 typedef enum JSDestroyContextMode {
     JSDCM_NO_GC,
     JSDCM_MAYBE_GC,
     JSDCM_FORCE_GC,
     JSDCM_NEW_FAILED
 } JSDestroyContextMode;
 
 typedef enum JSRuntimeState {
@@ -1177,17 +1213,16 @@ struct JSRuntime {
      * The propertyRemovals counter is incremented for every JSObject::clear,
      * and for each JSObject::remove method call that frees a slot in the given
      * object. See js_NativeGet and js_NativeSet in jsobj.cpp.
      */
     int32               propertyRemovals;
 
     /* Script filename table. */
     struct JSHashTable  *scriptFilenameTable;
-    JSCList             scriptFilenamePrefixes;
 #ifdef JS_THREADSAFE
     PRLock              *scriptFilenameTableLock;
 #endif
 
     /* Number localization, used by jsnum.c */
     const char          *thousandsSeparator;
     const char          *decimalSeparator;
     const char          *numGrouping;
@@ -1201,17 +1236,17 @@ struct JSRuntime {
      */
     JSObject            *anynameObject;
     JSObject            *functionNamespaceObject;
 
 #ifdef JS_THREADSAFE
     /* Number of threads with active requests and unhandled interrupts. */
     volatile int32      interruptCounter;
 #else
-    JSThreadData        threadData;
+    js::ThreadData      threadData;
 
 #define JS_THREAD_DATA(cx)      (&(cx)->runtime->threadData)
 #endif
 
     /*
      * Object shape (property cache structural type) identifier generator.
      *
      * Type 0 stands for the empty scope, and must not be regenerated due to
@@ -1426,17 +1461,16 @@ struct JSRuntime {
      * Other values of p mean a realloc failure.
      *
      * The function must be called outside the GC lock.
      */
     JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes, JSContext *cx);
 };
 
 /* Common macros to access thread-local caches in JSThread or JSRuntime. */
-#define JS_GSN_CACHE(cx)        (JS_THREAD_DATA(cx)->gsnCache)
 #define JS_PROPERTY_CACHE(cx)   (JS_THREAD_DATA(cx)->propertyCache)
 
 #ifdef DEBUG
 # define JS_RUNTIME_METER(rt, which)    JS_ATOMIC_INCREMENT(&(rt)->which)
 # define JS_RUNTIME_UNMETER(rt, which)  JS_ATOMIC_DECREMENT(&(rt)->which)
 #else
 # define JS_RUNTIME_METER(rt, which)    /* nothing */
 # define JS_RUNTIME_UNMETER(rt, which)  /* nothing */
@@ -1579,25 +1613,26 @@ OptionFlagsToVersion(uintN options, JSVe
 }
 
 static inline bool
 VersionIsKnown(JSVersion version)
 {
     return VersionNumber(version) != JSVERSION_UNKNOWN;
 }
 
-typedef js::HashSet<JSObject *,
-                    js::DefaultHasher<JSObject *>,
-                    js::SystemAllocPolicy> BusyArraysMap;
+typedef HashSet<JSObject *,
+                DefaultHasher<JSObject *>,
+                SystemAllocPolicy> BusyArraysSet;
 
 } /* namespace js */
 
 struct JSContext
 {
     explicit JSContext(JSRuntime *rt);
+    ~JSContext();
 
     /* JSRuntime contextList linkage. */
     JSCList             link;
 
   private:
     /* See JSContext::findVersion. */
     JSVersion           defaultVersion;      /* script compilation version */
     JSVersion           versionOverride;     /* supercedes defaultVersion when valid */
@@ -1674,17 +1709,17 @@ struct JSContext
     /* Temporary arena pool used while evaluate regular expressions. */
     JSArenaPool         regExpPool;
 
     /* Top-level object and pointer to top stack frame's scope chain. */
     JSObject            *globalObject;
 
     /* State for object and array toSource conversion. */
     JSSharpObjectMap    sharpObjectMap;
-    js::BusyArraysMap   busyArrays;
+    js::BusyArraysSet   busyArrays;
 
     /* Argument formatter support for JS_{Convert,Push}Arguments{,VA}. */
     JSArgumentFormatMap *argumentFormatMap;
 
     /* Last message string and log file for debugging. */
     char                *lastMessage;
 #ifdef DEBUG
     void                *logfp;
@@ -2852,39 +2887,39 @@ class JSAutoResolveFlags
     ~JSAutoResolveFlags() { mContext->resolveFlags = mSaved; }
 
   private:
     JSContext *mContext;
     uintN mSaved;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-extern JSThreadData *
+extern js::ThreadData *
 js_CurrentThreadData(JSRuntime *rt);
 
 extern JSBool
 js_InitThreads(JSRuntime *rt);
 
 extern void
 js_FinishThreads(JSRuntime *rt);
 
 extern void
 js_PurgeThreads(JSContext *cx);
 
 namespace js {
 
 #ifdef JS_THREADSAFE
 
-/* Iterator over JSThreadData from all JSThread instances. */
+/* Iterator over ThreadData from all JSThread instances. */
 class ThreadDataIter : public JSThread::Map::Range
 {
   public:
     ThreadDataIter(JSRuntime *rt) : JSThread::Map::Range(rt->threads.all()) {}
 
-    JSThreadData *threadData() const {
+    ThreadData *threadData() const {
         return &front().value->data;
     }
 };
 
 #else /* !JS_THREADSAFE */
 
 class ThreadDataIter
 {
@@ -2897,17 +2932,17 @@ class ThreadDataIter
         return done;
     }
 
     void popFront() {
         JS_ASSERT(!done);
         done = true;
     }
 
-    JSThreadData *threadData() const {
+    ThreadData *threadData() const {
         JS_ASSERT(!done);
         return &runtime->threadData;
     }
 };
 
 #endif  /* !JS_THREADSAFE */
 
 } /* namespace js */
@@ -3055,36 +3090,16 @@ extern JSErrorFormatString js_ErrorForma
  * If the operation callback flag was set, call the operation callback.
  * This macro can run the full GC. Return true if it is OK to continue and
  * false otherwise.
  */
 #define JS_CHECK_OPERATION_LIMIT(cx)                                          \
     (JS_ASSERT_REQUEST_DEPTH(cx),                                             \
      (!JS_THREAD_DATA(cx)->interruptFlags || js_InvokeOperationCallback(cx)))
 
-JS_ALWAYS_INLINE void
-JSThreadData::triggerOperationCallback(JSRuntime *rt)
-{
-    /*
-     * Use JS_ATOMIC_SET and JS_ATOMIC_INCREMENT in the hope that it ensures
-     * the write will become immediately visible to other processors polling
-     * the flag.  Note that we only care about visibility here, not read/write
-     * ordering: this field can only be written with the GC lock held.
-     */
-    if (interruptFlags)
-        return;
-    JS_ATOMIC_SET(&interruptFlags, 1);
-
-#ifdef JS_THREADSAFE
-    /* rt->interruptCounter does not reflect suspended threads. */
-    if (requestDepth != 0)
-        JS_ATOMIC_INCREMENT(&rt->interruptCounter);
-#endif
-}
-
 /*
  * Invoke the operation callback and return false if the current execution
  * is to be terminated.
  */
 extern JSBool
 js_InvokeOperationCallback(JSContext *cx);
 
 extern JSBool
@@ -3196,16 +3211,17 @@ class AutoVectorRooter : protected AutoG
     size_t length() const { return vector.length(); }
 
     bool append(const T &v) { return vector.append(v); }
 
     /* For use when space has already been reserved. */
     void infallibleAppend(const T &v) { vector.infallibleAppend(v); }
 
     void popBack() { vector.popBack(); }
+    T popCopy() { return vector.popCopy(); }
 
     bool growBy(size_t inc) {
         size_t oldLength = vector.length();
         if (!vector.growByUninitialized(inc))
             return false;
         MakeRangeGCSafe(vector.begin() + oldLength, vector.end());
         return true;
     }
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -491,16 +491,22 @@ FrameRegsIter::operator++()
         incSlow(fp, prev);
         return *this;
     }
 
     cursp = fp->formalArgsEnd();
     return *this;
 }
 
+inline GSNCache *
+GetGSNCache(JSContext *cx)
+{
+    return &JS_THREAD_DATA(cx)->gsnCache;
+}
+
 class AutoNamespaceArray : protected AutoGCRooter {
   public:
     AutoNamespaceArray(JSContext *cx) : AutoGCRooter(cx, NAMESPACES) {
         array.init();
     }
 
     ~AutoNamespaceArray() {
         array.finish(context);
@@ -730,22 +736,22 @@ CallJSNativeConstructor(JSContext *cx, j
     JS_ASSERT_IF(native != proxy_Construct && native != js::CallOrConstructBoundFunction &&
                  (!callee->isFunction() || callee->getFunctionPrivate()->u.n.clasp != &js_ObjectClass),
                  !vp->isPrimitive() && callee != &vp[0].toObject());
 
     return true;
 }
 
 JS_ALWAYS_INLINE bool
-CallJSPropertyOp(JSContext *cx, js::PropertyOp op, JSObject *obj, jsid id, js::Value *vp)
+CallJSPropertyOp(JSContext *cx, js::PropertyOp op, JSObject *receiver, jsid id, js::Value *vp)
 {
-    assertSameCompartment(cx, obj, id, *vp);
-    JSBool ok = op(cx, obj, id, vp);
+    assertSameCompartment(cx, receiver, id, *vp);
+    JSBool ok = op(cx, receiver, id, vp);
     if (ok)
-        assertSameCompartment(cx, obj, *vp);
+        assertSameCompartment(cx, receiver, *vp);
     return ok;
 }
 
 JS_ALWAYS_INLINE bool
 CallJSPropertyOpSetter(JSContext *cx, js::StrictPropertyOp op, JSObject *obj, jsid id,
                        JSBool strict, js::Value *vp)
 {
     assertSameCompartment(cx, obj, id, *vp);
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -76,16 +76,17 @@ JSCompartment::JSCompartment(JSRuntime *
     propertyTree(thisForCtor()),
     emptyArgumentsShape(NULL),
     emptyBlockShape(NULL),
     emptyCallShape(NULL),
     emptyDeclEnvShape(NULL),
     emptyEnumeratorShape(NULL),
     emptyWithShape(NULL),
     initialRegExpShape(NULL),
+    initialStringShape(NULL),
     debugMode(rt->debugMode),
 #if ENABLE_YARR_JIT
     regExpAllocator(NULL),
 #endif
     mathCache(NULL)
 {
     JS_INIT_CLIST(&scripts);
 
@@ -483,16 +484,18 @@ JSCompartment::sweep(JSContext *cx, uint
         emptyDeclEnvShape = NULL;
     if (emptyEnumeratorShape && IsAboutToBeFinalized(cx, emptyEnumeratorShape))
         emptyEnumeratorShape = NULL;
     if (emptyWithShape && IsAboutToBeFinalized(cx, emptyWithShape))
         emptyWithShape = NULL;
 
     if (initialRegExpShape && IsAboutToBeFinalized(cx, initialRegExpShape))
         initialRegExpShape = NULL;
+    if (initialStringShape && IsAboutToBeFinalized(cx, initialStringShape))
+        initialStringShape = NULL;
 
 #ifdef JS_TRACER
     traceMonitor.sweep(cx);
 #endif
 
 #if defined JS_METHODJIT && defined JS_MONOIC
 
     /*
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -433,25 +433,26 @@ struct JS_FRIEND_API(JSCompartment) {
 
     typedef js::HashSet<js::EmptyShape *,
                         js::DefaultHasher<js::EmptyShape *>,
                         js::SystemAllocPolicy> EmptyShapeSet;
 
     EmptyShapeSet                emptyShapes;
 
     /*
-     * Initial shape given to RegExp objects, encoding the initial set of
-     * built-in instance properties and the fixed slots where they must be
-     * stored (see JSObject::JSSLOT_REGEXP_*). Later property additions may
-     * cause this shape to not be used by a regular expression (even along the
-     * entire shape parent chain, should the object go into dictionary mode).
-     * But because all the initial properties are non-configurable, they will
-     * always map to fixed slots.
+     * Initial shapes given to RegExp and String objects, encoding the initial
+     * sets of built-in instance properties and the fixed slots where they must
+     * be stored (see JSObject::JSSLOT_(REGEXP|STRING)_*). Later property
+     * additions may cause these shapes to not be used by a RegExp or String
+     * (even along the entire shape parent chain, should the object go into
+     * dictionary mode). But because all the initial properties are
+     * non-configurable, they will always map to fixed slots.
      */
     const js::Shape              *initialRegExpShape;
+    const js::Shape              *initialStringShape;
 
     bool                         debugMode;  // true iff debug mode on
     JSCList                      scripts;    // scripts in this compartment
 
     JSC::ExecutableAllocator     *regExpAllocator;
 
     js::NativeIterCache          nativeIterCache;
 
--- a/js/src/jscpucfg.h
+++ b/js/src/jscpucfg.h
@@ -37,45 +37,45 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef js_cpucfg___
 #define js_cpucfg___
 
 #define JS_HAVE_LONG_LONG
 
-#if defined(XP_WIN) || defined(XP_OS2) || defined(WINCE)
+#if defined(XP_WIN) || defined(XP_OS2)
 
 #if defined(_WIN64)
 
 #if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)
 #define IS_LITTLE_ENDIAN 1
 #undef  IS_BIG_ENDIAN
 #define JS_BYTES_PER_DOUBLE 8L
 #define JS_BYTES_PER_WORD   8L
 #define JS_BITS_PER_WORD_LOG2   6
 #define JS_ALIGN_OF_POINTER 8L
 #else  /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */
 #error "CPU type is unknown"
 #endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */
 
-#elif defined(_WIN32) || defined(XP_OS2) || defined(WINCE)
+#elif defined(_WIN32) || defined(XP_OS2)
 
 #ifdef __WATCOMC__
 #define HAVE_VA_LIST_AS_ARRAY 1
 #endif
 
 #define IS_LITTLE_ENDIAN 1
 #undef  IS_BIG_ENDIAN
 #define JS_BYTES_PER_DOUBLE 8L
 #define JS_BYTES_PER_WORD   4L
 #define JS_BITS_PER_WORD_LOG2   5
 #define JS_ALIGN_OF_POINTER 4L
 
-#endif /* _WIN32 || XP_OS2 || WINCE*/
+#endif /* _WIN32 || XP_OS2 */
 
 #elif defined(XP_UNIX)
 
 #error "This file is supposed to be auto-generated on UNIX platforms, but the"
 #error "static version for Mac and Windows platforms is being used."
 #error "Something's probably wrong with paths/headers/dependencies/Makefiles."
 
 #else
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -190,17 +190,17 @@ TimeWithinDay(jsdouble t)
 
 static inline bool
 IsLeapYear(jsint year)
 {
     return year % 4 == 0 && (year % 100 || (year % 400 == 0));
 }
 
 static inline jsint
-DaysInYear(jsint year) 
+DaysInYear(jsint year)
 {
     return IsLeapYear(year) ? 366 : 365;
 }
 
 static inline jsint
 DaysInFebruary(jsint year)
 {
     return IsLeapYear(year) ? 29 : 28;
@@ -627,78 +627,78 @@ date_UTC(JSContext *cx, uintN argc, Valu
     msec_time = TIMECLIP(msec_time);
 
     vp->setNumber(msec_time);
     return JS_TRUE;
 }
 
 /*
  * Read and convert decimal digits from s[*i] into *result
- * while *i < limit. 
- * 
+ * while *i < limit.
+ *
  * Succeed if any digits are converted. Advance *i only
  * as digits are consumed.
  */
 static JSBool
 digits(size_t *result, const jschar *s, size_t *i, size_t limit)
 {
     size_t init = *i;
     *result = 0;
-    while (*i < limit && 
+    while (*i < limit &&
            ('0' <= s[*i] && s[*i] <= '9')) {
         *result *= 10;
         *result += (s[*i] - '0');
         ++(*i);
     }
     return (*i != init);
 }
 
-/* 
+/*
  * Read and convert decimal digits to the right of a decimal point,
  * representing a fractional integer, from s[*i] into *result
- * while *i < limit. 
- * 
+ * while *i < limit.
+ *
  * Succeed if any digits are converted. Advance *i only
  * as digits are consumed.
  */
 static JSBool
 fractional(jsdouble *result, const jschar *s, size_t *i, size_t limit)
 {
     jsdouble factor = 0.1;
     size_t init = *i;
     *result = 0.0;
-    while (*i < limit && 
+    while (*i < limit &&
            ('0' <= s[*i] && s[*i] <= '9')) {
         *result += (s[*i] - '0') * factor;
         factor *= 0.1;
         ++(*i);
     }
     return (*i != init);
 }
 
-/* 
- * Read and convert exactly n decimal digits from s[*i] 
- * to s[min(*i+n,limit)] into *result. 
+/*
+ * Read and convert exactly n decimal digits from s[*i]
+ * to s[min(*i+n,limit)] into *result.
  *
  * Succeed if exactly n digits are converted. Advance *i only
  * on success.
  */
 static JSBool
 ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
 {
     size_t init = *i;
 
     if (digits(result, s, i, JS_MIN(limit, init+n)))
         return ((*i - init) == n);
-    
+
     *i = init;
     return JS_FALSE;
 }
 
-/* 
+/*
  * Parse a string in one of the date-time formats given by the W3C
  * "NOTE-datetime" specification. These formats make up a restricted
  * profile of the ISO 8601 format. Quoted here:
  *
  *   The formats are as follows. Exactly the components shown here
  *   must be present, with exactly this punctuation. Note that the "T"
  *   appears literally in the string, to indicate the beginning of the
  *   time element, as specified in ISO 8601.
@@ -709,33 +709,33 @@ ndigits(size_t n, size_t *result, const 
  *   The specification is silent on the meaning when fields are
  *   ommitted so the interpretations are a guess, but hopefully a
  *   reasonable one. We default the month to January, the day to the
  *   1st, and hours minutes and seconds all to 0. If the date is
  *   missing entirely then we assume 1970-01-01 so that the time can
  *   be aded to a date later. If the time is missing then we assume
  *   00:00 UTC.  If the time is present but the time zone field is
  *   missing then we use local time.
- * 
+ *
  * Date part:
  *
  *  Year:
  *     YYYY (eg 1997)
  *
  *  Year and month:
  *     YYYY-MM (eg 1997-07)
  *
  *  Complete date:
  *     YYYY-MM-DD (eg 1997-07-16)
  *
  * Time part:
  *
  *  Hours and minutes:
  *     Thh:mmTZD (eg T19:20+01:00)
- * 
+ *
  *  Hours, minutes and seconds:
  *     Thh:mm:ssTZD (eg T19:20:30+01:00)
  *
  *  Hours, minutes, seconds and a decimal fraction of a second:
  *     Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
  *
  * where:
  *
@@ -770,32 +770,32 @@ date_parseISOString(JSLinearString *str,
     size_t tzHour = 0;
     size_t tzMin = 0;
 
 #define PEEK(ch) (i < limit && s[i] == ch)
 
 #define NEED(ch)                                                     \
     JS_BEGIN_MACRO                                                   \
         if (i >= limit || s[i] != ch) { goto syntax; } else { ++i; } \
-    JS_END_MACRO 
+    JS_END_MACRO
 
 #define DONE_DATE_UNLESS(ch)                                            \
     JS_BEGIN_MACRO                                                      \
         if (i >= limit || s[i] != ch) { goto done_date; } else { ++i; } \
-    JS_END_MACRO 
+    JS_END_MACRO
 
 #define DONE_UNLESS(ch)                                            \
     JS_BEGIN_MACRO                                                 \
         if (i >= limit || s[i] != ch) { goto done; } else { ++i; } \
-    JS_END_MACRO 
+    JS_END_MACRO
 
 #define NEED_NDIGITS(n, field)                                      \
     JS_BEGIN_MACRO                                                  \
         if (!ndigits(n, &field, s, &i, limit)) { goto syntax; }     \
-    JS_END_MACRO 
+    JS_END_MACRO
 
     s = str->chars();
     limit = str->length();
 
     if (PEEK('+') || PEEK('-')) {
         if (PEEK('-'))
             dateMul = -1;
         ++i;
@@ -836,37 +836,37 @@ date_parseISOString(JSLinearString *str,
     } else {
         isLocalTime = JS_TRUE;
     }
 
  done:
     if (year > 275943 // ceil(1e8/365) + 1970
         || (month == 0 || month > 12)
         || (day == 0 || day > size_t(DaysInMonth(year,month)))
-        || hour > 24 
+        || hour > 24
         || ((hour == 24) && (min > 0 || sec > 0))
-        || min > 59 
+        || min > 59
         || sec > 59
         || tzHour > 23
-        || tzMin > 59) 
+        || tzMin > 59)
         goto syntax;
 
     if (i != limit)
         goto syntax;
 
     month -= 1; /* convert month to 0-based */
 
     msec = date_msecFromDate(dateMul * (jsdouble)year, month, day,
                              hour, min, sec,
                              frac * 1000.0);;
 
     if (isLocalTime) {
         msec = UTC(msec, cx);
     } else {
-        msec -= ((tzMul) * ((tzHour * msPerHour) 
+        msec -= ((tzMul) * ((tzHour * msPerHour)
                             + (tzMin * msPerMinute)));
     }
 
     if (msec < -8.64e15 || msec > 8.64e15)
         goto syntax;
 
     *result = msec;
 
@@ -1206,20 +1206,23 @@ date_now_tn(JSContext*)
 
 /*
  * Get UTC time from the date object. Returns false if the object is not
  * Date type.
  */
 static JSBool
 GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
 {
-    if (!InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
-        return JS_FALSE;
+    if (!obj->isDate()) {
+        if (vp)
+            ReportIncompatibleMethod(cx, vp, &js_DateClass);
+        return false;
+    }
     *dp = obj->getDateUTCTime().toNumber();
-    return JS_TRUE;
+    return true;
 }
 
 /*
  * Set UTC time to a given time and invalidate cached local time.
  */
 static JSBool
 SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL)
 {
@@ -1383,18 +1386,23 @@ FillLocalTimes(JSContext *cx, JSObject *
 
     return true;
 }
 
 /* Cache the local times in obj, if necessary. */
 static inline JSBool
 GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = NULL)
 {
-    if (!obj || !InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
+    if (!obj)
         return false;
+    if (!obj->isDate()) {
+        if (vp)
+            ReportIncompatibleMethod(cx, vp, &js_DateClass);
+        return false;
+    }
 
     /* If the local time is undefined, we need to fill in the cached values. */
     if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
         if (!FillLocalTimes(cx, obj))
             return false;
     }
 
     if (time)
@@ -1674,18 +1682,20 @@ date_getTimezoneOffset(JSContext *cx, ui
 
 static JSBool
 date_setTime(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
-    if (!InstanceOf(cx, obj, &js_DateClass, vp + 2))
+    if (!obj->isDate()) {
+        ReportIncompatibleMethod(cx, vp, &js_DateClass);
         return false;
+    }
 
     if (argc == 0) {
         SetDateToNaN(cx, obj, vp);
         return true;
     }
 
     jsdouble result;
     if (!ValueToNumber(cx, vp[2], &result))
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -320,17 +320,17 @@ js_UntrapScriptCode(JSContext *cx, JSScr
                 for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
                     continue;
                 nbytes += (sn - notes + 1) * sizeof *sn;
 
                 code = (jsbytecode *) cx->malloc_(nbytes);
                 if (!code)
                     break;
                 memcpy(code, script->code, nbytes);
-                JS_PURGE_GSN_CACHE(cx);
+                GetGSNCache(cx)->purge();
             }
             code[trap->pc - script->code] = trap->op;
         }
     }
     DBG_UNLOCK(rt);
     return code;
 }
 
@@ -1984,69 +1984,31 @@ JS_GetScriptTotalSize(JSContext *cx, JSS
         if (principals->refcount > 1)
             pbytes = JS_HOWMANY(pbytes, principals->refcount);
         nbytes += pbytes;
     }
 
     return nbytes;
 }
 
-JS_PUBLIC_API(uint32)
-JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
-{
-    if (!fp)
-        fp = js_GetTopStackFrame(cx);
-    while (fp) {
-        if (fp->isScriptFrame())
-            return JS_GetScriptFilenameFlags(fp->script());
-        fp = fp->prev();
-    }
-    return 0;
- }
-
-JS_PUBLIC_API(uint32)
-JS_GetScriptFilenameFlags(JSScript *script)
-{
-    JS_ASSERT(script);
-    if (!script->filename)
-        return JSFILENAME_NULL;
-    return js_GetScriptFilenameFlags(script->filename);
-}
-
-JS_PUBLIC_API(JSBool)
-JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags)
-{
-    if (!js_SaveScriptFilenameRT(rt, prefix, flags))
-        return JS_FALSE;
-    return JS_TRUE;
-}
-
 JS_PUBLIC_API(JSBool)
 JS_IsSystemObject(JSContext *cx, JSObject *obj)
 {
     return obj->isSystem();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_MakeSystemObject(JSContext *cx, JSObject *obj)
 {
     obj->setSystem();
     return true;
 }
 
 /************************************************************************/
 
-JS_PUBLIC_API(JSObject *)
-JS_UnwrapObject(JSContext *cx, JSObject *obj)
-{
-    return obj->unwrap();
-}
-
-/************************************************************************/
-
 JS_FRIEND_API(void)
 js_RevertVersion(JSContext *cx)
 {
     cx->clearVersionOverride();
 }
 
 JS_PUBLIC_API(const JSDebugHooks *)
 JS_GetGlobalDebugHooks(JSRuntime *rt)
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -477,50 +477,16 @@ JS_GetObjectTotalSize(JSContext *cx, JSO
 
 extern JS_PUBLIC_API(size_t)
 JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun);
 
 extern JS_PUBLIC_API(size_t)
 JS_GetScriptTotalSize(JSContext *cx, JSScript *script);
 
 /*
- * Get the top-most running script on cx starting from fp, or from the top of
- * cx's frame stack if fp is null, and return its script filename flags.  If
- * the script has a null filename member, return JSFILENAME_NULL.
- */
-extern JS_PUBLIC_API(uint32)
-JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp);
-
-/*
- * Get the script filename flags for the script.  If the script doesn't have a
- * filename, return JSFILENAME_NULL.
- */
-extern JS_PUBLIC_API(uint32)
-JS_GetScriptFilenameFlags(JSScript *script);
-
-/*
- * Associate flags with a script filename prefix in rt, so that any subsequent
- * script compilation will inherit those flags if the script's filename is the
- * same as prefix, or if prefix is a substring of the script's filename.
- *
- * The API defines only one flag bit, JSFILENAME_SYSTEM, leaving the remaining
- * 31 bits up to the API client to define.  The union of all 32 bits must not
- * be a legal combination, however, in order to preserve JSFILENAME_NULL as a
- * unique value.  API clients may depend on JSFILENAME_SYSTEM being a set bit
- * in JSFILENAME_NULL -- a script with a null filename member is presumed to
- * be a "system" script.
- */
-extern JS_PUBLIC_API(JSBool)
-JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags);
-
-#define JSFILENAME_NULL         0xffffffff      /* null script filename */
-#define JSFILENAME_SYSTEM       0x00000001      /* "system" script, see below */
-#define JSFILENAME_PROTECTED    0x00000002      /* scripts need protection */
-
-/*
  * Return true if obj is a "system" object, that is, one created by
  * JS_NewSystemObject with the system flag set and not JS_NewObject.
  *
  * What "system" means is up to the API client, but it can be used to implement
  * access control policies based on script filenames and their prefixes, using
  * JS_FlagScriptFilenamePrefix and JS_GetTopScriptFilenameFlags.
  */
 extern JS_PUBLIC_API(JSBool)
@@ -531,21 +497,16 @@ JS_IsSystemObject(JSContext *cx, JSObjec
  * after allocating the object. A system object is an object for which
  * JS_IsSystemObject returns true.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_MakeSystemObject(JSContext *cx, JSObject *obj);
 
 /************************************************************************/
 
-extern JS_PUBLIC_API(JSObject *)
-JS_UnwrapObject(JSContext *cx, JSObject *obj);
-
-/************************************************************************/
-
 extern JS_FRIEND_API(void)
 js_RevertVersion(JSContext *cx);
 
 extern JS_PUBLIC_API(const JSDebugHooks *)
 JS_GetGlobalDebugHooks(JSRuntime *rt);
 
 extern JS_PUBLIC_API(JSDebugHooks *)
 JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks);
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -33,16 +33,44 @@
  * 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 "jscntxt.h"
+#include "jscompartment.h"
 #include "jsfriendapi.h"
 
+using namespace js;
+
 JS_FRIEND_API(JSString *)
 JS_GetAnonymousString(JSRuntime *rt)
 {
     JS_ASSERT(rt->state == JSRTS_UP);
     return rt->atomState.anonymousAtom;
 }
+
+JS_FRIEND_API(JSObject *)
+JS_FindCompilationScope(JSContext *cx, JSObject *obj)
+{
+    /*
+     * We unwrap wrappers here. This is a little weird, but it's what's being
+     * asked of us.
+     */
+    if (obj->isWrapper())
+        obj = obj->unwrap();
+    
+    /*
+     * Innerize the target_obj so that we compile in the correct (inner)
+     * scope.
+     */
+    if (JSObjectOp op = obj->getClass()->ext.innerObject)
+        obj = op(cx, obj);
+    return obj;
+}
+
+JS_FRIEND_API(JSObject *)
+JS_UnwrapObject(JSObject *obj)
+{
+    return obj->unwrap();
+}
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * ***** 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/
@@ -43,11 +43,17 @@
 #include "jspubtd.h"
 #include "jsprvtd.h"
 
 JS_BEGIN_EXTERN_C
 
 extern JS_FRIEND_API(JSString *)
 JS_GetAnonymousString(JSRuntime *rt);
 
+extern JS_FRIEND_API(JSObject *)
+JS_FindCompilationScope(JSContext *cx, JSObject *obj);
+
+extern JS_FRIEND_API(JSObject *)
+JS_UnwrapObject(JSObject *obj);
+
 JS_END_EXTERN_C
 
 #endif /* jsfriendapi_h___ */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -508,17 +508,17 @@ WrapEscapingClosure(JSContext *cx, JSSta
     return wfunobj;
 }
 
 static JSBool
 ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     LeaveTrace(cx);
 
-    if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
+    if (!obj->isNormalArguments())
         return true;
 
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         uintN arg = uintN(JSID_TO_INT(id));
@@ -561,17 +561,18 @@ ArgSetter(JSContext *cx, JSObject *obj, 
 #ifdef JS_TRACER
     // To be able to set a property here on trace, we would have to make
     // sure any updates also get written back to the trace native stack.
     // For simplicity, we just leave trace, since this is presumably not
     // a common operation.
     LeaveTrace(cx);
 #endif
 
-    if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
+
+    if (!obj->isNormalArguments())
         return true;
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
         if (arg < obj->getArgsInitialLength()) {
             JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
             if (fp) {
                 JSScript *script = fp->functionScript();
@@ -657,17 +658,17 @@ args_enumerate(JSContext *cx, JSObject *
     return true;
 }
 
 static JSBool
 StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     LeaveTrace(cx);
 
-    if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
+    if (!obj->isStrictArguments())
         return true;
 
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         uintN arg = uintN(JSID_TO_INT(id));
@@ -683,17 +684,17 @@ StrictArgGetter(JSContext *cx, JSObject 
     }
     return true;
 }
 
 static JSBool
 
 StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
-    if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
+    if (!obj->isStrictArguments())
         return true;
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
         if (arg < obj->getArgsInitialLength()) {
             obj->setArgsElement(arg, *vp);
             return true;
         }
@@ -1565,25 +1566,25 @@ fun_getProperty(JSContext *cx, JSObject 
      * and name.  If we didn't return early for slot != FUN_LENGTH, we would
      * clobber *vp with the native property value, instead of letting script
      * override that value in delegating objects.
      *
      * Note how that clobbering is what simulates JSPROP_READONLY for all of
      * the non-standard properties when the directly addressed object (obj)
      * is a function object (i.e., when this loop does not iterate).
      */
-    JSFunction *fun;
-    while (!(fun = (JSFunction *)
-                   GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) {
+
+    while (!obj->isFunction()) {
         if (slot != FUN_LENGTH)
             return true;
         obj = obj->getProto();
         if (!obj)
             return true;
     }
+    JSFunction *fun = obj->getFunctionPrivate();
 
     /* Find fun's top-most activation record. */
     JSStackFrame *fp;
     for (fp = js_GetTopStackFrame(cx);
          fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
          fp = fp->prev()) {
         continue;
     }
@@ -2112,25 +2113,17 @@ fun_toSource(JSContext *cx, uintN argc, 
 
 JSBool
 js_fun_call(JSContext *cx, uintN argc, Value *vp)
 {
     LeaveTrace(cx);
     Value fval = vp[1];
 
     if (!js_IsCallable(fval)) {
-        if (JSString *str = js_ValueToString(cx, fval)) {
-            JSAutoByteString bytes(cx, str);
-            if (!!bytes) {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                     JSMSG_INCOMPATIBLE_PROTO,
-                                     js_Function_str, js_call_str,
-                                     bytes.ptr());
-            }
-        }
+        ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
         return false;
     }
 
     Value *argv = vp + 2;
     Value thisv;
     if (argc == 0) {
         thisv.setUndefined();
     } else {
@@ -2157,25 +2150,17 @@ js_fun_call(JSContext *cx, uintN argc, V
 
 /* ES5 15.3.4.3 */
 JSBool
 js_fun_apply(JSContext *cx, uintN argc, Value *vp)
 {
     /* Step 1. */
     Value fval = vp[1];
     if (!js_IsCallable(fval)) {
-        if (JSString *str = js_ValueToString(cx, fval)) {
-            JSAutoByteString bytes(cx, str);
-            if (!!bytes) {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                     JSMSG_INCOMPATIBLE_PROTO,
-                                     js_Function_str, js_apply_str,
-                                     bytes.ptr());
-            }
-        }
+        ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
         return false;
     }
 
     /* Step 2. */
     if (argc < 2 || vp[3].isNullOrUndefined())
         return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
 
     /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
@@ -2331,33 +2316,50 @@ CallOrConstructBoundFunction(JSContext *
         return false;
 
     *vp = args.rval();
     return true;
 }
 
 }
 
+#if JS_HAS_GENERATORS
+static JSBool
+fun_isGenerator(JSContext *cx, uintN argc, Value *vp)
+{
+    JSObject *funobj;
+    if (!IsFunctionObject(vp[1], &funobj)) {
+        JS_SET_RVAL(cx, vp, BooleanValue(false));
+        return true;
+    }
+
+    JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
+
+    bool result = false;
+    if (fun->isInterpreted()) {
+        JSScript *script = fun->u.i.script;
+        JS_ASSERT(script->length != 0);
+        result = script->code[0] == JSOP_GENERATOR;
+    }
+
+    JS_SET_RVAL(cx, vp, BooleanValue(result));
+    return true;
+}
+#endif
+
 /* ES5 15.3.4.5. */
 static JSBool
 fun_bind(JSContext *cx, uintN argc, Value *vp)
 {
     /* Step 1. */
     Value &thisv = vp[1];
 
     /* Step 2. */
     if (!js_IsCallable(thisv)) {
-        if (JSString *str = js_ValueToString(cx, thisv)) {
-            JSAutoByteString bytes(cx, str);
-            if (!!bytes) {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                     JSMSG_INCOMPATIBLE_PROTO,
-                                     js_Function_str, "bind", bytes.ptr());
-            }
-        }
+        ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
         return false;
     }
 
     JSObject *target = &thisv.toObject();
 
     /* Step 3. */
     Value *args = NULL;
     uintN argslen = 0;
@@ -2400,16 +2402,19 @@ fun_bind(JSContext *cx, uintN argc, Valu
 static JSFunctionSpec function_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,   fun_toSource,   0,0),
 #endif
     JS_FN(js_toString_str,   fun_toString,   0,0),
     JS_FN(js_apply_str,      js_fun_apply,   2,0),
     JS_FN(js_call_str,       js_fun_call,    1,0),
     JS_FN("bind",            fun_bind,       1,0),
+#if JS_HAS_GENERATORS
+    JS_FN("isGenerator",     fun_isGenerator,0,0),
+#endif
     JS_FS_END
 };
 
 /*
  * Report "malformed formal parameter" iff no illegal char or similar scanner
  * error was already reported.
  */
 static bool
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -213,17 +213,17 @@ template<typename T>
 inline ConservativeGCTest
 Arena<T>::mark(T *thing, JSTracer *trc)
 {
     T *alignedThing = getAlignedThing(thing);
 
     if (alignedThing > &t.things[ThingsPerArena-1] || alignedThing < &t.things[0])
         return CGCT_NOTARENA;
 
-    if (!aheader.compartment || inFreeList(alignedThing))
+    if (inFreeList(alignedThing))
         return CGCT_NOTLIVE;
 
     JS_ASSERT(sizeof(T) == aheader.thingSize);
     JS_SET_TRACING_NAME(trc, "machine stack");
     js::gc::Mark(trc, alignedThing);
 
 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
     if (alignedThing != thing)
@@ -238,17 +238,17 @@ checkArenaListsForThing(JSCompartment *c
 {
     if (comp->arenas[FINALIZE_OBJECT0].arenasContainThing<JSObject>(thing) ||
         comp->arenas[FINALIZE_OBJECT2].arenasContainThing<JSObject_Slots2>(thing) ||
         comp->arenas[FINALIZE_OBJECT4].arenasContainThing<JSObject_Slots4>(thing) ||
         comp->arenas[FINALIZE_OBJECT8].arenasContainThing<JSObject_Slots8>(thing) ||
         comp->arenas[FINALIZE_OBJECT12].arenasContainThing<JSObject_Slots12>(thing) ||
         comp->arenas[FINALIZE_OBJECT16].arenasContainThing<JSObject_Slots16>(thing) ||
         comp->arenas[FINALIZE_FUNCTION].arenasContainThing<JSFunction>(thing) ||
-        comp->arenas[FINALIZE_FUNCTION].arenasContainThing<Shape>(thing) ||
+        comp->arenas[FINALIZE_SHAPE].arenasContainThing<Shape>(thing) ||
 #if JS_HAS_XML_SUPPORT
         comp->arenas[FINALIZE_XML].arenasContainThing<JSXML>(thing) ||
 #endif
         comp->arenas[FINALIZE_STRING].arenasContainThing<JSString>(thing) ||
         comp->arenas[FINALIZE_EXTERNAL_STRING].arenasContainThing<JSExternalString>(thing) ||
         comp->arenas[FINALIZE_SHORT_STRING].arenasContainThing<JSShortString>(thing))
     {
         return true;
@@ -639,16 +639,19 @@ MarkIfGCThingWord(JSTracer *trc, jsuword
     if (!rt->gcChunkSet.has(chunk))
         return CGCT_NOTCHUNK;
 
     if (!chunk->withinArenasRange(cell))
         return CGCT_NOTARENA;
 
     ArenaHeader *aheader = cell->arena()->header();
 
+    if (!aheader->compartment)
+        return CGCT_NOTLIVE;
+
     ConservativeGCTest test;
     thingKind = aheader->thingKind;
 
     switch (thingKind) {
       case FINALIZE_OBJECT0:
         test = MarkCell<JSObject>(cell, trc);
         break;
       case FINALIZE_OBJECT2:
@@ -748,17 +751,17 @@ static void
 MarkRangeConservatively(JSTracer *trc, const jsuword *begin, const jsuword *end)
 {
     JS_ASSERT(begin <= end);
     for (const jsuword *i = begin; i != end; ++i)
         MarkWordConservatively(trc, *i);
 }
 
 static void
-MarkThreadDataConservatively(JSTracer *trc, JSThreadData *td)
+MarkThreadDataConservatively(JSTracer *trc, ThreadData *td)
 {
     ConservativeGCThreadData *ctd = &td->conservativeGC;
     JS_ASSERT(ctd->hasStackToScan());
     jsuword *stackMin, *stackEnd;
 #if JS_STACK_GROWTH_DIRECTION > 0
     stackMin = td->nativeStackBase;
     stackEnd = ctd->nativeStackTop;
 #else
@@ -1777,46 +1780,16 @@ js_DestroyScriptsToGC(JSContext *cx, JSC
         while ((script = *listp) != NULL) {
             *listp = script->u.nextToGC;
             script->u.nextToGC = NULL;
             js_DestroyCachedScript(cx, script);
         }
     }
 }
 
-/*
- * This function is called from js_FinishAtomState to force the finalization
- * of the permanently interned strings when cx is not available.
- */
-void
-js_FinalizeStringRT(JSRuntime *rt, JSString *str)
-{
-    JS_RUNTIME_UNMETER(rt, liveStrings);
-    JS_ASSERT(str->isLinear() && !str->isStaticAtom());
-
-    if (str->isDependent()) {
-        /* A dependent string can not be external and must be valid. */
-        JS_ASSERT(str->arena()->header()->thingKind == FINALIZE_STRING);
-        JS_ASSERT(str->asDependent().base());
-        JS_RUNTIME_UNMETER(rt, liveDependentStrings);
-    } else {
-        unsigned thingKind = str->arena()->header()->thingKind;
-        JS_ASSERT(unsigned(FINALIZE_SHORT_STRING) <= thingKind &&
-                  thingKind <= unsigned(FINALIZE_EXTERNAL_STRING));
-
-        jschar *chars = const_cast<jschar *>(str->asFlat().chars());
-        if (thingKind == FINALIZE_STRING) {
-            rt->stringMemoryUsed -= str->length() * 2;
-            rt->free_(chars);
-        } else if (thingKind == FINALIZE_EXTERNAL_STRING) {
-            ((JSExternalString *)str)->finalize();
-        }
-    }
-}
-
 template<typename T>
 static void
 FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
 {
     JS_STATIC_ASSERT(!(sizeof(T) & Cell::CellMask));
     ArenaList *arenaList = GetFinalizableArenaList(comp, thingKind);
     Arena<FreeCell> **ap = &arenaList->head;
     Arena<T> *a = (Arena<T> *) *ap;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -515,17 +515,17 @@ GetArena(Cell *cell)
 #define JSTRACE_LIMIT       4
 
 /*
  * Lower limit after which we limit the heap growth
  */
 const size_t GC_ARENA_ALLOCATION_TRIGGER = 30 * js::GC_CHUNK_SIZE;
 
 /*
- * A GC is triggered once the number of newly allocated arenas 
+ * A GC is triggered once the number of newly allocated arenas
  * is GC_HEAP_GROWTH_FACTOR times the number of live arenas after
  * the last GC starting after the lower limit of
  * GC_ARENA_ALLOCATION_TRIGGER.
  */
 const float GC_HEAP_GROWTH_FACTOR = 3.0f;
 
 static inline size_t
 GetFinalizableTraceKind(size_t thingKind)
@@ -692,17 +692,17 @@ struct RootInfo {
 
 typedef js::HashMap<void *,
                     RootInfo,
                     js::DefaultHasher<void *>,
                     js::SystemAllocPolicy> RootedValueMap;
 
 /* If HashNumber grows, need to change WrapperHasher. */
 JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
-    
+
 struct WrapperHasher
 {
     typedef Value Lookup;
 
     static HashNumber hash(Value key) {
         uint64 bits = JSVAL_BITS(Jsvalify(key));
         return (uint32)bits ^ (uint32)(bits >> 32);
     }
@@ -910,26 +910,26 @@ class GCHelperThread {
     GCHelperThread()
       : thread(NULL),
         wakeup(NULL),
         sweepingDone(NULL),
         shutdown(false),
         sweeping(false),
         freeCursor(NULL),
         freeCursorEnd(NULL) { }
-    
+
     bool init(JSRuntime *rt);
     void finish(JSRuntime *rt);
-    
+
     /* Must be called with GC lock taken. */
     void startBackgroundSweep(JSRuntime *rt);
-    
+
     /* Must be called outside the GC lock. */
     void waitBackgroundSweepEnd(JSRuntime *rt);
-    
+
     void freeLater(void *ptr) {
         JS_ASSERT(!sweeping);
         if (freeCursor != freeCursorEnd)
             *freeCursor++ = ptr;
         else
             replenishAndFreeLater(ptr);
     }
 };
@@ -955,33 +955,48 @@ struct GCChunkHasher {
     }
 };
 
 typedef HashSet<js::gc::Chunk *, GCChunkHasher, SystemAllocPolicy> GCChunkSet;
 
 struct ConservativeGCThreadData {
 
     /*
-     * The GC scans conservatively between JSThreadData::nativeStackBase and
+     * The GC scans conservatively between ThreadData::nativeStackBase and
      * nativeStackTop unless the latter is NULL.
      */
     jsuword             *nativeStackTop;
 
     union {
         jmp_buf         jmpbuf;
         jsuword         words[JS_HOWMANY(sizeof(jmp_buf), sizeof(jsuword))];
     } registerSnapshot;
 
     /*
      * Cycle collector uses this to communicate that the native stack of the
      * GC thread should be scanned only if the thread have more than the given
      * threshold of requests.
      */
     unsigned requestThreshold;
 
+    ConservativeGCThreadData()
+      : nativeStackTop(NULL), requestThreshold(0)
+    {
+    }
+
+    ~ConservativeGCThreadData() {
+#ifdef JS_THREADSAFE
+        /*
+         * The conservative GC scanner should be disabled when the thread leaves
+         * the last request.
+         */
+        JS_ASSERT(!hasStackToScan());
+#endif
+    }
+
     JS_NEVER_INLINE void recordStackTop();
 
 #ifdef JS_THREADSAFE
     void updateForRequestEnd(unsigned suspendCount) {
         if (suspendCount)
             recordStackTop();
         else
             nativeStackTop = NULL;
--- a/js/src/jsgcchunk.cpp
+++ b/js/src/jsgcchunk.cpp
@@ -64,108 +64,30 @@
 # ifndef MAP_NOSYNC
 #  define MAP_NOSYNC    0
 # endif
 
 #endif
 
 #ifdef XP_WIN
 
-/*
- * On Windows CE < 6 we must use separated MEM_RESERVE and MEM_COMMIT
- * VirtualAlloc calls and we cannot use MEM_RESERVE to allocate at the given
- * address. So we use a workaround based on oversized allocation.
- */
-# if defined(WINCE) && !defined(MOZ_MEMORY_WINCE6)
-
-#  define JS_GC_HAS_MAP_ALIGN
-
-static void
-UnmapPagesAtBase(void *p)
-{
-    JS_ALWAYS_TRUE(VirtualFree(p, 0, MEM_RELEASE));
-}
-
-static void *
-MapAlignedPages(size_t size, size_t alignment)
-{
-    JS_ASSERT(size % alignment == 0);
-    JS_ASSERT(size >= alignment);
-
-    void *reserve = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
-    if (!reserve)
-        return NULL;
-
-    void *p = VirtualAlloc(reserve, size, MEM_COMMIT, PAGE_READWRITE);
-    JS_ASSERT(p == reserve);
-
-    size_t mask = alignment - 1;
-    size_t offset = (uintptr_t) p & mask;
-    if (!offset)
-        return p;
-
-    /* Try to extend the initial allocation. */
-    UnmapPagesAtBase(reserve);
-    reserve = VirtualAlloc(NULL, size + alignment - offset, MEM_RESERVE,
-                           PAGE_NOACCESS);
-    if (!reserve)
-        return NULL;
-    if (offset == ((uintptr_t) reserve & mask)) {
-        void *aligned = (void *) ((uintptr_t) reserve + alignment - offset);
-        p = VirtualAlloc(aligned, size, MEM_COMMIT, PAGE_READWRITE);
-        JS_ASSERT(p == aligned);
-        return p;
-    }
-
-    /* over allocate to ensure we have an aligned region */
-    UnmapPagesAtBase(reserve);
-    reserve = VirtualAlloc(NULL, size + alignment, MEM_RESERVE, PAGE_NOACCESS);
-    if (!reserve)
-        return NULL;
-
-    offset = (uintptr_t) reserve & mask;
-    void *aligned = (void *) ((uintptr_t) reserve + alignment - offset);
-    p = VirtualAlloc(aligned, size, MEM_COMMIT, PAGE_READWRITE);
-    JS_ASSERT(p == aligned);
-
-    return p;
-}
-
-static void
-UnmapPages(void *p, size_t size)
-{
-    if (VirtualFree(p, 0, MEM_RELEASE))
-        return;
-
-    /* We could have used the over allocation. */
-    JS_ASSERT(GetLastError() == ERROR_INVALID_PARAMETER);
-    MEMORY_BASIC_INFORMATION info;
-    VirtualQuery(p, &info, sizeof(info));
-
-    UnmapPagesAtBase(info.AllocationBase);
-}
-
-# else /* WINCE */
-
 static void *
 MapPages(void *addr, size_t size)
 {
     void *p = VirtualAlloc(addr, size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
     JS_ASSERT_IF(p && addr, p == addr);
     return p;
 }
 
 static void
 UnmapPages(void *addr, size_t size)
 {
     JS_ALWAYS_TRUE(VirtualFree(addr, 0, MEM_RELEASE));
 }
 
-# endif /* !WINCE */
-
 #elif defined(XP_OS2)
 
 #define JS_GC_HAS_MAP_ALIGN 1
 #define OS2_MAX_RECURSIONS  16
 
 static void
 UnmapPages(void *addr, size_t size)
 {
--- a/js/src/jsgcchunk.h
+++ b/js/src/jsgcchunk.h
@@ -40,22 +40,17 @@
 #ifndef jsgchunk_h__
 #define jsgchunk_h__
 
 #include "jsprvtd.h"
 #include "jsutil.h"
 
 namespace js {
 
-#if defined(WINCE) && !defined(MOZ_MEMORY_WINCE6)
-const size_t GC_CHUNK_SHIFT = 21;
-#else
 const size_t GC_CHUNK_SHIFT = 20;
-#endif
-
 const size_t GC_CHUNK_SIZE = size_t(1) << GC_CHUNK_SHIFT;
 const size_t GC_CHUNK_MASK = GC_CHUNK_SIZE - 1;
 
 JS_FRIEND_API(void *)
 AllocGCChunk();
 
 JS_FRIEND_API(void)
 FreeGCChunk(void *p);
--- a/js/src/jshashtable.h
+++ b/js/src/jshashtable.h
@@ -115,16 +115,23 @@ class HashTable : private AllocPolicy
         void nonNull() {}
 
         Entry *entry;
 
       protected:
         Ptr(Entry &entry) : entry(&entry) {}
 
       public:
+        /* Leaves Ptr uninitialized. */
+        Ptr() {
+#ifdef DEBUG
+            entry = (Entry *)0xbad;
+#endif
+        }
+
         bool found() const                    { return entry->isLive(); }
         operator ConvertibleToBool() const    { return found() ? &Ptr::nonNull : 0; }
         bool operator==(const Ptr &rhs) const { JS_ASSERT(found() && rhs.found()); return entry == rhs.entry; }
         bool operator!=(const Ptr &rhs) const { return !(*this == rhs); }
 
         T &operator*() const                  { return entry->t; }
         T *operator->() const                 { return &entry->t; }
     };
@@ -137,16 +144,19 @@ class HashTable : private AllocPolicy
 #ifdef DEBUG
         uint64 mutationCount;
 
         AddPtr(Entry &entry, HashNumber hn, uint64 mutationCount)
             : Ptr(entry), keyHash(hn), mutationCount(mutationCount) {}
 #else
         AddPtr(Entry &entry, HashNumber hn) : Ptr(entry), keyHash(hn) {}
 #endif
+      public:
+        /* Leaves AddPtr uninitialized. */
+        AddPtr() {}
     };
 
     /*
      * A collection of hash table entries. The collection is enumerated by
      * calling |front()| followed by |popFront()| as long as |!empty()|. As
      * with Ptr/AddPtr, Range objects must not be used after any mutating hash
      * table operation unless the |generation()| is tested.
      */
@@ -566,16 +576,33 @@ class HashTable : private AllocPolicy
             *e = Entry();
         removedCount = 0;
         entryCount = 0;
 #ifdef DEBUG
         mutationCount++;
 #endif
     }
 
+    void finish()
+    {
+        JS_ASSERT(!entered);
+
+        if (!table)
+            return;
+        
+        destroyTable(*this, table, tableCapacity);
+        table = NULL;
+        gen++;
+        entryCount = 0;
+        removedCount = 0;
+#ifdef DEBUG
+        mutationCount++;
+#endif
+    }
+
     Range all() const {
         return Range(table, table + tableCapacity);
     }
 
     bool empty() const {
         return !entryCount;
     }
 
@@ -733,35 +760,47 @@ struct DefaultHasher
         return l;
     }
     static bool match(const Key &k, const Lookup &l) {
         /* Use builtin or overloaded operator==. */
         return k == l;
     }
 };
 
-/* Specialized hashing policy for pointer types. */
-template <class T>
-struct DefaultHasher<T *>
+/*
+ * Pointer hashing policy that strips the lowest zeroBits when calculating the
+ * hash to improve key distribution.
+ */
+template <typename Key, size_t zeroBits>
+struct PointerHasher
 {
-    typedef T *Lookup;
-    static HashNumber hash(T *l) {
-        /*
-         * Strip often-0 lower bits for better distribution after multiplying
-         * by the sGoldenRatio.
-         */
-        return HashNumber(reinterpret_cast<size_t>(l) >>
-                          tl::FloorLog2<sizeof(void *)>::result);
+    typedef Key Lookup;
+    static HashNumber hash(const Lookup &l) {
+        size_t word = reinterpret_cast<size_t>(l) >> zeroBits;
+        JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
+#if JS_BYTES_PER_WORD == 4
+        return HashNumber(word);
+#else
+        JS_STATIC_ASSERT(sizeof word == 8);
+        return HashNumber((word >> 32) ^ word);
+#endif
     }
-    static bool match(T *k, T *l) {
+    static bool match(const Key &k, const Lookup &l) {
         return k == l;
     }
 };
 
 /*
+ * Specialized hashing policy for pointer types. It assumes that the type is
+ * at least word-aligned. For types with smaller size use PointerHasher.
+ */
+template <class T>
+struct DefaultHasher<T *>: PointerHasher<T *, tl::FloorLog2<sizeof(void *)>::result> { };
+
+/*
  * JS-friendly, STL-like container providing a hash-based map from keys to
  * values. In particular, HashMap calls constructors and destructors of all
  * objects added so non-PODs may be used safely.
  *
  * Key/Value requirements:
  *  - default constructible, copyable, destructible, assignable
  * HashPolicy requirements:
  *  - see "Hash policy" above (default js::DefaultHasher<Key>)
@@ -924,20 +963,29 @@ class HashMap
      *     if (e.front().value == 'l')
      *       e.removeFront();
      *
      * Table resize may occur in Enum's destructor. Also see the definition of
      * Enum in HashTable above (with T = Entry).
      */
     typedef typename Impl::Enum Enum;
 
-    /* Remove all entries. */
+    /*
+     * Remove all entries. This does not shrink the table. For that consider
+     * using the finish() method.
+     */
     void clear()                                      { impl.clear(); }
 
-    /* Does the table contain any entries? */
+    /*
+     * Remove all the entries and release all internal buffers. The map must
+     * be initialized again before any use.
+     */
+    void finish()                                     { impl.finish(); }
+
+   /* Does the table contain any entries? */
     bool empty() const                                { return impl.empty(); }
 
     /*
      * If |generation()| is the same before and after a HashMap operation,
      * pointers into the table remain valid.
      */
     unsigned generation() const                       { return impl.generation(); }
 
@@ -1113,19 +1161,28 @@ class HashSet
      *     if (e.front() == 42)
      *       e.removeFront();
      *
      * Table resize may occur in Enum's destructor. Also see the definition of
      * Enum in HashTable above.
      */
     typedef typename Impl::Enum Enum;
 
-    /* Remove all entries. */
+    /*
+     * Remove all entries. This does not shrink the table. For that consider
+     * using the finish() method.
+     */
     void clear()                                      { impl.clear(); }
 
+    /*
+     * Remove all the entries and release all internal buffers. The set must
+     * be initialized again before any use.
+     */
+    void finish()                                     { impl.finish(); }
+
     /* Does the table contain any entries? */
     bool empty() const                                { return impl.empty(); }
 
     /*
      * If |generation()| is the same before and after a HashSet operation,
      * pointers into the table remain valid.
      */
     unsigned generation() const                       { return impl.generation(); }
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1022,17 +1022,17 @@ CheckRedeclaration(JSContext *cx, JSObje
             return false;
     }
 
     /* We allow redeclaring some non-readonly properties. */
     if (((oldAttrs | attrs) & JSPROP_READONLY) == 0) {
         /* Allow redeclaration of variables and functions. */
         if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
             return true;
-        
+
         /*
          * Allow adding a getter only if a property already has a setter
          * but no getter and similarly for adding a setter. That is, we
          * allow only the following transitions:
          *
          *   no-property --> getter --> getter + setter
          *   no-property --> setter --> getter + setter
          */
@@ -1095,23 +1095,23 @@ LooselyEqual(JSContext *cx, const Value 
 #endif
 
     if (SameType(lval, rval)) {
         if (lval.isString()) {
             JSString *l = lval.toString();
             JSString *r = rval.toString();
             return EqualStrings(cx, l, r, result);
         }
-        
+
         if (lval.isDouble()) {
             double l = lval.toDouble(), r = rval.toDouble();
             *result = JSDOUBLE_COMPARE(l, ==, r, false);
             return true;
         }
-        
+
         if (lval.isObject()) {
             JSObject *l = &lval.toObject();
             JSObject *r = &rval.toObject();
             l->assertSpecialEqualitySynced();
 
             if (EqualityOp eq = l->getClass()->ext.equality) {
                 return eq(cx, l, &rval, result);
             }
@@ -1123,17 +1123,17 @@ LooselyEqual(JSContext *cx, const Value 
         *result = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
         return true;
     }
 
     if (lval.isNullOrUndefined()) {
         *result = rval.isNullOrUndefined();
         return true;
     }
-    
+
     if (rval.isNullOrUndefined()) {
         *result = false;
         return true;
     }
 
     Value lvalue = lval;
     Value rvalue = rval;
 
@@ -1241,34 +1241,16 @@ TypeOfValue(JSContext *cx, const Value &
     if (v.isUndefined())
         return JSTYPE_VOID;
     if (v.isObject())
         return v.toObject().typeOf(cx);
     JS_ASSERT(v.isBoolean());
     return JSTYPE_BOOLEAN;
 }
 
-bool
-InstanceOfSlow(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
-{
-    JS_ASSERT(!obj || obj->getClass() != clasp);
-    if (argv) {
-        JSFunction *fun = js_ValueToFunction(cx, &argv[-2], 0);
-        if (fun) {
-            JSAutoByteString funNameBytes;
-            if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
-                                     clasp->name, funName,
-                                     obj ? obj->getClass()->name : js_null_str);
-            }
-        }
-    }
-    return false;
-}
-
 JS_REQUIRES_STACK bool
 InvokeConstructor(JSContext *cx, const CallArgs &argsRef)
 {
     JS_ASSERT(!js_FunctionClass.construct);
     CallArgs args = argsRef;
 
     JSObject *callee;
     if (args.callee().isPrimitive() || !(callee = &args.callee().toObject())->getParent()) {
@@ -2365,17 +2347,17 @@ Interpret(JSContext *cx, JSStackFrame *e
 
 #define LOAD_FUNCTION(PCOFF)                                                  \
     (fun = script->getFunction(GET_FULL_INDEX(PCOFF)))
 
 #define LOAD_DOUBLE(PCOFF, dbl)                                               \
     (dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble())
 
     bool useMethodJIT = false;
-    
+
 #ifdef JS_METHODJIT
 
 #define RESET_USE_METHODJIT()                                                 \
     JS_BEGIN_MACRO                                                            \
         useMethodJIT = cx->methodJitEnabled &&                                \
             interpMode == JSINTERP_NORMAL &&                                  \
             script->getJITStatus(regs.fp->isConstructing()) != JITScript_Invalid; \
     JS_END_MACRO
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -1082,36 +1082,19 @@ LooselyEqual(JSContext *cx, const Value 
 
 /* === except that NaN is the same as NaN and -0 is not the same as +0. */
 extern bool
 SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same);
 
 extern JSType
 TypeOfValue(JSContext *cx, const Value &v);
 
-inline bool
-InstanceOf(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
-{
-    if (obj && obj->getClass() == clasp)
-        return true;
-    extern bool InstanceOfSlow(JSContext *, JSObject *, Class *, Value *);
-    return InstanceOfSlow(cx, obj, clasp, argv);
-}
-
 extern JSBool
 HasInstance(JSContext *cx, JSObject *obj, const js::Value *v, JSBool *bp);
 
-inline void *
-GetInstancePrivate(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
-{
-    if (!InstanceOf(cx, obj, clasp, argv))
-        return NULL;
-    return obj->getPrivate();
-}
-
 extern bool
 ValueToId(JSContext *cx, const Value &v, jsid *idp);
 
 /*
  * @param closureLevel      The static level of the closure that the cookie
  *                          pertains to.
  * @param cookie            Level amount is a "skip" (delta) value from the
  *                          closure level.
--- a/js/src/jsinttypes.h
+++ b/js/src/jsinttypes.h
@@ -119,22 +119,16 @@ typedef unsigned JS_INT64_TYPE  JSUint64
 #endif
 
 /* Microsoft Visual C/C++ defines intptr_t and uintptr_t in <stddef.h>.  */
 #if defined(JS_STDDEF_H_HAS_INTPTR_T)
 #include <stddef.h>
 typedef intptr_t JSIntPtr;
 typedef uintptr_t JSUintPtr;
 
-/* Windows Mobile defines intptr_t and uintptr_t in <crtdefs.h>.  Why not?  */
-#elif defined(JS_CRTDEFS_H_HAS_INTPTR_T)
-#include <crtdefs.h>
-typedef intptr_t JSIntPtr;
-typedef uintptr_t JSUintPtr;
-
 /* Failing that, the configure script will have found something.  */
 #elif defined(JS_INTPTR_TYPE)
 typedef signed   JS_INTPTR_TYPE JSIntPtr;
 typedef unsigned JS_INTPTR_TYPE JSUintPtr;
 
 #else
 #error "couldn't find pointer-sized integer types"
 #endif
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -588,19 +588,19 @@ GetIterator(JSContext *cx, JSObject *obj
              * objects here, as they are not inserted into the cache and
              * will result in a miss.
              */
             JSObject *last = cx->compartment->nativeIterCache.last;
             JSObject *proto = obj->getProto();
             if (last) {
                 NativeIterator *lastni = last->getNativeIterator();
                 if (!(lastni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
-                    obj->isNative() && 
+                    obj->isNative() &&
                     obj->shape() == lastni->shapes_array[0] &&
-                    proto && proto->isNative() && 
+                    proto && proto->isNative() &&
                     proto->shape() == lastni->shapes_array[1] &&
                     !proto->getProto()) {
                     vp->setObject(*last);
                     UpdateNativeIterator(lastni, obj);
                     RegisterEnumerator(cx, last, lastni);
                     return true;
                 }
             }
@@ -708,18 +708,22 @@ js_ThrowStopIteration(JSContext *cx)
         cx->setPendingException(v);
     return JS_FALSE;
 }
 
 static JSBool
 iterator_next(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
-    if (!obj || !InstanceOf(cx, obj, &js_IteratorClass, vp + 2))
+    if (!obj)
         return false;
+    if (obj->getClass() != &js_IteratorClass) {
+        ReportIncompatibleMethod(cx, vp, &js_IteratorClass);
+        return false;
+    }
 
     if (!js_IteratorMore(cx, obj, vp))
         return false;
     if (!vp->toBoolean()) {
         js_ThrowStopIteration(cx);
         return false;
     }
     return js_IteratorNext(cx, obj, vp);
@@ -809,17 +813,17 @@ js_CloseIterator(JSContext *cx, JSObject
         return CloseGenerator(cx, obj);
     }
 #endif
     return JS_TRUE;
 }
 
 /*
  * Suppress enumeration of deleted properties. This function must be called
- * when a property is deleted and there might be active enumerators. 
+ * when a property is deleted and there might be active enumerators.
  *
  * We maintain a list of active non-escaping for-in enumerators. To suppress
  * a property, we check whether each active enumerator contains the (obj, id)
  * pair and has not yet enumerated |id|. If so, and |id| is the next property,
  * we simply advance the cursor. Otherwise, we delete |id| from the list.
  *
  * We do not suppress enumeration of a property deleted along an object's
  * prototype chain. Only direct deletions on the object are handled.
@@ -914,17 +918,17 @@ js_SuppressDeletedProperty(JSContext *cx
     return SuppressDeletedPropertyHelper(cx, obj, SingleIdPredicate(id));
 }
 
 class IndexRangePredicate {
     jsint begin, end;
 public:
     IndexRangePredicate(jsint begin, jsint end) : begin(begin), end(end) {}
 
-    bool operator()(jsid id) { 
+    bool operator()(jsid id) {
         return JSID_IS_INT(id) && begin <= JSID_TO_INT(id) && JSID_TO_INT(id) < end;
     }
     bool matchesAtMostOne() { return false; }
 };
 
 bool
 js_SuppressDeletedIndexProperties(JSContext *cx, JSObject *obj, jsint begin, jsint end)
 {
@@ -1351,18 +1355,22 @@ CloseGenerator(JSContext *cx, JSObject *
  * Common subroutine of generator_(next|send|throw|close) methods.
  */
 static JSBool
 generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
 {
     LeaveTrace(cx);
 
     JSObject *obj = ToObject(cx, &vp[1]);
-    if (!obj || !InstanceOf(cx, obj, &js_GeneratorClass, vp + 2))
+    if (!obj)
         return JS_FALSE;
+    if (obj->getClass() != &js_GeneratorClass) {
+        ReportIncompatibleMethod(cx, vp, &js_GeneratorClass);
+        return JS_FALSE;
+    }
 
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen) {
         /* This happens when obj is the generator prototype. See bug 352885. */
         goto closed_generator;
     }
 
     if (gen->state == JSGEN_NEWBORN) {
--- a/js/src/jslibmath.h
+++ b/js/src/jslibmath.h
@@ -48,18 +48,16 @@
 
 /*
  * Use system provided math routines.
  */
 
 /* The right copysign function is not always named the same thing. */
 #if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
 #define js_copysign __builtin_copysign
-#elif defined WINCE
-#define js_copysign _copysign
 #elif defined _WIN32
 #if _MSC_VER < 1400
 /* Try to work around apparent _copysign bustage in VC7.x. */
 #define js_copysign js_copysign
 extern double js_copysign(double, double);
 #else
 #define js_copysign _copysign
 #endif
--- a/js/src/jslock.h
+++ b/js/src/jslock.h
@@ -45,18 +45,16 @@
 
 #ifdef JS_THREADSAFE
 # include "pratom.h"
 # include "prlock.h"
 # include "prcvar.h"
 # include "prthread.h"
 #endif
 
-JS_BEGIN_EXTERN_C
-
 #ifdef JS_THREADSAFE
 
 #if (defined(_WIN32) && defined(_M_IX86)) ||                                  \
     (defined(_WIN64) && (defined(_M_AMD64) || defined(_M_X64))) ||            \
     (defined(__i386) && (defined(__GNUC__) || defined(__SUNPRO_CC))) ||       \
     (defined(__x86_64) && (defined(__GNUC__) || defined(__SUNPRO_CC))) ||     \
     (defined(__sparc) && (defined(__GNUC__) || defined(__SUNPRO_CC))) ||      \
     defined(AIX) ||                                                           \
@@ -212,28 +210,27 @@ static inline JSBool
 js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
 {
     return (*w == ov) ? *w = nv, JS_TRUE : JS_FALSE;
 }
 
 #define JS_ATOMIC_SET_MASK(w, mask) (*(w) |= (mask))
 #define JS_ATOMIC_CLEAR_MASK(w, mask) (*(w) &= ~(mask))
 
-#endif /* JS_THREADSAFE */
-
-JS_END_EXTERN_C
+#endif
 
-#if defined JS_THREADSAFE && defined __cplusplus
+#ifdef JS_THREADSAFE
 namespace js {
-
 class AutoLock {
   private:
     JSLock *lock;
 
   public:
     AutoLock(JSLock *lock) : lock(lock) { JS_ACQUIRE_LOCK(lock); }
     ~AutoLock() { JS_RELEASE_LOCK(lock); }
 };
-
-}
+}  /* namespace js */
+# define JS_AUTO_LOCK_GUARD(name, l) AutoLock name((l));
+#else
+# define JS_AUTO_LOCK_GUARD(name, l)
 #endif
 
 #endif /* jslock_h___ */
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -560,17 +560,17 @@ random_nextDouble(JSContext *cx)
 static JSBool
 math_random(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble z = random_nextDouble(cx);
     vp->setDouble(z);
     return JS_TRUE;
 }
 
-#if defined _WIN32 && !defined WINCE && _MSC_VER < 1400
+#if defined _WIN32 && _MSC_VER < 1400
 /* Try to work around apparent _copysign bustage in VC7.x. */
 double
 js_copysign(double x, double y)
 {
     jsdpun xu, yu;
 
     xu.d = x;
     yu.d = y;
--- a/js/src/jsnativestack.cpp
+++ b/js/src/jsnativestack.cpp
@@ -56,73 +56,17 @@
 
 #else
 # error "Unsupported platform"
 
 #endif
 
 namespace js {
 
-#if defined(XP_WIN) && defined(WINCE)
-
-inline bool
-isPageWritable(void *page)
-{
-    MEMORY_BASIC_INFORMATION memoryInformation;
-    jsuword result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation));
-
-    /* return false on error, including ptr outside memory */
-    if (result != sizeof(memoryInformation))
-        return false;
-
-    jsuword protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE);
-    return protect == PAGE_READWRITE ||
-           protect == PAGE_WRITECOPY ||
-           protect == PAGE_EXECUTE_READWRITE ||
-           protect == PAGE_EXECUTE_WRITECOPY;
-}
-
-void *
-GetNativeStackBase()
-{
-    /* find the address of this stack frame by taking the address of a local variable */
-    bool isGrowingDownward = JS_STACK_GROWTH_DIRECTION < 0;
-    void *thisFrame = (void *)(&isGrowingDownward);
-
-    static jsuword pageSize = 0;
-    if (!pageSize) {
-        SYSTEM_INFO systemInfo;
-        GetSystemInfo(&systemInfo);
-        pageSize = systemInfo.dwPageSize;
-    }
-
-    /* scan all of memory starting from this frame, and return the last writeable page found */
-    register char *currentPage = (char *)((jsuword)thisFrame & ~(pageSize - 1));
-    if (isGrowingDownward) {
-        while (currentPage > 0) {
-            /* check for underflow */
-            if (currentPage >= (char *)pageSize)
-                currentPage -= pageSize;
-            else
-                currentPage = 0;
-            if (!isPageWritable(currentPage))
-                return currentPage + pageSize;
-        }
-        return 0;
-    } else {
-        while (true) {
-            /* guaranteed to complete because isPageWritable returns false at end of memory */
-            currentPage += pageSize;
-            if (!isPageWritable(currentPage))
-                return currentPage;
-        }
-    }
-}
-
-#elif defined(XP_WIN)
+#if defined(XP_WIN)
 
 void *
 GetNativeStackBaseImpl()
 {
 # if defined(_M_IX86) && defined(_MSC_VER)
     /*
      * offset 0x18 from the FS segment register gives a pointer to
      * the thread information block for the current thread
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -61,16 +61,17 @@
 #include "jsemit.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
+#include "jsonparser.h"
 #include "jsopcode.h"
 #include "jsparse.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstaticcheck.h"
 #include "jsstdint.h"
 #include "jsstr.h"
@@ -978,30 +979,16 @@ CheckScopeChainValidity(JSContext *cx, J
 
     return true;
 }
 
 const char *
 js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
                    JSPrincipals *principals, uintN *linenop)
 {
-    uint32 flags;
-#ifdef DEBUG
-    JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
-#endif
-
-    JS_ASSERT(principals || !(callbacks  && callbacks->findObjectPrincipals));
-    flags = JS_GetScriptFilenameFlags(caller->script());
-    if ((flags & JSFILENAME_PROTECTED) &&
-        principals &&
-        strcmp(principals->codebase, "[System Principal]")) {
-        *linenop = 0;
-        return principals->codebase;
-    }
-
     jsbytecode *pc = caller->pc(cx);
     if (pc && js_GetOpcode(cx, caller->script(), pc) == JSOP_EVAL) {
         JS_ASSERT(js_GetOpcode(cx, caller->script(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
         *linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
     } else {
         *linenop = js_FramePCToLineNumber(cx, caller);
     }
     return caller->script()->filename;
@@ -1224,24 +1211,33 @@ EvalKernel(JSContext *cx, uintN argc, Va
 
     /*
      * 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
         JSONParser *jp = js_BeginJSONParse(cx, vp, /* 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)
                 return true;
         }
+#else
+        JSONSourceParser parser(cx, chars + 1, length - 2, JSONSourceParser::StrictJSON,
+                                JSONSourceParser::NoError);
+        if (!parser.parse(vp))
+            return false;
+        if (!vp->isUndefined())
+            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 && !caller->computeThis(cx))
@@ -2945,20 +2941,20 @@ js_InitializerObject(JSContext* cx, JSOb
 
 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_InitializerObject, CONTEXT, OBJECT, OBJECT,
                      0, nanojit::ACCSET_STORE_ANY)
 
 JSObject* FASTCALL
 js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
 {
     JS_ASSERT(JS_ON_TRACE(cx));
+    JS_ASSERT(FINALIZE_OBJECT2 == gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(&js_StringClass)));
     JSObject *obj = NewObjectWithClassProto(cx, &js_StringClass, proto, FINALIZE_OBJECT2);
-    if (!obj)
+    if (!obj || !obj->initString(cx, str))
         return NULL;
-    obj->setPrimitiveThis(StringValue(str));
     return obj;
 }
 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0,
                      nanojit::ACCSET_STORE_ANY)
 
 JSObject * FASTCALL
 js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot)
 {
@@ -5475,16 +5471,24 @@ JSObject::reportNotConfigurable(JSContex
 bool
 JSObject::reportNotExtensible(JSContext *cx, uintN report)
 {
     return js_ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE,
                                     JSDVG_IGNORE_STACK, ObjectValue(*this),
                                     NULL, NULL, NULL);
 }
 
+bool
+JSObject::callMethod(JSContext *cx, jsid id, uintN argc, Value *argv, Value *vp)
+{
+    Value fval;
+    return js_GetMethod(cx, this, id, JSGET_NO_METHOD_BARRIER, &fval) &&
+           ExternalInvoke(cx, ObjectValue(*this), fval, argc, argv, vp);
+}
+
 JSBool
 js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
                      Value *vp, JSBool strict)
 {
     int protoIndex;
     JSObject *pobj;
     JSProperty *prop;
     const Shape *shape;
@@ -5894,22 +5898,31 @@ DefaultValue(JSContext *cx, JSObject *ob
             ClassMethodIsNative(cx, obj,
                                  &js_StringClass,
                                  ATOM_TO_JSID(cx->runtime->atomState.toStringAtom),
                                  js_str_toString)) {
             *vp = obj->getPrimitiveThis();
             return true;
         }
 
-        if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, &v))
+        Value fval;
+        jsid id = ATOM_TO_JSID(cx->runtime->atomState.toStringAtom);
+        if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval))
             return false;
-        if (!v.isPrimitive()) {
-            if (!obj->getClass()->convert(cx, obj, hint, &v))
+        if (js_IsCallable(fval)) {
+            if (!ExternalInvoke(cx, ObjectValue(*obj), fval, 0, NULL, &v))
                 return false;
+            if (v.isPrimitive()) {
+                *vp = v;
+                return true;
+            }
         }
+
+        if (!obj->getClass()->convert(cx, obj, hint, &v))
+            return false;
     } else {
         /* Optimize (new String(...)).valueOf(). */
         Class *clasp = obj->getClass();
         if ((clasp == &js_StringClass &&
              ClassMethodIsNative(cx, obj, &js_StringClass,
                                  ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom),
                                  js_str_toString)) ||
             (clasp == &js_NumberClass &&
@@ -5919,18 +5932,28 @@ DefaultValue(JSContext *cx, JSObject *ob
             *vp = obj->getPrimitiveThis();
             return true;
         }
 
         if (!obj->getClass()->convert(cx, obj, hint, &v))
             return false;
         if (v.isObject()) {
             JS_ASSERT(hint != TypeOfValue(cx, v));
-            if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, &v))
+            Value fval;
+            jsid id = ATOM_TO_JSID(cx->runtime->atomState.toStringAtom);
+            if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval))
                 return false;
+            if (js_IsCallable(fval)) {
+                if (!ExternalInvoke(cx, ObjectValue(*obj), fval, 0, NULL, &v))
+                    return false;
+                if (v.isPrimitive()) {
+                    *vp = v;
+                    return true;
+                }
+            }
         }
     }
     if (v.isObject()) {
         /* Avoid recursive death when decompiling in js_ReportValueError. */
         JSString *str;
         if (hint == JSTYPE_STRING) {
             str = JS_InternString(cx, obj->getClass()->name);
             if (!str)
@@ -6151,28 +6174,25 @@ js_SetClassPrototype(JSContext *cx, JSOb
      */
     return proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
                                  ObjectOrNullValue(ctor), PropertyStub, StrictPropertyStub, 0);
 }
 
 JSObject *
 PrimitiveToObject(JSContext *cx, const Value &v)
 {
-    JS_ASSERT(v.isPrimitive());
-
-    Class *clasp;
-    if (v.isNumber()) {
-        clasp = &js_NumberClass;
-    } else if (v.isString()) {
-        clasp = &js_StringClass;
-    } else {
-        JS_ASSERT(v.isBoolean());
-        clasp = &js_BooleanClass;
-    }
-
+    if (v.isString()) {
+        JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass);
+        if (!obj || !obj->initString(cx, v.toString()))
+            return NULL;
+        return obj;
+    }
+
+    JS_ASSERT(v.isNumber() || v.isBoolean());
+    Class *clasp = v.isNumber() ? &js_NumberClass : &js_BooleanClass;
     JSObject *obj = NewBuiltinClassInstance(cx, clasp);
     if (!obj)
         return NULL;
 
     obj->setPrimitiveThis(v);
     return obj;
 }
 
@@ -6238,45 +6258,31 @@ js_ValueToNonNullObject(JSContext *cx, c
     if (!obj)
         js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, v, NULL);
     return obj;
 }
 
 JSBool
 js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, Value *rval)
 {
-    Value argv[1];
-
-    argv[0].setString(cx->runtime->atomState.typeAtoms[type]);
-    return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom,
-                        1, argv, rval);
-}
-
-JSBool
-js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
-             uintN argc, Value *argv, Value *rval)
-{
-    JS_CHECK_RECURSION(cx, return JS_FALSE);
-
-    /*
-     * Report failure only if an appropriate method was found, and calling it
-     * returned failure.  We propagate failure in this case to make exceptions
-     * behave properly.
-     */
-    JSErrorReporter older = JS_SetErrorReporter(cx, NULL);
-    jsid id = ATOM_TO_JSID(atom);
     Value fval;
-    JSBool ok = js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval);
-    JS_SetErrorReporter(cx, older);
-    if (!ok)
+    jsid id = ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom);
+    if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval))
         return false;
-
-    if (fval.isPrimitive())
-        return JS_TRUE;
-    return ExternalInvoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
+    if (js_IsCallable(fval)) {
+        Value v;
+        Value argv[] = { StringValue(cx->runtime->atomState.typeAtoms[type]) };
+        if (!ExternalInvoke(cx, ObjectValue(*obj), fval, JS_ARRAY_LENGTH(argv), argv, &v))
+            return false;
+        if (v.isPrimitive()) {
+            *rval = v;
+            return true;
+        }
+    }
+    return true;
 }
 
 #if JS_HAS_XDR
 
 JSBool
 js_XDRObject(JSXDRState *xdr, JSObject **objp)
 {
     JSContext *cx;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -792,16 +792,34 @@ struct JSObject : js::gc::Cell {
 
   private:
     static const uint32 JSSLOT_PRIMITIVE_THIS = 0;
 
   public:
     inline const js::Value &getPrimitiveThis() const;
     inline void setPrimitiveThis(const js::Value &pthis);
 
+  private:
+    /* 0 is JSSLOT_PRIMITIVE_THIS */
+    static const uint32 JSSLOT_STRING_LENGTH = 1;
+
+    /*
+     * Compute the initial shape to associate with fresh String objects,
+     * encoding the initial length property. Return the shape after changing
+     * this String object's last property to it.
+     */
+    const js::Shape *assignInitialStringShape(JSContext *cx);
+
+  public:
+    static const uint32 STRING_RESERVED_SLOTS = 2;
+
+    inline size_t getStringLength() const;
+
+    inline bool initString(JSContext *cx, JSString *str);
+
     /*
      * Array-specific getters and setters (for both dense and slow arrays).
      */
 
     inline uint32 getArrayLength() const;
     inline void setArrayLength(uint32 length);
 
     inline uint32 getDenseArrayCapacity();
@@ -1181,16 +1199,24 @@ struct JSObject : js::gc::Cell {
     bool allocSlot(JSContext *cx, uint32 *slotp);
     bool freeSlot(JSContext *cx, uint32 slot);
 
   public:
     bool reportReadOnly(JSContext* cx, jsid id, uintN report = JSREPORT_ERROR);
     bool reportNotConfigurable(JSContext* cx, jsid id, uintN report = JSREPORT_ERROR);
     bool reportNotExtensible(JSContext *cx, uintN report = JSREPORT_ERROR);
 
+    /*
+     * Get the property with the given id, then call it as a function with the
+     * given arguments, providing this object as |this|. If the property isn't
+     * callable a TypeError will be thrown. On success the value returned by
+     * the call is stored in *vp.
+     */
+    bool callMethod(JSContext *cx, jsid id, uintN argc, js::Value *argv, js::Value *vp);
+
   private:
     js::Shape *getChildProperty(JSContext *cx, js::Shape *parent, js::Shape &child);
 
     /*
      * Internal helper that adds a shape not yet mapped by this object.
      *
      * Notes:
      * 1. getter and setter must be normalized based on flags (see jsscope.cpp).
@@ -1880,20 +1906,16 @@ ToObject(JSContext *cx, js::Value *vp)
  */
 extern JSObject *
 js_ValueToNonNullObject(JSContext *cx, const js::Value &v);
 
 extern JSBool
 js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, js::Value *rval);
 
 extern JSBool
-js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
-             uintN argc, js::Value *argv, js::Value *rval);
-
-extern JSBool
 js_XDRObject(JSXDRState *xdr, JSObject **objp);
 
 extern void
 js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
 
 extern void
 js_ClearNative(JSContext *cx, JSObject *obj);
 
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -46,16 +46,17 @@
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jsnum.h"
 #include "jsobj.h"
+#include "jsonparser.h"
 #include "jsprf.h"
 #include "jsscan.h"
 #include "jsstr.h"
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
 #include "jsxml.h"
 #include "jsvector.h"
@@ -110,35 +111,27 @@ Class js_JSONClass = {
     ConvertStub
 };
 
 JSBool
 js_json_parse(JSContext *cx, uintN argc, Value *vp)
 {
     JSString *s = NULL;
     Value *argv = vp + 2;
-    AutoValueRooter reviver(cx);
+    Value reviver = UndefinedValue();
 
-    if (!JS_ConvertArguments(cx, argc, Jsvalify(argv), "S / v", &s, reviver.addr()))
+    if (!JS_ConvertArguments(cx, argc, Jsvalify(argv), "S / v", &s, &reviver))
         return JS_FALSE;
 
     JSLinearString *linearStr = s->ensureLinear(cx);
     if (!linearStr)
         return JS_FALSE;
+    JS::Anchor<JSString *> anchor(linearStr);
 
-    JSONParser *jp = js_BeginJSONParse(cx, vp);
-    JSBool ok = jp != NULL;
-    if (ok) {
-        const jschar *chars = linearStr->chars();
-        size_t length = linearStr->length();
-        ok = js_ConsumeJSONText(cx, jp, chars, length);
-        ok &= !!js_FinishJSONParse(cx, jp, reviver.value());
-    }
-
-    return ok;
+    return ParseJSONWithReviver(cx, linearStr->chars(), linearStr->length(), reviver, vp);
 }
 
 JSBool
 js_json_stringify(JSContext *cx, uintN argc, Value *vp)
 {
     Value *argv = vp + 2;
     AutoValueRooter space(cx);
     AutoObjectRooter replacer(cx);
@@ -165,25 +158,29 @@ js_json_stringify(JSContext *cx, uintN a
     }
 
     return JS_TRUE;
 }
 
 JSBool
 js_TryJSON(JSContext *cx, Value *vp)
 {
-    // Checks whether the return value implements toJSON()
-    JSBool ok = JS_TRUE;
+    if (!vp->isObject())
+        return true;
 
-    if (vp->isObject()) {
-        JSObject *obj = &vp->toObject();
-        ok = js_TryMethod(cx, obj, cx->runtime->atomState.toJSONAtom, 0, NULL, vp);
+    JSObject *obj = &vp->toObject();
+    Value fval;
+    jsid id = ATOM_TO_JSID(cx->runtime->atomState.toJSONAtom);
+    if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval))
+        return false;
+    if (js_IsCallable(fval)) {
+        if (!ExternalInvoke(cx, ObjectValue(*obj), fval, 0, NULL, vp))
+            return false;
     }
-
-    return ok;
+    return true;
 }
 
 
 static const char quote = '\"';
 static const char backslash = '\\';
 static const char unicodeEscape[] = "\\u00";
 
 static JSBool
@@ -238,17 +235,17 @@ public:
         if (space.isObject()) {
             JSObject &obj = space.toObject();
             Class *clasp = obj.getClass();
             if (clasp == &js_NumberClass || clasp == &js_StringClass)
                 *gapValue.addr() = obj.getPrimitiveThis();
         }
 
         if (gapValue.value().isString()) {
-            if (!ValueToStringBuffer(cx, gapValue.value(), gap))
+            if (!gap.append(gapValue.value().toString()))
                 return false;
             if (gap.length() > 10)
                 gap.resize(10);
         } else if (gapValue.value().isNumber()) {
             jsdouble d = gapValue.value().isInt32()
                          ? gapValue.value().toInt32()
                          : js_DoubleToInteger(gapValue.value().toDouble());
             d = JS_MIN(10, d);
@@ -269,20 +266,17 @@ public:
 
     StringBuffer &sb;
     StringBuffer gap;
     JSObject *replacer;
     uint32 depth;
     HashSet<JSObject *> objectStack;
 };
 
-static JSBool CallReplacerFunction(JSContext *cx, jsid id, JSObject *holder,
-                                   StringifyContext *scx, Value *vp);
-static JSBool Str(JSContext *cx, jsid id, JSObject *holder,
-                  StringifyContext *scx, Value *vp, bool callReplacer = true);
+static JSBool Str(JSContext *cx, const Value &v, StringifyContext *scx);
 
 static JSBool
 WriteIndent(JSContext *cx, StringifyContext *scx, uint32 limit)
 {
     if (!scx->gap.empty()) {
         if (!scx->sb.append('\n'))
             return JS_FALSE;
         for (uint32 i = 0; i < limit; i++) {
@@ -314,207 +308,74 @@ class CycleDetector
         objectStack.remove(obj);
     }
 
   private:
     HashSet<JSObject *> &objectStack;
     JSObject *const obj;
 };
 
-static JSBool
-JO(JSContext *cx, Value *vp, StringifyContext *scx)
+/*
+ * ES5 15.12.3 Str, steps 2-4, extracted to enable preprocessing of property
+ * values when stringifying objects in JO.
+ */
+static bool
+PreprocessValue(JSContext *cx, JSObject *holder, jsid key, Value *vp, StringifyContext *scx)
 {
-    JSObject *obj = &vp->toObject();
-
-    CycleDetector detect(scx, obj);
-    if (!detect.init(cx))
-        return JS_FALSE;
-
-    if (!scx->sb.append('{'))
-        return JS_FALSE;
-
-    Value vec[3] = { NullValue(), NullValue(), NullValue() };
-    AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec);
-    Value& outputValue = vec[0];
-    Value& whitelistElement = vec[1];
-    AutoIdRooter idr(cx);
-    jsid& id = *idr.addr();
-
-    Value *keySource = vp;
-    bool usingWhitelist = false;
+    JSString *keyStr = NULL;
 
-    // if the replacer is an array, we use the keys from it
-    if (scx->replacer && JS_IsArrayObject(cx, scx->replacer)) {
-        usingWhitelist = true;
-        vec[2].setObject(*scx->replacer);
-        keySource = &vec[2];
-    }
-
-    JSBool memberWritten = JS_FALSE;
-    AutoIdVector props(cx);
-    if (!GetPropertyNames(cx, &keySource->toObject(), JSITER_OWNONLY, &props))
-        return JS_FALSE;
-
-    for (size_t i = 0, len = props.length(); i < len; i++) {
-        outputValue.setUndefined();
-
-        if (!usingWhitelist) {
-            if (!js_ValueToStringId(cx, IdToValue(props[i]), &id))
-                return JS_FALSE;
-        } else {
-            // skip non-index properties
-            jsuint index = 0;
-            if (!js_IdIsIndex(props[i], &index))
-                continue;
-
-            if (!scx->replacer->getProperty(cx, props[i], &whitelistElement))
-                return JS_FALSE;
+    /* Step 2. */
+    if (vp->isObject()) {
+        Value toJSON;
+        jsid id = ATOM_TO_JSID(cx->runtime->atomState.toJSONAtom);
+        if (!js_GetMethod(cx, &vp->toObject(), id, JSGET_NO_METHOD_BARRIER, &toJSON))
+            return false;
 
-            if (!js_ValueToStringId(cx, whitelistElement, &id))
-                return JS_FALSE;
-        }
-
-        // We should have a string id by this point. Either from 
-        // JS_Enumerate's id array, or by converting an element
-        // of the whitelist.
-        JS_ASSERT(JSID_IS_ATOM(id));
-
-        if (!JS_GetPropertyById(cx, obj, id, Jsvalify(&outputValue)))
-            return JS_FALSE;
-
-        if (outputValue.isObjectOrNull() && !js_TryJSON(cx, &outputValue))
-            return JS_FALSE;
-
-        // call this here, so we don't write out keys if the replacer function
-        // wants to elide the value.
-        if (!CallReplacerFunction(cx, id, obj, scx, &outputValue))
-            return JS_FALSE;
-
-        JSType type = JS_TypeOfValue(cx, Jsvalify(outputValue));
+        if (js_IsCallable(toJSON)) {
+            keyStr = IdToString(cx, key);
+            if (!keyStr)
+                return false;
 
-        // elide undefined values and functions and XML
-        if (outputValue.isUndefined() || type == JSTYPE_FUNCTION || type == JSTYPE_XML)
-            continue;
-
-        // output a comma unless this is the first member to write
-        if (memberWritten && !scx->sb.append(','))
-            return JS_FALSE;
-        memberWritten = JS_TRUE;
-
-        if (!WriteIndent(cx, scx, scx->depth))
-            return JS_FALSE;
+            LeaveTrace(cx);
+            InvokeArgsGuard args;
+            if (!cx->stack().pushInvokeArgs(cx, 1, &args))
+                return false;
 
-        // Be careful below, this string is weakly rooted
-        JSString *s = js_ValueToString(cx, IdToValue(id));
-        if (!s)
-            return JS_FALSE;
+            args.callee() = toJSON;
+            args.thisv() = *vp;
+            args[0] = StringValue(keyStr);
 
-        JS::Anchor<JSString *> anchor(s);
-        size_t length = s->length();
-        const jschar *chars = s->getChars(cx);
-        if (!chars)
-            return JS_FALSE;
-
-        if (!write_string(cx, scx->sb, chars, length) ||
-            !scx->sb.append(':') ||
-            !(scx->gap.empty() || scx->sb.append(' ')) ||
-            !Str(cx, id, obj, scx, &outputValue, true)) {
-            return JS_FALSE;
+            if (!Invoke(cx, args, 0))
+                return false;
+            *vp = args.rval();
         }
     }
 
-    if (memberWritten && !WriteIndent(cx, scx, scx->depth - 1))
-        return JS_FALSE;
-
-    return scx->sb.append('}');
-}
-
-static JSBool
-JA(JSContext *cx, Value *vp, StringifyContext *scx)
-{
-    JSObject *obj = &vp->toObject();
-
-    CycleDetector detect(scx, obj);
-    if (!detect.init(cx))
-        return JS_FALSE;
-
-    if (!scx->sb.append('['))
-        return JS_FALSE;
-
-    jsuint length;
-    if (!js_GetLengthProperty(cx, obj, &length))
-        return JS_FALSE;
-
-    if (length != 0 && !WriteIndent(cx, scx, scx->depth))
-        return JS_FALSE;
-
-    AutoValueRooter outputValue(cx);
-
-    jsid id;
-    jsuint i;
-    for (i = 0; i < length; i++) {
-        id = INT_TO_JSID(i);
-
-        if (!obj->getProperty(cx, id, outputValue.addr()))
-            return JS_FALSE;
-
-        if (!Str(cx, id, obj, scx, outputValue.addr()))
-            return JS_FALSE;
-
-        if (outputValue.value().isUndefined()) {
-            if (!scx->sb.append("null"))
-                return JS_FALSE;
+    /* Step 3. */
+    if (scx->replacer && scx->replacer->isCallable()) {
+        if (!keyStr) {
+            keyStr = IdToString(cx, key);
+            if (!keyStr)
+                return false;
         }
 
-        if (i < length - 1) {
-            if (!scx->sb.append(','))
-                return JS_FALSE;
-            if (!WriteIndent(cx, scx, scx->depth))
-                return JS_FALSE;
-        }
-    }
-
-    if (length != 0 && !WriteIndent(cx, scx, scx->depth - 1))
-        return JS_FALSE;
-
-    return scx->sb.append(']');
-}
+        LeaveTrace(cx);
+        InvokeArgsGuard args;
+        if (!cx->stack().pushInvokeArgs(cx, 2, &args))
+            return false;
 
-static JSBool
-CallReplacerFunction(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, Value *vp)
-{
-    if (scx->replacer && scx->replacer->isCallable()) {
-        Value vec[2] = { IdToValue(id), *vp};
-        if (!JS_CallFunctionValue(cx, holder, OBJECT_TO_JSVAL(scx->replacer),
-                                  2, Jsvalify(vec), Jsvalify(vp))) {
-            return JS_FALSE;
-        }
-    }
-
-    return JS_TRUE;
-}
+        args.callee() = ObjectValue(*scx->replacer);
+        args.thisv() = ObjectValue(*holder);
+        args[0] = StringValue(keyStr);
+        args[1] = *vp;
 
-static JSBool
-Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, Value *vp, bool callReplacer)
-{
-    JS_CHECK_RECURSION(cx, return false);
-
-    /*
-     * This method implements the Str algorithm in ES5 15.12.3, but we move
-     * property retrieval (step 1) into callers to stream the stringification
-     * process and avoid constantly copying strings.
-     */
-
-    /* Step 2. */
-    if (vp->isObject() && !js_TryJSON(cx, vp))
-        return false;
-
-    /* Step 3. */
-    if (callReplacer && !CallReplacerFunction(cx, id, holder, scx, vp))
-        return false;
+        if (!Invoke(cx, args, 0))
+            return false;
+        *vp = args.rval();
+    }
 
     /* Step 4. */
     if (vp->isObject()) {
         JSObject *obj = &vp->toObject();
         Class *clasp = obj->getClass();
         if (clasp == &js_NumberClass) {
             double d;
             if (!ValueToNumber(cx, *vp, &d))
@@ -522,87 +383,303 @@ Str(JSContext *cx, jsid id, JSObject *ho
             vp->setNumber(d);
         } else if (clasp == &js_StringClass) {
             JSString *str = js_ValueToString(cx, *vp);
             if (!str)
                 return false;
             vp->setString(str);
         } else if (clasp == &js_BooleanClass) {
             *vp = obj->getPrimitiveThis();
+            JS_ASSERT(vp->isBoolean());
         }
     }
 
+    return true;
+}
+
+/*
+ * Determines whether a value which has passed by ES5 150.2.3 Str steps 1-4's
+ * gauntlet will result in Str returning |undefined|.  This function is used to
+ * properly omit properties resulting in such values when stringifying objects,
+ * while properly stringifying such properties as null when they're encountered
+ * in arrays.
+ */
+static inline bool
+IsFilteredValue(const Value &v)
+{
+    return v.isUndefined() || js_IsCallable(v) || (v.isObject() && v.toObject().isXML());
+}
+
+/* ES5 15.12.3 JO. */
+static JSBool
+JO(JSContext *cx, JSObject *obj, StringifyContext *scx)
+{
+    /*
+     * This method implements the JO algorithm in ES5 15.12.3, but:
+     *
+     *   * The algorithm is somewhat reformulated to allow the final string to
+     *     be streamed into a single buffer, rather than be created and copied
+     *     into place incrementally as the ES5 algorithm specifies it.  This
+     *     requires moving portions of the Str call in 8a into this algorithm
+     *     (and in JA as well).
+     */
+
+    /* Steps 1-2, 11. */
+    CycleDetector detect(scx, obj);
+    if (!detect.init(cx))
+        return JS_FALSE;
+
+    if (!scx->sb.append('{'))
+        return JS_FALSE;
+
+    AutoIdRooter idr(cx);
+    jsid& id = *idr.addr();
+
+    /* Steps 5-7. */
+    /* XXX Bug 648471: Do this in js_Stringify, rename keySource. */
+    Value keySource = ObjectValue(*obj);
+    bool usingWhitelist = false;
+
+    // if the replacer is an array, we use the keys from it
+    if (scx->replacer && JS_IsArrayObject(cx, scx->replacer)) {
+        usingWhitelist = true;
+        keySource.setObject(*scx->replacer);
+    }
+
+    bool wroteMember = false;
+    AutoIdVector props(cx);
+    if (!GetPropertyNames(cx, &keySource.toObject(), JSITER_OWNONLY, &props))
+        return JS_FALSE;
+
+    /* Steps 8-10, 13. */
+    for (size_t i = 0, len = props.length(); i < len; i++) {
+        if (!usingWhitelist) {
+            if (!js_ValueToStringId(cx, IdToValue(props[i]), &id))
+                return JS_FALSE;
+        } else {
+            // skip non-index properties
+            jsuint index = 0;
+            if (!js_IdIsIndex(props[i], &index))
+                continue;
+
+            Value whitelistElement;
+            if (!scx->replacer->getProperty(cx, props[i], &whitelistElement))
+                return JS_FALSE;
+
+            if (!js_ValueToStringId(cx, whitelistElement, &id))
+                return JS_FALSE;
+        }
+
+        /*
+         * Steps 8a-8b.  Note that the call to Str is broken up into 1) getting
+         * the property; 2) processing for toJSON, calling the replacer, and
+         * handling boxed Number/String/Boolean objects; 3) filtering out
+         * values which process to |undefined|, and 4) stringifying all values
+         * which pass the filter.
+         */
+        Value outputValue;
+        if (!obj->getProperty(cx, id, &outputValue))
+            return JS_FALSE;
+        if (!PreprocessValue(cx, obj, id, &outputValue, scx))
+            return JS_FALSE;
+        if (IsFilteredValue(outputValue))
+            continue;
+
+        /* Output a comma unless this is the first member to write. */
+        if (wroteMember && !scx->sb.append(','))
+            return JS_FALSE;
+        wroteMember = true;
+
+        if (!WriteIndent(cx, scx, scx->depth))
+            return JS_FALSE;
+
+        // Be careful below: this string is weakly rooted!
+        JSString *s = js_ValueToString(cx, IdToValue(id));
+        if (!s)
+            return JS_FALSE;
+
+        JS::Anchor<JSString *> anchor(s);
+        size_t length = s->length();
+        const jschar *chars = s->getChars(cx);
+        if (!chars)
+            return JS_FALSE;
+
+        if (!write_string(cx, scx->sb, chars, length) ||
+            !scx->sb.append(':') ||
+            !(scx->gap.empty() || scx->sb.append(' ')) ||
+            !Str(cx, outputValue, scx)) {
+            return JS_FALSE;
+        }
+    }
+
+    if (wroteMember && !WriteIndent(cx, scx, scx->depth - 1))
+        return JS_FALSE;
+
+    return scx->sb.append('}');
+}
+
+/* ES5 15.12.3 JA. */
+static JSBool
+JA(JSContext *cx, JSObject *obj, StringifyContext *scx)
+{
+    /*
+     * This method implements the JA algorithm in ES5 15.12.3, but:
+     *
+     *   * The algorithm is somewhat reformulated to allow the final string to
+     *     be streamed into a single buffer, rather than be created and copied
+     *     into place incrementally as the ES5 algorithm specifies it.  This
+     *     requires moving portions of the Str call in 8a into this algorithm
+     *     (and in JO as well).
+     */
+
+    /* Steps 1-2, 11. */
+    CycleDetector detect(scx, obj);
+    if (!detect.init(cx))
+        return JS_FALSE;
+
+    if (!scx->sb.append('['))
+        return JS_FALSE;
+
+    /* Step 6. */
+    jsuint length;
+    if (!js_GetLengthProperty(cx, obj, &length))
+        return JS_FALSE;
+
+    /* Steps 7-10. */
+    if (length != 0) {
+        /* Steps 4, 10b(i). */
+        if (!WriteIndent(cx, scx, scx->depth))
+            return JS_FALSE;
+
+        /* Steps 7-10. */
+        Value outputValue;
+        for (jsuint i = 0; i < length; i++) {
+            jsid id = INT_TO_JSID(i);
+
+            /*
+             * Steps 8a-8c.  Again note how the call to the spec's Str method
+             * is broken up into getting the property, running it past toJSON
+             * and the replacer and maybe unboxing, and interpreting some
+             * values as |null| in separate steps.
+             */
+            if (!obj->getProperty(cx, id, &outputValue))
+                return JS_FALSE;
+            if (!PreprocessValue(cx, obj, id, &outputValue, scx))
+                return JS_FALSE;
+            if (IsFilteredValue(outputValue)) {
+                if (!scx->sb.append("null"))
+                    return JS_FALSE;
+            } else {
+                if (!Str(cx, outputValue, scx))
+                    return JS_FALSE;
+            }
+
+            /* Steps 3, 4, 10b(i). */
+            if (i < length - 1) {
+                if (!scx->sb.append(','))
+                    return JS_FALSE;
+                if (!WriteIndent(cx, scx, scx->depth))
+                    return JS_FALSE;
+            }
+        }
+
+        /* Step 10(b)(iii). */
+        if (!WriteIndent(cx, scx, scx->depth - 1))
+            return JS_FALSE;
+    }
+
+    return scx->sb.append(']');
+}
+
+static JSBool
+Str(JSContext *cx, const Value &v, StringifyContext *scx)
+{
+    /* Step 11 must be handled by the caller. */
+    JS_ASSERT(!IsFilteredValue(v));
+
+    JS_CHECK_RECURSION(cx, return false);
+
+    /*
+     * This method implements the Str algorithm in ES5 15.12.3, but:
+     *
+     *   * We move property retrieval (step 1) into callers to stream the
+     *     stringification process and avoid constantly copying strings.
+     *   * We move the preprocessing in steps 2-4 into a helper function to
+     *     allow both JO and JA to use this method.  While JA could use it
+     *     without this move, JO must omit any |undefined|-valued property per
+     *     so it can't stream out a value using the Str method exactly as
+     *     defined by ES5.
+     *   * We move step 11 into callers, again to ease streaming.
+     */
+
     /* Step 8. */
-    if (vp->isString()) {
-        JSString *str = vp->toString();
+    if (v.isString()) {
+        JSString *str = v.toString();
         size_t length = str->length();
         const jschar *chars = str->getChars(cx);
         if (!chars)
             return false;
         return write_string(cx, scx->sb, chars, length);
     }
 
     /* Step 5. */
-    if (vp->isNull())
+    if (v.isNull())
         return scx->sb.append("null");
 
     /* Steps 6-7. */
-    if (vp->isBoolean())
-        return vp->toBoolean() ? scx->sb.append("true") : scx->sb.append("false");
+    if (v.isBoolean())
+        return v.toBoolean() ? scx->sb.append("true") : scx->sb.append("false");
 
     /* Step 9. */
-    if (vp->isNumber()) {
-        if (vp->isDouble()) {
-            jsdouble d = vp->toDouble();
-            if (!JSDOUBLE_IS_FINITE(d))
+    if (v.isNumber()) {
+        if (v.isDouble()) {
+            if (!JSDOUBLE_IS_FINITE(v.toDouble()))
                 return scx->sb.append("null");
         }
 
         StringBuffer sb(cx);
-        if (!NumberValueToStringBuffer(cx, *vp, sb))
+        if (!NumberValueToStringBuffer(cx, v, sb))
             return false;
 
         return scx->sb.append(sb.begin(), sb.length());
     }
 
     /* Step 10. */
-    if (vp->isObject() && !IsFunctionObject(*vp) && !IsXML(*vp)) {
-        JSBool ok;
-
-        scx->depth++;
-        ok = (JS_IsArrayObject(cx, &vp->toObject()) ? JA : JO)(cx, vp, scx);
-        scx->depth--;
+    JS_ASSERT(v.isObject());
+    JSBool ok;
 
-        return ok;
-    }
+    scx->depth++;
+    ok = (JS_IsArrayObject(cx, &v.toObject()) ? JA : JO)(cx, &v.toObject(), scx);
+    scx->depth--;
 
-    /* Step 11. */
-    vp->setUndefined();
-    return true;
+    return ok;
 }
 
 JSBool
 js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, const Value &space,
              StringBuffer &sb)
 {
     StringifyContext scx(cx, sb, replacer);
     if (!scx.initializeGap(cx, space) || !scx.initializeStack())
         return JS_FALSE;
 
     JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!obj)
         return JS_FALSE;
 
     AutoObjectRooter tvr(cx, obj);
-    if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
-                             *vp, NULL, NULL, JSPROP_ENUMERATE)) {
+    jsid emptyId = ATOM_TO_JSID(cx->runtime->atomState.emptyAtom);
+    if (!obj->defineProperty(cx, emptyId, *vp, NULL, NULL, JSPROP_ENUMERATE))
         return JS_FALSE;
-    }
 
-    return Str(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, &scx, vp);
+    if (!PreprocessValue(cx, obj, emptyId, vp, &scx))
+        return JS_FALSE;
+    if (IsFilteredValue(*vp))
+        return JS_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');
 }
 
@@ -679,17 +756,17 @@ Walk(JSContext *cx, jsid id, JSObject *h
     *vp = reviverResult;
     return true;
 }
 
 static JSBool
 JSONParseError(JSONParser *jp, JSContext *cx)
 {
     if (!jp->suppressErrors)
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE);
+        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);
@@ -762,25 +839,53 @@ js_FinishJSONParse(JSContext *cx, JSONPa
 
     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 (reviver.isObject() && reviver.toObject().isCallable()) {
+    } 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
+    JSONSourceParser parser(cx, chars, length,
+                            decodingMode == STRICT
+                            ? JSONSourceParser::StrictJSON
+                            : JSONSourceParser::LegacyJSON);
+    if (!parser.parse(vp))
+        return false;
+    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);
     }
 
--- a/js/src/json.h
+++ b/js/src/json.h
@@ -129,9 +129,17 @@ 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 */
+
 #endif /* json_h___ */
new file mode 100644
--- /dev/null
+++ b/js/src/jsonparser.cpp
@@ -0,0 +1,695 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** 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
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jeff Walden <jwalden+code@mit.edu> (original author)
+ *
+ * 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 "jsarray.h"
+#include "jsnum.h"
+#include "jsonparser.h"
+
+#include "jsobjinlines.h"
+#include "jsstrinlines.h"
+
+using namespace js;
+
+void
+JSONSourceParser::error(const char *msg)
+{
+    if (errorHandling == RaiseError)
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE, msg);
+}
+
+bool
+JSONSourceParser::errorReturn()
+{
+    return errorHandling == NoError;
+}
+
+template<JSONSourceParser::StringType ST>
+JSONSourceParser::Token
+JSONSourceParser::readString()
+{
+    JS_ASSERT(current < end);
+    JS_ASSERT(*current == '"');
+
+    /*
+     * JSONString:
+     *   /^"([^\u0000-\u001F"\\]|\\(["/\\bfnrt]|u[0-9a-fA-F]{4}))*"$/
+     */
+
+    if (++current == end) {
+        error("unterminated string literal");
+        return token(Error);
+    }
+
+    /*
+     * 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)
+                                ? js_AtomizeChars(cx, start, length, 0)
+                                : js_NewStringCopyN(cx, start, length);
+            if (!str)
+                return token(OOM);
+            return stringToken(str);
+        }
+
+        if (*current == '\\')
+            break;
+
+        if (*current <= 0x001F) {
+            error("bad control character in string literal");
+            return token(Error);
+        }
+    }
+
+    /*
+     * Slow case: string contains escaped characters.  Copy a maximal sequence
+     * of unescaped characters into a temporary buffer, then an escaped
+     * character, and repeat until the entire string is consumed.
+     */
+    StringBuffer buffer(cx);
+    do {
+        if (start < current && !buffer.append(start, current))
+            return token(OOM);
+
+        if (current >= end)
+            break;
+
+        jschar c = *current++;
+        if (c == '"') {
+            JSFlatString *str = (ST == JSONSourceParser::PropertyName)
+                                ? buffer.finishAtom()
+                                : buffer.finishString();
+            if (!str)
+                return token(OOM);
+            return stringToken(str);
+        }
+
+        if (c != '\\') {
+            error("bad character in string literal");
+            return token(Error);
+        }
+
+        if (current >= end)
+            break;
+
+        switch (*current++) {
+          case '"':  c = '"';  break;
+          case '/':  c = '/';  break;
+          case '\\': c = '\\'; 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;
+
+          case 'u':
+            if (end - current < 4) {
+                error("bad Unicode escape");
+                return token(Error);
+            }
+            if (JS7_ISHEX(current[0]) &&
+                JS7_ISHEX(current[1]) &&
+                JS7_ISHEX(current[2]) &&
+                JS7_ISHEX(current[3]))
+            {
+                c = (JS7_UNHEX(current[0]) << 12)
+                  | (JS7_UNHEX(current[1]) << 8)
+                  | (JS7_UNHEX(current[2]) << 4)
+                  | (JS7_UNHEX(current[3]));
+                current += 4;
+                break;
+            }
+            /* FALL THROUGH */
+
+          default:
+            error("bad escaped character");
+            return token(Error);
+        }
+        if (!buffer.append(c))
+            return token(OOM);
+
+        start = current;
+        for (; current < end; current++) {
+            if (*current == '"' || *current == '\\' || *current <= 0x001F)
+                break;
+        }
+    } while (current < end);
+
+    error("unterminated string");
+    return token(Error);
+}
+
+JSONSourceParser::Token
+JSONSourceParser::readNumber()
+{
+    JS_ASSERT(current < end);
+    JS_ASSERT(JS7_ISDEC(*current) || *current == '-');
+
+    /*
+     * JSONNumber:
+     *   /^-?(0|[1-9][0-9]+)(\.[0-9]+)?([eE][\+\-]?[0-9]+)?$/
+     */
+
+    bool negative = *current == '-';
+
+    /* -? */
+    if (negative && ++current == end) {
+        error("no number after minus sign");
+        return token(Error);
+    }
+
+    const RangeCheckedPointer<const jschar> digitStart = current;
+
+    /* 0|[1-9][0-9]+ */
+    if (!JS7_ISDEC(*current)) {
+        error("unexpected non-digit");
+        return token(Error);
+    }
+    if (*current++ != '0') {
+        for (; current < end; current++) {
+            if (!JS7_ISDEC(*current))
+                break;
+        }
+    }
+
+    /* Fast path: no fractional or exponent part. */
+    if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) {
+        const jschar *dummy;
+        jsdouble d;
+        if (!GetPrefixInteger(cx, digitStart, current, 10, &dummy, &d))
+            return token(OOM);
+        JS_ASSERT(current == dummy);
+        return numberToken(negative ? -d : d);
+    }
+
+    /* (\.[0-9]+)? */
+    if (current < end && *current == '.') {
+        if (++current == end) {
+            error("missing digits after decimal point");
+            return token(Error);
+        }
+        if (!JS7_ISDEC(*current)) {
+            error("unterminated fractional number");
+            return token(Error);
+        }
+        while (++current < end) {
+            if (!JS7_ISDEC(*current))
+                break;
+        }
+    }
+
+    /* ([eE][\+\-]?[0-9]+)? */
+    if (current < end && (*current == 'e' || *current == 'E')) {
+        if (++current == end) {
+            error("missing digits after exponent indicator");
+            return token(Error);
+        }
+        if (*current == '+' || *current == '-') {
+            if (++current == end) {
+                error("missing digits after exponent sign");
+                return token(Error);
+            }
+        }
+        if (!JS7_ISDEC(*current)) {
+            error("exponent part is missing a number");
+            return token(Error);
+        }
+        while (++current < end) {
+            if (!JS7_ISDEC(*current))
+                break;
+        }
+    }
+
+    jsdouble d;
+    const jschar *finish;
+    if (!js_strtod(cx, digitStart, current, &finish, &d))
+        return token(OOM);
+    JS_ASSERT(current == finish);
+    return numberToken(negative ? -d : d);
+}
+
+static inline bool
+IsJSONWhitespace(jschar c)
+{
+    return c == '\t' || c == '\r' || c == '\n' || c == ' ';
+}
+
+JSONSourceParser::Token
+JSONSourceParser::advance()
+{
+    while (current < end && IsJSONWhitespace(*current))
+        current++;
+    if (current >= end) {
+        error("unexpected end of data");
+        return token(Error);
+    }
+
+    switch (*current) {
+      case '"':
+        return readString<LiteralValue>();
+
+      case '-':
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        return readNumber();
+
+      case 't':
+        if (end - current < 4 || current[1] != 'r' || current[2] != 'u' || current[3] != 'e') {
+            error("unexpected keyword");
+            return token(Error);
+        }
+        current += 4;
+        return token(True);
+
+      case 'f':
+        if (end - current < 5 ||
+            current[1] != 'a' || current[2] != 'l' || current[3] != 's' || current[4] != 'e')
+        {
+            error("unexpected keyword");
+            return token(Error);
+        }
+        current += 5;
+        return token(False);
+
+      case 'n':
+        if (end - current < 4 || current[1] != 'u' || current[2] != 'l' || current[3] != 'l') {
+            error("unexpected keyword");
+            return token(Error);
+        }
+        current += 4;
+        return token(Null);
+
+      case '[':
+        current++;
+        return token(ArrayOpen);
+      case ']':
+        current++;
+        return token(ArrayClose);
+
+      case '{':
+        current++;
+        return token(ObjectOpen);
+      case '}':
+        current++;
+        return token(ObjectClose);
+
+      case ',':
+        current++;
+        return token(Comma);
+
+      case ':':
+        current++;
+        return token(Colon);
+
+      default:
+        error("unexpected character");
+        return token(Error);
+    }
+}
+
+JSONSourceParser::Token
+JSONSourceParser::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);
+    }
+
+    if (*current == '"')
+        return readString<PropertyName>();
+
+    if (*current == '}') {
+        current++;
+        return token(ObjectClose);
+    }
+
+    error("expected property name or '}'");
+    return token(Error);
+}
+
+static inline void
+AssertPastValue(const jschar *current)
+{
+    /*
+     * We're past an arbitrary JSON value, so the previous character is
+     * *somewhat* constrained, even if this assertion is pretty broad.  Don't
+     * knock it till you tried it: this assertion *did* catch a bug once.
+     */
+    JS_ASSERT((current[-1] == 'l' &&
+               current[-2] == 'l' &&
+               current[-3] == 'u' &&
+               current[-4] == 'n') ||
+              (current[-1] == 'e' &&
+               current[-2] == 'u' &&
+               current[-3] == 'r' &&
+               current[-4] == 't') ||
+              (current[-1] == 'e' &&
+               current[-2] == 's' &&
+               current[-3] == 'l' &&
+               current[-4] == 'a' &&
+               current[-5] == 'f') ||
+              current[-1] == '}' ||
+              current[-1] == ']' ||
+              current[-1] == '"' ||
+              JS7_ISDEC(current[-1]));
+}
+
+JSONSourceParser::Token
+JSONSourceParser::advanceAfterArrayElement()
+{
+    AssertPastValue(current);
+
+    while (current < end && IsJSONWhitespace(*current))
+        current++;
+    if (current >= end) {
+        error("end of data when ',' or ']' was expected");
+        return token(Error);
+    }
+
+    if (*current == ',') {
+        current++;
+        return token(Comma);
+    }
+
+    if (*current == ']') {
+        current++;
+        return token(ArrayClose);
+    }
+
+    error("expected ',' or ']' after array element");
+    return token(Error);
+}
+
+JSONSourceParser::Token
+JSONSourceParser::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);
+    }
+
+    if (*current == '"')
+        return readString<PropertyName>();
+
+    if (parsingMode == LegacyJSON && *current == '}') {
+        /*
+         * Previous JSON parsing accepted trailing commas in non-empty object
+         * syntax, and some users depend on this.  (Specifically, Places data
+         * serialization in versions of Firefox before 4.0.  We can remove this
+         * mode when profile upgrades from 3.6 become unsupported.)  Permit
+         * such trailing commas only when legacy parsing is specifically
+         * requested.
+         */
+        current++;
+        return token(ObjectClose);
+    }
+
+    error("expected double-quoted property name");
+    return token(Error);
+}
+
+JSONSourceParser::Token
+JSONSourceParser::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);
+    }
+
+    if (*current == ':') {
+        current++;
+        return token(Colon);
+    }
+
+    error("expected ':' after property name in object");
+    return token(Error);
+}
+
+JSONSourceParser::Token
+JSONSourceParser::advanceAfterProperty()
+{
+    AssertPastValue(current);
+
+    while (current < end && IsJSONWhitespace(*current))
+        current++;
+    if (current >= end) {
+        error("end of data after property value in object");
+        return token(Error);
+    }
+
+    if (*current == ',') {
+        current++;
+        return token(Comma);
+    }
+
+    if (*current == '}') {
+        current++;
+        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!
+ */
+enum ParserState { FinishArrayElement, FinishObjectMember, JSONValue };
+
+bool
+JSONSourceParser::parse(Value *vp)
+{
+    Vector<ParserState> stateStack(cx);
+    AutoValueVector valueStack(cx);
+
+    *vp = UndefinedValue();
+
+    Token token;
+    ParserState state = JSONValue;
+    while (true) {
+        switch (state) {
+          case FinishObjectMember: {
+            Value v = valueStack.popCopy();
+            /*
+             * NB: Relies on js_DefineNativeProperty performing
+             *     js_CheckForStringIndex.
+             */
+            jsid propid = ATOM_TO_JSID(&valueStack.popCopy().toString()->asAtom());
+            if (!js_DefineNativeProperty(cx, &valueStack.back().toObject(), propid, v,
+                                         PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE,
+                                         0, 0, NULL))
+            {
+                return false;
+            }
+            token = advanceAfterProperty();
+            if (token == ObjectClose)
+                break;
+            if (token != Comma) {
+                if (token == OOM)
+                    return false;
+                if (token != Error)
+                    error("expected ',' or '}' after property-value pair in object literal");
+                return errorReturn();
+            }
+            token = advancePropertyName();
+            /* FALL THROUGH */
+          }
+
+          JSONMember:
+            if (token == String) {
+                if (!valueStack.append(atomValue()))
+                    return false;
+                token = advancePropertyColon();
+                if (token != Colon) {
+                    JS_ASSERT(token == Error);
+                    return errorReturn();
+                }
+                if (!stateStack.append(FinishObjectMember))
+                    return false;
+                goto JSONValue;
+            }
+            if (token == ObjectClose) {
+                JS_ASSERT(state == FinishObjectMember);
+                JS_ASSERT(parsingMode == LegacyJSON);
+                break;
+            }
+            if (token == OOM)
+                return false;
+            if (token != Error)
+                error("property names must be double-quoted strings");
+            return errorReturn();
+
+          case FinishArrayElement: {
+            Value v = valueStack.popCopy();
+            if (!js_ArrayCompPush(cx, &valueStack.back().toObject(), v))
+                return false;
+            token = advanceAfterArrayElement();
+            if (token == Comma) {
+                if (!stateStack.append(FinishArrayElement))
+                    return false;
+                goto JSONValue;
+            }
+            if (token == ArrayClose)
+                break;
+            JS_ASSERT(token == Error);
+            return errorReturn();
+          }
+
+          JSONValue:
+          case JSONValue:
+            token = advance();
+          JSONValueSwitch:
+            switch (token) {
+              case String:
+              case Number:
+                if (!valueStack.append(token == String ? stringValue() : numberValue()))
+                    return false;
+                break;
+              case True:
+                if (!valueStack.append(BooleanValue(true)))
+                    return false;
+                break;
+              case False:
+                if (!valueStack.append(BooleanValue(false)))
+                    return false;
+                break;
+              case Null:
+                if (!valueStack.append(NullValue()))
+                    return false;
+                break;
+
+              case ArrayOpen: {
+                JSObject *obj = NewDenseEmptyArray(cx);
+                if (!obj || !valueStack.append(ObjectValue(*obj)))
+                    return false;
+                token = advance();
+                if (token == ArrayClose)
+                    break;
+                if (!stateStack.append(FinishArrayElement))
+                    return false;
+                goto JSONValueSwitch;
+              }
+
+              case ObjectOpen: {
+                JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
+                if (!obj || !valueStack.append(ObjectValue(*obj)))
+                    return false;
+                token = advanceAfterObjectOpen();
+                if (token == ObjectClose)
+                    break;
+                goto JSONMember;
+              }
+
+              case ArrayClose:
+                if (parsingMode == LegacyJSON &&
+                    !stateStack.empty() &&
+                    stateStack.back() == FinishArrayElement) {
+                    /*
+                     * Previous JSON parsing accepted trailing commas in
+                     * non-empty array syntax, and some users depend on this.
+                     * (Specifically, Places data serialization in versions of
+                     * Firefox prior to 4.0.  We can remove this mode when
+                     * profile upgrades from 3.6 become unsupported.)  Permit
+                     * such trailing commas only when specifically
+                     * instructed to do so.
+                     */
+                    stateStack.popBack();
+                    break;
+                }
+                /* FALL THROUGH */
+
+              case ObjectClose:
+              case Colon:
+              case Comma:
+                error("unexpected character");
+                return errorReturn();
+
+              case OOM:
+                return false;
+
+              case Error:
+                return errorReturn();
+            }
+            break;
+        }
+
+        if (stateStack.empty())
+            break;
+        state = stateStack.popCopy();
+    }
+
+    for (; current < end; current++) {
+        if (!IsJSONWhitespace(*current)) {
+            error("unexpected non-whitespace character after JSON data");
+            return errorReturn();
+        }
+    }
+
+    JS_ASSERT(end == current);
+    JS_ASSERT(valueStack.length() == 1);
+    *vp = valueStack[0];
+    return true;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jsonparser.h
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** 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
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jeff Walden <jwalden+code@mit.edu> (original author)
+ *
+ * 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 jsonparser_h___
+#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
+{
+  public:
+    enum ErrorHandling { RaiseError, NoError };
+    enum ParsingMode { StrictJSON, LegacyJSON };
+
+  private:
+    /* Data members */
+
+    JSContext * const cx;
+    js::RangeCheckedPointer<const jschar> current;
+    const js::RangeCheckedPointer<const jschar> end;
+
+    js::Value v;
+
+    const ParsingMode parsingMode;
+    const ErrorHandling errorHandling;
+
+    enum Token { String, Number, True, False, Null,
+                 ArrayOpen, ArrayClose,
+                 ObjectOpen, ObjectClose,
+                 Colon, Comma,
+                 OOM, Error };
+#ifdef DEBUG
+    Token lastToken;
+#endif
+
+  public:
+    /* 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)
+      : cx(cx),
+        current(data, data, length),
+        end(data + length, data, length),
+        parsingMode(parsingMode),
+        errorHandling(errorHandling)
+#ifdef DEBUG
+      , lastToken(Error)
+#endif
+    {
+        JS_ASSERT(current <= end);
+    }
+
+    /*
+     * Parse the JSON data specified at construction time.  If it parses
+     * successfully, store the prescribed value in *vp and return true.  If an
+     * internal error (e.g. OOM) occurs during parsing, return false.
+     * Otherwise, if invalid input was specifed but no internal error occurred,
+     * behavior depends upon the error handling specified at construction: if
+     * error handling is RaiseError then throw a SyntaxError and return false,
+     * otherwise return true and set *vp to |undefined|.  (JSON syntax can't
+     * represent |undefined|, so the JSON data couldn't have specified it.)
+     */
+    bool parse(js::Value *vp);
+
+  private:
+    js::Value numberValue() const {
+        JS_ASSERT(lastToken == Number);
+        JS_ASSERT(v.isNumber());
+        return v;
+    }
+
+    js::Value stringValue() const {
+        JS_ASSERT(lastToken == String);
+        JS_ASSERT(v.isString());
+        return v;
+    }
+
+    js::Value atomValue() const {
+        js::Value strval = stringValue();
+        JS_ASSERT(strval.toString()->isAtom());
+        return strval;
+    }
+
+    Token token(Token t) {
+        JS_ASSERT(t != String);
+        JS_ASSERT(t != Number);
+#ifdef DEBUG
+        lastToken = t;
+#endif
+        return t;
+    }
+
+    Token stringToken(JSString *str) {
+        this->v = js::StringValue(str);
+#ifdef DEBUG
+        lastToken = String;
+#endif
+        return String;
+    }
+
+    Token numberToken(jsdouble d) {
+        this->v = js::NumberValue(d);
+#ifdef DEBUG
+        lastToken = Number;
+#endif
+        return Number;
+    }
+
+    enum StringType { PropertyName, LiteralValue };
+    template<StringType ST> Token readString();
+
+    Token readNumber();
+
+    Token advance();
+    Token advancePropertyName();
+    Token advancePropertyColon();
+    Token advanceAfterProperty();
+    Token advanceAfterObjectOpen();
+    Token advanceAfterArrayElement();
+
+    void error(const char *msg);
+    bool errorReturn();
+};
+
+#endif /* jsonparser_h___ */
--- a/js/src/jspropertycache.h
+++ b/js/src/jspropertycache.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=98:
  *
  * ***** 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
@@ -163,18 +163,19 @@ class PropertyCache
     enum {
         SIZE_LOG2 = 12,
         SIZE = JS_BIT(SIZE_LOG2),
         MASK = JS_BITMASK(SIZE_LOG2)
     };
 
     PropertyCacheEntry  table[SIZE];
     JSBool              empty;
+
+  public:
 #ifdef JS_PROPERTY_CACHE_METERING
-  public:
     PropertyCacheEntry  *pctestentry;   /* entry of the last PC-based test */
     uint32              fills;          /* number of cache entry fills */
     uint32              nofills;        /* couldn't fill (e.g. default get) */
     uint32              rofills;        /* set on read-only prop can't fill */
     uint32              disfills;       /* fill attempts on disabled cache */
     uint32              oddfills;       /* fill attempt after setter deleted */
     uint32              add2dictfills;  /* fill attempt on dictionary object */
     uint32              modfills;       /* fill that rehashed to a new entry */
@@ -195,22 +196,27 @@ class PropertyCache
     uint32              setpcmisses;    /* setting/adding property pc misses */
     uint32              setmisses;      /* JSOP_SET{NAME,PROP} total misses */
     uint32              kpcmisses;      /* slow-path key id == atom misses */
     uint32              kshapemisses;   /* slow-path key object misses */
     uint32              vcapmisses;     /* value capability misses */
     uint32              misses;         /* cache misses */
     uint32              flushes;        /* cache flushes */
     uint32              pcpurges;       /* shadowing purges on proto chain */
-  private:
+
 # define PCMETER(x)     x
 #else
 # define PCMETER(x)     ((void)0)
 #endif
 
+    PropertyCache() {
+        PodZero(this);
+    }
+    
+  private:
     /*
      * Add kshape rather than xor it to avoid collisions between nearby bytecode
      * that are evolving an object by setting successive properties, incrementing
      * the object's shape on each set.
      */
     static inline jsuword
     hash(jsbytecode *pc, jsuword kshape)
     {
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -66,17 +66,17 @@ GetConstruct(JSObject *proxy) {
     if (proxy->numSlots() <= JSSLOT_PROXY_CONSTRUCT)
         return UndefinedValue();
     return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT);
 }
 
 static bool
 OperationInProgress(JSContext *cx, JSObject *proxy)
 {
-    JSPendingProxyOperation *op = JS_THREAD_DATA(cx)->pendingProxyOperation;
+    PendingProxyOperation *op = JS_THREAD_DATA(cx)->pendingProxyOperation;
     while (op) {
         if (op->object == proxy)
             return true;
         op = op->next;
     }
     return false;
 }
 
@@ -672,18 +672,18 @@ JSScriptedProxyHandler::iterate(JSContex
         return JSProxyHandler::iterate(cx, proxy, flags, vp);
     return Trap(cx, handler, tvr.value(), 0, NULL, vp) &&
            ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(iterate), *vp);
 }
 
 JSScriptedProxyHandler JSScriptedProxyHandler::singleton;
 
 class AutoPendingProxyOperation {
-    JSThreadData *data;
-    JSPendingProxyOperation op;
+    ThreadData              *data;
+    PendingProxyOperation   op;
   public:
     AutoPendingProxyOperation(JSContext *cx, JSObject *proxy) : data(JS_THREAD_DATA(cx)) {
         op.next = data->pendingProxyOperation;
         op.object = proxy;
         data->pendingProxyOperation = &op;
     }
 
     ~AutoPendingProxyOperation() {
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -83,17 +83,16 @@ typedef struct JSGenerator          JSGe
 typedef struct JSNativeEnumerator   JSNativeEnumerator;
 typedef struct JSFunctionBox        JSFunctionBox;
 typedef struct JSObjectBox          JSObjectBox;
 typedef struct JSParseNode          JSParseNode;
 typedef struct JSProperty           JSProperty;
 typedef struct JSScript             JSScript;
 typedef struct JSSharpObjectMap     JSSharpObjectMap;
 typedef struct JSThread             JSThread;
-typedef struct JSThreadData         JSThreadData;
 typedef struct JSTreeContext        JSTreeContext;
 typedef struct JSTryNote            JSTryNote;
 
 /* Friend "Advanced API" typedefs. */
 typedef struct JSAtomList           JSAtomList;
 typedef struct JSAtomListElement    JSAtomListElement;
 typedef struct JSAtomMap            JSAtomMap;
 typedef struct JSAtomState          JSAtomState;
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -87,17 +87,17 @@ resc_trace(JSTracer *trc, JSObject *obj)
 {
     void *pdata = obj->getPrivate();
     JS_ASSERT(pdata);
     RegExpStatics *res = static_cast<RegExpStatics *>(pdata);
     res->mark(trc);
 }
 
 Class js::regexp_statics_class = {
-    "RegExpStatics", 
+    "RegExpStatics",
     JSCLASS_HAS_PRIVATE,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
@@ -141,17 +141,17 @@ js_CloneRegExpObject(JSContext *cx, JSOb
     JS_ASSERT(obj->getClass() == &js_RegExpClass);
     JS_ASSERT(proto);
     JS_ASSERT(proto->getClass() == &js_RegExpClass);
 
     JSObject *clone = NewNativeClassInstance(cx, &js_RegExpClass, proto, proto->getParent());
     if (!clone)
         return NULL;
 
-    /* 
+    /*
      * This clone functionality does not duplicate the JITted code blob, which is necessary for
      * cross-compartment cloning functionality.
      */
     assertSameCompartment(cx, obj, clone);
 
     RegExpStatics *res = cx->regExpStatics();
     RegExp *re = RegExp::extractFrom(obj);
     {
@@ -422,20 +422,16 @@ static void
 regexp_finalize(JSContext *cx, JSObject *obj)
 {
     RegExp *re = RegExp::extractFrom(obj);
     if (!re)
         return;
     re->decref(cx);
 }
 
-/* Forward static prototype. */
-static JSBool
-regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, JSBool test, Value *rval);
-
 #if JS_HAS_XDR
 
 #include "jsxdrapi.h"
 
 JSBool
 js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp)
 {
     JSString *source = 0;
@@ -497,18 +493,20 @@ js::Class js_RegExpClass = {
 
 /*
  * RegExp instance methods.
  */
 
 JSBool
 js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp)
 {
-    if (!InstanceOf(cx, obj, &js_RegExpClass, vp + 2))
+    if (!obj->isRegExp()) {
+        ReportIncompatibleMethod(cx, vp, &js_RegExpClass);
         return false;
+    }
 
     RegExp *re = RegExp::extractFrom(obj);
     if (!re) {
         *vp = StringValue(cx->runtime->emptyString);
         return true;
     }
 
     JSLinearString *src = re->getSource();
@@ -599,110 +597,133 @@ SwapRegExpInternals(JSContext *cx, JSObj
     AlreadyIncRefed<RegExp> re = RegExp::create(cx, str, flags);
     if (!re)
         return false;
     SwapObjectRegExp(cx, obj, re);
     *rval = ObjectValue(*obj);
     return true;
 }
 
+enum ExecType { RegExpExec, RegExpTest };
+
+/*
+ * ES5 15.10.6.2 (and 15.10.6.3, which calls 15.10.6.2).
+ *
+ * RegExp.prototype.test doesn't need to create a results array, and we use
+ * |execType| to perform this optimization.
+ */
 static JSBool
-regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, JSBool test, Value *rval)
+ExecuteRegExp(JSContext *cx, ExecType execType, uintN argc, Value *vp)
 {
-    if (!InstanceOf(cx, obj, &js_RegExpClass, argv))
+    /* Step 1. */
+    JSObject *obj = ToObject(cx, &vp[1]);
+    if (!obj)
         return false;
+    if (!obj->isRegExp()) {
+        JSFunction *fun = vp[0].toObject().getFunctionPrivate();
+        JSAutoByteString funNameBytes;
+        if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
+                                 "RegExp", funName, obj->getClass()->name);
+        }
+        return false;
+    }
 
     RegExp *re = RegExp::extractFrom(obj);
     if (!re)
         return true;
 
-    /* 
+    /*
      * Code execution under this call could swap out the guts of |obj|, so we
      * have to take a defensive refcount here.
      */
     AutoRefCount<RegExp> arc(cx, NeedsIncRef<RegExp>(re));
-
-    jsdouble lastIndex;
-    if (re->global() || re->sticky()) {
-        const Value v = obj->getRegExpLastIndex();
-        if (v.isInt32()) {
-            lastIndex = v.toInt32();
-        } else {
-            if (v.isDouble())
-                lastIndex = v.toDouble();
-            else if (!ValueToNumber(cx, v, &