mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 21:35:39 +00:00
Bug 1341355 - Refactor the mark stack r=sfink
This commit is contained in:
parent
7b865b5def
commit
e6282397f4
@ -897,18 +897,18 @@ template <> void GCMarker::traverse(js::Scope* thing) { markAndScan(thing); }
|
||||
// be used as a weakmap key and thereby recurse into weakmapped values.
|
||||
template <typename T>
|
||||
void
|
||||
js::GCMarker::markAndPush(StackTag tag, T* thing)
|
||||
js::GCMarker::markAndPush(T* thing)
|
||||
{
|
||||
if (!mark(thing))
|
||||
return;
|
||||
pushTaggedPtr(tag, thing);
|
||||
pushTaggedPtr(thing);
|
||||
markImplicitEdges(thing);
|
||||
}
|
||||
namespace js {
|
||||
template <> void GCMarker::traverse(JSObject* thing) { markAndPush(ObjectTag, thing); }
|
||||
template <> void GCMarker::traverse(ObjectGroup* thing) { markAndPush(GroupTag, thing); }
|
||||
template <> void GCMarker::traverse(jit::JitCode* thing) { markAndPush(JitCodeTag, thing); }
|
||||
template <> void GCMarker::traverse(JSScript* thing) { markAndPush(ScriptTag, thing); }
|
||||
template <> void GCMarker::traverse(JSObject* thing) { markAndPush(thing); }
|
||||
template <> void GCMarker::traverse(ObjectGroup* thing) { markAndPush(thing); }
|
||||
template <> void GCMarker::traverse(jit::JitCode* thing) { markAndPush(thing); }
|
||||
template <> void GCMarker::traverse(JSScript* thing) { markAndPush(thing); }
|
||||
} // namespace js
|
||||
|
||||
namespace js {
|
||||
@ -1192,7 +1192,7 @@ js::GCMarker::eagerlyMarkChildren(JSRope* rope)
|
||||
} else {
|
||||
// When both children are ropes, set aside the right one to
|
||||
// scan it later.
|
||||
if (next && !stack.push(reinterpret_cast<uintptr_t>(next)))
|
||||
if (next && !stack.pushTempRope(next))
|
||||
delayMarkingChildren(next);
|
||||
next = &left->asRope();
|
||||
}
|
||||
@ -1201,7 +1201,9 @@ js::GCMarker::eagerlyMarkChildren(JSRope* rope)
|
||||
rope = next;
|
||||
} else if (savedPos != stack.position()) {
|
||||
MOZ_ASSERT(savedPos < stack.position());
|
||||
rope = reinterpret_cast<JSRope*>(stack.pop());
|
||||
uintptr_t ptr = stack.pop();
|
||||
MOZ_ASSERT((ptr & MarkStack::TagMask) == MarkStack::TempRopeTag);
|
||||
rope = reinterpret_cast<JSRope*>(ptr &~ MarkStack::TempRopeTag);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -1646,13 +1648,13 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
||||
|
||||
// Decode
|
||||
uintptr_t addr = stack.pop();
|
||||
uintptr_t tag = addr & StackTagMask;
|
||||
addr &= ~StackTagMask;
|
||||
uintptr_t tag = addr & MarkStack::TagMask;
|
||||
addr &= ~MarkStack::TagMask;
|
||||
|
||||
// Dispatch
|
||||
switch (tag) {
|
||||
case ValueArrayTag: {
|
||||
JS_STATIC_ASSERT(ValueArrayTag == 0);
|
||||
case MarkStack::ValueArrayTag: {
|
||||
JS_STATIC_ASSERT(MarkStack::ValueArrayTag == 0);
|
||||
MOZ_ASSERT(!(addr & CellMask));
|
||||
obj = reinterpret_cast<JSObject*>(addr);
|
||||
uintptr_t addr2 = stack.pop();
|
||||
@ -1664,25 +1666,25 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
||||
goto scan_value_array;
|
||||
}
|
||||
|
||||
case ObjectTag: {
|
||||
case MarkStack::ObjectTag: {
|
||||
obj = reinterpret_cast<JSObject*>(addr);
|
||||
AssertZoneIsMarking(obj);
|
||||
goto scan_obj;
|
||||
}
|
||||
|
||||
case GroupTag: {
|
||||
case MarkStack::GroupTag: {
|
||||
return lazilyMarkChildren(reinterpret_cast<ObjectGroup*>(addr));
|
||||
}
|
||||
|
||||
case JitCodeTag: {
|
||||
case MarkStack::JitCodeTag: {
|
||||
return reinterpret_cast<jit::JitCode*>(addr)->traceChildren(this);
|
||||
}
|
||||
|
||||
case ScriptTag: {
|
||||
case MarkStack::ScriptTag: {
|
||||
return reinterpret_cast<JSScript*>(addr)->traceChildren(this);
|
||||
}
|
||||
|
||||
case SavedValueArrayTag: {
|
||||
case MarkStack::SavedValueArrayTag: {
|
||||
MOZ_ASSERT(!(addr & CellMask));
|
||||
JSObject* obj = reinterpret_cast<JSObject*>(addr);
|
||||
HeapSlot* vp;
|
||||
@ -1819,10 +1821,10 @@ struct SlotArrayLayout
|
||||
void
|
||||
GCMarker::saveValueRanges()
|
||||
{
|
||||
for (uintptr_t* p = stack.tos_; p > stack.stack_; ) {
|
||||
uintptr_t tag = *--p & StackTagMask;
|
||||
if (tag == ValueArrayTag) {
|
||||
*p &= ~StackTagMask;
|
||||
for (uintptr_t* p = stack.top(); p > stack.base(); ) {
|
||||
uintptr_t tag = *--p & MarkStack::TagMask;
|
||||
if (tag == MarkStack::ValueArrayTag) {
|
||||
*p &= ~MarkStack::TagMask;
|
||||
p -= 2;
|
||||
SlotArrayLayout* arr = reinterpret_cast<SlotArrayLayout*>(p);
|
||||
NativeObject* obj = arr->obj;
|
||||
@ -1848,8 +1850,8 @@ GCMarker::saveValueRanges()
|
||||
}
|
||||
arr->kind = HeapSlot::Slot;
|
||||
}
|
||||
p[2] |= SavedValueArrayTag;
|
||||
} else if (tag == SavedValueArrayTag) {
|
||||
p[2] |= MarkStack::SavedValueArrayTag;
|
||||
} else if (tag == MarkStack::SavedValueArrayTag) {
|
||||
p -= 2;
|
||||
}
|
||||
}
|
||||
@ -1904,6 +1906,26 @@ GCMarker::restoreValueArray(JSObject* objArg, void** vpp, void** endp)
|
||||
|
||||
/*** Mark Stack ***********************************************************************************/
|
||||
|
||||
template <typename T>
|
||||
struct MapTypeToMarkStackTag {};
|
||||
|
||||
template <>
|
||||
struct MapTypeToMarkStackTag<JSObject*> { static const auto value = MarkStack::ObjectTag; };
|
||||
template <>
|
||||
struct MapTypeToMarkStackTag<ObjectGroup*> { static const auto value = MarkStack::GroupTag; };
|
||||
template <>
|
||||
struct MapTypeToMarkStackTag<jit::JitCode*> { static const auto value = MarkStack::JitCodeTag; };
|
||||
template <>
|
||||
struct MapTypeToMarkStackTag<JSScript*> { static const auto value = MarkStack::ScriptTag; };
|
||||
|
||||
MarkStack::MarkStack(size_t maxCapacity)
|
||||
: stack_(nullptr),
|
||||
tos_(nullptr),
|
||||
end_(nullptr),
|
||||
baseCapacity_(0),
|
||||
maxCapacity_(maxCapacity)
|
||||
{}
|
||||
|
||||
bool
|
||||
MarkStack::init(JSGCMode gcMode)
|
||||
{
|
||||
@ -1949,6 +1971,51 @@ MarkStack::setMaxCapacity(size_t maxCapacity)
|
||||
reset();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool
|
||||
MarkStack::push(T* ptr)
|
||||
{
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
MOZ_ASSERT(!(addr & TagMask));
|
||||
auto tag = MapTypeToMarkStackTag<T*>::value;
|
||||
return pushTaggedPtr(addr | uintptr_t(tag));
|
||||
}
|
||||
|
||||
inline bool
|
||||
MarkStack::pushTempRope(JSRope* rope)
|
||||
{
|
||||
return pushTaggedPtr(uintptr_t(rope) | TempRopeTag);
|
||||
}
|
||||
|
||||
inline bool
|
||||
MarkStack::pushTaggedPtr(uintptr_t item)
|
||||
{
|
||||
if (tos_ == end_) {
|
||||
if (!enlarge(1))
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(tos_ < end_);
|
||||
*tos_++ = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
MarkStack::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;
|
||||
}
|
||||
MOZ_ASSERT(nextTos <= end_);
|
||||
tos_[0] = item1;
|
||||
tos_[1] = item2;
|
||||
tos_[2] = item3;
|
||||
tos_ = nextTos;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MarkStack::reset()
|
||||
{
|
||||
@ -2089,6 +2156,41 @@ GCMarker::reset()
|
||||
MOZ_ASSERT(!markLaterArenas);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
GCMarker::pushTaggedPtr(T* ptr)
|
||||
{
|
||||
checkZone(ptr);
|
||||
if (!stack.push(ptr))
|
||||
delayMarkingChildren(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
GCMarker::pushValueArray(JSObject* obj, HeapSlot* start, HeapSlot* end)
|
||||
{
|
||||
checkZone(obj);
|
||||
|
||||
MOZ_ASSERT(start <= end);
|
||||
uintptr_t tagged = reinterpret_cast<uintptr_t>(obj) | MarkStack::ValueArrayTag;
|
||||
uintptr_t startAddr = reinterpret_cast<uintptr_t>(start);
|
||||
uintptr_t endAddr = reinterpret_cast<uintptr_t>(end);
|
||||
|
||||
/*
|
||||
* Push in the reverse order so obj will be on top. If we cannot push
|
||||
* the array, we trigger delay marking for the whole object.
|
||||
*/
|
||||
if (!stack.push(endAddr, startAddr, tagged))
|
||||
delayMarkingChildren(obj);
|
||||
}
|
||||
|
||||
void
|
||||
GCMarker::repush(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(gc::TenuredCell::fromPointer(obj)->isMarked(markColor()));
|
||||
pushTaggedPtr(obj);
|
||||
}
|
||||
|
||||
void
|
||||
GCMarker::enterWeakMarkingMode()
|
||||
{
|
||||
|
@ -41,6 +41,8 @@ class JitCode;
|
||||
static const size_t NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY = 4096;
|
||||
static const size_t INCREMENTAL_MARK_STACK_BASE_CAPACITY = 32768;
|
||||
|
||||
namespace gc {
|
||||
|
||||
/*
|
||||
* When the native stack is low, the GC does not call js::TraceChildren to mark
|
||||
* the reachable "children" of the thing. Rather the thing is put aside and
|
||||
@ -55,8 +57,6 @@ static const size_t INCREMENTAL_MARK_STACK_BASE_CAPACITY = 32768;
|
||||
*/
|
||||
class MarkStack
|
||||
{
|
||||
friend class GCMarker;
|
||||
|
||||
ActiveThreadData<uintptr_t*> stack_;
|
||||
ActiveThreadData<uintptr_t*> tos_;
|
||||
ActiveThreadData<uintptr_t*> end_;
|
||||
@ -66,13 +66,28 @@ class MarkStack
|
||||
ActiveThreadData<size_t> maxCapacity_;
|
||||
|
||||
public:
|
||||
explicit MarkStack(size_t maxCapacity)
|
||||
: stack_(nullptr),
|
||||
tos_(nullptr),
|
||||
end_(nullptr),
|
||||
baseCapacity_(0),
|
||||
maxCapacity_(maxCapacity)
|
||||
{}
|
||||
/*
|
||||
* 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 Tag {
|
||||
ValueArrayTag,
|
||||
ObjectTag,
|
||||
GroupTag,
|
||||
SavedValueArrayTag,
|
||||
JitCodeTag,
|
||||
ScriptTag,
|
||||
TempRopeTag,
|
||||
|
||||
LastTag = TempRopeTag
|
||||
};
|
||||
|
||||
static const uintptr_t TagMask = 7;
|
||||
static_assert(TagMask >= uintptr_t(LastTag), "The tag mask must subsume the tags.");
|
||||
static_assert(TagMask <= gc::CellMask, "The tag mask must be embeddable in a Cell*.");
|
||||
|
||||
explicit MarkStack(size_t maxCapacity);
|
||||
|
||||
~MarkStack() {
|
||||
js_free(stack_);
|
||||
@ -94,30 +109,16 @@ class MarkStack
|
||||
size_t maxCapacity() const { return maxCapacity_; }
|
||||
void setMaxCapacity(size_t maxCapacity);
|
||||
|
||||
MOZ_MUST_USE bool push(uintptr_t item) {
|
||||
if (tos_ == end_) {
|
||||
if (!enlarge(1))
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(tos_ < end_);
|
||||
*tos_++ = item;
|
||||
return true;
|
||||
}
|
||||
uintptr_t* base() { return stack_; }
|
||||
uintptr_t* top() { return tos_; }
|
||||
|
||||
MOZ_MUST_USE 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;
|
||||
}
|
||||
MOZ_ASSERT(nextTos <= end_);
|
||||
tos_[0] = item1;
|
||||
tos_[1] = item2;
|
||||
tos_[2] = item3;
|
||||
tos_ = nextTos;
|
||||
return true;
|
||||
}
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool push(T* ptr);
|
||||
MOZ_MUST_USE bool push(uintptr_t item1, uintptr_t item2, uintptr_t item3);
|
||||
|
||||
// GCMarker::eagerlyMarkChildren uses unused marking stack as temporary
|
||||
// storage to hold rope pointers.
|
||||
MOZ_MUST_USE bool pushTempRope(JSRope* ptr);
|
||||
|
||||
bool isEmpty() const {
|
||||
return tos_ == stack_;
|
||||
@ -136,9 +137,10 @@ class MarkStack
|
||||
void setGCMode(JSGCMode gcMode);
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
};
|
||||
|
||||
namespace gc {
|
||||
private:
|
||||
MOZ_MUST_USE bool pushTaggedPtr(uintptr_t item);
|
||||
};
|
||||
|
||||
struct WeakKeyTableHashPolicy {
|
||||
typedef JS::GCCellPtr Lookup;
|
||||
@ -252,34 +254,12 @@ class GCMarker : public JSTracer
|
||||
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,
|
||||
GroupTag,
|
||||
SavedValueArrayTag,
|
||||
JitCodeTag,
|
||||
ScriptTag,
|
||||
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*.");
|
||||
|
||||
// Push an object onto the stack for later tracing and assert that it has
|
||||
// already been marked.
|
||||
void repush(JSObject* obj) {
|
||||
MOZ_ASSERT(gc::TenuredCell::fromPointer(obj)->isMarked(markColor()));
|
||||
pushTaggedPtr(ObjectTag, obj);
|
||||
}
|
||||
inline void repush(JSObject* obj);
|
||||
|
||||
template <typename T> void markAndTraceChildren(T* thing);
|
||||
template <typename T> void markAndPush(StackTag tag, T* thing);
|
||||
template <typename T> void markAndPush(T* thing);
|
||||
template <typename T> void markAndScan(T* thing);
|
||||
template <typename T> void markImplicitEdgesHelper(T oldThing);
|
||||
template <typename T> void markImplicitEdges(T* oldThing);
|
||||
@ -300,29 +280,10 @@ class GCMarker : public JSTracer
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool mark(T* thing);
|
||||
|
||||
void pushTaggedPtr(StackTag tag, void* ptr) {
|
||||
checkZone(ptr);
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
MOZ_ASSERT(!(addr & StackTagMask));
|
||||
if (!stack.push(addr | uintptr_t(tag)))
|
||||
delayMarkingChildren(ptr);
|
||||
}
|
||||
template <typename T>
|
||||
inline void pushTaggedPtr(T* ptr);
|
||||
|
||||
void pushValueArray(JSObject* obj, HeapSlot* start, HeapSlot* end) {
|
||||
checkZone(obj);
|
||||
|
||||
MOZ_ASSERT(start <= end);
|
||||
uintptr_t tagged = reinterpret_cast<uintptr_t>(obj) | GCMarker::ValueArrayTag;
|
||||
uintptr_t startAddr = reinterpret_cast<uintptr_t>(start);
|
||||
uintptr_t endAddr = reinterpret_cast<uintptr_t>(end);
|
||||
|
||||
/*
|
||||
* Push in the reverse order so obj will be on top. If we cannot push
|
||||
* the array, we trigger delay marking for the whole object.
|
||||
*/
|
||||
if (!stack.push(endAddr, startAddr, tagged))
|
||||
delayMarkingChildren(obj);
|
||||
}
|
||||
inline void pushValueArray(JSObject* obj, HeapSlot* start, HeapSlot* end);
|
||||
|
||||
bool isMarkStackEmpty() {
|
||||
return stack.isEmpty();
|
||||
@ -333,7 +294,7 @@ class GCMarker : public JSTracer
|
||||
inline void processMarkStackTop(SliceBudget& budget);
|
||||
|
||||
/* The mark stack. Pointers in this stack are "gray" in the GC sense. */
|
||||
MarkStack stack;
|
||||
gc::MarkStack stack;
|
||||
|
||||
/* The color is only applied to objects and functions. */
|
||||
ActiveThreadData<uint32_t> color;
|
||||
|
Loading…
Reference in New Issue
Block a user