testGCOutOfMemory.cpp (2557B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * 4 * Any copyright is dedicated to the Public Domain. 5 * http://creativecommons.org/licenses/publicdomain/ 6 * Contributor: Igor Bukanov 7 */ 8 9 #include "mozilla/Utf8.h" // mozilla::Utf8Unit 10 11 #include "gc/GCEnum.h" // js::gc::ZealMode 12 #include "js/CompilationAndEvaluation.h" // JS::Evaluate 13 #include "js/SourceText.h" // JS::Source{Ownership,Text} 14 #include "jsapi-tests/tests.h" 15 16 BEGIN_TEST(testGCOutOfMemory) { 17 // Count the number of allocations until we hit OOM, and store it in 'max'. 18 static const char source[] = 19 "var max = 0; (function() {" 20 " var array = [];" 21 " for (; ; ++max)" 22 " array.push({});" 23 " array = []; array.push(0);" 24 "})();"; 25 26 JS::CompileOptions opts(cx); 27 28 JS::SourceText<mozilla::Utf8Unit> srcBuf; 29 CHECK(srcBuf.init(cx, source, strlen(source), JS::SourceOwnership::Borrowed)); 30 31 JS::RootedValue root(cx); 32 bool ok = JS::Evaluate(cx, opts, srcBuf, &root); 33 34 /* Check that we get OOM. */ 35 CHECK(!ok); 36 CHECK(JS_GetPendingException(cx, &root)); 37 CHECK(root.isString()); 38 bool match = false; 39 CHECK(JS_StringEqualsLiteral(cx, root.toString(), "out of memory", &match)); 40 CHECK(match); 41 JS_ClearPendingException(cx); 42 43 JS_GC(cx); 44 45 // The above GC should have discarded everything. Verify that we can now 46 // allocate half as many objects without OOMing. 47 EVAL( 48 "(function() {" 49 " var array = [];" 50 " for (var i = max >> 2; i != 0;) {" 51 " --i;" 52 " array.push({});" 53 " }" 54 "})();", 55 &root); 56 CHECK(!JS_IsExceptionPending(cx)); 57 return true; 58 } 59 60 virtual JSContext* createContext() override { 61 // Note that the max nursery size must be less than the whole heap size, or 62 // the test will fail because 'max' (the number of allocations required for 63 // OOM) will be based on the nursery size, and that will overflow the 64 // tenured heap, which will cause the second pass with max/4 allocations to 65 // OOM. (Actually, this only happens with nursery zeal, because normally 66 // the nursery will start out with only a single chunk before triggering a 67 // major GC.) 68 JSContext* cx = JS_NewContext(4 * 1024 * 1024); 69 if (!cx) { 70 return nullptr; 71 } 72 JS_SetGCParameter(cx, JSGC_MAX_NURSERY_BYTES, js::gc::ChunkSize); 73 #ifdef JS_GC_ZEAL 74 JS::UnsetGCZeal(cx, uint8_t(js::gc::ZealMode::GenerationalGC)); 75 #endif 76 return cx; 77 } 78 79 END_TEST(testGCOutOfMemory)