Merge tracemonkey to mozilla-central. a=blockers
authorRobert Sayre <sayrer@gmail.com>
Thu, 09 Dec 2010 13:37:40 -0500
changeset 59010 ce3aa8d61749e13300e4738e942106636661f137
parent 58974 031a062400ff7ad25cb5c4100cf021ce1be9c960 (current diff)
parent 59009 52d20032116aa1ecd79113d0413d2f83ae9400d5 (diff)
child 59011 58dcad7165befb0aa4a9ad28936f0ecb991753cf
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersblockers
milestone2.0b8pre
Merge tracemonkey to mozilla-central. a=blockers
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/canvas/src/CustomQS_WebGL.h
dom/base/nsDOMClassInfo.cpp
js/src/jsapi-tests/testGetPropertyDefault.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/src/jsdate.cpp
js/src/jsnum.cpp
js/src/jsopcode.cpp
js/src/jsstr.cpp
js/src/shell/js.cpp
js/src/tests/js1_5/extensions/regress-313500.js
js/src/tests/js1_5/extensions/regress-325269.js
js/src/xpconnect/shell/xpcshell.cpp
js/src/xpconnect/src/xpcwrappednativejsops.cpp
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1860,58 +1860,16 @@ private:
   nsCOMPtr<nsIScriptContext> mScx;
   PRBool mScriptIsRunning;
   PRBool mPushedSomething;
 #ifdef DEBUG
   JSContext* mPushedContext;
 #endif
 };
 
-class NS_STACK_CLASS nsAutoGCRoot {
-public:
-  // aPtr should be the pointer to the jsval we want to protect
-  nsAutoGCRoot(jsval* aPtr, nsresult* aResult
-               MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM) :
-    mPtr(aPtr), mRootType(RootType_JSVal)
-  {
-    MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
-    mResult = *aResult = AddJSGCRoot(aPtr, RootType_JSVal, "nsAutoGCRoot");
-  }
-
-  // aPtr should be the pointer to the JSObject* we want to protect
-  nsAutoGCRoot(JSObject** aPtr, nsresult* aResult
-               MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM) :
-    mPtr(aPtr), mRootType(RootType_Object)
-  {
-    MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
-    mResult = *aResult = AddJSGCRoot(aPtr, RootType_Object, "nsAutoGCRoot");
-  }
-
-  ~nsAutoGCRoot() {
-    if (NS_SUCCEEDED(mResult)) {
-      RemoveJSGCRoot((jsval *)mPtr, mRootType);
-    }
-  }
-
-  static void Shutdown();
-
-private:
-  enum RootType { RootType_JSVal, RootType_Object };
-  static nsresult AddJSGCRoot(void *aPtr, RootType aRootType, const char* aName);
-  static nsresult RemoveJSGCRoot(void *aPtr, RootType aRootType);
-
-  static nsIJSRuntimeService* sJSRuntimeService;
-  static JSRuntime* sJSScriptRuntime;
-
-  void* mPtr;
-  RootType mRootType;
-  nsresult mResult;
-  MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 class NS_STACK_CLASS nsAutoScriptBlocker {
 public:
   nsAutoScriptBlocker(MOZILLA_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) {
     MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
     nsContentUtils::AddScriptBlocker();
   }
   ~nsAutoScriptBlocker() {
     nsContentUtils::RemoveScriptBlocker();
@@ -1929,23 +1887,16 @@ public:
 
 private:
   PRUint32 mNestingLevel;
   nsCOMPtr<nsIDocument> mDocument;
   nsCOMPtr<nsIDocumentObserver> mObserver;
   MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-#define NS_AUTO_GCROOT_PASTE2(tok,line) tok##line
-#define NS_AUTO_GCROOT_PASTE(tok,line) \
-  NS_AUTO_GCROOT_PASTE2(tok,line)
-#define NS_AUTO_GCROOT(ptr, result) \ \
-  nsAutoGCRoot NS_AUTO_GCROOT_PASTE(_autoGCRoot_, __LINE__) \
-  (ptr, result)
-
 #define NS_INTERFACE_MAP_ENTRY_TEAROFF(_interface, _allocator)                \
   if (aIID.Equals(NS_GET_IID(_interface))) {                                  \
     foundInterface = static_cast<_interface *>(_allocator);                   \
     if (!foundInterface) {                                                    \
       *aInstancePtr = nsnull;                                                 \
       return NS_ERROR_OUT_OF_MEMORY;                                          \
     }                                                                         \
   } else
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -255,19 +255,16 @@ nsIBidiKeyboard *nsContentUtils::sBidiKe
 #endif
 PRUint32 nsContentUtils::sScriptBlockerCount = 0;
 PRUint32 nsContentUtils::sRemovableScriptBlockerCount = 0;
 nsCOMArray<nsIRunnable>* nsContentUtils::sBlockedScriptRunners = nsnull;
 PRUint32 nsContentUtils::sRunnersCountAtFirstBlocker = 0;
 PRUint32 nsContentUtils::sScriptBlockerCountWhereRunnersPrevented = 0;
 nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nsnull;
 
-nsIJSRuntimeService *nsAutoGCRoot::sJSRuntimeService;
-JSRuntime *nsAutoGCRoot::sJSScriptRuntime;
-
 PRBool nsContentUtils::sIsHandlingKeyBoardEvent = PR_FALSE;
 PRBool nsContentUtils::sAllowXULXBL_for_file = PR_FALSE;
 
 PRBool nsContentUtils::sInitialized = PR_FALSE;
 
 nsRefPtrHashtable<nsPrefObserverHashKey, nsPrefOldCallback>
   *nsContentUtils::sPrefCallbackTable = nsnull;
 
@@ -1206,18 +1203,16 @@ nsContentUtils::Shutdown()
   NS_ASSERTION(!sBlockedScriptRunners ||
                sBlockedScriptRunners->Count() == 0,
                "How'd this happen?");
   delete sBlockedScriptRunners;
   sBlockedScriptRunners = nsnull;
 
   NS_IF_RELEASE(sSameOriginChecker);
   
-  nsAutoGCRoot::Shutdown();
-
   nsTextEditorState::ShutDown();
 }
 
 // static
 PRBool
 nsContentUtils::IsCallerTrustedForCapability(const char* aCapability)
 {
   // The secman really should handle UniversalXPConnect case, since that
@@ -3281,63 +3276,16 @@ nsContentUtils::GetContentPolicy()
     // It's OK to not have a content policy service
     sTriedToGetContentPolicy = PR_TRUE;
   }
 
   return sContentPolicyService;
 }
 
 // static
-nsresult
-nsAutoGCRoot::AddJSGCRoot(void* aPtr, RootType aRootType, const char* aName)
-{
-  if (!sJSScriptRuntime) {
-    nsresult rv = CallGetService("@mozilla.org/js/xpc/RuntimeService;1",
-                                 &sJSRuntimeService);
-    NS_ENSURE_TRUE(sJSRuntimeService, rv);
-
-    sJSRuntimeService->GetRuntime(&sJSScriptRuntime);
-    if (!sJSScriptRuntime) {
-      NS_RELEASE(sJSRuntimeService);
-      NS_WARNING("Unable to get JS runtime from JS runtime service");
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  PRBool ok;
-  if (aRootType == RootType_JSVal)
-    ok = ::js_AddRootRT(sJSScriptRuntime, (jsval *)aPtr, aName);
-  else
-    ok = ::js_AddGCThingRootRT(sJSScriptRuntime, (void **)aPtr, aName);
-  if (!ok) {
-    NS_WARNING("JS_AddNamedRootRT failed");
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  return NS_OK;
-}
-
-/* static */
-nsresult
-nsAutoGCRoot::RemoveJSGCRoot(void* aPtr, RootType aRootType)
-{
-  if (!sJSScriptRuntime) {
-    NS_NOTREACHED("Trying to remove a JS GC root when none were added");
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  if (aRootType == RootType_JSVal)
-    ::js_RemoveRoot(sJSScriptRuntime, (jsval *)aPtr);
-  else
-    ::js_RemoveRoot(sJSScriptRuntime, (JSObject **)aPtr);
-
-  return NS_OK;
-}
-
-// static
 PRBool
 nsContentUtils::IsEventAttributeName(nsIAtom* aName, PRInt32 aType)
 {
   const PRUnichar* name = aName->GetUTF16String();
   if (name[0] != 'o' || name[1] != 'n')
     return PR_FALSE;
 
   EventNameMapping mapping;
@@ -5190,23 +5138,16 @@ nsContentUtils::EqualsIgnoreASCIICase(co
       }
     }
   }
 
   return PR_TRUE;
 }
 
 /* static */
-void
-nsAutoGCRoot::Shutdown()
-{
-  NS_IF_RELEASE(sJSRuntimeService);
-}
-
-/* static */
 nsIInterfaceRequestor*
 nsContentUtils::GetSameOriginChecker()
 {
   if (!sSameOriginChecker) {
     sSameOriginChecker = new nsSameOriginChecker();
     NS_IF_ADDREF(sSameOriginChecker);
   }
   return sSameOriginChecker;
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -208,18 +208,16 @@ nsFrameMessageManager::GetParamsForMessa
   JSAutoRequest ar(ctx);
   JSString* str;
   if (argc && (str = JS_ValueToString(ctx, argv[0])) && str) {
     aMessageName.Assign(nsDependentJSString(str));
   }
 
   if (argc >= 2) {
     jsval v = argv[1];
-    nsAutoGCRoot root(&v, &rv);
-    NS_ENSURE_SUCCESS(rv, JS_FALSE);
     if (JS_TryJSON(ctx, &v)) {
       JS_Stringify(ctx, &v, nsnull, JSVAL_NULL, JSONCreator, &aJSON);
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -359,43 +357,34 @@ nsFrameMessageManager::ReceiveMessage(ns
         NS_ENSURE_STATE(pusher.Push(ctx, PR_FALSE));
 
         JSAutoRequest ar(ctx);
 
         // The parameter for the listener function.
         JSObject* param = JS_NewObject(ctx, NULL, NULL, NULL);
         NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
 
-        nsresult rv;
-        nsAutoGCRoot resultGCRoot(&param, &rv);
-        NS_ENSURE_SUCCESS(rv, rv);
-
         jsval targetv;
-        nsAutoGCRoot resultGCRoot2(&targetv, &rv);
-        NS_ENSURE_SUCCESS(rv, rv);
         nsContentUtils::WrapNative(ctx,
                                    JS_GetGlobalObject(ctx),
                                    aTarget, &targetv);
 
         // To keep compatibility with e10s message manager,
         // define empty objects array.
         if (!aObjectsArray) {
           // Because we want JS messages to have always the same properties,
           // create array even if len == 0.
           aObjectsArray = JS_NewArrayObject(ctx, 0, NULL);
           if (!aObjectsArray) {
             return false;
           }
         }
-        nsAutoGCRoot arrayGCRoot(&aObjectsArray, &rv);
-        NS_ENSURE_SUCCESS(rv, rv);
 
         jsval json = JSVAL_NULL;
-        nsAutoGCRoot root(&json, &rv);
-        if (NS_SUCCEEDED(rv) && !aJSON.IsEmpty()) {
+        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;
@@ -412,18 +401,16 @@ nsFrameMessageManager::ReceiveMessage(ns
                           STRING_TO_JSVAL(jsMessage), NULL, NULL, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "sync",
                           BOOLEAN_TO_JSVAL(aSync), NULL, NULL, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "json", json, NULL, NULL, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "objects", OBJECT_TO_JSVAL(aObjectsArray),
                           NULL, NULL, JSPROP_ENUMERATE);
 
         jsval thisValue = JSVAL_VOID;
-        nsAutoGCRoot resultGCRoot3(&thisValue, &rv);
-        NS_ENSURE_SUCCESS(rv, rv);
 
         JSAutoEnterCompartment ac;
 
         if (!ac.enter(ctx, object))
           return PR_FALSE;
 
         jsval funval = JSVAL_VOID;
         if (JS_ObjectIsFunction(ctx, object)) {
@@ -449,18 +436,16 @@ nsFrameMessageManager::ReceiveMessage(ns
                           JSVAL_IS_OBJECT(funval) &&
                           !JSVAL_IS_NULL(funval));
           JSObject* funobject = JSVAL_TO_OBJECT(funval);
           NS_ENSURE_STATE(JS_ObjectIsFunction(ctx, funobject));
           thisValue = OBJECT_TO_JSVAL(object);
         }
 
         jsval rval = JSVAL_VOID;
-        nsAutoGCRoot resultGCRoot4(&rval, &rv);
-        NS_ENSURE_SUCCESS(rv, rv);
 
         js::AutoValueRooter argv(ctx);
         argv.set(OBJECT_TO_JSVAL(param));
 
         {
           JSAutoEnterCompartment tac;
 
           JSObject* thisObject = JSVAL_TO_OBJECT(thisValue);
--- a/content/canvas/src/CustomQS_WebGL.h
+++ b/content/canvas/src/CustomQS_WebGL.h
@@ -902,33 +902,37 @@ nsIDOMWebGLRenderingContext_VertexAttrib
 static inline void FASTCALL
 helper_nsIDOMWebGLRenderingContext_Uniform_x_iv_tn(JSContext *cx, JSObject *obj, JSObject *locationobj,
                                                       JSObject *arg, int nElements)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
 
     nsIDOMWebGLRenderingContext *self;
     xpc_qsSelfRef selfref;
-    xpc_qsArgValArray<3> vp(cx);
-    if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
+    js::Anchor<jsval> self_anchor;
+    if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr,
+                          &self_anchor.get(), nsnull)) {
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
     if (!arg) {
         xpc_qsThrowMethodFailedWithDetails(cx, NS_ERROR_FAILURE, "nsIDOMWebGLRenderingContext", "uniformNiv");
         js_SetTraceableNativeFailed(cx);
     }
 
     js::AutoValueRooter obj_tvr(cx);
 
     nsIWebGLUniformLocation *location;
     xpc_qsSelfRef location_selfref;
+    js::Anchor<jsval> location_anchor;
     nsresult rv_convert_arg0
-        = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location, &location_selfref.ptr, &vp.array[1], nsnull);
+        = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location,
+                           &location_selfref.ptr, &location_anchor.get(),
+                           nsnull);
     if (NS_FAILED(rv_convert_arg0)) {
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
     js::TypedArray *wa = 0;
 
     if (helper_isInt32Array(arg)) {
@@ -970,33 +974,37 @@ helper_nsIDOMWebGLRenderingContext_Unifo
 static inline void FASTCALL
 helper_nsIDOMWebGLRenderingContext_Uniform_x_fv_tn(JSContext *cx, JSObject *obj, JSObject *locationobj,
                                                       JSObject *arg, int nElements)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
 
     nsIDOMWebGLRenderingContext *self;
     xpc_qsSelfRef selfref;
-    xpc_qsArgValArray<3> vp(cx);
-    if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
+    js::Anchor<jsval> self_anchor;
+    if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr,
+                          &self_anchor.get(), nsnull)) {
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
     if (!arg) {
         xpc_qsThrowMethodFailedWithDetails(cx, NS_ERROR_FAILURE, "nsIDOMWebGLRenderingContext", "uniformNfv");
         js_SetTraceableNativeFailed(cx);
     }
 
     js::AutoValueRooter obj_tvr(cx);
 
     nsIWebGLUniformLocation *location;
     xpc_qsSelfRef location_selfref;
+    js::Anchor<jsval> location_anchor;
     nsresult rv_convert_arg0
-        = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location, &location_selfref.ptr, &vp.array[1], nsnull);
+        = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location,
+                           &location_selfref.ptr, &location_anchor.get(),
+                           nsnull);
     if (NS_FAILED(rv_convert_arg0)) {
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
     js::TypedArray *wa = 0;
 
     if (helper_isFloat32Array(arg)) {
@@ -1040,33 +1048,37 @@ helper_nsIDOMWebGLRenderingContext_Unifo
 static inline void FASTCALL
 helper_nsIDOMWebGLRenderingContext_UniformMatrix_x_fv_tn(JSContext *cx, JSObject *obj, JSObject *locationobj,
                                                             JSBool transpose, JSObject *arg, int nElements)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
 
     nsIDOMWebGLRenderingContext *self;
     xpc_qsSelfRef selfref;
-    xpc_qsArgValArray<4> vp(cx);
-    if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) {
+    js::Anchor<jsval> self_anchor;
+    if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr,
+                          &self_anchor.get(), nsnull)) {
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
     if (!arg) {
         xpc_qsThrowMethodFailedWithDetails(cx, NS_ERROR_FAILURE, "nsIDOMWebGLRenderingContext", "uniformMatrixNfv");
         js_SetTraceableNativeFailed(cx);
     }
 
     js::AutoValueRooter obj_tvr(cx);
 
     nsIWebGLUniformLocation *location;
     xpc_qsSelfRef location_selfref;
+    js::Anchor<jsval> location_anchor;
     nsresult rv_convert_arg0
-        = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location, &location_selfref.ptr, &vp.array[1], nsnull);
+        = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location,
+                           &location_selfref.ptr, &location_anchor.get(),
+                           nsnull);
     if (NS_FAILED(rv_convert_arg0)) {
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
     js::TypedArray *wa = 0;
 
     if (helper_isFloat32Array(arg)) {
--- a/content/events/src/nsEventListenerService.cpp
+++ b/content/events/src/nsEventListenerService.cpp
@@ -122,67 +122,74 @@ nsEventListenerInfo::GetJSVal(jsval* aJS
   return PR_FALSE;
 }
 
 NS_IMETHODIMP
 nsEventListenerInfo::ToSource(nsAString& aResult)
 {
   aResult.SetIsVoid(PR_TRUE);
 
-  nsresult rv;
-  jsval v = JSVAL_NULL;
-  nsAutoGCRoot root(&v, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (GetJSVal(&v)) {
-    nsCOMPtr<nsIThreadJSContextStack> stack =
-      nsContentUtils::ThreadJSContextStack();
-    if (stack) {
-      JSContext* cx = nsnull;
-      stack->GetSafeJSContext(&cx);
-      if (cx && NS_SUCCEEDED(stack->Push(cx))) {
-        {
-          // Extra block to finish the auto request before calling pop
-          JSAutoRequest ar(cx);
+  nsCOMPtr<nsIThreadJSContextStack> stack =
+    nsContentUtils::ThreadJSContextStack();
+  if (stack) {
+    JSContext* cx = nsnull;
+    stack->GetSafeJSContext(&cx);
+    if (cx && NS_SUCCEEDED(stack->Push(cx))) {
+      {
+        // Extra block to finish the auto request before calling pop
+        JSAutoRequest ar(cx);
+        jsval v = JSVAL_NULL;
+        if (GetJSVal(&v)) {
           JSString* str = JS_ValueToSource(cx, v);
           if (str) {
             aResult.Assign(nsDependentJSString(str));
           }
         }
-        stack->Pop(&cx);
       }
+      stack->Pop(&cx);
     }
   }
-
+  
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEventListenerInfo::GetDebugObject(nsISupports** aRetVal)
 {
   *aRetVal = nsnull;
 
 #ifdef MOZ_JSDEBUGGER
   nsresult rv = NS_OK;
-  jsval v = JSVAL_NULL;
-  nsAutoGCRoot root(&v, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (GetJSVal(&v)) {
-    nsCOMPtr<jsdIDebuggerService> jsd =
-      do_GetService("@mozilla.org/js/jsd/debugger-service;1", &rv);
-    NS_ENSURE_SUCCESS(rv, NS_OK);
+  nsCOMPtr<jsdIDebuggerService> jsd =
+    do_GetService("@mozilla.org/js/jsd/debugger-service;1", &rv);
+  NS_ENSURE_SUCCESS(rv, NS_OK);
+  
+  PRBool isOn = PR_FALSE;
+  jsd->GetIsOn(&isOn);
+  NS_ENSURE_TRUE(isOn, NS_OK);
 
-    PRBool isOn = PR_FALSE;
-    jsd->GetIsOn(&isOn);
-    NS_ENSURE_TRUE(isOn, NS_OK);
+  nsCOMPtr<nsIThreadJSContextStack> stack =
+    nsContentUtils::ThreadJSContextStack();
+  if (stack) {
+    JSContext* cx = nsnull;
+    stack->GetSafeJSContext(&cx);
+    if (cx && NS_SUCCEEDED(stack->Push(cx))) {
+      {
+        // Extra block to finish the auto request before calling pop
+        JSAutoRequest ar(cx);
 
-    nsCOMPtr<jsdIValue> jsdValue;
-    jsd->WrapJSValue(v, getter_AddRefs(jsdValue));
-    *aRetVal = jsdValue.forget().get();
-    return NS_OK;
+        jsval v = JSVAL_NULL;
+        if (GetJSVal(&v)) {
+          nsCOMPtr<jsdIValue> jsdValue;
+          jsd->WrapJSValue(v, getter_AddRefs(jsdValue));
+          *aRetVal = jsdValue.forget().get();
+          return NS_OK;
+        }
+      }
+    }
   }
 #endif
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget,
--- a/content/xbl/src/nsXBLProtoImplField.cpp
+++ b/content/xbl/src/nsXBLProtoImplField.cpp
@@ -105,51 +105,48 @@ nsXBLProtoImplField::InstallField(nsIScr
                   "happen");
 
   *aDidInstall = PR_FALSE;
 
   if (mFieldTextLength == 0) {
     return NS_OK;
   }
 
-  jsval result = JSVAL_NULL;
-  
   // EvaluateStringWithValue and JS_DefineUCProperty can both trigger GC, so
   // protect |result| here.
   nsresult rv;
-  nsAutoGCRoot root(&result, &rv);
-  if (NS_FAILED(rv))
-    return rv;
 
   nsCAutoString uriSpec;
   aBindingDocURI->GetSpec(uriSpec);
   
   JSContext* cx = (JSContext*) aContext->GetNativeContext();
   NS_ASSERTION(!::JS_IsExceptionPending(cx),
                "Shouldn't get here when an exception is pending!");
   
   // compile the literal string
   PRBool undefined;
   nsCOMPtr<nsIScriptContext> context = aContext;
+
+  JSAutoRequest ar(cx);
+  jsval result = JSVAL_NULL;
   rv = context->EvaluateStringWithValue(nsDependentString(mFieldText,
                                                           mFieldTextLength), 
                                         aBoundNode,
                                         aPrincipal, uriSpec.get(),
                                         mLineNumber, JSVERSION_LATEST,
                                         (void*) &result, &undefined);
   if (NS_FAILED(rv))
     return rv;
 
   if (undefined) {
     result = JSVAL_VOID;
   }
 
   // Define the evaluated result as a JS property
   nsDependentString name(mName);
-  JSAutoRequest ar(cx);
   if (!::JS_DefineUCProperty(cx, aBoundNode,
                              reinterpret_cast<const jschar*>(mName), 
                              name.Length(), result, nsnull, nsnull,
                              mJSAttributes)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   *aDidInstall = PR_TRUE;
--- a/content/xbl/src/nsXBLProtoImplMember.h
+++ b/content/xbl/src/nsXBLProtoImplMember.h
@@ -115,15 +115,13 @@ public:
                                  const nsCString& aClassStr) = 0;
   virtual nsresult CompileMember(nsIScriptContext* aContext,
                                  const nsCString& aClassStr,
                                  void* aClassObject)=0;
 
   virtual void Trace(TraceCallback aCallback, void *aClosure) const = 0;
 
 protected:
-  friend class nsAutoGCRoot;
-  
   nsXBLProtoImplMember* mNext;  // The members of an implementation are chained.
   PRUnichar* mName;               // The name of the field, method, or property.
 };
 
 #endif // nsXBLProtoImplMember_h__
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -155,20 +155,16 @@ nsXBLProtoImplMethod::InstallMember(nsIS
       return NS_ERROR_UNEXPECTED;
     }
 
     JSObject * method = ::JS_CloneFunctionObject(cx, mJSMethodObject, globalObject);
     if (!method) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    nsresult rv;
-    nsAutoGCRoot root(&method, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    
     if (!::JS_DefineUCProperty(cx, targetClassObject,
                                reinterpret_cast<const jschar*>(mName), 
                                name.Length(), OBJECT_TO_JSVAL(method),
                                NULL, NULL, JSPROP_ENUMERATE)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
   return NS_OK;
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -180,28 +180,21 @@ nsXBLProtoImplProperty::InstallMember(ns
 
     if (!ac.enter(cx, globalObject))
       return NS_ERROR_UNEXPECTED;
 
     if (mJSGetterObject)
       if (!(getter = ::JS_CloneFunctionObject(cx, mJSGetterObject, globalObject)))
         return NS_ERROR_OUT_OF_MEMORY;
 
-    nsresult rv;
-    nsAutoGCRoot getterroot(&getter, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    
     JSObject * setter = nsnull;
     if (mJSSetterObject)
       if (!(setter = ::JS_CloneFunctionObject(cx, mJSSetterObject, globalObject)))
         return NS_ERROR_OUT_OF_MEMORY;
 
-    nsAutoGCRoot setterroot(&setter, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    
     nsDependentString name(mName);
     if (!::JS_DefineUCProperty(cx, targetClassObject,
                                reinterpret_cast<const jschar*>(mName),
                                name.Length(), JSVAL_VOID,
                                JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter),
                                JS_DATA_TO_FUNC_PTR(JSPropertyOp, setter),
                                mJSAttributes))
       return NS_ERROR_OUT_OF_MEMORY;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -6744,19 +6744,16 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     JSFunction *fun = ::JS_NewFunction(cx, ContentWindowGetter, 0, 0,
                                        windowObj, "_content");
     if (!fun) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     JSObject *funObj = ::JS_GetFunctionObject(fun);
 
-    nsAutoGCRoot root(&funObj, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
     if (!::JS_DefinePropertyById(cx, windowObj, id, JSVAL_VOID,
                                  JS_DATA_TO_FUNC_PTR(JSPropertyOp, funObj),
                                  nsnull,
                                  JSPROP_ENUMERATE | JSPROP_GETTER |
                                  JSPROP_SHARED)) {
       return NS_ERROR_FAILURE;
     }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7579,24 +7579,24 @@ nsGlobalWindow::DispatchSyncPopState()
     nsIScriptGlobalObject *sgo = document->GetScopeObject();
     NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
 
     nsIScriptContext *scx = sgo->GetContext();
     NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
 
     JSContext *cx = (JSContext*) scx->GetNativeContext();
 
+    // Make sure we in the request while we have jsval on the native stack.
+    JSAutoRequest ar(cx);
+
     // If our json call triggers a JS-to-C++ call, we want that call to use cx
     // as the context.  So we push cx onto the context stack.
     nsCxPusher cxPusher;
 
     jsval jsStateObj = JSVAL_NULL;
-    // Root the container which will hold our decoded state object.
-    nsAutoGCRoot root(&jsStateObj, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
 
     // Deserialize the state object into an nsIVariant.
     nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
     NS_ENSURE_TRUE(cxPusher.Push(cx), NS_ERROR_FAILURE);
     rv = json->DecodeToJSVal(stateObjJSON, cx, &jsStateObj);
     NS_ENSURE_SUCCESS(rv, rv);
     cxPusher.Pop();
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2214,27 +2214,25 @@ nsresult
 nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, void *aScope,
                                       nsIAtom *aName,
                                       void *aHandler)
 {
   NS_ENSURE_ARG(aHandler);
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
-  nsresult rv;
+
+  JSAutoRequest ar(mContext);
 
   // Get the jsobject associated with this target
   JSObject *target = nsnull;
-  nsAutoGCRoot root(&target, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = JSObjectFromInterface(aTarget, aScope, &target);
+  nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JSObject *funobj = (JSObject*) aHandler;
-  JSAutoRequest ar(mContext);
 
 #ifdef DEBUG
   {
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, funobj)) {
       return NS_ERROR_FAILURE;
     }
 
@@ -2285,22 +2283,19 @@ nsJSContext::BindCompiledEventHandler(ns
 
 nsresult
 nsJSContext::GetBoundEventHandler(nsISupports* aTarget, void *aScope,
                                   nsIAtom* aName,
                                   nsScriptObjectHolder &aHandler)
 {
     NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
 
-    nsresult rv;
+    JSAutoRequest ar(mContext);
     JSObject *obj = nsnull;
-    nsAutoGCRoot root(&obj, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    JSAutoRequest ar(mContext);
-    rv = JSObjectFromInterface(aTarget, aScope, &obj);
+    nsresult rv = JSObjectFromInterface(aTarget, aScope, &obj);
     NS_ENSURE_SUCCESS(rv, rv);
 
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, obj)) {
       return NS_ERROR_FAILURE;
     }
 
     jsval funval;
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -303,20 +303,16 @@ nsresult nsJSThunk::EvaluateScript(nsICh
 
         nsIXPConnect *xpc = nsContentUtils::XPConnect();
 
         nsCOMPtr<nsIXPConnectJSObjectHolder> sandbox;
         rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(sandbox));
         NS_ENSURE_SUCCESS(rv, rv);
 
         jsval rval = JSVAL_VOID;
-        nsAutoGCRoot root(&rval, &rv);
-        if (NS_FAILED(rv)) {
-            return rv;
-        }
 
         // Push our JSContext on the context stack so the JS_ValueToString call (and
         // JS_ReportPendingException, if relevant) will use the principal of cx.
         // Note that we do this as late as possible to make popping simpler.
         nsCOMPtr<nsIJSContextStack> stack =
             do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
         if (NS_SUCCEEDED(rv)) {
             rv = stack->Push(cx);
--- a/dom/src/threads/nsDOMWorker.cpp
+++ b/dom/src/threads/nsDOMWorker.cpp
@@ -154,16 +154,17 @@ nsDOMWorkerFunctions::MakeTimeout(JSCont
                                   uintN aArgc,
                                   jsval* aVp,
                                   PRBool aIsInterval)
 {
   nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
   NS_ASSERTION(worker, "This should be set by the DOM thread service!");
 
   if (worker->IsCanceled()) {
+    JS_ReportError(aCx, "Worker is canceled");
     return JS_FALSE;
   }
 
   PRUint32 id = worker->NextTimeoutId();
 
   if (worker->IsClosing()) {
     // Timeouts won't run in the close handler, fake success and bail.
     JS_SET_RVAL(aCx, aVp, INT_TO_JSVAL(id));
@@ -202,16 +203,17 @@ JSBool
 nsDOMWorkerFunctions::KillTimeout(JSContext* aCx,
                                   uintN aArgc,
                                   jsval* aVp)
 {
   nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
   NS_ASSERTION(worker, "This should be set by the DOM thread service!");
 
   if (worker->IsCanceled()) {
+    JS_ReportError(aCx, "Worker is canceled");
     return JS_FALSE;
   }
 
   if (!aArgc) {
     JS_ReportError(aCx, "Function requires at least 1 parameter");
     return JS_FALSE;
   }
 
@@ -230,16 +232,17 @@ JSBool
 nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
                                   uintN aArgc,
                                   jsval* aVp)
 {
   nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
   NS_ASSERTION(worker, "This should be set by the DOM thread service!");
 
   if (worker->IsCanceled()) {
+    JS_ReportError(aCx, "Worker is canceled");
     return JS_FALSE;
   }
 
   if (!aArgc) {
     // No argument is ok according to spec.
     return JS_TRUE;
   }
 
@@ -305,16 +308,17 @@ nsDOMWorkerFunctions::NewXMLHttpRequest(
   if (!obj) {
     return JS_FALSE;
   }
 
   nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
   NS_ASSERTION(worker, "This should be set by the DOM thread service!");
 
   if (worker->IsCanceled()) {
+    JS_ReportError(aCx, "Worker is canceled");
     return JS_FALSE;
   }
 
   if (aArgc) {
     JS_ReportError(aCx, "XMLHttpRequest constructor takes no arguments!");
     return JS_FALSE;
   }
 
@@ -354,16 +358,17 @@ JSBool
 nsDOMWorkerFunctions::AtoB(JSContext* aCx,
                            uintN aArgc,
                            jsval* aVp)
 {
   nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
   NS_ASSERTION(worker, "This should be set by the DOM thread service!");
 
   if (worker->IsCanceled()) {
+    JS_ReportError(aCx, "Worker is canceled");
     return JS_FALSE;
   }
 
   if (!aArgc) {
     JS_ReportError(aCx, "Function requires at least 1 parameter");
     return JS_FALSE;
   }
 
@@ -406,16 +411,17 @@ JSBool
 nsDOMWorkerFunctions::BtoA(JSContext* aCx,
                            uintN aArgc,
                            jsval* aVp)
 {
   nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
   NS_ASSERTION(worker, "This should be set by the DOM thread service!");
 
   if (worker->IsCanceled()) {
+    JS_ReportError(aCx, "Worker is canceled");
     return JS_FALSE;
   }
 
   if (!aArgc) {
     JS_ReportError(aCx, "Function requires at least 1 parameter");
     return JS_FALSE;
   }
 
@@ -480,16 +486,17 @@ nsDOMWorkerFunctions::MakeNewWorker(JSCo
   if (!obj) {
     return JS_FALSE;
   }
 
   nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
   NS_ASSERTION(worker, "This should be set by the DOM thread service!");
 
   if (worker->IsCanceled()) {
+    JS_ReportError(aCx, "Worker is canceled");
     return JS_FALSE;
   }
 
   if (!aArgc) {
     JS_ReportError(aCx, "Worker constructor must have an argument!");
     return JS_FALSE;
   }
 
@@ -573,16 +580,17 @@ nsDOMWorkerFunctions::CTypesLazyGetter(J
     NS_ASSERTION(nsDependentJSString(str).EqualsLiteral("ctypes"), "Bad id!");
   }
 #endif
   nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
   NS_ASSERTION(worker, "This should be set by the DOM thread service!");
   NS_ASSERTION(worker->IsPrivileged(), "This shouldn't be possible!");
 
   if (worker->IsCanceled()) {
+    JS_ReportError(aCx, "Worker is canceled");
     return JS_FALSE;
   }
 
   jsval ctypes;
   return JS_DeletePropertyById(aCx, aObj, aId) &&
          JS_InitCTypesClass(aCx, aObj) &&
          JS_GetProperty(aCx, aObj, "ctypes", &ctypes) &&
          JS_SetCTypesCallbacks(aCx, JSVAL_TO_OBJECT(ctypes), &sCallbacks) &&
--- a/js/jsd/jsd.h
+++ b/js/jsd/jsd.h
@@ -268,17 +268,17 @@ struct JSDStackFrameInfo
 #define GOT_CTOR    ((short) (1 << 3))
 
 struct JSDValue
 {
     jsval       val;
     intN        nref;
     JSCList     props;
     JSString*   string;
-    const char* funName;
+    JSString*   funName;
     const char* className;
     JSDValue*   proto;
     JSDValue*   parent;
     JSDValue*   ctor;
     uintN       flags;
 };
 
 struct JSDProperty
@@ -455,17 +455,17 @@ extern void *
 jsd_GetScriptPrivate (JSDScript *jsdscript);
 
 extern JSBool
 jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript);
 
 extern const char*
 jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript);
 
-extern const char*
+extern JSString*
 jsd_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript);
 
 extern uintN
 jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript);
 
 extern uintN
 jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript);
 
@@ -719,17 +719,17 @@ jsd_IsStackFrameConstructing(JSDContext*
                              JSDThreadState* jsdthreadstate,
                              JSDStackFrameInfo* jsdframe);
 
 extern JSDValue*
 jsd_GetThisForStackFrame(JSDContext* jsdc,
                          JSDThreadState* jsdthreadstate,
                          JSDStackFrameInfo* jsdframe);
 
-extern const char*
+extern JSString*
 jsd_GetNameForStackFrame(JSDContext* jsdc, 
                          JSDThreadState* jsdthreadstate,
                          JSDStackFrameInfo* jsdframe);
 
 extern JSDThreadState*
 jsd_NewThreadState(JSDContext* jsdc, JSContext *cx);
 
 extern void
@@ -964,17 +964,17 @@ extern int32
 jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval);
 
 extern jsdouble
 jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval);
 
 extern JSString*
 jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval);
 
-extern const char*
+extern JSString*
 jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval);
 
 /**************************************************/
 
 extern uintN
 jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval);
 
 extern JSDProperty*
--- a/js/jsd/jsd_scpt.c
+++ b/js/jsd/jsd_scpt.c
@@ -192,32 +192,39 @@ OutputDebugString (char *buf)
     fprintf (stderr, "%s", buf);
 }
 #endif
 
 static void
 _dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext)
 {
     const char* name;
-    const char* fun;
+    JSString* fun;
     uintN base;
     uintN extent;
     char Buf[256];
-    
+    size_t n;
+
     name   = jsd_GetScriptFilename(jsdc, jsdscript);
     fun    = jsd_GetScriptFunctionName(jsdc, jsdscript);
     base   = jsd_GetScriptBaseLineNumber(jsdc, jsdscript);
     extent = jsd_GetScriptLineExtent(jsdc, jsdscript);
-    
-    sprintf( Buf, "%sscript=%08X, %s, %s, %d-%d\n", 
-             leadingtext,
-             (unsigned) jsdscript->script,
-             name ? name : "no URL", 
-             fun  ? fun  : "no fun", 
-             base, base + extent - 1 );
+    n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ",
+                        leadingtext, (unsigned) jsdscript->script,
+                        name ? name : "no URL"));
+    if (n + 1 < sizeof(Buf)) {
+        if (fun) {
+            n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun"));
+        } else {
+            n += JS_PutEscapedString(Buf + n, sizeof(Buf) - n, fun, 0);
+            Buf[sizeof(Buf) - 1] = '\0';
+        }
+        if (n + 1 < sizeof(Buf))
+            snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1);
+    }
     OutputDebugString( Buf );
 }
 
 static void
 _dumpJSDScriptList( JSDContext* jsdc )
 {
     JSDScript* iterp = NULL;
     JSDScript* jsdscript = NULL;
@@ -483,22 +490,25 @@ jsd_IsActiveScript(JSDContext* jsdc, JSD
 }        
 
 const char*
 jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
 {
     return jsdscript->url;
 }
 
-const char*
+JSString*
 jsd_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript)
 {
+    JSString* str;
+
     if( ! jsdscript->function )
         return NULL;
-    return JS_GetFunctionName(jsdscript->function);
+    str = JS_GetFunctionId(jsdscript->function);
+    return str ? str : JS_GetEmptyString(jsdc->jsrt);
 }
 
 uintN
 jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript)
 {
     return jsdscript->lineBase;
 }
 
--- a/js/jsd/jsd_stak.c
+++ b/js/jsd/jsd_stak.c
@@ -351,31 +351,31 @@ jsd_GetThisForStackFrame(JSDContext* jsd
         if(ok)
             jsdval = JSD_NewValue(jsdc, thisval);
     }
 
     JSD_UNLOCK_THREADSTATES(jsdc);
     return jsdval;
 }
 
-const char*
+JSString*
 jsd_GetNameForStackFrame(JSDContext* jsdc, 
                          JSDThreadState* jsdthreadstate,
                          JSDStackFrameInfo* jsdframe)
 {
-    const char *rv = NULL;
+    JSString *rv = NULL;
     
     JSD_LOCK_THREADSTATES(jsdc);
     
     if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
     {
         JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
                                                jsdframe->fp);
         if (fun)
-            rv = JS_GetFunctionName (fun);
+            rv = JS_GetFunctionId (fun);
     }
     
     JSD_UNLOCK_THREADSTATES(jsdc);
     return rv;
 }
 
 JSBool
 jsd_IsStackFrameDebugger(JSDContext* jsdc, 
--- a/js/jsd/jsd_step.c
+++ b/js/jsd/jsd_step.c
@@ -64,48 +64,50 @@ static char*
 
 static void
 _interpreterTrace(JSDContext* jsdc, JSContext *cx, JSStackFrame *fp,
                   JSBool before)
 {
     JSDScript* jsdscript = NULL;
     JSScript * script;
     static indent = 0;
-    const char* funName = NULL;
+    JSString* funName = NULL;
 
     script = JS_GetFrameScript(cx, fp);
     if(script)
     {
         JSD_LOCK_SCRIPTS(jsdc);
         jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, fp);
         JSD_UNLOCK_SCRIPTS(jsdc);
         if(jsdscript)
             funName = JSD_GetScriptFunctionName(jsdc, jsdscript);
     }
-    if(!funName)
-        funName = "TOP_LEVEL";
+
+    if(before)
+        printf("%sentering ", _indentSpaces(indent++));
+    else
+        printf("%sleaving ", _indentSpaces(--indent));
+
+    if (!funName)
+        printf("TOP_LEVEL");
+    else
+        JS_FileEscapedString(stdout, funName, 0);
 
     if(before)
     {
         jsval thisVal;
 
-        printf("%sentering %s %s this: ",
-               _indentSpaces(indent++),
-               funName,
-               JS_IsConstructorFrame(cx, fp) ? "constructing":"");
+        printf("%s this: ", JS_IsConstructorFrame(cx, fp) ? "constructing":"");
 
         if (JS_GetFrameThis(cx, fp, &thisVal))
-            printf("0x%0llx\n", (JSUword) thisVal);
+            printf("0x%0llx", (JSUword) thisVal);
         else
             puts("<unavailable>");
     }
-    else
-    {
-        printf("%sleaving %s\n", _indentSpaces(--indent), funName);
-    }
+    printf("\n");
     JS_ASSERT(indent >= 0);
 }
 #endif
 
 JSBool
 _callHook(JSDContext *jsdc, JSContext *cx, JSStackFrame *fp, JSBool before,
           uintN type, JSD_CallHookProc hook, void *hookData)
 {
--- a/js/jsd/jsd_val.c
+++ b/js/jsd/jsd_val.c
@@ -241,17 +241,17 @@ jsd_GetValueString(JSDContext* jsdc, JSD
             }
             JS_LeaveCrossCompartmentCall(call);
             JS_EndRequest(cx);
         }
     }
     return jsdval->string;
 }
 
-const char*
+JSString*
 jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
 {
     JSContext* cx = jsdc->dumbContext;
     JSFunction* fun;
     JSExceptionState* exceptionState;
     JSCrossCompartmentCall *call = NULL;
 
     if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
@@ -267,17 +267,19 @@ jsd_GetValueFunctionName(JSDContext* jsd
 
         exceptionState = JS_SaveExceptionState(cx);
         fun = JS_ValueToFunction(cx, jsdval->val);
         JS_RestoreExceptionState(cx, exceptionState);
         JS_LeaveCrossCompartmentCall(call);
         JS_EndRequest(cx);
         if(!fun)
             return NULL;
-        jsdval->funName = JS_GetFunctionName(fun);
+        jsdval->funName = JS_GetFunctionId(fun);
+        if (!jsdval->funName)
+            jsdval->funName = JS_GetEmptyString(jsdc->jsrt);
     }
     return jsdval->funName;
 }
 
 /***************************************************************************/
 
 JSDValue*
 jsd_NewValue(JSDContext* jsdc, jsval val)
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -948,16 +948,33 @@ jsdProperty::GetVarArgSlot(PRUint32 *_rv
 {
     *_rval = JSD_GetPropertyVarArgSlot (mCx, mProperty);
     return NS_OK;
 }
 
 /* Scripts */
 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
 
+static NS_IMETHODIMP
+AssignToJSString(nsACString *x, JSString *str)
+{
+    if (!str) {
+        x->SetLength(0);
+        return NS_OK;
+    }
+    size_t length = JS_GetStringEncodingLength(NULL, str);
+    if (length == size_t(-1))
+        return NS_ERROR_FAILURE;
+    x->SetLength(PRUint32(length));
+    if (x->Length() != PRUint32(length))
+        return NS_ERROR_OUT_OF_MEMORY;
+    JS_EncodeStringToBuffer(str, x->BeginWriting(), length);
+    return NS_OK;
+}
+
 jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
                                                              mTag(0),
                                                              mCx(aCx),
                                                              mScript(aScript),
                                                              mFileName(0), 
                                                              mFunctionName(0),
                                                              mBaseLineNumber(0),
                                                              mLineExtent(0),
@@ -966,18 +983,22 @@ jsdScript::jsdScript (JSDContext *aCx, J
 {
     DEBUG_CREATE ("jsdScript", gScriptCount);
 
     if (mScript) {
         /* copy the script's information now, so we have it later, when it
          * gets destroyed. */
         JSD_LockScriptSubsystem(mCx);
         mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
-        mFunctionName =
-            new nsCString(JSD_GetScriptFunctionName(mCx, mScript));
+        mFunctionName = new nsCString();
+        if (mFunctionName) {
+            JSString *str = JSD_GetScriptFunctionName(mCx, mScript);
+            if (str)
+                AssignToJSString(mFunctionName, str);
+        }
         mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
         mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
         mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
         JSD_UnlockScriptSubsystem(mCx);
         
         mValid = PR_TRUE;
     }
 }
@@ -1839,17 +1860,21 @@ jsdStackFrame::GetExecutionContext(jsdIC
     *_rval = jsdContext::FromPtr (mCx, cx);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdStackFrame::GetFunctionName(nsACString &_rval)
 {
     ASSERT_VALID_EPHEMERAL;
-    _rval.Assign(JSD_GetNameForStackFrame(mCx, mThreadState, mStackFrameInfo));
+    JSString *str = JSD_GetNameForStackFrame(mCx, mThreadState, mStackFrameInfo);
+    if (str)
+        return AssignToJSString(&_rval, str);
+    
+    _rval.Assign("anonymous");
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdStackFrame::GetIsDebugger(PRBool *_rval)
 {
     ASSERT_VALID_EPHEMERAL;
     *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
@@ -2167,18 +2192,17 @@ jsdValue::GetJsConstructor (jsdIValue **
     *_rval = jsdValue::FromPtr (mCx, jsdv);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdValue::GetJsFunctionName(nsACString &_rval)
 {
     ASSERT_VALID_EPHEMERAL;
-    _rval.Assign(JSD_GetValueFunctionName(mCx, mValue));
-    return NS_OK;
+    return AssignToJSString(&_rval, JSD_GetValueFunctionName(mCx, mValue));
 }
 
 NS_IMETHODIMP
 jsdValue::GetBooleanValue(PRBool *_rval)
 {
     ASSERT_VALID_EPHEMERAL;
     *_rval = JSD_GetValueBoolean (mCx, mValue);
     return NS_OK;
--- a/js/jsd/jsdebug.c
+++ b/js/jsd/jsdebug.c
@@ -297,17 +297,17 @@ JSD_IsActiveScript(JSDContext* jsdc, JSD
 JSD_PUBLIC_API(const char*)
 JSD_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     JSD_ASSERT_VALID_SCRIPT(jsdscript);
     return jsd_GetScriptFilename(jsdc, jsdscript);
 }
 
-JSD_PUBLIC_API(const char*)
+JSD_PUBLIC_API(JSString *)
 JSD_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     JSD_ASSERT_VALID_SCRIPT(jsdscript);
     return jsd_GetScriptFunctionName(jsdc, jsdscript);
 }
 
 JSD_PUBLIC_API(uintN)
@@ -736,17 +736,17 @@ JSD_PUBLIC_API(JSDValue*)
 JSD_GetThisForStackFrame(JSDContext* jsdc,
                          JSDThreadState* jsdthreadstate,
                          JSDStackFrameInfo* jsdframe)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     return jsd_GetThisForStackFrame(jsdc, jsdthreadstate, jsdframe);
 }
 
-JSD_PUBLIC_API(const char*)
+JSD_PUBLIC_API(JSString *)
 JSD_GetNameForStackFrame(JSDContext* jsdc,
                          JSDThreadState* jsdthreadstate,
                          JSDStackFrameInfo* jsdframe)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     return jsd_GetNameForStackFrame(jsdc, jsdthreadstate, jsdframe);
 }
 
@@ -1103,17 +1103,17 @@ JSD_GetValueDouble(JSDContext* jsdc, JSD
 JSD_PUBLIC_API(JSString*)
 JSD_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     JSD_ASSERT_VALID_VALUE(jsdval);
     return jsd_GetValueString(jsdc, jsdval);
 }
 
-JSD_PUBLIC_API(const char*)
+JSD_PUBLIC_API(JSString *)
 JSD_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     JSD_ASSERT_VALID_VALUE(jsdval);
     return jsd_GetValueFunctionName(jsdc, jsdval);
 }
 
 /**************************************************/
--- a/js/jsd/jsdebug.h
+++ b/js/jsd/jsdebug.h
@@ -424,19 +424,20 @@ JSD_IsActiveScript(JSDContext* jsdc, JSD
 
 /*
 * Get the filename associated with this script
 */
 extern JSD_PUBLIC_API(const char*)
 JSD_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript);
 
 /*
-* Get the function name associated with this script (NULL if not a function)
+* Get the function name associated with this script (NULL if not a function).
+* If the function does not have a name the result is an empty string.
 */
-extern JSD_PUBLIC_API(const char*)
+extern JSD_PUBLIC_API(JSString *)
 JSD_GetScriptFunctionName(JSDContext* jsdc, JSDScript *jsdscript);
 
 /*
 * Get the base linenumber of the sourcefile from which this script was loaded.
 * This is one-based -- i.e. the first line of a file is line '1'. This may
 * return 0 if this infomation is unknown.
 */
 extern JSD_PUBLIC_API(uintN)
@@ -950,17 +951,17 @@ extern JSD_PUBLIC_API(JSDValue*)
 JSD_GetThisForStackFrame(JSDContext* jsdc,
                          JSDThreadState* jsdthreadstate,
                          JSDStackFrameInfo* jsdframe);
 
 /*
 * Get the name of the function executing in this stack frame.  Especially useful
 * for native frames (without script objects.)
 */
-extern JSD_PUBLIC_API(const char*)
+extern JSD_PUBLIC_API(JSString *)
 JSD_GetNameForStackFrame(JSDContext* jsdc,
                          JSDThreadState* jsdthreadstate,
                          JSDStackFrameInfo* jsdframe);
 
 /*
 * True if stack frame represents a frame created as a result of a debugger
 * evaluation.
 */
@@ -1283,17 +1284,17 @@ JSD_GetValueDouble(JSDContext* jsdc, JSD
 */
 extern JSD_PUBLIC_API(JSString*)
 JSD_GetValueString(JSDContext* jsdc, JSDValue* jsdval);
 
 /*
 * Return name of function IFF JSDValue represents a function.
 * *** new for version 1.1 ****
 */
-extern JSD_PUBLIC_API(const char*)
+extern JSD_PUBLIC_API(JSString *)
 JSD_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval);
 
 /**************************************************/
 
 /*
 * Return the number of properties for the JSDValue.
 * *** new for version 1.1 ****
 */
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-2.js
@@ -0,0 +1,8 @@
+function f() {
+    var a = [], i, N = HOTLOOP + 2;
+    for (i = 0; i < N; i++)
+        a[i] = {m: i, m: function() { return 0; }};
+    assertEq(a[N - 2].m === a[N - 1].m, false);
+}
+f();
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-3.js
@@ -0,0 +1,15 @@
+function f() {
+    var a = [], i, N = HOTLOOP + 2;
+    for (i = 0; i < N; i++) {
+        a[i] = {};
+        a[i].m = function() { return 0; };
+        a[i].m = function() { return 1; };
+    }
+    assertEq(a[N - 2].m === a[N - 1].m, false);
+    for (i = 0; i < N; i++) {
+        var f = a[i].m;
+        assertEq(f(), 1);
+    }
+}
+f();
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-4.js
@@ -0,0 +1,12 @@
+function f() {
+    var a = [], i, N = HOTLOOP + 2;
+    for (i = 0; i < N; i++)
+        a[i] = {m: function() { return 0; }, m: function() { return 1; }};
+    assertEq(a[N - 2].m === a[N - 1].m, false);
+    for (i = 0; i < N; i++) {
+        var f = a[i].m;
+        assertEq(f(), 1);
+    }
+}
+f();
+f();
--- a/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt.js
+++ b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt.js
@@ -1,17 +1,10 @@
 function f() {
-  var a = [{m: 0}, {m: 1}, {m: 2}, {m: 3}, {m: 4}];
-  var b = [{}, {}, {}, {}, {}];
-  for (var i = 0; i < a.length; i++) {
-    a[i].m = function() { return 0; };
-    b[i].m = function() { return 1; };
-  }
-  assertEq(false, a[0].m === a[1].m);
-  assertEq(false, a[0].m === a[2].m);
-  assertEq(false, a[0].m === a[3].m);
-  assertEq(false, a[0].m === a[4].m);
-  assertEq(false, b[0].m === b[1].m);
-  assertEq(false, b[0].m === b[2].m);
-  assertEq(false, b[0].m === b[3].m);
-  assertEq(false, b[0].m === b[4].m);
+    var a = [], i, N = HOTLOOP + 2;
+    for (i = 0; i < N; i++)
+        a[i] = {m: i};
+    for (i = 0; i < N; i++)
+        a[i].m = function() { return 0; };
+    assertEq(a[N - 2].m === a[N - 1].m, false);
 }
 f();
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/pic/to-dictionary.js
@@ -0,0 +1,9 @@
+function f() {
+    var MAX_HEIGHT = 64;
+    var obj = {};
+    for (var i = 0; i < MAX_HEIGHT; i++)
+        obj['a' + i] = i;
+    obj.m = function () { return 0; };
+}
+f();
+f();
--- a/js/src/jsapi-tests/testConservativeGC.cpp
+++ b/js/src/jsapi-tests/testConservativeGC.cpp
@@ -53,8 +53,28 @@ bool checkObjectFields(JSObject *savedCo
      */
     savedCopy->objShape = obj->objShape;
     savedCopy->slots = obj->slots;
     CHECK(!memcmp(savedCopy, obj, sizeof(*obj)));
     return true;
 }
 
 END_TEST(testConservativeGC)
+
+BEGIN_TEST(testDerivedValues)
+{
+  JSString *str = JS_NewStringCopyZ(cx, "once upon a midnight dreary");
+  js::Anchor<JSString *> str_anchor(str);
+  static const jschar expected[] = { 'o', 'n', 'c', 'e' };
+  const jschar *ch = JS_GetStringCharsZ(cx, str);
+  str = NULL;
+
+  /* Do a lot of allocation and collection. */
+  for (int i = 0; i < 3; i++) {
+    for (int j = 0; j < 1000; j++)
+      JS_NewStringCopyZ(cx, "as I pondered weak and weary");
+    JS_GC(cx);
+  }
+
+  CHECK(!memcmp(ch, expected, sizeof(expected)));
+  return true;
+}
+END_TEST(testDerivedValues)
--- a/js/src/jsapi-tests/testGetPropertyDefault.cpp
+++ b/js/src/jsapi-tests/testGetPropertyDefault.cpp
@@ -5,21 +5,17 @@
 #include "tests.h"
 
 #define JSVAL_IS_FALSE(x) ((JSVAL_IS_BOOLEAN(x)) && !(JSVAL_TO_BOOLEAN(x)))
 #define JSVAL_IS_TRUE(x)  ((JSVAL_IS_BOOLEAN(x)) && (JSVAL_TO_BOOLEAN(x)))
 
 static JSBool
 stringToId(JSContext *cx, const char *s, jsid *idp)
 {
-    char *buf = JS_strdup(cx, s);
-    if (!buf)
-        return false;
-
-    JSString *str = JS_NewString(cx, buf, strlen(s));
+    JSString *str = JS_NewStringCopyZ(cx, s);
     if (!str)
         return false;
 
     return JS_ValueToId(cx, STRING_TO_JSVAL(str), idp);
 }
 
 BEGIN_TEST(testGetPropertyDefault_bug594060)
 {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -40,16 +40,17 @@
 
 /*
  * JavaScript API.
  */
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsarena.h"
 #include "jsutil.h"
 #include "jsclist.h"
 #include "jsdhash.h"
 #include "jsprf.h"
 #include "jsapi.h"
@@ -197,16 +198,23 @@ JS_GetPositiveInfinityValue(JSContext *c
 }
 
 JS_PUBLIC_API(jsval)
 JS_GetEmptyStringValue(JSContext *cx)
 {
     return STRING_TO_JSVAL(cx->runtime->emptyString);
 }
 
+JS_PUBLIC_API(JSString *)
+JS_GetEmptyString(JSRuntime *rt)
+{
+    JS_ASSERT(rt->state == JSRTS_UP);
+    return rt->emptyString;
+}
+
 static JSBool
 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
 {
     const char *format;
     JSArgumentFormatMap *map;
 
     format = *formatp;
     for (map = cx->argumentFormatMap; map; map = map->next) {
@@ -629,20 +637,16 @@ JSRuntime::init(uint32 maxbytes)
         return false;
 
 #if ENABLE_YARR_JIT
     regExpAllocator = JSC::ExecutableAllocator::create();
     if (!regExpAllocator)
         return false;
 #endif
 
-    deflatedStringCache = new js::DeflatedStringCache();
-    if (!deflatedStringCache || !deflatedStringCache->init())
-        return false;
-
     wrapObjectCallback = js::TransparentObjectWrapper;
 
 #ifdef JS_THREADSAFE
     /* this is asymmetric with JS_ShutDown: */
     if (!js_SetupLocks(8, 16))
         return false;
     rtLock = JS_NEW_LOCK();
     if (!rtLock)
@@ -678,21 +682,16 @@ JSRuntime::~JSRuntime()
                 cxcount, (cxcount == 1) ? "" : "s");
     }
 #endif
 
     js_FinishThreads(this);
     js_FreeRuntimeScriptState(this);
     js_FinishAtomState(this);
 
-    /*
-     * Finish the deflated string cache after the last GC and after
-     * calling js_FinishAtomState, which finalizes strings.
-     */
-    delete deflatedStringCache;
 #if ENABLE_YARR_JIT
     delete regExpAllocator;
 #endif
     js_FinishGC(this);
 #ifdef JS_THREADSAFE
     if (gcLock)
         JS_DESTROY_LOCK(gcLock);
     if (gcDone)
@@ -938,16 +937,27 @@ JS_ResumeRequest(JSContext *cx, jsrefcou
     JS_ASSERT(!t->data.requestDepth);
     JS_ASSERT(t->suspendCount);
     StartRequest(cx);
     t->data.requestDepth = saveDepth;
     t->suspendCount--;
 #endif
 }
 
+JS_PUBLIC_API(JSBool)
+JS_IsInRequest(JSContext *cx)
+{
+#ifdef JS_THREADSAFE
+    JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
+    return JS_THREAD_DATA(cx)->requestDepth != 0;
+#else
+    return false;
+#endif
+}
+
 JS_PUBLIC_API(void)
 JS_Lock(JSRuntime *rt)
 {
     JS_LOCK_RUNTIME(rt);
 }
 
 JS_PUBLIC_API(void)
 JS_Unlock(JSRuntime *rt)
@@ -4207,25 +4217,16 @@ JS_CloneFunctionObject(JSContext *cx, JS
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetFunctionObject(JSFunction *fun)
 {
     return FUN_OBJECT(fun);
 }
 
-JS_PUBLIC_API(const char *)
-JS_GetFunctionName(JSFunction *fun)
-{
-    if (!fun->atom)
-        return js_anonymous_str;
-    const char *byte = js_GetStringBytes(fun->atom);
-    return byte ? byte : "";
-}
-
 JS_PUBLIC_API(JSString *)
 JS_GetFunctionId(JSFunction *fun)
 {
     return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
 }
 
 JS_PUBLIC_API(uintN)
 JS_GetFunctionFlags(JSFunction *fun)
@@ -4423,17 +4424,17 @@ JS_CompileUCScriptForPrincipals(JSContex
                                 const char *filename, uintN lineno)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
 
     uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
     JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
-                                               chars, length, NULL, filename, lineno);
+                                               chars, length, filename, lineno);
     if (script && !js_NewScriptObject(cx, script)) {
         js_DestroyScript(cx, script);
         script = NULL;
     }
     LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
@@ -4498,17 +4499,17 @@ JS_BufferIsCompilableUnit(JSContext *cx,
     /*
      * Return true on any out-of-memory error, so our caller doesn't try to
      * collect more buffered source.
      */
     result = JS_TRUE;
     exnState = JS_SaveExceptionState(cx);
     {
         Parser parser(cx);
-        if (parser.init(chars, length, NULL, NULL, 1)) {
+        if (parser.init(chars, length, NULL, 1)) {
             older = JS_SetErrorReporter(cx, NULL);
             if (!parser.parse(obj) &&
                 parser.tokenStream.isUnexpectedEOF()) {
                 /*
                  * We ran into an error. If it was because we ran out of
                  * source, we return false so our caller knows to try to
                  * collect more buffered source.
                  */
@@ -4517,16 +4518,80 @@ JS_BufferIsCompilableUnit(JSContext *cx,
             JS_SetErrorReporter(cx, older);
         }
     }
     cx->free(chars);
     JS_RestoreExceptionState(cx, exnState);
     return result;
 }
 
+/* Use the fastest available getc. */
+#if defined(HAVE_GETC_UNLOCKED)
+# define fast_getc getc_unlocked
+#elif defined(HAVE__GETC_NOLOCK)
+# define fast_getc _getc_nolock
+#else
+# define fast_getc getc
+#endif
+
+static JSScript *
+CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals, uint32 tcflags,
+                  const char* filename, FILE *fp)
+{
+    struct stat st;
+    int ok = fstat(fileno(fp), &st);
+    if (ok != 0)
+        return NULL;
+
+    jschar *buf = NULL;
+    size_t len = st.st_size;
+    size_t i = 0;
+    JSScript *script;
+
+    /* Read in the whole file, then compile it. */
+    if (fp == stdin) {
+        JS_ASSERT(len == 0);
+        len = 8;  /* start with a small buffer, expand as necessary */
+        int c;
+        bool hitEOF = false;
+        while (!hitEOF) {
+            len *= 2;
+            jschar* tmpbuf = (jschar *) cx->realloc(buf, len * sizeof(jschar));
+            if (!tmpbuf) {
+                cx->free(buf);
+                return NULL;
+            }
+            buf = tmpbuf;
+
+            while (i < len) {
+                c = fast_getc(fp);
+                if (c == EOF) {
+                    hitEOF = true;
+                    break;
+                }
+                buf[i++] = (jschar) (unsigned char) c;
+            }
+        }
+    } else {
+        buf = (jschar *) cx->malloc(len * sizeof(jschar));
+        if (!buf)
+            return NULL;
+
+        int c;
+        while ((c = fast_getc(fp)) != EOF)
+            buf[i++] = (jschar) (unsigned char) c;
+    }
+
+    JS_ASSERT(i <= len);
+    len = i;
+    script = Compiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len, filename, 1);
+    cx->free(buf);
+    return script;
+}
+
 JS_PUBLIC_API(JSScript *)
 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
     FILE *fp;
     uint32 tcflags;
     JSScript *script;
 
@@ -4539,18 +4604,18 @@ JS_CompileFile(JSContext *cx, JSObject *
         if (!fp) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
                                  filename, "No such file or directory");
             return NULL;
         }
     }
 
     tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
-    script = Compiler::compileScript(cx, obj, NULL, NULL, tcflags,
-                                     NULL, 0, fp, filename, 1);
+    script = CompileFileHelper(cx, obj, NULL, tcflags, filename, fp);
+
     if (fp != stdin)
         fclose(fp);
     if (script && !js_NewScriptObject(cx, script)) {
         js_DestroyScript(cx, script);
         script = NULL;
     }
     LAST_FRAME_CHECKS(cx, script);
     return script;
@@ -4562,18 +4627,18 @@ JS_CompileFileHandleForPrincipals(JSCont
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
     uint32 tcflags;
     JSScript *script;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
     tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
-    script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
-                                     NULL, 0, file, filename, 1);
+    script = CompileFileHelper(cx, obj, principals, tcflags, filename, file);
+
     if (script && !js_NewScriptObject(cx, script)) {
         js_DestroyScript(cx, script);
         script = NULL;
     }
     LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
@@ -4862,17 +4927,17 @@ JS_EvaluateUCScriptForPrincipals(JSConte
     JSScript *script;
     JSBool ok;
 
     CHECK_REQUEST(cx);
     script = Compiler::compileScript(cx, obj, NULL, principals,
                                      !rval
                                      ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
                                      : TCF_COMPILE_N_GO,
-                                     chars, length, NULL, filename, lineno);
+                                     chars, length, filename, lineno);
     if (!script) {
         LAST_FRAME_CHECKS(cx, script);
         return JS_FALSE;
     }
     ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
     LAST_FRAME_CHECKS(cx, ok);
     js_DestroyScript(cx, script);
     return ok;
@@ -5113,18 +5178,22 @@ JS_NewString(JSContext *cx, char *bytes,
 
     /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
     chars = js_InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
 
     /* Free chars (but not bytes, which caller frees on error) if we fail. */
     str = js_NewString(cx, chars, length);
-    if (!str)
+    if (!str) {
         cx->free(chars);
+        return NULL;
+    }
+
+    js_free(bytes);
     return str;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
 {
     jschar *js;
     JSString *str;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -540,16 +540,19 @@ extern JS_PUBLIC_API(jsval)
 JS_GetNegativeInfinityValue(JSContext *cx);
 
 extern JS_PUBLIC_API(jsval)
 JS_GetPositiveInfinityValue(JSContext *cx);
 
 extern JS_PUBLIC_API(jsval)
 JS_GetEmptyStringValue(JSContext *cx);
 
+extern JS_PUBLIC_API(JSString *)
+JS_GetEmptyString(JSRuntime *rt);
+
 /*
  * Format is a string of the following characters (spaces are insignificant),
  * specifying the tabulated type conversions:
  *
  *   b      JSBool          Boolean
  *   c      uint16/jschar   ECMA uint16, Unicode char
  *   i      int32           ECMA int32
  *   u      uint32          ECMA uint32
@@ -747,16 +750,19 @@ extern JS_PUBLIC_API(void)
 JS_YieldRequest(JSContext *cx);
 
 extern JS_PUBLIC_API(jsrefcount)
 JS_SuspendRequest(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth);
 
+extern JS_PUBLIC_API(JSBool)
+JS_IsInRequest(JSContext *cx);
+
 #ifdef __cplusplus
 JS_END_EXTERN_C
 
 class JSAutoRequest {
   public:
     JSAutoRequest(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM)
         : mContext(cx), mSaveDepth(0) {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
@@ -812,16 +818,40 @@ class JSAutoSuspendRequest {
 
 #if 0
   private:
     static void *operator new(size_t) CPP_THROW_NEW { return 0; };
     static void operator delete(void *, size_t) { };
 #endif
 };
 
+class JSAutoCheckRequest {
+  public:
+    JSAutoCheckRequest(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) {
+#if defined JS_THREADSAFE && defined DEBUG
+        mContext = cx;
+        JS_ASSERT(JS_IsInRequest(cx));
+#endif
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+    
+    ~JSAutoCheckRequest() {
+#if defined JS_THREADSAFE && defined DEBUG
+        JS_ASSERT(JS_IsInRequest(mContext));
+#endif
+    }
+
+
+  private:
+#if defined JS_THREADSAFE && defined DEBUG
+    JSContext *mContext;
+#endif
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 JS_BEGIN_EXTERN_C
 #endif
 
 extern JS_PUBLIC_API(void)
 JS_Lock(JSRuntime *rt);
 
 extern JS_PUBLIC_API(void)
 JS_Unlock(JSRuntime *rt);
@@ -1234,16 +1264,190 @@ extern JS_FRIEND_API(JSBool)
 js_AddRootRT(JSRuntime *rt, jsval *vp, const char *name);
 
 extern JS_FRIEND_API(JSBool)
 js_AddGCThingRootRT(JSRuntime *rt, void **rp, const char *name);
 
 extern JS_FRIEND_API(JSBool)
 js_RemoveRoot(JSRuntime *rt, void *rp);
 
+#ifdef __cplusplus
+JS_END_EXTERN_C
+
+namespace js {
+
+/*
+ * Protecting non-jsval, non-JSObject *, non-JSString * values from collection
+ * 
+ * Most of the time, the garbage collector's conservative stack scanner works
+ * behind the scenes, finding all live values and protecting them from being
+ * collected. However, when JSAPI client code obtains a pointer to data the
+ * scanner does not know about, owned by an object the scanner does know about,
+ * Care Must Be Taken.
+ *
+ * The scanner recognizes only a select set of types: pointers to JSObjects and
+ * similar things (JSFunctions, and so on), pointers to JSStrings, and jsvals.
+ * So while the scanner finds all live |JSString| pointers, it does not notice
+ * |jschar| pointers.
+ *
+ * So suppose we have:
+ *
+ *   void f(JSString *str) {
+ *     const jschar *ch = JS_GetStringCharsZ(str);
+ *     ... do stuff with ch, but no uses of str ...;
+ *   }
+ *
+ * After the call to |JS_GetStringCharsZ|, there are no further uses of
+ * |str|, which means that the compiler is within its rights to not store
+ * it anywhere. But because the stack scanner will not notice |ch|, there
+ * is no longer any live value in this frame that would keep the string
+ * alive. If |str| is the last reference to that |JSString|, and the
+ * collector runs while we are using |ch|, the string's array of |jschar|s
+ * may be freed out from under us.
+ *
+ * Note that there is only an issue when 1) we extract a thing X the scanner
+ * doesn't recognize from 2) a thing Y the scanner does recognize, and 3) if Y
+ * gets garbage-collected, then X gets freed. If we have code like this:
+ *
+ *   void g(JSObject *obj) {
+ *     jsval x;
+ *     JS_GetProperty(obj, "x", &x);
+ *     ... do stuff with x ...
+ *   }
+ *
+ * there's no problem, because the value we've extracted, x, is a jsval, a
+ * type that the conservative scanner recognizes.
+ *
+ * Conservative GC frees us from the obligation to explicitly root the types it
+ * knows about, but when we work with derived values like |ch|, we must root
+ * their owners, as the derived value alone won't keep them alive.
+ *
+ * A js::Anchor is a kind of GC root that allows us to keep the owners of
+ * derived values like |ch| alive throughout the Anchor's lifetime. We could
+ * fix the above code as follows:
+ *
+ *   void f(JSString *str) {
+ *     js::Anchor<JSString *> a_str(str);
+ *     const jschar *ch = JS_GetStringCharsZ(str);
+ *     ... do stuff with ch, but no uses of str ...;
+ *   }
+ *
+ * This simply ensures that |str| will be live until |a_str| goes out of scope.
+ * As long as we don't retain a pointer to the string's characters for longer
+ * than that, we have avoided all garbage collection hazards.
+ */
+template<typename T> class AnchorPermitted;
+template<typename T>
+class Anchor: AnchorPermitted<T> {
+  public:
+    Anchor() { }
+    explicit Anchor(T t) { hold = t; }
+    ~Anchor() {
+#ifdef __GNUC__
+        /* 
+         * No code is generated for this. But because this is marked 'volatile', G++ will
+         * assume it has important side-effects, and won't delete it. (G++ never looks at
+         * the actual text and notices it's empty.) And because we have passed |hold| to
+         * it, GCC will keep |hold| alive until this point.
+         *
+         * The "memory" clobber operand ensures that G++ will not move prior memory
+         * accesses after the asm --- it's a barrier. Unfortunately, it also means that
+         * G++ will assume that all memory has changed after the asm, as it would for a
+         * call to an unknown function. I don't know of a way to avoid that consequence.
+         */
+        asm volatile("":: "g" (hold) : "memory");
+#else
+        /*
+         * An adequate portable substitute.
+         *
+         * The compiler promises that, by the end of an expression statement, the
+         * last-stored value to a volatile object is the same as it would be in an
+         * unoptimized, direct implementation (the "abstract machine" whose behavior the
+         * language spec describes). However, the compiler is still free to reorder
+         * non-volatile accesses across this store --- which is what we must prevent. So
+         * assigning the held value to a volatile variable, as we do here, is not enough.
+         *
+         * In our case, however, garbage collection only occurs at function calls, so it
+         * is sufficient to ensure that the destructor's store isn't moved earlier across
+         * any function calls that could collect. It is hard to imagine the compiler
+         * analyzing the program so thoroughly that it could prove that such motion was
+         * safe. In practice, compilers treat calls to the collector as opaque operations
+         * --- in particular, as operations which could access volatile variables, across
+         * which this destructor must not be moved.
+         *
+         * ("Objection, your honor!  *Alleged* killer whale!")
+         *
+         * The disadvantage of this approach is that it does generate code for the store.
+         * We do need to use Anchors in some cases where cycles are tight.
+         */
+        volatile T sink;
+#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
+        /*
+         * Can't just do a simple assignment here.
+         */
+        doAssignment(sink, hold);
+#else
+        sink = hold;
+#endif
+#endif
+    }
+    T &get()      { return hold; }
+    void set(T t) { hold = t; }
+    void clear()  { hold = 0; }
+  private:
+    T hold;
+    /* Anchors should not be assigned or passed to functions. */
+    Anchor(const Anchor &);
+    const Anchor &operator=(const Anchor &);
+};
+
+/*
+ * Ensure that attempts to create Anchors for types the garbage collector's conservative
+ * scanner doesn't actually recgonize fail. Such anchors would have no effect.
+ */
+class Anchor_base {
+protected:
+#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
+    template<typename T> void doAssignment(volatile T &lhs, const T &rhs) {
+        lhs = rhs;
+    }
+#endif
+};
+template<> class AnchorPermitted<JSObject *> : protected Anchor_base { };
+template<> class AnchorPermitted<const JSObject *> : protected Anchor_base { };
+template<> class AnchorPermitted<JSFunction *> : protected Anchor_base { };
+template<> class AnchorPermitted<const JSFunction *> : protected Anchor_base { };
+template<> class AnchorPermitted<JSString *> : protected Anchor_base { };
+template<> class AnchorPermitted<const JSString *> : protected Anchor_base { };
+template<> class AnchorPermitted<jsval> : protected Anchor_base {
+protected:
+#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
+    void doAssignment(volatile jsval &lhs, const jsval &rhs) {
+        /*
+         * The default assignment operator for |struct C| has the signature:
+         *
+         *   C& C::operator=(const C&)
+         *
+         * And in particular requires implicit conversion of |this| to
+         * type |C| for the return value.  But |volatile C| cannot
+         * thus be converted to |C|, so just doing |sink = hold| here
+         * would fail to compile.  Do the assignment on asBits
+         * instead, since I don't think we want to give jsval_layout
+         * an assignment operator returning |volatile jsval_layout|.
+         */
+        lhs.asBits = rhs.asBits;
+    }
+#endif
+};
+
+}  /* namespace js */
+
+JS_BEGIN_EXTERN_C
+#endif
+
 /*
  * This symbol may be used by embedders to detect the change from the old
  * JS_AddRoot(JSContext *, void *) APIs to the new ones above.
  */
 #define JS_TYPED_ROOTING_API
 
 /* Obsolete rooting APIs. */
 #define JS_ClearNewbornRoots(cx) ((void) 0)
@@ -2335,31 +2539,20 @@ JS_NewFunction(JSContext *cx, JSNative c
 extern JS_PUBLIC_API(JSFunction *)
 JS_NewFunctionById(JSContext *cx, JSNative call, uintN nargs, uintN flags,
                    JSObject *parent, jsid id);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_GetFunctionObject(JSFunction *fun);
 
 /*
- * Deprecated, useful only for diagnostics.  Use JS_GetFunctionId instead for
- * anonymous vs. "anonymous" disambiguation and Unicode fidelity.
- */
-extern JS_PUBLIC_API(const char *)
-JS_GetFunctionName(JSFunction *fun);
-
-/*
  * Return the function's identifier as a JSString, or null if fun is unnamed.
  * The returned string lives as long as fun, so you don't need to root a saved
  * reference to it if fun is well-connected or rooted, and provided you bound
  * the use of the saved reference by fun's lifetime.
- *
- * Prefer JS_GetFunctionId over JS_GetFunctionName because it returns null for
- * truly anonymous functions, and because it doesn't chop to ISO-Latin-1 chars
- * from UTF-16-ish jschars.
  */
 extern JS_PUBLIC_API(JSString *)
 JS_GetFunctionId(JSFunction *fun);
 
 /*
  * Return JSFUN_* flags for fun.
  */
 extern JS_PUBLIC_API(uintN)
@@ -2950,16 +3143,22 @@ class JSAutoByteString {
       : mBytes(NULL) {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     ~JSAutoByteString() {
         js_free(mBytes);
     }
 
+    /* Take ownership of the given byte array. */
+    void initBytes(char *bytes) {
+        JS_ASSERT(!mBytes);
+        mBytes = bytes;
+    }
+
     char *encode(JSContext *cx, JSString *str) {
         JS_ASSERT(!mBytes);
         JS_ASSERT(cx);
         mBytes = JS_EncodeString(cx, str);
         return mBytes;
     }
 
     void clear() {
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -582,33 +582,33 @@ js_Atomize(JSContext *cx, const char *by
 }
 
 JSAtom *
 js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
 {
     JSString str;
 
     CHECK_REQUEST(cx);
-    str.initFlat((jschar *)chars, length);
+    str.initFlatNotTerminated((jschar *)chars, length);
     return js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
 }
 
 JSAtom *
 js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
 {
     JSString str, *str2;
     JSAtomState *state;
 
     if (length == 1) {
         jschar c = *chars;
         if (c < UNIT_STRING_LIMIT)
             return STRING_TO_ATOM(JSString::unitString(c));
     }
 
-    str.initFlat((jschar *)chars, length);
+    str.initFlatNotTerminated((jschar *)chars, length);
     state = &cx->runtime->atomState;
 
     JS_LOCK(cx, &state->lock);
     AtomSet::Ptr p = state->atoms.lookup(&str);
     str2 = p ? AtomEntryToKey(*p) : NULL;
     JS_UNLOCK(cx, &state->lock);
 
     return str2 ? STRING_TO_ATOM(str2) : NULL;
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -599,19 +599,24 @@ class Chars {
     JSContext *cx;
     jschar *p;
   public:
     Chars() : p(NULL) {}
     ~Chars() { if (p) cx->free(p); }
 
     bool allocate(JSContext *cx, size_t len) {
         JS_ASSERT(!p);
-        p = (jschar *) cx->malloc(len * sizeof(jschar));
+        // We're going to null-terminate!
+        p = (jschar *) cx->malloc((len + 1) * sizeof(jschar));
         this->cx = cx;
-        return p != NULL;
+        if (p) {
+            p[len] = jschar(0);
+            return true;
+        }
+        return false;
     }
     jschar *get() { return p; }
     void forget() { p = NULL; }
 };
 
 JSString *
 JSStructuredCloneReader::readString(uint32_t nchars)
 {
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1364,18 +1364,16 @@ struct JSRuntime {
     JSTraceDataOp       gcExtraRootsTraceOp;
     void                *gcExtraRootsData;
 
     /* Well-known numbers held for use by this runtime's contexts. */
     js::Value           NaNValue;
     js::Value           negativeInfinityValue;
     js::Value           positiveInfinityValue;
 
-    js::DeflatedStringCache *deflatedStringCache;
-
     JSString            *emptyString;
 
     /* List of active contexts sharing this runtime; protected by gcLock. */
     JSCList             contextList;
 
     /* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
     JSDebugHooks        globalDebugHooks;
 
@@ -1578,16 +1576,17 @@ struct JSRuntime {
     double              strdepLengthSum;
     double              strdepLengthSquaredSum;
 
     /* Script instrumentation. */
     jsrefcount          liveScripts;
     jsrefcount          totalScripts;
     jsrefcount          liveEmptyScripts;
     jsrefcount          totalEmptyScripts;
+    jsrefcount          highWaterLiveScripts;
 #endif /* DEBUG */
 
 #ifdef JS_SCOPE_DEPTH_METER
     /*
      * Stats on runtime prototype chain lookups and scope chain depths, i.e.,
      * counts of objects traversed on a chain until the wanted id is found.
      */
     JSBasicStats        protoLookupDepthStats;
@@ -1652,16 +1651,23 @@ struct JSRuntime {
      * reporting OOM error when cx is not null.
      */
     void* calloc(size_t bytes, JSContext *cx = NULL) {
         updateMallocCounter(bytes);
         void *p = ::js_calloc(bytes);
         return JS_LIKELY(!!p) ? p : onOutOfMemory(reinterpret_cast<void *>(1), bytes, cx);
     }
 
+    void* realloc(void* p, size_t oldBytes, size_t newBytes, JSContext *cx = NULL) {
+        JS_ASSERT(oldBytes < newBytes);
+        updateMallocCounter(newBytes - oldBytes);
+        void *p2 = ::js_realloc(p, newBytes);
+        return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, newBytes, cx);
+    }
+
     void* realloc(void* p, size_t bytes, JSContext *cx = NULL) {
         /*
          * For compatibility we do not account for realloc that increases
          * previously allocated memory.
          */
         if (!p)
             updateMallocCounter(bytes);
         void *p2 = ::js_realloc(p, bytes);
@@ -2291,16 +2297,20 @@ struct JSContext
         JS_ASSERT(bytes != 0);
         return runtime->calloc(bytes, this);
     }
 
     inline void* realloc(void* p, size_t bytes) {
         return runtime->realloc(p, bytes, this);
     }
 
+    inline void* realloc(void* p, size_t oldBytes, size_t newBytes) {
+        return runtime->realloc(p, oldBytes, newBytes, this);
+    }
+
     inline void free(void* p) {
 #ifdef JS_THREADSAFE
         if (gcBackgroundFree) {
             gcBackgroundFree->freeLater(p);
             return;
         }
 #endif
         runtime->free(p);
--- a/js/src/jscompat.h
+++ b/js/src/jscompat.h
@@ -47,10 +47,9 @@
 #include "jstypes.h"
 #include "jslong.h"
 
 typedef JSIntn intN;
 typedef JSUintn uintN;
 typedef JSUword jsuword;
 typedef JSWord jsword;
 typedef float float32;
-#define allocPriv allocPool
 #endif /* jscompat_h___ */
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2350,21 +2350,20 @@ date_toSource(JSContext *cx, uintN argc,
     }
 
     bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr);
     if (!bytes) {
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
 
-    str = JS_NewString(cx, bytes, strlen(bytes));
-    if (!str) {
-        js_free(bytes);
+    str = JS_NewStringCopyZ(cx, bytes);
+    js_free(bytes);
+    if (!str)
         return JS_FALSE;
-    }
     vp->setString(str);
     return JS_TRUE;
 }
 #endif
 
 static JSBool
 date_toString(JSContext *cx, uintN argc, Value *vp)
 {
@@ -2650,145 +2649,16 @@ js_DateGetSeconds(JSContext *cx, JSObjec
     jsdouble utctime;
 
     if (!GetUTCTime(cx, obj, NULL, &utctime) || JSDOUBLE_IS_NaN(utctime))
         return 0;
 
     return (int) SecFromTime(utctime);
 }
 
-JS_FRIEND_API(void)
-js_DateSetYear(JSContext *cx, JSObject *obj, int year)
-{
-    jsdouble local;
-
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
-        return;
-
-    /* reset date if it was NaN */
-    if (JSDOUBLE_IS_NaN(local))
-        local = 0;
-
-    local = date_msecFromDate(year,
-                              MonthFromTime(local),
-                              DateFromTime(local),
-                              HourFromTime(local),
-                              MinFromTime(local),
-                              SecFromTime(local),
-                              msFromTime(local));
-
-    /* SetUTCTime also invalidates local time cache. */
-    SetUTCTime(cx, obj, UTC(local, cx));
-}
-
-JS_FRIEND_API(void)
-js_DateSetMonth(JSContext *cx, JSObject *obj, int month)
-{
-    jsdouble local;
-
-    JS_ASSERT(month < 12);
-
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
-        return;
-
-    /* bail if date was NaN */
-    if (JSDOUBLE_IS_NaN(local))
-        return;
-
-    local = date_msecFromDate(YearFromTime(local),
-                              month,
-                              DateFromTime(local),
-                              HourFromTime(local),
-                              MinFromTime(local),
-                              SecFromTime(local),
-                              msFromTime(local));
-    SetUTCTime(cx, obj, UTC(local, cx));
-}
-
-JS_FRIEND_API(void)
-js_DateSetDate(JSContext *cx, JSObject *obj, int date)
-{
-    jsdouble local;
-
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
-        return;
-
-    if (JSDOUBLE_IS_NaN(local))
-        return;
-
-    local = date_msecFromDate(YearFromTime(local),
-                              MonthFromTime(local),
-                              date,
-                              HourFromTime(local),
-                              MinFromTime(local),
-                              SecFromTime(local),
-                              msFromTime(local));
-    SetUTCTime(cx, obj, UTC(local, cx));
-}
-
-JS_FRIEND_API(void)
-js_DateSetHours(JSContext *cx, JSObject *obj, int hours)
-{
-    jsdouble local;
-
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
-        return;
-
-    if (JSDOUBLE_IS_NaN(local))
-        return;
-    local = date_msecFromDate(YearFromTime(local),
-                              MonthFromTime(local),
-                              DateFromTime(local),
-                              hours,
-                              MinFromTime(local),
-                              SecFromTime(local),
-                              msFromTime(local));
-    SetUTCTime(cx, obj, UTC(local, cx));
-}
-
-JS_FRIEND_API(void)
-js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes)
-{
-    jsdouble local;
-
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
-        return;
-
-    if (JSDOUBLE_IS_NaN(local))
-        return;
-    local = date_msecFromDate(YearFromTime(local),
-                              MonthFromTime(local),
-                              DateFromTime(local),
-                              HourFromTime(local),
-                              minutes,
-                              SecFromTime(local),
-                              msFromTime(local));
-    SetUTCTime(cx, obj, UTC(local, cx));
-}
-
-JS_FRIEND_API(void)
-js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds)
-{
-    jsdouble local;
-
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &local))
-        return;
-
-    if (JSDOUBLE_IS_NaN(local))
-        return;
-    local = date_msecFromDate(YearFromTime(local),
-                              MonthFromTime(local),
-                              DateFromTime(local),
-                              HourFromTime(local),
-                              MinFromTime(local),
-                              seconds,
-                              msFromTime(local));
-    SetUTCTime(cx, obj, UTC(local, cx));
-}
-
 JS_FRIEND_API(jsdouble)
 js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
 {
     jsdouble utctime;
     if (!GetUTCTime(cx, obj, NULL, &utctime))
         return 0;
     return utctime;
 }
--- a/js/src/jsdate.h
+++ b/js/src/jsdate.h
@@ -74,17 +74,17 @@ js_InitDateClass(JSContext *cx, JSObject
 extern JS_FRIEND_API(JSObject*)
 js_NewDateObjectMsec(JSContext* cx, jsdouble msec_time);
 
 /*
  * Construct a new Date Object from an exploded local time value.
  *
  * Assert that mon < 12 to help catch off-by-one user errors, which are common
  * due to the 0-based month numbering copied into JS from Java (java.util.Date
- * in 1995). js_DateSetMonth (below) likewise asserts month < 12.
+ * in 1995).
  */
 extern JS_FRIEND_API(JSObject*)
 js_NewDateObject(JSContext* cx, int year, int mon, int mday,
                  int hour, int min, int sec);
 
 /*
  * Detect whether the internal date value is NaN.  (Because failure is
  * out-of-band for js_DateGet*)
@@ -105,34 +105,16 @@ extern JS_FRIEND_API(int)
 js_DateGetHours(JSContext *cx, JSObject* obj);
 
 extern JS_FRIEND_API(int)
 js_DateGetMinutes(JSContext *cx, JSObject* obj);
 
 extern JS_FRIEND_API(int)
 js_DateGetSeconds(JSContext *cx, JSObject* obj);
 
-extern JS_FRIEND_API(void)
-js_DateSetYear(JSContext *cx, JSObject *obj, int year);
-
-extern JS_FRIEND_API(void)
-js_DateSetMonth(JSContext *cx, JSObject *obj, int month);
-
-extern JS_FRIEND_API(void)
-js_DateSetDate(JSContext *cx, JSObject *obj, int date);
-
-extern JS_FRIEND_API(void)
-js_DateSetHours(JSContext *cx, JSObject *obj, int hours);
-
-extern JS_FRIEND_API(void)
-js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes);
-
-extern JS_FRIEND_API(void)
-js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds);
-
 extern JS_FRIEND_API(jsdouble)
 js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj);
 
 typedef uint32 JSIntervalTime;
 
 extern JS_FRIEND_API(JSIntervalTime)
 js_IntervalNow();
 
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1453,17 +1453,17 @@ JS_EvaluateUCInStackFrame(JSContext *cx,
 
     /*
      * NB: This function breaks the assumption that the compiler can see all
      * calls and properly compute a static level. In order to get around this,
      * we use a static level that will cause us not to attempt to optimize
      * variable references made by this frame.
      */
     JSScript *script = Compiler::compileScript(cx, scobj, fp, js_StackFramePrincipals(cx, fp),
-                                               TCF_COMPILE_N_GO, chars, length, NULL,
+                                               TCF_COMPILE_N_GO, chars, length,
                                                filename, lineno, NULL,
                                                UpvarCookie::UPVAR_LEVEL_LIMIT);
 
     if (!script)
         return false;
 
     bool ok = Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, Valueify(rval));
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1695,20 +1695,16 @@ fun_resolve(JSContext *cx, JSObject *obj
         /*
          * Assert that fun is not a compiler-created function object, which
          * must never leak to script or embedding code and then be mutated.
          * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
          */
         JS_ASSERT(!IsInternalFunctionObject(obj));
         JS_ASSERT(!obj->isBoundFunction());
 
-        /* No need to reflect fun.prototype in 'fun.prototype = ... '. */
-        if (flags & JSRESOLVE_ASSIGNING)
-            return true;
-
         /*
          * Make the prototype object an instance of Object with the same parent
          * as the function object itself.
          */
         JSObject *parent = obj->getParent();
         JSObject *proto;
         if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
             return false;
@@ -2613,17 +2609,17 @@ Function(JSContext *cx, uintN argc, Valu
             cp += arg_length;
 
             /* Add separating comma or terminating 0. */
             *cp++ = (i + 1 < n) ? ',' : 0;
         }
 
         /* Initialize a tokenstream that reads from the given string. */
         TokenStream ts(cx);
-        if (!ts.init(cx->findVersion(), collected_args, args_length, NULL, filename, lineno)) {
+        if (!ts.init(cx->findVersion(), collected_args, args_length, filename, lineno)) {
             JS_ARENA_RELEASE(&cx->tempPool, mark);
             return JS_FALSE;
         }
 
         /* The argument string may be empty or contain no tokens. */
         TokenKind tt = ts.getToken();
         if (tt != TOK_EOF) {
             for (;;) {
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2198,22 +2198,16 @@ MarkAndSweep(JSContext *cx, JSGCInvocati
         FinalizeArenaList<JSObject_Slots16>(*comp, cx, FINALIZE_OBJECT16);
         FinalizeArenaList<JSFunction>(*comp, cx, FINALIZE_FUNCTION);
 #if JS_HAS_XML_SUPPORT
         FinalizeArenaList<JSXML>(*comp, cx, FINALIZE_XML);
 #endif
     }
     TIMESTAMP(sweepObjectEnd);
 
-    /*
-     * We sweep the deflated cache before we finalize the strings so the
-     * cache can safely use js_IsAboutToBeFinalized..
-     */
-    rt->deflatedStringCache->sweep(cx);
-
     for (JSCompartment **comp = rt->compartments.begin(); comp != rt->compartments.end(); comp++) {
         FinalizeArenaList<JSShortString>(*comp, cx, FINALIZE_SHORT_STRING);
         FinalizeArenaList<JSString>(*comp, cx, FINALIZE_STRING);
         FinalizeArenaList<JSExternalString>(*comp, cx, FINALIZE_EXTERNAL_STRING);
     }
 
     TIMESTAMP(sweepStringEnd);
 
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -726,17 +726,17 @@ ScriptEpilogue(JSContext *cx, JSStackFra
      */
     if (fp->isFunctionFrame() && !fp->isEvalFrame() && !fp->isYielding())
         PutActivationObjects(cx, fp);
 
     /*
      * If inline-constructing, replace primitive rval with the new object
      * passed in via |this|, and instrument this constructor invocation.
      */
-    if (fp->isConstructing()) {
+    if (fp->isConstructing() && ok) {
         if (fp->returnValue().isPrimitive())
             fp->setReturnValue(ObjectValue(fp->constructorThis()));
         JS_RUNTIME_METER(cx->runtime, constructs);
     }
 
     return ok;
 }
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -807,21 +807,20 @@ num_toLocaleString(JSContext *cx, uintN 
         strcpy(tmpDest, nint + 1);
     } else {
         strcpy(tmpDest, nint);
     }
 
     if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
         return cx->localeCallbacks->localeToUnicode(cx, buf, Jsvalify(vp));
 
-    str = JS_NewString(cx, buf, size);
-    if (!str) {
-        cx->free(buf);
+    str = js_NewStringCopyN(cx, buf, size);
+    cx->free(buf);
+    if (!str)
         return JS_FALSE;
-    }
 
     vp->setString(str);
     return JS_TRUE;
 }
 
 JSBool
 js_num_valueOf(JSContext *cx, uintN argc, Value *vp)
 {
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1226,17 +1226,17 @@ EvalKernel(JSContext *cx, uintN argc, Va
     if (!script) {
         uintN lineno;
         const char *filename = js_ComputeFilename(cx, caller, principals, &lineno);
 
         uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL;
         script = Compiler::compileScript(cx, scopeobj, callerFrame,
                                          principals, tcflags,
                                          chars, length,
-                                         NULL, filename, lineno, str, staticLevel);
+                                         filename, lineno, str, staticLevel);
         if (!script)
             return false;
     }
 
     assertSameCompartment(cx, scopeobj, script);
 
     /*
      * Belt-and-braces: check that the lesser of eval's principals and the
@@ -3934,17 +3934,17 @@ JSObject::growSlots(JSContext *cx, size_
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
     /* If nothing was allocated yet, treat it as initial allocation. */
     if (!hasSlotsArray())
         return allocSlots(cx, actualCapacity);
 
-    Value *tmpslots = (Value*) cx->realloc(slots, actualCapacity * sizeof(Value));
+    Value *tmpslots = (Value*) cx->realloc(slots, oldcap * sizeof(Value), actualCapacity * sizeof(Value));
     if (!tmpslots)
         return false;    /* Leave dslots as its old size. */
     slots = tmpslots;
     capacity = actualCapacity;
 
     /* Initialize the additional slots we added. */
     ClearValueRange(slots + oldcap, actualCapacity - oldcap, isDenseArray());
     return true;
@@ -4622,22 +4622,26 @@ js_DefineNativeProperty(JSContext *cx, J
     /* XXXbe called with lock held */
     valueCopy = value;
     if (!CallAddPropertyHook(cx, clasp, obj, shape, &valueCopy)) {
         obj->removeProperty(cx, id);
         return false;
     }
 
     if (defineHow & JSDNP_CACHE_RESULT) {
+        JS_ASSERT_NOT_ON_TRACE(cx);
+        if (added) {
 #ifdef JS_TRACER
-        JS_ASSERT_NOT_ON_TRACE(cx);
-        PropertyCacheEntry *entry =
+            PropertyCacheEntry *entry =
 #endif
-            JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, shape, added);
-        TRACE_2(SetPropHit, entry, shape);
+                JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, shape, true);
+            TRACE_2(SetPropHit, entry, shape);
+        } else {
+            TRACE_2(SetPropHit, JS_NO_PROP_CACHE_FILL, shape);
+        }
     }
     if (propp)
         *propp = (JSProperty *) shape;
     return true;
 
 #ifdef JS_TRACER
 error: // TRACE_2 jumps here on error.
 #endif
@@ -5489,32 +5493,49 @@ js_SetPropertyHelper(JSContext *cx, JSOb
 
             /*
              * Forget we found the proto-property now that we've copied any
              * needed member values.
              */
             shape = NULL;
         }
 
-        if (shape) {
-            if (shape->isMethod()) {
-                JS_ASSERT(pobj->hasMethodBarrier());
-            } else if ((defineHow & JSDNP_SET_METHOD) && obj->canHaveMethodBarrier()) {
+        JS_ASSERT_IF(shape && shape->isMethod(), pobj->hasMethodBarrier());
+        JS_ASSERT_IF(shape && shape->isMethod(),
+                     &pobj->getSlot(shape->slot).toObject() == &shape->methodObject());
+        if (shape && (defineHow & JSDNP_SET_METHOD)) {
+            /*
+             * JSOP_SETMETHOD is assigning to an existing own property. If it
+             * is an identical method property, do nothing. Otherwise downgrade
+             * to ordinary assignment. Either way, do not fill the property
+             * cache, as the interpreter has no fast path for these unusual
+             * cases.
+             */
+            bool identical = shape->isMethod() && &shape->methodObject() == &vp->toObject();
+            if (!identical) {
+                if (!obj->methodShapeChange(cx, *shape))
+                    return false;
+
                 JS_ASSERT(IsFunctionObject(*vp));
                 JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
 
                 JSObject *funobj = &vp->toObject();
                 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
                 if (fun == funobj) {
                     funobj = CloneFunctionObject(cx, fun, fun->parent);
                     if (!funobj)
                         return JS_FALSE;
                     vp->setObject(*funobj);
                 }
             }
+            if (defineHow & JSDNP_CACHE_RESULT) {
+                JS_ASSERT_NOT_ON_TRACE(cx);
+                TRACE_2(SetPropHit, JS_NO_PROP_CACHE_FILL, shape);
+            }
+            return identical || js_NativeSet(cx, obj, shape, false, vp);
         }
     }
 
     added = false;
     if (!shape) {
         if (!obj->isExtensible()) {
             if (defineHow & JSDNP_CACHE_RESULT) {
                 JS_ASSERT_NOT_ON_TRACE(cx);
@@ -6577,16 +6598,18 @@ DumpShape(const Shape &shape)
     fprintf(stderr, "    ");
     if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate ");
     if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly ");
     if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent ");
     if (attrs & JSPROP_GETTER) fprintf(stderr, "getter ");
     if (attrs & JSPROP_SETTER) fprintf(stderr, "setter ");
     if (attrs & JSPROP_SHARED) fprintf(stderr, "shared ");
     if (shape.isAlias()) fprintf(stderr, "alias ");
+    if (shape.isMethod()) fprintf(stderr, "method(%p) ", (void *) &shape.methodObject());
+
     if (JSID_IS_ATOM(id))
         dumpString(JSID_TO_STRING(id));
     else if (JSID_IS_INT(id))
         fprintf(stderr, "%d", (int) JSID_TO_INT(id));
     else
         fprintf(stderr, "unknown jsid %p", (void *) JSID_BITS(id));
     fprintf(stderr, ": slot %d", shape.slot);
     fprintf(stderr, "\n");
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1025,21 +1025,26 @@ struct JSObject : js::gc::Cell {
     /* This method can only be called when hasSlotsArray() returns true. */
     inline void freeSlotsArray(JSContext *cx);
 
     /* Free the slots array and copy slots that fit into the fixed array. */
     inline void revertToFixedSlots(JSContext *cx);
 
     inline bool hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags = 0);
 
+    /*
+     * Allocate and free an object slot. Note that freeSlot is infallible: it
+     * returns true iff this is a dictionary-mode object and the freed slot was
+     * added to the freelist.
+     *
+     * FIXME: bug 593129 -- slot allocation should be done by object methods
+     * after calling object-parameter-free shape methods, avoiding coupling
+     * logic across the object vs. shape module wall.
+     */
     bool allocSlot(JSContext *cx, uint32 *slotp);
-
-    /*
-     * Return true iff this is a dictionary-mode object and the freed slot was
-     * added to the freelist. */
     bool freeSlot(JSContext *cx, uint32 slot);
 
     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);
 
   private:
     js::Shape *getChildProperty(JSContext *cx, js::Shape *parent, js::Shape &child);
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -291,52 +291,53 @@ static bool
 ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes)
 {
     if (!JSVAL_IS_PRIMITIVE(v)) {
         JSObject *obj = JSVAL_TO_OBJECT(v);
         Class *clasp = obj->getClass();
 
         if (clasp == &js_BlockClass) {
             char *source = JS_sprintf_append(NULL, "depth %d {", OBJ_BLOCK_DEPTH(cx, obj));
+            if (!source)
+                return false;
 
             Shape::Range r = obj->lastProperty()->all();
             while (!r.empty()) {
                 const Shape &shape = r.front();
                 JSAutoByteString bytes;
                 if (!js_AtomToPrintableString(cx, JSID_TO_ATOM(shape.id), &bytes))
-                    return NULL;
+                    return false;
 
                 r.popFront();
                 source = JS_sprintf_append(source, "%s: %d%s",
                                            bytes.ptr(), shape.shortid,
                                            !r.empty() ? ", " : "");
+                if (!source)
+                    return false;
             }
 
             source = JS_sprintf_append(source, "}");
             if (!source)
-                return NULL;
-
-            JSString *str = JS_NewString(cx, source, strlen(source));
-            if (!str)
-                return NULL;
-            return bytes->encode(cx, str);
+                return false;
+            bytes->initBytes(source);
+            return true;
         }
 
         if (clasp == &js_FunctionClass) {
             JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
             JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
             if (!str)
-                return NULL;
+                return false;
             return bytes->encode(cx, str);
         }
 
         if (clasp == &js_RegExpClass) {
             AutoValueRooter tvr(cx);
             if (!js_regexp_toString(cx, obj, tvr.addr()))
-                return NULL;
+                return false;
             return bytes->encode(cx, JSVAL_TO_STRING(Jsvalify(tvr.value())));
         }
     }
 
     return !!js_ValueToPrintable(cx, Valueify(v), bytes, true);
 }
 
 JS_FRIEND_API(uintN)
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -185,24 +185,23 @@ Parser::Parser(JSContext *cx, JSPrincipa
     keepAtoms(cx->runtime)
 {
     js::PodArrayZero(tempFreeList);
     setPrincipals(prin);
     JS_ASSERT_IF(cfp, cfp->isScriptFrame());
 }
 
 bool
-Parser::init(const jschar *base, size_t length,
-             FILE *fp, const char *filename, uintN lineno)
+Parser::init(const jschar *base, size_t length, const char *filename, uintN lineno)
 {
     JSContext *cx = context;
     version = cx->findVersion();
     
     tempPoolMark = JS_ARENA_MARK(&cx->tempPool);
-    if (!tokenStream.init(version, base, length, fp, filename, lineno)) {
+    if (!tokenStream.init(version, base, length, filename, lineno)) {
         JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
         return false;
     }
     return true;
 }
 
 Parser::~Parser()
 {
@@ -743,17 +742,17 @@ Compiler::Compiler(JSContext *cx, JSPrin
   : parser(cx, prin, cfp)
 {
 }
 
 JSScript *
 Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
                         JSPrincipals *principals, uint32 tcflags,
                         const jschar *chars, size_t length,
-                        FILE *file, const char *filename, uintN lineno,
+                        const char *filename, uintN lineno,
                         JSString *source /* = NULL */,
                         uintN staticLevel /* = 0 */)
 {
     JSArenaPool codePool, notePool;
     TokenKind tt;
     JSParseNode *pn;
     JSScript *script;
     bool inDirectivePrologue;
@@ -767,17 +766,17 @@ Compiler::compileScript(JSContext *cx, J
     /*
      * The scripted callerFrame can only be given for compile-and-go scripts
      * and non-zero static level requires callerFrame.
      */
     JS_ASSERT_IF(callerFrame, tcflags & TCF_COMPILE_N_GO);
     JS_ASSERT_IF(staticLevel != 0, callerFrame);
 
     Compiler compiler(cx, principals, callerFrame);
-    if (!compiler.init(chars, length, file, filename, lineno))
+    if (!compiler.init(chars, length, filename, lineno))
         return NULL;
 
     JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode),
                      &cx->scriptStackQuota);
     JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote),
                      &cx->scriptStackQuota);
 
     Parser &parser = compiler.parser;
@@ -1640,17 +1639,17 @@ DefineArg(JSParseNode *pn, JSAtom *atom,
  */
 bool
 Compiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
                               const jschar *chars, size_t length,
                               const char *filename, uintN lineno)
 {
     Compiler compiler(cx, principals);
 
-    if (!compiler.init(chars, length, NULL, filename, lineno))
+    if (!compiler.init(chars, length, filename, lineno))
         return false;
 
     /* No early return from after here until the js_FinishArenaPool calls. */
     JSArenaPool codePool, notePool;
     JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode),
                      &cx->scriptStackQuota);
     JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote),
                      &cx->scriptStackQuota);
@@ -9404,30 +9403,31 @@ js_FoldConstants(JSContext *cx, JSParseN
                     return JS_TRUE;
                 length += ATOM_TO_STRING(pn2->pn_atom)->flatLength();
             }
 
             /* Allocate a new buffer and string descriptor for the result. */
             chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
             if (!chars)
                 return JS_FALSE;
+            chars[length] = 0;
             str = js_NewString(cx, chars, length);
             if (!str) {
                 cx->free(chars);
                 return JS_FALSE;
             }
 
             /* Fill the buffer, advancing chars and recycling kids as we go. */
             for (pn2 = pn1; pn2; pn2 = RecycleTree(pn2, tc)) {
                 str2 = ATOM_TO_STRING(pn2->pn_atom);
                 length2 = str2->flatLength();
                 js_strncpy(chars, str2->flatChars(), length2);
                 chars += length2;
             }
-            *chars = 0;
+            JS_ASSERT(*chars == 0);
 
             /* Atomize the result string and mutate pn to refer to it. */
             pn->pn_atom = js_AtomizeString(cx, str, 0);
             if (!pn->pn_atom)
                 return JS_FALSE;
             pn->pn_type = TOK_STRING;
             pn->pn_op = JSOP_STRING;
             pn->pn_arity = PN_NULLARY;
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -1023,17 +1023,17 @@ struct Parser : private js::AutoGCRooter
 
     /*
      * Initialize a parser. Parameters are passed on to init tokenStream.
      * The compiler owns the arena pool "tops-of-stack" space above the current
      * JSContext.tempPool mark. This means you cannot allocate from tempPool
      * and save the pointer beyond the next Parser destructor invocation.
      */
     bool init(const jschar *base, size_t length,
-              FILE *fp, const char *filename, uintN lineno);
+              const char *filename, uintN lineno);
 
     void setPrincipals(JSPrincipals *prin);
 
     const char *getFilename()
     {
         return tokenStream.getFilename();
     }
 
@@ -1170,31 +1170,31 @@ struct Compiler
 
     Compiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL);
 
     /*
      * Initialize a compiler. Parameters are passed on to init parser.
      */
     inline bool
     init(const jschar *base, size_t length,
-         FILE *fp, const char *filename, uintN lineno)
+         const char *filename, uintN lineno)
     {
-        return parser.init(base, length, fp, filename, lineno);
+        return parser.init(base, length, filename, lineno);
     }
 
     static bool
     compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
                         const jschar *chars, size_t length,
                         const char *filename, uintN lineno);
 
     static JSScript *
     compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
                   JSPrincipals *principals, uint32 tcflags,
                   const jschar *chars, size_t length,
-                  FILE *file, const char *filename, uintN lineno,
+                  const char *filename, uintN lineno,
                   JSString *source = NULL,
                   uintN staticLevel = 0);
 
   private:
     static bool
     defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *script);
 };
 
--- a/js/src/jsprobes.cpp
+++ b/js/src/jsprobes.cpp
@@ -77,17 +77,17 @@ Probes::FunctionLineNumber(JSContext *cx
 }
 
 /*
  * This function is used to convert function arguments and return value (jsval)
  * into the following based on each value's type tag:
  *
  *      jsval      returned
  *      -------------------
- *      STRING  -> char *
+ *      STRING  -> void *
  *      INT     -> int
  *      DOUBLE  -> double *
  *      BOOLEAN -> int
  *      OBJECT  -> void *
  *
  * All are presented as void * for DTrace consumers to use, after shifting or
  * masking out the JavaScript type bits. This allows D scripts to use ints and
  * booleans directly and copyinstr() for string arguments, when types are known
@@ -104,19 +104,16 @@ jsprobes_jsvaltovoid(JSContext *cx, cons
         return (void *)JS_TYPE_STR(JSTYPE_NULL);
 
     if (argval.isUndefined())
         return (void *)JS_TYPE_STR(JSTYPE_VOID);
 
     if (argval.isBoolean())
         return (void *)argval.toBoolean();
 
-    if (argval.isString())
-        return (void *)js_GetStringBytes(cx, argval.toString());
-
     if (argval.isNumber()) {
         if (argval.isInt32())
             return (void *)argval.toInt32();
         // FIXME Now what?
         //return (void *)argval.toDouble();
     }
 
     return argval.toGCThing();
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1102,18 +1102,17 @@ NewProxyObject(JSContext *cx, JSProxyHan
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
     if (!obj || !obj->ensureInstanceReservedSlots(cx, 0))
         return NULL;
     obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
     obj->setSlot(JSSLOT_PROXY_PRIVATE, priv);
     if (fun) {
         obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
         if (construct) {
-            obj->setSlot(JSSLOT_PROXY_CONSTRUCT,
-                         construct ? ObjectValue(*construct) : UndefinedValue());
+            obj->setSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
         }
     }
     return obj;
 }
 
 static JSObject *
 NonNullObject(JSContext *cx, const Value &v)
 {
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -159,18 +159,16 @@ template <class Key,
           class AllocPolicy = ContextAllocPolicy>
 class HashMap;
 
 template <class T,
           class HashPolicy = DefaultHasher<T>,
           class AllocPolicy = ContextAllocPolicy>
 class HashSet;
 
-class DeflatedStringCache;
-
 class PropertyCache;
 struct PropertyCacheEntry;
 
 struct Shape;
 struct EmptyShape;
 
 } /* namespace js */
 
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -2846,17 +2846,17 @@ reflect_parse(JSContext *cx, uint32 argc
 
     const jschar *chars;
     size_t length;
 
     src->getCharsAndLength(chars, length);
 
     Parser parser(cx);
 
-    if (!parser.init(chars, length, NULL, filename, lineno))
+    if (!parser.init(chars, length, filename, lineno))
         return JS_FALSE;
 
     JSParseNode *pn = parser.parse(NULL);
     if (!pn)
         return JS_FALSE;
 
     ASTSerializer serialize(cx, loc, filename, lineno);
     if (!serialize.init())
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -647,19 +647,19 @@ EscapeNakedForwardSlashes(JSContext *cx,
         }
 
         if (newChars.length())
             newChars.append(*it);
     }
 
     if (newChars.length()) {
         size_t len = newChars.length();
+        if (!newChars.append('\0'))
+            return NULL;
         jschar *chars = newChars.extractRawBuffer();
-        if (!chars)
-            return NULL;
         JSString *escaped = js_NewString(cx, chars, len);
         if (!escaped)
             cx->free(chars);
         return escaped;
     }
     return unescaped;
 }
 
--- a/js/src/jsscan.cpp
+++ b/js/src/jsscan.cpp
@@ -170,76 +170,57 @@ js_IsIdentifier(JSString *str)
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4351)
 #endif
 
 /* Initialize members that aren't initialized in |init|. */
 TokenStream::TokenStream(JSContext *cx)
-  : cx(cx), tokens(), cursor(), lookahead(), flags(),
-    linepos(), lineposNext(), file(), listenerTSData(), tokenbuf(cx)
+  : cx(cx), tokens(), cursor(), lookahead(), flags(), listenerTSData(), tokenbuf(cx)
 {}
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 bool
-TokenStream::init(JSVersion version, const jschar *base, size_t length, FILE *fp,
-                  const char *fn, uintN ln)
+TokenStream::init(JSVersion version, const jschar *base, size_t length, const char *fn, uintN ln)
 {
     this->version = version;
-    JS_ASSERT_IF(fp, !base);
-    JS_ASSERT_IF(!base, length == 0);
-    size_t nb = fp
-         ? (UNGET_LIMIT + 2 * LINE_LIMIT) * sizeof(jschar)    /* see below */
-         : (UNGET_LIMIT + 1 * LINE_LIMIT) * sizeof(jschar);
-    jschar *buf;
-    JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb);
-    if (!buf) {
-        js_ReportOutOfScriptQuota(cx);
-        return false;
-    }
-    memset(buf, 0, nb);
 
-    /* Initialize members. */
     filename = fn;
     lineno = ln;
-    /* 
-     * Split 'buf' into 3 (ungetbuf, linebuf, userbuf) or 2 (ungetbuf, linebuf).
-     * ungetbuf is empty and fills backwards.  linebuf is empty and fills forwards.
-     */
-    ungetbuf.base = buf;
-    ungetbuf.limit = ungetbuf.ptr = buf + UNGET_LIMIT;
-    linebuf.base = linebuf.limit = linebuf.ptr = buf + UNGET_LIMIT;
-    if (fp) {
-        file = fp;
-        userbuf.base = buf + UNGET_LIMIT + LINE_LIMIT;
-        userbuf.ptr = userbuf.limit = userbuf.base + LINE_LIMIT;
-    } else {
-        userbuf.base = (jschar *)base;
-        userbuf.limit = (jschar *)base + length;
-        userbuf.ptr = (jschar *)base;
-    }
-    currbuf = &linebuf;
+
+    userbuf.base = (jschar *)base;
+    userbuf.limit = (jschar *)base + length;
+    userbuf.ptr = (jschar *)base;
+
+    linebase = userbuf.base;
+    prevLinebase = NULL;
+
     listener = cx->debugHooks->sourceHandler;
     listenerData = cx->debugHooks->sourceHandlerData;
-    /* See getCharFillLinebuf() for an explanation of maybeEOL[]. */
+
+    /* See getChar() for an explanation of maybeEOL[]. */
     memset(maybeEOL, 0, sizeof(maybeEOL));
     maybeEOL['\n'] = true;
     maybeEOL['\r'] = true;
     maybeEOL[LINE_SEPARATOR & 0xff] = true;
     maybeEOL[PARA_SEPARATOR & 0xff] = true;
+
     /* See getTokenInternal() for an explanation of maybeStrSpecial[]. */
     memset(maybeStrSpecial, 0, sizeof(maybeStrSpecial));
     maybeStrSpecial['"'] = true;
     maybeStrSpecial['\''] = true;
+    maybeStrSpecial['\\'] = true;
     maybeStrSpecial['\n'] = true;
-    maybeStrSpecial['\\'] = true;
+    maybeStrSpecial['\r'] = true;
+    maybeStrSpecial[LINE_SEPARATOR & 0xff] = true;
+    maybeStrSpecial[PARA_SEPARATOR & 0xff] = true;
     maybeStrSpecial[EOF & 0xff] = true;
     return true;
 }
 
 void
 TokenStream::close()
 {
     if (flags & TSF_OWNFILENAME)
@@ -278,195 +259,110 @@ js_fgets(char *buf, int size, FILE *file
         }
         crflag = (c == '\r');
     }
 
     buf[i] = '\0';
     return i;
 }
 
-/*
- * Nb: This does *not* append a terminating '\0'.  Returns the number of chars
- * read from the file.
- */
-int
-TokenStream::fillUserbuf()
+/* This gets the next char, normalizing all EOL sequences to '\n' as it goes. */
+int32
+TokenStream::getChar()
 {
-    /*
-     * We avoid splitting a \r\n pair, because this makes things much easier
-     * for getChar().  To do this, we only try to fill userbuf up with
-     * LINE_LIMIT-1 chars.  Once we've reached that number, if the last one is
-     * \r then we check if the following one is \n;  if so we get it too,
-     * knowing that we have space for it.
-     */
-    jschar *buf = userbuf.base;
-    int n = LINE_LIMIT - 1;     /* reserve space for \n following a \r */
-    JS_ASSERT(n > 0);
-    int i;
-    i = 0;
-    while (true) {
-        int c = fast_getc(file);
-        if (c == EOF)
-            break;
-        buf[i] = (jschar) (unsigned char) c;
-        i++;
-
-        if (i == n) {
-            if (buf[i - 1] == '\r') {
-                /* Look for a following \n.  We know we have space in buf for it. */
-                c = fast_getc(file);
-                if (c == EOF)
-                    break;
-                if (c == '\n') {
-                    buf[i] = (jschar) (unsigned char) c;
-                    i++;
-                    break;
-                }
-                ungetc(c, file);    /* \r wasn't followed by \n, unget */
-            }
-            break;
-        }
-    }
-    return i;
-}
-
-int32
-TokenStream::getCharFillLinebuf()
-{
-    ptrdiff_t ulen = userbuf.limit - userbuf.ptr;
-    if (ulen <= 0) {
-        if (!file) {
-            flags |= TSF_EOF;
-            return EOF;
-        }
-
-        /* Fill userbuf so that \r and \r\n convert to \n. */
-        ulen = fillUserbuf();
-        JS_ASSERT(ulen >= 0);
-        if (ulen == 0) {
-            flags |= TSF_EOF;
-            return EOF;
-        }
-        userbuf.limit = userbuf.base + ulen;
-        userbuf.ptr = userbuf.base;
-    }
-    if (listener)
-        listener(filename, lineno, userbuf.ptr, ulen, &listenerTSData, listenerData);
-
-    /*
-     * Copy from userbuf to linebuf.  Stop when any of these happen:
-     * (a) we reach the end of userbuf;
-     * (b) we reach the end of linebuf;
-     * (c) we hit an EOL.
-     *
-     * "EOL" means any of: \r, \n, \r\n, or the Unicode line and paragraph
-     * separators.
-     */
-    jschar *from = userbuf.ptr;
-    jschar *to = linebuf.base;
-
-    int llenAdjust = 0;
-    int limit = JS_MIN(size_t(ulen), LINE_LIMIT);
-    int i = 0;
-    while (i < limit) {
-        /* Copy the jschar from userbuf to linebuf. */
-        jschar d = to[i] = from[i];
-        i++;
+    int32 c;
+    if (JS_LIKELY(userbuf.ptr < userbuf.limit)) {
+        c = *userbuf.ptr++;
 
         /*
-         * Normalize the copied jschar if it was a newline.  We need to detect
-         * any of these four characters:  '\n' (0x000a), '\r' (0x000d),
+         * Normalize the jschar if it was a newline.  We need to detect any of
+         * these four characters:  '\n' (0x000a), '\r' (0x000d),
          * LINE_SEPARATOR (0x2028), PARA_SEPARATOR (0x2029).  Testing for each
          * one in turn is slow, so we use a single probabilistic check, and if
          * that succeeds, test for them individually.
          *
          * We use the bottom 8 bits to index into a lookup table, succeeding
          * when d&0xff is 0xa, 0xd, 0x28 or 0x29.  Among ASCII chars (which
          * are by the far the most common) this gives false positives for '('
          * (0x0028) and ')' (0x0029).  We could avoid those by incorporating
          * the 13th bit of d into the lookup, but that requires extra shifting
          * and masking and isn't worthwhile.  See TokenStream::init() for the
          * initialization of the relevant entries in the table.
          */
-        if (maybeEOL[d & 0xff]) {
-            if (d == '\n') {
-                break;
+        if (JS_UNLIKELY(maybeEOL[c & 0xff])) {
+            if (c == '\n')
+                goto eol;
+            if (c == '\r') {
+                if (userbuf.ptr < userbuf.limit && *userbuf.ptr == '\n') {
+                    /* a \r\n sequence: treat as a single EOL, skip over the \n */
+                    userbuf.ptr++;
+                }
+                goto eol;
             }
-
-            if (d == '\r') {
-                to[i - 1] = '\n';       /* overwrite with '\n' */
-                if (i < ulen && from[i] == '\n') {
-                    i++;                /* skip over '\n' */
-                    llenAdjust = -1;
-                }
-                break;
-            }
-
-            if (d == LINE_SEPARATOR || d == PARA_SEPARATOR) {
-                to[i - 1] = '\n';       /* overwrite with '\n' */
-                break;
-            }
+            if (c == LINE_SEPARATOR || c == PARA_SEPARATOR)
+                goto eol;
         }
+        return c;
     }
-    
-    /* At this point 'i' is the index one past the last char copied. */
-    ulen = i;
-    userbuf.ptr += ulen;
+
+    flags |= TSF_EOF;
+    return EOF;
 
-    /* Reset linebuf based on normalized length. */
-    linebuf.ptr = linebuf.base;
-    linebuf.limit = linebuf.base + ulen + llenAdjust;
-
-    /* Update position of linebuf within physical userbuf line. */
-    linepos = lineposNext;
-    if (linebuf.limit[-1] == '\n')
-        lineposNext = 0;
-    else
-        lineposNext += ulen;
-
-    return *linebuf.ptr++;
+  eol:
+    prevLinebase = linebase;
+    linebase = userbuf.ptr;
+    lineno++;
+    return '\n';
 }
 
 /*
- * This gets the next char, normalizing all EOL sequences to '\n' as it goes.
+ * This gets the next char. It does nothing special with EOL sequences, not
+ * even updating the line counters.
  */
 int32
-TokenStream::getCharSlowCase()
+TokenStream::getCharIgnoreEOL()
 {
-    int32 c;
-    if (currbuf->ptr == currbuf->limit - 1) {
-        /* Last char of currbuf.  Switch to linebuf if we're in ungetbuf. */
-        c = *currbuf->ptr++;
-        if (currbuf == &ungetbuf)
-            currbuf = &linebuf;
+    if (JS_LIKELY(userbuf.ptr < userbuf.limit))
+        return *userbuf.ptr++;
 
-    } else {
-        /* One past the last char of currbuf;  can only happen for linebuf. */
-        JS_ASSERT(currbuf->ptr == currbuf->limit);
-        JS_ASSERT(currbuf == &linebuf);
-        c = getCharFillLinebuf();
-    }
-    if (c == '\n')
-        lineno++;
-    return c;
+    flags |= TSF_EOF;
+    return EOF;
 }
 
 void
 TokenStream::ungetChar(int32 c)
 {
     if (c == EOF)
         return;
-    JS_ASSERT(ungetbuf.ptr >= ungetbuf.base);
+    JS_ASSERT(userbuf.ptr > userbuf.base);
+    userbuf.ptr--;
     if (c == '\n') {
-        /* We can only unget one '\n', and it must be the first ungotten char. */
-        JS_ASSERT(ungetbuf.ptr == ungetbuf.limit);
+#ifdef DEBUG
+        int32 c2 = *userbuf.ptr;
+        JS_ASSERT(c2 == '\n' || c2 == '\r' || c2 == LINE_SEPARATOR || c2 == PARA_SEPARATOR);
+#endif
+        if (userbuf.ptr > userbuf.base && *(userbuf.ptr - 1) == '\r')
+            userbuf.ptr--;          /* also unget the \r in a \r\n sequence */
+        JS_ASSERT(prevLinebase);    /* we should never get more than one EOL char */
+        linebase = prevLinebase;
+        prevLinebase = NULL;
         lineno--;
+    } else {
+        JS_ASSERT(*userbuf.ptr == c);
     }
-    *(--ungetbuf.ptr) = (jschar)c;
-    currbuf = &ungetbuf;
+}
+
+void
+TokenStream::ungetCharIgnoreEOL(int32 c)
+{
+    JS_ASSERT(c == '\n' || c == '\r' || c == LINE_SEPARATOR || c == PARA_SEPARATOR || c == EOF);
+    if (c == EOF)
+        return;
+    JS_ASSERT(userbuf.ptr > userbuf.base);
+    userbuf.ptr--;
 }
 
 /*
  * Peek n chars ahead into ts.  Return true if n chars were read, false if
  * there weren't enough characters in the input stream.  This function cannot
  * be used to peek into or past a newline.
  */
 JSBool
@@ -485,33 +381,58 @@ TokenStream::peekChars(intN n, jschar *c
         }
         cp[i] = (jschar)c;
     }
     for (j = i - 1; j >= 0; j--)
         ungetChar(cp[j]);
     return i == n;
 }
 
+jschar *
+TokenStream::findEOL()
+{
+    TokenBuf tmpUserbuf = userbuf;
+    jschar *tmpLinebase = linebase;
+    jschar *tmpPrevLinebase = prevLinebase;
+    uintN tmpFlags = flags;
+    uintN tmpLineno = lineno;
+
+    while (true) {
+        int32 c = getChar();
+        if (c == '\n' || c == EOF)
+            break;
+    }
+    jschar *linelimit = userbuf.ptr;
+
+    /* Need to restore everything changed by getChar(). */
+    userbuf = tmpUserbuf;
+    linebase = tmpLinebase;
+    prevLinebase = tmpPrevLinebase;
+    flags = tmpFlags;
+    lineno = tmpLineno;
+
+    return linelimit;
+}
+
 bool
 TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber,
                                         va_list ap)
 {
     JSErrorReport report;
     char *message;
     size_t linelength;
     jschar *linechars;
+    jschar *linelimit;
     char *linebytes;
     bool warning;
     JSBool ok;
     TokenPos *tp;
     uintN index, i;
     JSErrorReporter onError;
 
-    JS_ASSERT(linebuf.limit <= linebuf.base + LINE_LIMIT);
-
     if (JSREPORT_IS_STRICT(flags) && !JS_HAS_STRICT_OPTION(cx))
         return JS_TRUE;
 
     warning = JSREPORT_IS_WARNING(flags);
     if (warning && JS_HAS_WERROR_OPTION(cx)) {
         flags &= ~JSREPORT_WARNING;
         warning = false;
     }
@@ -539,46 +460,37 @@ TokenStream::reportCompileErrorNumberVA(
         if (report.lineno != lineno)
             goto report;
         tp = &pn->pn_pos;
     } else {
         /* Point to the current token, not the next one to get. */
         tp = &tokens[cursor].pos;
     }
     report.lineno = lineno;
-    linelength = linebuf.limit - linebuf.base;
+
+    linelimit = findEOL();
+    linelength = linelimit - linebase;
+
     linechars = (jschar *)cx->malloc((linelength + 1) * sizeof(jschar));
     if (!linechars) {
         warning = false;
         goto out;
     }
-    memcpy(linechars, linebuf.base, linelength * sizeof(jschar));
+    memcpy(linechars, linebase, linelength * sizeof(jschar));
     linechars[linelength] = 0;
     linebytes = js_DeflateString(cx, linechars, linelength);
     if (!linebytes) {
         warning = false;
         goto out;
     }
-    report.linebuf = linebytes;
+    report.linebuf = linebytes;     /* the offending source line, without final \n */
 
-    /*
-     * FIXME: What should instead happen here is that we should
-     * find error-tokens in userbuf, if !file.  That will
-     * allow us to deliver a more helpful error message, which
-     * includes all or part of the bad string or bad token.  The
-     * code here yields something that looks truncated.
-     * See https://bugzilla.mozilla.org/show_bug.cgi?id=352970
-     */
-    index = 0;
-    if (tp->begin.lineno == tp->end.lineno) {
-        if (tp->begin.index < linepos)
-            goto report;
-
-        index = tp->begin.index - linepos;
-    }
+    index = (tp->begin.lineno == tp->end.lineno) 
+            ? tp->begin.index         /* the column number of the start of the bad token */
+            : 0;
 
     report.tokenptr = report.linebuf + index;
     report.uclinebuf = linechars;
     report.uctokenptr = report.uclinebuf + index;
 
     /*
      * If there's a runtime exception type associated with this error
      * number, set that as the pending exception.  For errors occuring at
@@ -850,18 +762,18 @@ TokenStream::getUnicodeEscape()
     return '\\';
 }
 
 Token *
 TokenStream::newToken(ptrdiff_t adjust)
 {
     cursor = (cursor + 1) & ntokensMask;
     Token *tp = &tokens[cursor];
-    tp->ptr = linebuf.ptr + adjust;
-    tp->pos.begin.index = linepos + (tp->ptr - linebuf.base) - (ungetbuf.limit - ungetbuf.ptr);
+    tp->ptr = userbuf.ptr + adjust;
+    tp->pos.begin.index = tp->ptr - linebase;
     tp->pos.begin.lineno = tp->pos.end.lineno = lineno;
     return tp;
 }
 
 static JS_ALWAYS_INLINE JSBool
 ScanAsSpace(jschar c)
 {
     /* Treat little- and big-endian BOMs as whitespace for compatibility. */
@@ -887,16 +799,20 @@ TokenStream::getTokenInternal()
     const struct keyword *kw;
 #if JS_HAS_XML_SUPPORT
     JSBool inTarget;
     size_t targetLength;
     ptrdiff_t contentIndex;
 #endif
 
 #if JS_HAS_XML_SUPPORT
+    /*
+     * Look for XML text.
+     */
+
     if (flags & TSF_XMLTEXTMODE) {
         tt = TOK_XMLSPACE;      /* veto if non-space, return TOK_XMLTEXT */
         tp = newToken(0);
         tokenbuf.clear();
         qc = (flags & TSF_XMLONLYMODE) ? '<' : '{';
 
         while ((c = getChar()) != qc && c != '<' && c != EOF) {
             if (c == '&' && qc == '<') {
@@ -921,16 +837,20 @@ TokenStream::getTokenInternal()
                 goto error;
         }
         tp->pos.end.lineno = lineno;
         tp->t_op = JSOP_STRING;
         tp->t_atom = atom;
         goto out;
     }
 
+    /*
+     * Look for XML tags.
+     */
+
     if (flags & TSF_XMLTAGMODE) {
         tp = newToken(0);
         c = getChar();
         if (JS_ISXMLSPACE(c)) {
             do {
                 c = getChar();
             } while (JS_ISXMLSPACE(c));
             ungetChar(c);
@@ -1046,36 +966,44 @@ TokenStream::getTokenInternal()
             ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_XML_CHARACTER);
             goto error;
         }
         /* NOTREACHED */
     }
 #endif /* JS_HAS_XML_SUPPORT */
 
   retry:
+    /*
+     * This gets the next non-space char and starts the token.
+     */
     do {
         c = getChar();
         if (c == '\n') {
             flags &= ~TSF_DIRTYLINE;
             if (flags & TSF_NEWLINES)
                 break;
         }
     } while (ScanAsSpace((jschar)c));
 
     tp = newToken(-1);
     if (c == EOF) {
         tt = TOK_EOF;
         goto out;
     }
 
+    /*
+     * Look for an identifier.
+     */
+
     hadUnicodeEscape = JS_FALSE;
     if (JS_ISIDSTART(c) ||
         (c == '\\' &&
          (qc = getUnicodeEscape(),
-          hadUnicodeEscape = JS_ISIDSTART(qc)))) {
+          hadUnicodeEscape = JS_ISIDSTART(qc))))
+    {
         if (hadUnicodeEscape)
             c = qc;
         tokenbuf.clear();
         for (;;) {
             if (!tokenbuf.append(c))
                 goto error;
             c = getChar();
             if (c == '\\') {
@@ -1114,16 +1042,20 @@ TokenStream::getTokenInternal()
         if (!atom)
             goto error;
         tp->t_op = JSOP_NAME;
         tp->t_atom = atom;
         tt = TOK_NAME;
         goto out;
     }
 
+    /*
+     * Look for a number.
+     */
+
     if (JS7_ISDEC(c) || (c == '.' && JS7_ISDEC(peekChar()))) {
         int radix = 10;
         tokenbuf.clear();
 
         if (c == '0') {
             c = getChar();
             if (JS_TOLOWER(c) == 'x') {
                 radix = 16;
@@ -1216,30 +1148,36 @@ TokenStream::getTokenInternal()
             if (!GetPrefixInteger(cx, tokenbuf.begin(), tokenbuf.end(), radix, &dummy, &dval))
                 goto error;
         }
         tp->t_dval = dval;
         tt = TOK_NUMBER;
         goto out;
     }
 
+    /*
+     * Look for a string.
+     */
+
     if (c == '"' || c == '\'') {
         qc = c;
         tokenbuf.clear();
         while (true) {
-            c = getChar();
             /*
-             * We need to detect any of these four chars:  " or ', \n, \\,
-             * EOF.  We use maybeStrSpecial[] in a manner similar to
-             * maybeEOL[], see above.
+             * We need to detect any of these chars:  " or ', \n (or its
+             * equivalents), \\, EOF.  We use maybeStrSpecial[] in a manner
+             * similar to maybeEOL[], see above.  Because we detect EOL
+             * sequences here and put them back immediately, we can use
+             * getCharIgnoreEOL().
              */
+            c = getCharIgnoreEOL();
             if (maybeStrSpecial[c & 0xff]) {
-                if (c == qc) {
+                if (c == qc)
                     break;
-                } else if (c == '\\') {
+                if (c == '\\') {
                     switch (c = getChar()) {
                       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 'v': c = '\v'; break;
 
@@ -1289,18 +1227,20 @@ TokenStream::getTokenInternal()
                                 skipChars(2);
                             }
                         } else if (c == '\n') {
                             /* ECMA follows C by removing escaped newlines. */
                             continue;
                         }
                         break;
                     }
-                } else if (c == '\n' || c == EOF) {
-                    ungetChar(c);
+                } else if (c == '\n' || c == '\r' || c == LINE_SEPARATOR || c == PARA_SEPARATOR ||
+                           c == EOF)
+                {
+                    ungetCharIgnoreEOL(c);
                     ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR,
                                              JSMSG_UNTERMINATED_STRING);
                     goto error;
                 }
             }
             if (!tokenbuf.append(c))
                 goto error;
         }
@@ -1309,16 +1249,20 @@ TokenStream::getTokenInternal()
             goto error;
         tp->pos.end.lineno = lineno;
         tp->t_op = JSOP_STRING;
         tp->t_atom = atom;
         tt = TOK_STRING;
         goto out;
     }
 
+    /*
+     * This handles everything else.
+     */
+
     switch (c) {
       case '\n': tt = TOK_EOL; goto eol_out;
       case ';':  tt = TOK_SEMI; break;
       case '[':  tt = TOK_LB; break;
       case ']':  tt = TOK_RB; break;
       case '{':  tt = TOK_LC; break;
       case '}':  tt = TOK_RC; break;
       case '(':  tt = TOK_LP; break;
@@ -1844,17 +1788,17 @@ TokenStream::getTokenInternal()
     }
 
   out:
     JS_ASSERT(tt != TOK_EOL);
     flags |= TSF_DIRTYLINE;
 
   eol_out:
     JS_ASSERT(tt < TOK_LIMIT);
-    tp->pos.end.index = linepos + (linebuf.ptr - linebuf.base) - (ungetbuf.limit - ungetbuf.ptr);
+    tp->pos.end.index = userbuf.ptr - linebase;
     tp->type = tt;
     return tt;
 
   error:
     tt = TOK_ERROR;
     flags |= TSF_ERROR;
     goto out;
 }
--- a/js/src/jsscan.h
+++ b/js/src/jsscan.h
@@ -287,21 +287,16 @@ enum TokenStreamFlags
 };
 
 #define t_op            u.s.op
 #define t_reflags       u.reflags
 #define t_atom          u.s.atom
 #define t_atom2         u.p.atom2
 #define t_dval          u.dval
 
-static const size_t LINE_LIMIT = 1024; /* logical line buffer size limit
-                                          -- physical line length is unlimited */
-static const size_t UNGET_LIMIT = 6;   /* maximum number of chars to unget at once
-                                          -- for \uXXXX lookahead */
-
 class TokenStream
 {
     static const size_t ntokens = 4;                /* 1 current + 2 lookahead, rounded
                                                        to power of 2 to avoid divmod by 3 */
     static const uintN ntokensMask = ntokens - 1;
 
   public:
     /*
@@ -312,20 +307,20 @@ class TokenStream
      *
      * This class uses JSContext.tempPool to allocate internal buffers. The
      * caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE
      * after calling |close|.
      */
     TokenStream(JSContext *);
 
     /*
-     * Create a new token stream, either from an input buffer or from a file.
-     * Return false on file-open or memory-allocation failure.
+     * Create a new token stream from an input buffer.
+     * Return false on memory-allocation failure.
      */
-    bool init(JSVersion version, const jschar *base, size_t length, FILE *fp,
+    bool init(JSVersion version, const jschar *base, size_t length,
               const char *filename, uintN lineno);
     void close();
     ~TokenStream() {}
 
     /* Accessors. */
     JSContext *getContext() const { return cx; }
     bool onCurrentLine(const TokenPos &pos) const { return lineno == pos.end.lineno; }
     const Token &currentToken() const { return tokens[cursor]; }
@@ -378,18 +373,17 @@ class TokenStream
             flags &= ~flag;
     }
 
   public:
     /*
      * Get the next token from the stream, make it the current token, and
      * return its kind.
      */
-    TokenKind getToken(uintN withFlags = 0) {
-        Flagger flagger(this, withFlags);
+    TokenKind getToken() {
         /* Check for a pushed-back token resulting from mismatching lookahead. */
         while (lookahead != 0) {
             JS_ASSERT(!(flags & TSF_XMLTEXTMODE));
             lookahead--;
             cursor = (cursor + 1) & ntokensMask;
             TokenKind tt = currentToken().type;
             JS_ASSERT(!(flags & TSF_NEWLINES));
             if (tt != TOK_EOL)
@@ -398,16 +392,22 @@ class TokenStream
 
         /* If there was a fatal error, keep returning TOK_ERROR. */
         if (flags & TSF_ERROR)
             return TOK_ERROR;
 
         return getTokenInternal();
     }
 
+    /* Similar, but also sets flags. */
+    TokenKind getToken(uintN withFlags) {
+        Flagger flagger(this, withFlags);
+        return getToken();
+    }
+
     /*
      * Push the last scanned token back into the stream.
      */
     void ungetToken() {
         JS_ASSERT(lookahead < ntokensMask);
         lookahead++;
         cursor = (cursor - 1) & ntokensMask;
     }
@@ -447,38 +447,26 @@ class TokenStream
   private:
     typedef struct TokenBuf {
         jschar              *base;      /* base of line or stream buffer */
         jschar              *limit;     /* limit for quick bounds check */
         jschar              *ptr;       /* next char to get, or slot to use */
     } TokenBuf;
 
     TokenKind getTokenInternal();     /* doesn't check for pushback or error flag. */
-    int fillUserbuf();
-    int32 getCharFillLinebuf();
 
-    /* This gets the next char, normalizing all EOL sequences to '\n' as it goes. */
-    JS_ALWAYS_INLINE int32 getChar() {
-        int32 c;
-        if (currbuf->ptr < currbuf->limit - 1) {
-            /* Not yet the last char of currbuf, so it can't be a newline.  Just get it. */
-            c = *currbuf->ptr++;
-            JS_ASSERT(c != '\n');
-        } else {
-            c = getCharSlowCase();
-        }
-        return c;
-    }
-
-    int32 getCharSlowCase();
+    int32 getChar();
+    int32 getCharIgnoreEOL();
     void ungetChar(int32 c);
+    void ungetCharIgnoreEOL(int32 c);
     Token *newToken(ptrdiff_t adjust);
     int32 getUnicodeEscape();
     JSBool peekChars(intN n, jschar *cp);
     JSBool getXMLEntity();
+    jschar *findEOL();
 
     JSBool matchChar(int32 expect) {
         int32 c = getChar();
         if (c == expect)
             return JS_TRUE;
         ungetChar(c);
         return JS_FALSE;
     }
@@ -495,24 +483,20 @@ class TokenStream
     }
 
     JSContext           * const cx;
     Token               tokens[ntokens];/* circular token buffer */
     uintN               cursor;         /* index of last parsed token */
     uintN               lookahead;      /* count of lookahead tokens */
     uintN               lineno;         /* current line number */
     uintN               flags;          /* flags -- see above */
-    uint32              linepos;        /* linebuf offset in physical line */
-    uint32              lineposNext;    /* the next value of linepos */
-    TokenBuf            linebuf;        /* line buffer for diagnostics */
-    TokenBuf            userbuf;        /* user input buffer if !file */
-    TokenBuf            ungetbuf;       /* buffer for ungetChar */
-    TokenBuf            *currbuf;       /* the buffer getChar is currently using */
+    jschar              *linebase;      /* start of current line;  points into userbuf */
+    jschar              *prevLinebase;  /* start of previous line;  NULL if on the first line */
+    TokenBuf            userbuf;        /* user input buffer */
     const char          *filename;      /* input filename or null */
-    FILE                *file;          /* stdio stream if reading from file */
     JSSourceHandler     listener;       /* callback for source; eg debugger */
     void                *listenerData;  /* listener 'this' data */
     void                *listenerTSData;/* listener data for this TokenStream */
     JSCharBuffer        tokenbuf;       /* current token string buffer */
     bool                maybeEOL[256];  /* probabilistic EOL lookup table */
     bool                maybeStrSpecial[256];/* speeds up string scanning */
     JSVersion           version;        /* cached version number for scan */
 };
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1147,18 +1147,34 @@ JSScript::NewScriptFromCG(JSContext *cx,
                      * the emitter performs useless expression elimination.
                      */
                     goto skip_empty;
                 }
                 fun->freezeLocalNames(cx);
                 fun->u.i.script = empty;
             }
 
-            JS_RUNTIME_METER(cx->runtime, liveEmptyScripts);
-            JS_RUNTIME_METER(cx->runtime, totalEmptyScripts);
+#ifdef DEBUG
+            {
+                jsrefcount newEmptyLive = JS_RUNTIME_METER(cx->runtime, liveEmptyScripts);
+                jsrefcount newLive = cx->runtime->liveScripts;
+                jsrefcount newTotal =
+                    JS_RUNTIME_METER(cx->runtime, totalEmptyScripts) + cx->runtime->totalScripts;
+
+                jsrefcount oldHigh = cx->runtime->highWaterLiveScripts;
+                if (newEmptyLive + newLive > oldHigh) {
+                    JS_ATOMIC_SET(&cx->runtime->highWaterLiveScripts, newEmptyLive + newLive);
+                    if (getenv("JS_DUMP_LIVE_SCRIPTS")) {
+                        fprintf(stderr, "high water script count: %d empty, %d not (total %d)\n",
+                                newEmptyLive, newLive, newTotal);
+                    }
+                }
+            }
+#endif
+
             return empty;
         }
     }
 
   skip_empty:
     CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
     uint16 nClosedArgs = uint16(cg->closedArgs.length());
     JS_ASSERT(nClosedArgs == cg->closedArgs.length());
@@ -1263,18 +1279,33 @@ JSScript::NewScriptFromCG(JSContext *cx,
         script->owner = NULL;
 #endif
         if (cg->flags & TCF_FUN_HEAVYWEIGHT)
             fun->flags |= JSFUN_HEAVYWEIGHT;
     }
 
     /* Tell the debugger about this compiled script. */
     js_CallNewScriptHook(cx, script, fun);
-    JS_RUNTIME_METER(cx->runtime, liveScripts);
-    JS_RUNTIME_METER(cx->runtime, totalScripts);
+#ifdef DEBUG
+    {
+        jsrefcount newLive = JS_RUNTIME_METER(cx->runtime, liveScripts);
+        jsrefcount newEmptyLive = cx->runtime->liveEmptyScripts;
+        jsrefcount newTotal =
+            JS_RUNTIME_METER(cx->runtime, totalScripts) + cx->runtime->totalEmptyScripts;
+        jsrefcount oldHigh = cx->runtime->highWaterLiveScripts;
+        if (newEmptyLive + newLive > oldHigh) {
+            JS_ATOMIC_SET(&cx->runtime->highWaterLiveScripts, newEmptyLive + newLive);
+            if (getenv("JS_DUMP_LIVE_SCRIPTS")) {
+                fprintf(stderr, "high water script count: %d empty, %d not (total %d)\n",
+                        newEmptyLive, newLive, newTotal);
+            }
+        }
+    }
+#endif
+
     return script;
 
 bad:
     js_DestroyScript(cx, script);
     return NULL;
 }
 
 JS_FRIEND_API(void)
@@ -1307,16 +1338,20 @@ js_CallDestroyScriptHook(JSContext *cx, 
 static void
 DestroyScript(JSContext *cx, JSScript *script, JSThreadData *data)
 {
     if (script == JSScript::emptyScript()) {
         JS_RUNTIME_UNMETER(cx->runtime, liveEmptyScripts);
         return;
     }
 
+#ifdef DEBUG
+    JS_RUNTIME_UNMETER(cx->runtime, liveScripts);
+#endif
+
     js_CallDestroyScriptHook(cx, script);
     JS_ClearScriptTraps(cx, script);
 
     if (script->principals)
         JSPRINCIPALS_DROP(cx, script->principals);
 
     if (JS_GSN_CACHE(cx).code == script->code)
         JS_PURGE_GSN_CACHE(cx);
@@ -1375,18 +1410,16 @@ DestroyScript(JSContext *cx, JSScript *s
 #endif
 
 #if defined(JS_METHODJIT)
     mjit::ReleaseScriptCode(cx, script);
 #endif
     JS_REMOVE_LINK(&script->links);
 
     cx->free(script);
-
-    JS_RUNTIME_UNMETER(cx->runtime, liveScripts);
 }
 
 void
 js_DestroyScript(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(!cx->runtime->gcRunning);
     DestroyScript(cx, script, JS_THREAD_DATA(cx));
 }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -3249,22 +3249,16 @@ const JSString JSString::length2StringTa
 #ifdef __SUNPRO_CC
 #pragma pack(0)
 #else
 #pragma pack(pop)
 #endif
 
 #undef R
 
-#define R(c) FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3f), 0x00
-
-const char JSString::deflatedLength2StringTable[] = { R12(0) };
-
-#undef R
-
 /*
  * Declare int strings. Only int strings from 100 to 255 actually have to be
  * generated, since the rest are either unit strings or length-2 strings. To
  * avoid the runtime cost of figuring out where to look for the string for a
  * particular integer, we precompute a table of JSString*s which refer to the
  * correct location of the int string.
  */
 #define R(c) {                                                                \
@@ -3305,48 +3299,26 @@ const JSString *const JSString::intStrin
 #undef R
 
 #ifdef __SUNPRO_CC
 #pragma pack(0)
 #else
 #pragma pack(pop)
 #endif
 
-#define R(c) ((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00
-
-const char JSString::deflatedIntStringTable[] = {
-    R7(100), /* 100 through 227 */
-    R4(100 + (1 << 7)), /* 228 through 243 */
-    R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
-    R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
-};
-
-#undef R
 #undef R2
 #undef R4
 #undef R6
 #undef R8
 #undef R10
 #undef R12
 
 #undef R3
 #undef R7
 
-/* Static table for common UTF8 encoding */
-#define U8(c)   char(((c) >> 6) | 0xc0), char(((c) & 0x3f) | 0x80), 0
-#define U(c)    U8(c), U8(c+1), U8(c+2), U8(c+3), U8(c+4), U8(c+5), U8(c+6), U8(c+7)
-
-const char JSString::deflatedUnitStringTable[] = {
-    U(0x80), U(0x88), U(0x90), U(0x98), U(0xa0), U(0xa8), U(0xb0), U(0xb8),
-    U(0xc0), U(0xc8), U(0xd0), U(0xd8), U(0xe0), U(0xe8), U(0xf0), U(0xf8)
-};
-
-#undef U
-#undef U8
-
 JSBool
 js_String(JSContext *cx, uintN argc, Value *vp)
 {
     Value *argv = vp + 2;
 
     JSString *str;
     if (argc > 0) {
         str = js_ValueToString(cx, argv[0]);
@@ -3967,17 +3939,17 @@ js_InflateString(JSContext *cx, const ch
      * For compatibility with callers of JS_DecodeBytes we must zero lengthp
      * on errors.
      */
     *lengthp = 0;
     return NULL;
 }
 
 /*
- * May be called with null cx by js_GetStringBytes, see below.
+ * May be called with null cx.
  */
 char *
 js_DeflateString(JSContext *cx, const jschar *chars, size_t nchars)
 {
     size_t nbytes, i;
     char *bytes;
 #ifdef DEBUG
     JSBool ok;
@@ -4012,17 +3984,17 @@ js_GetDeflatedStringLength(JSContext *cx
 {
     if (!js_CStringsAreUTF8)
         return nchars;
 
     return js_GetDeflatedUTF8StringLength(cx, chars, nchars);
 }
 
 /*
- * May be called with null cx through js_GetStringBytes, see below.
+ * May be called with null cx through public API, see below.
  */
 size_t
 js_GetDeflatedUTF8StringLength(JSContext *cx, const jschar *chars, size_t nchars)
 {
     size_t nbytes;
     const jschar *end;
     uintN c, c2;
     char buffer[10];
@@ -4255,162 +4227,16 @@ bufferTooSmall:
     *dstlenp = (origDstlen - dstlen);
     if (cx) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_BUFFER_TOO_SMALL);
     }
     return JS_FALSE;
 }
 
-namespace js {
-
-DeflatedStringCache::DeflatedStringCache()
-{
-#ifdef JS_THREADSAFE
-    lock = NULL;
-#endif
-}
-
-bool
-DeflatedStringCache::init()
-{
-#ifdef JS_THREADSAFE
-    JS_ASSERT(!lock);
-    lock = JS_NEW_LOCK();
-    if (!lock)
-        return false;
-#endif
-
-    /*
-     * Make room for 2K deflated strings that a typical browser session
-     * creates.
-     */
-    return map.init(2048);
-}
-
-DeflatedStringCache::~DeflatedStringCache()
-{
-#ifdef JS_THREADSAFE
-    if (lock)
-        JS_DESTROY_LOCK(lock);
-#endif
-}
-
-void
-DeflatedStringCache::sweep(JSContext *cx)
-{
-    /*
-     * We must take a lock even during the GC as JS_GetFunctionName can be
-     * called outside the request.
-     */
-    JS_ACQUIRE_LOCK(lock);
-
-    for (Map::Enum e(map); !e.empty(); e.popFront()) {
-        JSString *str = e.front().key;
-        if (IsAboutToBeFinalized(str)) {
-            char *bytes = e.front().value;
-            e.removeFront();
-
-            /*
-             * We cannot use cx->free here as bytes may come from the
-             * embedding that calls JS_NewString(cx, bytes, length). Those
-             * bytes may not be allocated via js_malloc and may not have
-             * space for the background free list.
-             */
-            js_free(bytes);
-        }
-    }
-
-    JS_RELEASE_LOCK(lock);
-}
-
-char *
-DeflatedStringCache::getBytes(JSString *str)
-{
-    JS_ACQUIRE_LOCK(lock);
-    Map::AddPtr p = map.lookupForAdd(str);
-    char *bytes = p ? p->value : NULL;
-    JS_RELEASE_LOCK(lock);
-
-    if (bytes)
-        return bytes;
-
-    bytes = js_DeflateString(NULL, str->chars(), str->length());
-    if (!bytes)
-        return NULL;
-
-    /*
-     * In the single-threaded case we use the add method as js_DeflateString
-     * cannot mutate the map. In particular, it cannot run the GC that may
-     * delete entries from the map. But the JS_THREADSAFE version requires to
-     * deal with other threads adding the entries to the map.
-     */
-    char *bytesToFree = NULL;
-    JSBool ok;
-#ifdef JS_THREADSAFE
-    JS_ACQUIRE_LOCK(lock);
-    ok = map.relookupOrAdd(p, str, bytes);
-    if (ok && p->value != bytes) {
-        /* Some other thread has asked for str bytes .*/
-        JS_ASSERT(!strcmp(p->value, bytes));
-        bytesToFree = bytes;
-        bytes = p->value;
-    }
-    JS_RELEASE_LOCK(lock);
-#else  /* !JS_THREADSAFE */
-    ok = map.add(p, str, bytes);
-#endif
-    if (!ok) {
-        bytesToFree = bytes;
-        bytes = NULL;
-    }
-
-    if (bytesToFree)
-        js_free(bytesToFree);
-    return bytes;
-}
-
-} /* namespace js */
-
-const char *
-js_GetStringBytes(JSAtom *atom)
-{
-    JSString *str = ATOM_TO_STRING(atom);
-    if (JSString::isUnitString(str)) {
-        char *bytes;
-#ifdef IS_LITTLE_ENDIAN
-        /* Unit string data is {c, 0, 0, 0} so we can just cast. */
-        bytes = (char *)str->chars();
-#else
-        /* Unit string data is {0, c, 0, 0} so we can point into the middle. */
-        bytes = (char *)str->chars() + 1;
-#endif
-        return ((*bytes & 0x80) && js_CStringsAreUTF8)
-               ? JSString::deflatedUnitStringTable + ((*bytes & 0x7f) * 3)
-               : bytes;
-    }
-
-    /*
-     * We must burn some space on deflated int strings and length-2 strings
-     * to preserve static allocation (which is to say, JSRuntime independence).
-     */
-    if (JSString::isLength2String(str))
-        return JSString::deflatedLength2StringTable + ((str - JSString::length2StringTable) * 3);
-
-    if (JSString::isHundredString(str)) {
-        /*
-         * We handled the 1 and 2-digit number cases already, so we know that
-         * str is between 100 and 255.
-         */
-        return JSString::deflatedIntStringTable + ((str - JSString::hundredStringTable) * 4);
-    }
-
-    return GetGCThingRuntime(str)->deflatedStringCache->getBytes(str);
-}
-
 /*
  * From java.lang.Character.java:
  *
  * The character properties are currently encoded into 32 bits in the
  * following manner:
  *
  * 10 bits      signed offset used for converting case
  *  1 bit       if 1, adding the signed offset converts the character to
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -265,35 +265,41 @@ struct JSString {
         end = length() + (chars = this->chars());
     }
 
     JS_ALWAYS_INLINE jschar *inlineStorage() {
         JS_ASSERT(isFlat());
         return mInlineStorage;
     }
 
-    /* Specific flat string initializer and accessor methods. */
-    JS_ALWAYS_INLINE void initFlat(jschar *chars, size_t length) {
+    JS_ALWAYS_INLINE void initFlatNotTerminated(jschar *chars, size_t length) {
         JS_ASSERT(length <= MAX_LENGTH);
         JS_ASSERT(!isStatic(this));
         e.mBase = NULL;
         e.mCapacity = 0;
         mLengthAndFlags = (length << FLAGS_LENGTH_SHIFT) | FLAT;
         mChars = chars;
     }
 
+    /* Specific flat string initializer and accessor methods. */
+    JS_ALWAYS_INLINE void initFlat(jschar *chars, size_t length) {
+        initFlatNotTerminated(chars, length);
+        JS_ASSERT(chars[length] == jschar(0));
+    }
+
     JS_ALWAYS_INLINE void initShortString(jschar *chars, size_t length) {
         JS_ASSERT(length <= MAX_LENGTH);
         JS_ASSERT(!isStatic(this));
         mLengthAndFlags = (length << FLAGS_LENGTH_SHIFT) | FLAT;
         mChars = chars;
     }
 
     JS_ALWAYS_INLINE void initFlatExtensible(jschar *chars, size_t length, size_t cap) {
         JS_ASSERT(length <= MAX_LENGTH);
+        JS_ASSERT(chars[length] == jschar(0));
         JS_ASSERT(!isStatic(this));
         e.mBase = NULL;
         e.mCapacity = cap;
         mLengthAndFlags = (length << FLAGS_LENGTH_SHIFT) | FLAT | EXTENSIBLE;
         mChars = chars;
     }
 
     JS_ALWAYS_INLINE jschar *flatChars() const {
@@ -509,19 +515,16 @@ struct JSString {
     static const JSString unitStringTable[];
     static const JSString length2StringTable[];
     static const JSString hundredStringTable[];
     /*
      * Since int strings can be unit strings, length-2 strings, or hundred
      * strings, we keep a table to map from integer to the correct string.
      */
     static const JSString *const intStringTable[];
-    static const char deflatedIntStringTable[];
-    static const char deflatedUnitStringTable[];
-    static const char deflatedLength2StringTable[];
 
     static JSString *unitString(jschar c);
     static JSString *getUnitString(JSContext *cx, JSString *str, size_t index);
     static JSString *length2String(jschar c1, jschar c2);
     static JSString *length2String(uint32 i);
     static JSString *intString(jsint i);
 
     static JSString *lookupStaticString(const jschar *chars, size_t length);
@@ -1141,23 +1144,16 @@ js_DeflateStringToBuffer(JSContext *cx, 
 
 /*
  * Same as js_DeflateStringToBuffer, but always treats 'bytes' as UTF-8.
  */
 extern JSBool
 js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *chars,
                              size_t charsLength, char *bytes, size_t *length);
 
-/*
- * Find or create a deflated string cache entry for str that contains its
- * characters chopped from Unicode code points into bytes.
- */
-extern const char *
-js_GetStringBytes(JSAtom *atom);
-
 /* Export a few natives and a helper to other files in SpiderMonkey. */
 extern JSBool
 js_str_escape(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv,
               js::Value *rval);
 
 /*
  * The String.prototype.replace fast-native entry point is exported for joined
  * function optimization in js{interp,tracer}.cpp.
@@ -1218,59 +1214,9 @@ FileEscapedString(FILE *fp, JSString *st
     return PutEscapedStringImpl(NULL, 0, fp, str, quote) != size_t(-1);
 }
 
 } /* namespace js */
 
 extern JSBool
 js_String(JSContext *cx, uintN argc, js::Value *vp);
 
-namespace js {
-
-class DeflatedStringCache {
-  public:
-    DeflatedStringCache();
-    bool init();
-    ~DeflatedStringCache();
-
-    void sweep(JSContext *cx);
-
-  private:
-    struct StringPtrHasher
-    {
-        typedef JSString *Lookup;
-
-        static HashNumber hash(JSString *str) {
-            /*
-             * We hash only GC-allocated Strings. They are aligned on
-             * sizeof(JSString) boundary so we can improve hashing by stripping
-             * initial zeros.
-             */
-            const jsuword ALIGN_LOG = tl::FloorLog2<sizeof(JSString)>::result;
-            JS_STATIC_ASSERT(sizeof(JSString) == (size_t(1) << ALIGN_LOG));
-
-            jsuword ptr = reinterpret_cast<jsuword>(str);
-            jsuword key = ptr >> ALIGN_LOG;
-            JS_ASSERT((key << ALIGN_LOG) == ptr);
-            return HashNumber(key);
-        }
-
-        static bool match(JSString *s1, JSString *s2) {
-            return s1 == s2;
-        }
-    };
-
-    typedef HashMap<JSString *, char *, StringPtrHasher, SystemAllocPolicy> Map;
-
-    char *getBytes(JSString *str);
-
-    friend const char *
-    ::js_GetStringBytes(JSAtom *atom);
-
-    Map                 map;
-#ifdef JS_THREADSAFE
-    JSLock              *lock;
-#endif
-};
-
-} /* namespace js */
-
 #endif /* jsstr_h___ */
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -1766,17 +1766,17 @@ ParseXMLSource(JSContext *cx, JSString *
                 if (*srcp == '\n')
                     --lineno;
             }
         }
     }
 
     {
         Parser parser(cx);
-        if (parser.init(chars, length, NULL, filename, lineno)) {
+        if (parser.init(chars, length, filename, lineno)) {
             JSObject *scopeChain = GetScopeChain(cx);
             if (!scopeChain)
                 return NULL;
             JSParseNode *pn = parser.parseXMLText(scopeChain, false);
             uintN flags;
             if (pn && GetXMLSettingFlags(cx, &flags)) {
                 AutoNamespaceArray namespaces(cx);
                 if (namespaces.array.setCapacity(cx, 1))
--- a/js/src/lirasm/lirasm.cpp
+++ b/js/src/lirasm/lirasm.cpp
@@ -2224,28 +2224,35 @@ Lirasm::handlePatch(LirTokenStream &in)
 }
 
 void
 usageAndQuit(const string& progname)
 {
     cout <<
         "usage: " << progname << " [options] [filename]\n"
         "Options:\n"
-        "  -h --help        print this message\n"
-        "  -v --verbose     print LIR and assembly code\n"
-        "  --execute        execute LIR\n"
-        "  --[no-]optimize  enable or disable optimization of the LIR (default=off)\n"
-        "  --random [N]     generate a random LIR block of size N (default=1000)\n"
-        "  --word-size      prints the word size (32 or 64) for this build of lirasm and exits\n"
-        "  --endianness     prints endianness (little-endian or big-endian) for this build of librasm and exits\n"
-        " i386-specific options:\n"
-        "  --sse            use SSE2 instructions\n"
-        " ARM-specific options:\n"
-        "  --arch N         generate code for ARM architecture version N (default=7)\n"
-        "  --[no]vfp        enable or disable the generation of ARM VFP code (default=on)\n"
+        "  -h --help         print this message\n"
+        "  -v --verbose      print LIR and assembly code\n"
+        "  --execute         execute LIR\n"
+        "  --[no-]optimize   enable or disable optimization of the LIR (default=off)\n"
+        "  --random [N]      generate a random LIR block of size N (default=1000)\n"
+        "\n"
+        "Build query options (these print a value for this build of lirasm and exit)\n"
+        "  --show-arch       show the architecture ('i386', 'X64', 'arm', 'ppc',\n"
+        "                    'sparc', 'mips', or 'sh4')\n"
+        "  --show-word-size  show the word size ('32' or '64')\n"
+        "  --show-endianness show the endianness ('little-endian' or 'big-endian')\n"
+        "\n"
+        "i386-specific options:\n"
+        "  --[no]sse         use SSE2 instructions (default=on)\n"
+        "\n"
+        "ARM-specific options:\n"
+        "  --arch N          use ARM architecture version N instructions (default=7)\n"
+        "  --[no]vfp         use ARM VFP instructions (default=on)\n"
+        "\n"
         ;
     exit(0);
 }
 
 void
 errMsgAndQuit(const string& progname, const string& msg)
 {
     cerr << progname << ": " << msg << endl;
@@ -2267,17 +2274,17 @@ processCmdLine(int argc, char **argv, Cm
     opts.progname = argv[0];
     opts.verbose  = false;
     opts.execute  = false;
     opts.random   = 0;
     opts.optimize = false;
 
     // Architecture-specific options.
 #if defined NANOJIT_IA32
-    bool            i386_sse = false;
+    bool            i386_sse = true;
 #elif defined NANOJIT_ARM
     unsigned int    arm_arch = 7;
     bool            arm_vfp = true;
 #endif
 
     for (int i = 1; i < argc; i++) {
         string arg = argv[i];
 
@@ -2305,46 +2312,71 @@ processCmdLine(int argc, char **argv, Cm
                         errMsgAndQuit(opts.progname, "--random argument must be greater than zero");
                     opts.random = res;          // next arg is a number, use that for the size
                     i++;
                 } else {
                     opts.random = defaultSize;  // next arg is not a number
                 }
             }
         }
-        else if (arg == "--word-size") {
+        else if (arg == "--show-arch") {
+            const char* str = 
+#if defined NANOJIT_IA32
+                "i386";
+#elif defined NANOJIT_X64
+                "X64";
+#elif defined NANOJIT_ARM
+                "arm";
+#elif defined NANOJIT_PPC
+                "ppc";
+#elif defined NANOJIT_SPARC
+                "sparc";
+#elif defined NANOJIT_MIPS
+                "mips";
+#elif defined NANOJIT_SH4
+                "sh4";
+#else
+#               error "unknown arch"
+#endif
+            cout << str << "\n";
+            exit(0);
+        }
+        else if (arg == "--show-word-size") {
             cout << sizeof(void*) * 8 << "\n";
             exit(0);
         }
-        else if (arg == "--endianness") {
+        else if (arg == "--show-endianness") {
             int32_t x = 0x01020304;
             if (*(char*)&x == 0x1) {
               cout << "big-endian" << "\n";
             } else {
               cout << "little-endian" << "\n";
             }
             exit(0);
         }
 
         // Architecture-specific flags.
 #if defined NANOJIT_IA32
         else if (arg == "--sse") {
             i386_sse = true;
         }
+        else if (arg == "--nosse") {
+            i386_sse = false;
+        }
 #elif defined NANOJIT_ARM
         else if ((arg == "--arch") && (i < argc-1)) {
             char* endptr;
             arm_arch = strtoul(argv[i+1], &endptr, 10);
             // Check that the argument was a number.
             if ('\0' == *endptr) {
                 if ((arm_arch < 4) || (arm_arch > 7)) {
-                    errMsgAndQuit(opts.progname, "Unsupported argument to --arm-arch.\n");
+                    errMsgAndQuit(opts.progname, "Unsupported argument to --arch.\n");
                 }
             } else {
-                errMsgAndQuit(opts.progname, "Unrecognized argument to --arm-arch.\n");
+                errMsgAndQuit(opts.progname, "Unrecognized argument to --arch.\n");
             }
             i++;
         } else if (arg == "--vfp") {
             arm_vfp = true;
         } else if (arg == "--novfp") {
             arm_vfp = false;
         }
 #endif
--- a/js/src/lirasm/testlirc.sh
+++ b/js/src/lirasm/testlirc.sh
@@ -8,134 +8,141 @@ LIRASM=$1
 
 TESTS_DIR=`dirname "$0"`/tests
 
 function runtest {
     local infile=$1
     local options=${2-}
 
     # Catch a request for the random tests.
-    if [[ $infile == --random* ]]
-    then
+    if [[ $infile == --random* ]] ; then
         local outfile=$TESTS_DIR/random.out
     else
         local outfile=`echo $infile | sed 's/\.in/\.out/'`
     fi
 
-    if [[ ! -e "$outfile" ]]
-    then
+    if [[ ! -e "$outfile" ]] ; then
         echo "$0: error: no out file $outfile"
         exit 1
     fi
 
     # sed used to strip extra leading zeros from exponential values 'e+00' (see bug 602786)
-    if $LIRASM $options --execute $infile | tr -d '\r' | sed -e 's/e+00*/e+0/g' > testoutput.txt && cmp -s testoutput.txt $outfile
-    then
+    if $LIRASM $options --execute $infile | tr -d '\r' | sed -e 's/e+00*/e+0/g' > testoutput.txt && cmp -s testoutput.txt $outfile ; then
         echo "TEST-PASS | lirasm | lirasm $options --execute $infile"
     else
         echo "TEST-UNEXPECTED-FAIL | lirasm | lirasm $options --execute $infile"
         echo "expected output"
         cat $outfile
         echo "actual output"
         cat testoutput.txt
         exitcode=1
     fi
 }
 
-# Tests common to all supported back-ends.
-for infile in "$TESTS_DIR"/*.in
-do
-    runtest $infile
-done
-
-# ---- Platform-specific tests and configurations. ----
+function runtests {
+    local testdir=$1
+    local options=${2-}
+    for infile in "$TESTS_DIR"/"$testdir"/*.in ; do
+        runtest $infile "$options"
+    done
+}
 
-# Tests for hardware floating-point.
-# These tests use LIR instructions which are normally removed by the soft-float
-# filter, so soft-float targets do not need to support them.
-#
-# There is no conditional check for hardfloat support as every platform appears
-# to support it. If the default for a particular platform does not support
-# hardfloat, exclude the hardfloat tests (based on something like "uname -m").
-for infile in "$TESTS_DIR"/hardfloat/*.in
-do
-    runtest $infile
-done
+if [[ $($LIRASM --show-arch 2>/dev/null) == "i386" ]] ; then
+    # i386 with SSE2.
+    runtests "."
+    runtests "hardfloat"
+    runtests "32-bit"
+    runtests "littleendian"
+    runtest "--random 1000000"
+    runtest "--random 1000000 --optimize"
+
+    # i386 without SSE2.
+    runtests "."               "--nosse"
+    runtests "hardfloat"       "--nosse"
+    runtests "32-bit"          "--nosse"
+    runtests "littleendian"    "--nosse"
+    runtest "--random 1000000" "--nosse"
 
-# 64-bit platforms
-if [[ $($LIRASM --word-size) == 64 ]]
-then
-    for infile in "$TESTS_DIR"/64-bit/*.in
-    do
-        runtest $infile
-    done
-fi
+elif [[ $($LIRASM --show-arch 2>/dev/null) == "X64" ]] ; then
+    # X64.
+    runtests "."
+    runtests "hardfloat"
+    runtests "64-bit"
+    runtests "littleendian"
+    runtest "--random 1000000"
+    runtest "--random 1000000 --optimize"
 
-# 32-bit platforms
-if [[ $($LIRASM --word-size) == 32 ]]
-then
-    for infile in "$TESTS_DIR"/32-bit/*.in
-    do
-        runtest $infile
-    done
-fi
+elif [[ $($LIRASM --show-arch 2>/dev/null) == "arm" ]] ; then
+    # ARMv7 with VFP.  We could test without VFP but such a platform seems
+    # unlikely.  ARM is bi-endian but usually configured as little-endian.
+    runtests "."
+    runtests "hardfloat"
+    runtests "32-bit"
+    runtests "littleendian"
+    runtest "--random 1000000"
+    runtest "--random 1000000" "--optimize"
 
-# little endian
-if [[ $($LIRASM --endianness 2>/dev/null) != "big-endian" ]]
-then
-    for infile in "$TESTS_DIR"/littleendian/*.in
-    do
-        runtest $infile
-    done
-fi
+    # ARMv6 with VFP.  ARMv6 without VFP doesn't seem worth testing.
+    # Random tests are reduced.
+    runtests "."              "--arch 6"
+    runtests "hardfloat"      "--arch 6"
+    runtests "32-bit"         "--arch 6"
+    runtests "littleendian"   "--arch 6"
+    runtest "--random 100000" "--arch 6"
 
-# big endian
-if [[ $($LIRASM --endianness 2>/dev/null) == "big-endian" ]]
-then
-    for infile in "$TESTS_DIR"/bigendian/*.in
-    do
-        runtest $infile
-    done
-fi
+    # ARMv5 without VFP.  ARMv5 with VFP doesn't seem worth testing.
+    # Random tests are reduced.
+    runtests "."              "--arch 5 --novfp"
+    runtests "softfloat"      "--arch 5 --novfp"
+    runtests "32-bit"         "--arch 5 --novfp"
+    runtests "littleendian"   "--arch 5 --novfp"
+    runtest "--random 100000" "--arch 5 --novfp"
 
-# ARM
-if [[ $(uname -m) == arm* ]]
-then
-    for infile in "$TESTS_DIR"/*.in
-    do
-        # Run standard tests, but set code generation for older architectures.
-        # It may also be beneficial to test ARMv6 and ARMv7 with --novfp, but such
-        # a platform seems so unlikely that it probably isn't worthwhile. It's also
-        # unlikely that it's worth testing ARMv5 with VFP.
-        runtest $infile "--arch 6"
-        runtest $infile "--arch 5 --novfp"
-    done
+elif [[ $($LIRASM --show-arch 2>/dev/null) == "ppc" ]] ; then
+    # PPC is bi-endian but usually configured as big-endian.
+    runtests "."
+    runtests "hardfloat"
+    if [[ $($LIRASM --show-word-size) == "32" ]] ; then
+        runtests "32-bit"
+    else
+        runtests "64-bit"
+    fi
+    runtests "bigendian"
+    runtest "--random 1000000"
+    runtest "--random 1000000 --optimize"
 
-    for infile in "$TESTS_DIR"/hardfloat/*.in
-    do
-        # Run tests that require hardware floating-point.
-        runtest $infile "--arch 6"
-    done
+elif [[ $($LIRASM --show-arch 2>/dev/null) == "sparc" ]] ; then
+    # Sparc is bi-endian but usually configured as big-endian.
+    runtests "."
+    runtests "hardfloat"
+    runtests "32-bit"
+    runtests "bigendian"
+    runtest "--random 1000000"
+    runtest "--random 1000000 --optimize"
 
-    # Run specific soft-float tests, but only for ARMv5 without VFP.
-    # NOTE: It looks like MIPS ought to be able to run these tests, but I can't
-    # test this and _not_ running them seems like the safest option.
-    for infile in "$TESTS_DIR"/softfloat/*.in
-    do
-        runtest $infile "--arch 5 --novfp"
-    done
+elif [[ $($LIRASM --show-arch 2>/dev/null) == "mips" ]] ; then
+    # MIPS is bi-endian but usually configured as big-endian.
+    # XXX: should we run softfloat tests as well?  Seems to depend on
+    # the configuration...
+    runtests "."
+    runtests "hardfloat"
+    runtests "32-bit"
+    runtests "bigendian"
+    runtest "--random 1000000"
+    runtest "--random 1000000 --optimize"
 
-    # Run reduced random tests for these targets. (The default ARMv7 target
-    # still runs the long tests.)
-    runtest "--random 10000 --arch 6"
-    runtest "--random 10000 --arch 5 --novfp"
-    runtest "--random 10000 --optimize --arch 6"
-    runtest "--random 10000 --optimize --arch 5 --novfp"
+elif [[ $($LIRASM --show-arch 2>/dev/null) == "sh4" ]] ; then
+    # SH4 is bi-endian but usually configured as big-endian.
+    runtests "."
+    runtests "hardfloat"
+    runtests "32-bit"
+    runtests "bigendian"
+    runtest "--random 1000000"
+    runtest "--random 1000000 --optimize"
+
+else
+    echo "bad arch"
+    exit 1
 fi
 
-# ---- Randomized tests, they are run last because they are slow ----
-
-runtest "--random 1000000"
-runtest "--random 1000000 --optimize"
-
 rm testoutput.txt
 
 exit $exitcode
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -402,18 +402,25 @@ mjit::Compiler::finishThisUp(JITScript *
     uint8 *result = (uint8 *)execPool->alloc(totalSize);
     JSC::ExecutableAllocator::makeWritable(result, totalSize);
     masm.executableCopy(result);
     stubcc.masm.executableCopy(result + masm.size());
     
     JSC::LinkBuffer fullCode(result, totalSize);
     JSC::LinkBuffer stubCode(result + masm.size(), stubcc.size());
 
+    size_t nNmapLive = 0;
+    for (size_t i = 0; i < script->length; i++) {
+        analyze::Bytecode *opinfo = analysis->maybeCode(i);
+        if (opinfo && opinfo->safePoint)
+            nNmapLive++;
+    }
+
     size_t totalBytes = sizeof(JITScript) +
-                        sizeof(void *) * script->length +
+                        sizeof(NativeMapEntry) * nNmapLive +
 #if defined JS_MONOIC
                         sizeof(ic::MICInfo) * mics.length() +
                         sizeof(ic::CallICInfo) * callICs.length() +
                         sizeof(ic::EqualityICInfo) * equalityICs.length() +
                         sizeof(ic::TraceICInfo) * traceICs.length() +
 #endif
 #if defined JS_POLYIC
                         sizeof(ic::PICInfo) * pics.length() +
@@ -431,27 +438,33 @@ mjit::Compiler::finishThisUp(JITScript *
     JITScript *jit = new(cursor) JITScript;
     cursor += sizeof(JITScript);
 
     jit->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size());
     jit->nCallSites = callSites.length();
     jit->invokeEntry = result;
 
     /* Build the pc -> ncode mapping. */
-    void **nmap = (void **)cursor;
-    cursor += sizeof(void *) * script->length;
-
-    for (size_t i = 0; i < script->length; i++) {
-        Label L = jumpMap[i];
-        analyze::Bytecode *opinfo = analysis->maybeCode(i);
-        if (opinfo && opinfo->safePoint) {
-            JS_ASSERT(L.isValid());
-            nmap[i] = (uint8 *)(result + masm.distanceOf(L));
+    NativeMapEntry *nmap = (NativeMapEntry *)cursor;
+    cursor += sizeof(NativeMapEntry) * nNmapLive;
+
+    size_t ix = 0;
+    if (nNmapLive > 0) {
+        for (size_t i = 0; i < script->length; i++) {
+            analyze::Bytecode *opinfo = analysis->maybeCode(i);
+            if (opinfo && opinfo->safePoint) {
+                Label L = jumpMap[i];
+                JS_ASSERT(L.isValid());
+                nmap[ix].bcOff = i;
+                nmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L));
+                ix++;
+            }
         }
     }
+    JS_ASSERT(ix == nNmapLive);
 
     if (fun) {
         jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
         jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
     }
 
 #if defined JS_MONOIC
     jit->nMICs = mics.length();
@@ -768,16 +781,17 @@ mjit::Compiler::finishThisUp(JITScript *
         }
     } else {
         jit->callSites = NULL;
     }
 
     JS_ASSERT(size_t(cursor - (uint8*)jit) == totalBytes);
 
     jit->nmap = nmap;
+    jit->nNmapPairs = nNmapLive;
     *jitp = jit;
 
     return Compile_Okay;
 }
 
 #ifdef DEBUG
 #define SPEW_OPCODE()                                                         \
     JS_BEGIN_MACRO                                                            \
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -485,22 +485,22 @@ inline bool
 FrameState::shouldAvoidDataRemat(FrameEntry *fe)
 {
     return fe->data.inMemory();
 }
 
 inline void
 FrameState::ensureFeSynced(const FrameEntry *fe, Assembler &masm) const
 {
+#if defined JS_PUNBOX64
     Address to = addressOf(fe);
     const FrameEntry *backing = fe;
     if (fe->isCopy())
         backing = fe->copyOf();
 
-#if defined JS_PUNBOX64
     /* If we can, sync the type and data in one go. */
     if (!fe->data.synced() && !fe->type.synced()) {
         if (backing->isConstant())
             masm.storeValue(backing->getValue(), to);
         else if (backing->isTypeKnown())
             masm.storeValueFromComponents(ImmType(backing->getKnownType()), backing->data.reg(), to);
         else
             masm.storeValueFromComponents(backing->type.reg(), backing->data.reg(), to);
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -286,20 +286,28 @@ typedef void (JS_FASTCALL *VoidStubPIC)(
 typedef void (JS_FASTCALL *VoidStubGetElemIC)(VMFrame &, js::mjit::ic::GetElementIC *);
 typedef void (JS_FASTCALL *VoidStubSetElemIC)(VMFrame &f, js::mjit::ic::SetElementIC *);
 #endif
 
 namespace mjit {
 
 struct CallSite;
 
+struct NativeMapEntry {
+    size_t          bcOff;  /* bytecode offset in script */
+    void            *ncode; /* pointer to native code */
+};
+
 struct JITScript {
     typedef JSC::MacroAssemblerCodeRef CodeRef;
     CodeRef         code;       /* pool & code addresses */
-    void            **nmap;     /* pc -> JIT code map, sparse */
+
+    NativeMapEntry  *nmap;      /* array of NativeMapEntrys, sorted by .bcOff.
+                                   .ncode values may not be NULL. */
+    size_t          nNmapPairs; /* number of entries in nmap */
 
     js::mjit::CallSite *callSites;
     uint32          nCallSites;
 #ifdef JS_MONOIC
     ic::MICInfo     *mics;      /* MICs in this script. */
     uint32          nMICs;      /* number of MonoICs */
     ic::CallICInfo  *callICs;   /* CallICs in this script. */
     uint32          nCallICs;   /* number of call ICs */
@@ -404,43 +412,59 @@ struct CallSite
 
 /* Re-enables a tracepoint in the method JIT. */
 void
 EnableTraceHint(JSScript *script, jsbytecode *pc, uint16_t index);
 
 uintN
 GetCallTargetCount(JSScript *script, jsbytecode *pc);
 
+inline void * bsearch_nmap(NativeMapEntry *nmap, size_t nPairs, size_t bcOff)
+{
+    size_t lo = 1, hi = nPairs;
+    while (1) {
+        /* current unsearched space is from lo-1 to hi-1, inclusive. */
+        if (lo > hi)
+            return NULL; /* not found */
+        size_t mid       = (lo + hi) / 2;
+        size_t bcOff_mid = nmap[mid-1].bcOff;
+        if (bcOff < bcOff_mid) {
+            hi = mid-1;
+            continue;
+        } 
+        if (bcOff > bcOff_mid) {
+            lo = mid+1;
+            continue;
+        }
+        return nmap[mid-1].ncode;
+    }
+}
+
 } /* namespace mjit */
 
 } /* namespace js */
 
 inline void *
 JSScript::maybeNativeCodeForPC(bool constructing, jsbytecode *pc)
 {
     js::mjit::JITScript *jit = getJIT(constructing);
     if (!jit)
         return NULL;
     JS_ASSERT(pc >= code && pc < code + length);
-    return jit->nmap[pc - code];
-}
-
-inline void **
-JSScript::nativeMap(bool constructing)
-{
-    return getJIT(constructing)->nmap;
+    return bsearch_nmap(jit->nmap, jit->nNmapPairs, (size_t)(pc - code));
 }
 
 inline void *
 JSScript::nativeCodeForPC(bool constructing, jsbytecode *pc)
 {
-    void **nmap = nativeMap(constructing);
+    js::mjit::JITScript *jit = getJIT(constructing);
     JS_ASSERT(pc >= code && pc < code + length);
-    JS_ASSERT(nmap[pc - code]);
-    return nmap[pc - code];
+    void* native = bsearch_nmap(jit->nmap, jit->nNmapPairs, (size_t)(pc - code));
+    JS_ASSERT(native);
+    return native;
 }
 
 #ifdef _MSC_VER
 extern "C" void *JaegerThrowpoline(js::VMFrame *vmFrame);
 #else
 extern "C" void JaegerThrowpoline();
 #endif
 extern "C" void InjectJaegerReturn();
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -571,22 +571,28 @@ class SetPropCompiler : public PICStubCo
                 JSObject *funobj = &f.regs.sp[-1].toObject();
                 if (funobj != GET_FUNCTION_PRIVATE(cx, funobj))
                     return disable("mismatched function");
 
                 flags |= Shape::METHOD;
                 getter = CastAsPropertyOp(funobj);
             }
 
+            /*
+             * Define the property but do not set it yet. For setmethod,
+             * populate the slot to satisfy the method invariant (in case we
+             * hit an early return below).
+             */
             const Shape *shape =
                 obj->putProperty(cx, id, getter, clasp->setProperty,
                                  SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0);
-
             if (!shape)
                 return error();
+            if (flags & Shape::METHOD)
+                obj->nativeSetSlot(shape->slot, f.regs.sp[-1]);
 
             /*
              * Test after calling putProperty since it can switch obj into
              * dictionary mode, specifically if the shape tree ancestor line
              * exceeds PropertyTree::MAX_HEIGHT.
              */
             if (obj->inDictionaryMode())
                 return disable("dictionary");
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -2445,25 +2445,25 @@ stubs::LeaveBlock(VMFrame &f, JSObject *
     }
 }
 
 void * JS_FASTCALL
 stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
 {
     jsbytecode *jpc = pc;
     JSScript *script = f.fp()->script();
-    void **nmap = script->nativeMap(f.fp()->isConstructing());
+    bool ctor = f.fp()->isConstructing();
 
     /* This is correct because the compiler adjusts the stack beforehand. */
     Value lval = f.regs.sp[-1];
 
     if (!lval.isPrimitive()) {
-        ptrdiff_t offs = (pc + GET_JUMP_OFFSET(pc)) - script->code;
-        JS_ASSERT(nmap[offs]);
-        return nmap[offs];
+        void* native = script->nativeCodeForPC(ctor, pc + GET_JUMP_OFFSET(pc));
+        JS_ASSERT(native);
+        return native;
     }
 
     JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH);
 
     pc += JUMP_OFFSET_LEN;
     uint32 npairs = GET_UINT16(pc);
     pc += UINT16_LEN;
 
@@ -2472,51 +2472,54 @@ stubs::LookupSwitch(VMFrame &f, jsbyteco
     if (lval.isString()) {
         JSString *str = lval.toString();
         for (uint32 i = 1; i <= npairs; i++) {
             Value rval = script->getConst(GET_INDEX(pc));
             pc += INDEX_LEN;
             if (rval.isString()) {
                 JSString *rhs = rval.toString();
                 if (rhs == str || js_EqualStrings(str, rhs)) {
-                    ptrdiff_t offs = (jpc + GET_JUMP_OFFSET(pc)) - script->code;
-                    JS_ASSERT(nmap[offs]);
-                    return nmap[offs];
+                    void* native = script->nativeCodeForPC(ctor,
+                                                           jpc + GET_JUMP_OFFSET(pc));
+                    JS_ASSERT(native);
+                    return native;
                 }
             }
             pc += JUMP_OFFSET_LEN;
         }
     } else if (lval.isNumber()) {
         double d = lval.toNumber();
         for (uint32 i = 1; i <= npairs; i++) {
             Value rval = script->getConst(GET_INDEX(pc));
             pc += INDEX_LEN;
             if (rval.isNumber() && d == rval.toNumber()) {
-                ptrdiff_t offs = (jpc + GET_JUMP_OFFSET(pc)) - script->code;
-                JS_ASSERT(nmap[offs]);
-                return nmap[offs];
+                void* native = script->nativeCodeForPC(ctor,
+                                                       jpc + GET_JUMP_OFFSET(pc));
+                JS_ASSERT(native);
+                return native;
             }
             pc += JUMP_OFFSET_LEN;
         }
     } else {
         for (uint32 i = 1; i <= npairs; i++) {
             Value rval = script->getConst(GET_INDEX(pc));
             pc += INDEX_LEN;
             if (lval == rval) {
-                ptrdiff_t offs = (jpc + GET_JUMP_OFFSET(pc)) - script->code;
-                JS_ASSERT(nmap[offs]);
-                return nmap[offs];
+                void* native = script->nativeCodeForPC(ctor,
+                                                       jpc + GET_JUMP_OFFSET(pc));
+                JS_ASSERT(native);
+                return native;
             }
             pc += JUMP_OFFSET_LEN;
         }
     }
 
-    ptrdiff_t offs = (jpc + GET_JUMP_OFFSET(jpc)) - script->code;
-    JS_ASSERT(nmap[offs]);
-    return nmap[offs];
+    void* native = script->nativeCodeForPC(ctor, jpc + GET_JUMP_OFFSET(jpc));
+    JS_ASSERT(native);
+    return native;
 }
 
 void * JS_FASTCALL
 stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
 {
     jsbytecode * const originalPC = origPc;
     jsbytecode *pc = originalPC;
     uint32 jumpOffset = GET_JUMP_OFFSET(pc);
@@ -2551,23 +2554,22 @@ stubs::TableSwitch(VMFrame &f, jsbytecod
             pc += JUMP_OFFSET_LEN * tableIdx;
             uint32 candidateOffset = GET_JUMP_OFFSET(pc);
             if (candidateOffset)
                 jumpOffset = candidateOffset;
         }
     }
 
 finally:
-    JSScript *script = f.fp()->script();
-    void **nmap = script->nativeMap(f.fp()->isConstructing());
-
     /* Provide the native address. */
-    ptrdiff_t offset = (originalPC + jumpOffset) - script->code;
-    JS_ASSERT(nmap[offset]);
-    return nmap[offset];
+    JSScript* script = f.fp()->script();
+    void* native = script->nativeCodeForPC(f.fp()->isConstructing(),
+                                           originalPC + jumpOffset);
+    JS_ASSERT(native);
+    return native;
 }
 
 void JS_FASTCALL
 stubs::Unbrand(VMFrame &f)
 {
     const Value &thisv = f.regs.sp[-1];
     if (!thisv.isObject())
         return;
--- a/js/src/nanojit-import-rev
+++ b/js/src/nanojit-import-rev
@@ -1,1 +1,1 @@
-4effe362e918583ec7b98b08da24f02c0833d306
+1789b94e330017a4b932d04faece480564ce79c0
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -453,19 +453,17 @@ Process(JSContext *cx, JSObject *obj, ch
                 (void)JS_ExecuteScript(cx, obj, script, NULL);
                 int64 t2 = PRMJ_Now() - t1;
                 if (printTiming)
                     printf("runtime = %.3f ms\n", double(t2) / PRMJ_USEC_PER_MSEC);
             }
             JS_DestroyScript(cx, script);
         }
 
-        if (file != stdin)
-            fclose(file);
-        return;
+        goto cleanup;
     }
 
     /* It's an interactive filehandle; drop into read-eval-print loop. */
     lineno = 1;
     hitEOF = JS_FALSE;
     buffer = NULL;
     size = 0;           /* assign here to avoid warnings */
     do {
@@ -486,17 +484,17 @@ Process(JSContext *cx, JSObject *obj, ch
             {
                 JSAutoSuspendRequest suspended(cx);
                 line = GetLine(file, startline == lineno ? "js> " : "");
             }
             if (!line) {
                 if (errno) {
                     JS_ReportError(cx, strerror(errno));
                     free(buffer);
-                    return;
+                    goto cleanup;
                 }
                 hitEOF = JS_TRUE;
                 break;
             }
             if (!buffer) {
                 buffer = line;
                 len = strlen(buffer);
                 size = len + 1;
@@ -507,17 +505,17 @@ Process(JSContext *cx, JSObject *obj, ch
                 size_t newlen = strlen(line) + (len ? len + 1 : 0);
                 if (newlen + 1 > size) {
                     size = newlen + 1 > size * 2 ? newlen + 1 : size * 2;
                     char *newBuf = (char *) realloc(buffer, size);
                     if (!newBuf) {
                         free(buffer);
                         free(line);
                         JS_ReportOutOfMemory(cx);
-                        return;
+                        goto cleanup;
                     }
                     buffer = newBuf;
                 }
                 char *current = buffer + len;
                 if (startline != lineno)
                     *current++ = '\n';
                 strcpy(current, line);
                 len = newlen;
@@ -561,16 +559,17 @@ Process(JSContext *cx, JSObject *obj, ch
             }
             JS_DestroyScript(cx, script);
         }
         *buffer = '\0';
     } while (!hitEOF && !gQuitting);
 
     free(buffer);
     fprintf(gOutFile, "\n");
+cleanup:
     if (file != stdin)
         fclose(file);
     return;
 }
 
 static int
 usage(void)
 {
@@ -1009,21 +1008,20 @@ Options(JSContext *cx, uintN argc, jsval
         }
     }
     if (!found)
         names = strdup("");
     if (!names) {
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
-    str = JS_NewString(cx, names, strlen(names));
-    if (!str) {
-        free(names);
+    str = JS_NewStringCopyZ(cx, names);
+    free(names);
+    if (!str)
         return JS_FALSE;
-    }
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 static JSBool
 Load(JSContext *cx, uintN argc, jsval *vp)
 {
     uintN i;
@@ -1132,21 +1130,20 @@ ReadLine(JSContext *cx, uintN argc, jsva
     }
 
     buf = tmp;
 
     /*
      * Turn buf into a JSString. Note that buflength includes the trailing null
      * character.
      */
-    str = JS_NewString(cx, buf, sawNewline ? buflength - 1 : buflength);
-    if (!str) {
-        JS_free(cx, buf);
+    str = JS_NewStringCopyN(cx, buf, sawNewline ? buflength - 1 : buflength);
+    JS_free(cx, buf);
+    if (!str)
         return JS_FALSE;
-    }
 
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 static JSBool
 PutStr(JSContext *cx, uintN argc, jsval *vp)
 {
@@ -3387,18 +3384,18 @@ EvalInFrame(JSContext *cx, uintN argc, j
         JS_RestoreFrameChain(cx, oldfp);
 
     return ok;
 }
 
 static JSBool
 ShapeOf(JSContext *cx, uintN argc, jsval *vp)
 {
-    jsval v = JS_ARGV(cx, vp)[0];
-    if (!JSVAL_IS_OBJECT(v)) {
+    jsval v;
+    if (argc < 1 || !JSVAL_IS_OBJECT(v = JS_ARGV(cx, vp)[0])) {
         JS_ReportError(cx, "shapeOf: object expected");
         return JS_FALSE;
     }
     JSObject *obj = JSVAL_TO_OBJECT(v);
     if (!obj) {
         *vp = JSVAL_ZERO;
         return JS_TRUE;
     }
@@ -4065,17 +4062,17 @@ Parse(JSContext *cx, uintN argc, jsval *
         const char *typeName = JS_GetTypeName(cx, JS_TypeOfValue(cx, arg0));
         JS_ReportError(cx, "expected string to parse, got %s", typeName);
         return JS_FALSE;
     }
 
     JSString *scriptContents = JSVAL_TO_STRING(arg0);
     js::Parser parser(cx);
     parser.init(JS_GetStringCharsZ(cx, scriptContents), JS_GetStringLength(scriptContents),
-                NULL, "<string>", 0);
+                "<string>", 0);
     if (!parser.parse(NULL))
         return JS_FALSE;
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
 Snarf(JSContext *cx, uintN argc, jsval *vp)
@@ -4139,22 +4136,20 @@ Snarf(JSContext *cx, uintN argc, jsval *
         fclose(file);
     }
     JS_free(cx, (void*)pathname);
     if (!ok) {
         JS_free(cx, buf);
         return ok;
     }
 
-    buf[len] = '\0';
-    str = JS_NewString(cx, buf, len);
-    if (!str) {
-        JS_free(cx, buf);
+    str = JS_NewStringCopyN(cx, buf, len);
+    JS_free(cx, buf);
+    if (!str)
         return JS_FALSE;
-    }
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 JSBool
 Wrap(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval v = argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID;
--- a/js/src/tests/js1_5/extensions/jstests.list
+++ b/js/src/tests/js1_5/extensions/jstests.list
@@ -26,25 +26,23 @@ script regress-291213.js
 script regress-300079.js
 script regress-303277.js
 script regress-304897.js
 script regress-306738.js
 script regress-311161.js
 script regress-311583.js
 script regress-311792-01.js
 script regress-311792-02.js
-script regress-313500.js
 script regress-313763.js
 script regress-313803.js
 script regress-313938.js
 script regress-314874.js
 script regress-315509-02.js
 script regress-319683.js
 script regress-322957.js
-script regress-325269.js
 script regress-327608.js
 script regress-328443.js
 script regress-328556.js
 skip script regress-330569.js # Yarr doesn't bail on complex regexps.
 script regress-333541.js
 skip script regress-335700.js # bug xxx - reftest hang, BigO
 skip-if(!xulRuntime.shell) script regress-336409-1.js # no results reported.
 skip-if(!xulRuntime.shell&&xulRuntime.XPCOMABI.match(/x86_64/)) silentfail script regress-336409-2.js # can fail silently due to out of memory
deleted file mode 100644
--- a/js/src/tests/js1_5/extensions/regress-313500.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** 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 JavaScript Engine testing utilities.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): Igor Bukanov
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either 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 ***** */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 313500;
-var summary = 'Root access to "prototype" property';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-printStatus('This test requires TOO_MUCH_GC');
-
-function F() { }
-
-var prepared = new Object();
-
-F.prototype = {};
-F.__defineGetter__('prototype', function() {
-		     var tmp = prepared;
-		     prepared = null;
-		     return tmp;
-		   });
-
-new F();
- 
-reportCompare(expect, actual, summary);
deleted file mode 100644
--- a/js/src/tests/js1_5/extensions/regress-325269.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** 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 JavaScript Engine testing utilities.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2006
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): Igor Bukanov
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either 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 ***** */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 325269;
-var summary = 'GC hazard in js_ConstructObject';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-printBugNumber(BUGNUMBER);
-printStatus (summary);
-// only get exit code 3 if out of memory error occurs which
-// will not happen on machines with enough memory.
-// expectExitCode(3);
- 
-var SavedArray = Array;
-
-function Redirector() { }
-
-Redirector.prototype = 1;
-Redirector.__defineGetter__('prototype', function() {
-//        printStatus("REDIRECTOR");
-			      gc();
-			      return SavedArray.prototype;
-			    });
-
-//Array = Function('printStatus("Constructor")');
-try {
-    Array = Function('');
-} catch (e) { }
-
-if (Array === SavedArray) {
-  // No test of the hazard possible as the array is read-only
-  actual = expect;
-} else {
-  Array.prototype = 1;
-  Array.__defineGetter__('prototype', function() {
-//        printStatus("**** GETTER ****");
-      Array = Redirector;
-      gc();
-      new Object();
-      new Object();
-      return undefined;
-    });
-
-  new Object();
-
-  try
-  {
-    var y = "test".split('');
-  }
-  catch(ex)
-  {
-    printStatus(ex + '');
-  }
-}
-
-reportCompare(expect, actual, summary);
--- a/js/src/tests/js1_8_5/regress/jstests.list
+++ b/js/src/tests/js1_8_5/regress/jstests.list
@@ -49,8 +49,10 @@ script regress-598176.js
 script regress-600067.js
 script regress-600137.js
 script regress-601399.js
 script regress-602621.js
 fails-if(!xulRuntime.shell) script regress-607799.js
 fails-if(!xulRuntime.shell) script regress-607863.js
 script regress-610026.js
 script regress-609617.js
+script regress-617405-1.js
+script regress-617405-2.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/regress/regress-617405-1.js
@@ -0,0 +1,11 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ * Contributors: Christian Holler <decoder@own-hero.net> and Jason Orendorff
+ */
+
+function C(){}
+C.prototype = 1;
+assertEq(Object.getOwnPropertyDescriptor(C, "prototype").configurable, false);
+
+reportCompare(0, 0, "ok");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/regress/regress-617405-2.js
@@ -0,0 +1,17 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ * Contributors: Christian Holler <decoder@own-hero.net> and Jason Orendorff
+ */
+
+function C(){}
+C.prototype = 1;
+try {
+    Object.defineProperty(C, "prototype", {get: function() { throw 0; }});
+    actual = "no exception";
+} catch (exc) {
+    actual = exc.name;
+}
+new C; // don't assert
+assertEq(actual, "TypeError");
+reportCompare(0, 0, "ok");
--- a/js/src/tests/jstests.py
+++ b/js/src/tests/jstests.py
@@ -224,16 +224,18 @@ if __name__ == '__main__':
     op.add_option('--valgrind-args', dest='valgrind_args',
                   help='extra args to pass to valgrind')
     op.add_option('-c', '--check-manifest', dest='check_manifest', action='store_true',
                   help='check for test files not listed in the manifest')
     op.add_option('--failure-file', dest='failure_file',
                   help='write tests that have not passed to the given file')
     op.add_option('--run-slow-tests', dest='run_slow_tests', action='store_true',
                   help='run particularly slow tests as well as average-speed tests')
+    op.add_option('--xul-info', dest='xul_info_src',
+                  help='config data for xulRuntime (avoids search for config/autoconf.mk)')
     (OPTIONS, args) = op.parse_args()
     if len(args) < 1:
         if not OPTIONS.check_manifest:
             op.error('missing JS_SHELL argument')
         JS, args = None, []
     else:
         JS, args = args[0], args[1:]
     # Convert to an absolute path so we can run JS from a different directory.
@@ -274,17 +276,22 @@ if __name__ == '__main__':
         else:
             print >> sys.stderr, 'no manifest file given and defaults not found'
             sys.exit(2)
 
     import manifest
     if JS is None:
         xul_tester = manifest.NullXULInfoTester()
     else:
-        xul_info = manifest.XULInfo.create(JS)
+        if OPTIONS.xul_info_src is None:
+            xul_info = manifest.XULInfo.create(JS)
+        else:
+            xul_abi, xul_os, xul_debug = OPTIONS.xul_info_src.split(r':')
+            xul_debug = xul_debug.lower() is 'true'
+            xul_info = manifest.XULInfo(xul_abi, xul_os, xul_debug)
         xul_tester = manifest.XULInfoTester(xul_info, JS)
     test_list = manifest.parse(OPTIONS.manifest, xul_tester)
 
     if OPTIONS.check_manifest:
         check_manifest(test_list)
         if JS is None:
             sys.exit()
 
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -819,21 +819,20 @@ Options(JSContext *cx, uintN argc, jsval
         }
     }
     if (!found)
         names = strdup("");
     if (!names) {
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
-    str = JS_NewString(cx, names, strlen(names));
-    if (!str) {
-        free(names);
+    str = JS_NewStringCopyZ(cx, names);
+    free(names);
+    if (!str)
         return JS_FALSE;
-    }
     JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
     return JS_TRUE;
 }
 
 static JSBool
 Parent(JSContext *cx, uintN argc, jsval *vp)
 {
     if (argc != 1) {
--- a/js/src/xpconnect/src/XPCDispTearOff.cpp
+++ b/js/src/xpconnect/src/XPCDispTearOff.cpp
@@ -348,18 +348,17 @@ STDMETHODIMP XPCDispatchTearOff::Invoke(
         scriptEval.StartEvaluating(xpcWrappedJSErrorReporter);
 
         xpcc->SetPendingResult(pending_result);
         xpcc->SetException(nsnull);
         ccx.GetThreadData()->SetException(nsnull);
 
         // We use js_Invoke so that the gcthings we use as args will be rooted
         // by the engine as we do conversions and prepare to do the function
-        // call. This adds a fair amount of complexity, but it's a good
-        // optimization compared to calling JS_AddRoot for each item.
+        // call.
 
         js::LeaveTrace(cx);
 
         // In the xpidl [function] case we are making sure now that the 
         // JSObject is callable. If it is *not* callable then we silently 
         // fallback to looking up the named property...
         // (because jst says he thinks this fallback is 'The Right Thing'.)
         //
--- a/js/src/xpconnect/src/qsgen.py
+++ b/js/src/xpconnect/src/qsgen.py
@@ -617,16 +617,20 @@ def writeResultDecl(f, type, varname):
         f.write("    nsCOMPtr<%s> %s;\n" % (type.name, varname))
         return
 
     warn("Unable to declare result of type %s" % type.name)
     f.write("    !; // TODO - Declare out parameter `%s`.\n" % varname)
 
 def outParamForm(name, type):
     type = unaliasType(type)
+    # If we start allowing [jsval] return types here, we need to tack
+    # the return value onto the arguments list in the callers,
+    # possibly, and handle properly returning it too.  See bug 604198.
+    assert getBuiltinOrNativeTypeName(type) is not '[jsval]'
     if type.kind == 'builtin':
         return '&' + name
     elif type.kind == 'native':
         if getBuiltinOrNativeTypeName(type) == '[jsval]':
             return 'vp'
         elif type.modifier == 'ref':
             return name
         else:
@@ -1179,19 +1183,20 @@ def writeTraceableArgumentConversion(f, 
         elif type.name == 'nsIAtom':
             # Should have special atomizing behavior.  Fall through.
             pass
         else:
             if not rvdeclared:
                 f.write("    nsresult rv;\n");
             f.write("    %s *%s;\n" % (type.name, name))
             f.write("    xpc_qsSelfRef %sref;\n" % name)
+            f.write("    js::Anchor<jsval> %sanchor;\n" % name);
             f.write("    rv = xpc_qsUnwrapArg<%s>("
-                    "cx, js::Jsvalify(js::ValueArgToConstRef(%s)), &%s, &%sref.ptr, &vp.array[%d]);\n"
-                    % (type.name, argVal, name, name, 2 + i))
+                    "cx, js::Jsvalify(js::ValueArgToConstRef(%s)), &%s, &%sref.ptr, &%sanchor.get());\n"
+                    % (type.name, argVal, name, name, name))
             f.write("    if (NS_FAILED(rv)) {\n")
             if haveCcx:
                 f.write("        xpc_qsThrowBadArgWithCcx(ccx, rv, %d);\n" % i)
             else:
                 # XXX Fix this to return a real error!
                 f.write("        xpc_qsThrowBadArgWithDetails(cx, rv, %d, "
                         "\"%s\", \"%s\");\n"
                         % (i, member.iface.name, member.name))
@@ -1246,34 +1251,36 @@ def writeTraceableResultConv(f, type):
         if template is not None:
             values = { 'errorStr': getFailureString(
                                    getTraceInfoDefaultReturn(type), 2) }
             f.write(substitute(template, values))
             return
         # else fall through; this type isn't supported yet
     elif isInterfaceType(type):
         if isVariantType(type):
-            f.write("    JSBool ok = xpc_qsVariantToJsval(lccx, result, "
-                    "&vp.array[0]);\n")
+            f.write("    jsval returnVal;\n"
+                    "    JSBool ok = xpc_qsVariantToJsval(lccx, result, "
+                    "&returnVal);\n")
         else:
             f.write("    nsWrapperCache* cache = xpc_qsGetWrapperCache(result);\n"
                     "    JSObject* wrapper =\n"
-                    "      xpc_GetCachedSlimWrapper(cache, obj, &vp.array[0]);\n"
+                    "      xpc_GetCachedSlimWrapper(cache, obj);\n"
                     "    if (wrapper) {\n"
                     "      return wrapper;\n"
                     "    }\n"
                     "    // After this point do not use 'result'!\n"
                     "    qsObjectHelper helper(result, cache);\n"
+                    "    jsval returnVal;\n"
                     "    JSBool ok = xpc_qsXPCOMObjectToJsval(lccx, "
                     "helper, &NS_GET_IID(%s), &interfaces[k_%s], "
-                    "&vp.array[0]);\n"
+                    "&returnVal);\n"
                     % (type.name, type.name))
         f.write("    if (!ok) {\n");
         writeFailure(f, getTraceInfoDefaultReturn(type), 2)
-        f.write("    return JSVAL_TO_OBJECT(vp.array[0]);\n")
+        f.write("    return JSVAL_TO_OBJECT(returnVal);\n")
         return
 
     warn("Unable to convert result of type %s" % typeName)
     f.write("    !; // TODO - Convert `result` to jsval, store in rval.\n")
     f.write("    return xpc_qsThrow(cx, NS_ERROR_UNEXPECTED); // FIXME\n")
 
 def writeTraceableQuickStub(f, customMethodCalls, member, stubName):
     assert member.traceable
@@ -1316,27 +1323,27 @@ def writeTraceableQuickStub(f, customMet
             f.write("    XPCLazyCallContext lccx(ccx);\n")
 
     # Get the 'self' pointer.
     if customMethodCall is None or not 'thisType' in customMethodCall:
         f.write("    %s *self;\n" % member.iface.name)
     else:
         f.write("    %s *self;\n" % customMethodCall['thisType'])
     f.write("    xpc_qsSelfRef selfref;\n")
-    f.write("    xpc_qsArgValArray<%d> vp(cx);\n" % (2 + len(member.params)))
+    f.write("    js::Anchor<jsval> selfanchor;\n")
     if haveCcx:
         f.write("    if (!xpc_qsUnwrapThisFromCcx(ccx, &self, &selfref.ptr, "
-                "&vp.array[1])) {\n")
+                "&selfanchor.get())) {\n")
     elif (member.kind == 'method') and isInterfaceType(member.realtype):
         f.write("    XPCLazyCallContext lccx(JS_CALLER, cx, obj);\n")
         f.write("    if (!xpc_qsUnwrapThis(cx, obj, callee, &self, &selfref.ptr, "
-                "&vp.array[1], &lccx)) {\n")
+                "&selfanchor.get(), &lccx)) {\n")
     else:
         f.write("    if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, "
-                "&vp.array[1], nsnull)) {\n")
+                "&selfanchor.get(), nsnull)) {\n")
     writeFailure(f, getTraceInfoDefaultReturn(member.realtype), 2)
 
     argNames = []
 
     # Convert in-parameters.
     rvdeclared = False
     for i, param in enumerate(member.params):
         argName = "arg%d" % i
@@ -1366,19 +1373,17 @@ def writeTraceableQuickStub(f, customMet
         selfname = prefix + 'self'
         nsresultname = prefix + 'rv'
 
         # Prepare out-parameter.
         writeResultDecl(f, member.realtype, resultname)
 
         # Call the method.
         comName = header.methodNativeName(member)
-        if getBuiltinOrNativeTypeName(member.realtype) == '[jsval]':
-            argNames.append("&vp.array[0]")
-        elif not isVoidType(member.realtype):
+        if not isVoidType(member.realtype):
             argNames.append(outParamForm(resultname, member.realtype))
         args = ', '.join(argNames)
 
         f.write("    ")
         if canFail:
             f.write("%s = " % nsresultname)
         f.write("%s->%s(%s);\n" % (selfname, comName, args))
 
--- a/js/src/xpconnect/src/xpccallcontext.cpp
+++ b/js/src/xpconnect/src/xpccallcontext.cpp
@@ -444,17 +444,17 @@ XPCCallContext::~XPCCallContext()
     }
 #endif
 
     if(shouldReleaseXPC && mXPC)
         NS_RELEASE(mXPC);
 }
 
 XPCReadableJSStringWrapper *
-XPCCallContext::NewStringWrapper(PRUnichar *str, PRUint32 len)
+XPCCallContext::NewStringWrapper(const PRUnichar *str, PRUint32 len)
 {
     StringWrapperEntry *se =
         reinterpret_cast<StringWrapperEntry*>(&mStringWrapperData);
 
     PRUint32 i;
     for(i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i)
     {
         StringWrapperEntry& ent = se[i];
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -1122,17 +1122,18 @@ public:
                      JSBool isSetter);
 
     nsresult  CanCallNow();
 
     void SystemIsBeingShutDown();
 
     operator JSContext*() const {return GetJSContext();}
 
-    XPCReadableJSStringWrapper *NewStringWrapper(PRUnichar *str, PRUint32 len);
+    XPCReadableJSStringWrapper *NewStringWrapper(const PRUnichar *str,
+                                                 PRUint32 len);
     void DeleteString(nsAString *string);
 
 #ifdef XPC_IDISPATCH_SUPPORT
     /**
      * Sets the IDispatch information for the context
      * This has to be void* because of icky Microsoft macros that
      * would be introduced if we included the DispatchInterface header
      */
--- a/js/src/xpconnect/src/xpcpublic.h
+++ b/js/src/xpconnect/src/xpcpublic.h
@@ -119,9 +119,16 @@ xpc_GetCachedSlimWrapper(nsWrapperCache 
 
             return wrapper;
         }
     }
 
     return nsnull;
 }
 
+inline JSObject*
+xpc_GetCachedSlimWrapper(nsWrapperCache *cache, JSObject *scope)
+{
+    jsval dummy;
+    return xpc_GetCachedSlimWrapper(cache, scope, &dummy);
+}
+
 #endif
--- a/js/src/xpconnect/src/xpcquickstubs.h
+++ b/js/src/xpconnect/src/xpcquickstubs.h
@@ -456,28 +456,16 @@ struct xpc_qsSelfRef
 {
     xpc_qsSelfRef() : ptr(nsnull) {}
     explicit xpc_qsSelfRef(nsISupports *p) : ptr(p) {}
     ~xpc_qsSelfRef() { NS_IF_RELEASE(ptr); }
 
     nsISupports* ptr;
 };
 
-template<size_t N>
-struct xpc_qsArgValArray
-{
-    xpc_qsArgValArray(JSContext *cx) : tvr(cx, N, array)
-    {
-        memset(array, 0, N * sizeof(jsval));
-    }
-
-    js::AutoArrayRooter tvr;
-    jsval array[N];
-};
-
 /**
  * Convert a jsval to char*, returning JS_TRUE on success.
  *
  * @param cx
  *     A context.
  * @param v
  *     A value to convert.
  * @param bytes
--- a/js/src/xpconnect/src/xpcstring.cpp
+++ b/js/src/xpconnect/src/xpcstring.cpp
@@ -139,11 +139,15 @@ XPCStringConvert::ReadableToJSVal(JSCont
     }
     return STRING_TO_JSVAL(str);
 }
 
 // static
 XPCReadableJSStringWrapper *
 XPCStringConvert::JSStringToReadable(XPCCallContext& ccx, JSString *str)
 {
-    return ccx.NewStringWrapper(reinterpret_cast<PRUnichar *>(JS_GetStringChars(str)),
-                                JS_GetStringLength(str));
+    const PRUnichar *chars =
+        reinterpret_cast<const PRUnichar *>(JS_GetStringCharsZ(ccx, str));
+    if(!chars)
+        return nsnull;
+
+    return ccx.NewStringWrapper(chars, JS_GetStringLength(str));
 }
--- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp
+++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp
@@ -1344,18 +1344,16 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
 
                 principalGuard.principalPushed(ssm);
             }
         }
     }
 
     // We use js_Invoke so that the gcthings we use as args will be rooted by
     // the engine as we do conversions and prepare to do the function call.
-    // This adds a fair amount of complexity, but it's a good optimization
-    // compared to calling JS_AddRoot for each item.
 
     js::LeaveTrace(cx);
 
     // setup stack
 
     // if this isn't a function call then we don't need to push extra stuff
     if (!(XPT_MD_IS_SETTER(info->flags) || XPT_MD_IS_GETTER(info->flags)))
     {
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -86,23 +86,20 @@ ToStringGuts(XPCCallContext& ccx)
         sz = JS_smprintf("[xpconnect wrapped native prototype]");
 
     if(!sz)
     {
         JS_ReportOutOfMemory(ccx);
         return JS_FALSE;
     }
 
-    JSString* str = JS_NewString(ccx, sz, strlen(sz));
+    JSString* str = JS_NewStringCopyZ(ccx, sz);
+    JS_smprintf_free(sz);
     if(!str)
-    {
-        JS_smprintf_free(sz);
-        // JS_ReportOutOfMemory already reported by failed JS_NewString
         return JS_FALSE;
-    }
 
     ccx.SetRetVal(STRING_TO_JSVAL(str));
     return JS_TRUE;
 }
 
 /***************************************************************************/
 
 static JSBool
@@ -124,23 +121,20 @@ XPC_WN_Shared_ToString(JSContext *cx, ui
 #  define FMT_ADDR ""
 #  define FMT_STR(str)
 #  define PARAM_ADDR(w)
 #endif
         char *sz = JS_smprintf("[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]", si->GetJSClass()->name PARAM_ADDR(obj) PARAM_ADDR(xpc_GetJSPrivate(obj)));
         if(!sz)
             return JS_FALSE;
 
-        JSString* str = JS_NewString(cx, sz, strlen(sz));
+        JSString* str = JS_NewStringCopyZ(cx, sz);
+        JS_smprintf_free(sz);
         if(!str)
-        {
-            JS_smprintf_free(sz);
-
             return JS_FALSE;
-        }
 
         *vp = STRING_TO_JSVAL(str);
 
         return JS_TRUE;
     }
     
     XPCCallContext ccx(JS_CALLER, cx, obj);
     ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING));