Bug 1005978 - Add infrastructure to create main-thread WebIDL globals with XPConnect. r=bz.

--HG--
extra : rebase_source : 08c6f04e050bdd801a15883bb57d21ff93626024
This commit is contained in:
Peter Van der Beken 2014-04-08 20:48:37 +02:00
parent 3edcf39e96
commit 36aecd43e6
7 changed files with 142 additions and 82 deletions

View File

@ -2221,7 +2221,7 @@ CreateNativeGlobalForInner(JSContext* aCx,
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;
}

View File

@ -2197,12 +2197,15 @@ IsInCertifiedApp(JSContext* aCx, JSObject* aObj)
Preferences::GetBool("dom.ignore_webidl_scope_checks", false);
}
#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)
@ -2410,5 +2413,21 @@ ConvertExceptionToPromise(JSContext* cx,
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

View File

@ -483,11 +483,35 @@ AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
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.
static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok = true;
return;
}
#endif
if (!HasProtoAndIfaceCache(obj))
return;
ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
@ -2562,9 +2586,6 @@ IsInPrivilegedApp(JSContext* aCx, JSObject* aObj);
bool
IsInCertifiedApp(JSContext* aCx, JSObject* aObj);
void
TraceGlobal(JSTracer* aTrc, JSObject* aObj);
void
FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
@ -2575,55 +2596,86 @@ ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
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::AutoAssertNoGC nogc;
js::SetReservedSlot(global, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
NS_ADDREF(aObject);
// The setup of our global needs to be done before a GC happens.
js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aNative));
NS_ADDREF(aNative);
aCache->SetIsDOMBinding();
aCache->SetWrapper(global);
aCache->SetIsDOMBinding();
aCache->SetWrapper(aGlobal);
/* Intl API is broken and makes this fail intermittently, see bug 934889.
if (!JS_InitStandardClasses(aCx, global)) {
dom::AllocateProtoAndIfaceCache(aGlobal,
CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
return false;
}
}
if (aInitStandardClasses &&
!CreateGlobalOptions<T>::ForceInitStandardClassesToFalse &&
!JS_InitStandardClasses(aCx, aGlobal)) {
NS_WARNING("Failed to init standard classes");
return nullptr;
return false;
}
*/
JS::Handle<JSObject*> proto = ProtoGetter(aCx, global);
NS_ENSURE_TRUE(proto, nullptr);
if (!JS_SetPrototype(aCx, global, proto)) {
JS::Handle<JSObject*> proto = GetProto(aCx, aGlobal);
if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
NS_WARNING("Failed to set proto");
return nullptr;
return false;
}
MOZ_ALWAYS_TRUE(TryPreserveWrapper(global));
MOZ_ASSERT(UnwrapDOMObjectToISupports(global));
return global;
return true;
}
/*

View File

@ -2961,7 +2961,8 @@ class CGWrapGlobalMethod(CGAbstractMethod):
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
@ -2976,6 +2977,13 @@ class CGWrapGlobalMethod(CGAbstractMethod):
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}
@ -2983,12 +2991,17 @@ class CGWrapGlobalMethod(CGAbstractMethod):
"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.
@ -3000,9 +3013,7 @@ class CGWrapGlobalMethod(CGAbstractMethod):
$*{unforgeable}
$*{slots}
// XXXkhuey can't do this yet until workers can lazy resolve.
// JS_FireOnNewGlobalObject(aCx, obj);
$*{fireOnNewGlobal}
return obj;
""",
@ -3011,7 +3022,8 @@ class CGWrapGlobalMethod(CGAbstractMethod):
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):

View File

@ -299,7 +299,8 @@ DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx)
return DedicatedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this,
options,
GetWorkerPrincipal());
GetWorkerPrincipal(),
true);
}
void
@ -336,7 +337,8 @@ SharedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx)
mWorkerPrivate->CopyJSCompartmentOptions(options);
return SharedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this, options,
GetWorkerPrincipal());
GetWorkerPrincipal(),
true);
}
bool

View File

@ -78,8 +78,10 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext *cx,
// add ourselves to the scopes list
{
MOZ_ASSERT(aGlobal);
MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
JSCLASS_HAS_PRIVATE));
DebugOnly<const js::Class*> clasp = js::GetObjectClass(aGlobal);
MOZ_ASSERT(clasp->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
JSCLASS_HAS_PRIVATE) ||
IsDOMClass(clasp));
#ifdef DEBUG
for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object");

View File

@ -328,36 +328,9 @@ nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj)
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);
}
@ -388,7 +361,7 @@ CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
// 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.");
}