зеркало из https://github.com/mozilla/gecko-dev.git
Bug 666058 - Don't share chunks for system compartments. r=gal,igor.
This commit is contained in:
Родитель
159859c23d
Коммит
2930b1da1e
|
@ -308,6 +308,9 @@ nsSystemPrincipal::nsSystemPrincipal()
|
|||
{
|
||||
}
|
||||
|
||||
// Don't rename the system principal!
|
||||
// The JS engine (NewCompartment) relies on this name.
|
||||
// XXX: bug 669123 will fix this hack.
|
||||
#define SYSTEM_PRINCIPAL_SPEC "[System Principal]"
|
||||
|
||||
nsresult
|
||||
|
@ -320,7 +323,7 @@ nsSystemPrincipal::Init()
|
|||
NS_WARNING("Out of memory initializing system principal");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
return mJSPrincipals.Init(this, str);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,26 +10,38 @@
|
|||
#include "jsgcchunk.h"
|
||||
#include "jscntxt.h"
|
||||
|
||||
/* We allow to allocate only single chunk. */
|
||||
/* We allow to allocate 2 (system/user) chunks. */
|
||||
|
||||
/* XXX: using pool[0] and pool[1] is a hack; bug 669123 will fix this. */
|
||||
|
||||
class CustomGCChunkAllocator: public js::GCChunkAllocator {
|
||||
public:
|
||||
CustomGCChunkAllocator() : pool(NULL) {}
|
||||
void *pool;
|
||||
CustomGCChunkAllocator() { pool[0] = NULL; pool[1] = NULL; }
|
||||
void *pool[2];
|
||||
|
||||
private:
|
||||
|
||||
virtual void *doAlloc() {
|
||||
if (!pool)
|
||||
if (!pool[0] && !pool[1])
|
||||
return NULL;
|
||||
void *chunk = pool;
|
||||
pool = NULL;
|
||||
void *chunk = NULL;
|
||||
if (pool[0]) {
|
||||
chunk = pool[0];
|
||||
pool[0] = NULL;
|
||||
} else {
|
||||
chunk = pool[1];
|
||||
pool[1] = NULL;
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
virtual void doFree(void *chunk) {
|
||||
JS_ASSERT(!pool);
|
||||
pool = chunk;
|
||||
JS_ASSERT(!pool[0] || !pool[1]);
|
||||
if (!pool[0]) {
|
||||
pool[0] = chunk;
|
||||
} else {
|
||||
pool[1] = chunk;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -69,7 +81,8 @@ BEGIN_TEST(testGCChunkAlloc)
|
|||
CHECK(!ok);
|
||||
CHECK(!JS_IsExceptionPending(cx));
|
||||
CHECK(errorCount == 1);
|
||||
CHECK(!customGCChunkAllocator.pool);
|
||||
CHECK(!customGCChunkAllocator.pool[0]);
|
||||
CHECK(!customGCChunkAllocator.pool[1]);
|
||||
JS_GC(cx);
|
||||
JS_ToggleOptions(cx, JSOPTION_JIT);
|
||||
EVAL("(function() {"
|
||||
|
@ -92,8 +105,10 @@ virtual JSRuntime * createRuntime() {
|
|||
if (!rt)
|
||||
return NULL;
|
||||
|
||||
customGCChunkAllocator.pool = js::AllocGCChunk();
|
||||
JS_ASSERT(customGCChunkAllocator.pool);
|
||||
customGCChunkAllocator.pool[0] = js::AllocGCChunk();
|
||||
customGCChunkAllocator.pool[1] = js::AllocGCChunk();
|
||||
JS_ASSERT(customGCChunkAllocator.pool[0]);
|
||||
JS_ASSERT(customGCChunkAllocator.pool[1]);
|
||||
|
||||
rt->setCustomGCChunkAllocator(&customGCChunkAllocator);
|
||||
return rt;
|
||||
|
@ -103,9 +118,12 @@ virtual void destroyRuntime() {
|
|||
JS_DestroyRuntime(rt);
|
||||
|
||||
/* We should get the initial chunk back at this point. */
|
||||
JS_ASSERT(customGCChunkAllocator.pool);
|
||||
js::FreeGCChunk(customGCChunkAllocator.pool);
|
||||
customGCChunkAllocator.pool = NULL;
|
||||
JS_ASSERT(customGCChunkAllocator.pool[0]);
|
||||
JS_ASSERT(customGCChunkAllocator.pool[1]);
|
||||
js::FreeGCChunk(customGCChunkAllocator.pool[0]);
|
||||
js::FreeGCChunk(customGCChunkAllocator.pool[1]);
|
||||
customGCChunkAllocator.pool[0] = NULL;
|
||||
customGCChunkAllocator.pool[1] = NULL;
|
||||
}
|
||||
|
||||
END_TEST(testGCChunkAlloc)
|
||||
|
|
|
@ -666,6 +666,7 @@ JSRuntime::init(uint32 maxbytes)
|
|||
return false;
|
||||
}
|
||||
|
||||
atomsCompartment->systemGCChunks = true;
|
||||
atomsCompartment->setGCLastBytes(8192, GC_NORMAL);
|
||||
|
||||
if (!js_InitAtomState(this))
|
||||
|
|
|
@ -376,6 +376,7 @@ struct JSRuntime {
|
|||
|
||||
/* Garbage collector state, used by jsgc.c. */
|
||||
js::GCChunkSet gcChunkSet;
|
||||
js::GCChunkSet gcSystemChunkSet;
|
||||
|
||||
js::RootedValueMap gcRootsHash;
|
||||
js::GCLocks gcLocksHash;
|
||||
|
|
|
@ -378,6 +378,7 @@ struct JS_FRIEND_API(JSCompartment) {
|
|||
size_t gcLastBytes;
|
||||
|
||||
bool hold;
|
||||
bool systemGCChunks;
|
||||
|
||||
#ifdef JS_TRACER
|
||||
private:
|
||||
|
|
|
@ -462,12 +462,15 @@ PickChunk(JSContext *cx)
|
|||
if (chunk && chunk->hasAvailableArenas())
|
||||
return chunk;
|
||||
|
||||
JSRuntime *rt = cx->runtime;
|
||||
bool systemGCChunks = cx->compartment->systemGCChunks;
|
||||
|
||||
/*
|
||||
* The chunk used for the last allocation is full, search all chunks for
|
||||
* free arenas.
|
||||
*/
|
||||
JSRuntime *rt = cx->runtime;
|
||||
for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
|
||||
GCChunkSet::Range r(systemGCChunks ? rt->gcSystemChunkSet.all() : rt->gcChunkSet.all());
|
||||
for (; !r.empty(); r.popFront()) {
|
||||
chunk = r.front();
|
||||
if (chunk->hasAvailableArenas()) {
|
||||
cx->compartment->chunk = chunk;
|
||||
|
@ -476,18 +479,39 @@ PickChunk(JSContext *cx)
|
|||
}
|
||||
|
||||
chunk = AllocateGCChunk(rt);
|
||||
if (!chunk)
|
||||
return NULL;
|
||||
if (!chunk) {
|
||||
/* Our last chance is to find an empty chunk in the other chunk set. */
|
||||
GCChunkSet::Enum e(systemGCChunks ? rt->gcChunkSet : rt->gcSystemChunkSet);
|
||||
for (; !e.empty(); e.popFront()) {
|
||||
if (e.front()->info.numFree == ArenasPerChunk) {
|
||||
chunk = e.front();
|
||||
e.removeFront();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!chunk)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME bug 583732 - chunk is newly allocated and cannot be present in
|
||||
* the table so using ordinary lookupForAdd is suboptimal here.
|
||||
*/
|
||||
GCChunkSet::AddPtr p = rt->gcChunkSet.lookupForAdd(chunk);
|
||||
GCChunkSet::AddPtr p = systemGCChunks ?
|
||||
rt->gcSystemChunkSet.lookupForAdd(chunk) :
|
||||
rt->gcChunkSet.lookupForAdd(chunk);
|
||||
JS_ASSERT(!p);
|
||||
if (!rt->gcChunkSet.add(p, chunk)) {
|
||||
ReleaseGCChunk(rt, chunk);
|
||||
return NULL;
|
||||
if (systemGCChunks) {
|
||||
if (!rt->gcSystemChunkSet.add(p, chunk)) {
|
||||
ReleaseGCChunk(rt, chunk);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (!rt->gcChunkSet.add(p, chunk)) {
|
||||
ReleaseGCChunk(rt, chunk);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
chunk->init(rt);
|
||||
|
@ -517,6 +541,18 @@ ExpireGCChunks(JSRuntime *rt, JSGCInvocationKind gckind)
|
|||
rt->gcChunksWaitingToExpire++;
|
||||
}
|
||||
}
|
||||
for (GCChunkSet::Enum e(rt->gcSystemChunkSet); !e.empty(); e.popFront()) {
|
||||
Chunk *chunk = e.front();
|
||||
JS_ASSERT(chunk->info.runtime == rt);
|
||||
if (chunk->unused()) {
|
||||
if (gckind == GC_SHRINK || chunk->info.age++ > MaxAge) {
|
||||
e.removeFront();
|
||||
ReleaseGCChunk(rt, chunk);
|
||||
continue;
|
||||
}
|
||||
rt->gcChunksWaitingToExpire++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
|
@ -561,6 +597,9 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
|
|||
if (!rt->gcChunkSet.init(16))
|
||||
return false;
|
||||
|
||||
if (!rt->gcSystemChunkSet.init(16))
|
||||
return false;
|
||||
|
||||
if (!rt->gcRootsHash.init(256))
|
||||
return false;
|
||||
|
||||
|
@ -700,7 +739,8 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w)
|
|||
|
||||
Chunk *chunk = Chunk::fromAddress(addr);
|
||||
|
||||
if (!trc->context->runtime->gcChunkSet.has(chunk))
|
||||
if (!trc->context->runtime->gcChunkSet.has(chunk) &&
|
||||
!trc->context->runtime->gcSystemChunkSet.has(chunk))
|
||||
return CGCT_NOTCHUNK;
|
||||
|
||||
/*
|
||||
|
@ -909,7 +949,10 @@ js_FinishGC(JSRuntime *rt)
|
|||
|
||||
for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
|
||||
ReleaseGCChunk(rt, r.front());
|
||||
for (GCChunkSet::Range r(rt->gcSystemChunkSet.all()); !r.empty(); r.popFront())
|
||||
ReleaseGCChunk(rt, r.front());
|
||||
rt->gcChunkSet.clear();
|
||||
rt->gcSystemChunkSet.clear();
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
rt->gcHelperThread.finish(rt);
|
||||
|
@ -2230,7 +2273,10 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
|||
rt->gcMarkingTracer = &gcmarker;
|
||||
|
||||
for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
|
||||
r.front()->bitmap.clear();
|
||||
r.front()->bitmap.clear();
|
||||
|
||||
for (GCChunkSet::Range r(rt->gcSystemChunkSet.all()); !r.empty(); r.popFront())
|
||||
r.front()->bitmap.clear();
|
||||
|
||||
if (comp) {
|
||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
||||
|
@ -2790,6 +2836,7 @@ NewCompartment(JSContext *cx, JSPrincipals *principals)
|
|||
JSRuntime *rt = cx->runtime;
|
||||
JSCompartment *compartment = cx->new_<JSCompartment>(rt);
|
||||
if (compartment && compartment->init()) {
|
||||
compartment->systemGCChunks = principals && !strcmp(principals->codebase, "[System Principal]");
|
||||
if (principals) {
|
||||
compartment->principals = principals;
|
||||
JSPRINCIPALS_HOLD(cx, principals);
|
||||
|
|
Загрузка…
Ссылка в новой задаче