Bug 650161 - Relocate global objects (browser changes) r=bholley
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 20 Oct 2014 09:07:43 +0100
changeset 211115 5c097e67bdb02dd12e7a172334b9044ff7cb3eea
parent 211114 c42ba3f5ac3296b5930f57b5a39ade48134ecc53
child 211116 e7f156e252529b6b9241f19dae67fee8909e8b70
push id50645
push userjcoppeard@mozilla.com
push dateMon, 20 Oct 2014 08:17:00 +0000
treeherdermozilla-inbound@e7f156e25252 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs650161
milestone36.0a1
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
Bug 650161 - Relocate global objects (browser changes) r=bholley
dom/base/nsWrapperCache.h
js/public/Class.h
js/src/jsfriendapi.cpp
js/xpconnect/public/SandboxPrivate.h
js/xpconnect/src/BackstagePass.h
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCRuntimeService.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -101,17 +101,17 @@ public:
   {
     return GetWrapperJSObject();
   }
 
   void SetWrapper(JSObject* aWrapper)
   {
     MOZ_ASSERT(!PreservingWrapper(), "Clearing a preserved wrapper!");
     MOZ_ASSERT(aWrapper, "Use ClearWrapper!");
-    MOZ_ASSERT(js::HasObjectMovedOpIfRequired(aWrapper),
+    MOZ_ASSERT(js::HasObjectMovedOp(aWrapper),
                "Object has not provided the hook to update the wrapper if it is moved");
 
     SetWrapperJSObject(aWrapper);
   }
 
   /**
    * Clear the wrapper. This should be called from the finalizer for the
    * wrapper.
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -575,17 +575,16 @@ ObjectClassIs(JSObject &obj, ESClassValu
 /* Just a helper that checks v.isObject before calling ObjectClassIs. */
 inline bool
 IsObjectWithClass(const JS::Value &v, ESClassValue classValue, JSContext *cx);
 
 /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */
 inline bool
 Unbox(JSContext *cx, JS::HandleObject obj, JS::MutableHandleValue vp);
 
-/* Check whether the object's class supplies objectMovedOp for non-global objects. */
 #ifdef DEBUG
 JS_FRIEND_API(bool)
-HasObjectMovedOpIfRequired(JSObject *obj);
+HasObjectMovedOp(JSObject *obj);
 #endif
 
 }  /* namespace js */
 
 #endif  /* js_Class_h */
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1435,17 +1435,17 @@ js::ReportErrorWithId(JSContext *cx, con
 #ifdef DEBUG
 JS_PUBLIC_API(bool)
 js::IsInRequest(JSContext *cx)
 {
     return !!cx->runtime()->requestDepth;
 }
 
 bool
-js::HasObjectMovedOpIfRequired(JSObject *obj) {
+js::HasObjectMovedOp(JSObject *obj) {
     return !!GetObjectClass(obj)->ext.objectMovedOp;
 }
 #endif
 
 #ifdef JSGC_GENERATIONAL
 JS_FRIEND_API(void)
 JS_StoreObjectPostBarrierCallback(JSContext* cx,
                                   void (*callback)(JSTracer *trc, JSObject *key, void *data),
--- a/js/xpconnect/public/SandboxPrivate.h
+++ b/js/xpconnect/public/SandboxPrivate.h
@@ -50,15 +50,20 @@ public:
         ClearWrapper();
     }
 
     virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE
     {
         MOZ_CRASH("SandboxPrivate doesn't use DOM bindings!");
     }
 
+    void ObjectMoved(JSObject *obj, const JSObject *old)
+    {
+        UpdateWrapper(obj, old);
+    }
+
 private:
     virtual ~SandboxPrivate() { }
 
     nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 #endif // __SANDBOXPRIVATE_H__
--- a/js/xpconnect/src/BackstagePass.h
+++ b/js/xpconnect/src/BackstagePass.h
@@ -10,51 +10,49 @@
 #include "nsISupports.h"
 #include "nsWeakReference.h"
 #include "nsIGlobalObject.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIXPCScriptable.h"
 
 #include "js/HeapAPI.h"
 
+class XPCWrappedNative;
+
 class BackstagePass : public nsIGlobalObject,
                       public nsIScriptObjectPrincipal,
                       public nsIXPCScriptable,
                       public nsIClassInfo,
                       public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIXPCSCRIPTABLE
   NS_DECL_NSICLASSINFO
 
   virtual nsIPrincipal* GetPrincipal() {
     return mPrincipal;
   }
 
-  virtual JSObject* GetGlobalJSObject() {
-    return mGlobal;
-  }
+  virtual JSObject* GetGlobalJSObject();
 
   virtual void ForgetGlobalObject() {
-    mGlobal = nullptr;
+    mWrapper = nullptr;
   }
 
-  virtual void SetGlobalObject(JSObject* global) {
-    mGlobal = global;
-  }
+  virtual void SetGlobalObject(JSObject* global);
 
   explicit BackstagePass(nsIPrincipal *prin) :
     mPrincipal(prin)
   {
   }
 
 private:
   virtual ~BackstagePass() { }
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
-  JS::TenuredHeap<JSObject*> mGlobal;
+  XPCWrappedNative *mWrapper;
 };
 
 nsresult
 NS_NewBackstagePass(BackstagePass** ret);
 
 #endif // BackstagePass_h__
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -306,30 +306,39 @@ sandbox_enumerate(JSContext *cx, HandleO
 static bool
 sandbox_resolve(JSContext *cx, HandleObject obj, HandleId id)
 {
     bool resolved;
     return JS_ResolveStandardClass(cx, obj, id, &resolved);
 }
 
 static void
-sandbox_finalize(JSFreeOp *fop, JSObject *obj)
+sandbox_finalize(js::FreeOp *fop, JSObject *obj)
 {
     nsIScriptObjectPrincipal *sop =
         static_cast<nsIScriptObjectPrincipal *>(xpc_GetJSPrivate(obj));
     if (!sop) {
         // sop can be null if CreateSandboxObject fails in the middle.
         return;
     }
 
     static_cast<SandboxPrivate *>(sop)->ForgetGlobalObject();
     NS_RELEASE(sop);
     DestroyProtoAndIfaceCache(obj);
 }
 
+static void
+sandbox_moved(JSObject *obj, const JSObject *old)
+{
+    nsIScriptObjectPrincipal *sop =
+        static_cast<nsIScriptObjectPrincipal *>(xpc_GetJSPrivate(obj));
+    MOZ_ASSERT(sop);
+    static_cast<SandboxPrivate *>(sop)->ObjectMoved(obj, old);
+}
+
 static bool
 sandbox_convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp)
 {
     if (type == JSTYPE_OBJECT) {
         vp.set(OBJECT_TO_JSVAL(obj));
         return true;
     }
 
@@ -439,45 +448,65 @@ sandbox_addProperty(JSContext *cx, Handl
                                writeToProto_getProperty, writeToProto_setProperty))
         return false;
 
     return true;
 }
 
 #define XPCONNECT_SANDBOX_CLASS_METADATA_SLOT (XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET)
 
-static const JSClass SandboxClass = {
+static const js::Class SandboxClass = {
     "Sandbox",
     XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
     JS_PropertyStub,   JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     sandbox_enumerate, sandbox_resolve, sandbox_convert,  sandbox_finalize,
-    nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook
+    nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook,
+    JS_NULL_CLASS_SPEC,
+    {
+      nullptr,      /* outerObject */
+      nullptr,      /* innerObject */
+      nullptr,      /* iteratorObject */
+      false,        /* isWrappedNative */
+      nullptr,      /* weakmapKeyDelegateOp */
+      sandbox_moved /* objectMovedOp */
+    },
+    JS_NULL_OBJECT_OPS
 };
 
 // Note to whomever comes here to remove addProperty hooks: billm has promised
 // to do the work for this class.
-static const JSClass SandboxWriteToProtoClass = {
+static const js::Class SandboxWriteToProtoClass = {
     "Sandbox",
     XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
     sandbox_addProperty,   JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     sandbox_enumerate, sandbox_resolve, sandbox_convert,  sandbox_finalize,
-    nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook
+    nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook,
+    JS_NULL_CLASS_SPEC,
+    {
+      nullptr,      /* outerObject */
+      nullptr,      /* innerObject */
+      nullptr,      /* iteratorObject */
+      false,        /* isWrappedNative */
+      nullptr,      /* weakmapKeyDelegateOp */
+      sandbox_moved /* objectMovedOp */
+    },
+    JS_NULL_OBJECT_OPS
 };
 
 static const JSFunctionSpec SandboxFunctions[] = {
     JS_FS("dump",    SandboxDump,    1,0),
     JS_FS("debug",   SandboxDebug,   1,0),
     JS_FS("importFunction", SandboxImport, 1,0),
     JS_FS_END
 };
 
 bool
 xpc::IsSandbox(JSObject *obj)
 {
-    const JSClass *clasp = GetObjectJSClass(obj);
+    const Class *clasp = GetObjectClass(obj);
     return clasp == &SandboxClass || clasp == &SandboxWriteToProtoClass;
 }
 
 /***************************************************************************/
 nsXPCComponents_utils_Sandbox::nsXPCComponents_utils_Sandbox()
 {
 }
 
@@ -870,21 +899,21 @@ xpc::CreateSandboxObject(JSContext *cx, 
         NS_ENSURE_TRUE(addonId, NS_ERROR_FAILURE);
     } else if (JSObject *obj = JS::CurrentGlobalOrNull(cx)) {
         if (JSAddonId *id = JS::AddonIdOfObject(obj))
             addonId = id;
     }
 
     compartmentOptions.setAddonId(addonId);
 
-    const JSClass *clasp = options.writeToGlobalPrototype
-                         ? &SandboxWriteToProtoClass
-                         : &SandboxClass;
+    const Class *clasp = options.writeToGlobalPrototype
+                       ? &SandboxWriteToProtoClass
+                       : &SandboxClass;
 
-    RootedObject sandbox(cx, xpc::CreateGlobalObject(cx, clasp,
+    RootedObject sandbox(cx, xpc::CreateGlobalObject(cx, js::Jsvalify(clasp),
                                                      principal, compartmentOptions));
     if (!sandbox)
         return NS_ERROR_FAILURE;
 
     CompartmentPrivate::Get(sandbox)->writeToGlobalPrototype =
       options.writeToGlobalPrototype;
 
     // Set up the wantXrays flag, which indicates whether xrays are desired even
--- a/js/xpconnect/src/XPCRuntimeService.cpp
+++ b/js/xpconnect/src/XPCRuntimeService.cpp
@@ -1,14 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "xpcprivate.h"
+
 #include "nsContentUtils.h"
 #include "BackstagePass.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsDOMClassInfo.h"
 #include "nsIPrincipal.h"
 
 #include "mozilla/dom/ResolveSystemBinding.h"
 
@@ -38,16 +40,33 @@ NS_IMPL_RELEASE(BackstagePass)
                             nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY   |  \
                             nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY   |  \
                             nsIXPCScriptable::DONT_ENUM_STATIC_PROPS       |  \
                             nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE    |  \
                             nsIXPCScriptable::IS_GLOBAL_OBJECT             |  \
                             nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES
 #include "xpc_map_end.h" /* This will #undef the above */
 
+
+JSObject *
+BackstagePass::GetGlobalJSObject()
+{
+    if (mWrapper)
+        return mWrapper->GetFlatJSObject();
+    return nullptr;
+}
+
+void
+BackstagePass::SetGlobalObject(JSObject* global)
+{
+    nsISupports* p = XPCWrappedNative::Get(global);
+    MOZ_ASSERT(p);
+    mWrapper = static_cast<XPCWrappedNative*>(p);
+}
+
 /* bool newResolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval id, out JSObjectPtr objp); */
 NS_IMETHODIMP
 BackstagePass::NewResolve(nsIXPConnectWrappedNative *wrapper,
                           JSContext * cx, JSObject * objArg,
                           jsid idArg, JSObject * *objpArg,
                           bool *_retval)
 {
     JS::RootedObject obj(cx, objArg);
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -506,19 +506,23 @@ XPCWrappedNativeScope::UpdateWeakPointer
 
     while (cur) {
         // Sweep waivers.
         if (cur->mWaiverWrapperMap)
             cur->mWaiverWrapperMap->Sweep();
 
         XPCWrappedNativeScope* next = cur->mNext;
 
-        // Check for finalization of the global object.  Note that global
-        // objects are never moved, so we don't need to handle updating the
-        // object pointer here.
+        if (cur->mContentXBLScope)
+            cur->mContentXBLScope.updateWeakPointerAfterGC();
+        for (size_t i = 0; i < cur->mAddonScopes.Length(); i++)
+            cur->mAddonScopes[i].updateWeakPointerAfterGC();
+
+        // Check for finalization of the global object or update our pointer if
+        // it was moved.
         if (cur->mGlobalJSObject) {
             cur->mGlobalJSObject.updateWeakPointerAfterGC();
             if (!cur->mGlobalJSObject) {
                 // Move this scope from the live list to the dying list.
                 if (prev)
                     prev->mNext = next;
                 else
                     gScopes = next;