1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
/* -*- 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)
|