uox3/spidermonkey/jsapi-tests/testGCChunkAlloc.cpp
2025-03-19 21:25:58 +10:00

111 lines
2.7 KiB
C++

/* -*- 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 only single chunk. */
class CustomGCChunkAllocator: public js::GCChunkAllocator {
public:
CustomGCChunkAllocator() : pool(NULL) {}
void *pool;
private:
virtual void *doAlloc() {
if (!pool)
return NULL;
void *chunk = pool;
pool = NULL;
return chunk;
}
virtual void doFree(void *chunk) {
JS_ASSERT(!pool);
pool = 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(errorCount == 1);
CHECK(!customGCChunkAllocator.pool);
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(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 = js::AllocGCChunk();
JS_ASSERT(customGCChunkAllocator.pool);
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);
js::FreeGCChunk(customGCChunkAllocator.pool);
customGCChunkAllocator.pool = NULL;
}
END_TEST(testGCChunkAlloc)