Bug 921224 (part 1) - Don't use ballast in MarkStack. r=wmccloskey.

--HG--
extra : rebase_source : f847b35b7d5879816f1cde112c1f3cbf0fe58414
This commit is contained in:
Nicholas Nethercote 2013-11-14 18:43:11 -08:00
parent 52b6012860
commit 7a01468dca
4 changed files with 81 additions and 89 deletions

View File

@ -1270,7 +1270,7 @@ struct SlotArrayLayout
void
GCMarker::saveValueRanges()
{
for (uintptr_t *p = stack.tos; p > stack.stack; ) {
for (uintptr_t *p = stack.tos_; p > stack.stack_; ) {
uintptr_t tag = *--p & StackTagMask;
if (tag == ValueArrayTag) {
*p &= ~StackTagMask;

View File

@ -2094,7 +2094,7 @@ JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
case JSGC_SLICE_TIME_BUDGET:
return uint32_t(rt->gcSliceBudget > 0 ? rt->gcSliceBudget / PRMJ_USEC_PER_MSEC : 0);
case JSGC_MARK_STACK_LIMIT:
return rt->gcMarker.sizeLimit();
return rt->gcMarker.maxCapacity();
case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
return rt->gcHighFrequencyTimeThreshold;
case JSGC_HIGH_FREQUENCY_LOW_LIMIT:

View File

@ -1937,7 +1937,7 @@ void
js::SetMarkStackLimit(JSRuntime *rt, size_t limit)
{
JS_ASSERT(!rt->isHeapBusy());
rt->gcMarker.setSizeLimit(limit);
rt->gcMarker.setMaxCapacity(limit);
}
void

View File

@ -910,138 +910,130 @@ typedef HashSet<js::gc::Chunk *, GCChunkHasher, SystemAllocPolicy> GCChunkSet;
template<class T>
struct MarkStack {
T *stack;
T *tos;
T *limit;
T *stack_;
T *tos_;
T *end_;
T *ballast;
T *ballastLimit;
// The capacity we start with and reset() to.
size_t baseCapacity_;
size_t maxCapacity_;
size_t sizeLimit;
MarkStack(size_t sizeLimit)
: stack(nullptr),
tos(nullptr),
limit(nullptr),
ballast(nullptr),
ballastLimit(nullptr),
sizeLimit(sizeLimit) { }
MarkStack(size_t maxCapacity)
: stack_(nullptr),
tos_(nullptr),
end_(nullptr),
baseCapacity_(0),
maxCapacity_(maxCapacity)
{}
~MarkStack() {
if (stack != ballast)
js_free(stack);
js_free(ballast);
js_free(stack_);
}
bool init(size_t ballastcap) {
JS_ASSERT(!stack);
size_t capacity() { return end_ - stack_; }
if (ballastcap == 0)
return true;
ptrdiff_t position() const { return tos_ - stack_; }
ballast = js_pod_malloc<T>(ballastcap);
if (!ballast)
void setStack(T *stack, size_t tosIndex, size_t capacity) {
stack_ = stack;
tos_ = stack + tosIndex;
end_ = stack + capacity;
}
bool init(size_t baseCapacity) {
baseCapacity_ = baseCapacity;
if (baseCapacity_ > maxCapacity_)
baseCapacity_ = maxCapacity_;
JS_ASSERT(!stack_);
T *newStack = js_pod_malloc<T>(baseCapacity_);
if (!newStack)
return false;
ballastLimit = ballast + ballastcap;
initFromBallast();
setStack(newStack, 0, baseCapacity_);
return true;
}
void initFromBallast() {
stack = ballast;
limit = ballastLimit;
if (size_t(limit - stack) > sizeLimit)
limit = stack + sizeLimit;
tos = stack;
}
void setSizeLimit(size_t size) {
void setMaxCapacity(size_t maxCapacity) {
JS_ASSERT(isEmpty());
maxCapacity_ = maxCapacity;
if (baseCapacity_ > maxCapacity_)
baseCapacity_ = maxCapacity_;
sizeLimit = size;
reset();
}
bool push(T item) {
if (tos == limit) {
if (tos_ == end_) {
if (!enlarge())
return false;
}
JS_ASSERT(tos < limit);
*tos++ = item;
JS_ASSERT(tos_ < end_);
*tos_++ = item;
return true;
}
bool push(T item1, T item2, T item3) {
T *nextTos = tos + 3;
if (nextTos > limit) {
T *nextTos = tos_ + 3;
if (nextTos > end_) {
if (!enlarge())
return false;
nextTos = tos + 3;
nextTos = tos_ + 3;
}
JS_ASSERT(nextTos <= limit);
tos[0] = item1;
tos[1] = item2;
tos[2] = item3;
tos = nextTos;
JS_ASSERT(nextTos <= end_);
tos_[0] = item1;
tos_[1] = item2;
tos_[2] = item3;
tos_ = nextTos;
return true;
}
bool isEmpty() const {
return tos == stack;
return tos_ == stack_;
}
T pop() {
JS_ASSERT(!isEmpty());
return *--tos;
}
ptrdiff_t position() const {
return tos - stack;
return *--tos_;
}
void reset() {
if (stack != ballast)
js_free(stack);
initFromBallast();
JS_ASSERT(stack == ballast);
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_);
}
bool enlarge() {
size_t tosIndex = tos - stack;
size_t cap = limit - stack;
if (cap == sizeLimit)
if (capacity() == maxCapacity_)
return false;
size_t newcap = cap * 2;
if (newcap == 0)
newcap = 32;
if (newcap > sizeLimit)
newcap = sizeLimit;
T *newStack;
if (stack == ballast) {
newStack = js_pod_malloc<T>(newcap);
if (!newStack)
return false;
for (T *src = stack, *dst = newStack; src < tos; )
*dst++ = *src++;
} else {
newStack = (T *)js_realloc(stack, sizeof(T) * newcap);
if (!newStack)
return false;
}
stack = newStack;
tos = stack + tosIndex;
limit = newStack + newcap;
size_t newCapacity = capacity() * 2;
if (newCapacity > maxCapacity_)
newCapacity = maxCapacity_;
size_t tosIndex = position();
T *newStack = (T *)js_realloc(stack_, sizeof(T) * newCapacity);
if (!newStack)
return false;
setStack(newStack, tosIndex, newCapacity);
return true;
}
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
size_t n = 0;
if (stack != ballast)
n += mallocSizeOf(stack);
n += mallocSizeOf(ballast);
return n;
return mallocSizeOf(stack_);
}
};
@ -1129,8 +1121,8 @@ struct GCMarker : public JSTracer {
explicit GCMarker(JSRuntime *rt);
bool init();
void setSizeLimit(size_t size) { stack.setSizeLimit(size); }
size_t sizeLimit() const { return stack.sizeLimit; }
void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
size_t maxCapacity() const { return stack.maxCapacity_; }
void start();
void stop();