From dcaff5f593d18d05926508cbe9a87f06e251a686 Mon Sep 17 00:00:00 2001 From: "jst%netscape.com" Date: Tue, 17 Jul 2001 06:20:37 +0000 Subject: [PATCH] Fixing bug #87389 This refreshes prototypes when classes are initialized on the context (Page transition) to prevent changes to prototypes from persisting across document loads. r=dbradley@netscape.com, sr=jst@netscape.com, patch by jband and dbradley (dbradley checking in from jst's account) git-svn-id: svn://10.0.0.236/trunk@99394 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/dom/src/base/nsJSEnvironment.cpp | 19 ++++---- mozilla/js/src/xpconnect/idl/nsIXPConnect.idl | 2 + mozilla/js/src/xpconnect/src/nsXPConnect.cpp | 7 +++ mozilla/js/src/xpconnect/src/xpcjsruntime.cpp | 43 +++++++++++++++++ mozilla/js/src/xpconnect/src/xpcmaps.h | 6 +++ mozilla/js/src/xpconnect/src/xpcprivate.h | 32 +++++++++---- .../js/src/xpconnect/src/xpcthreadcontext.cpp | 13 +++++ .../js/src/xpconnect/src/xpcwrappednative.cpp | 47 +++++++++++++++++++ .../xpconnect/src/xpcwrappednativeproto.cpp | 9 +++- .../xpconnect/src/xpcwrappednativescope.cpp | 23 +++++++++ 10 files changed, 180 insertions(+), 21 deletions(-) diff --git a/mozilla/dom/src/base/nsJSEnvironment.cpp b/mozilla/dom/src/base/nsJSEnvironment.cpp index e4c121e9d3f..19c1604165a 100644 --- a/mozilla/dom/src/base/nsJSEnvironment.cpp +++ b/mozilla/dom/src/base/nsJSEnvironment.cpp @@ -1079,7 +1079,7 @@ nsJSContext::InitContext(nsIScriptGlobalObject *aGlobalObject) NS_ENSURE_SUCCESS(rv, rv); } else { // If there's already a global object in mContext we're called - // after ::JS_ClearScope() was called. We'll haveto tell XPConnect + // after ::JS_ClearScope() was called. We'll have to tell XPConnect // to re-initialize the global object to do things like define the // Components object on the global again. rv = xpc->InitClasses(mContext, global); @@ -1088,19 +1088,18 @@ nsJSContext::InitContext(nsIScriptGlobalObject *aGlobalObject) nsCOMPtr ci(do_QueryInterface(aGlobalObject)); if (ci) { - nsCOMPtr proto_holder; + nsCOMPtr holder; - rv = xpc->GetWrappedNativePrototype(mContext, global, ci, - getter_AddRefs(proto_holder)); + rv = xpc->WrapNative(mContext, global, aGlobalObject, + NS_GET_IID(nsISupports), + getter_AddRefs(holder)); NS_ENSURE_SUCCESS(rv, rv); - JSObject *proto = nsnull; - rv = proto_holder->GetJSObject(&proto); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr wrapper(do_QueryInterface(holder)); + NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE); - if (!::JS_SetPrototype(mContext, global, proto)) { - return NS_ERROR_FAILURE; - } + rv = wrapper->RefreshPrototype(); + NS_ENSURE_SUCCESS(rv, rv); } } diff --git a/mozilla/js/src/xpconnect/idl/nsIXPConnect.idl b/mozilla/js/src/xpconnect/idl/nsIXPConnect.idl index 8fc00c4fb4d..4b75befe13e 100644 --- a/mozilla/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/mozilla/js/src/xpconnect/idl/nsIXPConnect.idl @@ -153,6 +153,8 @@ interface nsIXPConnectWrappedNative : nsIXPConnectJSObjectHolder nsIInterfaceInfo FindInterfaceWithName(in JSVal nameID); void debugDump(in short depth); + + void refreshPrototype(); }; [uuid(BED52030-BCA6-11d2-BA79-00805F8A5DD7)] diff --git a/mozilla/js/src/xpconnect/src/nsXPConnect.cpp b/mozilla/js/src/xpconnect/src/nsXPConnect.cpp index e96a33dde34..22c8afe9260 100644 --- a/mozilla/js/src/xpconnect/src/nsXPConnect.cpp +++ b/mozilla/js/src/xpconnect/src/nsXPConnect.cpp @@ -113,7 +113,12 @@ nsXPConnect::~nsXPConnect() { // scoped callcontext XPCCallContext ccx(NATIVE_CALLER); if(ccx.IsValid()) + { XPCWrappedNativeScope::SystemIsBeingShutDown(ccx); + if(mRuntime) + mRuntime->SystemIsBeingShutDown(&ccx); + + } } NS_IF_RELEASE(mInterfaceInfoManager); @@ -364,6 +369,8 @@ nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj) if(!scope) return UnexpectedFailure(NS_ERROR_FAILURE); + scope->RemoveWrappedNativeProtos(); + if(!nsXPCComponents::AttachNewComponentsObject(ccx, scope, aGlobalJSObj)) return UnexpectedFailure(NS_ERROR_FAILURE); diff --git a/mozilla/js/src/xpconnect/src/xpcjsruntime.cpp b/mozilla/js/src/xpconnect/src/xpcjsruntime.cpp index 41b1d7bad46..b61bf499eeb 100644 --- a/mozilla/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/mozilla/js/src/xpconnect/src/xpcjsruntime.cpp @@ -201,6 +201,17 @@ DyingProtoKiller(JSDHashTable *table, JSDHashEntryHdr *hdr, return JS_DHASH_REMOVE; } +JS_STATIC_DLL_CALLBACK(JSDHashOperator) +DetachedWrappedNativeProtoMarker(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + XPCWrappedNativeProto* proto = + (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key; + + proto->Mark(); + return JS_DHASH_NEXT; +} + // static JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status) { @@ -295,6 +306,9 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status) // Do the marking... XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos(); + self->mDetachedWrappedNativeProtoMap-> + Enumerate(DetachedWrappedNativeProtoMarker, nsnull); + // Mark the sets used in the call contexts. There is a small // chance that a wrapper's set will change *while* a call is // happening which uses that wrapper's old interfface set. So, @@ -555,6 +569,24 @@ WrappedJSShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr, return JS_DHASH_NEXT; } +JS_STATIC_DLL_CALLBACK(JSDHashOperator) +DetachedWrappedNativeProtoShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + XPCWrappedNativeProto* proto = + (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key; + + proto->SystemIsBeingShutDown(*((XPCCallContext*)arg)); + return JS_DHASH_NEXT; +} + +void XPCJSRuntime::SystemIsBeingShutDown(XPCCallContext* ccx) +{ + if(mDetachedWrappedNativeProtoMap) + mDetachedWrappedNativeProtoMap-> + Enumerate(DetachedWrappedNativeProtoShutdownMarker, ccx); +} + XPCJSRuntime::~XPCJSRuntime() { #ifdef XPC_DUMP_AT_SHUTDOWN @@ -674,6 +706,16 @@ XPCJSRuntime::~XPCJSRuntime() delete mDyingWrappedNativeProtoMap; } + if(mDetachedWrappedNativeProtoMap) + { +#ifdef XPC_DUMP_AT_SHUTDOWN + uint32 count = mDetachedWrappedNativeProtoMap->Count(); + if(count) + printf("deleting XPCJSRuntime with %d live detached XPCWrappedNativeProto\n", (int)count); +#endif + delete mDetachedWrappedNativeProtoMap; + } + // unwire the readable/JSString sharing magic XPCStringConvert::ShutdownDOMStringFinalizer(); } @@ -692,6 +734,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect, mThisTranslatorMap(IID2ThisTranslatorMap::newMap(XPC_THIS_TRANSLATOR_MAP_SIZE)), mNativeScriptableSharedMap(XPCNativeScriptableSharedMap::newMap(XPC_NATIVE_JSCLASS_MAP_SIZE)), mDyingWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DYING_NATIVE_PROTO_MAP_SIZE)), + mDetachedWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DETACHED_NATIVE_PROTO_MAP_SIZE)), mMapLock(XPCAutoLock::NewLock("XPCJSRuntime::mMapLock")), mWrappedJSToReleaseArray(), mNativesToReleaseArray(), diff --git a/mozilla/js/src/xpconnect/src/xpcmaps.h b/mozilla/js/src/xpconnect/src/xpcmaps.h index 522e9f56313..acfb0837c13 100644 --- a/mozilla/js/src/xpconnect/src/xpcmaps.h +++ b/mozilla/js/src/xpconnect/src/xpcmaps.h @@ -628,6 +628,12 @@ public: return proto; } + inline void Remove(XPCWrappedNativeProto* proto) + { + NS_PRECONDITION(proto,"bad param"); + JS_DHashTableOperate(mTable, proto, JS_DHASH_REMOVE); + } + inline uint32 Count() {return mTable->entryCount;} inline uint32 Enumerate(JSDHashEnumerator f, void *arg) {return JS_DHashTableEnumerate(mTable, f, arg);} diff --git a/mozilla/js/src/xpconnect/src/xpcprivate.h b/mozilla/js/src/xpconnect/src/xpcprivate.h index 1005c509368..a95089f8d42 100644 --- a/mozilla/js/src/xpconnect/src/xpcprivate.h +++ b/mozilla/js/src/xpconnect/src/xpcprivate.h @@ -135,6 +135,7 @@ //#define DEBUG_stats_jband 1 //#define XPC_REPORT_NATIVE_INTERFACE_AND_SET_FLUSHING //#define XPC_REPORT_JSCLASS_FLUSHING +//#define XPC_TRACK_AUTOMARKINGPTR_STATS #endif /***************************************************************************/ @@ -174,17 +175,18 @@ void DEBUG_CheckWrapperThreadSafety(const XPCWrappedNative* wrapper); /***************************************************************************/ // default initial sizes for maps (hashtables) -#define XPC_CONTEXT_MAP_SIZE 16 -#define XPC_JS_MAP_SIZE 64 -#define XPC_JS_CLASS_MAP_SIZE 64 +#define XPC_CONTEXT_MAP_SIZE 16 +#define XPC_JS_MAP_SIZE 64 +#define XPC_JS_CLASS_MAP_SIZE 64 -#define XPC_NATIVE_MAP_SIZE 64 -#define XPC_NATIVE_PROTO_MAP_SIZE 16 -#define XPC_DYING_NATIVE_PROTO_MAP_SIZE 16 -#define XPC_NATIVE_INTERFACE_MAP_SIZE 64 -#define XPC_NATIVE_SET_MAP_SIZE 64 -#define XPC_NATIVE_JSCLASS_MAP_SIZE 32 -#define XPC_THIS_TRANSLATOR_MAP_SIZE 8 +#define XPC_NATIVE_MAP_SIZE 64 +#define XPC_NATIVE_PROTO_MAP_SIZE 16 +#define XPC_DYING_NATIVE_PROTO_MAP_SIZE 16 +#define XPC_DETACHED_NATIVE_PROTO_MAP_SIZE 32 +#define XPC_NATIVE_INTERFACE_MAP_SIZE 64 +#define XPC_NATIVE_SET_MAP_SIZE 64 +#define XPC_NATIVE_JSCLASS_MAP_SIZE 32 +#define XPC_THIS_TRANSLATOR_MAP_SIZE 8 /***************************************************************************/ // data declarations... @@ -469,6 +471,9 @@ public: XPCWrappedNativeProtoMap* GetDyingWrappedNativeProtoMap() const {return mDyingWrappedNativeProtoMap;} + XPCWrappedNativeProtoMap* GetDetachedWrappedNativeProtoMap() const + {return mDetachedWrappedNativeProtoMap;} + XPCLock* GetMapLock() const {return mMapLock;} XPCContext* GetXPCContext(JSContext* cx); @@ -528,6 +533,8 @@ public: void DebugDump(PRInt16 depth); + void SystemIsBeingShutDown(XPCCallContext* ccx); + ~XPCJSRuntime(); #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN @@ -573,6 +580,7 @@ private: IID2ThisTranslatorMap* mThisTranslatorMap; XPCNativeScriptableSharedMap* mNativeScriptableSharedMap; XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap; + XPCWrappedNativeProtoMap* mDetachedWrappedNativeProtoMap; XPCLock* mMapLock; nsVoidArray mWrappedJSToReleaseArray; nsVoidArray mNativesToReleaseArray; @@ -905,6 +913,8 @@ public: JSObject* GetPrototypeJSObject() const {return mPrototypeJSObject;} + void RemoveWrappedNativeProtos(); + static XPCWrappedNativeScope* FindInJSObjectScope(XPCCallContext& ccx, JSObject* obj, JSBool OKIfNotInitialized = JS_FALSE); @@ -2890,6 +2900,8 @@ public: mTLS = nsnull; } + AutoMarkingPtr* GetNext() {return mNext;} + virtual void MarkBeforeJSFinalize(JSContext* cx) = 0; virtual void MarkAfterJSFinalize() = 0; diff --git a/mozilla/js/src/xpconnect/src/xpcthreadcontext.cpp b/mozilla/js/src/xpconnect/src/xpcthreadcontext.cpp index 41852f63b11..4741ed6d1ab 100644 --- a/mozilla/js/src/xpconnect/src/xpcthreadcontext.cpp +++ b/mozilla/js/src/xpconnect/src/xpcthreadcontext.cpp @@ -416,6 +416,19 @@ xpc_ThreadDataDtorCB(void* ptr) void XPCPerThreadData::MarkAutoRootsBeforeJSFinalize(JSContext* cx) { +#ifdef XPC_TRACK_AUTOMARKINGPTR_STATS + { + static int maxLength = 0; + int length = 0; + for(AutoMarkingPtr* p = mAutoRoots; p; p = p->GetNext()) + length++; + if(length > maxLength) + maxLength = length; + printf("XPC gc on thread %x with %d AutoMarkingPtrs (%d max so far)\n", + this, length, maxLength); + } +#endif + if(mAutoRoots) mAutoRoots->MarkBeforeJSFinalize(cx); } diff --git a/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp b/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp index 50607622e6b..d423c0cb29a 100644 --- a/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp @@ -2148,6 +2148,53 @@ NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithName(jsval name, nsIInterfaceIn return NS_OK; } +inline nsresult UnexpectedFailure(nsresult rv) +{ + NS_ERROR("This is not supposed to fail!"); + return rv; +} + +/* void refreshPrototype (); */ +NS_IMETHODIMP XPCWrappedNative::RefreshPrototype() +{ + XPCCallContext ccx(NATIVE_CALLER); + if(!ccx.IsValid()) + return UnexpectedFailure(NS_ERROR_FAILURE); + + if(!HasProto()) + return NS_OK; + + if(!GetFlatJSObject()) + return UnexpectedFailure(NS_ERROR_FAILURE); + + AutoMarkingWrappedNativeProtoPtr oldProto(ccx); + AutoMarkingWrappedNativeProtoPtr newProto(ccx); + + oldProto = GetProto(); + XPCNativeScriptableCreateInfo ci(*oldProto->GetScriptableInfo()); + newProto = XPCWrappedNativeProto::GetNewOrUsed(ccx, oldProto->GetScope(), + oldProto->GetClassInfo(), + &ci, + !oldProto->IsShared()); + if(!newProto) + return UnexpectedFailure(NS_ERROR_FAILURE); + + // If nothing needs to change then we're done. + + if(newProto.get() == oldProto.get()) + return NS_OK; + + if(!JS_SetPrototype(ccx, GetFlatJSObject(), newProto->GetJSProtoObject())) + return UnexpectedFailure(NS_ERROR_FAILURE); + + mMaybeProto = newProto; + + if(mScriptableInfo == oldProto->GetScriptableInfo()) + mScriptableInfo = newProto->GetScriptableInfo(); + + return NS_OK; +} + /* void debugDump (in short depth); */ NS_IMETHODIMP XPCWrappedNative::DebugDump(PRInt16 depth) { diff --git a/mozilla/js/src/xpconnect/src/xpcwrappednativeproto.cpp b/mozilla/js/src/xpconnect/src/xpcwrappednativeproto.cpp index 58243a0672c..e853ed13fa7 100644 --- a/mozilla/js/src/xpconnect/src/xpcwrappednativeproto.cpp +++ b/mozilla/js/src/xpconnect/src/xpcwrappednativeproto.cpp @@ -115,8 +115,15 @@ XPCWrappedNativeProto::JSProtoObjectFinalized(JSContext *cx, JSObject *obj) // Map locking is not necessary since we are running gc. if(IsShared()) - GetScope()->GetWrappedNativeProtoMap()->Remove(mClassInfo); + { + // Only remove this proto from the map if it is the one in the map. + ClassInfo2WrappedNativeProtoMap* map = + GetScope()->GetWrappedNativeProtoMap(); + if(map->Find(mClassInfo) == this) + map->Remove(mClassInfo); + } + GetRuntime()->GetDetachedWrappedNativeProtoMap()->Remove(this); GetRuntime()->GetDyingWrappedNativeProtoMap()->Add(this); mJSProtoObject = nsnull; diff --git a/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp b/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp index 34cdc68cef2..f84ad357706 100644 --- a/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp +++ b/mozilla/js/src/xpconnect/src/xpcwrappednativescope.cpp @@ -608,6 +608,29 @@ XPCWrappedNativeScope::ClearAllWrappedNativeSecurityPolicies(XPCCallContext& ccx return NS_OK; } +JS_STATIC_DLL_CALLBACK(JSDHashOperator) +WNProtoRemover(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + XPCWrappedNativeProtoMap* detachedMap = (XPCWrappedNativeProtoMap*)arg; + + XPCWrappedNativeProto* proto = (XPCWrappedNativeProto*) + ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value; + + detachedMap->Add(proto); + + return JS_DHASH_REMOVE; +} + +void +XPCWrappedNativeScope::RemoveWrappedNativeProtos() +{ + XPCAutoLock al(mRuntime->GetMapLock()); + + mWrappedNativeProtoMap->Enumerate(WNProtoRemover, + GetRuntime()->GetDetachedWrappedNativeProtoMap()); +} + /***************************************************************************/ // static