Esempio n. 1
0
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
}
Esempio n. 2
0
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
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}