js/src/gc/Zone.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/gc/Zone.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,269 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "gc/Zone.h"
    1.11 +
    1.12 +#include "jsgc.h"
    1.13 +
    1.14 +#ifdef JS_ION
    1.15 +#include "jit/BaselineJIT.h"
    1.16 +#include "jit/Ion.h"
    1.17 +#include "jit/JitCompartment.h"
    1.18 +#endif
    1.19 +#include "vm/Debugger.h"
    1.20 +#include "vm/Runtime.h"
    1.21 +
    1.22 +#include "jsgcinlines.h"
    1.23 +
    1.24 +using namespace js;
    1.25 +using namespace js::gc;
    1.26 +
    1.27 +JS::Zone::Zone(JSRuntime *rt)
    1.28 +  : JS::shadow::Zone(rt, &rt->gcMarker),
    1.29 +    allocator(this),
    1.30 +    ionUsingBarriers_(false),
    1.31 +    active(false),
    1.32 +    gcScheduled(false),
    1.33 +    gcState(NoGC),
    1.34 +    gcPreserveCode(false),
    1.35 +    gcBytes(0),
    1.36 +    gcTriggerBytes(0),
    1.37 +    gcHeapGrowthFactor(3.0),
    1.38 +    isSystem(false),
    1.39 +    usedByExclusiveThread(false),
    1.40 +    scheduledForDestruction(false),
    1.41 +    maybeAlive(true),
    1.42 +    gcMallocBytes(0),
    1.43 +    gcMallocGCTriggered(false),
    1.44 +    gcGrayRoots(),
    1.45 +    data(nullptr),
    1.46 +    types(this)
    1.47 +#ifdef JS_ION
    1.48 +    , jitZone_(nullptr)
    1.49 +#endif
    1.50 +{
    1.51 +    /* Ensure that there are no vtables to mess us up here. */
    1.52 +    JS_ASSERT(reinterpret_cast<JS::shadow::Zone *>(this) ==
    1.53 +              static_cast<JS::shadow::Zone *>(this));
    1.54 +
    1.55 +    setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9);
    1.56 +}
    1.57 +
    1.58 +Zone::~Zone()
    1.59 +{
    1.60 +    if (this == runtimeFromMainThread()->systemZone)
    1.61 +        runtimeFromMainThread()->systemZone = nullptr;
    1.62 +
    1.63 +#ifdef JS_ION
    1.64 +    js_delete(jitZone_);
    1.65 +#endif
    1.66 +}
    1.67 +
    1.68 +void
    1.69 +Zone::setNeedsBarrier(bool needs, ShouldUpdateIon updateIon)
    1.70 +{
    1.71 +#ifdef JS_ION
    1.72 +    if (updateIon == UpdateIon && needs != ionUsingBarriers_) {
    1.73 +        jit::ToggleBarriers(this, needs);
    1.74 +        ionUsingBarriers_ = needs;
    1.75 +    }
    1.76 +#endif
    1.77 +
    1.78 +    if (needs && runtimeFromMainThread()->isAtomsZone(this))
    1.79 +        JS_ASSERT(!runtimeFromMainThread()->exclusiveThreadsPresent());
    1.80 +
    1.81 +    JS_ASSERT_IF(needs, canCollect());
    1.82 +    needsBarrier_ = needs;
    1.83 +}
    1.84 +
    1.85 +void
    1.86 +Zone::resetGCMallocBytes()
    1.87 +{
    1.88 +    gcMallocBytes = ptrdiff_t(gcMaxMallocBytes);
    1.89 +    gcMallocGCTriggered = false;
    1.90 +}
    1.91 +
    1.92 +void
    1.93 +Zone::setGCMaxMallocBytes(size_t value)
    1.94 +{
    1.95 +    /*
    1.96 +     * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
    1.97 +     * mean that value.
    1.98 +     */
    1.99 +    gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
   1.100 +    resetGCMallocBytes();
   1.101 +}
   1.102 +
   1.103 +void
   1.104 +Zone::onTooMuchMalloc()
   1.105 +{
   1.106 +    if (!gcMallocGCTriggered)
   1.107 +        gcMallocGCTriggered = TriggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC);
   1.108 +}
   1.109 +
   1.110 +void
   1.111 +Zone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
   1.112 +{
   1.113 +    /*
   1.114 +     * Periodically release observed types for all scripts. This is safe to
   1.115 +     * do when there are no frames for the zone on the stack.
   1.116 +     */
   1.117 +    if (active)
   1.118 +        releaseTypes = false;
   1.119 +
   1.120 +    {
   1.121 +        gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
   1.122 +        types.sweep(fop, releaseTypes, oom);
   1.123 +    }
   1.124 +
   1.125 +    if (!fop->runtime()->debuggerList.isEmpty())
   1.126 +        sweepBreakpoints(fop);
   1.127 +
   1.128 +    active = false;
   1.129 +}
   1.130 +
   1.131 +void
   1.132 +Zone::sweepBreakpoints(FreeOp *fop)
   1.133 +{
   1.134 +    /*
   1.135 +     * Sweep all compartments in a zone at the same time, since there is no way
   1.136 +     * to iterate over the scripts belonging to a single compartment in a zone.
   1.137 +     */
   1.138 +
   1.139 +    gcstats::AutoPhase ap1(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_TABLES);
   1.140 +    gcstats::AutoPhase ap2(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_TABLES_BREAKPOINT);
   1.141 +
   1.142 +    JS_ASSERT(isGCSweeping());
   1.143 +    for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
   1.144 +        JSScript *script = i.get<JSScript>();
   1.145 +        JS_ASSERT(script->zone()->isGCSweeping());
   1.146 +        if (!script->hasAnyBreakpointsOrStepMode())
   1.147 +            continue;
   1.148 +
   1.149 +        bool scriptGone = IsScriptAboutToBeFinalized(&script);
   1.150 +        JS_ASSERT(script == i.get<JSScript>());
   1.151 +        for (unsigned i = 0; i < script->length(); i++) {
   1.152 +            BreakpointSite *site = script->getBreakpointSite(script->offsetToPC(i));
   1.153 +            if (!site)
   1.154 +                continue;
   1.155 +
   1.156 +            Breakpoint *nextbp;
   1.157 +            for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
   1.158 +                nextbp = bp->nextInSite();
   1.159 +                HeapPtrObject& dbgobj = bp->debugger->toJSObjectRef();
   1.160 +                JS_ASSERT(dbgobj->zone()->isGCSweeping());
   1.161 +                bool dying = scriptGone || IsObjectAboutToBeFinalized(&dbgobj);
   1.162 +                JS_ASSERT_IF(!dying, bp->getHandler()->isMarked());
   1.163 +                if (dying)
   1.164 +                    bp->destroy(fop);
   1.165 +            }
   1.166 +        }
   1.167 +    }
   1.168 +}
   1.169 +
   1.170 +void
   1.171 +Zone::discardJitCode(FreeOp *fop)
   1.172 +{
   1.173 +#ifdef JS_ION
   1.174 +    if (!jitZone())
   1.175 +        return;
   1.176 +
   1.177 +    if (isPreservingCode()) {
   1.178 +        PurgeJITCaches(this);
   1.179 +    } else {
   1.180 +
   1.181 +# ifdef DEBUG
   1.182 +        /* Assert no baseline scripts are marked as active. */
   1.183 +        for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
   1.184 +            JSScript *script = i.get<JSScript>();
   1.185 +            JS_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active());
   1.186 +        }
   1.187 +# endif
   1.188 +
   1.189 +        /* Mark baseline scripts on the stack as active. */
   1.190 +        jit::MarkActiveBaselineScripts(this);
   1.191 +
   1.192 +        /* Only mark OSI points if code is being discarded. */
   1.193 +        jit::InvalidateAll(fop, this);
   1.194 +
   1.195 +        for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
   1.196 +            JSScript *script = i.get<JSScript>();
   1.197 +            jit::FinishInvalidation<SequentialExecution>(fop, script);
   1.198 +
   1.199 +            // Preserve JIT code that have been recently used in
   1.200 +            // parallel. Note that we mark their baseline scripts as active as
   1.201 +            // well to preserve them.
   1.202 +            if (script->hasParallelIonScript()) {
   1.203 +                if (jit::ShouldPreserveParallelJITCode(runtimeFromMainThread(), script)) {
   1.204 +                    script->parallelIonScript()->purgeCaches();
   1.205 +                    script->baselineScript()->setActive();
   1.206 +                } else {
   1.207 +                    jit::FinishInvalidation<ParallelExecution>(fop, script);
   1.208 +                }
   1.209 +            }
   1.210 +
   1.211 +            /*
   1.212 +             * Discard baseline script if it's not marked as active. Note that
   1.213 +             * this also resets the active flag.
   1.214 +             */
   1.215 +            jit::FinishDiscardBaselineScript(fop, script);
   1.216 +
   1.217 +            /*
   1.218 +             * Use counts for scripts are reset on GC. After discarding code we
   1.219 +             * need to let it warm back up to get information such as which
   1.220 +             * opcodes are setting array holes or accessing getter properties.
   1.221 +             */
   1.222 +            script->resetUseCount();
   1.223 +        }
   1.224 +
   1.225 +        jitZone()->optimizedStubSpace()->free();
   1.226 +    }
   1.227 +#endif
   1.228 +}
   1.229 +
   1.230 +uint64_t
   1.231 +Zone::gcNumber()
   1.232 +{
   1.233 +    // Zones in use by exclusive threads are not collected, and threads using
   1.234 +    // them cannot access the main runtime's gcNumber without racing.
   1.235 +    return usedByExclusiveThread ? 0 : runtimeFromMainThread()->gcNumber;
   1.236 +}
   1.237 +
   1.238 +#ifdef JS_ION
   1.239 +js::jit::JitZone *
   1.240 +Zone::createJitZone(JSContext *cx)
   1.241 +{
   1.242 +    MOZ_ASSERT(!jitZone_);
   1.243 +
   1.244 +    if (!cx->runtime()->getJitRuntime(cx))
   1.245 +        return nullptr;
   1.246 +
   1.247 +    jitZone_ = cx->new_<js::jit::JitZone>();
   1.248 +    return jitZone_;
   1.249 +}
   1.250 +#endif
   1.251 +
   1.252 +JS::Zone *
   1.253 +js::ZoneOfObject(const JSObject &obj)
   1.254 +{
   1.255 +    return obj.zone();
   1.256 +}
   1.257 +
   1.258 +JS::Zone *
   1.259 +js::ZoneOfObjectFromAnyThread(const JSObject &obj)
   1.260 +{
   1.261 +    return obj.zoneFromAnyThread();
   1.262 +}
   1.263 +
   1.264 +bool
   1.265 +Zone::hasMarkedCompartments()
   1.266 +{
   1.267 +    for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next()) {
   1.268 +        if (comp->marked)
   1.269 +            return true;
   1.270 +    }
   1.271 +    return false;
   1.272 +}

mercurial