Re-landing fix for bug 408301 to see if it really was the cause of the orange last time it landed. Make more XPConnect wrappers share their JSObject maps. r=peterv@propagandism.org, sr=brendan@mozilla.org

This commit is contained in:
jst@mozilla.org 2008-01-11 15:06:40 -08:00
parent cabcef517d
commit 0619ce52c3
4 changed files with 118 additions and 31 deletions

View File

@ -1151,6 +1151,7 @@ extern JSClass XPC_WN_NoMods_NoCall_Proto_JSClass;
extern JSClass XPC_WN_ModsAllowed_WithCall_Proto_JSClass;
extern JSClass XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
extern JSClass XPC_WN_Tearoff_JSClass;
extern JSClass XPC_WN_NoHelper_Proto_JSClass;
extern JSObjectOps * JS_DLL_CALLBACK
XPC_WN_GetObjectOpsNoCall(JSContext *cx, JSClass *clazz);
@ -1158,6 +1159,9 @@ XPC_WN_GetObjectOpsNoCall(JSContext *cx, JSClass *clazz);
extern JSObjectOps * JS_DLL_CALLBACK
XPC_WN_GetObjectOpsWithCall(JSContext *cx, JSClass *clazz);
extern JSObjectOps * JS_DLL_CALLBACK
XPC_WN_Proto_GetObjectOps(JSContext *cx, JSClass *clazz);
extern JSBool JS_DLL_CALLBACK
XPC_WN_CallMethod(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *vp);
@ -1215,6 +1219,11 @@ public:
JSObject*
GetPrototypeJSObject() const {return mPrototypeJSObject;}
// Getter for the prototype that we use for wrappers that have no
// helper.
JSObject*
GetPrototypeNoHelper(XPCCallContext& ccx);
#ifndef XPCONNECT_STANDALONE
nsIPrincipal*
GetPrincipal() const
@ -1308,8 +1317,13 @@ private:
// unless a PreCreate hook overrides it. Note that this _may_ be null (see
// constructor).
JSObject* mGlobalJSObject;
// Cached value of Object.prototype
JSObject* mPrototypeJSObject;
// Cached value of Function.prototype
JSObject* mPrototypeJSFunction;
// Prototype to use for wrappers with no helper.
JSObject* mPrototypeNoHelper;
#ifndef XPCONNECT_STANDALONE
// The script object principal instance corresponding to our current global

View File

@ -868,7 +868,11 @@ XPCWrappedNative::Init(XPCCallContext& ccx, JSObject* parent, JSBool isGlobal,
JSObject* protoJSObject = HasProto() ?
GetProto()->GetJSProtoObject() :
GetScope()->GetPrototypeJSObject();
GetScope()->GetPrototypeNoHelper(ccx);
if (!protoJSObject) {
return JS_FALSE;
}
mFlatJSObject = xpc_NewSystemInheritingJSObject(ccx, jsclazz, protoJSObject,
parent);

View File

@ -899,7 +899,7 @@ JSExtendedClass XPC_WN_NoHelper_JSClass = {
XPC_WN_NoHelper_Finalize, // finalize;
/* Optionally non-null members start here. */
nsnull, // getObjectOps;
XPC_WN_GetObjectOpsNoCall, // getObjectOps;
nsnull, // checkAccess;
nsnull, // call;
nsnull, // construct;
@ -1186,9 +1186,11 @@ JS_STATIC_DLL_CALLBACK(JSBool)
XPC_WN_JSOp_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp)
{
if(!IS_WRAPPER_CLASS(JS_GET_CLASS(cx, obj)))
JSClass *clazz = JS_GET_CLASS(cx, obj);
if(!IS_WRAPPER_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base)
{
// obj must be a prototype object. Short circuit this call to
// obj must be a prototype object or a wrapper w/o a
// helper. Short circuit this call to
// js_ObjectOps.enumerate().
return js_ObjectOps.enumerate(cx, obj, enum_op, statep, idp);
@ -1633,7 +1635,8 @@ XPC_WN_Proto_GetObjectOps(JSContext *cx, JSClass *clazz)
return &XPC_WN_WithCall_JSOps;
NS_ASSERTION(clazz == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass ||
clazz == &XPC_WN_NoMods_NoCall_Proto_JSClass,
clazz == &XPC_WN_NoMods_NoCall_Proto_JSClass ||
clazz == &XPC_WN_NoHelper_Proto_JSClass,
"bad proto");
return &XPC_WN_NoCall_JSOps;

View File

@ -119,11 +119,12 @@ XPCWrappedNativeScope::GetNewOrUsed(XPCCallContext& ccx, JSObject* aGlobal)
scope = new XPCWrappedNativeScope(ccx, aGlobal);
else
{
// We need to call SetGlobal in order to refresh our cached
// mPrototypeJSObject and mPrototypeJSFunction in the case where
// the global object is being reused (JS_ClearScope has been
// called).
// NOTE: We are only called by nsXPConnect::InitClasses.
// We need to call SetGlobal in order to refresh our cached
// mPrototypeJSObject and mPrototypeJSFunction and to clear
// mPrototypeNoHelper (so we get a new one if requested in the
// new scope) in the case where the global object is being
// reused (JS_ClearScope has been called). NOTE: We are only
// called by nsXPConnect::InitClasses.
scope->SetGlobal(ccx, aGlobal);
}
return scope;
@ -139,7 +140,8 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(XPCCallContext& ccx,
mNext(nsnull),
mGlobalJSObject(nsnull),
mPrototypeJSObject(nsnull),
mPrototypeJSFunction(nsnull)
mPrototypeJSFunction(nsnull),
mPrototypeNoHelper(nsnull)
{
// add ourselves to the scopes list
{ // scoped lock
@ -181,6 +183,41 @@ XPCWrappedNativeScope::SetComponents(nsXPCComponents* aComponents)
mComponents = aComponents;
}
// Dummy JS class to let wrappers w/o an xpc prototype share
// scopes. By doing this we avoid allocating a new scope for every
// wrapper on creation of the wrapper, and most wrappers won't need
// their own scope at all for the lifetime of the wrapper.
// JSCLASS_HAS_PRIVATE is key here (even though there's never anything
// in the private data slot in these prototypes), as the number of
// reserved slots in this class needs to match that of the wrappers
// for the JS engine to share scopes.
JSClass XPC_WN_NoHelper_Proto_JSClass = {
"XPC_WN_NoHelper_Proto_JSClass",// name;
JSCLASS_HAS_PRIVATE, // flags;
/* Mandatory non-null function pointer members. */
JS_PropertyStub, // addProperty;
JS_PropertyStub, // delProperty;
JS_PropertyStub, // getProperty;
JS_PropertyStub, // setProperty;
JS_EnumerateStub, // enumerate;
JS_ResolveStub, // resolve;
JS_ConvertStub, // convert;
JS_FinalizeStub, // finalize;
/* Optionally non-null members start here. */
XPC_WN_Proto_GetObjectOps, // getObjectOps;
nsnull, // checkAccess;
nsnull, // call;
nsnull, // construct;
nsnull, // xdrObject;
nsnull, // hasInstance;
nsnull, // mark/trace;
nsnull // spare;
};
void
XPCWrappedNativeScope::SetGlobal(XPCCallContext& ccx, JSObject* aGlobal)
{
@ -191,25 +228,24 @@ XPCWrappedNativeScope::SetGlobal(XPCCallContext& ccx, JSObject* aGlobal)
#ifndef XPCONNECT_STANDALONE
mScriptObjectPrincipal = nsnull;
// Now init our script object principal, if the new global has one
if (aGlobal)
JSContext* cx = ccx.GetJSContext();
const JSClass* jsClass = JS_GetClass(cx, aGlobal);
if(!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
JSCLASS_PRIVATE_IS_NSISUPPORTS)))
{
JSContext* cx = ccx.GetJSContext();
const JSClass* jsClass = JS_GetClass(cx, aGlobal);
if (jsClass && !(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
JSCLASS_PRIVATE_IS_NSISUPPORTS)))
// Our global has an nsISupports native pointer. Let's
// see whether it's what we want.
nsISupports* priv = (nsISupports*)JS_GetPrivate(cx, aGlobal);
nsCOMPtr<nsIXPConnectWrappedNative> native =
do_QueryInterface(priv);
if(native)
{
// Our global has an nsISupports native pointer. Let's
// see whether it's what we want.
nsISupports* priv = (nsISupports*)JS_GetPrivate(cx, aGlobal);
nsCOMPtr<nsIXPConnectWrappedNative> native =
do_QueryInterface(priv);
if (native)
{
mScriptObjectPrincipal = do_QueryWrappedNative(native);
}
if (!mScriptObjectPrincipal) {
mScriptObjectPrincipal = do_QueryInterface(priv);
}
mScriptObjectPrincipal = do_QueryWrappedNative(native);
}
if(!mScriptObjectPrincipal)
{
mScriptObjectPrincipal = do_QueryInterface(priv);
}
}
#endif
@ -247,6 +283,10 @@ XPCWrappedNativeScope::SetGlobal(XPCCallContext& ccx, JSObject* aGlobal)
NS_ERROR("Can't get globalObject.Function.prototype");
}
}
// Clear the no helper wrapper prototype object so that a new one
// gets created if needed.
mPrototypeNoHelper = nsnull;
}
XPCWrappedNativeScope::~XPCWrappedNativeScope()
@ -279,6 +319,25 @@ XPCWrappedNativeScope::~XPCWrappedNativeScope()
NS_IF_RELEASE(mComponents);
}
JSObject *
XPCWrappedNativeScope::GetPrototypeNoHelper(XPCCallContext& ccx)
{
// We could create this prototype in SetGlobal(), but all scopes
// don't need one, so we save ourselves a bit of space if we
// create these when they're needed.
if(!mPrototypeNoHelper)
{
mPrototypeNoHelper =
xpc_NewSystemInheritingJSObject(ccx, &XPC_WN_NoHelper_Proto_JSClass,
mPrototypeJSObject,
mGlobalJSObject);
NS_ASSERTION(mPrototypeNoHelper,
"Failed to create prototype for wrappers w/o a helper");
}
return mPrototypeNoHelper;
}
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
WrappedNativeJSGCThingTracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
@ -407,6 +466,11 @@ XPCWrappedNativeScope::FinishedMarkPhaseOfGC(JSContext* cx, XPCJSRuntime* rt)
{
cur->mPrototypeJSFunction = nsnull;
}
if(cur->mPrototypeNoHelper &&
JS_IsAboutToBeFinalized(cx, cur->mPrototypeNoHelper))
{
cur->mPrototypeNoHelper = nsnull;
}
}
if(cur)
prev = cur;
@ -637,11 +701,12 @@ GetScopeOfObject(JSContext* cx, JSObject* obj)
{
#ifdef DEBUG
{
if(clazz->flags & JSCLASS_HAS_PRIVATE &&
clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)
if(!(~clazz->flags & (JSCLASS_HAS_PRIVATE |
JSCLASS_PRIVATE_IS_NSISUPPORTS)) &&
(supports = (nsISupports*) JS_GetPrivate(cx, obj)))
{
nsCOMPtr<nsIXPConnectWrappedNative> iface =
do_QueryInterface((nsISupports*) JS_GetPrivate(cx, obj));
do_QueryInterface(supports);
NS_ASSERTION(!iface, "Uh, how'd this happen?");
}
@ -861,6 +926,7 @@ XPCWrappedNativeScope::DebugDump(PRInt16 depth)
XPC_LOG_ALWAYS(("mGlobalJSObject @ %x", mGlobalJSObject));
XPC_LOG_ALWAYS(("mPrototypeJSObject @ %x", mPrototypeJSObject));
XPC_LOG_ALWAYS(("mPrototypeJSFunction @ %x", mPrototypeJSFunction));
XPC_LOG_ALWAYS(("mPrototypeNoHelper @ %x", mPrototypeNoHelper));
XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)", \
mWrappedNativeMap, \