Bug 797821 - Create XPCWrappedNativeScopes immediately after global creation. r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Thu, 25 Oct 2012 17:01:08 +0200
changeset 111527 9c24c122583b261f5298a72650558de79ee6d23b
parent 111526 23d2c7d33c79cd26d8d05896cdf2f0c86ec17266
child 111528 f060ac1febfb878360274ca36f3a0cc17db63d5c
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersmrbkap
bugs797821
milestone19.0a1
Bug 797821 - Create XPCWrappedNativeScopes immediately after global creation. r=mrbkap
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3304,24 +3304,18 @@ xpc_CreateSandboxObject(JSContext *cx, j
         JS_SetPrivate(sandbox, sop.forget().get());
 
         XPCCallContext ccx(NATIVE_CALLER, cx);
         if (!ccx.IsValid())
             return NS_ERROR_XPC_UNEXPECTED;
 
         {
           JSAutoCompartment ac(ccx, sandbox);
-          XPCWrappedNativeScope* scope =
-              XPCWrappedNativeScope::GetNewOrUsed(ccx, sandbox);
-
-          if (!scope)
-              return NS_ERROR_XPC_UNEXPECTED;
-
           if (options.wantComponents &&
-              !nsXPCComponents::AttachComponentsObject(ccx, scope))
+              !nsXPCComponents::AttachComponentsObject(ccx, XPCWrappedNativeScope::FindInJSObjectScope(ccx, sandbox)))
               return NS_ERROR_XPC_UNEXPECTED;
 
           if (!XPCNativeWrapper::AttachNewConstructorObject(ccx, sandbox))
               return NS_ERROR_XPC_UNEXPECTED;
         }
 
         if (!JS_DefineFunctions(cx, sandbox, SandboxFunctions))
             return NS_ERROR_XPC_UNEXPECTED;
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -310,33 +310,31 @@ XPCWrappedNative::WrapNewGlobal(XPCCallC
     // Finally, we get to the JSClass.
     JSClass *clasp = si->GetJSClass();
     MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
 
     // Create the global.
     JSObject *global =  xpc::CreateGlobalObject(ccx, clasp, principal);
     if (!global)
         return NS_ERROR_FAILURE;
+    XPCWrappedNativeScope *scope = GetCompartmentPrivate(global)->scope;
 
     // Immediately enter the global's compartment, so that everything else we
     // create ends up there.
     JSAutoCompartment ac(ccx, global);
 
     // If requested, initialize the standard classes on the global.
     if (initStandardClasses && ! JS_InitStandardClasses(ccx, global))
         return NS_ERROR_FAILURE;
 
-    // Create a scope, but don't do any extra stuff like initializing |Components|.
-    // All of that stuff happens in the caller.
-    XPCWrappedNativeScope *scope = XPCWrappedNativeScope::GetNewOrUsed(ccx, global);
-    MOZ_ASSERT(scope);
-
     // Make a proto.
     XPCWrappedNativeProto *proto =
-        XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, nativeHelper.GetClassInfo(), &sciProto,
+        XPCWrappedNativeProto::GetNewOrUsed(ccx,
+                                            scope,
+                                            nativeHelper.GetClassInfo(), &sciProto,
                                             UNKNOWN_OFFSETS, /* callPostCreatePrototype = */ false);
     if (!proto)
         return NS_ERROR_FAILURE;
     proto->CacheOffsets(identity);
 
     // Set up the prototype on the global.
     MOZ_ASSERT(proto->GetJSProtoObject());
     bool success = JS_SplicePrototype(ccx, global, proto->GetJSProtoObject());
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -7,16 +7,17 @@
 
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 #include "jsproxy.h"
 
 #include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
+using namespace xpc;
 
 /***************************************************************************/
 
 #ifdef XPC_TRACK_SCOPE_STATS
 static int DEBUG_TotalScopeCount;
 static int DEBUG_TotalLiveScopeCount;
 static int DEBUG_TotalMaxScopeCount;
 static int DEBUG_TotalScopeTraversalCount;
@@ -80,18 +81,19 @@ XPCWrappedNativeScope* XPCWrappedNativeS
 XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nullptr;
 
 // static
 XPCWrappedNativeScope*
 XPCWrappedNativeScope::GetNewOrUsed(JSContext *cx, JSObject* aGlobal)
 {
 
     XPCWrappedNativeScope* scope = FindInJSObjectScope(cx, aGlobal, true);
-    if (!scope)
+    if (!scope) {
         scope = new XPCWrappedNativeScope(cx, aGlobal);
+    }
     else {
         // We need to call SetGlobal in order to clear mPrototypeNoHelper (so we
         // get a new new one if requested in the new scope) in the case where
         // the global object is being reused (JS_SetAllNonReservedSlotsToUndefined
         // has been called). NOTE: We are only called by nsXPConnect::InitClasses.
         scope->SetGlobal(cx, aGlobal);
     }
     if (js::GetObjectClass(aGlobal)->flags & JSCLASS_XPCONNECT_GLOBAL)
@@ -129,16 +131,20 @@ XPCWrappedNativeScope::XPCWrappedNativeS
         mContext->AddScope(this);
     }
 
     if (aGlobal)
         SetGlobal(cx, aGlobal);
 
     DEBUG_TrackNewScope(this);
     MOZ_COUNT_CTOR(XPCWrappedNativeScope);
+
+    // Attach ourselves to the compartment private.
+    CompartmentPrivate *priv = EnsureCompartmentPrivate(aGlobal);
+    priv->scope = this;
 }
 
 // static
 JSBool
 XPCWrappedNativeScope::IsDyingScope(XPCWrappedNativeScope *scope)
 {
     for (XPCWrappedNativeScope *cur = gDyingScopes; cur; cur = cur->mNext) {
         if (scope == cur)
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -1082,17 +1082,20 @@ CreateGlobalObject(JSContext *cx, JSClas
     // Sandboxes and compilation scopes are exceptions. See bug 744034.
     CheckTypeInference(cx, clasp, principal);
 
     NS_ABORT_IF_FALSE(NS_IsMainThread(), "using a principal off the main thread?");
 
     JSObject *global = JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal));
     if (!global)
         return nullptr;
-    EnsureCompartmentPrivate(global);
+    JSAutoCompartment ac(cx, global);
+    // The constructor automatically attaches the scope to the compartment private
+    // of |global|.
+    (void) new XPCWrappedNativeScope(cx, global);
     JSCompartment *compartment = js::GetObjectCompartment(global);
 
     XPCCompartmentSet& set = nsXPConnect::GetRuntimeInstance()->GetCompartmentSet();
     if (!set.put(compartment))
         return nullptr;
 
 #ifdef DEBUG
     // Verify that the right trace hook is called. Note that this doesn't
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -4299,30 +4299,34 @@ namespace xpc {
 class CompartmentPrivate
 {
 public:
     typedef nsTHashtable<nsPtrHashKey<JSObject> > DOMExpandoMap;
 
     CompartmentPrivate()
         : wantXrays(false)
         , universalXPConnectEnabled(false)
+        , scope(nullptr)
     {
         MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
     }
 
     ~CompartmentPrivate();
 
     bool wantXrays;
 
     // This is only ever set during mochitest runs when enablePrivilege is called.
     // It's intended as a temporary stopgap measure until we can finish ripping out
     // enablePrivilege. Once set, this value is never unset (i.e., it doesn't follow
     // the old scoping rules of enablePrivilege). Using it is inherently unsafe.
     bool universalXPConnectEnabled;
 
+    // Our XPCWrappedNativeScope. This is non-null if and only if this is an
+    // XPConnect compartment.
+    XPCWrappedNativeScope *scope;
     nsAutoPtr<JSObject2JSObjectMap> waiverWrapperMap;
     nsAutoPtr<DOMExpandoMap> domExpandoMap;
 
     bool RegisterDOMExpandoObject(JSObject *expando) {
         if (!domExpandoMap) {
             domExpandoMap = new DOMExpandoMap();
             domExpandoMap->Init(8);
         }