js/src/gc/Tracer.h

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 #ifndef js_Tracer_h
michael@0 8 #define js_Tracer_h
michael@0 9
michael@0 10 #include "mozilla/DebugOnly.h"
michael@0 11
michael@0 12 #include "js/GCAPI.h"
michael@0 13 #include "js/SliceBudget.h"
michael@0 14 #include "js/TracingAPI.h"
michael@0 15
michael@0 16 namespace js {
michael@0 17 class GCMarker;
michael@0 18 class ObjectImpl;
michael@0 19 namespace gc {
michael@0 20 class ArenaHeader;
michael@0 21 }
michael@0 22 namespace jit {
michael@0 23 class JitCode;
michael@0 24 }
michael@0 25 namespace types {
michael@0 26 class TypeObject;
michael@0 27 }
michael@0 28
michael@0 29 static const size_t NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY = 4096;
michael@0 30 static const size_t INCREMENTAL_MARK_STACK_BASE_CAPACITY = 32768;
michael@0 31
michael@0 32 /*
michael@0 33 * When the native stack is low, the GC does not call JS_TraceChildren to mark
michael@0 34 * the reachable "children" of the thing. Rather the thing is put aside and
michael@0 35 * JS_TraceChildren is called later with more space on the C stack.
michael@0 36 *
michael@0 37 * To implement such delayed marking of the children with minimal overhead for
michael@0 38 * the normal case of sufficient native stack, the code adds a field per arena.
michael@0 39 * The field markingDelay->link links all arenas with delayed things into a
michael@0 40 * stack list with the pointer to stack top in GCMarker::unmarkedArenaStackTop.
michael@0 41 * GCMarker::delayMarkingChildren adds arenas to the stack as necessary while
michael@0 42 * markDelayedChildren pops the arenas from the stack until it empties.
michael@0 43 */
michael@0 44 class MarkStack
michael@0 45 {
michael@0 46 friend class GCMarker;
michael@0 47
michael@0 48 uintptr_t *stack_;
michael@0 49 uintptr_t *tos_;
michael@0 50 uintptr_t *end_;
michael@0 51
michael@0 52 // The capacity we start with and reset() to.
michael@0 53 size_t baseCapacity_;
michael@0 54 size_t maxCapacity_;
michael@0 55
michael@0 56 public:
michael@0 57 MarkStack(size_t maxCapacity)
michael@0 58 : stack_(nullptr),
michael@0 59 tos_(nullptr),
michael@0 60 end_(nullptr),
michael@0 61 baseCapacity_(0),
michael@0 62 maxCapacity_(maxCapacity)
michael@0 63 {}
michael@0 64
michael@0 65 ~MarkStack() {
michael@0 66 js_free(stack_);
michael@0 67 }
michael@0 68
michael@0 69 size_t capacity() { return end_ - stack_; }
michael@0 70
michael@0 71 ptrdiff_t position() const { return tos_ - stack_; }
michael@0 72
michael@0 73 void setStack(uintptr_t *stack, size_t tosIndex, size_t capacity) {
michael@0 74 stack_ = stack;
michael@0 75 tos_ = stack + tosIndex;
michael@0 76 end_ = stack + capacity;
michael@0 77 }
michael@0 78
michael@0 79 bool init(JSGCMode gcMode);
michael@0 80
michael@0 81 void setBaseCapacity(JSGCMode mode);
michael@0 82 size_t maxCapacity() const { return maxCapacity_; }
michael@0 83 void setMaxCapacity(size_t maxCapacity);
michael@0 84
michael@0 85 bool push(uintptr_t item) {
michael@0 86 if (tos_ == end_) {
michael@0 87 if (!enlarge(1))
michael@0 88 return false;
michael@0 89 }
michael@0 90 JS_ASSERT(tos_ < end_);
michael@0 91 *tos_++ = item;
michael@0 92 return true;
michael@0 93 }
michael@0 94
michael@0 95 bool push(uintptr_t item1, uintptr_t item2, uintptr_t item3) {
michael@0 96 uintptr_t *nextTos = tos_ + 3;
michael@0 97 if (nextTos > end_) {
michael@0 98 if (!enlarge(3))
michael@0 99 return false;
michael@0 100 nextTos = tos_ + 3;
michael@0 101 }
michael@0 102 JS_ASSERT(nextTos <= end_);
michael@0 103 tos_[0] = item1;
michael@0 104 tos_[1] = item2;
michael@0 105 tos_[2] = item3;
michael@0 106 tos_ = nextTos;
michael@0 107 return true;
michael@0 108 }
michael@0 109
michael@0 110 bool isEmpty() const {
michael@0 111 return tos_ == stack_;
michael@0 112 }
michael@0 113
michael@0 114 uintptr_t pop() {
michael@0 115 JS_ASSERT(!isEmpty());
michael@0 116 return *--tos_;
michael@0 117 }
michael@0 118
michael@0 119 void reset();
michael@0 120
michael@0 121 /* Grow the stack, ensuring there is space for at least count elements. */
michael@0 122 bool enlarge(unsigned count);
michael@0 123
michael@0 124 void setGCMode(JSGCMode gcMode);
michael@0 125
michael@0 126 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
michael@0 127 };
michael@0 128
michael@0 129 class GCMarker : public JSTracer
michael@0 130 {
michael@0 131 public:
michael@0 132 explicit GCMarker(JSRuntime *rt);
michael@0 133 bool init(JSGCMode gcMode);
michael@0 134
michael@0 135 void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
michael@0 136 size_t maxCapacity() const { return stack.maxCapacity(); }
michael@0 137
michael@0 138 void start();
michael@0 139 void stop();
michael@0 140 void reset();
michael@0 141
michael@0 142 void pushObject(ObjectImpl *obj) {
michael@0 143 pushTaggedPtr(ObjectTag, obj);
michael@0 144 }
michael@0 145
michael@0 146 void pushType(types::TypeObject *type) {
michael@0 147 pushTaggedPtr(TypeTag, type);
michael@0 148 }
michael@0 149
michael@0 150 void pushJitCode(jit::JitCode *code) {
michael@0 151 pushTaggedPtr(JitCodeTag, code);
michael@0 152 }
michael@0 153
michael@0 154 uint32_t getMarkColor() const {
michael@0 155 return color;
michael@0 156 }
michael@0 157
michael@0 158 /*
michael@0 159 * Care must be taken changing the mark color from gray to black. The cycle
michael@0 160 * collector depends on the invariant that there are no black to gray edges
michael@0 161 * in the GC heap. This invariant lets the CC not trace through black
michael@0 162 * objects. If this invariant is violated, the cycle collector may free
michael@0 163 * objects that are still reachable.
michael@0 164 */
michael@0 165 void setMarkColorGray() {
michael@0 166 JS_ASSERT(isDrained());
michael@0 167 JS_ASSERT(color == gc::BLACK);
michael@0 168 color = gc::GRAY;
michael@0 169 }
michael@0 170
michael@0 171 void setMarkColorBlack() {
michael@0 172 JS_ASSERT(isDrained());
michael@0 173 JS_ASSERT(color == gc::GRAY);
michael@0 174 color = gc::BLACK;
michael@0 175 }
michael@0 176
michael@0 177 inline void delayMarkingArena(gc::ArenaHeader *aheader);
michael@0 178 void delayMarkingChildren(const void *thing);
michael@0 179 void markDelayedChildren(gc::ArenaHeader *aheader);
michael@0 180 bool markDelayedChildren(SliceBudget &budget);
michael@0 181 bool hasDelayedChildren() const {
michael@0 182 return !!unmarkedArenaStackTop;
michael@0 183 }
michael@0 184
michael@0 185 bool isDrained() {
michael@0 186 return isMarkStackEmpty() && !unmarkedArenaStackTop;
michael@0 187 }
michael@0 188
michael@0 189 bool drainMarkStack(SliceBudget &budget);
michael@0 190
michael@0 191 /*
michael@0 192 * Gray marking must be done after all black marking is complete. However,
michael@0 193 * we do not have write barriers on XPConnect roots. Therefore, XPConnect
michael@0 194 * roots must be accumulated in the first slice of incremental GC. We
michael@0 195 * accumulate these roots in the each compartment's gcGrayRoots vector and
michael@0 196 * then mark them later, after black marking is complete for each
michael@0 197 * compartment. This accumulation can fail, but in that case we switch to
michael@0 198 * non-incremental GC.
michael@0 199 */
michael@0 200 bool hasBufferedGrayRoots() const;
michael@0 201 void startBufferingGrayRoots();
michael@0 202 void endBufferingGrayRoots();
michael@0 203 void resetBufferedGrayRoots();
michael@0 204 void markBufferedGrayRoots(JS::Zone *zone);
michael@0 205
michael@0 206 static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind);
michael@0 207
michael@0 208 void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
michael@0 209
michael@0 210 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
michael@0 211
michael@0 212 /* This is public exclusively for ScanRope. */
michael@0 213 MarkStack stack;
michael@0 214
michael@0 215 private:
michael@0 216 #ifdef DEBUG
michael@0 217 void checkZone(void *p);
michael@0 218 #else
michael@0 219 void checkZone(void *p) {}
michael@0 220 #endif
michael@0 221
michael@0 222 /*
michael@0 223 * We use a common mark stack to mark GC things of different types and use
michael@0 224 * the explicit tags to distinguish them when it cannot be deduced from
michael@0 225 * the context of push or pop operation.
michael@0 226 */
michael@0 227 enum StackTag {
michael@0 228 ValueArrayTag,
michael@0 229 ObjectTag,
michael@0 230 TypeTag,
michael@0 231 XmlTag,
michael@0 232 SavedValueArrayTag,
michael@0 233 JitCodeTag,
michael@0 234 LastTag = JitCodeTag
michael@0 235 };
michael@0 236
michael@0 237 static const uintptr_t StackTagMask = 7;
michael@0 238 static_assert(StackTagMask >= uintptr_t(LastTag), "The tag mask must subsume the tags.");
michael@0 239 static_assert(StackTagMask <= gc::CellMask, "The tag mask must be embeddable in a Cell*.");
michael@0 240
michael@0 241 void pushTaggedPtr(StackTag tag, void *ptr) {
michael@0 242 checkZone(ptr);
michael@0 243 uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
michael@0 244 JS_ASSERT(!(addr & StackTagMask));
michael@0 245 if (!stack.push(addr | uintptr_t(tag)))
michael@0 246 delayMarkingChildren(ptr);
michael@0 247 }
michael@0 248
michael@0 249 void pushValueArray(JSObject *obj, void *start, void *end) {
michael@0 250 checkZone(obj);
michael@0 251
michael@0 252 JS_ASSERT(start <= end);
michael@0 253 uintptr_t tagged = reinterpret_cast<uintptr_t>(obj) | GCMarker::ValueArrayTag;
michael@0 254 uintptr_t startAddr = reinterpret_cast<uintptr_t>(start);
michael@0 255 uintptr_t endAddr = reinterpret_cast<uintptr_t>(end);
michael@0 256
michael@0 257 /*
michael@0 258 * Push in the reverse order so obj will be on top. If we cannot push
michael@0 259 * the array, we trigger delay marking for the whole object.
michael@0 260 */
michael@0 261 if (!stack.push(endAddr, startAddr, tagged))
michael@0 262 delayMarkingChildren(obj);
michael@0 263 }
michael@0 264
michael@0 265 bool isMarkStackEmpty() {
michael@0 266 return stack.isEmpty();
michael@0 267 }
michael@0 268
michael@0 269 bool restoreValueArray(JSObject *obj, void **vpp, void **endp);
michael@0 270 void saveValueRanges();
michael@0 271 inline void processMarkStackTop(SliceBudget &budget);
michael@0 272 void processMarkStackOther(uintptr_t tag, uintptr_t addr);
michael@0 273
michael@0 274 void appendGrayRoot(void *thing, JSGCTraceKind kind);
michael@0 275
michael@0 276 /* The color is only applied to objects and functions. */
michael@0 277 uint32_t color;
michael@0 278
michael@0 279 /* Pointer to the top of the stack of arenas we are delaying marking on. */
michael@0 280 js::gc::ArenaHeader *unmarkedArenaStackTop;
michael@0 281
michael@0 282 /* Count of arenas that are currently in the stack. */
michael@0 283 mozilla::DebugOnly<size_t> markLaterArenas;
michael@0 284
michael@0 285 enum GrayBufferState {
michael@0 286 GRAY_BUFFER_UNUSED,
michael@0 287 GRAY_BUFFER_OK,
michael@0 288 GRAY_BUFFER_FAILED
michael@0 289 };
michael@0 290 GrayBufferState grayBufferState;
michael@0 291
michael@0 292 /* Assert that start and stop are called with correct ordering. */
michael@0 293 mozilla::DebugOnly<bool> started;
michael@0 294 };
michael@0 295
michael@0 296 void
michael@0 297 SetMarkStackLimit(JSRuntime *rt, size_t limit);
michael@0 298
michael@0 299 } /* namespace js */
michael@0 300
michael@0 301 /*
michael@0 302 * Macro to test if a traversal is the marking phase of the GC.
michael@0 303 */
michael@0 304 #define IS_GC_MARKING_TRACER(trc) \
michael@0 305 ((trc)->callback == nullptr || (trc)->callback == GCMarker::GrayCallback)
michael@0 306
michael@0 307 #endif /* js_Tracer_h */

mercurial