summaryrefslogtreecommitdiff
path: root/js/src/jsapi-tests/testGCChunkAlloc.cpp
blob: a63af4b9241f79ff0f7e0899970a1a73062fca59 (plain)
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)