author | Terrence Cole <terrence@mozilla.com> |
Wed, 16 Apr 2014 16:36:44 -0700 | |
changeset 179625 | 098f943ba58dcddc8e469f8ecf430998d1ef1d69 |
parent 179624 | 84b4cf605262bff4881bc08859a45f7611482fc3 |
child 179626 | 139c2e8c264ff015779ca62b87b81f41396542be |
push id | 26632 |
push user | kwierso@gmail.com |
push date | Wed, 23 Apr 2014 00:54:42 +0000 |
treeherder | mozilla-central@02515cf4fcfd [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jonco |
bugs | 807168 |
milestone | 31.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
|
js/src/gc/Tracer.cpp | file | annotate | diff | comparison | revisions | |
js/src/gc/Tracer.h | file | annotate | diff | comparison | revisions |
--- 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 */ /*