Add infrastructure to create main-thread WebIDL globals with XPConnect.
Add infrastructure to create main-thread WebIDL globals with XPConnect.
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2208,17 +2208,17 @@ CreateNativeGlobalForInner(JSContext* aC
// Determine if we need the Components object.
bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
TreatAsRemoteXUL(aPrincipal);
uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
if (aNewInner->IsDOMBinding()) {
aGlobal.set(WindowBinding::Wrap(aCx, aNewInner, aNewInner, options,
- nsJSPrincipals::get(aPrincipal)));
+ nsJSPrincipals::get(aPrincipal), false));
if (!aGlobal || !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
return NS_ERROR_FAILURE;
}
} else {
nsIXPConnect* xpc = nsContentUtils::XPConnect();
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
aCx, ToSupports(aNewInner),
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2209,22 +2209,25 @@ IsInCertifiedApp(JSContext* aCx, JSObjec
if (!NS_IsMainThread()) {
return GetWorkerPrivateFromContext(aCx)->IsInCertifiedApp();
}
nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aObj);
return principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
}
+#ifdef DEBUG
void
-TraceGlobal(JSTracer* aTrc, JSObject* aObj)
+VerifyTraceProtoAndIfaceCacheCalled(JSTracer *trc, void **thingp,
+ JSGCTraceKind kind)
{
- MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
- mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
+ // We don't do anything here, we only want to verify that TraceProtoAndIfaceCache
+ // was called.
}
+#endif
void
FinalizeGlobal(JSFreeOp* aFreeOp, JSObject* aObj)
{
MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
mozilla::dom::DestroyProtoAndIfaceCache(aObj);
}
@@ -2422,10 +2425,26 @@ ConvertExceptionToPromise(JSContext* cx,
ThrowMethodFailedWithDetails(cx, rv, "", "");
JS_SetPendingException(cx, exn);
return false;
}
return WrapNewBindingObject(cx, promise, rval);
}
+/* static */
+void
+CreateGlobalOptions<nsGlobalWindow>::TraceGlobal(JSTracer* aTrc, JSObject* aObj)
+{
+ mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
+ xpc::GetCompartmentPrivate(aObj)->scope->TraceSelf(aTrc);
+}
+
+/* static */
+bool
+CreateGlobalOptions<nsGlobalWindow>::PostCreateGlobal(JSContext* aCx,
+ JS::Handle<JSObject*> aGlobal)
+{
+ return XPCWrappedNativeScope::GetNewOrUsed(aCx, aGlobal);
+}
+
} // namespace dom
} // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -480,21 +480,46 @@ AllocateProtoAndIfaceCache(JSObject* obj
MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
ProtoAndIfaceCache* protoAndIfaceCache = new ProtoAndIfaceCache(aKind);
js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
JS::PrivateValue(protoAndIfaceCache));
}
+#ifdef DEBUG
+void
+VerifyTraceProtoAndIfaceCacheCalled(JSTracer *trc, void **thingp,
+ JSGCTraceKind kind);
+
+struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JSTracer
+{
+ bool ok;
+
+ VerifyTraceProtoAndIfaceCacheCalledTracer(JSRuntime *rt)
+ : JSTracer(rt, VerifyTraceProtoAndIfaceCacheCalled), ok(false)
+ {}
+};
+#endif
+
inline void
TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
{
MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
+#ifdef DEBUG
+ if (trc->callback == VerifyTraceProtoAndIfaceCacheCalled) {
+ // We don't do anything here, we only want to verify that
+ // TraceProtoAndIfaceCache was called.
+ reinterpret_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok =
+ true;
+ return;
+ }
+#endif
+
if (!HasProtoAndIfaceCache(obj))
return;
ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
protoAndIfaceCache->Trace(trc);
}
inline void
DestroyProtoAndIfaceCache(JSObject* obj)
@@ -2557,77 +2582,102 @@ IsInPrivilegedApp(JSContext* aCx, JSObje
/*
* Helper function for testing whether the given object comes from a
* certified app.
*/
bool
IsInCertifiedApp(JSContext* aCx, JSObject* aObj);
void
-TraceGlobal(JSTracer* aTrc, JSObject* aObj);
-
-void
FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
bool
ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId, JS::MutableHandle<JSObject*> aObjp);
bool
EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
-template <class T, JS::Handle<JSObject*> (*ProtoGetter)(JSContext*,
- JS::Handle<JSObject*>)>
-JSObject*
-CreateGlobal(JSContext* aCx, T* aObject, nsWrapperCache* aCache,
- const JSClass* aClass, JS::CompartmentOptions& aOptions,
- JSPrincipals* aPrincipal)
+template <class T>
+struct CreateGlobalOptions
{
- MOZ_ASSERT(!NS_IsMainThread());
+ static MOZ_CONSTEXPR_VAR ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
+ ProtoAndIfaceCache::NonWindowLike;
+ // Intl API is broken and makes JS_InitStandardClasses fail intermittently,
+ // see bug 934889.
+ static MOZ_CONSTEXPR_VAR bool ForceInitStandardClassesToFalse = true;
+ static void TraceGlobal(JSTracer* aTrc, JSObject* aObj)
+ {
+ mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
+ }
+ static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
+ {
+ MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal));
- aOptions.setTrace(TraceGlobal);
+ return true;
+ }
+};
- JS::Rooted<JSObject*> global(aCx,
- JS_NewGlobalObject(aCx, aClass, aPrincipal, JS::DontFireOnNewGlobalHook,
- aOptions));
- if (!global) {
+template <>
+struct CreateGlobalOptions<nsGlobalWindow>
+{
+ static MOZ_CONSTEXPR_VAR ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
+ ProtoAndIfaceCache::WindowLike;
+ static MOZ_CONSTEXPR_VAR bool ForceInitStandardClassesToFalse = false;
+ static void TraceGlobal(JSTracer* aTrc, JSObject* aObj);
+ static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
+};
+
+template <class T, ProtoGetter GetProto>
+bool
+CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
+ const JSClass* aClass, JS::CompartmentOptions& aOptions,
+ JSPrincipals* aPrincipal, bool aInitStandardClasses,
+ JS::MutableHandle<JSObject*> aGlobal)
+{
+ aOptions.setTrace(CreateGlobalOptions<T>::TraceGlobal);
+
+ aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
+ JS::DontFireOnNewGlobalHook, aOptions));
+ if (!aGlobal) {
NS_WARNING("Failed to create global");
return nullptr;
}
- JSAutoCompartment ac(aCx, global);
+ JSAutoCompartment ac(aCx, aGlobal);
- dom::AllocateProtoAndIfaceCache(global, ProtoAndIfaceCache::WindowLike);
-
- js::SetReservedSlot(global, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
- NS_ADDREF(aObject);
+ js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aNative));
+ NS_ADDREF(aNative);
aCache->SetIsDOMBinding();
- aCache->SetWrapper(global);
+ aCache->SetWrapper(aGlobal);
+
+ dom::AllocateProtoAndIfaceCache(aGlobal,
+ CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
- /* Intl API is broken and makes this fail intermittently, see bug 934889.
- if (!JS_InitStandardClasses(aCx, global)) {
- NS_WARNING("Failed to init standard classes");
- return nullptr;
- }
- */
-
- JS::Handle<JSObject*> proto = ProtoGetter(aCx, global);
- NS_ENSURE_TRUE(proto, nullptr);
-
- if (!JS_SetPrototype(aCx, global, proto)) {
- NS_WARNING("Failed to set proto");
- return nullptr;
+ // Call this before doing anything that can GC, the setup of our global needs
+ // to be done before a GC happens.
+ if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
+ return false;
}
- MOZ_ALWAYS_TRUE(TryPreserveWrapper(global));
+ if (aInitStandardClasses &&
+ !CreateGlobalOptions<T>::ForceInitStandardClassesToFalse &&
+ !JS_InitStandardClasses(aCx, aGlobal)) {
+ NS_WARNING("Failed to init standard classes");
+ return false;
+ }
- MOZ_ASSERT(UnwrapDOMObjectToISupports(global));
+ JS::Handle<JSObject*> proto = GetProto(aCx, aGlobal);
+ if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
+ NS_WARNING("Failed to set proto");
+ return false;
+ }
- return global;
+ return true;
}
/*
* Holds a jsid that is initialized to an interned string, with conversion to
* Handle<jsid>.
*/
class InternedStringId
{
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2945,67 +2945,79 @@ class CGWrapGlobalMethod(CGAbstractMetho
properties should be a PropertyArrays instance.
"""
def __init__(self, descriptor, properties):
assert descriptor.interface.hasInterfacePrototypeObject()
args = [Argument('JSContext*', 'aCx'),
Argument(descriptor.nativeType + '*', 'aObject'),
Argument('nsWrapperCache*', 'aCache'),
Argument('JS::CompartmentOptions&', 'aOptions'),
- Argument('JSPrincipals*', 'aPrincipal')]
+ Argument('JSPrincipals*', 'aPrincipal'),
+ Argument('bool', 'aInitStandardClasses')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
self.descriptor = descriptor
self.properties = properties
def definition_body(self):
if self.properties.hasNonChromeOnly():
properties = "GlobalPropertiesAreOwn() ? &sNativeProperties : nullptr"
else:
properties = "nullptr"
if self.properties.hasChromeOnly():
chromeProperties = "GlobalPropertiesAreOwn() && nsContentUtils::ThreadsafeIsCallerChrome() ? &sChromeOnlyNativeProperties : nullptr"
else:
chromeProperties = "nullptr"
+ if self.descriptor.workers:
+ fireOnNewGlobal = """// XXXkhuey can't do this yet until workers can lazy resolve.
+// JS_FireOnNewGlobalObject(aCx, obj);
+"""
+ else:
+ fireOnNewGlobal = ""
+
return fill(
"""
${assertions}
MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
"nsISupports must be on our primary inheritance chain");
JS::Rooted<JSObject*> obj(aCx);
- obj = CreateGlobal<${nativeType}, GetProtoObject>(aCx,
- aObject,
- aCache,
- Class.ToJSClass(),
- aOptions,
- aPrincipal);
+ CreateGlobal<${nativeType}, GetProtoObject>(aCx,
+ aObject,
+ aCache,
+ Class.ToJSClass(),
+ aOptions,
+ aPrincipal,
+ aInitStandardClasses,
+ &obj);
+ if (!obj) {
+ return nullptr;
+ }
// obj is a new global, so has a new compartment. Enter it
// before doing anything with it.
JSAutoCompartment ac(aCx, obj);
if (!DefineProperties(aCx, obj, ${properties}, ${chromeProperties})) {
return nullptr;
}
$*{unforgeable}
$*{slots}
-
- // XXXkhuey can't do this yet until workers can lazy resolve.
- // JS_FireOnNewGlobalObject(aCx, obj);
+ $*{fireOnNewGlobal}
return obj;
""",
assertions=AssertInheritanceChain(self.descriptor),
nativeType=self.descriptor.nativeType,
properties=properties,
chromeProperties=chromeProperties,
unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
- slots=InitMemberSlots(self.descriptor, True))
+ slots=InitMemberSlots(self.descriptor, True),
+ fireOnNewGlobal=fireOnNewGlobal)
class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
def __init__(self, descriptor):
args = [Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aWrapper'),
Argument(descriptor.nativeType + '*', 'aObject')]
CGAbstractStaticMethod.__init__(self, descriptor, 'UpdateMemberSlots', 'bool', args)
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -294,17 +294,18 @@ DedicatedWorkerGlobalScope::WrapGlobalOb
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(!mWorkerPrivate->IsSharedWorker());
JS::CompartmentOptions options;
mWorkerPrivate->CopyJSCompartmentOptions(options);
return DedicatedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this,
options,
- GetWorkerPrincipal());
+ GetWorkerPrincipal(),
+ true);
}
void
DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv)
{
@@ -331,17 +332,18 @@ SharedWorkerGlobalScope::WrapGlobalObjec
{
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(mWorkerPrivate->IsSharedWorker());
JS::CompartmentOptions options;
mWorkerPrivate->CopyJSCompartmentOptions(options);
return SharedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this, options,
- GetWorkerPrincipal());
+ GetWorkerPrincipal(),
+ true);
}
bool
GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr, JSMSG_GETTER_ONLY);
return false;
}
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -73,18 +73,16 @@ XPCWrappedNativeScope::XPCWrappedNativeS
mComponents(nullptr),
mNext(nullptr),
mGlobalJSObject(aGlobal),
mIsXBLScope(false)
{
// add ourselves to the scopes list
{
MOZ_ASSERT(aGlobal);
- MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
- JSCLASS_HAS_PRIVATE));
#ifdef DEBUG
for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object");
#endif
mNext = gScopes;
gScopes = this;
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -316,46 +316,19 @@ nsXPConnect::InitClasses(JSContext * aJS
scope->RemoveWrappedNativeProtos();
if (!XPCNativeWrapper::AttachNewConstructorObject(aJSContext, globalJSObj))
return UnexpectedFailure(NS_ERROR_FAILURE);
return NS_OK;
}
-#ifdef DEBUG
-static void
-VerifyTraceXPCGlobalCalled(JSTracer *trc, void **thingp, JSGCTraceKind kind)
-{
- // We don't do anything here, we only want to verify that TraceXPCGlobal
- // was called.
-}
-
-struct VerifyTraceXPCGlobalCalledTracer : public JSTracer
-{
- bool ok;
-
- VerifyTraceXPCGlobalCalledTracer(JSRuntime *rt)
- : JSTracer(rt, VerifyTraceXPCGlobalCalled), ok(false)
- {}
-};
-#endif
-
void
TraceXPCGlobal(JSTracer *trc, JSObject *obj)
{
-#ifdef DEBUG
- if (trc->callback == VerifyTraceXPCGlobalCalled) {
- // We don't do anything here, we only want to verify that TraceXPCGlobal
- // was called.
- reinterpret_cast<VerifyTraceXPCGlobalCalledTracer*>(trc)->ok = true;
- return;
- }
-#endif
-
if (js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL)
mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
}
namespace xpc {
JSObject*
CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
@@ -376,17 +349,17 @@ CreateGlobalObject(JSContext *cx, const
(void) new XPCWrappedNativeScope(cx, global);
#ifdef DEBUG
// Verify that the right trace hook is called. Note that this doesn't
// work right for wrapped globals, since the tracing situation there is
// more complicated. Manual inspection shows that they do the right thing.
if (!((const js::Class*)clasp)->ext.isWrappedNative)
{
- VerifyTraceXPCGlobalCalledTracer trc(JS_GetRuntime(cx));
+ VerifyTraceProtoAndIfaceCacheCalledTracer trc(JS_GetRuntime(cx));
JS_TraceChildren(&trc, global, JSTRACE_OBJECT);
MOZ_ASSERT(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for XPConnect compartments.");
}
#endif
if (clasp->flags & JSCLASS_DOM_GLOBAL) {
const char* className = clasp->name;
AllocateProtoAndIfaceCache(global,