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.

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

mercurial