void JSCompartment::updateForDebugMode(JSContext *cx) { for (ThreadContextRange r(cx); !r.empty(); r.popFront()) { JSContext *cx = r.front(); if (cx->compartment == this) cx->updateJITEnabled(); } #ifdef JS_METHODJIT bool enabled = debugMode(); if (enabled) { JS_ASSERT(!hasScriptsOnStack(cx)); } else if (hasScriptsOnStack(cx)) { hasDebugModeCodeToDrop = true; return; } /* * Discard JIT code and bytecode analyses for any scripts that change * debugMode. This assumes that 'comp' is in the same thread as 'cx'. */ for (gc::CellIter i(cx, this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->debugMode != enabled) { mjit::ReleaseScriptCode(cx, script); script->clearAnalysis(); script->debugMode = enabled; } } hasDebugModeCodeToDrop = false; #endif }
void JSCompartment::sweep(FreeOp *fop, bool releaseTypes) { JS_ASSERT(!activeAnalysis); { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_DISCARD_CODE); discardJitCode(fop, !zone()->isPreservingCode()); } /* This function includes itself in PHASE_SWEEP_TABLES. */ sweepCrossCompartmentWrappers(); { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_TABLES); /* Remove dead references held weakly by the compartment. */ sweepBaseShapeTable(); sweepInitialShapeTable(); sweepNewTypeObjectTable(newTypeObjects); sweepNewTypeObjectTable(lazyTypeObjects); sweepBreakpoints(fop); sweepCallsiteClones(); if (global_ && IsObjectAboutToBeFinalized(global_.unsafeGet())) global_ = NULL; #ifdef JS_ION if (ionCompartment_) ionCompartment_->sweep(fop); #endif /* * JIT code increments activeUseCount for any RegExpShared used by jit * code for the lifetime of the JIT script. Thus, we must perform * sweeping after clearing jit code. */ regExps.sweep(rt); if (debugScopes) debugScopes->sweep(rt); /* Finalize unreachable (key,value) pairs in all weak maps. */ WeakMapBase::sweepCompartment(this); } if (!zone()->isPreservingCode()) { JS_ASSERT(!types.constrainedOutputs); gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS); /* * 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); /* * Periodically release observed types for all scripts. This is safe to * do when there are no frames for the compartment on the stack. */ if (active) releaseTypes = false; /* * 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) { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { RawScript script = i.get<JSScript>(); if (script->types) { types::TypeScript::Sweep(fop, script); if (releaseTypes) { script->types->destroy(); script->types = NULL; } } } } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TYPES); types.sweep(fop); } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_CLEAR_SCRIPT_ANALYSIS); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); script->clearAnalysis(); script->clearPropertyReadTypes(); } } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_FREE_TI_ARENA); rt->freeLifoAlloc.transferFrom(&analysisLifoAlloc); rt->freeLifoAlloc.transferFrom(&oldAlloc); } } NativeIterator *ni = enumerators->next(); while (ni != enumerators) { JSObject *iterObj = ni->iterObj(); NativeIterator *next = ni->next(); if (gc::IsObjectAboutToBeFinalized(&iterObj)) ni->unlink(); ni = next; } active = false; }
void JSCompartment::sweep(FreeOp *fop, bool releaseTypes) { /* Remove dead wrappers from the table. */ for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) { JS_ASSERT_IF(IsAboutToBeFinalized(e.front().key) && !IsAboutToBeFinalized(e.front().value), e.front().key.isString()); if (IsAboutToBeFinalized(e.front().key) || IsAboutToBeFinalized(e.front().value)) { e.removeFront(); } } /* Remove dead references held weakly by the compartment. */ regExps.sweep(rt); sweepBaseShapeTable(); sweepInitialShapeTable(); sweepNewTypeObjectTable(newTypeObjects); sweepNewTypeObjectTable(lazyTypeObjects); if (emptyTypeObject && IsAboutToBeFinalized(emptyTypeObject)) emptyTypeObject = NULL; newObjectCache.reset(); sweepBreakpoints(fop); { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE); discardJitCode(fop); } if (!activeAnalysis) { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS); /* * 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); /* * Periodically release observed types for all scripts. This is safe to * do when there are no frames for the compartment on the stack. */ if (active) releaseTypes = false; /* * 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) { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->types) { types::TypeScript::Sweep(fop, script); if (releaseTypes) { script->types->destroy(); script->types = NULL; script->typesPurged = true; } } } } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TYPES); types.sweep(fop); } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_CLEAR_SCRIPT_ANALYSIS); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); script->clearAnalysis(); } } } active = false; }
void JSCompartment::sweep(FreeOp *fop, bool releaseTypes) { { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_DISCARD_CODE); discardJitCode(fop, !activeAnalysis && !gcPreserveCode); } /* This function includes itself in PHASE_SWEEP_TABLES. */ sweepCrossCompartmentWrappers(); { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_TABLES); /* Remove dead references held weakly by the compartment. */ sweepBaseShapeTable(); sweepInitialShapeTable(); sweepNewTypeObjectTable(newTypeObjects); sweepNewTypeObjectTable(lazyTypeObjects); if (emptyTypeObject && !IsTypeObjectMarked(emptyTypeObject.unsafeGet())) emptyTypeObject = NULL; sweepBreakpoints(fop); if (global_ && !IsObjectMarked(&global_)) global_ = NULL; #ifdef JS_ION if (ionCompartment_) ionCompartment_->sweep(fop); #endif /* JIT code can hold references on RegExpShared, so sweep regexps after clearing code. */ regExps.sweep(rt); } if (!activeAnalysis && !gcPreserveCode) { JS_ASSERT(!types.constrainedOutputs); gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS); /* * 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); /* * Periodically release observed types for all scripts. This is safe to * do when there are no frames for the compartment on the stack. */ if (active) releaseTypes = false; /* * 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) { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->types) { types::TypeScript::Sweep(fop, script); if (releaseTypes) { script->types->destroy(); script->types = NULL; } } } } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TYPES); types.sweep(fop); } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_CLEAR_SCRIPT_ANALYSIS); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); script->clearAnalysis(); script->clearPropertyReadTypes(); } } { gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_FREE_TI_ARENA); rt->freeLifoAlloc.transferFrom(&analysisLifoAlloc); rt->freeLifoAlloc.transferFrom(&oldAlloc); } } active = false; }
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, bool releaseTypes) { /* 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 ICs in the compartment. These can reference GC things. */ for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); mjit::PurgeICs(cx, script); } 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. */ JSArenaPool oldPool; MoveArenaPool(&pool, &oldPool); /* * 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) { if (active) releaseTypes = false; for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); if (script->types) { types::TypeScript::Sweep(cx, script); /* * Periodically release observed types for all scripts. * This is always safe to do when there are no frames for * the compartment on the stack. */ if (releaseTypes) { script->types->destroy(); script->types = NULL; script->typesPurged = true; } } } } else { #ifdef JS_METHODJIT /* :XXX: bug 685358 only releasing jitcode if there are no frames on the stack */ if (!active) { for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); mjit::ReleaseScriptCode(cx, script); } } #endif } types.sweep(cx); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); script->clearAnalysis(); } /* Reset the analysis pool, releasing all analysis and intermediate type data. */ JS_FinishArenaPool(&oldPool); } active = false; }
void JSCompartment::sweep(JSContext *cx, bool releaseTypes) { /* Remove dead wrappers from the table. */ for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) { JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key) && !IsAboutToBeFinalized(cx, e.front().value), e.front().key.isString()); if (IsAboutToBeFinalized(cx, e.front().key) || IsAboutToBeFinalized(cx, e.front().value)) { e.removeFront(); } } /* Remove dead references held weakly by the compartment. */ sweepBaseShapeTable(cx); sweepInitialShapeTable(cx); sweepNewTypeObjectTable(cx, newTypeObjects); sweepNewTypeObjectTable(cx, lazyTypeObjects); if (emptyTypeObject && IsAboutToBeFinalized(cx, emptyTypeObject)) emptyTypeObject = NULL; newObjectCache.reset(); sweepBreakpoints(cx); { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE); /* * Kick all frames on the stack into the interpreter, and release all JIT * code in the compartment. */ #ifdef JS_METHODJIT mjit::ClearAllFrames(this); for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get<JSScript>(); mjit::ReleaseScriptCode(cx, script); /* * Use counts for scripts are reset on GC. After discarding code we * need to let it warm back up to get information like which opcodes * are setting array holes or accessing getter properties. */ script->resetUseCount(); } #endif } if (!activeAnalysis) { gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS); /* * 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); /* * Periodically release observed types for all scripts. This is safe to * do when there are no frames for the compartment on the stack. */ if (active) releaseTypes = false; /* * 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); if (releaseTypes) { 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; }