Bug 807168 - Move rarely used code in GCMarker out of the header; r=jonco
authorTerrence Cole <terrence@mozilla.com>
Wed, 16 Apr 2014 16:36:44 -0700
changeset 198121 098f943ba58dcddc8e469f8ecf430998d1ef1d69
parent 198120 84b4cf605262bff4881bc08859a45f7611482fc3
child 198122 139c2e8c264ff015779ca62b87b81f41396542be
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs807168
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 807168 - Move rarely used code in GCMarker out of the header; r=jonco
js/src/gc/Tracer.cpp
js/src/gc/Tracer.h
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -8,16 +8,17 @@
 
 #include "mozilla/DebugOnly.h"
 
 #include "jsapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsprf.h"
 #include "jsscript.h"
+#include "jsutil.h"
 #include "NamespaceImports.h"
 
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 
 #include "jsgcinlines.h"
 
 using namespace js;
@@ -328,28 +329,122 @@ JSTracer::unsetTracingLocation()
 
 void **
 JSTracer::tracingLocation(void **thingp)
 {
     return realLocation_ ? (void **)realLocation_ : thingp;
 }
 #endif
 
+bool
+MarkStack::init(JSGCMode gcMode)
+{
+    setBaseCapacity(gcMode);
+
+    JS_ASSERT(!stack_);
+    uintptr_t *newStack = js_pod_malloc<uintptr_t>(baseCapacity_);
+    if (!newStack)
+        return false;
+
+    setStack(newStack, 0, baseCapacity_);
+    return true;
+}
+
+void
+MarkStack::setBaseCapacity(JSGCMode mode)
+{
+    switch (mode) {
+      case JSGC_MODE_GLOBAL:
+      case JSGC_MODE_COMPARTMENT:
+        baseCapacity_ = NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY;
+        break;
+      case JSGC_MODE_INCREMENTAL:
+        baseCapacity_ = INCREMENTAL_MARK_STACK_BASE_CAPACITY;
+        break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("bad gc mode");
+    }
+
+    if (baseCapacity_ > maxCapacity_)
+        baseCapacity_ = maxCapacity_;
+}
+
+void
+MarkStack::setMaxCapacity(size_t maxCapacity)
+{
+    JS_ASSERT(isEmpty());
+    maxCapacity_ = maxCapacity;
+    if (baseCapacity_ > maxCapacity_)
+        baseCapacity_ = maxCapacity_;
+
+    reset();
+}
+
+void
+MarkStack::reset()
+{
+    if (capacity() == baseCapacity_) {
+        // No size change; keep the current stack.
+        setStack(stack_, 0, baseCapacity_);
+        return;
+    }
+
+    uintptr_t *newStack = (uintptr_t *)js_realloc(stack_, sizeof(uintptr_t) * baseCapacity_);
+    if (!newStack) {
+        // If the realloc fails, just keep using the existing stack; it's
+        // not ideal but better than failing.
+        newStack = stack_;
+        baseCapacity_ = capacity();
+    }
+    setStack(newStack, 0, baseCapacity_);
+}
+
+bool
+MarkStack::enlarge(unsigned count)
+{
+    size_t newCapacity = Min(maxCapacity_, capacity() * 2);
+    if (newCapacity < capacity() + count)
+        return false;
+
+    size_t tosIndex = position();
+
+    uintptr_t *newStack = (uintptr_t *)js_realloc(stack_, sizeof(uintptr_t) * newCapacity);
+    if (!newStack)
+        return false;
+
+    setStack(newStack, tosIndex, newCapacity);
+    return true;
+}
+
+void
+MarkStack::setGCMode(JSGCMode gcMode)
+{
+    // The mark stack won't be resized until the next call to reset(), but
+    // that will happen at the end of the next GC.
+    setBaseCapacity(gcMode);
+}
+
+size_t
+MarkStack::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+{
+    return mallocSizeOf(stack_);
+}
+
 /*
  * DoNotTraceWeakMaps: the GC is recomputing the liveness of WeakMap entries,
  * so we delay visting entries.
  */
 GCMarker::GCMarker(JSRuntime *rt)
   : JSTracer(rt, nullptr, DoNotTraceWeakMaps),
     stack(size_t(-1)),
     color(BLACK),
-    started(false),
     unmarkedArenaStackTop(nullptr),
     markLaterArenas(0),
-    grayBufferState(GRAY_BUFFER_UNUSED)
+    grayBufferState(GRAY_BUFFER_UNUSED),
+    started(false)
 {
 }
 
 bool
 GCMarker::init(JSGCMode gcMode)
 {
     return stack.init(gcMode);
 }
--- a/js/src/gc/Tracer.h
+++ b/js/src/gc/Tracer.h
@@ -4,23 +4,22 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef js_Tracer_h
 #define js_Tracer_h
 
 #include "mozilla/DebugOnly.h"
 
-#include "jsutil.h"
-
 #include "js/GCAPI.h"
 #include "js/SliceBudget.h"
 #include "js/TracingAPI.h"
 
 namespace js {
+class GCMarker;
 class ObjectImpl;
 namespace gc {
 class ArenaHeader;
 }
 namespace jit {
 class JitCode;
 }
 namespace types {
@@ -37,98 +36,69 @@ static const size_t INCREMENTAL_MARK_STA
  *
  * To implement such delayed marking of the children with minimal overhead for
  * the normal case of sufficient native stack, the code adds a field per arena.
  * The field markingDelay->link links all arenas with delayed things into a
  * stack list with the pointer to stack top in GCMarker::unmarkedArenaStackTop.
  * GCMarker::delayMarkingChildren adds arenas to the stack as necessary while
  * markDelayedChildren pops the arenas from the stack until it empties.
  */
-template<class T>
-struct MarkStack {
-    T *stack_;
-    T *tos_;
-    T *end_;
+class MarkStack
+{
+    friend class GCMarker;
+
+    uintptr_t *stack_;
+    uintptr_t *tos_;
+    uintptr_t *end_;
 
     // The capacity we start with and reset() to.
     size_t baseCapacity_;
     size_t maxCapacity_;
 
+  public:
     MarkStack(size_t maxCapacity)
       : stack_(nullptr),
         tos_(nullptr),
         end_(nullptr),
         baseCapacity_(0),
         maxCapacity_(maxCapacity)
     {}
 
     ~MarkStack() {
         js_free(stack_);
     }
 
     size_t capacity() { return end_ - stack_; }
 
     ptrdiff_t position() const { return tos_ - stack_; }
 
-    void setStack(T *stack, size_t tosIndex, size_t capacity) {
+    void setStack(uintptr_t *stack, size_t tosIndex, size_t capacity) {
         stack_ = stack;
         tos_ = stack + tosIndex;
         end_ = stack + capacity;
     }
 
-    void setBaseCapacity(JSGCMode mode) {
-        switch (mode) {
-          case JSGC_MODE_GLOBAL:
-          case JSGC_MODE_COMPARTMENT:
-            baseCapacity_ = NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY;
-            break;
-          case JSGC_MODE_INCREMENTAL:
-            baseCapacity_ = INCREMENTAL_MARK_STACK_BASE_CAPACITY;
-            break;
-          default:
-            MOZ_ASSUME_UNREACHABLE("bad gc mode");
-        }
-
-        if (baseCapacity_ > maxCapacity_)
-            baseCapacity_ = maxCapacity_;
-    }
-
-    bool init(JSGCMode gcMode) {
-        setBaseCapacity(gcMode);
+    bool init(JSGCMode gcMode);
 
-        JS_ASSERT(!stack_);
-        T *newStack = js_pod_malloc<T>(baseCapacity_);
-        if (!newStack)
-            return false;
-
-        setStack(newStack, 0, baseCapacity_);
-        return true;
-    }
+    void setBaseCapacity(JSGCMode mode);
+    size_t maxCapacity() const { return maxCapacity_; }
+    void setMaxCapacity(size_t maxCapacity);
 
-    void setMaxCapacity(size_t maxCapacity) {
-        JS_ASSERT(isEmpty());
-        maxCapacity_ = maxCapacity;
-        if (baseCapacity_ > maxCapacity_)
-            baseCapacity_ = maxCapacity_;
-
-        reset();
-    }
-
-    bool push(T item) {
+    bool push(uintptr_t item) {
         if (tos_ == end_) {
             if (!enlarge(1))
                 return false;
         }
         JS_ASSERT(tos_ < end_);
         *tos_++ = item;
         return true;
     }
 
-    bool push(T item1, T item2, T item3) {
-        T *nextTos = tos_ + 3;
+    bool push(uintptr_t item1, uintptr_t item2, uintptr_t item3) {
+        uintptr_t *nextTos = tos_ + 3;
         if (nextTos > end_) {
             if (!enlarge(3))
                 return false;
             nextTos = tos_ + 3;
         }
         JS_ASSERT(nextTos <= end_);
         tos_[0] = item1;
         tos_[1] = item2;
@@ -136,95 +106,39 @@ struct MarkStack {
         tos_ = nextTos;
         return true;
     }
 
     bool isEmpty() const {
         return tos_ == stack_;
     }
 
-    T pop() {
+    uintptr_t pop() {
         JS_ASSERT(!isEmpty());
         return *--tos_;
     }
 
-    void reset() {
-        if (capacity() == baseCapacity_) {
-            // No size change; keep the current stack.
-            setStack(stack_, 0, baseCapacity_);
-            return;
-        }
-
-        T *newStack = (T *)js_realloc(stack_, sizeof(T) * baseCapacity_);
-        if (!newStack) {
-            // If the realloc fails, just keep using the existing stack; it's
-            // not ideal but better than failing.
-            newStack = stack_;
-            baseCapacity_ = capacity();
-        }
-        setStack(newStack, 0, baseCapacity_);
-    }
+    void reset();
 
     /* Grow the stack, ensuring there is space for at least count elements. */
-    bool enlarge(unsigned count) {
-        size_t newCapacity = Min(maxCapacity_, capacity() * 2);
-        if (newCapacity < capacity() + count)
-            return false;
-
-        size_t tosIndex = position();
-
-        T *newStack = (T *)js_realloc(stack_, sizeof(T) * newCapacity);
-        if (!newStack)
-            return false;
+    bool enlarge(unsigned count);
 
-        setStack(newStack, tosIndex, newCapacity);
-        return true;
-    }
+    void setGCMode(JSGCMode gcMode);
 
-    void setGCMode(JSGCMode gcMode) {
-        // The mark stack won't be resized until the next call to reset(), but
-        // that will happen at the end of the next GC.
-        setBaseCapacity(gcMode);
-    }
-
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        return mallocSizeOf(stack_);
-    }
+    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 };
 
-struct GCMarker : public JSTracer {
-  private:
-    /*
-     * We use a common mark stack to mark GC things of different types and use
-     * the explicit tags to distinguish them when it cannot be deduced from
-     * the context of push or pop operation.
-     */
-    enum StackTag {
-        ValueArrayTag,
-        ObjectTag,
-        TypeTag,
-        XmlTag,
-        SavedValueArrayTag,
-        JitCodeTag,
-        LastTag = JitCodeTag
-    };
-
-    static const uintptr_t StackTagMask = 7;
-
-    static void staticAsserts() {
-        JS_STATIC_ASSERT(StackTagMask >= uintptr_t(LastTag));
-        JS_STATIC_ASSERT(StackTagMask <= gc::CellMask);
-    }
-
+class GCMarker : public JSTracer
+{
   public:
     explicit GCMarker(JSRuntime *rt);
     bool init(JSGCMode gcMode);
 
     void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
-    size_t maxCapacity() const { return stack.maxCapacity_; }
+    size_t maxCapacity() const { return stack.maxCapacity(); }
 
     void start();
     void stop();
     void reset();
 
     void pushObject(ObjectImpl *obj) {
         pushTaggedPtr(ObjectTag, obj);
     }
@@ -290,25 +204,45 @@ struct GCMarker : public JSTracer {
     void markBufferedGrayRoots(JS::Zone *zone);
 
     static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind);
 
     void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
-    MarkStack<uintptr_t> stack;
+    /* This is public exclusively for ScanRope. */
+    MarkStack stack;
 
   private:
 #ifdef DEBUG
     void checkZone(void *p);
 #else
     void checkZone(void *p) {}
 #endif
 
+    /*
+     * We use a common mark stack to mark GC things of different types and use
+     * the explicit tags to distinguish them when it cannot be deduced from
+     * the context of push or pop operation.
+     */
+    enum StackTag {
+        ValueArrayTag,
+        ObjectTag,
+        TypeTag,
+        XmlTag,
+        SavedValueArrayTag,
+        JitCodeTag,
+        LastTag = JitCodeTag
+    };
+
+    static const uintptr_t StackTagMask = 7;
+    static_assert(StackTagMask >= uintptr_t(LastTag), "The tag mask must subsume the tags.");
+    static_assert(StackTagMask <= gc::CellMask, "The tag mask must be embeddable in a Cell*.");
+
     void pushTaggedPtr(StackTag tag, void *ptr) {
         checkZone(ptr);
         uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
         JS_ASSERT(!(addr & StackTagMask));
         if (!stack.push(addr | uintptr_t(tag)))
             delayMarkingChildren(ptr);
     }
 
@@ -337,31 +271,31 @@ struct GCMarker : public JSTracer {
     inline void processMarkStackTop(SliceBudget &budget);
     void processMarkStackOther(uintptr_t tag, uintptr_t addr);
 
     void appendGrayRoot(void *thing, JSGCTraceKind kind);
 
     /* The color is only applied to objects and functions. */
     uint32_t color;
 
-    mozilla::DebugOnly<bool> started;
-
     /* Pointer to the top of the stack of arenas we are delaying marking on. */
     js::gc::ArenaHeader *unmarkedArenaStackTop;
+
     /* Count of arenas that are currently in the stack. */
     mozilla::DebugOnly<size_t> markLaterArenas;
 
-    enum GrayBufferState
-    {
+    enum GrayBufferState {
         GRAY_BUFFER_UNUSED,
         GRAY_BUFFER_OK,
         GRAY_BUFFER_FAILED
     };
+    GrayBufferState grayBufferState;
 
-    GrayBufferState grayBufferState;
+    /* Assert that start and stop are called with correct ordering. */
+    mozilla::DebugOnly<bool> started;
 };
 
 void
 SetMarkStackLimit(JSRuntime *rt, size_t limit);
 
 } /* namespace js */
 
 /*