[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 id15660
push userrsayre@mozilla.com
push dateSat, 11 Sep 2010 19:16:24 +0000
treeherdermozilla-central@f1bd314e64ac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.0b4pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
[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;
         }