JS_XDRDestroy(JSXDRState *xdr) { JSContext *cx = xdr->cx; xdr->ops->finalize(xdr); if (xdr->registry) { JS_free(cx, xdr->registry); if (xdr->reghash) JS_DHashTableDestroy(xdr->reghash); } JS_free(cx, xdr); }
XPCJSRuntime::~XPCJSRuntime() { #ifdef XPC_DUMP_AT_SHUTDOWN { // count the total JSContexts in use JSContext* iter = nsnull; int count = 0; while(JS_ContextIterator(mJSRuntime, &iter)) count ++; if(count) printf("deleting XPCJSRuntime with %d live JSContexts\n", count); } #endif // clean up and destroy maps... if(mContextMap) { PurgeXPCContextList(); delete mContextMap; } if(mWrappedJSMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mWrappedJSMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live wrapped JSObject\n", (int)count); #endif mWrappedJSMap->Enumerate(WrappedJSShutdownMarker, mJSRuntime); delete mWrappedJSMap; } if(mWrappedJSClassMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mWrappedJSClassMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live nsXPCWrappedJSClass\n", (int)count); #endif delete mWrappedJSClassMap; } if(mIID2NativeInterfaceMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mIID2NativeInterfaceMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live XPCNativeInterfaces\n", (int)count); #endif delete mIID2NativeInterfaceMap; } if(mClassInfo2NativeSetMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mClassInfo2NativeSetMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live XPCNativeSets\n", (int)count); #endif delete mClassInfo2NativeSetMap; } if(mNativeSetMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mNativeSetMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live XPCNativeSets\n", (int)count); #endif delete mNativeSetMap; } if(mMapLock) XPCAutoLock::DestroyLock(mMapLock); NS_IF_RELEASE(mJSRuntimeService); if(mThisTranslatorMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mThisTranslatorMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live ThisTranslator\n", (int)count); #endif delete mThisTranslatorMap; } #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN if(DEBUG_WrappedNativeHashtable) { int LiveWrapperCount = 0; JS_DHashTableEnumerate(DEBUG_WrappedNativeHashtable, DEBUG_WrapperChecker, &LiveWrapperCount); if(LiveWrapperCount) printf("deleting XPCJSRuntime with %d live XPCWrappedNative (found in wrapper check)\n", (int)LiveWrapperCount); JS_DHashTableDestroy(DEBUG_WrappedNativeHashtable); } #endif if(mNativeScriptableSharedMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mNativeScriptableSharedMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live XPCNativeScriptableShared\n", (int)count); #endif delete mNativeScriptableSharedMap; } if(mDyingWrappedNativeProtoMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mDyingWrappedNativeProtoMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live but dying XPCWrappedNativeProto\n", (int)count); #endif 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; } if(mExplicitNativeWrapperMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mExplicitNativeWrapperMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live explicit XPCNativeWrapper\n", (int)count); #endif delete mExplicitNativeWrapperMap; } // unwire the readable/JSString sharing magic XPCStringConvert::ShutdownDOMStringFinalizer(); XPCConvert::RemoveXPCOMUCStringFinalizer(); gOldJSGCCallback = NULL; gOldJSContextCallback = NULL; if(mJSHolders.ops) { JS_DHashTableFinish(&mJSHolders); mJSHolders.ops = nsnull; } if(mClearedGlobalObjects.ops) { JS_DHashTableFinish(&mClearedGlobalObjects); mClearedGlobalObjects.ops = nsnull; } }
void js_DestroyContext(JSContext *cx, JSGCMode gcmode) { JSRuntime *rt; JSBool last; JSArgumentFormatMap *map; rt = cx->runtime; /* Remove cx from context list first. */ JS_LOCK_RUNTIME(rt); JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING); JS_REMOVE_LINK(&cx->links); last = (rt->contextList.next == &rt->contextList); if (last) rt->state = JSRTS_LANDING; JS_UNLOCK_RUNTIME(rt); if (last) { /* Unpin all pinned atoms before final GC. */ js_UnpinPinnedAtoms(&rt->atomState); /* Unlock and clear GC things held by runtime pointers. */ js_FinishRuntimeNumberState(cx); js_FinishRuntimeStringState(cx); /* Clear debugging state to remove GC roots. */ JS_ClearAllTraps(cx); JS_ClearAllWatchPoints(cx); } #if JS_HAS_REGEXPS /* * Remove more GC roots in regExpStatics, then collect garbage. * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within * XXX this function call to wait for any racing GC to complete, in the * XXX case where JS_DestroyContext is called outside of a request on cx */ js_FreeRegExpStatics(cx, &cx->regExpStatics); #endif #ifdef JS_THREADSAFE /* * Destroying a context implicitly calls JS_EndRequest(). Also, we must * end our request here in case we are "last" -- in that event, another * js_DestroyContext that was not last might be waiting in the GC for our * request to end. We'll let it run below, just before we do the truly * final GC and then free atom state. * * At this point, cx must be inaccessible to other threads. It's off the * rt->contextList, and it should not be reachable via any object private * data structure. */ while (cx->requestDepth != 0) JS_EndRequest(cx); #endif if (last) { /* Always force, so we wait for any racing GC to finish. */ js_ForceGC(cx); /* Iterate until no finalizer removes a GC root or lock. */ while (rt->gcPoke) js_GC(cx, GC_LAST_CONTEXT); /* Try to free atom state, now that no unrooted scripts survive. */ if (rt->atomState.liveAtoms == 0) js_FreeAtomState(cx, &rt->atomState); /* Take the runtime down, now that it has no contexts or atoms. */ JS_LOCK_RUNTIME(rt); rt->state = JSRTS_DOWN; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_RUNTIME(rt); } else { if (gcmode == JS_FORCE_GC) js_ForceGC(cx); else if (gcmode == JS_MAYBE_GC) JS_MaybeGC(cx); } /* Free the stuff hanging off of cx. */ JS_FinishArenaPool(&cx->stackPool); JS_FinishArenaPool(&cx->codePool); JS_FinishArenaPool(&cx->notePool); JS_FinishArenaPool(&cx->tempPool); if (cx->lastMessage) free(cx->lastMessage); /* Remove any argument formatters. */ map = cx->argumentFormatMap; while (map) { JSArgumentFormatMap *temp = map; map = map->next; JS_free(cx, temp); } /* Destroy the resolve recursion damper. */ if (cx->resolvingTable) { JS_DHashTableDestroy(cx->resolvingTable); cx->resolvingTable = NULL; } /* Finally, free cx itself. */ free(cx); }
XPCJSRuntime::~XPCJSRuntime() { if (mWatchdogWakeup) { // If the watchdog thread is running, tell it to terminate waking it // up if necessary and wait until it signals that it finished. As we // must release the lock before calling PR_DestroyCondVar, we use an // extra block here. { AutoLockJSGC lock(mJSRuntime); if (mWatchdogThread) { mWatchdogThread = nsnull; PR_NotifyCondVar(mWatchdogWakeup); PR_WaitCondVar(mWatchdogWakeup, PR_INTERVAL_NO_TIMEOUT); } } PR_DestroyCondVar(mWatchdogWakeup); mWatchdogWakeup = nsnull; } #ifdef XPC_DUMP_AT_SHUTDOWN { // count the total JSContexts in use JSContext* iter = nsnull; int count = 0; while(JS_ContextIterator(mJSRuntime, &iter)) count ++; if(count) printf("deleting XPCJSRuntime with %d live JSContexts\n", count); } #endif // clean up and destroy maps... if(mWrappedJSMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mWrappedJSMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live wrapped JSObject\n", (int)count); #endif mWrappedJSMap->Enumerate(WrappedJSShutdownMarker, mJSRuntime); delete mWrappedJSMap; } if(mWrappedJSClassMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mWrappedJSClassMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live nsXPCWrappedJSClass\n", (int)count); #endif delete mWrappedJSClassMap; } if(mIID2NativeInterfaceMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mIID2NativeInterfaceMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live XPCNativeInterfaces\n", (int)count); #endif delete mIID2NativeInterfaceMap; } if(mClassInfo2NativeSetMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mClassInfo2NativeSetMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live XPCNativeSets\n", (int)count); #endif delete mClassInfo2NativeSetMap; } if(mNativeSetMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mNativeSetMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live XPCNativeSets\n", (int)count); #endif delete mNativeSetMap; } if(mMapLock) XPCAutoLock::DestroyLock(mMapLock); if(mThisTranslatorMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mThisTranslatorMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live ThisTranslator\n", (int)count); #endif delete mThisTranslatorMap; } #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN if(DEBUG_WrappedNativeHashtable) { int LiveWrapperCount = 0; JS_DHashTableEnumerate(DEBUG_WrappedNativeHashtable, DEBUG_WrapperChecker, &LiveWrapperCount); if(LiveWrapperCount) printf("deleting XPCJSRuntime with %d live XPCWrappedNative (found in wrapper check)\n", (int)LiveWrapperCount); JS_DHashTableDestroy(DEBUG_WrappedNativeHashtable); } #endif if(mNativeScriptableSharedMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mNativeScriptableSharedMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live XPCNativeScriptableShared\n", (int)count); #endif delete mNativeScriptableSharedMap; } if(mDyingWrappedNativeProtoMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mDyingWrappedNativeProtoMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live but dying XPCWrappedNativeProto\n", (int)count); #endif 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; } if(mExplicitNativeWrapperMap) { #ifdef XPC_DUMP_AT_SHUTDOWN uint32 count = mExplicitNativeWrapperMap->Count(); if(count) printf("deleting XPCJSRuntime with %d live explicit XPCNativeWrapper\n", (int)count); #endif delete mExplicitNativeWrapperMap; } // unwire the readable/JSString sharing magic XPCStringConvert::ShutdownDOMStringFinalizer(); XPCConvert::RemoveXPCOMUCStringFinalizer(); if(mJSHolders.ops) { JS_DHashTableFinish(&mJSHolders); mJSHolders.ops = nsnull; } if(mJSRuntime) { JS_DestroyRuntime(mJSRuntime); JS_ShutDown(); #ifdef DEBUG_shaver_off fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime); #endif } XPCPerThreadData::ShutDown(); }
void js_DestroyContext(JSContext *cx, JSDestroyContextMode mode) { JSRuntime *rt; JSContextCallback cxCallback; JSBool last; JSArgumentFormatMap *map; JSLocalRootStack *lrs; JSLocalRootChunk *lrc; rt = cx->runtime; if (mode != JSDCM_NEW_FAILED) { cxCallback = rt->cxCallback; if (cxCallback) { /* * JSCONTEXT_DESTROY callback is not allowed to fail and must * return true. */ #ifdef DEBUG JSBool callbackStatus = #endif cxCallback(cx, JSCONTEXT_DESTROY); JS_ASSERT(callbackStatus); } } /* Remove cx from context list first. */ JS_LOCK_GC(rt); JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING); JS_REMOVE_LINK(&cx->links); last = (rt->contextList.next == &rt->contextList); if (last) rt->state = JSRTS_LANDING; JS_UNLOCK_GC(rt); if (last) { #ifdef JS_THREADSAFE /* * If cx is not in a request already, begin one now so that we wait * for any racing GC started on a not-last context to finish, before * we plow ahead and unpin atoms. Note that even though we begin a * request here if necessary, we end all requests on cx below before * forcing a final GC. This lets any not-last context destruction * racing in another thread try to force or maybe run the GC, but by * that point, rt->state will not be JSRTS_UP, and that GC attempt * will return early. */ if (cx->requestDepth == 0) JS_BeginRequest(cx); #endif /* Unlock and clear GC things held by runtime pointers. */ js_FinishRuntimeNumberState(cx); js_FinishRuntimeStringState(cx); /* Unpin all common atoms before final GC. */ js_FinishCommonAtoms(cx); /* Clear debugging state to remove GC roots. */ JS_ClearAllTraps(cx); JS_ClearAllWatchPoints(cx); } /* * Remove more GC roots in regExpStatics, then collect garbage. * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within * XXX this function call to wait for any racing GC to complete, in the * XXX case where JS_DestroyContext is called outside of a request on cx */ js_FreeRegExpStatics(cx, &cx->regExpStatics); #ifdef JS_THREADSAFE /* * Destroying a context implicitly calls JS_EndRequest(). Also, we must * end our request here in case we are "last" -- in that event, another * js_DestroyContext that was not last might be waiting in the GC for our * request to end. We'll let it run below, just before we do the truly * final GC and then free atom state. * * At this point, cx must be inaccessible to other threads. It's off the * rt->contextList, and it should not be reachable via any object private * data structure. */ while (cx->requestDepth != 0) JS_EndRequest(cx); #endif if (last) { js_GC(cx, GC_LAST_CONTEXT); /* * Free the script filename table if it exists and is empty. Do this * after the last GC to avoid finalizers tripping on free memory. */ if (rt->scriptFilenameTable && rt->scriptFilenameTable->nentries == 0) js_FinishRuntimeScriptState(rt); /* Take the runtime down, now that it has no contexts or atoms. */ JS_LOCK_GC(rt); rt->state = JSRTS_DOWN; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_GC(rt); } else { if (mode == JSDCM_FORCE_GC) js_GC(cx, GC_NORMAL); else if (mode == JSDCM_MAYBE_GC) JS_MaybeGC(cx); } /* Free the stuff hanging off of cx. */ JS_FinishArenaPool(&cx->stackPool); JS_FinishArenaPool(&cx->tempPool); if (cx->lastMessage) free(cx->lastMessage); /* Remove any argument formatters. */ map = cx->argumentFormatMap; while (map) { JSArgumentFormatMap *temp = map; map = map->next; JS_free(cx, temp); } /* Destroy the resolve recursion damper. */ if (cx->resolvingTable) { JS_DHashTableDestroy(cx->resolvingTable); cx->resolvingTable = NULL; } lrs = cx->localRootStack; if (lrs) { while ((lrc = lrs->topChunk) != &lrs->firstChunk) { lrs->topChunk = lrc->down; JS_free(cx, lrc); } JS_free(cx, lrs); } #ifdef JS_THREADSAFE js_ClearContextThread(cx); #endif /* Finally, free cx itself. */ free(cx); }