зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1199203 - Add support for per-thread OOM testing. r=jonco
This commit is contained in:
Родитель
fd1ffff272
Коммит
3f7b44f628
|
@ -62,6 +62,46 @@ JS_Assert(const char* s, const char* file, int ln);
|
|||
#if defined JS_USE_CUSTOM_ALLOCATOR
|
||||
# include "jscustomallocator.h"
|
||||
#else
|
||||
|
||||
namespace js {
|
||||
namespace oom {
|
||||
|
||||
/*
|
||||
* To make testing OOM in certain helper threads more effective,
|
||||
* allow restricting the OOM testing to a certain helper thread
|
||||
* type. This allows us to fail e.g. in off-thread script parsing
|
||||
* without causing an OOM in the main thread first.
|
||||
*/
|
||||
enum ThreadType {
|
||||
THREAD_TYPE_NONE, // 0
|
||||
THREAD_TYPE_MAIN, // 1
|
||||
THREAD_TYPE_ASMJS, // 2
|
||||
THREAD_TYPE_ION, // 3
|
||||
THREAD_TYPE_PARSE, // 4
|
||||
THREAD_TYPE_COMPRESS, // 5
|
||||
THREAD_TYPE_GCHELPER, // 6
|
||||
THREAD_TYPE_GCPARALLEL, // 7
|
||||
THREAD_TYPE_MAX // Used to check shell function arguments
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Getter/Setter functions to encapsulate mozilla::ThreadLocal,
|
||||
* implementation is in jsutil.cpp.
|
||||
*/
|
||||
# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
|
||||
extern bool InitThreadType(void);
|
||||
extern void SetThreadType(ThreadType);
|
||||
extern uint32_t GetThreadType(void);
|
||||
# else
|
||||
inline bool InitThreadType(void) { return true; }
|
||||
inline void SetThreadType(ThreadType t) {};
|
||||
inline uint32_t GetThreadType(void) { return 0; }
|
||||
# endif
|
||||
|
||||
} /* namespace oom */
|
||||
} /* namespace js */
|
||||
|
||||
# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
|
||||
|
||||
/*
|
||||
|
@ -83,16 +123,28 @@ static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
|
|||
namespace js {
|
||||
namespace oom {
|
||||
|
||||
extern JS_PUBLIC_DATA(uint32_t) targetThread;
|
||||
|
||||
static inline bool
|
||||
OOMThreadCheck()
|
||||
{
|
||||
return (!js::oom::targetThread
|
||||
|| js::oom::targetThread == js::oom::GetThreadType());
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsSimulatedOOMAllocation()
|
||||
{
|
||||
return OOM_counter == OOM_maxAllocations ||
|
||||
(OOM_counter > OOM_maxAllocations && OOM_failAlways);
|
||||
return OOMThreadCheck() && (OOM_counter == OOM_maxAllocations ||
|
||||
(OOM_counter > OOM_maxAllocations && OOM_failAlways));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ShouldFailWithOOM()
|
||||
{
|
||||
if (!OOMThreadCheck())
|
||||
return false;
|
||||
|
||||
OOM_counter++;
|
||||
if (IsSimulatedOOMAllocation()) {
|
||||
JS_OOM_CALL_BP_FUNC();
|
||||
|
|
|
@ -987,15 +987,30 @@ static bool
|
|||
OOMAfterAllocations(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 1) {
|
||||
if (args.length() < 1) {
|
||||
JS_ReportError(cx, "count argument required");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t count;
|
||||
if (!JS::ToUint32(cx, args[0], &count))
|
||||
if (args.length() > 2) {
|
||||
JS_ReportError(cx, "too many arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t targetThread = 0;
|
||||
if (!ToUint32(cx, args.get(1), &targetThread))
|
||||
return false;
|
||||
|
||||
if (targetThread >= js::oom::THREAD_TYPE_MAX) {
|
||||
JS_ReportError(cx, "invalid thread type specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t count;
|
||||
if (!JS::ToUint32(cx, args.get(0), &count))
|
||||
return false;
|
||||
|
||||
js::oom::targetThread = targetThread;
|
||||
OOM_maxAllocations = OOM_counter + count;
|
||||
OOM_failAlways = true;
|
||||
return true;
|
||||
|
@ -1005,15 +1020,30 @@ static bool
|
|||
OOMAtAllocation(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 1) {
|
||||
if (args.length() < 1) {
|
||||
JS_ReportError(cx, "count argument required");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t count;
|
||||
if (!JS::ToUint32(cx, args[0], &count))
|
||||
if (args.length() > 2) {
|
||||
JS_ReportError(cx, "too many arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t targetThread = 0;
|
||||
if (!ToUint32(cx, args.get(1), &targetThread))
|
||||
return false;
|
||||
|
||||
if (targetThread >= js::oom::THREAD_TYPE_MAX) {
|
||||
JS_ReportError(cx, "invalid thread type specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t count;
|
||||
if (!JS::ToUint32(cx, args.get(0), &count))
|
||||
return false;
|
||||
|
||||
js::oom::targetThread = targetThread;
|
||||
OOM_maxAllocations = OOM_counter + count;
|
||||
OOM_failAlways = false;
|
||||
return true;
|
||||
|
@ -2832,15 +2862,17 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
|||
" Stop capturing the JS stack at every allocation."),
|
||||
|
||||
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
|
||||
JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 1, 0,
|
||||
"oomAfterAllocations(count)",
|
||||
JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 2, 0,
|
||||
"oomAfterAllocations(count [,threadType])",
|
||||
" After 'count' js_malloc memory allocations, fail every following allocation\n"
|
||||
" (return NULL)."),
|
||||
" (return nullptr). The optional thread type limits the effect to the\n"
|
||||
" specified type of helper thread."),
|
||||
|
||||
JS_FN_HELP("oomAtAllocation", OOMAtAllocation, 1, 0,
|
||||
"oomAtAllocation(count)",
|
||||
JS_FN_HELP("oomAtAllocation", OOMAtAllocation, 2, 0,
|
||||
"oomAtAllocation(count [,threadType])",
|
||||
" After 'count' js_malloc memory allocations, fail the next allocation\n"
|
||||
" (return NULL)."),
|
||||
" (return nullptr). The optional thread type limits the effect to the\n"
|
||||
" specified type of helper thread."),
|
||||
|
||||
JS_FN_HELP("resetOOMFailure", ResetOOMFailure, 0, 0,
|
||||
"resetOOMFailure()",
|
||||
|
|
|
@ -590,6 +590,12 @@ JS_Init(void)
|
|||
if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init())
|
||||
return false;
|
||||
|
||||
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
|
||||
if (!js::oom::InitThreadType())
|
||||
return false;
|
||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN);
|
||||
#endif
|
||||
|
||||
jit::ExecutableAllocator::initStatic();
|
||||
|
||||
if (!jit::InitializeIon())
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -32,7 +33,30 @@ using mozilla::PodArrayZero;
|
|||
JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations = UINT32_MAX;
|
||||
JS_PUBLIC_DATA(uint32_t) OOM_counter = 0;
|
||||
JS_PUBLIC_DATA(bool) OOM_failAlways = true;
|
||||
#endif
|
||||
namespace js {
|
||||
namespace oom {
|
||||
|
||||
JS_PUBLIC_DATA(uint32_t) targetThread = 0;
|
||||
JS_PUBLIC_DATA(mozilla::ThreadLocal<uint32_t>) threadType;
|
||||
|
||||
bool
|
||||
InitThreadType(void) {
|
||||
return threadType.initialized() || threadType.init();
|
||||
}
|
||||
|
||||
void
|
||||
SetThreadType(ThreadType type) {
|
||||
threadType.set(type);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetThreadType(void) {
|
||||
return threadType.get();
|
||||
}
|
||||
|
||||
} // namespace oom
|
||||
} // namespace js
|
||||
#endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_Assert(const char* s, const char* file, int ln)
|
||||
|
|
|
@ -1451,19 +1451,26 @@ HelperThread::threadLoop()
|
|||
}
|
||||
|
||||
// Dispatch tasks, prioritizing AsmJS work.
|
||||
if (HelperThreadState().canStartAsmJSCompile())
|
||||
if (HelperThreadState().canStartAsmJSCompile()) {
|
||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_ASMJS);
|
||||
handleAsmJSWorkload();
|
||||
else if (ionCompile)
|
||||
} else if (ionCompile) {
|
||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_ION);
|
||||
handleIonWorkload();
|
||||
else if (HelperThreadState().canStartParseTask())
|
||||
} else if (HelperThreadState().canStartParseTask()) {
|
||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_PARSE);
|
||||
handleParseWorkload();
|
||||
else if (HelperThreadState().canStartCompressionTask())
|
||||
} else if (HelperThreadState().canStartCompressionTask()) {
|
||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_COMPRESS);
|
||||
handleCompressionWorkload();
|
||||
else if (HelperThreadState().canStartGCHelperTask())
|
||||
} else if (HelperThreadState().canStartGCHelperTask()) {
|
||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_GCHELPER);
|
||||
handleGCHelperWorkload();
|
||||
else if (HelperThreadState().canStartGCParallelTask())
|
||||
} else if (HelperThreadState().canStartGCParallelTask()) {
|
||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_GCPARALLEL);
|
||||
handleGCParallelWorkload();
|
||||
else
|
||||
} else {
|
||||
MOZ_CRASH("No task to perform");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче