diff --git a/mozilla/js/src/xpconnect/src/xpcprivate.h b/mozilla/js/src/xpconnect/src/xpcprivate.h index 19a2f35e56c..3fd08a8108d 100644 --- a/mozilla/js/src/xpconnect/src/xpcprivate.h +++ b/mozilla/js/src/xpconnect/src/xpcprivate.h @@ -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 diff --git a/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp b/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp index 07bfc8e9a29..913a3910c87 100644 --- a/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp @@ -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); diff --git a/mozilla/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/mozilla/js/src/xpconnect/src/xpcwrappednativejsops.cpp index 17dc86748c9..75f4f19145c 100644 --- a/mozilla/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/mozilla/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -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; diff --git a/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp b/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp index 24befddad12..8ffacaeb318 100644 --- a/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp +++ b/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp @@ -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 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 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 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, \