mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 938124 - Add classes for use in IonBuilder thread safety analysis, r=jandem.
This commit is contained in:
parent
b354a123b3
commit
80ea5ead55
@ -1114,6 +1114,32 @@ InFreeList(ArenaHeader *aheader, void *thing)
|
||||
}
|
||||
|
||||
} /* namespace gc */
|
||||
|
||||
// Ion compilation mainly occurs off the main thread, and may run while the
|
||||
// main thread is performing arbitrary VM operations, excepting GC activity.
|
||||
// The below class is used to mark functions and other operations which can
|
||||
// safely be performed off thread without racing. When running with thread
|
||||
// safety checking on, any access to a GC thing outside of AutoThreadSafeAccess
|
||||
// will cause an access violation.
|
||||
class AutoThreadSafeAccess
|
||||
{
|
||||
public:
|
||||
#if defined(DEBUG) && !defined(XP_WIN)
|
||||
JSRuntime *runtime;
|
||||
gc::ArenaHeader *arena;
|
||||
|
||||
AutoThreadSafeAccess(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
~AutoThreadSafeAccess();
|
||||
#else
|
||||
AutoThreadSafeAccess(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
~AutoThreadSafeAccess() {}
|
||||
#endif
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* gc_Heap_h */
|
||||
|
@ -1669,6 +1669,15 @@ IonCompile(JSContext *cx, JSScript *script,
|
||||
RootedScript builderScript(cx, builder->script());
|
||||
IonSpewNewFunction(graph, builderScript);
|
||||
|
||||
Maybe<AutoProtectHeapForCompilation> protect;
|
||||
if (js_IonOptions.checkThreadSafety &&
|
||||
cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL &&
|
||||
!cx->runtime()->profilingScripts &&
|
||||
!cx->runtime()->spsProfiler.enabled())
|
||||
{
|
||||
protect.construct(cx->runtime());
|
||||
}
|
||||
|
||||
bool succeeded = builder->build();
|
||||
builder->clearForBackEnd();
|
||||
|
||||
@ -1704,6 +1713,9 @@ IonCompile(JSContext *cx, JSScript *script,
|
||||
return AbortReason_Disable;
|
||||
}
|
||||
|
||||
if (!protect.empty())
|
||||
protect.destroy();
|
||||
|
||||
bool success = codegen->link(cx, builder->constraints());
|
||||
|
||||
IonSpewEndFunction();
|
||||
|
@ -83,6 +83,12 @@ struct IonOptions
|
||||
// Default: false
|
||||
bool checkRangeAnalysis;
|
||||
|
||||
// Whether to protect the GC heap during Ion compilation and ensure that
|
||||
// only threadsafe operations are performed on it.
|
||||
//
|
||||
// Default: false
|
||||
bool checkThreadSafety;
|
||||
|
||||
// Whether to perform expensive graph-consistency DEBUG-only assertions.
|
||||
// It can be useful to disable this to reduce DEBUG-compile time of large
|
||||
// asm.js programs.
|
||||
@ -221,6 +227,7 @@ struct IonOptions
|
||||
edgeCaseAnalysis(true),
|
||||
rangeAnalysis(true),
|
||||
checkRangeAnalysis(false),
|
||||
checkThreadSafety(false),
|
||||
assertGraphConsistency(true),
|
||||
uce(true),
|
||||
eaa(true),
|
||||
|
@ -5467,6 +5467,9 @@ ProcessArgs(JSContext *cx, JSObject *obj_, OptionParser *op)
|
||||
if (op->getBoolOption("ion-check-range-analysis"))
|
||||
jit::js_IonOptions.checkRangeAnalysis = true;
|
||||
|
||||
if (op->getBoolOption("ion-check-thread-safety"))
|
||||
jit::js_IonOptions.checkThreadSafety = true;
|
||||
|
||||
if (const char *str = op->getStringOption("ion-inlining")) {
|
||||
if (strcmp(str, "on") == 0)
|
||||
jit::js_IonOptions.inlining = true;
|
||||
@ -5775,6 +5778,8 @@ main(int argc, char **argv, char **envp)
|
||||
"Range analysis (default: on, off to disable)")
|
||||
|| !op.addBoolOption('\0', "ion-check-range-analysis",
|
||||
"Range analysis checking")
|
||||
|| !op.addBoolOption('\0', "ion-check-thread-safety",
|
||||
"IonBuilder thread safety checking")
|
||||
|| !op.addStringOption('\0', "ion-inlining", "on/off",
|
||||
"Inline methods where possible (default: on, off to disable)")
|
||||
|| !op.addStringOption('\0', "ion-osr", "on/off",
|
||||
@ -5868,8 +5873,15 @@ main(int argc, char **argv, char **envp)
|
||||
if (!JS_Init())
|
||||
return 1;
|
||||
|
||||
// When doing thread safety checks for VM accesses made during Ion compilation,
|
||||
// we rely on protected memory and only the main thread should be active.
|
||||
JSUseHelperThreads useHelperThreads =
|
||||
op.getBoolOption("ion-check-thread-safety")
|
||||
? JS_NO_HELPER_THREADS
|
||||
: JS_USE_HELPER_THREADS;
|
||||
|
||||
/* Use the same parameters as the browser in xpcjsruntime.cpp. */
|
||||
rt = JS_NewRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS);
|
||||
rt = JS_NewRuntime(32L * 1024L * 1024L, useHelperThreads);
|
||||
if (!rt)
|
||||
return 1;
|
||||
gTimeoutFunc = NullValue();
|
||||
|
@ -15,6 +15,10 @@
|
||||
#include <locale.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(DEBUG) && !defined(XP_WIN)
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "jsatom.h"
|
||||
#include "jsdtoa.h"
|
||||
#include "jsgc.h"
|
||||
@ -266,6 +270,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
||||
decimalSeparator(0),
|
||||
numGrouping(0),
|
||||
#endif
|
||||
heapProtected_(false),
|
||||
mathCache_(nullptr),
|
||||
activeCompilations_(0),
|
||||
keepAtoms_(0),
|
||||
@ -802,6 +807,76 @@ JSRuntime::activeGCInAtomsZone()
|
||||
return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted();
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && !defined(XP_WIN)
|
||||
|
||||
AutoProtectHeapForCompilation::AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
: runtime(rt)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
JS_ASSERT(!runtime->heapProtected_);
|
||||
runtime->heapProtected_ = true;
|
||||
|
||||
for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
|
||||
Chunk *chunk = r.front();
|
||||
// Note: Don't protect the last page in the chunk, which stores
|
||||
// immutable info and needs to be accessible for runtimeFromAnyThread()
|
||||
// in AutoThreadSafeAccess.
|
||||
if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_NONE))
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
AutoProtectHeapForCompilation::~AutoProtectHeapForCompilation()
|
||||
{
|
||||
JS_ASSERT(runtime->heapProtected_);
|
||||
JS_ASSERT(runtime->unprotectedArenas.empty());
|
||||
runtime->heapProtected_ = false;
|
||||
|
||||
for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) {
|
||||
Chunk *chunk = r.front();
|
||||
if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_READ | PROT_WRITE))
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
AutoThreadSafeAccess::AutoThreadSafeAccess(const Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
: runtime(cell->runtimeFromAnyThread()), arena(nullptr)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
if (!runtime->heapProtected_)
|
||||
return;
|
||||
|
||||
ArenaHeader *base = cell->arenaHeader();
|
||||
for (size_t i = 0; i < runtime->unprotectedArenas.length(); i++) {
|
||||
if (base == runtime->unprotectedArenas[i])
|
||||
return;
|
||||
}
|
||||
|
||||
arena = base;
|
||||
|
||||
if (mprotect(arena, sizeof(Arena), PROT_READ))
|
||||
MOZ_CRASH();
|
||||
|
||||
if (!runtime->unprotectedArenas.append(arena))
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
AutoThreadSafeAccess::~AutoThreadSafeAccess()
|
||||
{
|
||||
if (!arena)
|
||||
return;
|
||||
|
||||
if (mprotect(arena, sizeof(Arena), PROT_NONE))
|
||||
MOZ_CRASH();
|
||||
|
||||
JS_ASSERT(arena == runtime->unprotectedArenas.back());
|
||||
runtime->unprotectedArenas.popBack();
|
||||
}
|
||||
|
||||
#endif // DEBUG && !XP_WIN
|
||||
|
||||
#ifdef JS_WORKER_THREADS
|
||||
|
||||
void
|
||||
|
@ -679,6 +679,7 @@ class MarkingValidator;
|
||||
typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
|
||||
|
||||
class AutoLockForExclusiveAccess;
|
||||
class AutoProtectHeapForCompilation;
|
||||
|
||||
void RecomputeStackLimit(JSRuntime *rt, StackKind kind);
|
||||
|
||||
@ -1432,6 +1433,18 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
const char *numGrouping;
|
||||
#endif
|
||||
|
||||
friend class js::AutoProtectHeapForCompilation;
|
||||
friend class js::AutoThreadSafeAccess;
|
||||
mozilla::DebugOnly<bool> heapProtected_;
|
||||
#ifdef DEBUG
|
||||
js::Vector<js::gc::ArenaHeader *, 0, js::SystemAllocPolicy> unprotectedArenas;
|
||||
|
||||
public:
|
||||
bool heapProtected() {
|
||||
return heapProtected_;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
js::MathCache *mathCache_;
|
||||
js::MathCache *createMathCache(JSContext *cx);
|
||||
@ -2023,6 +2036,23 @@ class RuntimeAllocPolicy
|
||||
|
||||
extern const JSSecurityCallbacks NullSecurityCallbacks;
|
||||
|
||||
class AutoProtectHeapForCompilation
|
||||
{
|
||||
public:
|
||||
#if defined(DEBUG) && !defined(XP_WIN)
|
||||
JSRuntime *runtime;
|
||||
|
||||
AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
~AutoProtectHeapForCompilation();
|
||||
#else
|
||||
AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
#endif
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
Loading…
Reference in New Issue
Block a user