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