[JAEGER] Merge from tracemonkey. Note that we will currently fail one trace test that was recently added. There is a bug in that test that will be fixed posthaste.
authorDavid Mandelin <dmandelin@mozilla.com>
Tue, 17 Aug 2010 15:32:40 -0700
changeset 53446 d98210dc7e0635cd8d8884a873d9b9c722ee8671
parent 53445 31db2f636fdc110259f41d8b8ab452a693f61dff (current diff)
parent 51100 2573e884e17b21868f57e04147511550323fa289 (diff)
child 53447 b32ec7fa1e2e552e8d513b57e54f0ae55ef82ae8
push idunknown
push userunknown
push dateunknown
milestone2.0b4pre
[JAEGER] Merge from tracemonkey. Note that we will currently fail one trace test that was recently added. There is a bug in that test that will be fixed posthaste.
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsJSEnvironment.cpp
js/src/js.msg
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsatom.h
js/src/jscntxt.cpp
js/src/jsdate.cpp
js/src/jsdtracef.cpp
js/src/jsemit.cpp
js/src/jsemit.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsparse.cpp
js/src/jsparse.h
js/src/jsscript.cpp
js/src/jstracer.cpp
js/src/jstracer.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/xpconnect/idl/nsIXPConnect.idl
js/src/xpconnect/src/XPCNativeWrapper.cpp
js/src/xpconnect/src/XPCWrapper.h
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpcconvert.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -4887,18 +4887,18 @@ nsDOMClassInfo::ShutDown()
   NS_IF_RELEASE(sXPConnect);
   NS_IF_RELEASE(sSecMan);
   sIsInitialized = PR_FALSE;
 }
 
 // Window helper
 
 NS_IMETHODIMP
-nsCommonWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
-                            JSObject *globalObj, JSObject **parentObj)
+nsInnerWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
+                           JSObject *globalObj, JSObject **parentObj)
 {
   // Normally ::PreCreate() is used to give XPConnect the parent
   // object for the object that's being wrapped, this parent object is
   // set as the parent of the wrapper and it's also used to find the
   // right scope for the object being wrapped. Now, in the case of the
   // global object the wrapper shouldn't have a parent but we supply
   // one here anyway (the global object itself) and this will be used
   // by XPConnect only to find the right scope, once the scope is
@@ -4906,35 +4906,40 @@ nsCommonWindowSH::PreCreate(nsISupports 
   // exists since it's created on window construction), since an
   // existing wrapper is found the parent we supply here is ignored
   // after the wrapper is found.
 
   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeObj));
   NS_ASSERTION(sgo, "nativeObj not a global object!");
 
   nsGlobalWindow *win = nsGlobalWindow::FromSupports(nativeObj);
-
-  if (win->IsOuterWindow()) {
-    win->EnsureInnerWindow();
-  }
-
-  if (sgo) {
-    *parentObj = sgo->GetGlobalJSObject();
-
-    if (*parentObj) {
-      return win->IsChromeWindow() ? NS_OK : NS_SUCCESS_NEEDS_XOW;
-    }
-  }
-
-  // We're most likely being called when the global object is
-  // created, at that point we won't get a nsIScriptContext but we
-  // know we're called on the correct context so we return globalObj
-
-  *parentObj = globalObj;
-
+  JSObject *winObj = win->FastGetGlobalJSObject();
+  if (!winObj) {
+    NS_ASSERTION(win->GetOuterWindowInternal()->IsCreatingInnerWindow(),
+                 "should have a JS object by this point");
+    return NS_OK;
+  }
+
+  *parentObj = winObj;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOuterWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
+                           JSObject *globalObj, JSObject **parentObj)
+{
+  nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeObj));
+  NS_ASSERTION(sgo, "nativeObj not a global object!");
+
+  nsGlobalWindow *win = nsGlobalWindow::FromSupports(nativeObj);
+  if (!win->EnsureInnerWindow()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  *parentObj = win->GetCurrentInnerWindowInternal()->FastGetGlobalJSObject();
   return win->IsChromeWindow() ? NS_OK : NS_SUCCESS_NEEDS_XOW;
 }
 
 
 // This JS class piggybacks on nsHTMLDocumentSH::ReleaseDocument()...
 
 static JSClass sGlobalScopePolluterClass = {
   "Global Scope Polluter",
@@ -6657,43 +6662,43 @@ nsCommonWindowSH::NewResolve(nsIXPConnec
   JSContext *my_cx;
 
   if (!my_context) {
     my_cx = cx;
   } else {
     my_cx = (JSContext *)my_context->GetNativeContext();
   }
 
-  JSBool ok;
-  jsval exn;
-  {
+  JSBool ok = JS_TRUE;
+  jsval exn = JSVAL_VOID;
+  if (win->IsInnerWindow()) {
     JSAutoRequest transfer(my_cx);
 
     JSObject *realObj;
     wrapper->GetJSObject(&realObj);
-    
+
     // Don't resolve standard classes on XPCNativeWrapper etc, only
     // resolve them if we're resolving on the real global object.
     ok = obj == realObj ?
          ::JS_ResolveStandardClass(my_cx, obj, id, &did_resolve) :
          JS_TRUE;
-    
+
     if (!ok) {
       // Trust the JS engine (or the script security manager) to set
       // the exception in the JS engine.
-      
+
       if (!JS_GetPendingException(my_cx, &exn)) {
         return NS_ERROR_UNEXPECTED;
       }
-      
+
       // Return NS_OK to avoid stomping over the exception that was passed
       // down from the ResolveStandardClass call.
       // Note that the order of the JS_ClearPendingException and
       // JS_SetPendingException is important in the case that my_cx == cx.
-      
+
       JS_ClearPendingException(my_cx);
     }
   }
 
   if (!ok) {
     JS_SetPendingException(cx, exn);
     *_retval = JS_FALSE;
     return NS_OK;
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -509,18 +509,16 @@ protected:
   {
   }
 
   static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
                                 JSObject *obj, JSString *str,
                                 PRBool *did_resolve);
 
 public:
-  NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
-                       JSObject *globalObj, JSObject **parentObj);
 #ifdef DEBUG
   NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj)
   {
     nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
 
     NS_ASSERTION(!sgo || sgo->GetGlobalJSObject() == nsnull,
                  "Multiple wrappers created for global object!");
@@ -573,16 +571,18 @@ protected:
 
   virtual ~nsOuterWindowSH()
   {
   }
 
   static PRBool sResolving;
 
 public:
+  NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
+                       JSObject *globalObj, JSObject **parentObj);
   NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
   NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, jsid id, PRUint32 flags,
                         JSObject **objp, PRBool *_retval);
   NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                           JSObject *obj, PRUint32 enum_op, jsval *statep,
                           jsid *idp, PRBool *_retval);
@@ -602,16 +602,18 @@ protected:
   {
   }
 
   virtual ~nsInnerWindowSH()
   {
   }
 
 public:
+  NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
+                       JSObject *globalObj, JSObject **parentObj);
   // We WANT_ADDPROPERTY, but are content to inherit it from nsEventReceiverSH.
   NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                          JSObject * obj, JSObject * *_retval);
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsInnerWindowSH(aData);
   }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1507,54 +1507,60 @@ class WindowStateHolder : public nsISupp
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
   NS_DECL_ISUPPORTS
 
   WindowStateHolder(nsGlobalWindow *aWindow,
                     nsIXPConnectJSObjectHolder *aHolder,
                     nsNavigator *aNavigator,
-                    nsIXPConnectJSObjectHolder *aOuterProto);
+                    nsIXPConnectJSObjectHolder *aOuterProto,
+                    nsIXPConnectJSObjectHolder *aOuterRealProto);
 
   nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
   nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
   { return mInnerWindowHolder; }
 
   nsNavigator* GetNavigator() { return mNavigator; }
   nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
+  nsIXPConnectJSObjectHolder* GetOuterRealProto() { return mOuterRealProto; }
 
   void DidRestoreWindow()
   {
     mInnerWindow = nsnull;
 
     mInnerWindowHolder = nsnull;
     mNavigator = nsnull;
     mOuterProto = nsnull;
+    mOuterRealProto = nsnull;
   }
 
 protected:
   ~WindowStateHolder();
 
   nsGlobalWindow *mInnerWindow;
   // We hold onto this to make sure the inner window doesn't go away. The outer
   // window ends up recalculating it anyway.
   nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
   nsRefPtr<nsNavigator> mNavigator;
   nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
+  nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterRealProto;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
 
 WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
                                      nsIXPConnectJSObjectHolder *aHolder,
                                      nsNavigator *aNavigator,
-                                     nsIXPConnectJSObjectHolder *aOuterProto)
+                                     nsIXPConnectJSObjectHolder *aOuterProto,
+                                     nsIXPConnectJSObjectHolder *aOuterRealProto)
   : mInnerWindow(aWindow),
     mNavigator(aNavigator),
-    mOuterProto(aOuterProto)
+    mOuterProto(aOuterProto),
+    mOuterRealProto(aOuterRealProto)
 {
   NS_PRECONDITION(aWindow, "null window");
   NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
 
   mInnerWindowHolder = aHolder;
 
   aWindow->SuspendTimeouts();
 }
@@ -1604,19 +1610,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     return GetOuterWindowInternal()->SetNewDocument(aDocument, aState);
   }
 
   NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
 
   if (IsFrozen()) {
     // This outer is now getting its first inner, thaw the outer now
     // that it's ready and is getting an inner window.
-    mContext->CreateOuterObject(this, aDocument->NodePrincipal());
-    mContext->DidInitializeContext();
-    mJSObject = (JSObject *)mContext->GetNativeGlobal();
 
     Thaw();
   }
 
   // XXX Brain transplant outer window JSObject and create new one!
 
   NS_ASSERTION(!GetCurrentInnerWindow() ||
                GetCurrentInnerWindow()->GetExtantDocument() == mDocument,
@@ -1720,36 +1723,41 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
   nsCxPusher cxPusher;
   if (!cxPusher.Push(cx)) {
     return NS_ERROR_FAILURE;
   }
 
   JSAutoRequest ar(cx);
 
+  nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
+  NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
+
   // Make sure to clear scope on the outer window *before* we
   // initialize the new inner window. If we don't, things
   // (Object.prototype etc) could leak from the old outer to the new
   // inner scope.
   mContext->ClearScope(mJSObject, PR_FALSE);
 
+  // This code should not be called during shutdown any more (now that
+  // we don't ever call SetNewDocument(nsnull), so no need to null
+  // check xpc here.
+  nsIXPConnect *xpc = nsContentUtils::XPConnect();
+  nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
   if (reUseInnerWindow) {
     // We're reusing the current inner window.
     NS_ASSERTION(!currentInner->IsFrozen(),
                  "We should never be reusing a shared inner window");
     newInnerWindow = currentInner;
 
     if (aDocument != oldDoc) {
       nsCommonWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
     }
   } else {
     if (aState) {
-      nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
-      NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
-
       newInnerWindow = wsh->GetInnerWindow();
       mInnerWindowHolder = wsh->GetInnerWindowHolder();
 
       // These assignments addref.
       mNavigator = wsh->GetNavigator();
 
       if (mNavigator) {
         // Update mNavigator's docshell pointer now.
@@ -1813,17 +1821,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       void *&newGlobal = (void *&)newInnerWindow->mJSObject;
       nsCOMPtr<nsIXPConnectJSObjectHolder> &holder = mInnerWindowHolder;
       rv = mContext->CreateNativeGlobalForInner(sgo, isChrome,
                                                 aDocument->NodePrincipal(),
                                                 &newGlobal,
                                                 getter_AddRefs(holder));
       NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder,
                    "Failed to get script global and holder");
-      newInnerWindow->mJSObject = (JSObject *)newGlobal;
 
       mCreatingInnerWindow = PR_FALSE;
       Thaw();
 
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (currentInner && currentInner->mJSObject) {
@@ -1867,16 +1874,55 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       if (!currentInner->IsFrozen()) {
         // Skip the ClearScope if we set a termination function to do
         // it ourselves, later.
         currentInner->FreeInnerObjects(!termFuncSet);
       }
     }
 
     mInnerWindow = newInnerWindow;
+
+    if (!mJSObject) {
+      mContext->CreateOuterObject(this, newInnerWindow);
+      mContext->DidInitializeContext();
+      mJSObject = (JSObject *)mContext->GetNativeGlobal();
+    } else {
+      // XXX New global object and brain transplant!
+      rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
+                                           getter_AddRefs(wrapper));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      // Restore our object's prototype to its original value so we're sure to
+      // update it under ReparentWrappedNativeIfFound.
+      JSObject *proto;
+      wrapper->GetJSObjectPrototype(&proto);
+      if (!JS_SetPrototype(cx, mJSObject, proto)) {
+        NS_ERROR("Can't set prototype");
+        return NS_ERROR_UNEXPECTED;
+      }
+
+      nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
+      xpc->ReparentWrappedNativeIfFound(cx, currentInner->mJSObject,
+                                        newInnerWindow->mJSObject,
+                                        ToSupports(this),
+                                        getter_AddRefs(holder));
+
+      if (aState) {
+        if (nsIXPConnectJSObjectHolder *holder = wsh->GetOuterRealProto()) {
+          holder->GetJSObject(&proto);
+        } else {
+          proto = nsnull;
+        }
+
+        if (!JS_SetPrototype(cx, mJSObject, proto)) {
+          NS_ERROR("can't set prototype");
+          return NS_ERROR_FAILURE;
+        }
+      }
+    }
   }
 
   if (!aState && !reUseInnerWindow) {
     // Loading a new page and creating a new inner window, *not*
     // restoring from session history.
 
     // InitClassesWithNewWrappedGlobal() (via CreateNativeGlobalForInner)
     // for the new inner window
@@ -1919,52 +1965,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   // alive etc.
 
   if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) {
     nsCOMPtr<nsIHTMLDocument> html_doc(do_QueryInterface(mDocument));
     nsCommonWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject,
                                                  html_doc);
   }
 
-  // This code should not be called during shutdown any more (now that
-  // we don't ever call SetNewDocument(nsnull), so no need to null
-  // check xpc here.
-  nsIXPConnect *xpc = nsContentUtils::XPConnect();
-
-  nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-  if (aState) {
-    // Restoring from session history.
-
-    nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
-    NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
-
-    // Restore the prototype for the Window/ChromeWindow class in
-    // the outer window scope.
-    nsCOMPtr<nsIClassInfo> ci =
-      do_QueryInterface((nsIScriptGlobalObject *)this);
-
-    rv = xpc->RestoreWrappedNativePrototype(cx, mJSObject, ci,
-                                            wsh->GetOuterProto());
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Refresh the outer window's prototype to what it was when the
-    // window state was saved. This will make the outer window
-    // object (and wrapper) pick up the prototype it had when the
-    // window state was saved. This means Object.prototype etc from
-    // the old inner will again be on the outer window's prototype
-    // chain.
-
-    rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
-                                         getter_AddRefs(wrapper));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = wrapper->RefreshPrototype();
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
   if (aDocument) {
     aDocument->SetScriptGlobalObject(newInnerWindow);
   }
 
   if (!aState) {
     if (reUseInnerWindow) {
       if (newInnerWindow->mDoc != aDocument) {
         newInnerWindow->mDocument = do_QueryInterface(aDocument);
@@ -9068,31 +9078,49 @@ nsGlobalWindow::SaveWindowState(nsISuppo
 
   // Don't do anything else to this inner window! After this point, all
   // calls to SetTimeoutOrInterval will create entries in the timeout
   // list that will only run after this window has come out of the bfcache.
   // Also, while we're frozen, we won't dispatch online/offline events
   // to the page.
   inner->Freeze();
 
-  // Remember the outer window's XPConnect prototype.
+  // Remember the outer window's prototype.
+  JSContext *cx = (JSContext *)mContext->GetNativeContext();
+  JSAutoRequest req(cx);
+
+  nsIXPConnect *xpc = nsContentUtils::XPConnect();
+
   nsCOMPtr<nsIClassInfo> ci =
     do_QueryInterface((nsIScriptGlobalObject *)this);
   nsCOMPtr<nsIXPConnectJSObjectHolder> proto;
-  nsresult rv = nsContentUtils::XPConnect()->
-    GetWrappedNativePrototype((JSContext *)mContext->GetNativeContext(),
-                              mJSObject, ci, getter_AddRefs(proto));
+  nsresult rv = xpc->GetWrappedNativePrototype(cx, mJSObject, ci,
+                                               getter_AddRefs(proto));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  JSObject *realProto = JS_GetPrototype(cx, mJSObject);
+  nsCOMPtr<nsIXPConnectJSObjectHolder> realProtoHolder;
+  if (realProto) {
+    rv = xpc->HoldObject(cx, realProto, getter_AddRefs(realProtoHolder));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
   nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
                                                       mInnerWindowHolder,
                                                       mNavigator,
-                                                      proto);
+                                                      proto,
+                                                      realProtoHolder);
   NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
 
+  JSObject *wnProto;
+  proto->GetJSObject(&wnProto);
+  if (!JS_SetPrototype(cx, mJSObject, wnProto)) {
+    return NS_ERROR_FAILURE;
+  }
+
 #ifdef DEBUG_PAGE_CACHE
   printf("saving window state, state = %p\n", (void*)state);
 #endif
 
   state.swap(*aState);
   return NS_OK;
 }
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -378,16 +378,21 @@ public:
   // Object Management
   nsGlobalWindow(nsGlobalWindow *aOuterWindow);
 
   static nsGlobalWindow *FromSupports(nsISupports *supports)
   {
     // Make sure this matches the casts we do in QueryInterface().
     return (nsGlobalWindow *)(nsIScriptGlobalObject *)supports;
   }
+  static nsISupports *ToSupports(nsGlobalWindow *win)
+  {
+    // Make sure this matches the casts we do in QueryInterface().
+    return (nsISupports *)(nsIScriptGlobalObject *)win;
+  }
   static nsGlobalWindow *FromWrapper(nsIXPConnectWrappedNative *wrapper)
   {
     return FromSupports(wrapper->Native());
   }
 
   nsIScriptContext *GetContextInternal()
   {
     if (mOuterWindow) {
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -339,21 +339,21 @@ public:
   virtual nsresult InitContext() = 0;
 
   /**
    * Creates the outer window for this context.
    *
    * @param aGlobalObject The script global object to use as our global.
    */
   virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
-                                     nsIPrincipal *aPrincipal) = 0;
+                                     nsIScriptGlobalObject *aCurrentInner) = 0;
 
   /**
    * Prepares this context for use with the current inner window for the
-   * context's global object. This must be called after InitOuterWindow.
+   * context's global object. This must be called after CreateOuterObject.
    */
   virtual nsresult InitOuterWindow() = 0;
 
   /**
    * Check to see if context is as yet intialized. Used to prevent
    * reentrancy issues during the initialization process.
    *
    * @return PR_TRUE if initialized, PR_FALSE if not
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2589,17 +2589,17 @@ nsJSContext::CreateNativeGlobalForInner(
   return NS_OK;
 }
 
 nsresult
 nsJSContext::ConnectToInner(nsIScriptGlobalObject *aNewInner, void *aOuterGlobal)
 {
   NS_ENSURE_ARG(aNewInner);
   JSObject *newInnerJSObject = (JSObject *)aNewInner->GetScriptGlobal(JAVASCRIPT);
-  JSObject *myobject = (JSObject *)aOuterGlobal;
+  JSObject *outerGlobal = (JSObject *)aOuterGlobal;
 
   // Make the inner and outer window both share the same
   // prototype. The prototype we share is the outer window's
   // prototype, this way XPConnect can still find the wrapper to
   // use when making a call like alert() (w/o qualifying it with
   // "window."). XPConnect looks up the wrapper based on the
   // function object's parent, which is the object the function
   // was called on, and when calling alert() we'll be calling the
@@ -2610,22 +2610,28 @@ nsJSContext::ConnectToInner(nsIScriptGlo
 
   // We do *not* want to use anything else out of the outer
   // object's prototype chain than the first prototype, which is
   // the XPConnect prototype. The rest we want from the inner
   // window's prototype, i.e. the global scope polluter and
   // Object.prototype. This way the outer also gets the benefits
   // of the global scope polluter, and the inner window's
   // Object.prototype.
-  JSObject *proto = ::JS_GetPrototype(mContext, myobject);
-  JSObject *innerProto = ::JS_GetPrototype(mContext, newInnerJSObject);
-  JSObject *innerProtoProto = ::JS_GetPrototype(mContext, innerProto);
-
-  ::JS_SetPrototype(mContext, newInnerJSObject, proto);
-  ::JS_SetPrototype(mContext, proto, innerProtoProto);
+  JSObject *proto = JS_GetPrototype(mContext, outerGlobal);
+  JSObject *innerProto = JS_GetPrototype(mContext, newInnerJSObject);
+  JSObject *innerProtoProto = JS_GetPrototype(mContext, innerProto);
+
+  JS_SetPrototype(mContext, newInnerJSObject, proto);
+  JS_SetPrototype(mContext, proto, innerProtoProto);
+
+  // Now that we're connecting the outer global to the inner one,
+  // we must have transplanted it. The JS engine tries to maintain
+  // the global object's compartment as its default compartment,
+  // so update that now since it might have changed.
+  JS_SetGlobalObject(mContext, outerGlobal);
   return NS_OK;
 }
 
 void *
 nsJSContext::GetNativeContext()
 {
   return mContext;
 }
@@ -2655,46 +2661,46 @@ nsJSContext::InitContext()
     nsDOMClassInfo::SetXrayWrapperPropertyHolderGetPropertyOp(getProperty);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
-                               nsIPrincipal *aPrincipal)
+                               nsIScriptGlobalObject *aCurrentInner)
 {
-  NS_PRECONDITION(!JS_GetGlobalObject(mContext),
-                  "Outer window already initialized");
-
   nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(aGlobalObject));
   PRUint32 flags = 0;
 
   if (chromeWindow) {
     // Flag this window's global object and objects under it as "system",
     // for optional automated XPCNativeWrapper construction when chrome JS
     // views a content DOM.
     flags = nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT;
 
     // Always enable E4X for XUL and other chrome content -- there is no
     // need to preserve the <!-- script hiding hack from JS-in-HTML daze
     // (introduced in 1995 for graceful script degradation in Netscape 1,
     // Mosaic, and other pre-JS browsers).
-    ::JS_SetOptions(mContext, ::JS_GetOptions(mContext) | JSOPTION_XML);
+    JS_SetOptions(mContext, JS_GetOptions(mContext) | JSOPTION_XML);
   }
 
   nsIXPConnect *xpc = nsContentUtils::XPConnect();
   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-  nsresult rv =
-    xpc->InitClassesWithNewWrappedGlobal(mContext, aGlobalObject,
-                                         NS_GET_IID(nsISupports),
-                                         aPrincipal, EmptyCString(),
-                                         flags, getter_AddRefs(holder));
+  nsresult rv = xpc->WrapNative(mContext, aCurrentInner->GetGlobalJSObject(),
+                                aGlobalObject, NS_GET_IID(nsISupports),
+                                getter_AddRefs(holder));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // Force our context's global object to be the outer.
+  JSObject *globalObj;
+  holder->GetJSObject(&globalObj);
+  JS_SetGlobalObject(mContext, globalObj);
+
   // Hold a strong reference to the wrapper for the global to avoid
   // rooting and unrooting the global object every time its AddRef()
   // or Release() methods are called
   mGlobalWrapperRef = holder;
   return NS_OK;
 }
 
 nsresult
@@ -2703,24 +2709,19 @@ nsJSContext::InitOuterWindow()
   JSObject *global = JS_GetGlobalObject(mContext);
   nsIScriptGlobalObject *sgo = GetGlobalObject();
 
   // Call ClearScope to nuke any properties (e.g. Function and Object) on the
   // outer object. From now on, anybody asking the outer object for these
   // properties will be forwarded to the inner window.
   JS_ClearScope(mContext, global);
 
-  // Now that the inner and outer windows are connected, tell XPConnect to
-  // re-initialize the prototypes on the outer window's scope.
-  nsIXPConnect *xpc = nsContentUtils::XPConnect();
-  nsresult rv = xpc->InitClassesForOuterObject(mContext, global);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsresult rv = NS_OK;
 
   nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(sgo));
-
   if (ci) {
     jsval v;
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     rv = nsContentUtils::WrapNative(mContext, global, sgo, &v,
                                     getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -137,17 +137,17 @@ public:
                                       PRBool aIsChrome,
                                       nsIPrincipal *aPrincipal,
                                       void **aNativeGlobal,
                                       nsISupports **aHolder);
   virtual nsresult ConnectToInner(nsIScriptGlobalObject *aNewInner,
                                   void *aOuterGlobal);
   virtual nsresult InitContext();
   virtual nsresult CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
-                                     nsIPrincipal *aPrincipal);
+                                     nsIScriptGlobalObject *aCurrentInner);
   virtual nsresult InitOuterWindow();
   virtual PRBool IsContextInitialized();
   virtual void FinalizeContext();
 
   virtual void GC();
 
   virtual void ScriptEvaluated(PRBool aTerminated);
   virtual nsresult SetTerminationFunction(nsScriptTerminationFunc aFunc,
--- a/dom/tests/mochitest/general/Makefile.in
+++ b/dom/tests/mochitest/general/Makefile.in
@@ -54,12 +54,14 @@ include $(topsrcdir)/config/rules.mk
 		test_innerScreen.xul \
 		test_offsets.html \
 		test_offsets.js \
 		test_offsets.xul \
 		test_windowProperties.html \
 		test_clipboard_events.html \
 		test_focusrings.xul \
 		test_nodesFromRect.html \
+		test_frameElementWrapping.html \
+		file_frameElementWrapping.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/file_frameElementWrapping.html
@@ -0,0 +1,26 @@
+<html>
+    <script>
+        function check(elt, expectXOW, message) {
+            netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+            var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                              .getInterface(Components.interfaces.nsIDOMWindowUtils);
+            var result = ((utils.getClassName(elt) === 'XPCCrossOriginWrapper') === expectXOW)
+                         ? "PASS"
+                         : "FAIL";
+
+            parent.postMessage(result + ',' + message, '*');
+        }
+
+        try {
+            // true if same origin, throws otherwise
+            var sameOrigin = parent.location.href !== '';
+        } catch (e) {
+            sameOrigin = false;
+        }
+
+        check(frameElement, !sameOrigin,
+              sameOrigin
+              ? 'no wrapper needed if same origin'
+              : 'wrapper needed if not same origin');
+    </script>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_frameElementWrapping.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for location object behaviors</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+ 
+</div>
+<iframe id="ifr" src="file_frameElementWrapping.html"></iframe>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var count = 0;
+
+function runTest(result, message) {
+    ok(result === 'PASS', message);
+
+    if (++count === 2)
+        SimpleTest.finish();
+    else
+        $('ifr').contentWindow.location = 'http://example.org/tests/dom/tests/mochitest/general/file_frameElementWrapping.html';
+}
+
+window.addEventListener("message",
+                        function(event) { runTest.apply(null, event.data.split(',')) },
+                        false);
+
+</script>
+</pre>
+</body>
+</html>
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -325,9 +325,12 @@ MSG_DEF(JSMSG_DEFINE_ARRAY_LENGTH_UNSUPP
 MSG_DEF(JSMSG_CANT_DEFINE_ARRAY_INDEX,243, 0, JSEXN_TYPEERR, "can't define array index property")
 MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX,  244, 0, JSEXN_ERR, "invalid or out-of-range index")
 MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG, 245, 1, JSEXN_ERR, "argument {0} must be >= 0")
 MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS,   246, 0, JSEXN_ERR, "invalid arguments")
 MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION,   247, 0, JSEXN_ERR, "call to Function() blocked by CSP")
 MSG_DEF(JSMSG_BAD_GET_SET_FIELD,      248, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
 MSG_DEF(JSMSG_BAD_PROXY_FIX,          249, 0, JSEXN_TYPEERR, "proxy was fixed while executing the handler")
 MSG_DEF(JSMSG_INVALID_EVAL_SCOPE_ARG, 250, 0, JSEXN_EVALERR, "invalid eval scope argument")
-MSG_DEF(JSMSG_NEED_DEBUG_MODE,        251, 0, JSEXN_ERR, "function can be called only in debug mode")
+MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS,    251, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
+MSG_DEF(JSMSG_THROW_TYPE_ERROR,       252, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them")
+MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP,   253, 0, JSEXN_TYPEERR, "toISOString property is not callable")
+MSG_DEF(JSMSG_NEED_DEBUG_MODE,        254, 0, JSEXN_ERR, "function can be called only in debug mode")
--- a/js/src/jsapi-tests/testContexts.cpp
+++ b/js/src/jsapi-tests/testContexts.cpp
@@ -80,16 +80,18 @@ END_TEST(testContexts_bug561444)
 BEGIN_TEST(testContexts_bug563735)
 {
     JSContext *cx2 = JS_NewContext(rt, 8192);
     CHECK(cx2);
 
     JSBool ok;
     {
         JSAutoRequest req(cx2);
+        JSAutoCrossCompartmentCall crossCall;
+        CHECK(crossCall.enter(cx2, global));
         jsval v = JSVAL_NULL;
         ok = JS_SetProperty(cx2, global, "x", &v);
     }
     CHECK(ok);
 
     EXEC("(function () { for (var i = 0; i < 9; i++) ; })();");
 
     JS_DestroyContext(cx2);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1682,32 +1682,36 @@ struct JSClass {
 #define JSCLASS_INTERNAL_FLAG1          (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0))
 #define JSCLASS_IS_ANONYMOUS            (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1))
 #define JSCLASS_IS_GLOBAL               (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2))
 
 /* Indicates that JSClass.mark is a tracer with JSTraceOp type. */
 #define JSCLASS_MARK_IS_TRACE           (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3))
 #define JSCLASS_INTERNAL_FLAG2          (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4))
 
+/* Additional global reserved slots, beyond those for standard prototypes. */
+#define JSRESERVED_GLOBAL_SLOTS_COUNT     3
+#define JSRESERVED_GLOBAL_COMPARTMENT     (JSProto_LIMIT * 3)
+#define JSRESERVED_GLOBAL_THIS            (JSRESERVED_GLOBAL_COMPARTMENT + 1)
+#define JSRESERVED_GLOBAL_THROWTYPEERROR  (JSRESERVED_GLOBAL_THIS + 1)
+
 /*
  * ECMA-262 requires that most constructors used internally create objects
  * with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
  * member initial value.  The "original ... value" verbiage is there because
  * in ECMA-262, global properties naming class objects are read/write and
  * deleteable, for the most part.
  *
  * Implementing this efficiently requires that global objects have classes
  * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
  * prevously allowed, but is now an ES5 violation and thus unsupported.
  */
-#define JSCLASS_GLOBAL_FLAGS \
-    (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSProto_LIMIT * 3 + 2))
-
-#define JSRESERVED_GLOBAL_COMPARTMENT (JSProto_LIMIT * 3)
-#define JSRESERVED_GLOBAL_THIS        (JSRESERVED_GLOBAL_COMPARTMENT + 1)
+#define JSCLASS_GLOBAL_FLAGS                                                  \
+    (JSCLASS_IS_GLOBAL |                                                      \
+     JSCLASS_HAS_RESERVED_SLOTS(JSProto_LIMIT * 3 + JSRESERVED_GLOBAL_SLOTS_COUNT))
 
 /* Fast access to the original value of each standard class's prototype. */
 #define JSCLASS_CACHED_PROTO_SHIFT      (JSCLASS_HIGH_FLAGS_SHIFT + 8)
 #define JSCLASS_CACHED_PROTO_WIDTH      8
 #define JSCLASS_CACHED_PROTO_MASK       JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH)
 #define JSCLASS_HAS_CACHED_PROTO(key)   ((key) << JSCLASS_CACHED_PROTO_SHIFT)
 #define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey)                         \
                                          (((clasp)->flags                     \
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -226,17 +226,17 @@ JSBool
 js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
     if (obj->isArray()) {
         *lengthp = obj->getArrayLength();
         return true;
     }
 
     if (obj->isArguments() && !obj->isArgsLengthOverridden()) {
-        *lengthp = obj->getArgsLength();
+        *lengthp = obj->getArgsInitialLength();
         return true;
     }
 
     AutoValueRooter tvr(cx);
     if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr()))
         return false;
 
     if (tvr.value().isInt32()) {
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -143,16 +143,17 @@ const char *const js_common_atom_names[]
     js_each_str,                /* eachAtom                     */
     js_eval_str,                /* evalAtom                     */
     js_fileName_str,            /* fileNameAtom                 */
     js_get_str,                 /* getAtom                      */
     js_global_str,              /* globalAtom                   */
     js_ignoreCase_str,          /* ignoreCaseAtom               */
     js_index_str,               /* indexAtom                    */
     js_input_str,               /* inputAtom                    */
+    "toISOString",              /* toISOStringAtom              */
     js_iterator_str,            /* iteratorAtom                 */
     js_join_str,                /* joinAtom                     */
     js_lastIndex_str,           /* lastIndexAtom                */
     js_length_str,              /* lengthAtom                   */
     js_lineNumber_str,          /* lineNumberAtom               */
     js_message_str,             /* messageAtom                  */
     js_multiline_str,           /* multilineAtom                */
     js_name_str,                /* nameAtom                     */
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -335,16 +335,17 @@ struct JSAtomState
     JSAtom              *eachAtom;
     JSAtom              *evalAtom;
     JSAtom              *fileNameAtom;
     JSAtom              *getAtom;
     JSAtom              *globalAtom;
     JSAtom              *ignoreCaseAtom;
     JSAtom              *indexAtom;
     JSAtom              *inputAtom;
+    JSAtom              *toISOStringAtom;
     JSAtom              *iteratorAtom;
     JSAtom              *joinAtom;
     JSAtom              *lastIndexAtom;
     JSAtom              *lengthAtom;
     JSAtom              *lineNumberAtom;
     JSAtom              *messageAtom;
     JSAtom              *multilineAtom;
     JSAtom              *nameAtom;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1963,16 +1963,18 @@ DSTOffsetCache::purge()
 {
     /*
      * NB: The initial range values are carefully chosen to result in a cache
      *     miss on first use given the range of possible values.  Be careful
      *     to keep these values and the caching algorithm in sync!
      */
     offsetMilliseconds = 0;
     rangeStartSeconds = rangeEndSeconds = INT64_MIN;
+    oldOffsetMilliseconds = 0;
+    oldRangeStartSeconds = oldRangeEndSeconds = INT64_MIN;
 
 #ifdef JS_METER_DST_OFFSET_CACHING
     totalCalculations = 0;
     hit = 0;
     missIncreasing = missDecreasing = 0;
     missIncreasingOffsetChangeExpand = missIncreasingOffsetChangeUpper = 0;
     missDecreasingOffsetChangeExpand = missDecreasingOffsetChangeLower = 0;
     missLargeIncrease = missLargeDecrease = 0;
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -200,16 +200,21 @@ TimeWithinDay(jsdouble t)
 #define TimeFromYear(y) (DayFromYear(y) * msPerDay)
 
 static jsint
 YearFromTime(jsdouble t)
 {
     jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970;
     jsdouble t2 = (jsdouble) TimeFromYear(y);
 
+    /*
+     * Adjust the year if the approximation was wrong.  Since the year was
+     * computed using the average number of ms per year, it will usually
+     * be wrong for dates within several hours of a year transition.
+     */
     if (t2 > t) {
         y--;
     } else {
         if (t2 + msPerDay * DaysInYear(y) <= t)
             y++;
     }
     return y;
 }
@@ -478,17 +483,17 @@ msFromTime(jsdouble t)
  */
 
 /*
  * Other Support routines and definitions
  */
 
 Class js_DateClass = {
     js_Date_str,
-    JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_FIXED_RESERVED_SLOTS) |
+    JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date) |
     JSCLASS_FAST_CONSTRUCTOR,
     PropertyStub,   /* addProperty */
     PropertyStub,   /* delProperty */
     PropertyStub,   /* getProperty */
     PropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -1199,64 +1204,199 @@ static JSBool
 GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
 {
     if (!InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
         return JS_FALSE;
     *dp = obj->getDateUTCTime().toNumber();
     return JS_TRUE;
 }
 
-static void
-SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL)
-{
-    JS_ASSERT(obj->getClass() == &js_DateClass);
-
-    obj->setDateLocalTime(cx->runtime->NaNValue);
-    obj->setDateUTCTime(cx->runtime->NaNValue);
-    if (vp)
-        vp->setDouble(js_NaN);
-}
-
 /*
  * Set UTC time to a given time and invalidate cached local time.
  */
 static JSBool
 SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL)
 {
-    JS_ASSERT(obj->getClass() == &js_DateClass);
-
-    obj->setDateLocalTime(cx->runtime->NaNValue);
+    JS_ASSERT(obj->isDate());
+
+    size_t slotCap = JS_MIN(obj->numSlots(), JSObject::DATE_CLASS_RESERVED_SLOTS);
+    for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; ind < slotCap; ind++)
+        obj->getSlotRef(ind).setUndefined();
+
     obj->setDateUTCTime(DoubleValue(t));
     if (vp)
         vp->setDouble(t);
     return true;
 }
 
+static void
+SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL)
+{
+    jsdouble NaN = cx->runtime->NaNValue.getDoubleRef();
+    SetUTCTime(cx, obj, NaN, vp);
+}
+
 /*
- * Get the local time, cache it if necessary. If UTC time is not finite
- * (e.g., NaN), the local time slot is set to the UTC time without conversion.
+ * Cache the local time, year, month, and so forth of the object.
+ * If UTC time is not finite (e.g., NaN), the local time
+ * slots will be set to the UTC time without conversion.
  */
-static JSBool
-GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
+static bool
+FillLocalTimes(JSContext *cx, JSObject *obj)
+{
+    JS_ASSERT(obj->isDate());
+
+    jsdouble utcTime = obj->getDateUTCTime().toNumber();
+
+    /* Make sure there are slots to store the cached information. */
+    if (obj->numSlots() < JSObject::DATE_CLASS_RESERVED_SLOTS) {
+        if (!obj->growSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
+            return false;
+    }
+
+    if (!JSDOUBLE_IS_FINITE(utcTime)) {
+        for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
+             ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
+             ind++) {
+            obj->setSlot(ind, DoubleValue(utcTime));
+        }
+        return true;
+    }
+
+    jsdouble localTime = LocalTime(utcTime, cx);
+
+    obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime));
+
+    jsint year = (jsint) floor(localTime /(msPerDay*365.2425)) + 1970;
+    jsdouble yearStartTime = (jsdouble) TimeFromYear(year);
+
+    /* Adjust the year in case the approximation was wrong, as in YearFromTime. */
+    jsint yearDays;
+    if (yearStartTime > localTime) {
+        year--;
+        yearStartTime -= (msPerDay * DaysInYear(year));
+        yearDays = DaysInYear(year);
+    } else {
+        yearDays = DaysInYear(year);
+        jsdouble nextStart = yearStartTime + (msPerDay * yearDays);
+        if (nextStart <= localTime) {
+            year++;
+            yearStartTime = nextStart;
+            yearDays = DaysInYear(year);
+        }
+    }
+
+    obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR, Int32Value(year));
+
+    uint64 yearTime = uint64(localTime - yearStartTime);
+    jsint yearSeconds = uint32(yearTime / 1000);
+
+    jsint day = yearSeconds / jsint(SecondsPerDay);
+
+    jsint step = -1, next = 30;
+    jsint month;
+
+    do {
+        if (day <= next) {
+            month = 0;
+            break;
+        }
+        step = next;
+        next += ((yearDays == 366) ? 29 : 28);
+        if (day <= next) {
+            month = 1;
+            break;
+        }
+        step = next;
+        if (day <= (next += 31)) {
+            month = 2;
+            break;
+        }
+        step = next;
+        if (day <= (next += 30)) {
+            month = 3;
+            break;
+        }
+        step = next;
+        if (day <= (next += 31)) {
+            month = 4;
+            break;
+        }
+        step = next;
+        if (day <= (next += 30)) {
+            month = 5;
+            break;
+        }
+        step = next;
+        if (day <= (next += 31)) {
+            month = 6;
+            break;
+        }
+        step = next;
+        if (day <= (next += 31)) {
+            month = 7;
+            break;
+        }
+        step = next;
+        if (day <= (next += 30)) {
+            month = 8;
+            break;
+        }
+        step = next;
+        if (day <= (next += 31)) {
+            month = 9;
+            break;
+        }
+        step = next;
+        if (day <= (next += 30)) {
+            month = 10;
+            break;
+        }
+        step = next;
+        month = 11;
+    } while (0);
+
+    obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH, Int32Value(month));
+    obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DATE, Int32Value(day - step));
+
+    jsint weekday = WeekDay(localTime);
+
+    obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DAY, Int32Value(weekday));
+
+    jsint seconds = yearSeconds % 60;
+
+    obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS, Int32Value(seconds));
+
+    jsint minutes = (yearSeconds / 60) % 60;
+
+    obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES, Int32Value(minutes));
+
+    jsint hours = (yearSeconds / (60 * 60)) % 24;
+
+    obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours));
+
+    return true;
+}
+
+/* Cache the local times in obj, if necessary. */
+static inline JSBool
+GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = NULL)
 {
     if (!obj || !InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
         return false;
 
-    jsdouble result = obj->getDateLocalTime().toNumber();
-    if (JSDOUBLE_IS_NaN(result)) {
-        result = obj->getDateUTCTime().toDouble();
-
-        /* if result is NaN, it couldn't be finite. */
-        if (JSDOUBLE_IS_FINITE(result))
-            result = LocalTime(result, cx);
-
-        obj->setDateLocalTime(DoubleValue(result));
+    /* If the local time is undefined, we need to fill in the cached values. */
+    if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
+        if (!FillLocalTimes(cx, obj))
+            return false;
     }
 
-    *dp = result;
+    if (time)
+        *time = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble();
+
     return true;
 }
 
 /*
  * See ECMA 15.9.5.4 thru 15.9.5.23
  */
 static JSBool
 date_getTime(JSContext *cx, uintN argc, Value *vp)
@@ -1265,45 +1405,43 @@ date_getTime(JSContext *cx, uintN argc, 
 
     if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
         return JS_FALSE;
     vp->setNumber(result);
     return JS_TRUE;
 }
 
 static JSBool
-GetYear(JSContext *cx, JSBool fullyear, Value *vp)
-{
-    jsdouble result;
-
-    if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
-        return JS_FALSE;
-
-    if (JSDOUBLE_IS_FINITE(result)) {
-        result = YearFromTime(result);
-
-        /* Follow ECMA-262 to the letter, contrary to IE JScript. */
-        if (!fullyear)
-            result -= 1900;
-    }
-
-    vp->setNumber(result);
-    return JS_TRUE;
-}
-
-static JSBool
 date_getYear(JSContext *cx, uintN argc, Value *vp)
 {
-    return GetYear(cx, JS_FALSE, vp);
+    JSObject *obj = ComputeThisFromVp(cx, vp);
+    if (!GetAndCacheLocalTime(cx, obj, vp))
+        return JS_FALSE;
+
+    Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
+    if (yearVal.isInt32()) {
+        /* Follow ECMA-262 to the letter, contrary to IE JScript. */
+        jsint year = yearVal.toInt32() - 1900;
+        vp->setInt32(year);
+    } else {
+        *vp = yearVal;
+    }
+
+    return JS_TRUE;
 }
 
 static JSBool
 date_getFullYear(JSContext *cx, uintN argc, Value *vp)
 {
-    return GetYear(cx, JS_TRUE, vp);
+    JSObject *obj = ComputeThisFromVp(cx, vp);
+    if (!GetAndCacheLocalTime(cx, obj, vp))
+        return JS_FALSE;
+
+    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
+    return JS_TRUE;
 }
 
 static JSBool
 date_getUTCFullYear(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
 
     if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
@@ -1314,25 +1452,21 @@ date_getUTCFullYear(JSContext *cx, uintN
 
     vp->setNumber(result);
     return JS_TRUE;
 }
 
 static JSBool
 date_getMonth(JSContext *cx, uintN argc, Value *vp)
 {
-    jsdouble result;
-
-    if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
+    JSObject *obj = ComputeThisFromVp(cx, vp);
+    if (!GetAndCacheLocalTime(cx, obj, vp))
         return JS_FALSE;
 
-    if (JSDOUBLE_IS_FINITE(result))
-        result = MonthFromTime(result);
-
-    vp->setNumber(result);
+    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
     return JS_TRUE;
 }
 
 static JSBool
 date_getUTCMonth(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
 
@@ -1344,25 +1478,21 @@ date_getUTCMonth(JSContext *cx, uintN ar
 
     vp->setNumber(result);
     return JS_TRUE;
 }
 
 static JSBool
 date_getDate(JSContext *cx, uintN argc, Value *vp)
 {
-    jsdouble result;
-
-    if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
+    JSObject *obj = ComputeThisFromVp(cx, vp);
+    if (!GetAndCacheLocalTime(cx, obj, vp))
         return JS_FALSE;
 
-    if (JSDOUBLE_IS_FINITE(result))
-        result = DateFromTime(result);
-
-    vp->setNumber(result);
+    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
     return JS_TRUE;
 }
 
 static JSBool
 date_getUTCDate(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
 
@@ -1374,25 +1504,21 @@ date_getUTCDate(JSContext *cx, uintN arg
 
     vp->setNumber(result);
     return JS_TRUE;
 }
 
 static JSBool
 date_getDay(JSContext *cx, uintN argc, Value *vp)
 {
-    jsdouble result;
-
-    if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
+    JSObject *obj = ComputeThisFromVp(cx, vp);
+    if (!GetAndCacheLocalTime(cx, obj, vp))
         return JS_FALSE;
 
-    if (JSDOUBLE_IS_FINITE(result))
-        result = WeekDay(result);
-
-    vp->setNumber(result);
+    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
     return JS_TRUE;
 }
 
 static JSBool
 date_getUTCDay(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
 
@@ -1404,25 +1530,21 @@ date_getUTCDay(JSContext *cx, uintN argc
 
     vp->setNumber(result);
     return JS_TRUE;
 }
 
 static JSBool
 date_getHours(JSContext *cx, uintN argc, Value *vp)
 {
-    jsdouble result;
-
-    if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
+    JSObject *obj = ComputeThisFromVp(cx, vp);
+    if (!GetAndCacheLocalTime(cx, obj, vp))
         return JS_FALSE;
 
-    if (JSDOUBLE_IS_FINITE(result))
-        result = HourFromTime(result);
-
-    vp->setNumber(result);
+    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
     return JS_TRUE;
 }
 
 static JSBool
 date_getUTCHours(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
 
@@ -1434,25 +1556,21 @@ date_getUTCHours(JSContext *cx, uintN ar
 
     vp->setNumber(result);
     return JS_TRUE;
 }
 
 static JSBool
 date_getMinutes(JSContext *cx, uintN argc, Value *vp)
 {
-    jsdouble result;
-
-    if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
+    JSObject *obj = ComputeThisFromVp(cx, vp);
+    if (!GetAndCacheLocalTime(cx, obj, vp))
         return JS_FALSE;
 
-    if (JSDOUBLE_IS_FINITE(result))
-        result = MinFromTime(result);
-
-    vp->setNumber(result);
+    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
     return JS_TRUE;
 }
 
 static JSBool
 date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
 
@@ -1466,25 +1584,21 @@ date_getUTCMinutes(JSContext *cx, uintN 
     return JS_TRUE;
 }
 
 /* Date.getSeconds is mapped to getUTCSeconds */
 
 static JSBool
 date_getUTCSeconds(JSContext *cx, uintN argc, Value *vp)
 {
-    jsdouble result;
-
-    if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result))
+    JSObject *obj = ComputeThisFromVp(cx, vp);
+    if (!GetAndCacheLocalTime(cx, obj, vp))
         return JS_FALSE;
 
-    if (JSDOUBLE_IS_FINITE(result))
-        result = SecFromTime(result);
-
-    vp->setNumber(result);
+    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
     return JS_TRUE;
 }
 
 /* Date.getMilliseconds is mapped to getUTCMilliseconds */
 
 static JSBool
 date_getUTCMilliseconds(JSContext *cx, uintN argc, Value *vp)
 {
@@ -1893,16 +2007,68 @@ date_toGMTString(JSContext *cx, uintN ar
 }
 
 static JSBool
 date_toISOString(JSContext *cx, uintN argc, Value *vp)
 {
     return date_utc_format(cx, vp, print_iso_string);
 }
 
+namespace {
+
+/* ES5 15.9.5.44. */
+JSBool
+date_toJSON(JSContext *cx, uintN argc, Value *vp)
+{
+    /* Step 1. */
+    JSObject *obj = ComputeThisFromVp(cx, vp);
+    if (!obj)
+        return false;
+
+    /* Step 2. */
+    Value &tv = vp[0];
+    if (!DefaultValue(cx, obj, JSTYPE_NUMBER, &tv))
+        return false;
+
+    /* Step 3. */
+    if (tv.isDouble() && !JSDOUBLE_IS_FINITE(tv.toDouble())) {
+        vp->setNull();
+        return true;
+    }
+
+    /* Step 4. */
+    Value &toISO = vp[0];
+    if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.toISOStringAtom), &toISO))
+        return false;
+
+    /* Step 5. */
+    if (!js_IsCallable(toISO)) {
+        JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
+                                     JSMSG_BAD_TOISOSTRING_PROP);
+        return false;
+    }
+
+    /* Step 6. */
+    LeaveTrace(cx);
+    InvokeArgsGuard args;
+    if (!cx->stack().pushInvokeArgs(cx, 0, args))
+        return false;
+
+    args.callee() = toISO;
+    args.thisv().setObject(*obj);
+
+    if (!Invoke(cx, args, 0))
+        return false;
+
+    *vp = args.rval();
+    return true;
+}
+
+}
+
 /* for Date.toLocaleString; interface to PRMJTime date struct.
  */
 static void
 new_explode(jsdouble timeval, PRMJTime *split, JSContext *cx)
 {
     jsint year = YearFromTime(timeval);
 
     split->tm_usec = (int32) msFromTime(timeval) * 1000;
@@ -2288,17 +2454,17 @@ static JSFunctionSpec date_methods[] = {
     JS_FN("toUTCString",         date_toGMTString,        0,0),
     JS_FN(js_toLocaleString_str, date_toLocaleString,     0,0),
     JS_FN("toLocaleDateString",  date_toLocaleDateString, 0,0),
     JS_FN("toLocaleTimeString",  date_toLocaleTimeString, 0,0),
     JS_FN("toLocaleFormat",      date_toLocaleFormat,     0,0),
     JS_FN("toDateString",        date_toDateString,       0,0),
     JS_FN("toTimeString",        date_toTimeString,       0,0),
     JS_FN("toISOString",         date_toISOString,        0,0),
-    JS_FN(js_toJSON_str,         date_toISOString,        0,0),
+    JS_FN(js_toJSON_str,         date_toJSON,             1,0),
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,       date_toSource,           0,0),
 #endif
     JS_FN(js_toString_str,       date_toString,           0,0),
     JS_FN(js_valueOf_str,        date_valueOf,            0,0),
     JS_FS_END
 };
 
--- a/js/src/jsdtracef.cpp
+++ b/js/src/jsdtracef.cpp
@@ -59,17 +59,19 @@ jsdtrace_fun_classname(const JSFunction 
     return (fun && !FUN_INTERPRETED(fun) && !(fun->flags & JSFUN_TRCINFO) && FUN_CLASP(fun))
            ? (char *)FUN_CLASP(fun)->name
            : dempty;
 }
 
 static char *
 jsdtrace_filename(JSStackFrame *fp)
 {
-    return (fp && fp->script && fp->script->filename) ? (char *)fp->script->filename : dempty;
+    return (fp && fp->hasScript() && fp->getScript()->filename)
+           ? (char *)fp->getScript()->filename
+           : dempty;
 }
 
 static int
 jsdtrace_fun_linenumber(JSContext *cx, const JSFunction *fun)
 {
     if (fun && FUN_INTERPRETED(fun))
         return (int) JS_GetScriptBaseLineNumber(cx, FUN_SCRIPT(fun));
 
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -2894,17 +2894,19 @@ EmitElemOp(JSContext *cx, JSParseNode *p
          * Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by
          * one or more index expression and JSOP_GETELEM op pairs.
          */
         if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {
             if (!BindNameToSlot(cx, cg, left))
                 return JS_FALSE;
             if (left->pn_op == JSOP_ARGUMENTS &&
                 JSDOUBLE_IS_INT32(next->pn_dval, &slot) &&
-                (jsuint)slot < JS_BIT(16)) {
+                jsuint(slot) < JS_BIT(16) &&
+                (!cg->inStrictMode() ||
+                 (!cg->mutatesParameter() && !cg->callsEval()))) {
                 /*
                  * arguments[i]() requires arguments object as "this".
                  * Check that we never generates list for that usage.
                  */
                 JS_ASSERT(op != JSOP_CALLELEM || next->pn_next);
                 left->pn_offset = next->pn_offset = top;
                 EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
                 left = next;
@@ -2968,17 +2970,19 @@ EmitElemOp(JSContext *cx, JSParseNode *p
         /* Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. */
         if (op == JSOP_GETELEM &&
             left->pn_type == TOK_NAME &&
             right->pn_type == TOK_NUMBER) {
             if (!BindNameToSlot(cx, cg, left))
                 return JS_FALSE;
             if (left->pn_op == JSOP_ARGUMENTS &&
                 JSDOUBLE_IS_INT32(right->pn_dval, &slot) &&
-                (jsuint)slot < JS_BIT(16)) {
+                jsuint(slot) < JS_BIT(16) &&
+                (!cg->inStrictMode() ||
+                 (!cg->mutatesParameter() && !cg->callsEval()))) {
                 left->pn_offset = right->pn_offset = top;
                 EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
                 return JS_TRUE;
             }
         }
 
         if (!js_EmitTree(cx, cg, left))
             return JS_FALSE;
@@ -3620,16 +3624,23 @@ js_EmitFunctionScript(JSContext *cx, JSC
         /*
          * Emit a trace hint opcode only if not in a generator, since generators
          * are not yet traced and both want to be the first instruction.
          */
         if (js_Emit1(cx, cg, JSOP_TRACE) < 0)
             return false;
     }
 
+    if (cg->needsEagerArguments()) {
+        CG_SWITCH_TO_PROLOG(cg);
+        if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
+            return false;
+        CG_SWITCH_TO_MAIN(cg);
+    }
+
     if (cg->flags & TCF_FUN_UNBRAND_THIS) {
         if (js_Emit1(cx, cg, JSOP_UNBRANDTHIS) < 0)
             return false;
     }
 
     return js_EmitTree(cx, cg, body) &&
            js_Emit1(cx, cg, JSOP_STOP) >= 0 &&
            js_NewScriptFromCG(cx, cg);
@@ -3696,17 +3707,17 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGe
         CG_SWITCH_TO_PROLOG(cg);
         if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
             return JS_FALSE;
         EMIT_INDEX_OP(prologOp, atomIndex);
         CG_SWITCH_TO_MAIN(cg);
     }
 
     if (JOF_OPTYPE(pn->pn_op) == JOF_LOCAL &&
-        !(cg->flags & TCF_FUN_USES_EVAL) &&
+        !(cg->flags & TCF_FUN_CALLS_EVAL) &&
         pn->pn_defn &&
         (((JSDefinition *)pn)->pn_dflags & PND_CLOSED))
     {
         CG_SWITCH_TO_PROLOG(cg);
         EMIT_UINT16_IMM_OP(JSOP_DEFUPVAR, pn->pn_cookie.asInteger());
         CG_SWITCH_TO_MAIN(cg);
     }
 
@@ -4531,17 +4542,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 #ifdef DEBUG
             JSLocalKind localKind =
 #endif
                 js_LookupLocal(cx, cg->fun, fun->atom, &slot);
             JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
             JS_ASSERT(index < JS_BIT(20));
             pn->pn_index = index;
             op = FUN_FLAT_CLOSURE(fun) ? JSOP_DEFLOCALFUN_FC : JSOP_DEFLOCALFUN;
-            if ((pn->pn_dflags & PND_CLOSED) && !(cg->flags & TCF_FUN_USES_EVAL)) {
+            if ((pn->pn_dflags & PND_CLOSED) && !(cg->flags & TCF_FUN_CALLS_EVAL)) {
                 CG_SWITCH_TO_PROLOG(cg);
                 EMIT_UINT16_IMM_OP(JSOP_DEFUPVAR, pn->pn_cookie.asInteger());
                 CG_SWITCH_TO_MAIN(cg);
             }
             if (!EmitSlotIndexOp(cx, op, slot, index, cg))
                 return JS_FALSE;
         }
         break;
--- a/js/src/jsemit.h
+++ b/js/src/jsemit.h
@@ -235,42 +235,44 @@ struct JSStmtInfo {
  * Flag to prevent a non-escaping function from being optimized into a null
  * closure (i.e., a closure that needs only its global object for free variable
  * resolution, thanks to JSOP_{GET,CALL}UPVAR), because this function contains
  * a closure that needs one or more scope objects surrounding it (i.e., Call
  * object for a heavyweight outer function). See bug 560234.
  */
 #define TCF_FUN_ENTRAINS_SCOPES 0x400000
 
-/*
- * Function uses eval.
- */
-#define TCF_FUN_USES_EVAL       0x800000
+/* The function calls 'eval'. */
+#define TCF_FUN_CALLS_EVAL       0x800000
+
+/* The function mutates a positional (non-destructuring) parameter. */
+#define TCF_FUN_MUTATES_PARAMETER 0x1000000
 
 /*
  * Compiling an eval() script.
  */
-#define TCF_COMPILE_FOR_EVAL   0x1000000
+#define TCF_COMPILE_FOR_EVAL     0x2000000
 
 /*
  * Flags to check for return; vs. return expr; in a function.
  */
 #define TCF_RETURN_FLAGS        (TCF_RETURN_EXPR | TCF_RETURN_VOID)
 
 /*
  * Sticky deoptimization flags to propagate from FunctionBody.
  */
 #define TCF_FUN_FLAGS           (TCF_FUN_SETS_OUTER_NAME |                    \
                                  TCF_FUN_USES_ARGUMENTS  |                    \
                                  TCF_FUN_PARAM_ARGUMENTS |                    \
                                  TCF_FUN_HEAVYWEIGHT     |                    \
                                  TCF_FUN_IS_GENERATOR    |                    \
                                  TCF_FUN_USES_OWN_NAME   |                    \
-                                 TCF_FUN_USES_EVAL       |                    \
                                  TCF_HAS_SHARPS          |                    \
+                                 TCF_FUN_CALLS_EVAL      |                    \
+                                 TCF_FUN_MUTATES_PARAMETER |                  \
                                  TCF_STRICT_MODE_CODE)
 
 struct JSTreeContext {              /* tree context for semantic checks */
     uint32          flags;          /* statement state flags, see above */
     uint16          ngvars;         /* max. no. of global variables/regexps */
     uint32          bodyid;         /* block number of program/function body */
     uint32          blockidGen;     /* preincremented block number generator */
     JSStmtInfo      *topStmt;       /* top of statement info stack */
@@ -332,44 +334,81 @@ struct JSTreeContext {              /* t
 
     uintN blockid() { return topStmt ? topStmt->blockid : bodyid; }
 
     bool atTopLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); }
 
     /* Test whether we're in a statement of given type. */
     bool inStatement(JSStmtType type);
 
+    bool inStrictMode() const {
+        return flags & TCF_STRICT_MODE_CODE;
+    }
+
     inline bool needStrictChecks();
 
     /* 
      * sharpSlotBase is -1 or first slot of pair for [sharpArray, sharpDepth].
      * The parser calls ensureSharpSlots to allocate these two stack locals.
      */
     int sharpSlotBase;
     bool ensureSharpSlots();
 
     js::Compiler *compiler() { return (js::Compiler *)parser; }
 
     // Return true there is a generator function within |skip| lexical scopes
     // (going upward) from this context's lexical scope. Always return true if
     // this context is itself a generator.
     bool skipSpansGenerator(unsigned skip);
 
-    bool compileAndGo() { return !!(flags & TCF_COMPILE_N_GO); }
-    bool inFunction() { return !!(flags & TCF_IN_FUNCTION); }
-    bool compiling() { return !!(flags & TCF_COMPILING); }
+    bool compileAndGo() const { return flags & TCF_COMPILE_N_GO; }
+    bool inFunction() const { return flags & TCF_IN_FUNCTION; }
+    bool compiling() const { return flags & TCF_COMPILING; }
+
+    bool usesArguments() const {
+        return flags & TCF_FUN_USES_ARGUMENTS;
+    }
+
+    void noteCallsEval() {
+        flags |= TCF_FUN_CALLS_EVAL;
+    }
+
+    bool callsEval() const {
+        JS_ASSERT(inFunction());
+        return flags & TCF_FUN_CALLS_EVAL;
+    }
+
+    void noteParameterMutation() {
+        JS_ASSERT(inFunction());
+        flags |= TCF_FUN_MUTATES_PARAMETER;
+    }
+
+    bool mutatesParameter() const {
+        JS_ASSERT(inFunction());
+        return flags & TCF_FUN_MUTATES_PARAMETER;
+    }
+
+    void noteArgumentsUse() {
+        JS_ASSERT(inFunction());
+        flags |= TCF_FUN_USES_ARGUMENTS;
+        if (funbox)
+            funbox->node->pn_dflags |= PND_FUNARG;
+    }
+
+    bool needsEagerArguments() const {
+        return inStrictMode() && ((usesArguments() && mutatesParameter()) || callsEval());
+    }
 };
 
 /*
  * Return true if we need to check for conditions that elicit
  * JSOPTION_STRICT warnings or strict mode errors.
  */
 inline bool JSTreeContext::needStrictChecks() {
-    return JS_HAS_STRICT_OPTION(parser->context) ||
-           (flags & TCF_STRICT_MODE_CODE);
+    return JS_HAS_STRICT_OPTION(parser->context) || inStrictMode();
 }
 
 /*
  * Span-dependent instructions are jumps whose span (from the jump bytecode to
  * the jump target) may require 2 or 4 bytes of immediate operand.
  */
 typedef struct JSSpanDep    JSSpanDep;
 typedef struct JSJumpTarget JSJumpTarget;
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -77,21 +77,28 @@
 #endif
 
 #if JS_HAS_XDR
 # include "jsxdrapi.h"
 #endif
 
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
+#include "jsfuninlines.h"
 #include "jsobjinlines.h"
 #include "jscntxtinlines.h"
 
 using namespace js;
 
+inline JSObject *
+JSObject::getThrowTypeError() const
+{
+    return &getGlobal()->getReservedSlot(JSRESERVED_GLOBAL_THROWTYPEERROR).toObject();
+}
+
 JSBool
 js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
 {
     JSObject *argsobj;
 
     if (fp->flags & JSFRAME_OVERRIDE_ARGS) {
         JS_ASSERT(fp->hasCallObj());
         jsid id = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
@@ -168,32 +175,35 @@ NewArguments(JSContext *cx, JSObject *pa
     if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
         return NULL;
 
     JSObject *argsobj = js_NewGCObject(cx);
     if (!argsobj)
         return NULL;
 
     /* Init immediately to avoid GC seeing a half-init'ed object. */
-    argsobj->init(&js_ArgumentsClass, proto, parent, PrivateValue(NULL));
-    argsobj->setArgsCallee(ObjectOrNullValue(callee));
+    bool strict = callee->getFunctionPrivate()->inStrictMode();
+    argsobj->init(strict ? &StrictArgumentsClass : &js_ArgumentsClass, proto, parent,
+                  PrivateValue(NULL));
     argsobj->setArgsLength(argc);
-
+    argsobj->setArgsCallee(ObjectValue(*callee));
     argsobj->map = cx->runtime->emptyArgumentsScope->hold();
 
     /* This must come after argsobj->map has been set. */
     if (!js_EnsureReservedSlots(cx, argsobj, argc))
         return NULL;
+
     return argsobj;
 }
 
 static void
 PutArguments(JSContext *cx, JSObject *argsobj, Value *args)
 {
-    uint32 argc = argsobj->getArgsLength();
+    JS_ASSERT(argsobj->isNormalArguments());
+    uint32 argc = argsobj->getArgsInitialLength();
     for (uint32 i = 0; i != argc; ++i) {
         if (!argsobj->getArgsElement(i).isMagic(JS_ARGS_HOLE))
             argsobj->setArgsElement(i, args[i]);
     }
 }
 
 JSObject *
 js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
@@ -215,72 +225,101 @@ js_GetArgsObject(JSContext *cx, JSStackF
         return fp->getArgsObj();
 
     /* Compute the arguments object's parent slot from fp's scope chain. */
     JSObject *global = fp->getScopeChain()->getGlobal();
     JSObject *argsobj = NewArguments(cx, global, fp->argc, &fp->argv[-2].toObject());
     if (!argsobj)
         return argsobj;
 
-    /* Link the new object to fp so it can get actual argument values. */
-    argsobj->setPrivate(fp);
+    /*
+     * Strict mode functions have arguments which copy the initial parameter
+     * values.  It is the caller's responsibility to get the arguments object
+     * before any parameters are modified!  (The emitter ensures this by
+     * synthesizing an arguments access at the start of any strict mode
+     * function which contains an assignment to a parameter or which calls
+     * eval.)  Non-strict mode arguments use the frame pointer to retrieve
+     * up-to-date parameter values.
+     */
+    if (argsobj->isStrictArguments()) {
+        JS_ASSERT_IF(fp->argc > 0, argsobj->dslots[-1].toPrivateUint32() >= fp->argc);
+        memcpy(argsobj->dslots, fp->argv, fp->argc * sizeof(Value));
+    } else {
+        argsobj->setPrivate(fp);
+    }
+
     fp->setArgsObj(argsobj);
     return argsobj;
 }
 
 void
 js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
 {
     JSObject *argsobj = fp->getArgsObj();
-    JS_ASSERT(argsobj->getPrivate() == fp);
-    PutArguments(cx, argsobj, fp->argv);
-    argsobj->setPrivate(NULL);
+    if (argsobj->isNormalArguments()) {
+        JS_ASSERT(argsobj->getPrivate() == fp);
+        PutArguments(cx, argsobj, fp->argv);
+        argsobj->setPrivate(NULL);
+    } else {
+        JS_ASSERT(!argsobj->getPrivate());
+    }
     fp->setArgsObj(NULL);
 }
 
 /*
  * Traced versions of js_GetArgsObject and js_PutArgsObject.
  */
 
 #ifdef JS_TRACER
 JSObject * JS_FASTCALL
 js_Arguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
 {
     JSObject *argsobj = NewArguments(cx, parent, argc, callee);
     if (!argsobj)
         return NULL;
-    argsobj->setPrivate(JS_ARGUMENT_OBJECT_ON_TRACE);
+
+    if (callee->getFunctionPrivate()->inStrictMode()) {
+        /*
+         * Strict mode callers must copy arguments into the created arguments
+         * object.
+         */
+        JS_ASSERT(!argsobj->getPrivate());
+    } else {
+        argsobj->setPrivate(JS_ARGUMENT_OBJECT_ON_TRACE);
+    }
+
     return argsobj;
 }
 #endif
 
 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_Arguments, CONTEXT, OBJECT, UINT32, OBJECT,
                      0, nanojit::ACCSET_STORE_ANY)
 
 /* FIXME change the return type to void. */
 JSBool JS_FASTCALL
 js_PutArguments(JSContext *cx, JSObject *argsobj, Value *args)
 {
+    JS_ASSERT(argsobj->isNormalArguments());
     JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENT_OBJECT_ON_TRACE);
     PutArguments(cx, argsobj, args);
     argsobj->setPrivate(NULL);
     return true;
 }
 
 JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArguments, CONTEXT, OBJECT, VALUEPTR, 0,
                      nanojit::ACCSET_STORE_ANY)
 
 static JSBool
 args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     JS_ASSERT(obj->isArguments());
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
-        if (arg < obj->getArgsLength())
+        if (arg < obj->getArgsInitialLength())
             obj->setArgsElement(arg, MagicValue(JS_ARGS_HOLE));
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         obj->setArgsLengthOverridden();
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
         obj->setArgsCallee(MagicValue(JS_ARGS_HOLE));
     }
     return true;
 }
@@ -473,29 +512,29 @@ ArgGetter(JSContext *cx, JSObject *obj, 
         return true;
 
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         uintN arg = uintN(JSID_TO_INT(id));
-        if (arg < obj->getArgsLength()) {
+        if (arg < obj->getArgsInitialLength()) {
             JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
             if (fp) {
                 *vp = fp->argv[arg];
             } else {
                 const Value &v = obj->getArgsElement(arg);
                 if (!v.isMagic(JS_ARGS_HOLE))
                     *vp = v;
             }
         }
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         if (!obj->isArgsLengthOverridden())
-            vp->setInt32(obj->getArgsLength());
+            vp->setInt32(obj->getArgsInitialLength());
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
         const Value &v = obj->getArgsCallee();
         if (!v.isMagic(JS_ARGS_HOLE)) {
             /*
              * If this function or one in it needs upvars that reach above it
              * in the scope chain, it must not be a null closure (it could be a
              * flat closure, or an unoptimized closure -- the latter itself not
@@ -528,82 +567,80 @@ ArgSetter(JSContext *cx, JSObject *obj, 
     }
 #endif
 
     if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL))
         return true;
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
-        if (arg < obj->getArgsLength()) {
+        if (arg < obj->getArgsInitialLength()) {
             JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
             if (fp) {
                 fp->argv[arg] = *vp;
                 return true;
             }
         }
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
                   JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
     }
 
     /*
      * For simplicity we use delete/set to replace the property with one
-     * backed by the default Object getter and setter. Note the we rely on
-     * args_delete to clear the corresponding reserved slot so the GC can
+     * backed by the default Object getter and setter. Note that we rely on
+     * args_delProperty to clear the corresponding reserved slot so the GC can
      * collect its value.
      */
     AutoValueRooter tvr(cx);
     return js_DeleteProperty(cx, obj, id, tvr.addr()) &&
            js_SetProperty(cx, obj, id, vp);
 }
 
 static JSBool
 args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
              JSObject **objp)
 {
-    JS_ASSERT(obj->isArguments());
+    JS_ASSERT(obj->isNormalArguments());
 
     *objp = NULL;
     bool valid = false;
+    uintN attrs = JSPROP_SHARED;
     if (JSID_IS_INT(id)) {
         uint32 arg = uint32(JSID_TO_INT(id));
-        if (arg < obj->getArgsLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
+        attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
+        if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
             valid = true;
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         if (!obj->isArgsLengthOverridden())
             valid = true;
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
         if (!obj->getArgsCallee().isMagic(JS_ARGS_HOLE))
             valid = true;
     }
 
     if (valid) {
-        /*
-         * XXX ECMA specs DontEnum even for indexed properties, contrary to
-         * other array-like objects.
-         */
         Value tmp = UndefinedValue();
-        if (!js_DefineProperty(cx, obj, id, &tmp, ArgGetter, ArgSetter, JSPROP_SHARED))
+        if (!js_DefineProperty(cx, obj, id, &tmp, ArgGetter, ArgSetter, attrs))
             return JS_FALSE;
         *objp = obj;
     }
     return true;
 }
 
 static JSBool
 args_enumerate(JSContext *cx, JSObject *obj)
 {
-    JS_ASSERT(obj->isArguments());
+    JS_ASSERT(obj->isNormalArguments());
 
     /*
      * Trigger reflection in args_resolve using a series of js_LookupProperty
      * calls.
      */
-    int argc = int(obj->getArgsLength());
+    int argc = int(obj->getArgsInitialLength());
     for (int i = -2; i != argc; i++) {
         jsid id = (i == -2)
                   ? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)
                   : (i == -1)
                   ? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom)
                   : INT_TO_JSID(i);
 
         JSObject *pobj;
@@ -613,16 +650,164 @@ args_enumerate(JSContext *cx, JSObject *
 
         /* prop is null when the property was deleted. */
         if (prop)
             pobj->dropProperty(cx, prop);
     }
     return true;
 }
 
+namespace {
+
+JSBool
+StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
+{
+    LeaveTrace(cx);
+
+    if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
+        return true;
+
+    if (JSID_IS_INT(id)) {
+        /*
+         * arg can exceed the number of arguments if a script changed the
+         * prototype to point to another Arguments object with a bigger argc.
+         */
+        uintN arg = uintN(JSID_TO_INT(id));
+        if (arg < obj->getArgsInitialLength()) {
+            const Value &v = obj->getArgsElement(arg);
+            if (!v.isMagic(JS_ARGS_HOLE))
+                *vp = v;
+        }
+    } else {
+        JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
+        if (!obj->isArgsLengthOverridden())
+            vp->setInt32(obj->getArgsInitialLength());
+    }
+    return true;
+}
+
+JSBool
+StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
+{
+    if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL))
+        return true;
+
+    if (JSID_IS_INT(id)) {
+        uintN arg = uintN(JSID_TO_INT(id));
+        if (arg < obj->getArgsInitialLength()) {
+            obj->setArgsElement(arg, *vp);
+            return true;
+        }
+    } else {
+        JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
+    }
+
+    /*
+     * For simplicity we use delete/set to replace the property with one
+     * backed by the default Object getter and setter. Note that we rely on
+     * args_delProperty to clear the corresponding reserved slot so the GC can
+     * collect its value.
+     */
+    AutoValueRooter tvr(cx);
+    return js_DeleteProperty(cx, obj, id, tvr.addr()) &&
+           js_SetProperty(cx, obj, id, vp);
+}
+
+JSBool
+strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
+{
+    JS_ASSERT(obj->isStrictArguments());
+
+    *objp = NULL;
+    bool valid = false;
+    uintN attrs = JSPROP_SHARED;
+    if (JSID_IS_INT(id)) {
+        uint32 arg = uint32(JSID_TO_INT(id));
+        attrs = JSPROP_SHARED | JSPROP_ENUMERATE;
+        if (arg < obj->getArgsInitialLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
+            valid = true;
+    } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
+        if (!obj->isArgsLengthOverridden())
+            valid = true;
+    } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
+        Value tmp = UndefinedValue();
+        PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError());
+        uintN attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
+        if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError, attrs))
+            return false;
+
+        *objp = obj;
+        return true;
+    } else if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
+        /*
+         * Strict mode arguments objects have an immutable poison-pill caller
+         * property that throws a TypeError on getting or setting.
+         */
+        PropertyOp throwTypeError = CastAsPropertyOp(obj->getThrowTypeError());
+        Value tmp = UndefinedValue();
+        if (!js_DefineProperty(cx, obj, id, &tmp, throwTypeError, throwTypeError,
+                               JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED)) {
+            return false;
+        }
+
+        *objp = obj;
+        return true;
+    }
+
+    if (valid) {
+        Value tmp = UndefinedValue();
+        if (!js_DefineProperty(cx, obj, id, &tmp, StrictArgGetter, StrictArgSetter, attrs))
+            return false;
+        *objp = obj;
+    }
+    return true;
+}
+
+JSBool
+strictargs_enumerate(JSContext *cx, JSObject *obj)
+{
+    JS_ASSERT(obj->isStrictArguments());
+
+    /*
+     * Trigger reflection in strictargs_resolve using a series of
+     * js_LookupProperty calls.  Beware deleted properties!
+     */
+    JSObject *pobj;
+    JSProperty *prop;
+
+    // length
+    if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop))
+        return false;
+    if (prop)
+        pobj->dropProperty(cx, prop);
+
+    // callee
+    if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop))
+        return false;
+    if (prop)
+        pobj->dropProperty(cx, prop);
+
+    // caller
+    if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop))
+        return false;
+    if (prop)
+        pobj->dropProperty(cx, prop);
+
+    for (uint32 i = 0, argc = obj->getArgsInitialLength(); i < argc; i++) {
+        if (!js_LookupProperty(cx, obj, INT_TO_JSID(i), &pobj, &prop))
+            return false;
+        if (prop)
+            pobj->dropProperty(cx, prop);
+    }
+
+    return true;
+}
+
+} // namespace
+
 #if JS_HAS_GENERATORS
 /*
  * If a generator's arguments or call object escapes, and the generator frame
  * is not executing, the generator object needs to be marked because it is not
  * otherwise reachable. An executing generator is rooted by its invocation.  To
  * distinguish the two cases (which imply different access paths to the
  * generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only
  * set on the JSStackFrame kept in the generator object's JSGenerator.
@@ -643,21 +828,24 @@ args_or_call_trace(JSTracer *trc, JSObje
         JS_CALL_OBJECT_TRACER(trc, obj, "generator object");
     }
 }
 #else
 # define args_or_call_trace NULL
 #endif
 
 /*
- * The Arguments class is not initialized via JS_InitClass, because arguments
+ * The Arguments classes aren't initialized via JS_InitClass, because arguments
  * objects have the initial value of Object.prototype as their [[Prototype]].
  * However, Object.prototype.toString.call(arguments) === "[object Arguments]"
- * per ES5 (although not ES3), so its class name is "Arguments" rather than
+ * per ES5 (although not ES3), so the class name is "Arguments" rather than
  * "Object".
+ */
+
+/*
  *
  * The JSClass functions below collaborate to lazily reflect and synchronize
  * actual argument values, argument count, and callee function object stored
  * in a JSStackFrame with their corresponding property values in the frame's
  * arguments object.
  */
 Class js_ArgumentsClass = {
     "Arguments",
@@ -676,16 +864,47 @@ Class js_ArgumentsClass = {
     NULL,           /* checkAccess */
     NULL,           /* call        */
     NULL,           /* construct   */
     NULL,           /* xdrObject   */
     NULL,           /* hasInstance */
     JS_CLASS_TRACE(args_or_call_trace)
 };
 
+namespace js {
+
+/*
+ * Strict mode arguments is significantly less magical than non-strict mode
+ * arguments, so it is represented by a different class while sharing some
+ * functionality.
+ */
+Class StrictArgumentsClass = {
+    "Arguments",
+    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
+    JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_FIXED_RESERVED_SLOTS) |
+    JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
+    PropertyStub,   /* addProperty */
+    args_delProperty,
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    strictargs_enumerate,
+    reinterpret_cast<JSResolveOp>(strictargs_resolve),
+    ConvertStub,
+    NULL,           /* finalize   */
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(args_or_call_trace)
+};
+
+}
+
 const uint32 JSSLOT_CALLEE =                    JSSLOT_PRIVATE + 1;
 const uint32 JSSLOT_CALL_ARGUMENTS =            JSSLOT_PRIVATE + 2;
 const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS =  2;
 
 /*
  * A Declarative Environment object stores its active JSStackFrame pointer in
  * its private slot, just as Call and Arguments objects do.
  */
@@ -1387,18 +1606,19 @@ fun_getProperty(JSContext *cx, JSObject 
 
     /*
      * Loop because getter and setter can be delegated from another class,
      * but loop only for FUN_LENGTH because we must pretend that f.length
      * is in each function instance f, per ECMA-262, instead of only in the
      * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
      * to make it appear so).
      *
-     * This code couples tightly to the attributes for lazy_function_props[]
-     * initializers above, and to js_SetProperty and js_HasOwnProperty.
+     * This code couples tightly to the attributes for lazyFunctionDataProps[]
+     * and poisonPillProps[] initializers below, and to js_SetProperty and
+     * js_HasOwnProperty.
      *
      * It's important to allow delegating objects, even though they inherit
      * this getter (fun_getProperty), to override arguments, arity, caller,
      * and name.  If we didn't return early for slot != FUN_LENGTH, we would
      * clobber *vp with the native property value, instead of letting script
      * override that value in delegating objects.
      *
      * Note how that clobbering is what simulates JSPROP_READONLY for all of
@@ -1468,50 +1688,71 @@ fun_getProperty(JSContext *cx, JSObject 
         if (fp && fp->hasFunction() && (uintN)slot < fp->getFunction()->nargs)
             *vp = fp->argv[slot];
         break;
     }
 
     return true;
 }
 
-struct LazyFunctionProp {
+namespace {
+
+struct LazyFunctionDataProp {
     uint16      atomOffset;
     int8        tinyid;
     uint8       attrs;
 };
 
-/* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */
-static LazyFunctionProp lazy_function_props[] = {
-    {ATOM_OFFSET(arguments), FUN_ARGUMENTS,  JSPROP_PERMANENT},
+struct PoisonPillProp {
+    uint16       atomOffset;
+    int8         tinyid;
+};
+
+/* NB: no sentinels at ends -- use JS_ARRAY_LENGTH to bound loops. */
+
+const LazyFunctionDataProp lazyFunctionDataProps[] = {
     {ATOM_OFFSET(arity),     FUN_ARITY,      JSPROP_PERMANENT},
-    {ATOM_OFFSET(caller),    FUN_CALLER,     JSPROP_PERMANENT},
     {ATOM_OFFSET(name),      FUN_NAME,       JSPROP_PERMANENT},
 };
 
+/* Properties censored into [[ThrowTypeError]] in strict mode. */
+const PoisonPillProp poisonPillProps[] = {
+    {ATOM_OFFSET(arguments), FUN_ARGUMENTS },
+    {ATOM_OFFSET(caller),    FUN_CALLER    },
+};
+
+}
+
 static JSBool
 fun_enumerate(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isFunction());
 
     jsval v;
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
     if (!JS_LookupPropertyById(cx, obj, id, &v))
         return false;
     id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
     if (!JS_LookupPropertyById(cx, obj, id, &v))
         return false;
 
-    for (uintN i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) {
-        LazyFunctionProp &lfp = lazy_function_props[i];
+    for (uintN i = 0; i < JS_ARRAY_LENGTH(lazyFunctionDataProps); i++) {
+        const LazyFunctionDataProp &lfp = lazyFunctionDataProps[i];
         id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, lfp.atomOffset));
         if (!JS_LookupPropertyById(cx, obj, id, &v))
             return false;
     }
 
+    for (uintN i = 0; i < JS_ARRAY_LENGTH(poisonPillProps); i++) {
+        const PoisonPillProp &p = poisonPillProps[i];
+        id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, p.atomOffset));
+        if (!JS_LookupPropertyById(cx, obj, id, &v))
+            return false;
+    }
+
     return true;
 }
 
 static JSBool
 fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
             JSObject **objp)
 {
     if (!JSID_IS_ATOM(id))
@@ -1577,18 +1818,18 @@ fun_resolve(JSContext *cx, JSObject *obj
                                      PropertyStub, PropertyStub,
                                      JSPROP_PERMANENT | JSPROP_READONLY, 0, 0, NULL)) {
             return JS_FALSE;
         }
         *objp = obj;
         return JS_TRUE;
     }
 
-    for (uintN i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) {
-        LazyFunctionProp *lfp = &lazy_function_props[i];
+    for (uintN i = 0; i < JS_ARRAY_LENGTH(lazyFunctionDataProps); i++) {
+        const LazyFunctionDataProp *lfp = &lazyFunctionDataProps[i];
 
         atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset);
         if (id == ATOM_TO_JSID(atom)) {
             JS_ASSERT(!IsInternalFunctionObject(obj));
 
             if (!js_DefineNativeProperty(cx, obj,
                                          ATOM_TO_JSID(atom), UndefinedValue(),
                                          fun_getProperty, PropertyStub,
@@ -1596,16 +1837,47 @@ fun_resolve(JSContext *cx, JSObject *obj
                                          lfp->tinyid, NULL)) {
                 return JS_FALSE;
             }
             *objp = obj;
             return JS_TRUE;
         }
     }
 
+    for (uintN i = 0; i < JS_ARRAY_LENGTH(poisonPillProps); i++) {
+        const PoisonPillProp &p = poisonPillProps[i];
+
+        atom = OFFSET_TO_ATOM(cx->runtime, p.atomOffset);
+        if (id == ATOM_TO_JSID(atom)) {
+            JS_ASSERT(!IsInternalFunctionObject(obj));
+
+            PropertyOp getter, setter;
+            uintN attrs = JSPROP_PERMANENT;
+            if (fun->inStrictMode()) {
+                JSObject *throwTypeError = obj->getThrowTypeError();
+
+                getter = CastAsPropertyOp(throwTypeError);
+                setter = CastAsPropertyOp(throwTypeError);
+                attrs |= JSPROP_GETTER | JSPROP_SETTER;
+            } else {
+                getter = fun_getProperty;
+                setter = PropertyStub;
+            }
+
+            if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), UndefinedValue(),
+                                         getter, setter,
+                                         attrs, JSScopeProperty::HAS_SHORTID,
+                                         p.tinyid, NULL)) {
+                return JS_FALSE;
+            }
+            *objp = obj;
+            return JS_TRUE;
+        }
+    }
+
     return JS_TRUE;
 }
 
 #if JS_HAS_XDR
 
 /* XXX store parent and proto, if defined */
 JSBool
 js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
@@ -2075,17 +2347,17 @@ js_fun_apply(JSContext *cx, uintN argc, 
      * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
      * original version of ES5).
      */
     JSObject *aobj = vp[3].toObject().wrappedObject(cx);
     jsuint length;
     if (aobj->isArray()) {
         length = aobj->getArrayLength();
     } else if (aobj->isArguments() && !aobj->isArgsLengthOverridden()) {
-        length = aobj->getArgsLength();
+        length = aobj->getArgsInitialLength();
     } else {
         Value &lenval = vp[0];
         if (!aobj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &lenval))
             return false;
 
         if (lenval.isInt32()) {
             length = jsuint(lenval.toInt32()); /* jsuint cast does ToUint32 */
         } else {
@@ -2395,30 +2667,53 @@ Function(JSContext *cx, JSObject *obj, u
         str = cx->runtime->emptyString;
     }
 
     return Compiler::compileFunctionBody(cx, fun, principals,
                                          str->chars(), str->length(),
                                          filename, lineno);
 }
 
+namespace {
+
+JSBool
+ThrowTypeError(JSContext *cx, uintN argc, Value *vp)
+{
+    JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
+                                 JSMSG_THROW_TYPE_ERROR);
+    return false;
+}
+
+}
+
 JSObject *
 js_InitFunctionClass(JSContext *cx, JSObject *obj)
 {
-    JSObject *proto;
-    JSFunction *fun;
-
-    proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
-                         NULL, function_methods, NULL, NULL);
+    JSObject *proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
+                                   NULL, function_methods, NULL, NULL);
     if (!proto)
         return NULL;
-    fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
+
+    JSFunction *fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
     if (!fun)
         return NULL;
     fun->u.i.script = JSScript::emptyScript();
+
+    if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
+        /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
+        JSObject *throwTypeError =
+            js_NewFunction(cx, NULL, reinterpret_cast<Native>(ThrowTypeError), 0,
+                           JSFUN_FAST_NATIVE, obj, NULL);
+        if (!throwTypeError)
+            return NULL;
+
+        JS_ALWAYS_TRUE(js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_THROWTYPEERROR,
+                                          ObjectValue(*throwTypeError)));
+    }
+
     return proto;
 }
 
 JSFunction *
 js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
                uintN flags, JSObject *parent, JSAtom *atom)
 {
     JSFunction *fun;
@@ -2605,55 +2900,36 @@ js_ValueToFunction(JSContext *cx, const 
         return NULL;
     }
     return GET_FUNCTION_PRIVATE(cx, funobj);
 }
 
 JSObject *
 js_ValueToFunctionObject(JSContext *cx, Value *vp, uintN flags)
 {
-    JSFunction *fun;
-    JSStackFrame *caller;
-    JSPrincipals *principals;
-
     JSObject *funobj;
-    if (IsFunctionObject(*vp, &funobj))
-        return funobj;
-
-    fun = js_ValueToFunction(cx, vp, flags);
-    if (!fun)
-        return NULL;
-    vp->setObject(*fun);
-
-    caller = js_GetScriptedCaller(cx, NULL);
-    if (caller) {
-        principals = JS_StackFramePrincipals(cx, caller);
-    } else {
-        /* No scripted caller, don't allow access. */
-        principals = NULL;
-    }
-
-    if (!js_CheckPrincipalsAccess(cx, FUN_OBJECT(fun), principals,
-                                  fun->atom
-                                  ? fun->atom
-                                  : cx->runtime->atomState.anonymousAtom)) {
+    if (!IsFunctionObject(*vp, &funobj)) {
+        js_ReportIsNotFunction(cx, vp, flags);
         return NULL;
     }
-    return FUN_OBJECT(fun);
+
+    return funobj;
 }
 
 JSObject *
 js_ValueToCallableObject(JSContext *cx, Value *vp, uintN flags)
 {
     if (vp->isObject()) {
         JSObject *callable = &vp->toObject();
         if (callable->isCallable())
             return callable;
     }
-    return js_ValueToFunctionObject(cx, vp, flags);
+
+    js_ReportIsNotFunction(cx, vp, flags);
+    return NULL;
 }
 
 void
 js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags)
 {
     const char *name = NULL, *source = NULL;
     AutoValueRooter tvr(cx);
     uintN error = (flags & JSV2F_CONSTRUCT) ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
@@ -3119,16 +3395,18 @@ js_FreezeLocalNames(JSContext *cx, JSFun
     if (n > MAX_ARRAY_LOCALS)
         JS_DHashMarkTableImmutable(&fun->u.i.names.map->names);
 #endif
 }
 
 JSAtom *
 JSFunction::findDuplicateFormal() const
 {
+    JS_ASSERT(isInterpreted());
+
     if (nargs <= 1)
         return NULL;
 
     /* Function with two to MAX_ARRAY_LOCALS parameters use an aray. */
     unsigned n = nargs + u.i.nvars + u.i.nupvars;
     if (n <= MAX_ARRAY_LOCALS) {
         jsuword *array = u.i.names.array;
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -179,16 +179,18 @@ struct JSFunction : public JSObject
     bool optimizedClosure()  const { return FUN_KIND(this) > JSFUN_INTERPRETED; }
     bool needsWrapper()      const { return FUN_NULL_CLOSURE(this) && u.i.skipmin != 0; }
     bool isInterpreted()     const { return FUN_INTERPRETED(this); }
     bool isFastNative()      const { return !!(flags & JSFUN_FAST_NATIVE); }
     bool isFastConstructor() const { return !!(flags & JSFUN_FAST_NATIVE_CTOR); }
     bool isHeavyweight()     const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
     unsigned minArgs()       const { return FUN_MINARGS(this); }
 
+    inline bool inStrictMode() const;
+
     uintN countVars() const {
         JS_ASSERT(FUN_INTERPRETED(this));
         return u.i.nvars;
     }
 
     /* uint16 representation bounds number of call object dynamic slots. */
     enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
 
@@ -273,34 +275,50 @@ JS_STATIC_ASSERT(sizeof(JSFunction) % JS
     JS_FN(name, JS_DATA_TO_FUNC_PTR(JSNative, trcinfo), nargs,                \
           (flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS | JSFUN_TRCINFO)
 #else
 # define JS_TN(name,fastcall,nargs,flags,trcinfo)                             \
     JS_FN(name, fastcall, nargs, flags)
 #endif
 
 /*
- * NB: the Arguments class is an uninitialized internal class that masquerades
- * (according to Object.prototype.toString.call(argsobj)) as "Object".
+ * NB: the Arguments classes are uninitialized internal classes that masquerade
+ * (according to Object.prototype.toString.call(arguments)) as "Arguments",
+ * while having Object.getPrototypeOf(arguments) === Object.prototype.
  *
  * WARNING (to alert embedders reading this private .h file): arguments objects
  * are *not* thread-safe and should not be used concurrently -- they should be
  * used by only one thread at a time, preferably by only one thread over their
  * lifetime (a JS worker that migrates from one OS thread to another but shares
  * nothing is ok).
  *
  * Yes, this is an incompatible change, which prefigures the impending move to
  * single-threaded objects and GC heaps.
  */
 extern js::Class js_ArgumentsClass;
+namespace js {
+extern Class StrictArgumentsClass;
+}
+
+inline bool
+JSObject::isNormalArguments() const
+{
+    return getClass() == &js_ArgumentsClass;
+}
+
+inline bool
+JSObject::isStrictArguments() const
+{
+    return getClass() == &js::StrictArgumentsClass;
+}
 
 inline bool
 JSObject::isArguments() const
 {
-    return getClass() == &js_ArgumentsClass;
+    return isNormalArguments() || isStrictArguments();
 }
 
 #define JS_ARGUMENT_OBJECT_ON_TRACE ((void *)0xa126)
 
 extern JS_PUBLIC_DATA(js::Class) js_CallClass;
 extern JS_PUBLIC_DATA(js::Class) js_FunctionClass;
 extern js::Class js_DeclEnvClass;
 extern const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS;
@@ -344,43 +362,46 @@ IsFunctionObject(const js::Value &v, JSO
 /*
  * Macro to access the private slot of the function object after the slot is
  * initialized.
  */
 #define GET_FUNCTION_PRIVATE(cx, funobj)                                      \
     (JS_ASSERT((funobj)->isFunction()),                                       \
      (JSFunction *) (funobj)->getPrivate())
 
+extern JSFunction *
+js_NewFunction(JSContext *cx, JSObject *funobj, js::Native native, uintN nargs,
+               uintN flags, JSObject *parent, JSAtom *atom);
+
 namespace js {
 
 /*
  * Return true if this is a compiler-created internal function accessed by
  * its own object. Such a function object must not be accessible to script
  * or embedding code.
  */
 inline bool
 IsInternalFunctionObject(JSObject *funobj)
 {
     JS_ASSERT(funobj->isFunction());
     JSFunction *fun = (JSFunction *) funobj->getPrivate();
     return funobj == fun && (fun->flags & JSFUN_LAMBDA) && !funobj->getParent();
 }
     
+extern JSString *
+fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent);
+
 } /* namespace js */
 
 extern JSObject *
 js_InitFunctionClass(JSContext *cx, JSObject *obj);
 
 extern JSObject *
 js_InitArgumentsClass(JSContext *cx, JSObject *obj);
 
-extern JSFunction *
-js_NewFunction(JSContext *cx, JSObject *funobj, js::Native native, uintN nargs,
-               uintN flags, JSObject *parent, JSAtom *atom);
-
 extern void
 js_TraceFunction(JSTracer *trc, JSFunction *fun);
 
 extern void
 js_FinalizeFunction(JSContext *cx, JSFunction *fun);
 
 extern JSObject * JS_FASTCALL
 js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
@@ -462,16 +483,26 @@ extern JSBool
 js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
 
 extern JSBool
 js_GetArgsValue(JSContext *cx, JSStackFrame *fp, js::Value *vp);
 
 extern JSBool
 js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, js::Value *vp);
 
+/*
+ * Get the arguments object for the given frame.  If the frame is strict mode
+ * code, its current arguments will be copied into the arguments object.
+ *
+ * NB: Callers *must* get the arguments object before any parameters are
+ *     mutated when the frame is strict mode code!  The emitter ensures this
+ *     occurs for strict mode functions containing syntax which might mutate a
+ *     named parameter by synthesizing an arguments access at the start of the
+ *     function.
+ */
 extern JSObject *
 js_GetArgsObject(JSContext *cx, JSStackFrame *fp);
 
 extern void
 js_PutArgsObject(JSContext *cx, JSStackFrame *fp);
 
 inline bool
 js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
@@ -484,19 +515,18 @@ js_IsNamedLambda(JSFunction *fun) { retu
  *
  * The thread's stack is the limiting factor for this number. It is currently
  * 2MB, which fits a little less than 2^19 arguments (once the stack frame,
  * callstack, etc. are included). Pick a max args length that is a little less.
  */
 const uint32 JS_ARGS_LENGTH_MAX = JS_BIT(19) - 1024;
 
 /*
- * JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as int jsval.
- * Thus (JS_ARGS_LENGTH_MAX << 1) | 1 must fit JSVAL_INT_MAX. To assert that
- * we check first that the shift does not overflow uint32.
+ * JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as an Int32
+ * Value.  Thus (JS_ARGS_LENGTH_MAX << 1) | 1 must be less than JSVAL_INT_MAX.
  */
 JS_STATIC_ASSERT(JS_ARGS_LENGTH_MAX <= JS_BIT(30));
 JS_STATIC_ASSERT(((JS_ARGS_LENGTH_MAX << 1) | 1) <= JSVAL_INT_MAX);
 
 extern JSBool
 js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp);
 
 typedef enum JSLocalKind {
@@ -550,16 +580,9 @@ extern void
 js_FreezeLocalNames(JSContext *cx, JSFunction *fun);
 
 extern JSBool
 js_fun_apply(JSContext *cx, uintN argc, js::Value *vp);
 
 extern JSBool
 js_fun_call(JSContext *cx, uintN argc, js::Value *vp);
 
-
-namespace js {
-
-extern JSString *
-fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent);
-
-}
 #endif /* jsfun_h___ */
new file mode 100644
--- /dev/null
+++ b/js/src/jsfuninlines.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * 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 ***** */
+
+#ifndef jsfuninlines_h___
+#define jsfuninlines_h___
+
+#include "jsfun.h"
+#include "jsscript.h"
+
+inline bool
+JSFunction::inStrictMode() const
+{
+    return isInterpreted() && u.i.script->strictModeCode;
+}
+
+#endif /* jsfuninlines_h___ */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1347,46 +1347,37 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp)
             continue;
         fprintf(fp,
                 "%s (thing size %lu, %lu things per arena)\n",
                 GC_ARENA_NAMES[i], UL(thingSize), UL(thingsPerArena));
     }
     fprintf(fp, "\nTOTAL STATS:\n");
     fprintf(fp, "            bytes allocated: %lu\n", UL(rt->gcBytes));
     fprintf(fp, "            total GC arenas: %lu\n", UL(sumArenas));
+    fprintf(fp, "       max allocated arenas: %lu\n", ULSTAT(maxnallarenas));
+    fprintf(fp, "       max allocated chunks: %lu\n", ULSTAT(maxnchunks));
     fprintf(fp, "            total GC things: %lu\n", UL(sumThings));
     fprintf(fp, "        max total GC things: %lu\n", UL(sumMaxThings));
     fprintf(fp, "        GC cell utilization: %.1f%%\n",
             PERCENT(sumThingSize, sumArenaCapacity));
     fprintf(fp, "   average cell utilization: %.1f%%\n",
             PERCENT(sumTotalThingSize, sumTotalArenaCapacity));
     fprintf(fp, "allocation retries after GC: %lu\n", UL(sumRetry));
     fprintf(fp, "             alloc attempts: %lu\n", UL(sumAlloc));
     fprintf(fp, "        alloc without locks: %lu  (%.1f%%)\n",
             UL(sumLocalAlloc), PERCENT(sumLocalAlloc, sumAlloc));
     fprintf(fp, "        allocation failures: %lu\n", UL(sumFail));
-    fprintf(fp, "         things born locked: %lu\n", ULSTAT(lockborn));
     fprintf(fp, "           valid lock calls: %lu\n", ULSTAT(lock));
     fprintf(fp, "         valid unlock calls: %lu\n", ULSTAT(unlock));
-    fprintf(fp, "       mark recursion depth: %lu\n", ULSTAT(depth));
-    fprintf(fp, "     maximum mark recursion: %lu\n", ULSTAT(maxdepth));
-    fprintf(fp, "     mark C recursion depth: %lu\n", ULSTAT(cdepth));
-    fprintf(fp, "   maximum mark C recursion: %lu\n", ULSTAT(maxcdepth));
     fprintf(fp, "      delayed tracing calls: %lu\n", ULSTAT(unmarked));
 #ifdef DEBUG
     fprintf(fp, "      max trace later count: %lu\n", ULSTAT(maxunmarked));
 #endif
     fprintf(fp, "potentially useful GC calls: %lu\n", ULSTAT(poke));
     fprintf(fp, "  thing arenas freed so far: %lu\n", ULSTAT(afree));
-    fprintf(fp, "     stack segments scanned: %lu\n", ULSTAT(stackseg));
-    fprintf(fp, "stack segment slots scanned: %lu\n", ULSTAT(segslots));
-    fprintf(fp, "reachable closeable objects: %lu\n", ULSTAT(nclose));
-    fprintf(fp, "    max reachable closeable: %lu\n", ULSTAT(maxnclose));
-    fprintf(fp, "      scheduled close hooks: %lu\n", ULSTAT(closelater));
-    fprintf(fp, "  max scheduled close hooks: %lu\n", ULSTAT(maxcloselater));
     rt->gcStats.conservative.dump(fp);
 
 #undef UL
 #undef ULSTAT
 #undef PERCENT
 }
 #endif
 
@@ -1642,20 +1633,18 @@ RefillFinalizableFreeList(JSContext *cx,
     JS_ASSERT(!JS_THREAD_DATA(cx)->gcFreeLists.finalizables[thingKind]);
     JSRuntime *rt = cx->runtime;
     JSGCArenaList *arenaList;
     JSGCArena *a;
 
     {
         AutoLockGC lock(rt);
         JS_ASSERT(!rt->gcRunning);
-        if (rt->gcRunning) {
-            METER(rt->gcStats.finalfail++);
+        if (rt->gcRunning)
             return NULL;
-        }
 
         bool canGC = !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota;
         bool doGC = canGC && IsGCThresholdReached(rt);
         arenaList = &rt->gcArenaList[thingKind];
         for (;;) {
             if (doGC) {
                 LastDitchGC(cx);
                 METER(cx->runtime->gcStats.arenaStats[thingKind].retry++);
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -551,38 +551,26 @@ struct JSGCArenaStats {
     uint32  newarenas;      /* new arenas allocated before the last GC */
     uint32  livearenas;     /* number of live arenas after the last GC */
     uint32  maxarenas;      /* maximum of allocated arenas */
     uint32  totalarenas;    /* total number of arenas with live things that
                                GC scanned so far */
 };
 
 struct JSGCStats {
-    uint32  finalfail;  /* finalizer calls allocator failures */
-    uint32  lockborn;   /* things born locked */
     uint32  lock;       /* valid lock calls */
     uint32  unlock;     /* valid unlock calls */
-    uint32  depth;      /* mark tail recursion depth */
-    uint32  maxdepth;   /* maximum mark tail recursion depth */
-    uint32  cdepth;     /* mark recursion depth of C functions */
-    uint32  maxcdepth;  /* maximum mark recursion depth of C functions */
     uint32  unmarked;   /* number of times marking of GC thing's children were
                            delayed due to a low C stack */
 #ifdef DEBUG
     uint32  maxunmarked;/* maximum number of things with children to mark
                            later */
 #endif
     uint32  poke;           /* number of potentially useful GC calls */
     uint32  afree;          /* thing arenas freed so far */
-    uint32  stackseg;       /* total extraordinary stack segments scanned */
-    uint32  segslots;       /* total stack segment value slots scanned */
-    uint32  nclose;         /* number of objects with close hooks */
-    uint32  maxnclose;      /* max number of objects with close hooks */
-    uint32  closelater;     /* number of close hooks scheduled to run */
-    uint32  maxcloselater;  /* max number of close hooks scheduled to run */
     uint32  nallarenas;     /* number of all allocated arenas */
     uint32  maxnallarenas;  /* maximum number of all allocated arenas */
     uint32  nchunks;        /* number of allocated chunks */
     uint32  maxnchunks;     /* maximum number of allocated chunks */
 
     JSGCArenaStats  arenaStats[FINALIZE_LIMIT];
 
     js::ConservativeGCStats conservative;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -4142,17 +4142,17 @@ BEGIN_CASE(JSOP_LENGTH)
     if (vp->isString()) {
         vp->setInt32(vp->toString()->length());
     } else if (vp->isObject()) {
         JSObject *obj = &vp->toObject();
         if (obj->isArray()) {
             jsuint length = obj->getArrayLength();
             regs.sp[-1].setNumber(length);
         } else if (obj->isArguments() && !obj->isArgsLengthOverridden()) {
-            uint32 length = obj->getArgsLength();
+            uint32 length = obj->getArgsInitialLength();
             JS_ASSERT(length < INT32_MAX);
             regs.sp[-1].setInt32(int32_t(length));
         } else {
             i = -2;
             goto do_getprop_with_lval;
         }
     } else {
         i = -2;
@@ -4513,17 +4513,17 @@ BEGIN_CASE(JSOP_GETELEM)
                     goto end_getelem;
 
                 /* Reload retval from the stack in the rare hole case. */
                 copyFrom = &regs.sp[-1];
             }
         } else if (obj->isArguments()) {
             uint32 arg = uint32(i);
 
-            if (arg < obj->getArgsLength()) {
+            if (arg < obj->getArgsInitialLength()) {
                 JSStackFrame *afp = (JSStackFrame *) obj->getPrivate();
                 if (afp) {
                     copyFrom = &afp->argv[arg];
                     goto end_getelem;
                 }
 
                 copyFrom = obj->addressOfArgsElement(arg);
                 if (!copyFrom->isMagic())
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1019,20 +1019,23 @@ obj_eval(JSContext *cx, uintN argc, Valu
      *   check.
      */
     Value *argv = JS_ARGV(cx, vp);
     JSObject *obj = ComputeThisFromVp(cx, vp);
     if (!obj)
         return JS_FALSE;
     obj = obj->wrappedObject(cx);
 
+    OBJ_TO_INNER_OBJECT(cx, obj);
+    if (!obj)
+        return JS_FALSE;
+
     /*
-     * Ban all indirect uses of eval (global.foo = eval; global.foo(...)) and
-     * calls that attempt to use a non-global object as the "with" object in
-     * the former indirect case.
+     * Ban indirect uses of eval (nonglobal.eval = eval; nonglobal.eval(....))
+     * that attempt to use a non-global object as the scope object.
      */
     {
         JSObject *parent = obj->getParent();
         if (indirectCall || parent) {
             uintN flags = parent
                           ? JSREPORT_ERROR
                           : JSREPORT_STRICT | JSREPORT_WARNING;
             if (!JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, NULL,
@@ -1081,20 +1084,16 @@ obj_eval(JSContext *cx, uintN argc, Valu
      * If we see an indirect call, then run eval in the global scope. We do
      * this so the compiler can make assumptions about what bindings may or
      * may not exist in the current frame if it doesn't see 'eval'.
      */
     if (indirectCall) {
         /* Pretend that we're top level. */
         staticLevel = 0;
 
-        OBJ_TO_INNER_OBJECT(cx, obj);
-        if (!obj)
-            return JS_FALSE;
-
         if (!js_CheckPrincipalsAccess(cx, obj,
                                       JS_StackFramePrincipals(cx, caller),
                                       cx->runtime->atomState.evalAtom)) {
             return JS_FALSE;
         }
 
         /* NB: We know inner is a global object here. */
         JS_ASSERT(!obj->getParent());
@@ -6043,19 +6042,19 @@ JSObject::wrappedObject(JSContext *cx) c
     if (JSObjectOp op = getClass()->ext.wrappedObject) {
         if (JSObject *obj = op(cx, const_cast<JSObject *>(this)))
             return obj;
     }
     return const_cast<JSObject *>(this);
 }
 
 JSObject *
-JSObject::getGlobal()
-{
-    JSObject *obj = this;
+JSObject::getGlobal() const
+{
+    JSObject *obj = const_cast<JSObject *>(this);
     while (JSObject *parent = obj->getParent())
         obj = parent;
     return obj;
 }
 
 JSBool
 js_ReportGetterOnlyAssignment(JSContext *cx)
 {
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -416,17 +416,17 @@ struct JSObject {
 #ifdef DEBUG
         for (JSObject *obj = newParent; obj; obj = obj->getParent())
             JS_ASSERT(obj != this);
 #endif
         setDelegateNullSafe(newParent);
         parent = newParent;
     }
 
-    JSObject *getGlobal();
+    JSObject *getGlobal() const;
 
     void *getPrivate() const {
         JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
         void *priv = fslots[JSSLOT_PRIVATE].toPrivate();
         return priv;
     }
 
     void setPrivate(void *data) {
@@ -495,56 +495,82 @@ struct JSObject {
 
   private:
     /*
      * Reserved slot structure for Arguments objects:
      *
      * JSSLOT_PRIVATE       - the corresponding frame until the frame exits.
      * JSSLOT_ARGS_LENGTH   - the number of actual arguments and a flag
      *                        indicating whether arguments.length was
-     *                        overwritten.
+     *                        overwritten.  This slot is not used to represent
+     *                        arguments.length after that property has been
+     *                        assigned, even if the new value is integral: it's
+     *                        always the original length.
      * JSSLOT_ARGS_CALLEE   - the arguments.callee value or JSVAL_HOLE if that
      *                        was overwritten.
      *
      * Argument index i is stored in dslots[i], accessible via
      * {get,set}ArgsElement().
      */
     static const uint32 JSSLOT_ARGS_CALLEE = JSSLOT_PRIVATE + 2;
 
   public:
     /* Number of extra fixed slots besides JSSLOT_PRIVATE. */
     static const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1;
     static const uint32 ARGS_FIXED_RESERVED_SLOTS = 2;
 
-    inline uint32 getArgsLength() const;
+    /* Lower-order bit stolen from the length slot. */
+    static const uint32 ARGS_LENGTH_OVERRIDDEN_BIT = 0x1;
+    static const uint32 ARGS_PACKED_BITS_COUNT = 1;
+
+    /*
+     * Set the initial length of the arguments, and mark it as not overridden.
+     */
     inline void setArgsLength(uint32 argc);
+
+    /*
+     * Return the initial length of the arguments.  This may differ from the
+     * current value of arguments.length!
+     */
+    inline uint32 getArgsInitialLength() const;
+
     inline void setArgsLengthOverridden();
     inline bool isArgsLengthOverridden() const;
 
     inline const js::Value &getArgsCallee() const;
     inline void setArgsCallee(const js::Value &callee);
 
     inline const js::Value &getArgsElement(uint32 i) const;
     inline js::Value *addressOfArgsElement(uint32 i) const;
     inline void setArgsElement(uint32 i, const js::Value &v);
 
     /*
      * Date-specific getters and setters.
      */
 
-  private:
-    // The second slot caches the local time;  it's initialized to NaN.
-    static const uint32 JSSLOT_DATE_UTC_TIME   = JSSLOT_PRIVATE;
-    static const uint32 JSSLOT_DATE_LOCAL_TIME = JSSLOT_PRIVATE + 1;
+  public:
+    static const uint32 JSSLOT_DATE_UTC_TIME = JSSLOT_PRIVATE;
+
+    /*
+     * Cached slots holding local properties of the date.
+     * These are undefined until the first actual lookup occurs
+     * and are reset to undefined whenever the date's time is modified.
+     */
+    static const uint32 JSSLOT_DATE_COMPONENTS_START = JSSLOT_PRIVATE + 1;
 
-  public:
-    static const uint32 DATE_FIXED_RESERVED_SLOTS = 2;
+    static const uint32 JSSLOT_DATE_LOCAL_TIME = JSSLOT_PRIVATE + 1;
+    static const uint32 JSSLOT_DATE_LOCAL_YEAR = JSSLOT_PRIVATE + 2;
+    static const uint32 JSSLOT_DATE_LOCAL_MONTH = JSSLOT_PRIVATE + 3;
+    static const uint32 JSSLOT_DATE_LOCAL_DATE = JSSLOT_PRIVATE + 4;
+    static const uint32 JSSLOT_DATE_LOCAL_DAY = JSSLOT_PRIVATE + 5;
+    static const uint32 JSSLOT_DATE_LOCAL_HOURS = JSSLOT_PRIVATE + 6;
+    static const uint32 JSSLOT_DATE_LOCAL_MINUTES = JSSLOT_PRIVATE + 7;
+    static const uint32 JSSLOT_DATE_LOCAL_SECONDS = JSSLOT_PRIVATE + 8;
 
-    inline const js::Value &getDateLocalTime() const;
-    inline void setDateLocalTime(const js::Value &pthis);
+    static const uint32 DATE_CLASS_RESERVED_SLOTS = 9;
 
     inline const js::Value &getDateUTCTime() const;
     inline void setDateUTCTime(const js::Value &pthis);
 
     /*
      * Function-specific getters and setters.
      */
 
@@ -555,16 +581,18 @@ struct JSObject {
     static const uint32 JSSLOT_FUN_METHOD_OBJ  = JSSLOT_PRIVATE + 2;
 
   public:
     static const uint32 FUN_FIXED_RESERVED_SLOTS = 2;
 
     inline bool hasMethodObj(const JSObject& obj) const;
     inline void setMethodObj(JSObject& obj);
 
+    inline JSFunction *getFunctionPrivate() const;
+
     /*
      * RegExp-specific getters and setters.
      */
 
   private:
     static const uint32 JSSLOT_REGEXP_LAST_INDEX = JSSLOT_PRIVATE + 1;
 
   public:
@@ -726,21 +754,25 @@ struct JSObject {
     }
 
     static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
 
     inline void dropProperty(JSContext *cx, JSProperty *prop);
 
     JS_FRIEND_API(JSCompartment *) getCompartment(JSContext *cx);
 
+    inline JSObject *getThrowTypeError() const;
+
     void swap(JSObject *obj);
 
     inline bool canHaveMethodBarrier() const;
 
     inline bool isArguments() const;
+    inline bool isNormalArguments() const;
+    inline bool isStrictArguments() const;
     inline bool isArray() const;
     inline bool isDenseArray() const;
     inline bool isSlowArray() const;
     inline bool isNumber() const;
     inline bool isBoolean() const;
     inline bool isString() const;
     inline bool isPrimitive() const;
     inline bool isDate() const;
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -215,42 +215,43 @@ JSObject::voidDenseOnlyArraySlots()
     fslots[JSSLOT_DENSE_ARRAY_CAPACITY].setUndefined();
 }
 
 inline void
 JSObject::setArgsLength(uint32 argc)
 {
     JS_ASSERT(isArguments());
     JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
-    fslots[JSSLOT_ARGS_LENGTH].setInt32(argc << 1);
+    JS_ASSERT(UINT32_MAX > (uint64(argc) << ARGS_PACKED_BITS_COUNT));
+    fslots[JSSLOT_ARGS_LENGTH].setInt32(argc << ARGS_PACKED_BITS_COUNT);
     JS_ASSERT(!isArgsLengthOverridden());
 }
 
 inline uint32
-JSObject::getArgsLength() const
+JSObject::getArgsInitialLength() const
 {
     JS_ASSERT(isArguments());
-    uint32 argc = uint32(fslots[JSSLOT_ARGS_LENGTH].toInt32()) >> 1;
+    uint32 argc = uint32(fslots[JSSLOT_ARGS_LENGTH].toInt32()) >> ARGS_PACKED_BITS_COUNT;
     JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
     return argc;
 }
 
 inline void
 JSObject::setArgsLengthOverridden()
 {
     JS_ASSERT(isArguments());
-    fslots[JSSLOT_ARGS_LENGTH].getInt32Ref() |= 1;
+    fslots[JSSLOT_ARGS_LENGTH].getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT;
 }
 
 inline bool
 JSObject::isArgsLengthOverridden() const
 {
     JS_ASSERT(isArguments());
     const js::Value &v = fslots[JSSLOT_ARGS_LENGTH];
-    return (v.toInt32() & 1) != 0;
+    return v.toInt32() & ARGS_LENGTH_OVERRIDDEN_BIT;
 }
 
 inline const js::Value & 
 JSObject::getArgsCallee() const
 {
     JS_ASSERT(isArguments());
     return fslots[JSSLOT_ARGS_CALLEE];
 }
@@ -282,30 +283,16 @@ inline void
 JSObject::setArgsElement(uint32 i, const js::Value &v)
 {
     JS_ASSERT(isArguments());
     JS_ASSERT(i < numSlots() - JS_INITIAL_NSLOTS);
     dslots[i] = v;
 }
 
 inline const js::Value &
-JSObject::getDateLocalTime() const
-{
-    JS_ASSERT(isDate());
-    return fslots[JSSLOT_DATE_LOCAL_TIME];
-}
-
-inline void 
-JSObject::setDateLocalTime(const js::Value &time)
-{
-    JS_ASSERT(isDate());
-    fslots[JSSLOT_DATE_LOCAL_TIME] = time;
-}
-
-inline const js::Value &
 JSObject::getDateUTCTime() const
 {
     JS_ASSERT(isDate());
     return fslots[JSSLOT_DATE_UTC_TIME];
 }
 
 inline void 
 JSObject::setDateUTCTime(const js::Value &time)
@@ -322,16 +309,23 @@ JSObject::hasMethodObj(const JSObject& o
 }
 
 inline void
 JSObject::setMethodObj(JSObject& obj)
 {
     fslots[JSSLOT_FUN_METHOD_OBJ].setObject(obj);
 }
 
+inline JSFunction *
+JSObject::getFunctionPrivate() const
+{
+    JS_ASSERT(isFunction());
+    return reinterpret_cast<JSFunction *>(getPrivate());
+}
+
 inline NativeIterator *
 JSObject::getNativeIterator() const
 {
     return (NativeIterator *) getPrivate();
 }
 
 inline void
 JSObject::setNativeIterator(NativeIterator *ni)
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -235,26 +235,24 @@ public:
             Class *clasp = obj.getClass();
             if (clasp == &js_NumberClass || clasp == &js_StringClass)
                 *gapValue.addr() = obj.getPrimitiveThis();
         }
 
         if (gapValue.value().isString()) {
             if (!js_ValueToCharBuffer(cx, gapValue.value(), gap))
                 return false;
-            if (cb.length() > 10)
-                cb.resize(10);
-        }
-
-        if (gapValue.value().isNumber()) {
+            if (gap.length() > 10)
+                gap.resize(10);
+        } else if (gapValue.value().isNumber()) {
             jsdouble d = gapValue.value().isInt32()
                          ? gapValue.value().toInt32()
                          : js_DoubleToInteger(gapValue.value().toDouble());
             d = JS_MIN(10, d);
-            if (d >= 1 && !cb.appendN(' ', uint32(d)))
+            if (d >= 1 && !gap.appendN(' ', uint32(d)))
                 return false;
         }
 
         return true;
     }
 
     bool initializeStack() {
         return objectStack.init(16);
@@ -341,33 +339,33 @@ JO(JSContext *cx, Value *vp, StringifyCo
     // if the replacer is an array, we use the keys from it
     if (scx->replacer && JS_IsArrayObject(cx, scx->replacer)) {
         usingWhitelist = true;
         vec[2].setObject(*scx->replacer);
         keySource = &vec[2];
     }
 
     JSBool memberWritten = JS_FALSE;
-    AutoIdArray ida(cx, JS_Enumerate(cx, &keySource->toObject()));
-    if (!ida)
+    AutoIdVector props(cx);
+    if (!GetPropertyNames(cx, &keySource->toObject(), JSITER_OWNONLY, props))
         return JS_FALSE;
 
-    for (jsint i = 0, len = ida.length(); i < len; i++) {
+    for (size_t i = 0, len = props.length(); i < len; i++) {
         outputValue.setUndefined();
 
         if (!usingWhitelist) {
-            if (!js_ValueToStringId(cx, IdToValue(ida[i]), &id))
+            if (!js_ValueToStringId(cx, IdToValue(props[i]), &id))
                 return JS_FALSE;
         } else {
             // skip non-index properties
             jsuint index = 0;
-            if (!js_IdIsIndex(ida[i], &index))
+            if (!js_IdIsIndex(props[i], &index))
                 continue;
 
-            if (!scx->replacer->getProperty(cx, ida[i], &whitelistElement))
+            if (!scx->replacer->getProperty(cx, props[i], &whitelistElement))
                 return JS_FALSE;
 
             if (!js_ValueToStringId(cx, whitelistElement, &id))
                 return JS_FALSE;
         }
 
         // We should have a string id by this point. Either from 
         // JS_Enumerate's id array, or by converting an element
@@ -404,16 +402,17 @@ JO(JSContext *cx, Value *vp, StringifyCo
         if (!s)
             return JS_FALSE;
 
         const jschar *chars;
         size_t length;
         s->getCharsAndLength(chars, length);
         if (!write_string(cx, scx->cb, chars, length) ||
             !scx->cb.append(':') ||
+            !(scx->gap.empty() || scx->cb.append(' ')) ||
             !Str(cx, id, obj, scx, &outputValue, true)) {
             return JS_FALSE;
         }
     }
 
     if (memberWritten && !WriteIndent(cx, scx, scx->depth - 1))
         return JS_FALSE;
 
@@ -613,22 +612,22 @@ Walk(JSContext *cx, jsid id, JSObject *h
 
                 if (!Walk(cx, index, obj, reviver, propValue.addr()))
                     return false;
 
                 if (!obj->defineProperty(cx, index, propValue.value(), NULL, NULL, JSPROP_ENUMERATE))
                     return false;
             }
         } else {
-            AutoIdArray ida(cx, JS_Enumerate(cx, obj));
-            if (!ida)
+            AutoIdVector props(cx);
+            if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, props))
                 return false;
 
-            for (jsint i = 0, len = ida.length(); i < len; i++) {
-                jsid idName = ida[i];
+            for (size_t i = 0, len = props.length(); i < len; i++) {
+                jsid idName = props[i];
                 if (!Walk(cx, idName, obj, reviver, propValue.addr()))
                     return false;
                 if (propValue.value().isUndefined()) {
                     if (!js_DeleteProperty(cx, obj, idName, propValue.addr()))
                         return false;
                 } else {
                     if (!obj->defineProperty(cx, idName, propValue.value(), NULL, NULL,
                                              JSPROP_ENUMERATE)) {
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -5431,21 +5431,25 @@ SimulateOp(JSContext *cx, JSScript *scri
 #undef LOCAL_ASSERT
 #define LOCAL_ASSERT(expr)      LOCAL_ASSERT_CUSTOM(expr, goto failure);
 
 static intN
 SimulateImacroCFG(JSContext *cx, JSScript *script,
                   uintN pcdepth, jsbytecode *pc, jsbytecode *target,
                   jsbytecode **pcstack)
 {
-    size_t nbytes = StackDepth(script) * sizeof *pcstack;
-    jsbytecode** tmp_pcstack = (jsbytecode **) cx->malloc(nbytes);
-    if (!tmp_pcstack)
-        return -1;
-    memcpy(tmp_pcstack, pcstack, nbytes);
+    size_t nbytes;
+    jsbytecode** tmp_pcstack = NULL;
+    if (pcstack) {
+        nbytes = StackDepth(script) * sizeof *pcstack;
+        tmp_pcstack = (jsbytecode **) cx->malloc(nbytes);
+        if (!tmp_pcstack)
+            return -1;
+        memcpy(tmp_pcstack, pcstack, nbytes);
+    }
 
     ptrdiff_t oplen;
     for (; pc < target; pc += oplen) {
         JSOp op = js_GetOpcode(cx, script, pc);
         const JSCodeSpec *cs = &js_CodeSpec[op];
         oplen = cs->length;
         if (oplen < 0)
             oplen = js_GetVariableBytecodeLength(pc);
@@ -5471,22 +5475,25 @@ SimulateImacroCFG(JSContext *cx, JSScrip
     }
 
     if (pc > target)
         goto failure;
 
     LOCAL_ASSERT(pc == target);
 
   success:
-    memcpy(pcstack, tmp_pcstack, nbytes);
-    cx->free(tmp_pcstack);
+    if (tmp_pcstack) {
+        memcpy(pcstack, tmp_pcstack, nbytes);
+        cx->free(tmp_pcstack);
+    }
     return pcdepth;
 
   failure:
-    cx->free(tmp_pcstack);
+    if (tmp_pcstack)
+        cx->free(tmp_pcstack);
     return -1;
 }
 
 #undef LOCAL_ASSERT
 #define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, -1);
 
 static intN
 ReconstructImacroPCStack(JSContext *cx, JSScript *script,
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -1186,18 +1186,17 @@ CheckFinalReturn(JSContext *cx, JSTreeCo
 
 /*
  * Check that it is permitted to assign to lhs.  Strict mode code may not
  * assign to 'eval' or 'arguments'.
  */
 bool
 CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs)
 {
-    if (tc->needStrictChecks() &&
-        lhs->pn_type == TOK_NAME) {
+    if (tc->needStrictChecks() && lhs->pn_type == TOK_NAME) {
         JSAtom *atom = lhs->pn_atom;
         JSAtomState *atomState = &cx->runtime->atomState;
         if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) {
             const char *name = js_AtomToPrintableString(cx, atom);
             if (!name ||
                 !ReportStrictModeError(cx, TS(tc->parser), tc, lhs, JSMSG_DEPRECATED_ASSIGN,
                                        name)) {
                 return false;
@@ -1217,19 +1216,19 @@ bool
 CheckStrictBinding(JSContext *cx, JSTreeContext *tc, JSAtom *atom, JSParseNode *pn)
 {
     if (!tc->needStrictChecks())
         return true;
 
     JSAtomState *atomState = &cx->runtime->atomState;
     if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) {
         const char *name = js_AtomToPrintableString(cx, atom);
-        if (name)
-            ReportStrictModeError(cx, TS(tc->parser), tc, pn, JSMSG_BAD_BINDING, name);
-        return false;
+        if (!name)
+            return false;
+        return ReportStrictModeError(cx, TS(tc->parser), tc, pn, JSMSG_BAD_BINDING, name);
     }
     return true;
 }
 
 /*
  * In strict mode code, all formal parameter names must be distinct. If fun's
  * formals are legit given fun's strictness level, return true. Otherwise,
  * report an error and return false. Use pn for error position reporting,
@@ -2524,17 +2523,17 @@ LeaveFunction(JSParseNode *fn, JSTreeCon
             }
 
             JSAtomListElement *outer_ale = tc->decls.lookup(atom);
 
             /*
              * Make sure to deoptimize lexical dependencies that are polluted
              * by eval or with, to safely statically bind globals (see bug 561923).
              */
-            if ((funtc->flags & TCF_FUN_USES_EVAL) ||
+            if ((funtc->flags & TCF_FUN_CALLS_EVAL) ||
                 (outer_ale && tc->innermostWith &&
                  ALE_DEFN(outer_ale)->pn_pos < tc->innermostWith->pn_pos)) {
                 DeoptimizeUsesWithin(dn, fn->pn_pos);
             }
 
             JSDefinition *outer_dn;
 
             if (!outer_ale)
@@ -2603,80 +2602,198 @@ LeaveFunction(JSParseNode *fn, JSTreeCon
                 funtc->lexdeps.remove(tc->parser, funAtom);
             fn->pn_body->pn_names = funtc->lexdeps;
             fn->pn_body->pn_tree = body;
         }
 
         funtc->lexdeps.clear();
     }
 
+    /*
+     * Check whether any parameters have been assigned within this function.
+     * In strict mode parameters do not alias arguments[i], and to make the
+     * arguments object reflect initial parameter values prior to any mutation
+     * we create it eagerly whenever parameters are (or might, in the case of
+     * calls to eval) be assigned.
+     */
+    if (funtc->inStrictMode() && funbox->object->getFunctionPrivate()->nargs > 0) {
+        JSAtomListIterator iter(&funtc->decls);
+        JSAtomListElement *ale;
+
+        while ((ale = iter()) != NULL) {
+            JSDefinition *dn = ALE_DEFN(ale);
+            if (dn->kind() == JSDefinition::ARG && dn->isAssigned()) {
+                funbox->tcflags |= TCF_FUN_MUTATES_PARAMETER;
+                break;
+            }
+        }
+    }
+
     return true;
 }
 
 static bool
 DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, JSAtom *atom);
 
-JSParseNode *
-Parser::functionDef(uintN lambda, bool namePermitted)
-{
-    JSParseNode *pn, *body, *result;
-    TokenKind tt;
-    JSAtomListElement *ale;
+bool
+Parser::functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSFunction *fun,
+                          JSParseNode **listp)
+{
+    if (tokenStream.getToken() != TOK_LP) {
+        reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_BEFORE_FORMAL);
+        return false;
+    }
+
+    if (!tokenStream.matchToken(TOK_RP)) {
+#if JS_HAS_DESTRUCTURING
+        JSAtom *duplicatedArg = NULL;
+        bool destructuringArg = false;
+        JSParseNode *list = NULL;
+#endif
+        do {
+            switch (TokenKind tt = tokenStream.getToken()) {
 #if JS_HAS_DESTRUCTURING
-    JSParseNode *item, *list = NULL;
-    bool destructuringArg = false;
-    JSAtom *duplicatedArg = NULL;
+              case TOK_LB:
+              case TOK_LC:
+              {
+                /* See comment below in the TOK_NAME case. */
+                if (duplicatedArg)
+                    goto report_dup_and_destructuring;
+                destructuringArg = true;
+
+                /*
+                 * A destructuring formal parameter turns into one or more
+                 * local variables initialized from properties of a single
+                 * anonymous positional parameter, so here we must tweak our
+                 * binder and its data.
+                 */
+                BindData data;
+                data.pn = NULL;
+                data.op = JSOP_DEFVAR;
+                data.binder = BindDestructuringArg;
+                JSParseNode *lhs = destructuringExpr(&data, tt);
+                if (!lhs)
+                    return false;
+
+                /*
+                 * Adjust fun->nargs to count the single anonymous positional
+                 * parameter that is to be destructured.
+                 */
+                jsint slot = fun->nargs;
+                if (!js_AddLocal(context, fun, NULL, JSLOCAL_ARG))
+                    return false;
+
+                /*
+                 * Synthesize a destructuring assignment from the single
+                 * anonymous positional parameter into the destructuring
+                 * left-hand-side expression and accumulate it in list.
+                 */
+                JSParseNode *rhs = NameNode::create(context->runtime->atomState.emptyAtom, &funtc);
+                if (!rhs)
+                    return false;
+                rhs->pn_type = TOK_NAME;
+                rhs->pn_op = JSOP_GETARG;
+                rhs->pn_cookie.set(funtc.staticLevel, uint16(slot));
+                rhs->pn_dflags |= PND_BOUND;
+
+                JSParseNode *item = JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc);
+                if (!item)
+                    return false;
+                if (!list) {
+                    list = ListNode::create(&funtc);
+                    if (!list)
+                        return false;
+                    list->pn_type = TOK_COMMA;
+                    list->makeEmpty();
+                    *listp = list;
+                }
+                list->append(item);
+                break;
+              }
+#endif /* JS_HAS_DESTRUCTURING */
+
+              case TOK_NAME:
+              {
+                JSAtom *atom = tokenStream.currentToken().t_atom;
+                if (!DefineArg(funbox->node, atom, fun->nargs, &funtc))
+                    return false;
+#ifdef JS_HAS_DESTRUCTURING
+                /*
+                 * ECMA-262 requires us to support duplicate parameter names, but if the
+                 * parameter list includes destructuring, we consider the code to have
+                 * opted in to higher standards, and forbid duplicates. We may see a
+                 * destructuring parameter later, so always note duplicates now.
+                 *
+                 * Duplicates are warned about (strict option) or cause errors (strict
+                 * mode code), but we do those tests in one place below, after having
+                 * parsed the body.
+                 */
+                if (js_LookupLocal(context, fun, atom, NULL) != JSLOCAL_NONE) {
+                    duplicatedArg = atom;
+                    if (destructuringArg)
+                        goto report_dup_and_destructuring;
+                }
 #endif
-
-    /*
-     * Save the current op for later so we can tag the created function as a
-     * getter/setter if necessary.
-     */
-    JSOp op = tokenStream.currentToken().t_op;
-
+                if (!js_AddLocal(context, fun, atom, JSLOCAL_ARG))
+                    return false;
+                break;
+              }
+
+              default:
+                reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_MISSING_FORMAL);
+                /* FALL THROUGH */
+              case TOK_ERROR:
+                return false;
+
+#if JS_HAS_DESTRUCTURING
+              report_dup_and_destructuring:
+                JSDefinition *dn = ALE_DEFN(funtc.decls.lookup(duplicatedArg));
+                reportErrorNumber(dn, JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG);
+                return false;
+#endif
+            }
+        } while (tokenStream.matchToken(TOK_COMMA));
+
+        if (tokenStream.getToken() != TOK_RP) {
+            reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_AFTER_FORMAL);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+JSParseNode *
+Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
+{
     /* Make a TOK_FUNCTION node. */
-    pn = FunctionNode::create(tc);
+    tokenStream.mungeCurrentToken(TOK_FUNCTION, JSOP_NOP);
+    JSParseNode *pn = FunctionNode::create(tc);
     if (!pn)
         return NULL;
     pn->pn_body = NULL;
     pn->pn_cookie.makeFree();
 
     /*
      * If a lambda, give up on JSOP_{GET,CALL}UPVAR usage unless this function
      * is immediately applied (we clear PND_FUNARG if so -- see memberExpr).
      *
      * Also treat function sub-statements (non-lambda, non-top-level functions)
      * as escaping funargs, since we can't statically analyze their definitions
      * and uses.
      */
     bool topLevel = tc->atTopLevel();
     pn->pn_dflags = (lambda || !topLevel) ? PND_FUNARG : 0;
 
-    /* Scan the optional function name into funAtom. */
-    JSAtom *funAtom = NULL;
-    if (namePermitted) {
-        tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
-        if (tt == TOK_NAME) {
-            funAtom = tokenStream.currentToken().t_atom;
-        } else {
-            if (lambda == 0 && (context->options & JSOPTION_ANONFUNFIX)) {
-                reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
-                return NULL;
-            }
-            tokenStream.ungetToken();
-        }
-    }
-
     /*
      * Record names for function statements in tc->decls so we know when to
      * avoid optimizing variable references that might name a function.
      */
     if (lambda == 0 && funAtom) {
-        ale = tc->decls.lookup(funAtom);
-        if (ale) {
+        if (JSAtomListElement *ale = tc->decls.lookup(funAtom)) {
             JSDefinition *dn = ALE_DEFN(ale);
             JSDefinition::Kind dn_kind = dn->kind();
 
             JS_ASSERT(!dn->pn_used);
             JS_ASSERT(dn->pn_defn);
 
             if (JS_HAS_STRICT_OPTION(context) || dn_kind == JSDefinition::CONST) {
                 const char *name = js_AtomToPrintableString(context, funAtom);
@@ -2776,143 +2893,43 @@ Parser::functionDef(uintN lambda, bool n
     JSTreeContext funtc(tc->parser);
 
     JSFunctionBox *funbox = EnterFunction(pn, &funtc, funAtom, lambda);
     if (!funbox)
         return NULL;
 
     JSFunction *fun = (JSFunction *) funbox->object;
 
-    if (op != JSOP_NOP)
-        fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;
-
     /* Now parse formal argument list and compute fun->nargs. */
-    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
-    if (!tokenStream.matchToken(TOK_RP)) {
-        do {
-            tt = tokenStream.getToken();
-            switch (tt) {
-#if JS_HAS_DESTRUCTURING
-              case TOK_LB:
-              case TOK_LC:
-              {
-                BindData data;
-                JSParseNode *lhs, *rhs;
-                jsint slot;
-
-                /* See comment below in the TOK_NAME case. */
-                if (duplicatedArg)
-                    goto report_dup_and_destructuring;
-                destructuringArg = true;
-
-                /*
-                 * A destructuring formal parameter turns into one or more
-                 * local variables initialized from properties of a single
-                 * anonymous positional parameter, so here we must tweak our
-                 * binder and its data.
-                 */
-                data.pn = NULL;
-                data.op = JSOP_DEFVAR;
-                data.binder = BindDestructuringArg;
-                lhs = destructuringExpr(&data, tt);
-                if (!lhs)
-                    return NULL;
-
-                /*
-                 * Adjust fun->nargs to count the single anonymous positional
-                 * parameter that is to be destructured.
-                 */
-                slot = fun->nargs;
-                if (!js_AddLocal(context, fun, NULL, JSLOCAL_ARG))
-                    return NULL;
-
-                /*
-                 * Synthesize a destructuring assignment from the single
-                 * anonymous positional parameter into the destructuring
-                 * left-hand-side expression and accumulate it in list.
-                 */
-                rhs = NameNode::create(context->runtime->atomState.emptyAtom, &funtc);
-                if (!rhs)
-                    return NULL;
-                rhs->pn_type = TOK_NAME;
-                rhs->pn_op = JSOP_GETARG;
-                rhs->pn_cookie.set(funtc.staticLevel, uint16(slot));
-                rhs->pn_dflags |= PND_BOUND;
-
-                item = JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc);
-                if (!item)
-                    return NULL;
-                if (!list) {
-                    list = ListNode::create(&funtc);
-                    if (!list)
-                        return NULL;
-                    list->pn_type = TOK_COMMA;
-                    list->makeEmpty();
-                }
-                list->append(item);
-                break;
-              }
-#endif /* JS_HAS_DESTRUCTURING */
-
-              case TOK_NAME:
-              {
-                JSAtom *atom = tokenStream.currentToken().t_atom;
-                if (!DefineArg(pn, atom, fun->nargs, &funtc))
-                    return NULL;
-#ifdef JS_HAS_DESTRUCTURING
-                /*
-                 * ECMA-262 requires us to support duplicate parameter names, but if the
-                 * parameter list includes destructuring, we consider the code to have
-                 * opted in to higher standards, and forbid duplicates. We may see a
-                 * destructuring parameter later, so always note duplicates now.
-                 *
-                 * Duplicates are warned about (strict option) or cause errors (strict
-                 * mode code), but we do those tests in one place below, after having
-                 * parsed the body.
-                 */
-                if (js_LookupLocal(context, fun, atom, NULL) != JSLOCAL_NONE) {
-                    duplicatedArg = atom;
-                    if (destructuringArg)
-                        goto report_dup_and_destructuring;
-                }
-#endif
-                if (!js_AddLocal(context, fun, atom, JSLOCAL_ARG))
-                    return NULL;
-                break;
-              }
-
-              default:
-                reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_MISSING_FORMAL);
-                /* FALL THROUGH */
-              case TOK_ERROR:
-                return NULL;
-
-#if JS_HAS_DESTRUCTURING
-              report_dup_and_destructuring:
-                JSDefinition *dn = ALE_DEFN(funtc.decls.lookup(duplicatedArg));
-                reportErrorNumber(dn, JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG);
-                return NULL;
-#endif
-            }
-        } while (tokenStream.matchToken(TOK_COMMA));
-
-        MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL);
+    JSParseNode *prolog = NULL;
+    if (!functionArguments(funtc, funbox, fun, &prolog))
+        return NULL;
+
+    if (type == GETTER && fun->nargs > 0) {
+        reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ACCESSOR_WRONG_ARGS,
+                          "getter", "no", "s");
+        return NULL;
+    }
+    if (type == SETTER && fun->nargs != 1) {
+        reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ACCESSOR_WRONG_ARGS,
+                          "setter", "one", "");
+        return NULL;
     }
 
 #if JS_HAS_EXPR_CLOSURES
-    tt = tokenStream.getToken(TSF_OPERAND);
+    TokenKind tt = tokenStream.getToken(TSF_OPERAND);
     if (tt != TOK_LC) {
         tokenStream.ungetToken();
         fun->flags |= JSFUN_EXPR_CLOSURE;
     }
 #else
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);
 #endif
 
-    body = functionBody();
+    JSParseNode *body = functionBody();
     if (!body)
         return NULL;
 
     if (!CheckStrictBinding(context, &funtc, funAtom, pn))
         return NULL;
 
     if (!CheckStrictFormals(context, &funtc, fun, pn))
         return NULL;
@@ -2922,45 +2939,63 @@ Parser::functionDef(uintN lambda, bool n
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
     else if (lambda == 0 && !MatchOrInsertSemicolon(context, &tokenStream))
         return NULL;
 #else
     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
 #endif
     pn->pn_pos.end = tokenStream.currentToken().pos.end;
 
+    /*
+     * Strict mode functions' arguments objects copy initial parameter values.
+     * We create arguments objects lazily -- but that doesn't work for strict
+     * mode functions where a parameter might be modified and arguments might
+     * be accessed.  For such functions we synthesize an access to arguments to
+     * initialize it with the original parameter values.
+     */
+    if (funtc.inStrictMode()) {
+        /*
+         * Fruit of the poisonous tree: eval forces eager arguments
+         * creation in (strict mode) parent functions.
+         */
+        if (outertc->inFunction() && outertc->inStrictMode()) {
+            if (funtc.callsEval())
+                outertc->noteCallsEval();
+        }
+    }
+
 #if JS_HAS_DESTRUCTURING
     /*
      * If there were destructuring formal parameters, prepend the initializing
      * comma expression that we synthesized to body.  If the body is a lexical
      * scope node, we must make a special TOK_SEQ node, to prepend the formal
      * parameter destructuring code without bracing the decompilation of the
      * function body's lexical scope.
      */
-    if (list) {
+    if (prolog) {
         if (body->pn_arity != PN_LIST) {
             JSParseNode *block;
 
             block = ListNode::create(outertc);
             if (!block)
                 return NULL;
             block->pn_type = TOK_SEQ;
             block->pn_pos = body->pn_pos;
             block->initList(body);
 
             body = block;
         }
 
-        item = UnaryNode::create(outertc);
+        JSParseNode *item = UnaryNode::create(outertc);
         if (!item)
             return NULL;
 
         item->pn_type = TOK_SEMI;
         item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin;
-        item->pn_kid = list;
+        item->pn_kid = prolog;
         item->pn_next = body->pn_head;
         body->pn_head = item;
         if (body->pn_tail == &body->pn_head)
             body->pn_tail = &item->pn_next;
         ++body->pn_count;
         body->pn_xflags |= PNX_DESTRUCT;
     }
 #endif
@@ -2979,17 +3014,18 @@ Parser::functionDef(uintN lambda, bool n
          * If this function is a named statement function not at top-level
          * (i.e. not a top-level function definiton or expression), then our
          * enclosing function, if any, must be heavyweight.
          */
         if (!topLevel && lambda == 0 && funAtom)
             outertc->flags |= TCF_FUN_HEAVYWEIGHT;
     }
 
-    result = pn;
+    JSParseNode *result = pn;
+    JSOp op = JSOP_NOP;
     if (lambda != 0) {
         /*
          * ECMA ed. 3 standard: function expression, possibly anonymous.
          */
         op = JSOP_LAMBDA;
     } else if (!funAtom) {
         /*
          * If this anonymous function definition is *not* embedded within a
@@ -3008,18 +3044,16 @@ Parser::functionDef(uintN lambda, bool n
     } else if (!topLevel) {
         /*
          * ECMA ed. 3 extension: a function expression statement not at the
          * top level, e.g., in a compound statement such as the "then" part
          * of an "if" statement, binds a closure only if control reaches that
          * sub-statement.
          */
         op = JSOP_DEFFUN;
-    } else {
-        op = JSOP_NOP;
     }
 
     funbox->kids = funtc.functionList;
 
     pn->pn_funbox = funbox;
     pn->pn_op = op;
     if (pn->pn_body) {
         pn->pn_body->append(body);
@@ -3036,32 +3070,48 @@ Parser::functionDef(uintN lambda, bool n
     }
 
     pn->pn_blockid = outertc->blockid();
 
     if (!LeaveFunction(pn, &funtc, funAtom, lambda))
         return NULL;
 
     /* If the surrounding function is not strict code, reset the lexer. */
-    if (!(outertc->flags & TCF_STRICT_MODE_CODE))
+    if (!outertc->inStrictMode())
         tokenStream.setStrictMode(false);
 
     return result;
 }
 
 JSParseNode *
 Parser::functionStmt()
 {
-    return functionDef(0, true);
+    JSAtom *name = NULL;
+    if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME) {
+        name = tokenStream.currentToken().t_atom;
+    } else {
+        if (context->options & JSOPTION_ANONFUNFIX) {
+            /* Extension: accept unnamed function expressions as statements. */
+            reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
+            return NULL;
+        }
+        tokenStream.ungetToken();
+    }
+    return functionDef(name, GENERAL, 0);
 }
 
 JSParseNode *
 Parser::functionExpr()
 {
-    return functionDef(JSFUN_LAMBDA, true);
+    JSAtom *name = NULL;
+    if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME)
+        name = tokenStream.currentToken().t_atom;
+    else
+        tokenStream.ungetToken();
+    return functionDef(name, GENERAL, JSFUN_LAMBDA);
 }
 
 /*
  * Recognize Directive Prologue members and directives.  Assuming pn
  * is a candidate for membership in a directive prologue, return
  * true if it is in fact a member.  Recognize directives and set
  * tc's flags accordingly.
  *
@@ -3668,17 +3718,18 @@ NoteLValue(JSContext *cx, JSParseNode *p
         dn->pn_dflags |= dflag;
 
         if (dn->pn_cookie.isFree() || dn->frameLevel() < tc->staticLevel)
             tc->flags |= TCF_FUN_SETS_OUTER_NAME;
     }
 
     pn->pn_dflags |= dflag;
 
-    if (pn->pn_atom == cx->runtime->atomState.argumentsAtom)
+    JSAtom *lname = pn->pn_atom;
+    if (lname == cx->runtime->atomState.argumentsAtom)
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
 }
 
 #if JS_HAS_DESTRUCTURING
 
 static JSBool
 BindDestructuringVar(JSContext *cx, BindData *data, JSParseNode *pn,
                      JSTreeContext *tc)
@@ -5801,25 +5852,16 @@ Parser::statement()
         }
         break;
     }
 
     /* Check termination of this primitive statement. */
     return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL;
 }
 
-static void
-NoteArgumentsUse(JSTreeContext *tc)
-{
-    JS_ASSERT(tc->inFunction());
-    tc->flags |= TCF_FUN_USES_ARGUMENTS;
-    if (tc->funbox)
-        tc->funbox->node->pn_dflags |= PND_FUNARG;
-}
-
 JSParseNode *
 Parser::variables(bool inLetHead)
 {
     TokenKind tt;
     bool let;
     JSStmtInfo *scopeStmt;
     BindData data;
     JSParseNode *pn, *pn2;
@@ -5977,17 +6019,17 @@ Parser::variables(bool inLetHead)
 
             NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED);
 
             /* The declarator's position must include the initializer. */
             pn2->pn_pos.end = init->pn_pos.end;
 
             if (tc->inFunction() &&
                 atom == context->runtime->atomState.argumentsAtom) {
-                NoteArgumentsUse(tc);
+                tc->noteArgumentsUse();
                 if (!let)
                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
             }
         }
     } while (tokenStream.matchToken(TOK_COMMA));
 
     pn->pn_pos.end = pn->last()->pn_pos.end;
     return pn;
@@ -7179,17 +7221,18 @@ Parser::memberExpr(JSBool allowCallSynta
                 return NULL;
             pn2->pn_op = JSOP_CALL;
 
             pn = CheckForImmediatelyAppliedLambda(pn);
             if (pn->pn_op == JSOP_NAME) {
                 if (pn->pn_atom == context->runtime->atomState.evalAtom) {
                     /* Select JSOP_EVAL and flag tc as heavyweight. */
                     pn2->pn_op = JSOP_EVAL;
-                    tc->flags |= TCF_FUN_HEAVYWEIGHT | TCF_FUN_USES_EVAL;
+                    tc->noteCallsEval();
+                    tc->flags |= TCF_FUN_HEAVYWEIGHT;
                 }
             } else if (pn->pn_op == JSOP_GETPROP) {
                 if (pn->pn_atom == context->runtime->atomState.applyAtom ||
                     pn->pn_atom == context->runtime->atomState.callAtom) {
                     /* Select JSOP_APPLY given foo.apply(...). */
                     pn2->pn_op = JSOP_APPLY;
                 }
             }
@@ -8110,19 +8153,18 @@ Parser::primaryExpr(TokenKind tt, JSBool
                         } else {
                             atom = NULL; /* for the compiler */
                         }
                     } else {
                         tokenStream.ungetToken();
                         goto property_name;
                     }
 
-                    /* We have to fake a 'function' token here. */
-                    tokenStream.mungeCurrentToken(TOK_FUNCTION, JSOP_NOP);
-                    pn2 = functionDef(JSFUN_LAMBDA, false);
+                    /* NB: Getter function in { get x(){} } is unnamed. */
+                    pn2 = functionDef(NULL, op == JSOP_SETTER ? SETTER : GETTER, JSFUN_LAMBDA);
                     pn2 = JSParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pn2, tc);
                     goto skip;
                 }
               property_name:
               case TOK_STRING:
                 atom = tokenStream.currentToken().t_atom;
                 pn3 = NullaryNode::create(tc);
                 if (!pn3)
@@ -8328,17 +8370,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
             pn->pn_atom == context->runtime->atomState.argumentsAtom) {
             /*
              * Flag arguments usage so we can avoid unsafe optimizations such
              * as formal parameter assignment analysis (because of the hated
              * feature whereby arguments alias formals). We do this even for
              * a reference of the form foo.arguments, which ancient code may
              * still use instead of arguments (more hate).
              */
-            NoteArgumentsUse(tc);
+            tc->noteArgumentsUse();
 
             /*
              * Bind early to JSOP_ARGUMENTS to relieve later code from having
              * to do this work (new rule for the emitter to count on).
              */
             if (!afterDot && !(tc->flags & TCF_DECL_DESTRUCTURING) && !tc->inStatement(STMT_WITH)) {
                 pn->pn_op = JSOP_ARGUMENTS;
                 pn->pn_dflags |= PND_BOUND;
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -481,19 +481,19 @@ public:
 #define PNX_XMLROOT     0x20            /* top-most node in XML literal tree */
 #define PNX_GROUPINIT   0x40            /* var [a, b] = [c, d]; unit list */
 #define PNX_NEEDBRACES  0x80            /* braces necessary due to closure */
 #define PNX_FUNCDEFS   0x100            /* contains top-level function
                                            statements */
 #define PNX_DESTRUCT   0x200            /* destructuring special cases:
                                            1. shorthand syntax used, at present
                                               object destructuring ({x,y}) only;
-                                           2. the first child of function body
-                                              is code evaluating destructuring
-                                              arguments */
+                                           2. code evaluating destructuring
+                                              arguments occurs before function
+                                              body */
 #define PNX_HOLEY      0x400            /* array initialiser has holes */
 
     uintN frameLevel() const {
         JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
         return pn_cookie.level();
     }
 
     uintN frameSlot() const {
@@ -1056,18 +1056,23 @@ private:
     JSParseNode *memberExpr(JSBool allowCallSyntax);
     JSParseNode *primaryExpr(js::TokenKind tt, JSBool afterDot);
     JSParseNode *parenExpr(JSParseNode *pn1, JSBool *genexp);
 
     /*
      * Additional JS parsers.
      */
     bool recognizeDirectivePrologue(JSParseNode *pn);
+
+    enum FunctionType { GETTER, SETTER, GENERAL };
+    bool functionArguments(JSTreeContext &funtc, JSFunctionBox *funbox, JSFunction *fun,
+                           JSParseNode **list);
     JSParseNode *functionBody();
-    JSParseNode *functionDef(uintN lambda, bool namePermitted);
+    JSParseNode *functionDef(JSAtom *name, FunctionType type, uintN lambda);
+
     JSParseNode *condition();
     JSParseNode *comprehensionTail(JSParseNode *kid, uintN blockid,
                                    js::TokenKind type = js::TOK_SEMI, JSOp op = JSOP_NOP);
     JSParseNode *generatorExpr(JSParseNode *pn, JSParseNode *kid);
     JSBool argumentList(JSParseNode *listNode);
     JSParseNode *bracketedExpr();
     JSParseNode *letBlock(JSBool statement);
     JSParseNode *returnOrYield(bool useAssignExpr);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1025,23 +1025,35 @@ js_NewScriptFromCG(JSContext *cx, JSCode
             ++pc;
 
         if (JSOp(*pc) == JSOP_STOP &&
             !cx->debugHooks->newScriptHook &&
             !(cg->flags & TCF_NEED_MUTABLE_SCRIPT))
         {
             /*
              * We can probably use the immutable empty script singleton, just
-             * one hard case (nupvars != 0) may stand in our way.
+             * two hard cases (nupvars != 0, strict mode code) may stand in our
+             * way.
              */
             JSScript *empty = JSScript::emptyScript();
 
             if (cg->flags & TCF_IN_FUNCTION) {
                 fun = cg->fun;
-                JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
+                JS_ASSERT(fun->isInterpreted() && !FUN_SCRIPT(fun));
+                if (cg->flags & TCF_STRICT_MODE_CODE) {
+                    /*
+                     * We can't use a script singleton for empty strict mode
+                     * functions because they have poison-pill caller and
+                     * arguments properties:
+                     *
+                     * function strict() { "use strict"; }
+                     * strict.caller; // calls [[ThrowTypeError]] function
+                     */
+                    goto skip_empty;
+                }
                 if (fun->u.i.nupvars != 0) {
                     /*
                      * FIXME: upvar uses that were all optimized away may leave
                      * fun->u.i.nupvars non-zero, and since that count is added
                      * into fun->countLocalNames() in order to discriminate the
                      * fun->u.i.names union, we cannot force fun->u.i.nupvars
                      * to 0 to match JSScript::emptyScript()->upvars()->length.
                      * So we skip the empty script optimization.
@@ -1113,17 +1125,17 @@ js_NewScriptFromCG(JSContext *cx, JSCode
     if (cg->flags & TCF_NO_SCRIPT_RVAL)
         script->noScriptRval = true;
     if (cg->hasSharps())
         script->hasSharps = true;
     if (cg->flags & TCF_STRICT_MODE_CODE)
         script->strictModeCode = true;
     if (cg->flags & TCF_COMPILE_N_GO)
         script->compileAndGo = true;
-    if (cg->flags & TCF_FUN_USES_EVAL)
+    if (cg->flags & TCF_FUN_CALLS_EVAL)
         script->usesEval = true;
 
     if (cg->upvarList.count != 0) {
         JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length);
         memcpy(script->upvars()->vector, cg->upvarMap.vector,
                cg->upvarList.count * sizeof(uint32));
         cg->upvarList.clear();
         cx->free(cg->upvarMap.vector);
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -74,16 +74,17 @@
 #include "jsscript.h"
 #include "jsstaticcheck.h"
 #include "jstracer.h"
 #include "jsxml.h"
 #include "jstypedarray.h"
 
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
+#include "jsfuninlines.h"
 #include "jspropertycacheinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jscntxtinlines.h"
 
 #include "jsautooplen.h"        // generated headers last
 #include "imacros.c.out"
@@ -3448,18 +3449,20 @@ FlushNativeStackFrame(JSContext* cx, uns
             // Skip over stopFrame itself.
             JS_ASSERT(n != 0);
             --n;
             fp = fp->down;
         }
         for (; n != 0; fp = fp->down) {
             --n;
             if (fp->argv) {
-                if (fp->hasArgsObj() && fp->getArgsObj()->getPrivate() == JS_ARGUMENT_OBJECT_ON_TRACE)
+                if (fp->hasArgsObj() && fp->getArgsObj()->getPrivate() == JS_ARGUMENT_OBJECT_ON_TRACE) {
+                    JS_ASSERT(fp->getArgsObj()->isNormalArguments());
                     fp->getArgsObj()->setPrivate(fp);
+                }
 
                 JS_ASSERT(fp->argv[-1].isObjectOrNull());
                 JS_ASSERT(fp->callee()->isFunction());
                 JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee()) == fp->getFunction());
 
                 if (FUN_INTERPRETED(fp->getFunction()) &&
                     (fp->getFunction()->flags & JSFUN_HEAVYWEIGHT)) {
                     // Iff these fields are NULL, then |fp| was synthesized on trace exit, so
@@ -8743,23 +8746,32 @@ TraceRecorder::tableswitch()
         high = GET_JUMP_OFFSET(pc);
     } else {
         pc += JUMPX_OFFSET_LEN;
         low = GET_JUMPX_OFFSET(pc);
         pc += JUMPX_OFFSET_LEN;
         high = GET_JUMPX_OFFSET(pc);
     }
 
+    /* 
+     * If there are no cases, this is a no-op. The default case immediately
+     * follows in the bytecode and is always taken, so we need no special
+     * action to handle it.
+     */
+    int count = high + 1 - low;
+    if (count == 0)
+        return ARECORD_CONTINUE;
+
     /* Cap maximum table-switch size for modesty. */
-    if ((high + 1 - low) > MAX_TABLE_SWITCH)
+    if (count > MAX_TABLE_SWITCH)
         return InjectStatus(switchop());
 
     /* Generate switch LIR. */
     SwitchInfo* si = new (traceAlloc()) SwitchInfo();
-    si->count = high + 1 - low;
+    si->count = count;
     si->table = 0;
     si->index = (uint32) -1;
     LIns* diff = lir->ins2(LIR_subi, v_ins, lir->insImmI(low));
     LIns* cmp = lir->ins2(LIR_ltui, diff, lir->insImmI(si->count));
     lir->insGuard(LIR_xf, cmp, createGuardRecord(snapshot(DEFAULT_EXIT)));
     lir->insStore(diff, lir->insImmP(&si->index), 0, ACCSET_OTHER);
     VMSideExit* exit = snapshot(CASE_EXIT);
     exit->switchInfo = si;
@@ -10292,17 +10304,17 @@ TraceRecorder::clearCurrentFrameSlotsFro
 /*
  * If we have created an |arguments| object for the frame, we must copy the
  * argument values into the object as properties in case it is used after
  * this frame returns.
  */
 JS_REQUIRES_STACK void
 TraceRecorder::putActivationObjects()
 {
-    bool have_args = cx->fp->hasArgsObj() && cx->fp->argc;
+    bool have_args = cx->fp->hasArgsObj() && !cx->fp->getArgsObj()->isStrictArguments() && cx->fp->argc > 0;
     bool have_call = cx->fp->hasFunction() &&
         JSFUN_HEAVYWEIGHT_TEST(cx->fp->getFunction()->flags) &&
         cx->fp->getFunction()->countArgsAndVars();
 
     if (!have_args && !have_call)
         return;
 
     int nargs = have_args ? argSlots(cx->fp) : cx->fp->getArgumentCount();
@@ -10655,65 +10667,77 @@ TraceRecorder::record_JSOP_IFEQ()
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_IFNE()
 {
     return ifop();
 }
 
 LIns*
-TraceRecorder::newArguments(LIns* callee_ins)
+TraceRecorder::newArguments(LIns* callee_ins, bool strict)
 {
     LIns* global_ins = INS_CONSTOBJ(globalObj);
     LIns* argc_ins = INS_CONST(cx->fp->argc);
 
     LIns* args[] = { callee_ins, argc_ins, global_ins, cx_ins };
     LIns* call_ins = lir->insCall(&js_Arguments_ci, args);
     guard(false, lir->insEqP_0(call_ins), OOM_EXIT);
+
+    if (strict) {
+        JSStackFrame* fp = cx->fp;
+        uintN argc = fp->argc;
+        LIns* argsSlots_ins = NULL;
+        for (uintN i = 0; i < argc; i++)
+            stobj_set_dslot(call_ins, i, argsSlots_ins, fp->argv[i], get(&fp->argv[i]));
+    }
+
     return call_ins;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ARGUMENTS()
 {
     /* In an eval, 'arguments' will be a BINDNAME, which we don't trace. */
     JS_ASSERT(!(cx->fp->flags & JSFRAME_EVAL));
 
     if (cx->fp->flags & JSFRAME_OVERRIDE_ARGS)
         RETURN_STOP_A("Can't trace |arguments| if |arguments| is assigned to");
 
+    JSStackFrame* const fp = cx->fp;
+
     LIns* a_ins = getFrameObjPtr(cx->fp->addressArgsObj());
     LIns* args_ins;
-    LIns* callee_ins = get(&cx->fp->argv[-2]);
+    LIns* callee_ins = get(&fp->argv[-2]);
+    bool strict = fp->getFunction()->inStrictMode();
     if (a_ins->isImmP()) {
         // |arguments| is set to 0 by EnterFrame on this trace, so call to create it.
-        args_ins = newArguments(callee_ins);
+        args_ins = newArguments(callee_ins, strict);
     } else {
         // Generate LIR to create arguments only if it has not already been created.
 
         LIns* mem_ins = lir->insAlloc(sizeof(JSObject *));
 
         LIns* br1 = lir->insBranch(LIR_jt, lir->insEqP_0(a_ins), NULL);
         lir->insStore(a_ins, mem_ins, 0, ACCSET_OTHER);
         LIns* br2 = lir->insBranch(LIR_j, NULL, NULL);
 
         LIns* label1 = lir->ins0(LIR_label);
         br1->setTarget(label1);
 
-        LIns* call_ins = newArguments(callee_ins);
+        LIns* call_ins = newArguments(callee_ins, strict);
         lir->insStore(call_ins, mem_ins, 0, ACCSET_OTHER);
 
         LIns* label2 = lir->ins0(LIR_label);
         br2->setTarget(label2);
 
         args_ins = lir->insLoad(LIR_ldp, mem_ins, 0, ACCSET_OTHER);
     }
 
     stack(0, args_ins);
-    setFrameObjPtr(cx->fp->addressArgsObj(), args_ins);
+    setFrameObjPtr(fp->addressArgsObj(), args_ins);
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_DUP()
 {
     stack(0, get(&stackval(-1)));
     return ARECORD_CONTINUE;
@@ -13356,17 +13380,17 @@ TraceRecorder::guardArguments(JSObject *
 {
     JS_ASSERT(obj->isArguments());
 
     JSStackFrame *afp = frameIfInRange(obj, depthp);
     if (!afp)
         return NULL;
 
     VMSideExit *exit = snapshot(MISMATCH_EXIT);
-    guardClass(obj_ins, &js_ArgumentsClass, exit, LOAD_CONST);
+    guardClass(obj_ins, obj->getClass(), exit, LOAD_CONST);
 
     LIns* args_ins = getFrameObjPtr(afp->addressArgsObj());
     LIns* cmp = lir->ins2(LIR_eqp, args_ins, obj_ins);
     lir->insGuard(LIR_xf, cmp, createGuardRecord(exit));
     return afp;
 }
 
 JS_REQUIRES_STACK RecordingStatus
@@ -15267,20 +15291,20 @@ TraceRecorder::record_JSOP_ARGSUB()
         return ARECORD_CONTINUE;
     }
     RETURN_STOP_A("can't trace JSOP_ARGSUB hard case");
 }
 
 JS_REQUIRES_STACK LIns*
 TraceRecorder::guardArgsLengthNotAssigned(LIns* argsobj_ins)
 {
-    // The following implements IsOverriddenArgsLength on trace.
-    // The '2' bit is set if length was overridden.
+    // The following implements JSObject::isArgsLengthOverridden on trace.
+    // ARGS_LENGTH_OVERRIDDEN_BIT is set if length was overridden.
     LIns *len_ins = stobj_get_fslot_uint32(argsobj_ins, JSObject::JSSLOT_ARGS_LENGTH);
-    LIns *ovr_ins = lir->ins2(LIR_andi, len_ins, INS_CONST(2));
+    LIns *ovr_ins = lir->ins2(LIR_andi, len_ins, INS_CONST(JSObject::ARGS_LENGTH_OVERRIDDEN_BIT));
     guard(true, lir->insEqI_0(ovr_ins), snapshot(BRANCH_EXIT));
     return len_ins;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_ARGCNT()
 {
     if (cx->fp->getFunction()->flags & JSFUN_HEAVYWEIGHT)
@@ -15968,19 +15992,21 @@ TraceRecorder::record_JSOP_LENGTH()
             RETURN_STOP_A("can't reach arguments object's frame");
 
         // We must both check at record time and guard at run time that
         // arguments.length has not been reassigned, redefined or deleted.
         if (obj->isArgsLengthOverridden())
             RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified");
         LIns* slot_ins = guardArgsLengthNotAssigned(obj_ins);
 
-        // slot_ins is the value from the slot; right-shift by 2 bits to get
-        // the length (see GetArgsLength in jsfun.cpp).
-        LIns* v_ins = lir->ins1(LIR_i2d, lir->ins2ImmI(LIR_rshi, slot_ins, 1));
+        // slot_ins is the value from the slot; right-shift to get the length
+        // (see JSObject::getArgsInitialLength in jsfun.cpp).
+        LIns* v_ins =
+            lir->ins1(LIR_i2d, lir->ins2ImmI(LIR_rshi,
+                                             slot_ins, JSObject::ARGS_PACKED_BITS_COUNT));
         set(&l, v_ins);
         return ARECORD_CONTINUE;
     }
 
     LIns* v_ins;
     if (obj->isArray()) {
         if (obj->isDenseArray()) {
             guardDenseArray(obj_ins, BRANCH_EXIT);
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -1162,17 +1162,17 @@ class TraceRecorder
                                          nanojit::LIns* s0, nanojit::LIns* s1);
 
     nanojit::LIns* i2d(nanojit::LIns* i);
     nanojit::LIns* d2i(nanojit::LIns* f, bool resultCanBeImpreciseIfFractional = false);
     nanojit::LIns* f2u(nanojit::LIns* f);
     JS_REQUIRES_STACK nanojit::LIns* makeNumberInt32(nanojit::LIns* f);
     JS_REQUIRES_STACK nanojit::LIns* stringify(const Value& v);
 
-    JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins);
+    JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins, bool strict);
 
     JS_REQUIRES_STACK bool canCallImacro() const;
     JS_REQUIRES_STACK RecordingStatus callImacro(jsbytecode* imacro);
     JS_REQUIRES_STACK RecordingStatus callImacroInfallibly(jsbytecode* imacro);
 
     JS_REQUIRES_STACK AbortableRecordingStatus ifop();
     JS_REQUIRES_STACK RecordingStatus switchop();
 #ifdef NANOJIT_IA32
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -1838,17 +1838,17 @@ ic::GetProp(VMFrame &f, uint32 index)
                         THROW();
                     }
                     f.regs.sp[-1].setNumber(obj->getArrayLength());
                 } else if (obj->isArguments()) {
                     if (!cc.generateArgsLengthStub()) {
                         cc.disable("error");
                         THROW();
                     }
-                    f.regs.sp[-1].setInt32(int32_t(obj->getArgsLength()));
+                    f.regs.sp[-1].setInt32(int32_t(obj->getArgsInitialLength()));
                 }
                 return;
             }
         }
         atom = f.cx->runtime->atomState.lengthAtom;
     }
 
     JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]);
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -520,17 +520,17 @@ stubs::GetElem(VMFrame &f)
             }
         } else if (obj->isArguments()
 #if 0 /* def JS_TRACER */
                    && !GetArgsPrivateNative(obj)
 #endif
                   ) {
             uint32 arg = uint32(rval.toInt32());
 
-            if (arg < obj->getArgsLength()) {
+            if (arg < obj->getArgsInitialLength()) {
                 JSStackFrame *afp = (JSStackFrame *) obj->getPrivate();
                 if (afp) {
                     copyFrom = &afp->argv[arg];
                     goto end_getelem;
                 }
 
                 copyFrom = obj->addressOfArgsElement(arg);
                 if (!copyFrom->isMagic())
@@ -2154,17 +2154,17 @@ stubs::Length(VMFrame &f)
         return;
     } else if (vp->isObject()) {
         JSObject *obj = &vp->toObject();
         if (obj->isArray()) {
             jsuint length = obj->getArrayLength();
             regs.sp[-1].setNumber(length);
             return;
         } else if (obj->isArguments() && !obj->isArgsLengthOverridden()) {
-            uint32 length = obj->getArgsLength();
+            uint32 length = obj->getArgsInitialLength();
             JS_ASSERT(length < INT32_MAX);
             regs.sp[-1].setInt32(int32_t(length));
             return;
         }
     }
 
     if (!InlineGetProp(f))
         THROW();
--- a/js/src/prmjtime.cpp
+++ b/js/src/prmjtime.cpp
@@ -93,39 +93,55 @@ extern int gettimeofday(struct timeval *
 #define PRMJ_FOUR_YEARS_DAYS (4 * PRMJ_YEAR_DAYS + 1)
 #define PRMJ_CENTURY_DAYS (25 * PRMJ_FOUR_YEARS_DAYS - 1)
 #define PRMJ_FOUR_CENTURIES_DAYS (4 * PRMJ_CENTURY_DAYS + 1)
 #define PRMJ_HOUR_SECONDS  3600L
 #define PRMJ_DAY_SECONDS  (24L * PRMJ_HOUR_SECONDS)
 #define PRMJ_YEAR_SECONDS (PRMJ_DAY_SECONDS * PRMJ_YEAR_DAYS)
 #define PRMJ_MAX_UNIX_TIMET 2145859200L /*time_t value equiv. to 12/31/2037 */
 
-/* function prototypes */
-static void PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm);
 /*
  * get the difference in seconds between this time zone and UTC (GMT)
  */
 JSInt32
 PRMJ_LocalGMTDifference()
 {
-    struct tm ltime;
-
 #if defined(XP_WIN) && !defined(WINCE)
     /* Windows does not follow POSIX. Updates to the
      * TZ environment variable are not reflected
      * immediately on that platform as they are
      * on UNIX systems without this call.
      */
     _tzset();
 #endif
-    /* get the difference between this time zone and GMT */
-    memset((char *)&ltime,0,sizeof(ltime));
-    ltime.tm_mday = 2;
-    ltime.tm_year = 70;
-    return (JSInt32)mktime(&ltime) - (24L * 3600L);
+
+    /*
+     * Get the difference between this time zone and GMT, by checking the local
+     * time at the epoch.
+     */
+    time_t local = 0;
+    struct tm tm;
+#ifndef HAVE_LOCALTIME_R
+    struct tm *ptm = localtime(&local);
+    if (!ptm)
+        return 0;
+    tm = *ptm;
+#else
+    localtime_r(&local, &tm);
+#endif
+
+    JSInt32 time = (tm.tm_hour * 3600)
+                 + (tm.tm_min * 60)
+                 + tm.tm_sec;
+    time = (24 * 3600) - time;
+
+    if (time >= (12 * 3600))
+        time -= (24 * 3600);
+
+    return time;
 }
 
 /* Constants for GMT offset from 1970 */
 #define G1970GMTMICROHI        0x00dcdcad /* micro secs to 1970 hi */
 #define G1970GMTMICROLOW       0x8b3fa000 /* micro secs to 1970 low */
 
 #define G2037GMTMICROHI        0x00e45fab /* micro secs to 2037 high */
 #define G2037GMTMICROLOW       0x7a238000 /* micro secs to 2037 low */
@@ -684,210 +700,49 @@ PRMJ_FormatTime(char *buf, int buflen, c
 /* table for number of days in a month */
 static int mtab[] = {
     /* jan, feb,mar,apr,may,jun */
     31,28,31,30,31,30,
     /* july,aug,sep,oct,nov,dec */
     31,31,30,31,30,31
 };
 
-/*
- * basic time calculation functionality for localtime and gmtime
- * setups up prtm argument with correct values based upon input number
- * of seconds.
- */
-static void
-PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm)
-{
-    /* convert tsecs back to year,month,day,hour,secs */
-    JSInt32 year    = 0;
-    JSInt32 month   = 0;
-    JSInt32 yday    = 0;
-    JSInt32 mday    = 0;
-    JSInt32 wday    = 6; /* start on a Sunday */
-    JSInt32 days    = 0;
-    JSInt32 seconds = 0;
-    JSInt32 minutes = 0;
-    JSInt32 hours   = 0;
-    JSInt32 isleap  = 0;
-
-    /* Temporaries used for various computations */
-    JSInt64 result;
-    JSInt64	result1;
-    JSInt64	result2;
-
-    JSInt64 base;
-
-    /* Some variables for intermediate result storage to make computing isleap
-       easier/faster */
-    JSInt32 fourCenturyBlocks;
-    JSInt32 centuriesLeft;
-    JSInt32 fourYearBlocksLeft;
-    JSInt32 yearsLeft;
-
-    /* Since leap years work by 400/100/4 year intervals, precompute the length
-       of those in seconds if they start at the beginning of year 1. */
-    JSInt64 fourYears;
-    JSInt64 century;
-    JSInt64 fourCenturies;
-
-    JSLL_UI2L(result, PRMJ_DAY_SECONDS);
-
-    JSLL_I2L(fourYears, PRMJ_FOUR_YEARS_DAYS);
-    JSLL_MUL(fourYears, fourYears, result);
-
-    JSLL_I2L(century, PRMJ_CENTURY_DAYS);
-    JSLL_MUL(century, century, result);
-
-    JSLL_I2L(fourCenturies, PRMJ_FOUR_CENTURIES_DAYS);
-    JSLL_MUL(fourCenturies, fourCenturies, result);
-
-    /* get the base time via UTC */
-    base = PRMJ_ToExtendedTime(0);
-    JSLL_UI2L(result,  PRMJ_USEC_PER_SEC);
-    JSLL_DIV(base,base,result);
-    JSLL_ADD(tsecs,tsecs,base);
-
-    /* Compute our |year|, |isleap|, and part of |days|.  When this part is
-       done, |year| should hold the year our date falls in (number of whole
-       years elapsed before our date), isleap should hold 1 if the year the
-       date falls in is a leap year and 0 otherwise. */
-
-    /* First do year 0; it's special and nonleap. */
-    JSLL_UI2L(result, PRMJ_YEAR_SECONDS);
-    if (!JSLL_CMP(tsecs,<,result)) {
-        days = PRMJ_YEAR_DAYS;
-        year = 1;
-        JSLL_SUB(tsecs, tsecs, result);
-    }
-
-    /* Now use those constants we computed above */
-    JSLL_UDIVMOD(&result1, &result2, tsecs, fourCenturies);
-    JSLL_L2I(fourCenturyBlocks, result1);
-    year += fourCenturyBlocks * 400;
-    days += fourCenturyBlocks * PRMJ_FOUR_CENTURIES_DAYS;
-    tsecs = result2;
-
-    JSLL_UDIVMOD(&result1, &result2, tsecs, century);
-    JSLL_L2I(centuriesLeft, result1);
-    year += centuriesLeft * 100;
-    days += centuriesLeft * PRMJ_CENTURY_DAYS;
-    tsecs = result2;
-
-    JSLL_UDIVMOD(&result1, &result2, tsecs, fourYears);
-    JSLL_L2I(fourYearBlocksLeft, result1);
-    year += fourYearBlocksLeft * 4;
-    days += fourYearBlocksLeft * PRMJ_FOUR_YEARS_DAYS;
-    tsecs = result2;
-
-    /* Recall that |result| holds PRMJ_YEAR_SECONDS */
-    JSLL_UDIVMOD(&result1, &result2, tsecs, result);
-    JSLL_L2I(yearsLeft, result1);
-    year += yearsLeft;
-    days += yearsLeft * PRMJ_YEAR_DAYS;
-    tsecs = result2;
-
-    /* now compute isleap.  Note that we don't have to use %, since we've
-       already computed those remainders.  Also note that they're all offset by
-       1 because of the 1 for year 0. */
-    isleap =
-        (yearsLeft == 3) && (fourYearBlocksLeft != 24 || centuriesLeft == 3);
-    JS_ASSERT(isleap ==
-              ((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)));
-
-    JSLL_UI2L(result1,PRMJ_DAY_SECONDS);
-
-    JSLL_DIV(result,tsecs,result1);
-    JSLL_L2I(mday,result);
-
-    /* let's find the month */
-    while(((month == 1 && isleap) ?
-            (mday >= mtab[month] + 1) :
-            (mday >= mtab[month]))){
-	 yday += mtab[month];
-	 days += mtab[month];
-
-	 mday -= mtab[month];
-
-         /* it's a Feb, check if this is a leap year */
-	 if(month == 1 && isleap != 0){
-	     yday++;
-	     days++;
-	     mday--;
-	 }
-	 month++;
-    }
-
-    /* now adjust tsecs */
-    JSLL_MUL(result,result,result1);
-    JSLL_SUB(tsecs,tsecs,result);
-
-    mday++; /* day of month always start with 1 */
-    days += mday;
-    wday = (days + wday) % 7;
-
-    yday += mday;
-
-    /* get the hours */
-    JSLL_UI2L(result1,PRMJ_HOUR_SECONDS);
-    JSLL_DIV(result,tsecs,result1);
-    JSLL_L2I(hours,result);
-    JSLL_MUL(result,result,result1);
-    JSLL_SUB(tsecs,tsecs,result);
-
-    /* get minutes */
-    JSLL_UI2L(result1,60);
-    JSLL_DIV(result,tsecs,result1);
-    JSLL_L2I(minutes,result);
-    JSLL_MUL(result,result,result1);
-    JSLL_SUB(tsecs,tsecs,result);
-
-    JSLL_L2I(seconds,tsecs);
-
-    prtm->tm_usec  = 0L;
-    prtm->tm_sec   = (JSInt8)seconds;
-    prtm->tm_min   = (JSInt8)minutes;
-    prtm->tm_hour  = (JSInt8)hours;
-    prtm->tm_mday  = (JSInt8)mday;
-    prtm->tm_mon   = (JSInt8)month;
-    prtm->tm_wday  = (JSInt8)wday;
-    prtm->tm_year  = (JSInt16)year;
-    prtm->tm_yday  = (JSInt16)yday;
-}
-
 JSInt64
 DSTOffsetCache::computeDSTOffsetMilliseconds(int64 localTimeSeconds)
 {
     JS_ASSERT(localTimeSeconds >= 0);
     JS_ASSERT(localTimeSeconds <= MAX_UNIX_TIMET);
 
 #if defined(XP_WIN) && !defined(WINCE)
     /* Windows does not follow POSIX. Updates to the
      * TZ environment variable are not reflected
      * immediately on that platform as they are
      * on UNIX systems without this call.
      */
     _tzset();
 #endif
 
     time_t local = static_cast<time_t>(localTimeSeconds);
-    PRMJTime prtm;
     struct tm tm;
-    PRMJ_basetime(localTimeSeconds, &prtm);
 #ifndef HAVE_LOCALTIME_R
     struct tm *ptm = localtime(&local);
     if (!ptm)
         return 0;
     tm = *ptm;
 #else
     localtime_r(&local, &tm); /* get dst information */
 #endif
 
-    JSInt32 diff = ((tm.tm_hour - prtm.tm_hour) * SECONDS_PER_HOUR) +
-                   ((tm.tm_min - prtm.tm_min) * SECONDS_PER_MINUTE);
+    JSInt32 base = PRMJ_LocalGMTDifference();
+
+    int32 dayoff = int32((localTimeSeconds - base) % (SECONDS_PER_HOUR * 24));
+    int32 tmoff = tm.tm_sec + (tm.tm_min * SECONDS_PER_MINUTE) +
+        (tm.tm_hour * SECONDS_PER_HOUR);
+
+    JSInt32 diff = tmoff - dayoff;
 
     if (diff < 0)
         diff += SECONDS_PER_DAY;
 
     return diff * MILLISECONDS_PER_SECOND;
 }
 
 JSInt64
@@ -906,22 +761,33 @@ DSTOffsetCache::getDSTOffsetMilliseconds
     }
 
     /*
      * NB: Be aware of the initial range values when making changes to this
      *     code: the first call to this method, with those initial range
      *     values, must result in a cache miss.
      */
 
+    if (rangeStartSeconds <= localTimeSeconds &&
+        localTimeSeconds <= rangeEndSeconds) {
+        noteCacheHit();
+        return offsetMilliseconds;
+    }
+
+    if (oldRangeStartSeconds <= localTimeSeconds &&
+        localTimeSeconds <= oldRangeEndSeconds) {
+        noteCacheHit();
+        return oldOffsetMilliseconds;
+    }
+
+    oldOffsetMilliseconds = offsetMilliseconds;
+    oldRangeStartSeconds = rangeStartSeconds;
+    oldRangeEndSeconds = rangeEndSeconds;
+
     if (rangeStartSeconds <= localTimeSeconds) {
-        if (localTimeSeconds <= rangeEndSeconds) {
-            noteCacheHit();
-            return offsetMilliseconds;
-        }
-
         JSInt64 newEndSeconds = JS_MIN(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET);
         if (newEndSeconds >= localTimeSeconds) {
             JSInt64 endOffsetMilliseconds = computeDSTOffsetMilliseconds(newEndSeconds);
             if (endOffsetMilliseconds == offsetMilliseconds) {
                 noteCacheMissIncrease();
                 rangeEndSeconds = newEndSeconds;
                 return offsetMilliseconds;
             }
--- a/js/src/prmjtime.h
+++ b/js/src/prmjtime.h
@@ -107,16 +107,19 @@ class DSTOffsetCache {
 #endif
 
   private:
     JSInt64 computeDSTOffsetMilliseconds(int64 localTimeSeconds);
 
     JSInt64 offsetMilliseconds;
     JSInt64 rangeStartSeconds, rangeEndSeconds;
 
+    JSInt64 oldOffsetMilliseconds;
+    JSInt64 oldRangeStartSeconds, oldRangeEndSeconds;
+
 #ifdef JS_METER_DST_OFFSET_CACHING
     size_t totalCalculations;
     size_t hit;
     size_t missIncreasing;
     size_t missDecreasing;
     size_t missIncreasingOffsetChangeUpper;
     size_t missIncreasingOffsetChangeExpand;
     size_t missLargeIncrease;
--- a/js/src/tests/ecma_5/Date/jstests.list
+++ b/js/src/tests/ecma_5/Date/jstests.list
@@ -1,2 +1,3 @@
 url-prefix ../../jsreftest.html?test=ecma_5/Date/
 script 15.9.4.2.js
+script toJSON-01.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Date/toJSON-01.js
@@ -0,0 +1,242 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'toJSON-01.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 584811;
+var summary = "Date.prototype.toJSON isn't to spec";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var called;
+
+var dateToJSON = Date.prototype.toJSON;
+assertEq(Date.prototype.hasOwnProperty("toJSON"), true);
+assertEq(typeof dateToJSON, "function");
+
+// brief test to exercise this outside of isolation, just for sanity
+var invalidDate = new Date();
+invalidDate.setTime(NaN);
+assertEq(JSON.stringify({ p: invalidDate }), '{"p":null}');
+
+
+/* 15.9.5.44 Date.prototype.toJSON ( key ) */
+assertEq(dateToJSON.length, 1);
+
+/*
+ * 1. Let O be the result of calling ToObject, giving it the this value as its
+ *    argument.
+ */
+function strictThis() { "use strict"; return this; }
+if (strictThis.call(null) === null)
+{
+  try
+  {
+    dateToJSON.call(null);
+    throw new Error("should have thrown a TypeError");
+  }
+  catch (e)
+  {
+    assertEq(e instanceof TypeError, true,
+             "ToObject throws TypeError for null/undefined");
+  }
+
+  try
+  {
+    dateToJSON.call(undefined);
+    throw new Error("should have thrown a TypeError");
+  }
+  catch (e)
+  {
+    assertEq(e instanceof TypeError, true,
+             "ToObject throws TypeError for null/undefined");
+  }
+}
+
+
+/*
+ * 2. Let tv be ToPrimitive(O, hint Number).
+ * ...expands to:
+ *    1. Let valueOf be the result of calling the [[Get]] internal method of object O with argument "valueOf".
+ *    2. If IsCallable(valueOf) is true then,
+ *       a. Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and
+ *                an empty argument list.
+ *       b. If val is a primitive value, return val.
+ *    3. Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".
+ *    4. If IsCallable(toString) is true then,
+ *       a. Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and
+ *               an empty argument list.
+ *       b. If str is a primitive value, return str.
+ *    5. Throw a TypeError exception.
+ */
+try
+{
+  var r = dateToJSON.call({ get valueOf() { throw 17; } });
+  throw new Error("didn't throw, returned: " + r);
+}
+catch (e)
+{
+  assertEq(e, 17, "bad exception: " + e);
+}
+
+called = false;
+assertEq(dateToJSON.call({ valueOf: null,
+                           toString: function() { called = true; return 12; },
+                           toISOString: function() { return "ohai"; } }),
+         "ohai");
+assertEq(called, true);
+
+called = false;
+assertEq(dateToJSON.call({ valueOf: function() { called = true; return 42; },
+                           toISOString: function() { return null; } }),
+         null);
+assertEq(called, true);
+
+try
+{
+  called = false;
+  dateToJSON.call({ valueOf: function() { called = true; return {}; },
+                    get toString() { throw 42; } });
+}
+catch (e)
+{
+  assertEq(called, true);
+  assertEq(e, 42, "bad exception: " + e);
+}
+
+called = false;
+assertEq(dateToJSON.call({ valueOf: function() { called = true; return {}; },
+                           get toString() { return function() { return 8675309; }; },
+                           toISOString: function() { return true; } }),
+         true);
+assertEq(called, true);
+
+var asserted = false;
+called = false;
+assertEq(dateToJSON.call({ valueOf: function() { called = true; return {}; },
+                           get toString()
+                           {
+                             assertEq(called, true);
+                             asserted = true;
+                             return function() { return 8675309; };
+                           },
+                           toISOString: function() { return NaN; } }),
+         NaN);
+assertEq(asserted, true);
+
+try
+{
+  var r = dateToJSON.call({ valueOf: null, toString: null,
+                            get toISOString()
+                            {
+                              throw new Error("shouldn't have been gotten");
+                            } });
+  throw new Error("didn't throw, returned: " + r);
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true, "bad exception: " + e);
+}
+
+
+/* 3. If tv is a Number and is not finite, return null. */
+assertEq(dateToJSON.call({ valueOf: function() { return Infinity; } }), null);
+assertEq(dateToJSON.call({ valueOf: function() { return -Infinity; } }), null);
+assertEq(dateToJSON.call({ valueOf: function() { return NaN; } }), null);
+
+assertEq(dateToJSON.call({ valueOf: function() { return Infinity; },
+                           toISOString: function() { return {}; } }), null);
+assertEq(dateToJSON.call({ valueOf: function() { return -Infinity; },
+                           toISOString: function() { return []; } }), null);
+assertEq(dateToJSON.call({ valueOf: function() { return NaN; },
+                           toISOString: function() { return undefined; } }), null);
+
+
+/*
+ * 4. Let toISO be the result of calling the [[Get]] internal method of O with
+ *    argument "toISOString".
+ */
+try
+{
+  var r = dateToJSON.call({ get toISOString() { throw 42; } });
+  throw new Error("didn't throw, returned: " + r);
+}
+catch (e)
+{
+  assertEq(e, 42, "bad exception: " + e);
+}
+
+
+/* 5. If IsCallable(toISO) is false, throw a TypeError exception. */
+try
+{
+  var r = dateToJSON.call({ toISOString: null });
+  throw new Error("didn't throw, returned: " + r);
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true, "bad exception: " + e);
+}
+
+try
+{
+  var r = dateToJSON.call({ toISOString: undefined });
+  throw new Error("didn't throw, returned: " + r);
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true, "bad exception: " + e);
+}
+
+try
+{
+  var r = dateToJSON.call({ toISOString: "oogabooga" });
+  throw new Error("didn't throw, returned: " + r);
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true, "bad exception: " + e);
+}
+
+try
+{
+  var r = dateToJSON.call({ toISOString: Math.PI });
+  throw new Error("didn't throw, returned: " + r);
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true, "bad exception: " + e);
+}
+
+
+/*
+ * 6. Return the result of calling the [[Call]] internal method of toISO with O
+ *    as the this value and an empty argument list.
+ */
+var o =
+  {
+    toISOString: function(a)
+    {
+      called = true;
+      assertEq(this, o);
+      assertEq(a, undefined);
+      assertEq(arguments.length, 0);
+      return obj;
+    }
+  };
+var obj = {};
+called = false;
+assertEq(dateToJSON.call(o), obj, "should have gotten obj back");
+assertEq(called, true);
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("All tests passed!");
--- a/js/src/tests/ecma_5/Expressions/11.1.5-01.js
+++ b/js/src/tests/ecma_5/Expressions/11.1.5-01.js
@@ -13,18 +13,18 @@ print(BUGNUMBER + ": " + summary);
 var o;
 
 o = { get "a b c"() { return 17; } };
 assertEq("get" in Object.getOwnPropertyDescriptor(o, "a b c"), true);
 
 o = eval('({ get "a b c"() { return 17; } })');
 assertEq("get" in Object.getOwnPropertyDescriptor(o, "a b c"), true);
 
-var f = eval("(function literalInside() { return { set 'c d e'() { } }; })");
-f = function literalInside() { return { set 'c d e'() { } }; };
+var f = eval("(function literalInside() { return { set 'c d e'(q) { } }; })");
+f = function literalInside() { return { set 'c d e'(q) { } }; };
 
 function checkO()
 {
   assertEq(3.141592654 in o, true, "fractional-named property isn't in object");
   assertEq(10000 in o, true, "exponential-named property is in object");
   assertEq(0xdeadbeef in o, true, "hex-named property is in object");
   assertEq("Infinity" in o, true, "numeric index stringified correctly");
 }
--- a/js/src/tests/ecma_5/Expressions/jstests.list
+++ b/js/src/tests/ecma_5/Expressions/jstests.list
@@ -1,3 +1,4 @@
 url-prefix ../../jsreftest.html?test=ecma_5/Expressions/
 script 11.1.5-01.js
 script named-accessor-function.js
+script object-literal-accessor-arguments.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Expressions/object-literal-accessor-arguments.js
@@ -0,0 +1,42 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'object-literal-accessor-arguments.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 536472;
+var summary =
+  'ES5: { get x(v) { } } and { set x(v, v2) { } } should be syntax errors';
+
+print(BUGNUMBER + ": " + summary);
+
+//-----------------------------------------------------------------------------
+
+function expectSyntaxError(s)
+{
+  try
+  {
+    eval(s);
+    throw new Error("no error thrown");
+  }
+  catch (e)
+  {
+    assertEq(e instanceof SyntaxError, true,
+             "expected syntax error parsing '" + s + "', got: " + e);
+  }
+}
+
+expectSyntaxError("({ get x(a) { } })");
+expectSyntaxError("({ get x(a, a) { } })");
+expectSyntaxError("({ get x(a, b) { } })");
+expectSyntaxError("({ get x(a, a, b) { } })");
+expectSyntaxError("({ get x(a, b, c) { } })");
+
+expectSyntaxError("({ set x() { } })");
+expectSyntaxError("({ set x(a, a) { } })");
+expectSyntaxError("({ set x(a, b) { } })");
+expectSyntaxError("({ set x(a, a, b) { } })");
+expectSyntaxError("({ set x(a, b, c) { } })");
+
+//-----------------------------------------------------------------------------
+
+reportCompare(true, true);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Function/arguments-caller-callee.js
@@ -0,0 +1,66 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var gTestfile = 'arguments-caller-callee.js';
+var BUGNUMBER = 514563;
+var summary = "arguments.caller and arguments.callee are poison pills in ES5";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+// behavior
+
+function expectTypeError(fun)
+{
+  try
+  {
+    fun();
+    throw new Error("didn't throw");
+  }
+  catch (e)
+  {
+    assertEq(e instanceof TypeError, true,
+             "expected TypeError calling function" +
+             ("name" in fun ? " " + fun.name : "") + ", instead got: " + e);
+  }
+}
+
+function bar() { "use strict"; return arguments; }
+expectTypeError(function barCaller() { bar().caller; });
+expectTypeError(function barCallee() { bar().callee; });
+
+function baz() { return arguments; }
+assertEq(baz().callee, baz);
+
+
+// accessor identity
+
+function strictMode() { "use strict"; return arguments; }
+var canonicalTTE = Object.getOwnPropertyDescriptor(strictMode(), "caller").get;
+
+var args = strictMode();
+
+var argsCaller = Object.getOwnPropertyDescriptor(args, "caller");
+assertEq("get" in argsCaller, true);
+assertEq("set" in argsCaller, true);
+assertEq(argsCaller.get, canonicalTTE);
+assertEq(argsCaller.set, canonicalTTE);
+
+var argsCallee = Object.getOwnPropertyDescriptor(args, "callee");
+assertEq("get" in argsCallee, true);
+assertEq("set" in argsCallee, true);
+assertEq(argsCallee.get, canonicalTTE);
+assertEq(argsCallee.set, canonicalTTE);
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("All tests passed!");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Function/arguments-property-attributes.js
@@ -0,0 +1,102 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var gTestfile = 'arguments-property-attributes.js';
+var BUGNUMBER = 516255;
+var summary = "Attributes for properties of arguments objects";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+// normal
+
+function args() { return arguments; }
+var a = args(0, 1);
+
+var argProps = Object.getOwnPropertyNames(a).sort();
+assertEq(argProps.indexOf("callee") >= 0, true);
+assertEq(argProps.indexOf("0") >= 0, true);
+assertEq(argProps.indexOf("1") >= 0, true);
+assertEq(argProps.indexOf("length") >= 0, true);
+
+var calleeDesc = Object.getOwnPropertyDescriptor(a, "callee");
+assertEq(calleeDesc.value, args);
+assertEq(calleeDesc.writable, true);
+assertEq(calleeDesc.enumerable, false);
+assertEq(calleeDesc.configurable, true);
+
+var zeroDesc = Object.getOwnPropertyDescriptor(a, "0");
+assertEq(zeroDesc.value, 0);
+assertEq(zeroDesc.writable, true);
+assertEq(zeroDesc.enumerable, true);
+assertEq(zeroDesc.configurable, true);
+
+var oneDesc = Object.getOwnPropertyDescriptor(a, "1");
+assertEq(oneDesc.value, 1);
+assertEq(oneDesc.writable, true);
+assertEq(oneDesc.enumerable, true);
+assertEq(oneDesc.configurable, true);
+
+var lengthDesc = Object.getOwnPropertyDescriptor(a, "length");
+assertEq(lengthDesc.value, 2);
+assertEq(lengthDesc.writable, true);
+assertEq(lengthDesc.enumerable, false);
+assertEq(lengthDesc.configurable, true);
+
+
+// strict
+
+function strictArgs() { "use strict"; return arguments; }
+var sa = strictArgs(0, 1);
+
+var strictArgProps = Object.getOwnPropertyNames(sa).sort();
+assertEq(strictArgProps.indexOf("callee") >= 0, true);
+assertEq(strictArgProps.indexOf("caller") >= 0, true);
+assertEq(strictArgProps.indexOf("0") >= 0, true);
+assertEq(strictArgProps.indexOf("1") >= 0, true);
+assertEq(strictArgProps.indexOf("length") >= 0, true);
+
+var strictCalleeDesc = Object.getOwnPropertyDescriptor(sa, "callee");
+assertEq(typeof strictCalleeDesc.get, "function");
+assertEq(typeof strictCalleeDesc.set, "function");
+assertEq(strictCalleeDesc.get, strictCalleeDesc.set);
+assertEq(strictCalleeDesc.enumerable, false);
+assertEq(strictCalleeDesc.configurable, false);
+
+var strictCallerDesc = Object.getOwnPropertyDescriptor(sa, "caller");
+assertEq(typeof strictCallerDesc.get, "function");
+assertEq(typeof strictCallerDesc.set, "function");
+assertEq(strictCallerDesc.get, strictCallerDesc.set);
+assertEq(strictCallerDesc.enumerable, false);
+assertEq(strictCallerDesc.configurable, false);
+
+var strictZeroDesc = Object.getOwnPropertyDescriptor(sa, "0");
+assertEq(strictZeroDesc.value, 0);
+assertEq(strictZeroDesc.writable, true);
+assertEq(strictZeroDesc.enumerable, true);
+assertEq(strictZeroDesc.configurable, true);
+
+var strictOneDesc = Object.getOwnPropertyDescriptor(sa, "1");
+assertEq(strictOneDesc.value, 1);
+assertEq(strictOneDesc.writable, true);
+assertEq(strictOneDesc.enumerable, true);
+assertEq(strictOneDesc.configurable, true);
+
+var strictLengthDesc = Object.getOwnPropertyDescriptor(sa, "length");
+assertEq(strictLengthDesc.value, 2);
+assertEq(strictLengthDesc.writable, true);
+assertEq(strictLengthDesc.enumerable, false);
+assertEq(strictLengthDesc.configurable, true);
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("All tests passed!");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Function/function-caller.js
@@ -0,0 +1,76 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var gTestfile = 'function-caller.js';
+var BUGNUMBER = 514581;
+var summary = "Function.prototype.caller should throw a TypeError for " +
+              "strict-mode functions";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+// behavior
+
+function expectTypeError(fun)
+{
+  try
+  {
+    fun();
+    throw new Error("didn't throw");
+  }
+  catch (e)
+  {
+    assertEq(e instanceof TypeError, true,
+             "expected TypeError calling function" +
+             ("name" in fun ? " " + fun.name : "") + ", instead got: " + e);
+  }
+}
+
+function bar() { "use strict"; }
+expectTypeError(function barCaller() { bar.caller; });
+
+function baz() { "use strict"; return 17; }
+expectTypeError(function bazCaller() { baz.caller; });
+
+
+// accessor identity
+
+function strictMode() { "use strict"; return 42; }
+var canonicalTTE = Object.getOwnPropertyDescriptor(strictMode, "caller").get;
+
+var barCaller = Object.getOwnPropertyDescriptor(bar, "caller");
+assertEq("get" in barCaller, true);
+assertEq("set" in barCaller, true);
+assertEq(barCaller.get, canonicalTTE);
+assertEq(barCaller.set, canonicalTTE);
+
+var barArguments = Object.getOwnPropertyDescriptor(bar, "arguments");
+assertEq("get" in barArguments, true);
+assertEq("set" in barArguments, true);
+assertEq(barArguments.get, canonicalTTE);
+assertEq(barArguments.set, canonicalTTE);
+
+var bazCaller = Object.getOwnPropertyDescriptor(baz, "caller");
+assertEq("get" in bazCaller, true);
+assertEq("set" in bazCaller, true);
+assertEq(bazCaller.get, canonicalTTE);
+assertEq(bazCaller.set, canonicalTTE);
+
+var bazArguments = Object.getOwnPropertyDescriptor(baz, "arguments");
+assertEq("get" in bazArguments, true);
+assertEq("set" in bazArguments, true);
+assertEq(bazArguments.get, canonicalTTE);
+assertEq(bazArguments.set, canonicalTTE);
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("All tests passed!");
--- a/js/src/tests/ecma_5/Function/jstests.list
+++ b/js/src/tests/ecma_5/Function/jstests.list
@@ -1,2 +1,6 @@
 url-prefix ../../jsreftest.html?test=ecma_5/Function/
 script 15.3.4.3-01.js
+script arguments-caller-callee.js
+script function-caller.js
+script strict-arguments.js
+script arguments-property-attributes.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Function/strict-arguments.js
@@ -0,0 +1,382 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var gTestfile = 'strict-arguments.js';
+var BUGNUMBER = 516255;
+var summary =
+  "ES5 strict mode: arguments objects of strict mode functions must copy " +
+  "argument values";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+function arrayEvery(arr, fun)
+{
+  return Array.prototype.every.call(arr, fun);
+}
+
+function arraysEqual(a1, a2)
+{
+  return a1.length === a2.length &&
+         arrayEvery(a1, function(v, i) { return v === a2[i]; });
+}
+
+
+/************************
+ * NON-STRICT ARGUMENTS *
+ ************************/
+
+var obj = {};
+
+function noargs() { return arguments; }
+
+assertEq(arraysEqual(noargs(), []), true);
+assertEq(arraysEqual(noargs(1), [1]), true);
+assertEq(arraysEqual(noargs(2, obj, 8), [2, obj, 8]), true);
+
+function args(a) { return arguments; }
+
+assertEq(arraysEqual(args(), []), true);
+assertEq(arraysEqual(args(1), [1]), true);
+assertEq(arraysEqual(args(1, obj), [1, obj]), true);
+assertEq(arraysEqual(args("foopy"), ["foopy"]), true);
+
+function assign(a)
+{
+  a = 17;
+  return arguments;
+}
+
+assertEq(arraysEqual(assign(1), [17]), true);
+
+function getLaterAssign(a)
+{
+  var o = arguments;
+  a = 17;
+  return o;
+}
+
+assertEq(arraysEqual(getLaterAssign(1), [17]), true);
+
+function assignElementGetParameter(a)
+{
+  arguments[0] = 17;
+  return a;
+}
+
+assertEq(assignElementGetParameter(42), 17);
+
+function assignParameterGetElement(a)
+{
+  a = 17;
+  return arguments[0];
+}
+
+assertEq(assignParameterGetElement(42), 17);
+
+
+/********************
+ * STRICT ARGUMENTS *
+ ********************/
+
+function strictNoargs()
+{
+  "use strict";
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNoargs(), []), true);
+assertEq(arraysEqual(strictNoargs(1), [1]), true);
+assertEq(arraysEqual(strictNoargs(1, obj), [1, obj]), true);
+
+function strictArgs(a)
+{
+  "use strict";
+  return arguments;
+}
+
+assertEq(arraysEqual(strictArgs(), []), true);
+assertEq(arraysEqual(strictArgs(1), [1]), true);
+assertEq(arraysEqual(strictArgs(1, obj), [1, obj]), true);
+
+function strictAssign(a)
+{
+  "use strict";
+  a = 17;
+  return arguments;
+}
+
+assertEq(arraysEqual(strictAssign(), []), true);
+assertEq(arraysEqual(strictAssign(1), [1]), true);
+assertEq(arraysEqual(strictAssign(1, obj), [1, obj]), true);
+
+var upper;
+function strictAssignAfter(a)
+{
+  "use strict";
+  upper = arguments;
+  a = 42;
+  return upper;
+}
+
+assertEq(arraysEqual(strictAssignAfter(), []), true);
+assertEq(arraysEqual(strictAssignAfter(17), [17]), true);
+assertEq(arraysEqual(strictAssignAfter(obj), [obj]), true);
+
+function strictMaybeAssignOuterParam(p)
+{
+  "use strict";
+  function inner() { p = 17; }
+  return arguments;
+}
+
+assertEq(arraysEqual(strictMaybeAssignOuterParam(), []), true);
+assertEq(arraysEqual(strictMaybeAssignOuterParam(42), [42]), true);
+assertEq(arraysEqual(strictMaybeAssignOuterParam(obj), [obj]), true);
+
+function strictAssignOuterParam(p)
+{
+  "use strict";
+  function inner() { p = 17; }
+  inner();
+  return arguments;
+}
+
+assertEq(arraysEqual(strictAssignOuterParam(), []), true);
+assertEq(arraysEqual(strictAssignOuterParam(17), [17]), true);
+assertEq(arraysEqual(strictAssignOuterParam(obj), [obj]), true);
+
+function strictAssignOuterParamPSYCH(p)
+{
+  "use strict";
+  function inner(p) { p = 17; }
+  inner();
+  return arguments;
+}
+
+assertEq(arraysEqual(strictAssignOuterParamPSYCH(), []), true);
+assertEq(arraysEqual(strictAssignOuterParamPSYCH(17), [17]), true);
+assertEq(arraysEqual(strictAssignOuterParamPSYCH(obj), [obj]), true);
+
+function strictEval(code, p)
+{
+  "use strict";
+  eval(code);
+  return arguments;
+}
+
+assertEq(arraysEqual(strictEval("1", 2), ["1", 2]), true);
+assertEq(arraysEqual(strictEval("arguments"), ["arguments"]), true);
+assertEq(arraysEqual(strictEval("p = 2"), ["p = 2"]), true);
+assertEq(arraysEqual(strictEval("p = 2", 17), ["p = 2", 17]), true);
+assertEq(arraysEqual(strictEval("arguments[0] = 17"), [17]), true);
+assertEq(arraysEqual(strictEval("arguments[0] = 17", 42), [17, 42]), true);
+
+function strictMaybeNestedEval(code, p)
+{
+  "use strict";
+  function inner() { eval(code); }
+  return arguments;
+}
+
+assertEq(arraysEqual(strictMaybeNestedEval("1", 2), ["1", 2]), true);
+assertEq(arraysEqual(strictMaybeNestedEval("arguments"), ["arguments"]), true);
+assertEq(arraysEqual(strictMaybeNestedEval("p = 2"), ["p = 2"]), true);
+assertEq(arraysEqual(strictMaybeNestedEval("p = 2", 17), ["p = 2", 17]), true);
+
+function strictNestedEval(code, p)
+{
+  "use strict";
+  function inner() { eval(code); }
+  inner();
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedEval("1", 2), ["1", 2]), true);
+assertEq(arraysEqual(strictNestedEval("arguments"), ["arguments"]), true);
+assertEq(arraysEqual(strictNestedEval("p = 2"), ["p = 2"]), true);
+assertEq(arraysEqual(strictNestedEval("p = 2", 17), ["p = 2", 17]), true);
+assertEq(arraysEqual(strictNestedEval("arguments[0] = 17"), ["arguments[0] = 17"]), true);
+assertEq(arraysEqual(strictNestedEval("arguments[0] = 17", 42), ["arguments[0] = 17", 42]), true);
+
+function strictAssignArguments(a)
+{
+  "use strict";
+  arguments[0] = 42;
+  return a;
+}
+
+assertEq(strictAssignArguments(), undefined);
+assertEq(strictAssignArguments(obj), obj);
+assertEq(strictAssignArguments(17), 17);
+
+function strictAssignParameterGetElement(a)
+{
+  "use strict";
+  a = 17;
+  return arguments[0];
+}
+
+assertEq(strictAssignParameterGetElement(42), 42);
+
+function strictNestedAssignShadowVar(p)
+{
+  "use strict";
+  function inner()
+  {
+    var p = 12;
+    function innermost() { p = 1776; return 12; }
+    return innermost();
+  }
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedAssignShadowVar(), []), true);
+assertEq(arraysEqual(strictNestedAssignShadowVar(99), [99]), true);
+assertEq(arraysEqual(strictNestedAssignShadowVar(""), [""]), true);
+assertEq(arraysEqual(strictNestedAssignShadowVar(obj), [obj]), true);
+
+function strictNestedAssignShadowCatch(p)
+{
+  "use strict";
+  function inner()
+  {
+    try
+    {
+    }
+    catch (p)
+    {
+      var f = function innermost() { p = 1776; return 12; };
+      f();
+    }
+  }
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedAssignShadowCatch(), []), true);
+assertEq(arraysEqual(strictNestedAssignShadowCatch(99), [99]), true);
+assertEq(arraysEqual(strictNestedAssignShadowCatch(""), [""]), true);
+assertEq(arraysEqual(strictNestedAssignShadowCatch(obj), [obj]), true);
+
+function strictNestedAssignShadowCatchCall(p)
+{
+  "use strict";
+  function inner()
+  {
+    try
+    {
+    }
+    catch (p)
+    {
+      var f = function innermost() { p = 1776; return 12; };
+      f();
+    }
+  }
+  inner();
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedAssignShadowCatchCall(), []), true);
+assertEq(arraysEqual(strictNestedAssignShadowCatchCall(99), [99]), true);
+assertEq(arraysEqual(strictNestedAssignShadowCatchCall(""), [""]), true);
+assertEq(arraysEqual(strictNestedAssignShadowCatchCall(obj), [obj]), true);
+
+function strictNestedAssignShadowFunction(p)
+{
+  "use strict";
+  function inner()
+  {
+    function p() { }
+    p = 1776;
+  }
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedAssignShadowFunction(), []), true);
+assertEq(arraysEqual(strictNestedAssignShadowFunction(99), [99]), true);
+assertEq(arraysEqual(strictNestedAssignShadowFunction(""), [""]), true);
+assertEq(arraysEqual(strictNestedAssignShadowFunction(obj), [obj]), true);
+
+function strictNestedAssignShadowFunctionCall(p)
+{
+  "use strict";
+  function inner()
+  {
+    function p() { }
+    p = 1776;
+  }
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedAssignShadowFunctionCall(), []), true);
+assertEq(arraysEqual(strictNestedAssignShadowFunctionCall(99), [99]), true);
+assertEq(arraysEqual(strictNestedAssignShadowFunctionCall(""), [""]), true);
+assertEq(arraysEqual(strictNestedAssignShadowFunctionCall(obj), [obj]), true);
+
+function strictNestedShadowAndMaybeEval(code, p)
+{
+  "use strict";
+  function inner(p) { eval(code); }
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedShadowAndMaybeEval("1", 2), ["1", 2]), true);
+assertEq(arraysEqual(strictNestedShadowAndMaybeEval("arguments"), ["arguments"]), true);
+assertEq(arraysEqual(strictNestedShadowAndMaybeEval("p = 2"), ["p = 2"]), true);
+assertEq(arraysEqual(strictNestedShadowAndMaybeEval("p = 2", 17), ["p = 2", 17]), true);
+assertEq(arraysEqual(strictNestedShadowAndMaybeEval("arguments[0] = 17"), ["arguments[0] = 17"]), true);
+assertEq(arraysEqual(strictNestedShadowAndMaybeEval("arguments[0] = 17", 42), ["arguments[0] = 17", 42]), true);
+
+function strictNestedShadowAndEval(code, p)
+{
+  "use strict";
+  function inner(p) { eval(code); }
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedShadowAndEval("1", 2), ["1", 2]), true);
+assertEq(arraysEqual(strictNestedShadowAndEval("arguments"), ["arguments"]), true);
+assertEq(arraysEqual(strictNestedShadowAndEval("p = 2"), ["p = 2"]), true);
+assertEq(arraysEqual(strictNestedShadowAndEval("p = 2", 17), ["p = 2", 17]), true);
+assertEq(arraysEqual(strictNestedShadowAndEval("arguments[0] = 17"), ["arguments[0] = 17"]), true);
+assertEq(arraysEqual(strictNestedShadowAndEval("arguments[0] = 17", 42), ["arguments[0] = 17", 42]), true);
+
+function strictEvalContainsMutation(code)
+{
+  "use strict";
+  return eval(code);
+}
+
+assertEq(arraysEqual(strictEvalContainsMutation("code = 17; arguments"), ["code = 17; arguments"]), true);
+assertEq(arraysEqual(strictEvalContainsMutation("arguments[0] = 17; arguments"), [17]), true);
+assertEq(strictEvalContainsMutation("arguments[0] = 17; code"), "arguments[0] = 17; code");
+
+function strictNestedAssignShadowFunctionName(p)
+{
+  "use strict";
+  function inner()
+  {
+    function p() { p = 1776; }
+    p();
+  }
+  inner();
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedAssignShadowFunctionName(), []), true);
+assertEq(arraysEqual(strictNestedAssignShadowFunctionName(99), [99]), true);
+assertEq(arraysEqual(strictNestedAssignShadowFunctionName(""), [""]), true);
+assertEq(arraysEqual(strictNestedAssignShadowFunctionName(obj), [obj]), true);
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("All tests passed!");
--- a/js/src/tests/ecma_5/JSON/jstests.list
+++ b/js/src/tests/ecma_5/JSON/jstests.list
@@ -1,2 +1,3 @@
 url-prefix ../../jsreftest.html?test=ecma_5/JSON/
 script cyclic-stringify.js
+script stringify-gap.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/JSON/stringify-gap.js
@@ -0,0 +1,52 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-gap.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 584909;
+var summary =
+  "JSON.stringify(_1, _2, numberGreaterThanOne) produces wrong output";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var LF = "\n";
+var GAP = "   ";
+
+var obj = { a: { b: [1, 2], c: { d: 3, e: 4 }, f: [], g: {}, h: [5], i: { j: 6 } } };
+
+var expected =
+  '{\n' +
+  '   "a": {\n' +
+  '      "b": [\n' +
+  '         1,\n' +
+  '         2\n' +
+  '      ],\n' +
+  '      "c": {\n' +
+  '         "d": 3,\n' +
+  '         "e": 4\n' +
+  '      },\n' +
+  '      "f": [],\n' +
+  '      "g": {},\n' +
+  '      "h": [\n' +
+  '         5\n' +
+  '      ],\n' +
+  '      "i": {\n' +
+  '         "j": 6\n' +
+  '      }\n' +
+  '   }\n' +
+  '}';
+
+assertEq(JSON.stringify(obj, null, 3), expected);
+assertEq(JSON.stringify(obj, null, "   "), expected);
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("All tests passed!");
--- a/js/src/tests/ecma_5/Object/15.2.3.3-01.js
+++ b/js/src/tests/ecma_5/Object/15.2.3.3-01.js
@@ -151,17 +151,17 @@ expected =
     writable: true,
     enumerable: true,
     configurable: true
   };
 expectDescriptor(pd, expected);
 
 /******************************************************************************/
 
-o = { get y() { return 17; }, set y() { } };
+o = { get y() { return 17; }, set y(z) { } };
 
 pd = Object.getOwnPropertyDescriptor(o, "y");
 expected =
   {
     enumerable: true,
     configurable: true
   };
 adjustDescriptorField(o, pd, expected, "get");
--- a/js/src/tests/ecma_5/strict/11.1.5.js
+++ b/js/src/tests/ecma_5/strict/11.1.5.js
@@ -98,49 +98,49 @@ assertEq(testLenientAndStrict('({get x()
                               parseRaisesException(SyntaxError)),
          true);
 
 assertEq(testLenientAndStrict('({x:1, get x() {}})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 
-assertEq(testLenientAndStrict('({set x() {}, x:1})',
+assertEq(testLenientAndStrict('({set x(q) {}, x:1})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 
-assertEq(testLenientAndStrict('({x:1, set x() {}})',
+assertEq(testLenientAndStrict('({x:1, set x(q) {}})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 
-assertEq(testLenientAndStrict('({get x() {}, set x() {}})',
+assertEq(testLenientAndStrict('({get x() {}, set x(q) {}})',
                               parsesSuccessfully,
                               parsesSuccessfully),
          true);
 
-assertEq(testLenientAndStrict('({set x() {}, get x() {}})',
+assertEq(testLenientAndStrict('({set x(q) {}, get x() {}})',
                               parsesSuccessfully,
                               parsesSuccessfully),
          true);
 
-assertEq(testLenientAndStrict('({get x() {}, set x() {}, x:1})',
+assertEq(testLenientAndStrict('({get x() {}, set x(q) {}, x:1})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 
-assertEq(testLenientAndStrict('({set x() {}, get x() {}, x:1})',
+assertEq(testLenientAndStrict('({set x(q) {}, get x() {}, x:1})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 
 assertEq(testLenientAndStrict('({get x() {}, get x() {}})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 
-assertEq(testLenientAndStrict('({get x() {}, set x() {}, y:1})',
+assertEq(testLenientAndStrict('({get x() {}, set x(q) {}, y:1})',
                               parsesSuccessfully,
                               parsesSuccessfully),
          true);
 
 reportCompare(true, true);
--- a/js/src/tests/ecma_5/strict/13.1.js
+++ b/js/src/tests/ecma_5/strict/13.1.js
@@ -78,37 +78,16 @@ assertEq(testLenientAndStrict('Function(
          true);
 assertEq(testLenientAndStrict('Function("x","y","\'use strict\'")',
                               completesNormally,
                               completesNormally),
          true);
 
 
 /*
- * The parameter lists of getters and setters in object literals
- * should not contain duplicate identifiers.
- */
-assertEq(testLenientAndStrict('({get x(y,y) {}})',
-                               parsesSuccessfully,
-                               parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x(y,y) { "use strict"; }})',
-                              parseRaisesException(SyntaxError),
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({set x(y,y) {}})',
-                               parsesSuccessfully,
-                               parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({set x(y,y) { "use strict"; }})',
-                              parseRaisesException(SyntaxError),
-                              parseRaisesException(SyntaxError)),
-         true);
-
-/*
  * The parameter lists of function expressions should not contain
  * duplicate identifiers.
  */
 assertEq(testLenientAndStrict('(function (x,x) 2)',
                                parsesSuccessfully,
                                parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict('(function (x,y) 2)',
@@ -205,40 +184,16 @@ assertEq(testLenientAndStrict('(function
 assertEq(testLenientAndStrict('(function f({x:eval}) 2)',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict('(function eval() 2)',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
-assertEq(testLenientAndStrict('({get x(eval){}})',
-                              parsesSuccessfully,
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x([eval]){}})',
-                              parsesSuccessfully,
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x({x:eval}){}})',
-                              parsesSuccessfully,
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x(eval){"use strict";}})',
-                              parseRaisesException(SyntaxError),
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x([eval]){"use strict";}})',
-                              parseRaisesException(SyntaxError),
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x({x:eval}){"use strict";}})',
-                              parseRaisesException(SyntaxError),
-                              parseRaisesException(SyntaxError)),
-         true);
 assertEq(testLenientAndStrict('({set x(eval){}})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict('({set x([eval]){}})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
@@ -333,40 +288,16 @@ assertEq(testLenientAndStrict('(function
 assertEq(testLenientAndStrict('(function f({x:arguments}) 2)',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict('(function arguments() 2)',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
-assertEq(testLenientAndStrict('({get x(arguments){}})',
-                              parsesSuccessfully,
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x([arguments]){}})',
-                              parsesSuccessfully,
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x({x:arguments}){}})',
-                              parsesSuccessfully,
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x(arguments){"use strict";}})',
-                              parseRaisesException(SyntaxError),
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x([arguments]){"use strict";}})',
-                              parseRaisesException(SyntaxError),
-                              parseRaisesException(SyntaxError)),
-         true);
-assertEq(testLenientAndStrict('({get x({x:arguments}){"use strict";}})',
-                              parseRaisesException(SyntaxError),
-                              parseRaisesException(SyntaxError)),
-         true);
 assertEq(testLenientAndStrict('({set x(arguments){}})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict('({set x([arguments]){}})',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
--- a/js/src/tests/js1_5/decompilation/regress-356083.js
+++ b/js/src/tests/js1_5/decompilation/regress-356083.js
@@ -47,19 +47,19 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
-  var f = function() { return { set this() { } }; } ;
-  expect = 'function() { return { set this() { } }; }';
+  var f = function() { return { set this(v) { } }; } ;
+  expect = 'function() { return { set this(v) { } }; }';
   actual = f + '';
 
   compareSource(expect, actual, summary);
 
-  expect = "({ set ''() {} })";
-  actual = uneval({ set ''() {} });
+  expect = "({ set ''(v) {} })";
+  actual = uneval({ set ''(v) {} });
   compareSource(expect, actual, expect);
   exitFunc ('test');
 }
--- a/js/src/tests/js1_5/extensions/regress-367501-01.js
+++ b/js/src/tests/js1_5/extensions/regress-367501-01.js
@@ -50,17 +50,17 @@ function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
   try
   { 
     expect = 'undefined';
-    var a = { set x() {} };
+    var a = { set x(v) {} };
     actual = a.x + '';
   }
   catch(ex)
   {
   }
   reportCompare(expect, actual, summary);
 
   exitFunc ('test');
--- a/js/src/tests/js1_5/extensions/regress-367501-02.js
+++ b/js/src/tests/js1_5/extensions/regress-367501-02.js
@@ -50,17 +50,17 @@ function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
   try
   {
     expect = 'undefined';
-    var a = { set x() {} };
+    var a = { set x(v) {} };
     for (var i = 0; i < 92169 - 3; ++i) a[i] = 1;
     actual = a.x + '';
     actual = a.x + '';
   }
   catch(ex)
   {
   }
   reportCompare(expect, actual, summary);
--- a/js/src/tests/js1_5/extensions/regress-367501-03.js
+++ b/js/src/tests/js1_5/extensions/regress-367501-03.js
@@ -50,17 +50,17 @@ function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
   try
   {
     expect = actual = 'No Crash';
-    var a = { set x() {} };
+    var a = { set x(v) {} };
     for (var i = 0; i < 0x4bf20 - 3; ++i) a[i] = 1;
     a.x;
     a.x.x;
   }
   catch(ex)
   {
   }
 
--- a/js/src/tests/js1_5/extensions/regress-367501-04.js
+++ b/js/src/tests/js1_5/extensions/regress-367501-04.js
@@ -50,17 +50,17 @@ function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
   try
   {
     expect = actual = 'No Crash'; 
-    var a = { set x() {} };
+    var a = { set x(v) {} };
     for (var i = 0; i < 0x10050c - 3; ++i) a[i] = 1;
     a.x;
     typeof a.x;
   }
   catch(ex)
   {
   }
 
--- a/js/src/tests/js1_8_1/regress/regress-452498-160.js
+++ b/js/src/tests/js1_8_1/regress/regress-452498-160.js
@@ -59,13 +59,13 @@ function test()
   reportCompare(expect, actual, summary + ': 1');
 
 // crash [@ js_Interpret]
   (eval("(function(){ watch(\"x\", function () { new function ()y } ); const y });"))();
   x = NaN;
   reportCompare(expect, actual, summary + ': 2');
 
 // Assertion failure: JOF_OPTYPE(op) == JOF_ATOM, at ../jsemit.cpp:5916
-  ({ set z(){},  set y()--x, set w()--w });
+  ({ set z(v){},  set y(v)--x, set w(v)--w });
   reportCompare(expect, actual, summary + ': 3');
 
   exitFunc ('test');
 }
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/destructure-accessor.js
@@ -0,0 +1,75 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'destructure-accessor.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 536472;
+var summary =
+  'ES5: { get x(v) { } } and { set x(v, v2) { } } should be syntax errors';
+
+print(BUGNUMBER + ": " + summary);
+
+//-----------------------------------------------------------------------------
+
+function expectOk(s)
+{
+  try
+  {
+    eval(s);
+    return;
+  }
+  catch (e)
+  {
+    assertEq(true, false,
+             "expected no error parsing '" + "', got : " + e);
+  }
+}
+
+function expectSyntaxError(s)
+{
+  try
+  {
+    eval(s);
+    throw new Error("no error thrown");
+  }
+  catch (e)
+  {
+    assertEq(e instanceof SyntaxError, true,
+             "expected syntax error parsing '" + s + "', got: " + e);
+  }
+}
+
+expectSyntaxError("({ get x([]) { } })");
+expectSyntaxError("({ get x({}) { } })");
+expectSyntaxError("({ get x(a, []) { } })");
+expectSyntaxError("({ get x(a, {}) { } })");
+expectSyntaxError("({ get x([], a) { } })");
+expectSyntaxError("({ get x({}, a) { } })");
+expectSyntaxError("({ get x([], a, []) { } })");
+expectSyntaxError("({ get x([], a, {}) { } })");
+expectSyntaxError("({ get x({}, a, []) { } })");
+expectSyntaxError("({ get x({}, a, {}) { } })");
+
+expectOk("({ get x() { } })");
+
+
+expectSyntaxError("({ set x() { } })");
+expectSyntaxError("({ set x(a, []) { } })");
+expectSyntaxError("({ set x(a, b, c) { } })");
+
+expectOk("({ set x([]) { } })");
+expectOk("({ set x({}) { } })");
+expectOk("({ set x([a]) { } })");
+expectOk("({ set x([a, b]) { } })");
+expectOk("({ set x([a,]) { } })");
+expectOk("({ set x([a, b,]) { } })");
+expectOk("({ set x([, b]) { } })");
+expectOk("({ set x([, b,]) { } })");
+expectOk("({ set x([, b, c]) { } })");
+expectOk("({ set x([, b, c,]) { } })");
+expectOk("({ set x({ a: a }) { } })");
+expectOk("({ set x({ a: a, b: b }) { } })");
+
+//-----------------------------------------------------------------------------
+
+reportCompare(true, true);
--- a/js/src/tests/js1_8_5/extensions/jstests.list
+++ b/js/src/tests/js1_8_5/extensions/jstests.list
@@ -7,8 +7,9 @@ skip-if(!xulRuntime.shell) script worker
 skip-if(!xulRuntime.shell) script worker-init.js
 skip-if(!xulRuntime.shell) script worker-simple.js
 skip-if(!xulRuntime.shell) script worker-terminate.js
 skip-if(!xulRuntime.shell) script worker-timeout.js
 script scripted-proxies.js
 script array-length-protochange.js
 script parseInt-octal.js
 script proxy-enumerateOwn-duplicates.js
+script destructure-accessor.js
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/lib/array-compare.js
@@ -0,0 +1,24 @@
+// Library file for tests to load.
+
+function SameValue(v1, v2)
+{
+  if (v1 === 0 && v2 === 0)
+    return 1 / v1 === 1 / v2;
+  if (v1 !== v1 && v2 !== v2)
+    return true;
+  return v1 === v2;
+}
+
+function arraysEqual(a1, a2)
+{
+  var len1 = a1.length, len2 = a2.length;
+  if (len1 !== len2)
+    return false;
+  for (var i = 0; i < len1; i++)
+  {
+    if (!SameValue(a1[i], a2[i]))
+      return false;
+  }
+  return true;
+}
+
--- a/js/src/trace-test/tests/arguments/args6.js
+++ b/js/src/trace-test/tests/arguments/args6.js
@@ -1,22 +1,22 @@
 actual = '';
-expected = '5,';
+expected = '6,';
 
 // tracing length
 
 var g = 0;
 
 function h(args) {
   g = args.length;
 }
 
 function f() {
   h(arguments);
 }
 
 for (var i = 0; i < 5; ++i) {
-  f(10, 20, 30, 40, 50);
+  f(10, 20, 30, 40, 50, 60);
 }
 appendToActual(g);
 
 
 assertEq(actual, expected)
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/nonstrict-args.js
@@ -0,0 +1,24 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function args(a) { return arguments; }
+
+var a1, a2, a3, a4;
+
+for (var i = 0; i < 5; i++)
+{
+  a1 = args();
+  a2 = args(1);
+  a3 = args(1, obj);
+  a4 = args("foopy");
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [1]), true);
+assertEq(arraysEqual(a3, [1, obj]), true);
+assertEq(arraysEqual(a4, ["foopy"]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/nonstrict-assign-element-get-parameter.js
@@ -0,0 +1,13 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+function assignElementGetParameter(a)
+{
+  arguments[0] = 17;
+  return a;
+}
+
+for (var i = 0; i < 5; i++)
+  assertEq(assignElementGetParameter(42), 17);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/nonstrict-assign-parameter-get-element.js
@@ -0,0 +1,13 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+function assignParameterGetElement(a)
+{
+  a = 17;
+  return arguments[0];
+}
+
+for (var i = 0; i < 5; i++)
+  assertEq(assignParameterGetElement(42), 17);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/nonstrict-assign.js
@@ -0,0 +1,17 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+function assign(a)
+{
+  a = 17;
+  return arguments;
+}
+
+var a1;
+for (var i = 0; i < 5; i++)
+  a1 = assign(1);
+
+assertEq(arraysEqual(a1, [17]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/nonstrict-later-assign.js
@@ -0,0 +1,18 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+function getLaterAssign(a)
+{
+  var o = arguments;
+  a = 17;
+  return o;
+}
+
+var a1, a2;
+for (var i = 0; i < 5; i++)
+  a1 = getLaterAssign(1);
+
+assertEq(arraysEqual(a1, [17]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/nonstrict-noargs.js
@@ -0,0 +1,21 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function noargs() { return arguments; }
+
+var a1, a2, a3;
+for (var i = 0; i < 5; i++)
+{
+  a1 = noargs();
+  a2 = noargs(1);
+  a3 = noargs(2, obj, 8);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [1]), true);
+assertEq(arraysEqual(a3, [2, obj, 8]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-args.js
@@ -0,0 +1,25 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictArgs(a)
+{
+  "use strict";
+  return arguments;
+}
+
+var a1, a2, a3;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictArgs();
+  a2 = strictArgs(1);
+  a3 = strictArgs(1, obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [1]), true);
+assertEq(arraysEqual(a3, [1, obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-assign-after.js
@@ -0,0 +1,28 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+var upper;
+function strictAssignAfter(a)
+{
+  "use strict";
+  upper = arguments;
+  a = 42;
+  return upper;
+}
+
+var a1, a2, a3;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictAssignAfter();
+  a2 = strictAssignAfter(17);
+  a3 = strictAssignAfter(obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [17]), true);
+assertEq(arraysEqual(a3, [obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-assign-arguments-element.js
@@ -0,0 +1,21 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictAssignArgumentsElement(a)
+{
+  "use strict";
+  arguments[0] = 42;
+  return a;
+}
+
+for (var i = 0; i < 5; i++)
+{
+  assertEq(strictAssignArgumentsElement(), undefined);
+  assertEq(strictAssignArgumentsElement(obj), obj);
+  assertEq(strictAssignArgumentsElement(17), 17);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-assign-outer-param-psych.js
@@ -0,0 +1,27 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictAssignOuterParamPSYCH(p)
+{
+  "use strict";
+  function inner(p) { p = 17; }
+  inner();
+  return arguments;
+}
+
+var a1, a2, a3;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictAssignOuterParamPSYCH();
+  a2 = strictAssignOuterParamPSYCH(17);
+  a3 = strictAssignOuterParamPSYCH(obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [17]), true);
+assertEq(arraysEqual(a3, [obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-assign-outer-param.js
@@ -0,0 +1,27 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictAssignOuterParam(p)
+{
+  "use strict";
+  function inner() { p = 17; }
+  inner();
+  return arguments;
+}
+
+var a1, a2, a3;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictAssignOuterParam();
+  a2 = strictAssignOuterParam(42);
+  a3 = strictAssignOuterParam(obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [42]), true);
+assertEq(arraysEqual(a3, [obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-assign-parameter-get-element.js
@@ -0,0 +1,14 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+function strictAssignParameterGetElement(a)
+{
+  "use strict";
+  a = 17;
+  return arguments[0];
+}
+
+for (var i = 0; i < 5; i++)
+  assertEq(strictAssignParameterGetElement(42), 42);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-assign.js
@@ -0,0 +1,26 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictAssign(a)
+{
+  "use strict";
+  a = 17;
+  return arguments;
+}
+
+var a1, a2, a3;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictAssign();
+  a2 = strictAssign(1);
+  a3 = strictAssign(1, obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [1]), true);
+assertEq(arraysEqual(a3, [1, obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-eval-mutation.js
@@ -0,0 +1,24 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictEvalMutation(code)
+{
+  "use strict";
+  return eval(code);
+}
+
+var a1, a2;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictEvalMutation("code = 17; arguments");
+  a2 = strictEvalMutation("arguments[0] = 17; arguments");
+  assertEq(strictEvalMutation("arguments[0] = 17; code"), "arguments[0] = 17; code");
+}
+
+assertEq(arraysEqual(a1, ["code = 17; arguments"]), true);
+assertEq(arraysEqual(a2, [17]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-eval.js
@@ -0,0 +1,30 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+function strictEval(code, p)
+{
+  "use strict";
+  eval(code);
+  return arguments;
+}
+
+var a1, a2, a3, a4, a5, a6;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictEval("1", 2);
+  a2 = strictEval("arguments");
+  a3 = strictEval("p = 2");
+  a4 = strictEval("p = 2", 17);
+  a5 = strictEval("arguments[0] = 17");
+  a6 = strictEval("arguments[0] = 17", 42);
+}
+
+assertEq(arraysEqual(a1, ["1", 2]), true);
+assertEq(arraysEqual(a2, ["arguments"]), true);
+assertEq(arraysEqual(a3, ["p = 2"]), true);
+assertEq(arraysEqual(a4, ["p = 2", 17]), true);
+assertEq(arraysEqual(a5, [17]), true);
+assertEq(arraysEqual(a6, [17, 42]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-maybe-assign-outer.js
@@ -0,0 +1,26 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictMaybeAssignOuterParam(p)
+{
+  "use strict";
+  function inner() { p = 17; }
+  return arguments;
+}
+
+var a1, a2, a3;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictMaybeAssignOuterParam();
+  a2 = strictMaybeAssignOuterParam(17);
+  a3 = strictMaybeAssignOuterParam(obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [17]), true);
+assertEq(arraysEqual(a3, [obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-maybe-nested-eval.js
@@ -0,0 +1,26 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+function strictMaybeNestedEval(code, p)
+{
+  "use strict";
+  function inner() { eval(code); }
+  return arguments;
+}
+
+var a1, a2, a3, a4;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictMaybeNestedEval("1", 2);
+  a2 = strictMaybeNestedEval("arguments");
+  a3 = strictMaybeNestedEval("p = 2");
+  a4 = strictMaybeNestedEval("p = 2", 17);
+}
+
+assertEq(arraysEqual(a1, ["1", 2]), true);
+assertEq(arraysEqual(a2, ["arguments"]), true);
+assertEq(arraysEqual(a3, ["p = 2"]), true);
+assertEq(arraysEqual(a4, ["p = 2", 17]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-nested-assign-shadow-function-call.js
@@ -0,0 +1,33 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictNestedAssignShadowFunctionCall(p)
+{
+  "use strict";
+  function inner()
+  {
+    function p() { }
+    p = 1776;
+  }
+  inner();
+  return arguments;
+}
+
+var a1, a2, a3, a4;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictNestedAssignShadowFunctionCall();
+  a2 = strictNestedAssignShadowFunctionCall(99);
+  a3 = strictNestedAssignShadowFunctionCall("");
+  a4 = strictNestedAssignShadowFunctionCall(obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [99]), true);
+assertEq(arraysEqual(a3, [""]), true);
+assertEq(arraysEqual(a4, [obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-nested-assign-shadow-function-name.js
@@ -0,0 +1,33 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictNestedAssignShadowFunctionName(p)
+{
+  "use strict";
+  function inner()
+  {
+    function p() { p = 1776; }
+    p();
+  }
+  inner();
+  return arguments;
+}
+
+var a1, a2, a3, a4, a5;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictNestedAssignShadowFunctionName();
+  a2 = strictNestedAssignShadowFunctionName(99);
+  a3 = strictNestedAssignShadowFunctionName("");
+  a4 = strictNestedAssignShadowFunctionName(obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [99]), true);
+assertEq(arraysEqual(a3, [""]), true);
+assertEq(arraysEqual(a4, [obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-nested-assign-shadow-function.js
@@ -0,0 +1,32 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictNestedAssignShadowFunction(p)
+{
+  "use strict";
+  function inner()
+  {
+    function p() { }
+    p = 1776;
+  }
+  return arguments;
+}
+
+var a1, a2, a3, a4;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictNestedAssignShadowFunction();
+  a2 = strictNestedAssignShadowFunction(99);
+  a3 = strictNestedAssignShadowFunction("");
+  a4 = strictNestedAssignShadowFunction(obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [99]), true);
+assertEq(arraysEqual(a3, [""]), true);
+assertEq(arraysEqual(a4, [obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-nested-assign-shadowed-catch-call.js
@@ -0,0 +1,39 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictNestedAssignShadowCatchCall(p)
+{
+  "use strict";
+  function inner()
+  {
+    try
+    {
+    }
+    catch (p)
+    {
+      var f = function innermost() { p = 1776; return 12; };
+      f();
+    }
+  }
+  inner();
+  return arguments;
+}
+
+var a1, a2, a3, a4;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictNestedAssignShadowCatchCall();
+  a2 = strictNestedAssignShadowCatchCall(99);
+  a3 = strictNestedAssignShadowCatchCall("");
+  a4 = strictNestedAssignShadowCatchCall(obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [99]), true);
+assertEq(arraysEqual(a3, [""]), true);
+assertEq(arraysEqual(a4, [obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-nested-assign-shadowed-catch.js
@@ -0,0 +1,39 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictNestedAssignShadowCatch(p)
+{
+  "use strict";
+  function inner()
+  {
+    try
+    {
+    }
+    catch (p)
+    {
+      var f = function innermost() { p = 1776; return 12; };
+      f();
+    }
+  }
+  return arguments;
+}
+
+var a1, a2, a3, a4;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictNestedAssignShadowCatch();
+  a2 = strictNestedAssignShadowCatch(99);
+  a3 = strictNestedAssignShadowCatch("");
+  a4 = strictNestedAssignShadowCatch(obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [99]), true);
+assertEq(arraysEqual(a3, [""]), true);
+assertEq(arraysEqual(a4, [obj]), true);
+
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-nested-assign-shadowed-var.js
@@ -0,0 +1,29 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+/********************
+ * STRICT ARGUMENTS *
+ ********************/
+
+function strictNestedAssignShadowVar(p)
+{
+  "use strict";
+  function inner()
+  {
+    var p = 12;
+    function innermost() { p = 1776; return 12; }
+    return innermost();
+  }
+  return arguments;
+}
+
+assertEq(arraysEqual(strictNestedAssignShadowVar(), []), true);
+assertEq(arraysEqual(strictNestedAssignShadowVar(99), [99]), true);
+assertEq(arraysEqual(strictNestedAssignShadowVar(""), [""]), true);
+assertEq(arraysEqual(strictNestedAssignShadowVar(obj), [obj]), true);
+
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-nested-eval.js
@@ -0,0 +1,31 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+function strictNestedEval(code, p)
+{
+  "use strict";
+  function inner() { eval(code); }
+  inner();
+  return arguments;
+}
+
+var a1, a2, a3, a4, a5, a6;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictNestedEval("1", 2);
+  a2 = strictNestedEval("arguments");
+  a3 = strictNestedEval("p = 2");
+  a4 = strictNestedEval("p = 2", 17);
+  a5 = strictNestedEval("arguments[0] = 17");
+  a6 = strictNestedEval("arguments[0] = 17", 42);
+}
+
+assertEq(arraysEqual(a1, ["1", 2]), true);
+assertEq(arraysEqual(a2, ["arguments"]), true);
+assertEq(arraysEqual(a3, ["p = 2"]), true);
+assertEq(arraysEqual(a4, ["p = 2", 17]), true);
+assertEq(arraysEqual(a5, ["arguments[0] = 17"]), true);
+assertEq(arraysEqual(a6, ["arguments[0] = 17", 42]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-nested-shadow-eval.js
@@ -0,0 +1,30 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+function strictNestedShadowEval(code, p)
+{
+  "use strict";
+  function inner(p) { eval(code); }
+  return arguments;
+}
+
+var a1, a2, a3, a4, a5, a6;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictNestedShadowEval("1", 2);
+  a2 = strictNestedShadowEval("arguments");
+  a3 = strictNestedShadowEval("p = 2");
+  a4 = strictNestedShadowEval("p = 2", 17);
+  a5 = strictNestedShadowEval("arguments[0] = 17");
+  a6 = strictNestedShadowEval("arguments[0] = 17", 42);
+}
+
+assertEq(arraysEqual(a1, ["1", 2]), true);
+assertEq(arraysEqual(a2, ["arguments"]), true);
+assertEq(arraysEqual(a3, ["p = 2"]), true);
+assertEq(arraysEqual(a4, ["p = 2", 17]), true);
+assertEq(arraysEqual(a5, ["arguments[0] = 17"]), true);
+assertEq(arraysEqual(a6, ["arguments[0] = 17", 42]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-nested-shadow-maybe-eval.js
@@ -0,0 +1,30 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+function strictNestedShadowMaybeEval(code, p)
+{
+  "use strict";
+  function inner(p) { eval(code); }
+  return arguments;
+}
+
+var a1, a2, a3, a4, a5, a6;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictNestedShadowMaybeEval("1", 2);
+  a2 = strictNestedShadowMaybeEval("arguments");
+  a3 = strictNestedShadowMaybeEval("p = 2");
+  a4 = strictNestedShadowMaybeEval("p = 2", 17);
+  a5 = strictNestedShadowMaybeEval("arguments[0] = 17");
+  a6 = strictNestedShadowMaybeEval("arguments[0] = 17", 42);
+}
+
+assertEq(arraysEqual(a1, ["1", 2]), true);
+assertEq(arraysEqual(a2, ["arguments"]), true);
+assertEq(arraysEqual(a3, ["p = 2"]), true);
+assertEq(arraysEqual(a4, ["p = 2", 17]), true);
+assertEq(arraysEqual(a5, ["arguments[0] = 17"]), true);
+assertEq(arraysEqual(a6, ["arguments[0] = 17", 42]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/arguments/strict-noargs.js
@@ -0,0 +1,25 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+load(libdir + 'array-compare.js');
+
+var obj = {};
+
+function strictNoargs()
+{
+  "use strict";
+  return arguments;
+}
+
+var a1, a2, a3;
+for (var i = 0; i < 5; i++)
+{
+  a1 = strictNoargs();
+  a2 = strictNoargs(1);
+  a3 = strictNoargs(1, obj);
+}
+
+assertEq(arraysEqual(a1, []), true);
+assertEq(arraysEqual(a2, [1]), true);
+assertEq(arraysEqual(a3, [1, obj]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/basic/bug570663-1.js
@@ -0,0 +1,4 @@
+// don't crash
+for (var a = 0; a < 4; a++) {
+  switch (NaN) {}
+}
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/basic/bug570663-2.js
@@ -0,0 +1,12 @@
+function f() {
+    var x;
+    for (var a = 0; a < 4; a++) {
+	switch (NaN) {
+	default:
+	    x = a;
+	}
+    }
+    assertEq(x, 3);
+}
+
+f();
--- a/js/src/trace-test/tests/basic/bug584565.js
+++ b/js/src/trace-test/tests/basic/bug584565.js
@@ -1,10 +1,10 @@
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-// Contributor: Luke Wagner <lw@mozilla.com>
-
-var x, f;
-for (var i = 0; i < 100; i++) {
-    f = function() {};
-    f.foo;
-    x = f.length;
-}
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+// Contributor: Luke Wagner <lw@mozilla.com>
+
+var x, f;
+for (var i = 0; i < 100; i++) {
+    f = function() {};
+    f.foo;
+    x = f.length;
+}
--- a/js/src/trace-test/tests/basic/testAssignmentThatIgnoresSetterRetval.js
+++ b/js/src/trace-test/tests/basic/testAssignmentThatIgnoresSetterRetval.js
@@ -1,10 +1,10 @@
 var o = {
-    set x() {
+    set x(v) {
         return 42;
     }
 };
 
 for (var i = 0; i < 10; ++i) {
     var z = o.x = "choose me";
     assertEq(z, "choose me");
 }
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/basic/testReconstructImacroPCStack.js
@@ -0,0 +1,23 @@
+var actual = "";
+var expect = "TypeError: x is not a function";
+
+x = Proxy.create((function () {
+    return {
+        get: function () {}
+    }
+}()), Object.e)
+
+try {
+    Function("\
+      for(var a = 0; a < 2; ++a) {\
+        if (a == 0) {}\
+        else {\
+          x > x\
+        }\
+      }\
+    ")()
+} catch (e) {
+    actual = "" + e;
+}
+
+assertEq(actual, expect);
--- a/js/src/xpconnect/idl/nsIXPConnect.idl
+++ b/js/src/xpconnect/idl/nsIXPConnect.idl
@@ -394,41 +394,31 @@ interface nsIXPCFunctionThisTranslator :
 %{ C++
 // For use with the service manager
 // {CB6593E0-F9B2-11d2-BDD6-000064657374}
 #define NS_XPCONNECT_CID \
 { 0xcb6593e0, 0xf9b2, 0x11d2, \
     { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
 %}
 
-[uuid(4abf8614-2b0c-495f-8c67-97115470b53c)]
+[uuid(7a3c8687-6f52-47d5-9b8e-2ed8bf86c415)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     /**
      * Initializes classes on a global object that has already been created.
      */
     void
     initClasses(in JSContextPtr aJSContext,
                 in JSObjectPtr  aGlobalJSObj);
 
     /**
-     * Like initClasses, but only does some of the initialization on the
-     * existing global. In particular this function assumes that the outer
-     * window has already been connected to an inner window, so
-     * re-initializing things like XPCNativeWrapper is useless.
-     */
-    void
-    initClassesForOuterObject(in JSContextPtr aJSContext,
-                              in JSObjectPtr  aGlobalJSObj);
-
-    /**
      * Creates a new global object using the given aCOMObj as the global
      * object. The object will be set up according to the flags (defined
      * below). If you do not pass INIT_JS_STANDARD_CLASSES, then aCOMObj
      * must implement nsIXPCScriptable so it can resolve the standard
      * classes when asked by the JS engine.
      *
      * @param aJSContext the context to use while creating the global object.
      * @param aCOMObj the native object that represents the global object.
@@ -890,9 +880,16 @@ interface nsIXPConnect : nsISupports
      */
     virtual nsIPrincipal* GetPrincipal(JSObject* obj,
                                        PRBool allowShortCircuit) const = 0;
 #endif
 %}
 
     [notxpcom] void getNativeWrapperGetPropertyOp(out JSPropertyOp getProperty);
     [notxpcom] void getXrayWrapperPropertyHolderGetPropertyOp(out JSPropertyOp getProperty);
+
+    /**
+     * Creates a JS object holder around aObject that will hold the object
+     * alive for as long as the holder stays alive.
+     */
+    nsIXPConnectJSObjectHolder holdObject(in JSContextPtr aJSContext,
+                                          in JSObjectPtr aObject);
 };
--- a/js/src/xpconnect/src/XPCNativeWrapper.cpp
+++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp
@@ -742,42 +742,16 @@ XPC_NW_Construct(JSContext *cx, JSObject
 
 static JSBool
 XPC_NW_HasInstance(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp)
 {
   return JS_TRUE;
 }
 
 static JSBool
-MirrorWrappedNativeParent(JSContext *cx, XPCWrappedNative *wrapper,
-                          JSObject **result NS_OUTPARAM)
-{
-  JSObject *wn_parent = wrapper->GetFlatJSObject()->getParent();
-  if (!wn_parent) {
-    *result = nsnull;
-  } else {
-    XPCWrappedNative *parent_wrapper =
-      XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, wn_parent);
-
-    // parent_wrapper can be null if we're in a Components.utils.evalInSandbox
-    // scope. In that case, the best we can do is just use the
-    // non-native-wrapped sandbox global object for our parent.
-    if (parent_wrapper) {
-      *result = XPCNativeWrapper::GetNewOrUsed(cx, parent_wrapper, nsnull,
-                                               nsnull);
-      if (!*result)
-        return JS_FALSE;
-    } else {
-      *result = nsnull;
-    }
-  }
-  return JS_TRUE;
-}
-
-static JSBool
 XPCNativeWrapperCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                      jsval *rval)
 {
   JSStackFrame *fp = nsnull;
   JSBool constructing = JS_FALSE;
   if (JS_FrameIterator(cx, &fp) && JS_IsConstructorFrame(cx, fp)) {
     constructing = JS_TRUE;
 
@@ -1104,48 +1078,25 @@ XPCNativeWrapper::GetNewOrUsed(JSContext
     return nsnull;
   }
 
   JSObject *obj = wrapper->GetWrapper();
   if (obj) {
     return obj;
   }
 
-  JSObject *nw_parent;
-  if (!MirrorWrappedNativeParent(cx, wrapper, &nw_parent)) {
-    return nsnull;
-  }
-
-  PRBool lock;
-
-  if (!nw_parent) {
-    nw_parent = wrapper->GetScope()->GetGlobalJSObject();
-
-    lock = PR_FALSE;
-  } else {
-    lock = PR_TRUE;
-  }
-
-  if (lock) {
-    // Make sure nw_parent doesn't get collected while we're creating
-    // the new wrapper.
-    ::JS_LockGCThing(cx, nw_parent);
-  }
+  JSObject *nw_parent = wrapper->GetScope()->GetGlobalJSObject();
 
   bool call = NATIVE_HAS_FLAG(wrapper, WantCall) ||
               NATIVE_HAS_FLAG(wrapper, WantConstruct);
-  obj = ::JS_NewObjectWithGivenProto(cx, GetJSClass(call), nsnull, nw_parent);
-
-  if (lock) {
-    ::JS_UnlockGCThing(cx, nw_parent);
-  }
+  obj = JS_NewObjectWithGivenProto(cx, GetJSClass(call), nsnull, nw_parent);
 
   if (!obj ||
-      !::JS_SetPrivate(cx, obj, wrapper) ||
-      !::JS_SetReservedSlot(cx, obj, 0, JSVAL_ZERO)) {
+      !JS_SetPrivate(cx, obj, wrapper) ||
+      !JS_SetReservedSlot(cx, obj, 0, JSVAL_ZERO)) {
     return nsnull;
   }
 
   wrapper->SetWrapper(obj);
 
 #if defined(DEBUG_XPCNativeWrapper) || defined(DEBUG_xpc_leaks)
   {
     XPCCallContext ccx(NATIVE_CALLER, cx);
@@ -1180,40 +1131,20 @@ XPCNativeWrapper::CreateExplicitWrapper(
     JS_NewObjectWithGivenProto(cx, XPCNativeWrapper::GetJSClass(call), nsnull,
                                wrappedNative->GetScope()->GetGlobalJSObject());
 
   if (!wrapperObj) {
     // JS_NewObject already threw (or reported OOM).
     return JS_FALSE;
   }
 
-  if (!::JS_SetReservedSlot(cx, wrapperObj, 0, INT_TO_JSVAL(FLAG_EXPLICIT))) {
+  if (!JS_SetReservedSlot(cx, wrapperObj, 0, INT_TO_JSVAL(FLAG_EXPLICIT))) {
     return JS_FALSE;
   }
 
-  JSObject *parent = nsnull;
-
-  // Make sure wrapperObj doesn't get collected while we're wrapping
-  // parents for it.
-  JS_LockGCThing(cx, wrapperObj);
-
-  // A deep XPCNativeWrapper has a parent chain that mirrors its
-  // XPCWrappedNative's chain.
-  if (!MirrorWrappedNativeParent(cx, wrappedNative, &parent))
-    return JS_FALSE;
-
-  JS_UnlockGCThing(cx, wrapperObj);
-
-  if (!parent) {
-    parent = wrappedNative->GetScope()->GetGlobalJSObject();
-  }
-
-  if (!JS_SetParent(cx, wrapperObj, parent))
-    return JS_FALSE;
-
   // Set the XPCWrappedNative as private data in the native wrapper.
   if (!JS_SetPrivate(cx, wrapperObj, wrappedNative)) {
     return JS_FALSE;
   }
 
 #if defined(DEBUG_XPCNativeWrapper) || defined(DEBUG_xpc_leaks)
   {
     XPCCallContext ccx(JS_CALLER, cx);
--- a/js/src/xpconnect/src/XPCWrapper.h
+++ b/js/src/xpconnect/src/XPCWrapper.h
@@ -104,23 +104,16 @@ CanAccessWrapper(JSContext *cx, JSObject
 inline JSBool
 ClassNeedsXOW(const char *name)
 {
   switch (*name) {
     case 'W':
       return strcmp(++name, "indow") == 0;
     case 'L':
       return strcmp(++name, "ocation") == 0;
-    case 'H':
-      if (strncmp(++name, "TML", 3))
-        break;
-      name += 3;
-      if (*name == 'I')
-        ++name;
-      return strcmp(name, "FrameElement") == 0;
     default:
       break;
   }
 
   return JS_FALSE;
 }
 
 } // namespace XPCCrossOriginWrapper
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -1037,35 +1037,16 @@ nsXPConnect::InitClasses(JSContext * aJS
     }
 
     if (!InitWebGLTypes(ccx, aGlobalJSObj))
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     return NS_OK;
 }
 
-/* void initClassesForOuterObject (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */
-NS_IMETHODIMP nsXPConnect::InitClassesForOuterObject(JSContext * aJSContext, JSObject * aGlobalJSObj)
-{
-    // Nest frame chain save/restore in request created by XPCCallContext.
-    XPCCallContext ccx(NATIVE_CALLER, aJSContext);
-    if(!ccx.IsValid())
-        return UnexpectedFailure(NS_ERROR_FAILURE);
-    SaveFrame sf(aJSContext);
-
-    XPCWrappedNativeScope* scope =
-        XPCWrappedNativeScope::GetNewOrUsed(ccx, aGlobalJSObj);
-
-    if(!scope)
-        return UnexpectedFailure(NS_ERROR_FAILURE);
-
-    scope->RemoveWrappedNativeProtos();
-    return NS_OK;
-}
-
 static JSBool
 TempGlobalResolve(JSContext *aJSContext, JSObject *obj, jsid id)
 {
     JSBool resolved;
     return JS_ResolveStandardClass(aJSContext, obj, id, &resolved);
 }
 
 static JSClass xpcTempGlobalClass = {
@@ -2781,16 +2762,29 @@ nsXPConnect::GetNativeWrapperGetProperty
 {
     NS_ASSERTION(XPCNativeWrapper::GetJSClass(true)->getProperty ==
                  XPCNativeWrapper::GetJSClass(false)->getProperty,
                  "Call and NoCall XPCNativeWrapper Class must use the same "
                  "getProperty hook.");
     *getPropertyPtr = XPCNativeWrapper::GetJSClass(true)->getProperty;
 }
 
+NS_IMETHODIMP
+nsXPConnect::HoldObject(JSContext *aJSContext, JSObject *aObject,
+                        nsIXPConnectJSObjectHolder **aHolder)
+{
+    XPCCallContext ccx(NATIVE_CALLER, aJSContext);
+    XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, aObject);
+    if(!objHolder)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    NS_ADDREF(*aHolder = objHolder);
+    return NS_OK;
+}
+
 /* These are here to be callable from a debugger */
 JS_BEGIN_EXTERN_C
 JS_EXPORT_API(void) DumpJSStack()
 {
     nsresult rv;
     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
     if(NS_SUCCEEDED(rv) && xpc)
         xpc->DebugDumpJSStack(PR_TRUE, PR_TRUE, PR_FALSE);
--- a/js/src/xpconnect/src/xpcconvert.cpp
+++ b/js/src/xpconnect/src/xpcconvert.cpp
@@ -623,23 +623,25 @@ XPCConvert::JSData2Native(XPCCallContext
                 break;
             }
             chars = JS_GetStringChars(str);
             *((uint16*)d) = (uint16) chars[0];
             break;
         }
     case nsXPTType::T_JSVAL :
         {
-            NS_ASSERTION(useAllocator, "trying to convert a jsval to const jsval & without allocator : this would leak");
-
-            // The C++ type is (const jsval &), which here means (jsval *).
-            jsval *buf = new jsval(s);
-            if(!buf)
-                return JS_FALSE;
-            *((jsval**)d) = buf;
+            if (useAllocator) {
+                // The C++ type is (const jsval &), which here means (jsval *).
+                jsval *buf = new jsval(s);
+                if(!buf)
+                    return JS_FALSE;
+                *((jsval**)d) = buf;
+            } else {
+                **((jsval**)d) = s;
+            }
             break;
         }
     default:
         if(!type.IsPointer())
         {
             NS_ERROR("unsupported type");
             return JS_FALSE;
         }
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -1645,18 +1645,29 @@ XPCWrappedNative::ReparentWrapperIfFound
                 NS_ERROR("JS_SetPrototype failed");
                 return NS_ERROR_FAILURE;
             }
         }
     }
 
     // Now we can just fix up the parent and return the wrapper
 
-    if(aNewParent && !JS_SetParent(ccx, flat, aNewParent))
-        return NS_ERROR_FAILURE;
+    if(aNewParent)
+    {
+        if(!JS_SetParent(ccx, flat, aNewParent))
+            return NS_ERROR_FAILURE;
+
+        JSObject *nw;
+        if(wrapper &&
+           (nw = wrapper->GetWrapper()) &&
+           !JS_SetParent(ccx, nw, JS_GetGlobalForObject(ccx, aNewParent)))
+        {
+            return NS_ERROR_FAILURE;
+        }
+    }
 
     *aWrapper = nsnull;
     wrapper.swap(*aWrapper);
 
     return NS_OK;
 }
 
 #define IS_TEAROFF_CLASS(clazz)                                               \
@@ -1723,22 +1734,18 @@ XPCWrappedNative::GetWrappedNativeOfJSOb
 return_wrapper:
             JSBool isWN = IS_WN_WRAPPER_OBJECT(cur);
             XPCWrappedNative* wrapper =
                 isWN ? (XPCWrappedNative*) xpc_GetJSPrivate(cur) : nsnull;
             if(proto)
             {
                 XPCWrappedNativeProto* wrapper_proto =
                     isWN ? wrapper->GetProto() : GetSlimWrapperProto(cur);
-                XPCWrappedNativeScope* wrapper_scope =
-                    wrapper_proto ? wrapper_proto->GetScope() :
-                                    wrapper->GetScope();
                 if(proto != wrapper_proto &&
-                   (proto->GetScope() != wrapper_scope ||
-                    !protoClassInfo || !wrapper_proto ||
+                   (!protoClassInfo || !wrapper_proto ||
                     protoClassInfo != wrapper_proto->GetClassInfo()))
                     continue;
             }
             if(pobj2)
                 *pobj2 = isWN ? nsnull : cur;
             return wrapper;
         }