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.

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

mercurial