Bug 851627 - Make LifoAlloc::release run in O(1) (r=sstangl)

This commit is contained in:
Luke Wagner 2013-04-25 12:28:29 -07:00
parent a5cff84c9d
commit 971d6ebe6e
7 changed files with 44 additions and 53 deletions

View File

@ -307,31 +307,30 @@ class LifoAlloc
return static_cast<T *>(alloc(sizeof(T) * count));
}
void *mark() {
markCount++;
class Mark {
BumpChunk *chunk;
void *markInChunk;
friend class LifoAlloc;
Mark(BumpChunk *chunk, void *markInChunk) : chunk(chunk), markInChunk(markInChunk) {}
public:
Mark() : chunk(NULL), markInChunk(NULL) {}
};
return latest ? latest->mark() : NULL;
Mark mark() {
markCount++;
return latest ? Mark(latest, latest->mark()) : Mark();
}
void release(void *mark) {
void release(Mark mark) {
markCount--;
if (!mark) {
if (!mark.chunk) {
latest = first;
if (latest)
latest->resetBump();
return;
} else {
latest = mark.chunk;
latest->release(mark.markInChunk);
}
// Find the chunk that contains |mark|, and make sure we don't pass
// |latest| along the way -- we should be making the chain of active
// chunks shorter, not longer!
BumpChunk *container;
for (container = first; !container->contains(mark); container = container->next())
JS_ASSERT(container != latest);
latest = container;
latest->release(mark);
}
void releaseAll() {
@ -381,18 +380,19 @@ class LifoAlloc
class LifoAllocScope
{
LifoAlloc *lifoAlloc;
void *mark;
bool shouldRelease;
LifoAlloc *lifoAlloc;
LifoAlloc::Mark mark;
bool shouldRelease;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
public:
explicit LifoAllocScope(LifoAlloc *lifoAlloc
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: lifoAlloc(lifoAlloc), shouldRelease(true)
: lifoAlloc(lifoAlloc),
mark(lifoAlloc->mark()),
shouldRelease(true)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
mark = lifoAlloc->mark();
}
~LifoAllocScope() {

View File

@ -384,7 +384,6 @@ Parser<ParseHandler>::Parser(JSContext *cx, const CompileOptions &options,
: AutoGCRooter(cx, PARSER),
context(cx),
tokenStream(cx, options, chars, length, thisForCtor()),
tempPoolMark(NULL),
traceListHead(NULL),
pc(NULL),
sct(NULL),

View File

@ -263,7 +263,7 @@ struct Parser : private AutoGCRooter, public StrictModeGetter
{
JSContext *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
TokenStream tokenStream;
void *tempPoolMark; /* initial JSContext.tempLifoAlloc mark */
LifoAlloc::Mark tempPoolMark;
/* list of parsed objects for GC tracing */
ObjectBox *traceListHead;

View File

@ -20,34 +20,27 @@ namespace ion {
class TempAllocator
{
LifoAlloc *lifoAlloc_;
void *mark_;
LifoAllocScope lifoScope_;
// Linked list of GCThings rooted by this allocator.
CompilerRootNode *rootList_;
public:
TempAllocator(LifoAlloc *lifoAlloc)
: lifoAlloc_(lifoAlloc),
mark_(lifoAlloc->mark()),
: lifoScope_(lifoAlloc),
rootList_(NULL)
{ }
~TempAllocator()
{
lifoAlloc_->release(mark_);
}
void *allocateInfallible(size_t bytes)
{
void *p = lifoAlloc_->allocInfallible(bytes);
void *p = lifoScope_.alloc().allocInfallible(bytes);
JS_ASSERT(p);
return p;
}
void *allocate(size_t bytes)
{
void *p = lifoAlloc_->alloc(bytes);
void *p = lifoScope_.alloc().alloc(bytes);
if (!ensureBallast())
return NULL;
return p;
@ -55,7 +48,7 @@ class TempAllocator
LifoAlloc *lifoAlloc()
{
return lifoAlloc_;
return &lifoScope_.alloc();
}
CompilerRootNode *&rootList()
@ -66,7 +59,7 @@ class TempAllocator
bool ensureBallast() {
// Most infallible Ion allocations are small, so we use a ballast of
// ~16K for now.
return lifoAlloc_->ensureUnusedApproximate(16 * 1024);
return lifoScope_.alloc().ensureUnusedApproximate(16 * 1024);
}
};

View File

@ -475,22 +475,27 @@ JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun)
}
extern JS_PUBLIC_API(uintptr_t *)
JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp)
JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **memp)
{
RootedScript script(cx, fun->nonLazyScript());
BindingVector bindings(cx);
if (!FillBindingVector(script, &bindings))
return NULL;
/* Munge data into the API this method implements. Avert your eyes! */
*markp = cx->tempLifoAlloc().mark();
LifoAlloc &lifo = cx->tempLifoAlloc();
uintptr_t *names = cx->tempLifoAlloc().newArray<uintptr_t>(bindings.length());
if (!names) {
// Store the LifoAlloc::Mark right before the allocation.
LifoAlloc::Mark mark = lifo.mark();
void *mem = lifo.alloc(sizeof(LifoAlloc::Mark) + bindings.length() * sizeof(uintptr_t));
if (!mem) {
js_ReportOutOfMemory(cx);
return NULL;
}
*memp = mem;
*reinterpret_cast<LifoAlloc::Mark*>(mem) = mark;
// Munge data into the API this method implements. Avert your eyes!
uintptr_t *names = reinterpret_cast<uintptr_t*>((char*)mem + sizeof(LifoAlloc::Mark));
for (size_t i = 0; i < bindings.length(); i++)
names[i] = reinterpret_cast<uintptr_t>(bindings[i].name());
@ -510,9 +515,9 @@ JS_AtomKey(JSAtom *atom)
}
extern JS_PUBLIC_API(void)
JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark)
JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mem)
{
cx->tempLifoAlloc().release(mark);
cx->tempLifoAlloc().release(*reinterpret_cast<LifoAlloc::Mark*>(mem));
}
JS_PUBLIC_API(JSScript *)

View File

@ -98,20 +98,14 @@ class MatchPairs
/* MatchPairs allocated into temporary storage, removed when out of scope. */
class ScopedMatchPairs : public MatchPairs
{
LifoAlloc *lifoAlloc_;
void *mark_; /* Saved original position in bump allocator. */
LifoAllocScope lifoScope_;
public:
/* Constructs an implicit LifoAllocScope. */
ScopedMatchPairs(LifoAlloc *lifoAlloc)
: lifoAlloc_(lifoAlloc),
mark_(lifoAlloc->mark())
: lifoScope_(lifoAlloc)
{ }
~ScopedMatchPairs() {
lifoAlloc_->release(mark_);
}
const MatchPair &operator[](size_t i) const { return pair(i); }
protected:

View File

@ -169,7 +169,7 @@ ScopedMatchPairs::allocOrExpandArray(size_t pairCount)
}
JS_ASSERT(!pairs_);
pairs_ = (MatchPair *)lifoAlloc_->alloc(sizeof(MatchPair) * pairCount);
pairs_ = (MatchPair *)lifoScope_.alloc().alloc(sizeof(MatchPair) * pairCount);
if (!pairs_)
return false;