зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
4afcf12af5
Коммит
aaa99c61c5
|
@ -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));
|
||||
|
|
Загрузка…
Ссылка в новой задаче