js/src/gc/Zone.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "gc/Zone.h"
     9 #include "jsgc.h"
    11 #ifdef JS_ION
    12 #include "jit/BaselineJIT.h"
    13 #include "jit/Ion.h"
    14 #include "jit/JitCompartment.h"
    15 #endif
    16 #include "vm/Debugger.h"
    17 #include "vm/Runtime.h"
    19 #include "jsgcinlines.h"
    21 using namespace js;
    22 using namespace js::gc;
    24 JS::Zone::Zone(JSRuntime *rt)
    25   : JS::shadow::Zone(rt, &rt->gcMarker),
    26     allocator(this),
    27     ionUsingBarriers_(false),
    28     active(false),
    29     gcScheduled(false),
    30     gcState(NoGC),
    31     gcPreserveCode(false),
    32     gcBytes(0),
    33     gcTriggerBytes(0),
    34     gcHeapGrowthFactor(3.0),
    35     isSystem(false),
    36     usedByExclusiveThread(false),
    37     scheduledForDestruction(false),
    38     maybeAlive(true),
    39     gcMallocBytes(0),
    40     gcMallocGCTriggered(false),
    41     gcGrayRoots(),
    42     data(nullptr),
    43     types(this)
    44 #ifdef JS_ION
    45     , jitZone_(nullptr)
    46 #endif
    47 {
    48     /* Ensure that there are no vtables to mess us up here. */
    49     JS_ASSERT(reinterpret_cast<JS::shadow::Zone *>(this) ==
    50               static_cast<JS::shadow::Zone *>(this));
    52     setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9);
    53 }
    55 Zone::~Zone()
    56 {
    57     if (this == runtimeFromMainThread()->systemZone)
    58         runtimeFromMainThread()->systemZone = nullptr;
    60 #ifdef JS_ION
    61     js_delete(jitZone_);
    62 #endif
    63 }
    65 void
    66 Zone::setNeedsBarrier(bool needs, ShouldUpdateIon updateIon)
    67 {
    68 #ifdef JS_ION
    69     if (updateIon == UpdateIon && needs != ionUsingBarriers_) {
    70         jit::ToggleBarriers(this, needs);
    71         ionUsingBarriers_ = needs;
    72     }
    73 #endif
    75     if (needs && runtimeFromMainThread()->isAtomsZone(this))
    76         JS_ASSERT(!runtimeFromMainThread()->exclusiveThreadsPresent());
    78     JS_ASSERT_IF(needs, canCollect());
    79     needsBarrier_ = needs;
    80 }
    82 void
    83 Zone::resetGCMallocBytes()
    84 {
    85     gcMallocBytes = ptrdiff_t(gcMaxMallocBytes);
    86     gcMallocGCTriggered = false;
    87 }
    89 void
    90 Zone::setGCMaxMallocBytes(size_t value)
    91 {
    92     /*
    93      * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
    94      * mean that value.
    95      */
    96     gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
    97     resetGCMallocBytes();
    98 }
   100 void
   101 Zone::onTooMuchMalloc()
   102 {
   103     if (!gcMallocGCTriggered)
   104         gcMallocGCTriggered = TriggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC);
   105 }
   107 void
   108 Zone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
   109 {
   110     /*
   111      * Periodically release observed types for all scripts. This is safe to
   112      * do when there are no frames for the zone on the stack.
   113      */
   114     if (active)
   115         releaseTypes = false;
   117     {
   118         gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
   119         types.sweep(fop, releaseTypes, oom);
   120     }
   122     if (!fop->runtime()->debuggerList.isEmpty())
   123         sweepBreakpoints(fop);
   125     active = false;
   126 }
   128 void
   129 Zone::sweepBreakpoints(FreeOp *fop)
   130 {
   131     /*
   132      * Sweep all compartments in a zone at the same time, since there is no way
   133      * to iterate over the scripts belonging to a single compartment in a zone.
   134      */
   136     gcstats::AutoPhase ap1(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_TABLES);
   137     gcstats::AutoPhase ap2(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_TABLES_BREAKPOINT);
   139     JS_ASSERT(isGCSweeping());
   140     for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
   141         JSScript *script = i.get<JSScript>();
   142         JS_ASSERT(script->zone()->isGCSweeping());
   143         if (!script->hasAnyBreakpointsOrStepMode())
   144             continue;
   146         bool scriptGone = IsScriptAboutToBeFinalized(&script);
   147         JS_ASSERT(script == i.get<JSScript>());
   148         for (unsigned i = 0; i < script->length(); i++) {
   149             BreakpointSite *site = script->getBreakpointSite(script->offsetToPC(i));
   150             if (!site)
   151                 continue;
   153             Breakpoint *nextbp;
   154             for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
   155                 nextbp = bp->nextInSite();
   156                 HeapPtrObject& dbgobj = bp->debugger->toJSObjectRef();
   157                 JS_ASSERT(dbgobj->zone()->isGCSweeping());
   158                 bool dying = scriptGone || IsObjectAboutToBeFinalized(&dbgobj);
   159                 JS_ASSERT_IF(!dying, bp->getHandler()->isMarked());
   160                 if (dying)
   161                     bp->destroy(fop);
   162             }
   163         }
   164     }
   165 }
   167 void
   168 Zone::discardJitCode(FreeOp *fop)
   169 {
   170 #ifdef JS_ION
   171     if (!jitZone())
   172         return;
   174     if (isPreservingCode()) {
   175         PurgeJITCaches(this);
   176     } else {
   178 # ifdef DEBUG
   179         /* Assert no baseline scripts are marked as active. */
   180         for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
   181             JSScript *script = i.get<JSScript>();
   182             JS_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active());
   183         }
   184 # endif
   186         /* Mark baseline scripts on the stack as active. */
   187         jit::MarkActiveBaselineScripts(this);
   189         /* Only mark OSI points if code is being discarded. */
   190         jit::InvalidateAll(fop, this);
   192         for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
   193             JSScript *script = i.get<JSScript>();
   194             jit::FinishInvalidation<SequentialExecution>(fop, script);
   196             // Preserve JIT code that have been recently used in
   197             // parallel. Note that we mark their baseline scripts as active as
   198             // well to preserve them.
   199             if (script->hasParallelIonScript()) {
   200                 if (jit::ShouldPreserveParallelJITCode(runtimeFromMainThread(), script)) {
   201                     script->parallelIonScript()->purgeCaches();
   202                     script->baselineScript()->setActive();
   203                 } else {
   204                     jit::FinishInvalidation<ParallelExecution>(fop, script);
   205                 }
   206             }
   208             /*
   209              * Discard baseline script if it's not marked as active. Note that
   210              * this also resets the active flag.
   211              */
   212             jit::FinishDiscardBaselineScript(fop, script);
   214             /*
   215              * Use counts for scripts are reset on GC. After discarding code we
   216              * need to let it warm back up to get information such as which
   217              * opcodes are setting array holes or accessing getter properties.
   218              */
   219             script->resetUseCount();
   220         }
   222         jitZone()->optimizedStubSpace()->free();
   223     }
   224 #endif
   225 }
   227 uint64_t
   228 Zone::gcNumber()
   229 {
   230     // Zones in use by exclusive threads are not collected, and threads using
   231     // them cannot access the main runtime's gcNumber without racing.
   232     return usedByExclusiveThread ? 0 : runtimeFromMainThread()->gcNumber;
   233 }
   235 #ifdef JS_ION
   236 js::jit::JitZone *
   237 Zone::createJitZone(JSContext *cx)
   238 {
   239     MOZ_ASSERT(!jitZone_);
   241     if (!cx->runtime()->getJitRuntime(cx))
   242         return nullptr;
   244     jitZone_ = cx->new_<js::jit::JitZone>();
   245     return jitZone_;
   246 }
   247 #endif
   249 JS::Zone *
   250 js::ZoneOfObject(const JSObject &obj)
   251 {
   252     return obj.zone();
   253 }
   255 JS::Zone *
   256 js::ZoneOfObjectFromAnyThread(const JSObject &obj)
   257 {
   258     return obj.zoneFromAnyThread();
   259 }
   261 bool
   262 Zone::hasMarkedCompartments()
   263 {
   264     for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next()) {
   265         if (comp->marked)
   266             return true;
   267     }
   268     return false;
   269 }

mercurial