bug 684569 - remove support for custom chunk allocation. r=nnethercote

--HG--
rename : js/src/jsapi-tests/testGCChunkAlloc.cpp => js/src/jsapi-tests/testGCOutOfMemory.cpp
This commit is contained in:
Igor Bukanov 2011-07-31 20:50:42 +02:00
Родитель 4afcf12af5
Коммит aaa99c61c5
9 изменённых файлов: 76 добавлений и 218 удалений

Просмотреть файл

@ -65,7 +65,7 @@ CPPSRCS = \
testExternalStrings.cpp \
testFuncCallback.cpp \
testFunctionProperties.cpp \
testGCChunkAlloc.cpp \
testGCOutOfMemory.cpp \
testGetPropertyDefault.cpp \
testIndexToString.cpp \
testIntString.cpp \

Просмотреть файл

@ -1,131 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor: Igor Bukanov
*/
#include "tests.h"
#include "jsgcchunk.h"
#include "jscntxt.h"
/* We allow to allocate 2 (system/user) chunks. */
static const int SYSTEM = 0;
static const int USER = 1;
static const int N_POOLS = 2;
class CustomGCChunkAllocator: public js::GCChunkAllocator {
public:
CustomGCChunkAllocator() { pool[SYSTEM] = NULL; pool[USER] = NULL; }
void *pool[N_POOLS];
private:
virtual void *doAlloc() {
if (!pool[SYSTEM] && !pool[USER])
return NULL;
void *chunk = NULL;
if (pool[SYSTEM]) {
chunk = pool[SYSTEM];
pool[SYSTEM] = NULL;
} else {
chunk = pool[USER];
pool[USER] = NULL;
}
return chunk;
}
virtual void doFree(void *chunk) {
JS_ASSERT(!pool[SYSTEM] || !pool[USER]);
if (!pool[SYSTEM]) {
pool[SYSTEM] = chunk;
} else {
pool[USER] = chunk;
}
}
};
static CustomGCChunkAllocator customGCChunkAllocator;
static unsigned errorCount = 0;
static void
ErrorCounter(JSContext *cx, const char *message, JSErrorReport *report)
{
++errorCount;
}
BEGIN_TEST(testGCChunkAlloc)
{
JS_SetErrorReporter(cx, ErrorCounter);
jsvalRoot root(cx);
/*
* We loop until out-of-memory happens during the chunk allocation. But
* we have to disable the jit since it cannot tolerate OOM during the
* chunk allocation.
*/
JS_ToggleOptions(cx, JSOPTION_JIT);
static const char source[] =
"var max = 0; (function() {"
" var array = [];"
" for (; ; ++max)"
" array.push({});"
"})();";
JSBool ok = JS_EvaluateScript(cx, global, source, strlen(source), "", 1,
root.addr());
/* Check that we get OOM. */
CHECK(!ok);
CHECK(!JS_IsExceptionPending(cx));
CHECK_EQUAL(errorCount, 1);
CHECK(!customGCChunkAllocator.pool[SYSTEM]);
CHECK(!customGCChunkAllocator.pool[USER]);
JS_GC(cx);
JS_ToggleOptions(cx, JSOPTION_JIT);
EVAL("(function() {"
" var array = [];"
" for (var i = max >> 1; i != 0;) {"
" --i;"
" array.push({});"
" }"
"})();", root.addr());
CHECK_EQUAL(errorCount, 1);
return true;
}
virtual JSRuntime * createRuntime() {
/*
* To test failure of chunk allocation allow to use GC twice the memory
* the single chunk contains.
*/
JSRuntime *rt = JS_NewRuntime(2 * js::GC_CHUNK_SIZE);
if (!rt)
return NULL;
customGCChunkAllocator.pool[SYSTEM] = js::AllocGCChunk();
customGCChunkAllocator.pool[USER] = js::AllocGCChunk();
JS_ASSERT(customGCChunkAllocator.pool[SYSTEM]);
JS_ASSERT(customGCChunkAllocator.pool[USER]);
rt->setCustomGCChunkAllocator(&customGCChunkAllocator);
return rt;
}
virtual void destroyRuntime() {
JS_DestroyRuntime(rt);
/* We should get the initial chunk back at this point. */
JS_ASSERT(customGCChunkAllocator.pool[SYSTEM]);
JS_ASSERT(customGCChunkAllocator.pool[USER]);
js::FreeGCChunk(customGCChunkAllocator.pool[SYSTEM]);
js::FreeGCChunk(customGCChunkAllocator.pool[USER]);
customGCChunkAllocator.pool[SYSTEM] = NULL;
customGCChunkAllocator.pool[USER] = NULL;
}
END_TEST(testGCChunkAlloc)

Просмотреть файл

@ -0,0 +1,68 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor: Igor Bukanov
*/
#include "tests.h"
#include "jsgcchunk.h"
#include "jscntxt.h"
static unsigned errorCount = 0;
static void
ErrorCounter(JSContext *cx, const char *message, JSErrorReport *report)
{
++errorCount;
}
BEGIN_TEST(testGCOutOfMemory)
{
JS_SetErrorReporter(cx, ErrorCounter);
jsvalRoot root(cx);
/*
* We loop until we get out-of-memory. We have to disable the jit since it
* ignores the runtime allocation limits during execution.
*/
JS_ToggleOptions(cx, JSOPTION_JIT);
static const char source[] =
"var max = 0; (function() {"
" var array = [];"
" for (; ; ++max)"
" array.push({});"
" array = []; array.push(0);"
"})();";
JSBool ok = JS_EvaluateScript(cx, global, source, strlen(source), "", 1,
root.addr());
/* Check that we get OOM. */
CHECK(!ok);
CHECK(!JS_IsExceptionPending(cx));
CHECK_EQUAL(errorCount, 1);
JS_GC(cx);
JS_ToggleOptions(cx, JSOPTION_JIT);
EVAL("(function() {"
" var array = [];"
" for (var i = max >> 2; i != 0;) {"
" --i;"
" array.push({});"
" }"
"})();", root.addr());
CHECK_EQUAL(errorCount, 1);
return true;
}
virtual JSRuntime * createRuntime() {
return JS_NewRuntime(256 * 1024);
}
virtual void destroyRuntime() {
JS_DestroyRuntime(rt);
}
END_TEST(testGCOutOfMemory)

Просмотреть файл

@ -638,8 +638,7 @@ JS_IsBuiltinFunctionConstructor(JSFunction *fun)
static JSBool js_NewRuntimeWasCalled = JS_FALSE;
JSRuntime::JSRuntime()
: gcChunkAllocator(&defaultGCChunkAllocator),
trustedPrincipals_(NULL)
: trustedPrincipals_(NULL)
{
/* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
JS_INIT_CLIST(&contextList);

Просмотреть файл

@ -512,14 +512,6 @@ struct JSRuntime {
volatile ptrdiff_t gcMallocBytes;
public:
js::GCChunkAllocator *gcChunkAllocator;
void setCustomGCChunkAllocator(js::GCChunkAllocator *allocator) {
JS_ASSERT(allocator);
JS_ASSERT(state == JSRTS_DOWN);
gcChunkAllocator = allocator;
}
/*
* The trace operation and its data argument to trace embedding-specific
* GC roots.

Просмотреть файл

@ -534,7 +534,7 @@ Chunk::releaseArena(ArenaHeader *aheader)
inline Chunk *
AllocateGCChunk(JSRuntime *rt)
{
Chunk *p = (Chunk *)rt->gcChunkAllocator->alloc();
Chunk *p = static_cast<Chunk *>(AllocGCChunk());
#ifdef MOZ_GCTIMER
if (p)
JS_ATOMIC_INCREMENT(&newChunkCount);
@ -549,7 +549,7 @@ ReleaseGCChunk(JSRuntime *rt, Chunk *p)
#ifdef MOZ_GCTIMER
JS_ATOMIC_INCREMENT(&destroyChunkCount);
#endif
rt->gcChunkAllocator->free_(p);
FreeGCChunk(p);
}
/* The caller must hold the GC lock. */

Просмотреть файл

@ -272,8 +272,6 @@ UnmapPages(void *addr, size_t size)
namespace js {
GCChunkAllocator defaultGCChunkAllocator;
inline void *
FindChunkStart(void *p)
{
@ -282,7 +280,7 @@ FindChunkStart(void *p)
return reinterpret_cast<void *>(addr);
}
JS_FRIEND_API(void *)
void *
AllocGCChunk()
{
void *p;
@ -329,7 +327,7 @@ AllocGCChunk()
return p;
}
JS_FRIEND_API(void)
void
FreeGCChunk(void *p)
{
JS_ASSERT(p);

Просмотреть файл

@ -49,44 +49,12 @@ const size_t GC_CHUNK_SHIFT = 20;
const size_t GC_CHUNK_SIZE = size_t(1) << GC_CHUNK_SHIFT;
const size_t GC_CHUNK_MASK = GC_CHUNK_SIZE - 1;
JS_FRIEND_API(void *)
void *
AllocGCChunk();
JS_FRIEND_API(void)
void
FreeGCChunk(void *p);
class GCChunkAllocator {
public:
GCChunkAllocator() {}
void *alloc() {
void *chunk = doAlloc();
JS_ASSERT(!(reinterpret_cast<jsuword>(chunk) & GC_CHUNK_MASK));
return chunk;
}
void free_(void *chunk) {
JS_ASSERT(chunk);
JS_ASSERT(!(reinterpret_cast<jsuword>(chunk) & GC_CHUNK_MASK));
doFree(chunk);
}
private:
virtual void *doAlloc() {
return AllocGCChunk();
}
virtual void doFree(void *chunk) {
FreeGCChunk(chunk);
}
/* No copy or assignment semantics. */
GCChunkAllocator(const GCChunkAllocator &);
void operator=(const GCChunkAllocator &);
};
extern GCChunkAllocator defaultGCChunkAllocator;
}
#endif /* jsgchunk_h__ */

Просмотреть файл

@ -1445,41 +1445,7 @@ MakeMemoryReporterPath(const nsACString &pathPrefix,
} // anonymous namespace
class XPConnectGCChunkAllocator
: public js::GCChunkAllocator
{
public:
XPConnectGCChunkAllocator() {}
private:
virtual void *doAlloc() {
void *chunk;
#ifdef MOZ_MEMORY
// posix_memalign returns zero on success, nonzero on failure.
if (posix_memalign(&chunk, js::GC_CHUNK_SIZE, js::GC_CHUNK_SIZE))
chunk = 0;
#else
chunk = js::AllocGCChunk();
#endif
return chunk;
}
virtual void doFree(void *chunk) {
#ifdef MOZ_MEMORY
free(chunk);
#else
js::FreeGCChunk(chunk);
#endif
}
};
static XPConnectGCChunkAllocator gXPCJSChunkAllocator;
#ifdef MOZ_MEMORY
#define JS_GC_HEAP_KIND nsIMemoryReporter::KIND_HEAP
#else
#define JS_GC_HEAP_KIND nsIMemoryReporter::KIND_NONHEAP
#endif
// We have per-compartment GC heap totals, so we can't put the total GC heap
// size in the explicit allocations tree. But it's a useful figure, so put it
@ -2087,8 +2053,6 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
mJSRuntime->setActivityCallback(ActivityCallback, this);
mJSRuntime->setCustomGCChunkAllocator(&gXPCJSChunkAllocator);
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));