Bug 650161 - Relocate global objects (browser changes) r=bholley
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 20 Oct 2014 09:07:43 +0100
changeset 211204 5c097e67bdb02dd12e7a172334b9044ff7cb3eea
parent 211203 c42ba3f5ac3296b5930f57b5a39ade48134ecc53
child 211205 e7f156e252529b6b9241f19dae67fee8909e8b70
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbholley
bugs650161
milestone36.0a1
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;