void JSCompartment::purge(JSContext *cx) { arenas.purge(); dtoaCache.purge(); /* * Clear the hash and reset all evalHashLink to null before the GC. This * way MarkChildren(trc, JSScript *) can assume that JSScript::u.object is * not null when we have script owned by an object and not from the eval * cache. */ for (size_t i = 0; i != JS_ARRAY_LENGTH(evalCache); ++i) { for (JSScript **listHeadp = &evalCache[i]; *listHeadp; ) { JSScript *script = *listHeadp; JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT); *listHeadp = NULL; listHeadp = &script->u.evalHashLink; } } nativeIterCache.purge(); toSourceCache.destroyIfConstructed(); #ifdef JS_TRACER /* * If we are about to regenerate shapes, we have to flush the JIT cache, * which will eventually abort any current recording. */ if (cx->runtime->gcRegenShapes) if (hasTraceMonitor()) traceMonitor()->needFlush = JS_TRUE; #endif #if defined JS_METHODJIT && defined JS_MONOIC /* * MICs do not refer to data which can be GC'ed and do not generate stubs * which might need to be discarded, but are sensitive to shape regeneration. */ if (cx->runtime->gcRegenShapes) { for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->hasJITCode()) mjit::ic::PurgeMICs(cx, script); } } #endif }
void JSCompartment::purge(JSContext *cx) { freeLists.purge(); dtoaCache.purge(); /* Destroy eval'ed scripts. */ js_DestroyScriptsToGC(cx, this); nativeIterCache.purge(); toSourceCache.destroyIfConstructed(); #ifdef JS_TRACER /* * If we are about to regenerate shapes, we have to flush the JIT cache, * which will eventually abort any current recording. */ if (cx->runtime->gcRegenShapes) traceMonitor.needFlush = JS_TRUE; #endif #ifdef JS_METHODJIT for (JSScript *script = (JSScript *)scripts.next; &script->links != &scripts; script = (JSScript *)script->links.next) { if (script->hasJITCode()) { # if defined JS_POLYIC mjit::ic::PurgePICs(cx, script); # endif # if defined JS_MONOIC /* * MICs do not refer to data which can be GC'ed and do not generate stubs * which might need to be discarded, but are sensitive to shape regeneration. */ if (cx->runtime->gcRegenShapes) mjit::ic::PurgeMICs(cx, script); # endif } } #endif }
void JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) { /* Remove dead wrappers from the table. */ for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) { JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key.toGCThing()) && !IsAboutToBeFinalized(cx, e.front().value.toGCThing()), e.front().key.isString()); if (IsAboutToBeFinalized(cx, e.front().key.toGCThing()) || IsAboutToBeFinalized(cx, e.front().value.toGCThing())) { e.removeFront(); } } /* Remove dead empty shapes. */ if (emptyArgumentsShape && IsAboutToBeFinalized(cx, emptyArgumentsShape)) emptyArgumentsShape = NULL; if (emptyBlockShape && IsAboutToBeFinalized(cx, emptyBlockShape)) emptyBlockShape = NULL; if (emptyCallShape && IsAboutToBeFinalized(cx, emptyCallShape)) emptyCallShape = NULL; if (emptyDeclEnvShape && IsAboutToBeFinalized(cx, emptyDeclEnvShape)) emptyDeclEnvShape = NULL; if (emptyEnumeratorShape && IsAboutToBeFinalized(cx, emptyEnumeratorShape)) emptyEnumeratorShape = NULL; if (emptyWithShape && IsAboutToBeFinalized(cx, emptyWithShape)) emptyWithShape = NULL; if (initialRegExpShape && IsAboutToBeFinalized(cx, initialRegExpShape)) initialRegExpShape = NULL; if (initialStringShape && IsAboutToBeFinalized(cx, initialStringShape)) initialStringShape = NULL; sweepBreakpoints(cx); #ifdef JS_TRACER if (hasTraceMonitor()) traceMonitor()->sweep(cx); #endif #ifdef JS_METHODJIT /* * Purge PICs in the compartment, along with native call stubs for * compartments which do not have such stubs on the stack. PICs can * reference shapes and type data, and native call stubs are disassociated * from the PIC or MIC they were generated for. */ bool canPurgeNativeCalls = true; VMFrame *f = hasJaegerCompartment() ? jaegerCompartment()->activeFrame() : NULL; for (; f; f = f->previous) { if (f->stubRejoin) canPurgeNativeCalls = false; } for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->hasJITCode()) { #ifdef JS_POLYIC mjit::ic::PurgePICs(cx, script); #endif if (canPurgeNativeCalls) { if (script->jitNormal) script->jitNormal->purgeNativeCallStubs(); if (script->jitCtor) script->jitCtor->purgeNativeCallStubs(); } } } #endif bool discardScripts = !active && (releaseInterval != 0 || hasDebugModeCodeToDrop); #if defined JS_METHODJIT && defined JS_MONOIC /* * The release interval is the frequency with which we should try to destroy * executable pools by releasing all JIT code in them, zero to never destroy pools. * Initialize counter so that the first pool will be destroyed, and eventually drive * the amount of JIT code in never-used compartments to zero. Don't discard anything * for compartments which currently have active stack frames. */ uint32 counter = 1; if (discardScripts) hasDebugModeCodeToDrop = false; for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->hasJITCode()) { mjit::ic::SweepCallICs(cx, script, discardScripts); if (discardScripts) { ScriptTryDestroyCode(cx, script, true, releaseInterval, counter); ScriptTryDestroyCode(cx, script, false, releaseInterval, counter); } } } #endif #ifdef JS_METHODJIT if (types.inferenceEnabled) mjit::ClearAllFrames(this); #endif if (activeAnalysis) { /* * Analysis information is in use, so don't clear the analysis pool. * jitcode still needs to be released, if this is a shape-regenerating * GC then shape numbers baked into the code may change. */ #ifdef JS_METHODJIT if (types.inferenceEnabled) { for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); mjit::ReleaseScriptCode(cx, script); } } #endif } else { /* * Clear the analysis pool, but don't release its data yet. While * sweeping types any live data will be allocated into the pool. */ LifoAlloc oldAlloc(typeLifoAlloc.defaultChunkSize()); oldAlloc.steal(&typeLifoAlloc); /* * Sweep analysis information and everything depending on it from the * compartment, including all remaining mjit code if inference is * enabled in the compartment. */ if (types.inferenceEnabled) { for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->types) { types::TypeScript::Sweep(cx, script); /* * On each 1/8 lifetime, release observed types for all scripts. * This is always safe to do when there are no frames for the * compartment on the stack. */ if (discardScripts) { script->types->destroy(); script->types = NULL; script->typesPurged = true; } } } } types.sweep(cx); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); script->clearAnalysis(); } } active = false; }
void JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) { chunk = NULL; /* Remove dead wrappers from the table. */ for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) { JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key.toGCThing()) && !IsAboutToBeFinalized(cx, e.front().value.toGCThing()), e.front().key.isString()); if (IsAboutToBeFinalized(cx, e.front().key.toGCThing()) || IsAboutToBeFinalized(cx, e.front().value.toGCThing())) { e.removeFront(); } } /* Remove dead empty shapes. */ if (emptyArgumentsShape && IsAboutToBeFinalized(cx, emptyArgumentsShape)) emptyArgumentsShape = NULL; if (emptyBlockShape && IsAboutToBeFinalized(cx, emptyBlockShape)) emptyBlockShape = NULL; if (emptyCallShape && IsAboutToBeFinalized(cx, emptyCallShape)) emptyCallShape = NULL; if (emptyDeclEnvShape && IsAboutToBeFinalized(cx, emptyDeclEnvShape)) emptyDeclEnvShape = NULL; if (emptyEnumeratorShape && IsAboutToBeFinalized(cx, emptyEnumeratorShape)) emptyEnumeratorShape = NULL; if (emptyWithShape && IsAboutToBeFinalized(cx, emptyWithShape)) emptyWithShape = NULL; if (initialRegExpShape && IsAboutToBeFinalized(cx, initialRegExpShape)) initialRegExpShape = NULL; if (initialStringShape && IsAboutToBeFinalized(cx, initialStringShape)) initialStringShape = NULL; #ifdef JS_TRACER traceMonitor.sweep(cx); #endif #if defined JS_METHODJIT && defined JS_MONOIC /* * The release interval is the frequency with which we should try to destroy * executable pools by releasing all JIT code in them, zero to never destroy pools. * Initialize counter so that the first pool will be destroyed, and eventually drive * the amount of JIT code in never-used compartments to zero. Don't discard anything * for compartments which currently have active stack frames. */ uint32 counter = 1; bool discardScripts = !active && releaseInterval != 0; for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) { JSScript *script = reinterpret_cast<JSScript *>(cursor); if (script->hasJITCode()) { mjit::ic::SweepCallICs(cx, script, discardScripts); if (discardScripts) { if (script->jitNormal && ScriptPoolDestroyed(cx, script->jitNormal, releaseInterval, counter)) { mjit::ReleaseScriptCode(cx, script); continue; } if (script->jitCtor && ScriptPoolDestroyed(cx, script->jitCtor, releaseInterval, counter)) { mjit::ReleaseScriptCode(cx, script); } } } } #endif /* JS_METHODJIT && JS_MONOIC */ active = false; }