Bug 1468252 part 4 - Add JSObject::nonCCWGlobal() and use it in a few places. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 14 Jun 2018 09:07:31 -0700
changeset 422554 3d767ed287af
parent 422553 4face648a152
child 422555 e9c6358496ff
push id34138
push userdluca@mozilla.com
push date2018-06-15 02:39 +0000
treeherdermozilla-central@e51f8dbf0397 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1468252
milestone62.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 1468252 part 4 - Add JSObject::nonCCWGlobal() and use it in a few places. r=luke
js/public/Wrapper.h
js/src/builtin/Promise.cpp
js/src/builtin/TestingFunctions.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/proxy/Wrapper.cpp
js/src/vm/JSObject-inl.h
js/src/vm/JSObject.cpp
js/src/vm/JSObject.h
js/src/vm/NativeObject-inl.h
--- a/js/public/Wrapper.h
+++ b/js/public/Wrapper.h
@@ -138,17 +138,17 @@ class JS_FRIEND_API(Wrapper) : public Fo
         LAST_USED_FLAG = CROSS_COMPARTMENT
     };
 
     static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
                          const WrapperOptions& options = WrapperOptions());
 
     static JSObject* Renew(JSObject* existing, JSObject* obj, const Wrapper* handler);
 
-    static const Wrapper* wrapperHandler(JSObject* wrapper);
+    static const Wrapper* wrapperHandler(const JSObject* wrapper);
 
     static JSObject* wrappedObject(JSObject* wrapper);
 
     unsigned flags() const {
         return mFlags;
     }
 
     static const char family;
@@ -330,17 +330,17 @@ class JS_FRIEND_API(SecurityWrapper) : p
 };
 
 typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
 
 extern JSObject*
 TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj);
 
 inline bool
-IsWrapper(JSObject* obj)
+IsWrapper(const JSObject* obj)
 {
     return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family;
 }
 
 // Given a JSObject, returns that object stripped of wrappers. If
 // stopAtWindowProxy is true, then this returns the WindowProxy if it was
 // previously wrapped. Otherwise, this returns the first object for which
 // JSObject::isWrapper returns false.
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -750,17 +750,17 @@ EnqueuePromiseReactionJob(JSContext* cx,
     // unwrapping and then getting the global. This is very convoluted, but
     // much better than having to store the original global as a private value
     // because we couldn't wrap it to store it as a normal JS value.
     RootedObject global(cx);
     RootedObject objectFromIncumbentGlobal(cx, reaction->incumbentGlobalObject());
     if (objectFromIncumbentGlobal) {
         objectFromIncumbentGlobal = CheckedUnwrap(objectFromIncumbentGlobal);
         MOZ_ASSERT(objectFromIncumbentGlobal);
-        global = &objectFromIncumbentGlobal->global();
+        global = &objectFromIncumbentGlobal->nonCCWGlobal();
     }
 
     // Note: the global we pass here might be from a different compartment
     // than job and promise. While it's somewhat unusual to pass objects
     // from multiple compartments, in this case we specifically need the
     // global to be unwrapped because wrapping and unwrapping aren't
     // necessarily symmetric for globals.
     return cx->runtime()->enqueuePromiseJob(cx, job, promise, global);
@@ -1022,17 +1022,17 @@ RejectMaybeWrappedPromise(JSContext *cx,
         // rejection handler.
         if (!promise->compartment()->wrap(cx, &reason))
             return false;
         if (reason.isObject() && !CheckedUnwrap(&reason.toObject())) {
             // Report the existing reason, so we don't just drop it on the
             // floor.
             RootedObject realReason(cx, UncheckedUnwrap(&reason.toObject()));
             RootedValue realReasonVal(cx, ObjectValue(*realReason));
-            RootedObject realGlobal(cx, &realReason->global());
+            RootedObject realGlobal(cx, &realReason->nonCCWGlobal());
             ReportErrorToGlobal(cx, realGlobal, realReasonVal);
 
             // Async stacks are only properly adopted if there's at least one
             // interpreter frame active right now. If a thenable job with a
             // throwing `then` function got us here, that'll not be the case,
             // so we add one by throwing the error from self-hosted code.
             if (!GetInternalError(cx, JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON, &reason))
                 return false;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -5173,17 +5173,17 @@ ObjectGlobal(JSContext* cx, unsigned arg
     }
 
     RootedObject obj(cx, &args[0].toObject());
     if (IsWrapper(obj)) {
         args.rval().setNull();
         return true;
     }
 
-    obj = ToWindowProxyIfWindow(&obj->global());
+    obj = ToWindowProxyIfWindow(&obj->nonCCWGlobal());
 
     args.rval().setObject(*obj);
     return true;
 }
 
 JSScript*
 js::TestingFunctionArgumentToScript(JSContext* cx,
                                     HandleValue v,
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1498,17 +1498,17 @@ js::SetWindowProxy(JSContext* cx, Handle
     MOZ_ASSERT(IsWindowProxy(windowProxy));
     global->as<GlobalObject>().setWindowProxy(windowProxy);
 }
 
 JS_FRIEND_API(JSObject*)
 js::ToWindowIfWindowProxy(JSObject* obj)
 {
     if (IsWindowProxy(obj))
-        return &obj->global();
+        return &obj->nonCCWGlobal();
     return obj;
 }
 
 JS_FRIEND_API(JSObject*)
 js::detail::ToWindowProxyIfWindowSlow(JSObject* obj)
 {
     if (JSObject* windowProxy = obj->as<GlobalObject>().maybeWindowProxy())
         return windowProxy;
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -670,17 +670,17 @@ InheritanceProtoKeyForStandardClass(JSPr
     // Otherwise, we inherit [Object].
     return JSProto_Object;
 }
 
 JS_FRIEND_API(bool)
 IsFunctionObject(JSObject* obj);
 
 JS_FRIEND_API(bool)
-IsCrossCompartmentWrapper(JSObject* obj);
+IsCrossCompartmentWrapper(const JSObject* obj);
 
 static MOZ_ALWAYS_INLINE JS::Compartment*
 GetObjectCompartment(JSObject* obj)
 {
     JS::Realm* realm = reinterpret_cast<shadow::Object*>(obj)->group->realm;
     return JS::GetCompartmentForRealm(realm);
 }
 
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -487,17 +487,17 @@ CrossCompartmentWrapper::boxedValue_unbo
            NOTHING,
            Wrapper::boxedValue_unbox(cx, wrapper, vp),
            cx->compartment()->wrap(cx, vp));
 }
 
 const CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
 
 bool
-js::IsCrossCompartmentWrapper(JSObject* obj)
+js::IsCrossCompartmentWrapper(const JSObject* obj)
 {
     return IsWrapper(obj) &&
            !!(Wrapper::wrapperHandler(obj)->flags() & Wrapper::CROSS_COMPARTMENT);
 }
 
 static void
 NukeRemovedCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper)
 {
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -325,17 +325,17 @@ Wrapper::New(JSContext* cx, JSObject* ob
 JSObject*
 Wrapper::Renew(JSObject* existing, JSObject* obj, const Wrapper* handler)
 {
     existing->as<ProxyObject>().renew(handler, ObjectValue(*obj));
     return existing;
 }
 
 const Wrapper*
-Wrapper::wrapperHandler(JSObject* wrapper)
+Wrapper::wrapperHandler(const JSObject* wrapper)
 {
     MOZ_ASSERT(wrapper->is<WrapperObject>());
     return static_cast<const Wrapper*>(wrapper->as<ProxyObject>().handler());
 }
 
 JSObject*
 Wrapper::wrappedObject(JSObject* wrapper)
 {
--- a/js/src/vm/JSObject-inl.h
+++ b/js/src/vm/JSObject-inl.h
@@ -397,16 +397,23 @@ JSObject::global() const
      * The global is read-barriered so that it is kept live by access through
      * the Realm. When accessed through a JSObject, however, the global will be
      * already kept live by the black JSObject's group pointer, so does not
      * need to be read-barriered.
      */
     return *realm()->unsafeUnbarrieredMaybeGlobal();
 }
 
+inline js::GlobalObject&
+JSObject::nonCCWGlobal() const
+{
+    MOZ_ASSERT(!js::IsCrossCompartmentWrapper(this));
+    return global();
+}
+
 inline js::GlobalObject*
 JSObject::globalForTracing(JSTracer*) const
 {
     return realm()->unsafeUnbarrieredMaybeGlobal();
 }
 
 inline bool
 JSObject::isOwnGlobal(JSTracer* trc) const
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -2194,17 +2194,17 @@ js::GetObjectFromIncumbentGlobal(JSConte
         return false;
 
     return true;
 }
 
 static bool
 IsStandardPrototype(JSObject* obj, JSProtoKey key)
 {
-    Value v = obj->global().getPrototype(key);
+    Value v = obj->nonCCWGlobal().getPrototype(key);
     return v.isObject() && obj == &v.toObject();
 }
 
 JSProtoKey
 JS::IdentifyStandardInstance(JSObject* obj)
 {
     // Note: The prototype shares its JSClass with instances.
     MOZ_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
@@ -2236,17 +2236,17 @@ JS::IdentifyStandardConstructor(JSObject
 {
     // Note that NATIVE_CTOR does not imply that we are a standard constructor,
     // but the converse is true (at least until we start having self-hosted
     // constructors for standard classes). This lets us avoid a costly loop for
     // many functions (which, depending on the call site, may be the common case).
     if (!obj->is<JSFunction>() || !(obj->as<JSFunction>().flags() & JSFunction::NATIVE_CTOR))
         return JSProto_Null;
 
-    GlobalObject& global = obj->global();
+    GlobalObject& global = obj->as<JSFunction>().global();
     for (size_t k = 0; k < JSProto_LIMIT; ++k) {
         JSProtoKey key = static_cast<JSProtoKey>(k);
         if (global.getConstructor(key) == ObjectValue(*obj))
             return key;
     }
 
     return JSProto_Null;
 }
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -426,16 +426,20 @@ class JSObject : public js::gc::Cell
      * non-EnvironmentObject, this will just be the global (the name
      * "enclosing environment" still applies in this situation because
      * non-EnvironmentObjects can be on the environment chain).
      */
     inline JSObject* enclosingEnvironment() const;
 
     inline js::GlobalObject& global() const;
 
+    // Cross-compartment wrappers are not associated with a single realm/global,
+    // so this method asserts the object is not a CCW.
+    inline js::GlobalObject& nonCCWGlobal() const;
+
     // In some rare cases the global object's compartment's global may not be
     // the same global object. For this reason, we need to take extra care when
     // tracing.
     //
     // These cases are:
     //  1) The off-thread parsing task uses a dummy global since it cannot
     //     share with the actual global being used concurrently on the active
     //     thread.
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -667,17 +667,17 @@ NativeObject::allocKindForTenure() const
     if (!CanBeFinalizedInBackground(kind, getClass()))
         return kind;
     return GetBackgroundAllocKind(kind);
 }
 
 inline js::GlobalObject&
 NativeObject::global() const
 {
-    return JSObject::global();
+    return nonCCWGlobal();
 }
 
 inline js::gc::AllocKind
 PlainObject::allocKindForTenure() const
 {
     using namespace js::gc;
     AllocKind kind = GetGCObjectFixedSlotsKind(numFixedSlots());
     MOZ_ASSERT(!IsBackgroundFinalized(kind));