mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 807480 - Add Rooted<T> roots to PerThread state. r=luke
Currently there are a number of global fields in JSRuntime* which are basically tracking per-thread state. This makes sense on the current trunk since there is only ever a single thread associated with a runtime, but as Parallel JS (nee Rivertrail) starts to land this assumption no longer holds. This patch makes a struct, currently called |JS::PerThreadData|, that stores per-thread data from the runtime. There is one instance of this struct embedded in "Runtime" itself (the field |mainThread|). For now I have only migrated the debug GC fields into |PerThread|, those are the ones causing me immediate pain. Eventually more fields will want to move into there. The eventual goal is to distinguish thread-safe code, which will take as argument a |JS::PerThread*|, from non-thread-safe code, which will take a |JSRuntime*| or |JSContext*|.
This commit is contained in:
parent
6240239870
commit
0f88896f1a
@ -519,27 +519,23 @@ class Rooted : public RootedBase<T>
|
|||||||
{
|
{
|
||||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||||
ContextFriendFields *cx = ContextFriendFields::get(cxArg);
|
ContextFriendFields *cx = ContextFriendFields::get(cxArg);
|
||||||
|
commonInit(cx->thingGCRooters);
|
||||||
ThingRootKind kind = RootMethods<T>::kind();
|
|
||||||
this->stack = reinterpret_cast<Rooted<T>**>(&cx->thingGCRooters[kind]);
|
|
||||||
this->prev = *stack;
|
|
||||||
*stack = this;
|
|
||||||
|
|
||||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(JSRuntime *rtArg)
|
void init(JSRuntime *rtArg)
|
||||||
{
|
{
|
||||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||||
RuntimeFriendFields *rt = const_cast<RuntimeFriendFields *>(RuntimeFriendFields::get(rtArg));
|
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::getMainThread(rtArg);
|
||||||
|
commonInit(pt->thingGCRooters);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
ThingRootKind kind = RootMethods<T>::kind();
|
void init(js::PerThreadData *ptArg)
|
||||||
this->stack = reinterpret_cast<Rooted<T>**>(&rt->thingGCRooters[kind]);
|
{
|
||||||
this->prev = *stack;
|
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||||
*stack = this;
|
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::get(ptArg);
|
||||||
|
commonInit(pt->thingGCRooters);
|
||||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,6 +572,22 @@ class Rooted : public RootedBase<T>
|
|||||||
init(cx);
|
init(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rooted(js::PerThreadData *pt
|
||||||
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||||
|
: ptr(RootMethods<T>::initial())
|
||||||
|
{
|
||||||
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||||
|
init(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rooted(js::PerThreadData *pt, T initial
|
||||||
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||||
|
: ptr(initial)
|
||||||
|
{
|
||||||
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||||
|
init(pt);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
Rooted(JSContext *cx, const Return<S> &initial
|
Rooted(JSContext *cx, const Return<S> &initial
|
||||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||||
@ -585,6 +597,15 @@ class Rooted : public RootedBase<T>
|
|||||||
init(cx);
|
init(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
Rooted(js::PerThreadData *pt, const Return<S> &initial
|
||||||
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||||
|
: ptr(initial.ptr_)
|
||||||
|
{
|
||||||
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||||
|
init(pt);
|
||||||
|
}
|
||||||
|
|
||||||
~Rooted()
|
~Rooted()
|
||||||
{
|
{
|
||||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||||
@ -625,6 +646,17 @@ class Rooted : public RootedBase<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void commonInit(Rooted<void*> **thingGCRooters) {
|
||||||
|
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||||
|
ThingRootKind kind = RootMethods<T>::kind();
|
||||||
|
this->stack = reinterpret_cast<Rooted<T>**>(&thingGCRooters[kind]);
|
||||||
|
this->prev = *stack;
|
||||||
|
*stack = this;
|
||||||
|
|
||||||
|
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||||
Rooted<T> **stack, *prev;
|
Rooted<T> **stack, *prev;
|
||||||
#endif
|
#endif
|
||||||
|
@ -676,33 +676,36 @@ static JSBool js_NewRuntimeWasCalled = JS_FALSE;
|
|||||||
/*
|
/*
|
||||||
* Thread Local Storage slot for storing the runtime for a thread.
|
* Thread Local Storage slot for storing the runtime for a thread.
|
||||||
*/
|
*/
|
||||||
|
namespace js {
|
||||||
|
mozilla::ThreadLocal<PerThreadData *> TlsPerThreadData;
|
||||||
|
}
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
mozilla::ThreadLocal<JSRuntime *> TlsRuntime;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
EnterAssertNoGCScope()
|
EnterAssertNoGCScope()
|
||||||
{
|
{
|
||||||
++TlsRuntime.get()->gcAssertNoGCDepth;
|
++TlsPerThreadData.get()->gcAssertNoGCDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
LeaveAssertNoGCScope()
|
LeaveAssertNoGCScope()
|
||||||
{
|
{
|
||||||
--TlsRuntime.get()->gcAssertNoGCDepth;
|
--TlsPerThreadData.get()->gcAssertNoGCDepth;
|
||||||
JS_ASSERT(TlsRuntime.get()->gcAssertNoGCDepth >= 0);
|
JS_ASSERT(TlsPerThreadData.get()->gcAssertNoGCDepth >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(bool)
|
JS_FRIEND_API(bool)
|
||||||
InNoGCScope()
|
InNoGCScope()
|
||||||
{
|
{
|
||||||
return TlsRuntime.get()->gcAssertNoGCDepth > 0;
|
return TlsPerThreadData.get()->gcAssertNoGCDepth > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(bool)
|
JS_FRIEND_API(bool)
|
||||||
NeedRelaxedRootChecks()
|
NeedRelaxedRootChecks()
|
||||||
{
|
{
|
||||||
return TlsRuntime.get()->gcRelaxRootChecks;
|
return TlsPerThreadData.get()->gcRelaxRootChecks;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
JS_FRIEND_API(void) EnterAssertNoGCScope() {}
|
JS_FRIEND_API(void) EnterAssertNoGCScope() {}
|
||||||
@ -715,8 +718,17 @@ JS_FRIEND_API(bool) NeedRelaxedRootChecks() { return false; }
|
|||||||
|
|
||||||
static const JSSecurityCallbacks NullSecurityCallbacks = { };
|
static const JSSecurityCallbacks NullSecurityCallbacks = { };
|
||||||
|
|
||||||
|
js::PerThreadData::PerThreadData(JSRuntime *runtime)
|
||||||
|
: runtime_(runtime)
|
||||||
|
#ifdef DEBUG
|
||||||
|
, gcRelaxRootChecks(false)
|
||||||
|
, gcAssertNoGCDepth(0)
|
||||||
|
#endif
|
||||||
|
{}
|
||||||
|
|
||||||
JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
||||||
: atomsCompartment(NULL),
|
: mainThread(this),
|
||||||
|
atomsCompartment(NULL),
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
ownerThread_(NULL),
|
ownerThread_(NULL),
|
||||||
#endif
|
#endif
|
||||||
@ -788,10 +800,6 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
|||||||
gcSliceBudget(SliceBudget::Unlimited),
|
gcSliceBudget(SliceBudget::Unlimited),
|
||||||
gcIncrementalEnabled(true),
|
gcIncrementalEnabled(true),
|
||||||
gcExactScanningEnabled(true),
|
gcExactScanningEnabled(true),
|
||||||
#ifdef DEBUG
|
|
||||||
gcRelaxRootChecks(false),
|
|
||||||
gcAssertNoGCDepth(0),
|
|
||||||
#endif
|
|
||||||
gcPoke(false),
|
gcPoke(false),
|
||||||
heapState(Idle),
|
heapState(Idle),
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
@ -885,16 +893,12 @@ JSRuntime::init(uint32_t maxbytes)
|
|||||||
ownerThread_ = PR_GetCurrentThread();
|
ownerThread_ = PR_GetCurrentThread();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS::TlsRuntime.set(this);
|
js::TlsPerThreadData.set(&mainThread);
|
||||||
|
|
||||||
#ifdef JS_METHODJIT_SPEW
|
#ifdef JS_METHODJIT_SPEW
|
||||||
JMCheckLogging();
|
JMCheckLogging();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
|
||||||
PodArrayZero(thingGCRooters);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!js_InitGC(this, maxbytes))
|
if (!js_InitGC(this, maxbytes))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1018,9 +1022,9 @@ JSRuntime::setOwnerThread()
|
|||||||
JS_ASSERT(ownerThread_ == (void *)0xc1ea12); /* "clear" */
|
JS_ASSERT(ownerThread_ == (void *)0xc1ea12); /* "clear" */
|
||||||
JS_ASSERT(requestDepth == 0);
|
JS_ASSERT(requestDepth == 0);
|
||||||
JS_ASSERT(js_NewRuntimeWasCalled);
|
JS_ASSERT(js_NewRuntimeWasCalled);
|
||||||
JS_ASSERT(JS::TlsRuntime.get() == NULL);
|
JS_ASSERT(js::TlsPerThreadData.get() == NULL);
|
||||||
ownerThread_ = PR_GetCurrentThread();
|
ownerThread_ = PR_GetCurrentThread();
|
||||||
JS::TlsRuntime.set(this);
|
js::TlsPerThreadData.set(&mainThread);
|
||||||
nativeStackBase = GetNativeStackBase();
|
nativeStackBase = GetNativeStackBase();
|
||||||
if (nativeStackQuota)
|
if (nativeStackQuota)
|
||||||
JS_SetNativeStackQuota(this, nativeStackQuota);
|
JS_SetNativeStackQuota(this, nativeStackQuota);
|
||||||
@ -1033,7 +1037,7 @@ JSRuntime::clearOwnerThread()
|
|||||||
JS_ASSERT(requestDepth == 0);
|
JS_ASSERT(requestDepth == 0);
|
||||||
JS_ASSERT(js_NewRuntimeWasCalled);
|
JS_ASSERT(js_NewRuntimeWasCalled);
|
||||||
ownerThread_ = (void *)0xc1ea12; /* "clear" */
|
ownerThread_ = (void *)0xc1ea12; /* "clear" */
|
||||||
JS::TlsRuntime.set(NULL);
|
js::TlsPerThreadData.set(NULL);
|
||||||
nativeStackBase = 0;
|
nativeStackBase = 0;
|
||||||
#if JS_STACK_GROWTH_DIRECTION > 0
|
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||||
nativeStackLimit = UINTPTR_MAX;
|
nativeStackLimit = UINTPTR_MAX;
|
||||||
@ -1047,7 +1051,7 @@ JSRuntime::abortIfWrongThread() const
|
|||||||
{
|
{
|
||||||
if (ownerThread_ != PR_GetCurrentThread())
|
if (ownerThread_ != PR_GetCurrentThread())
|
||||||
MOZ_CRASH();
|
MOZ_CRASH();
|
||||||
if (this != JS::TlsRuntime.get())
|
if (!js::TlsPerThreadData.get()->associatedWith(this))
|
||||||
MOZ_CRASH();
|
MOZ_CRASH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1055,7 +1059,7 @@ JS_FRIEND_API(void)
|
|||||||
JSRuntime::assertValidThread() const
|
JSRuntime::assertValidThread() const
|
||||||
{
|
{
|
||||||
JS_ASSERT(ownerThread_ == PR_GetCurrentThread());
|
JS_ASSERT(ownerThread_ == PR_GetCurrentThread());
|
||||||
JS_ASSERT(this == JS::TlsRuntime.get());
|
JS_ASSERT(js::TlsPerThreadData.get()->associatedWith(this));
|
||||||
}
|
}
|
||||||
#endif /* JS_THREADSAFE */
|
#endif /* JS_THREADSAFE */
|
||||||
|
|
||||||
@ -1092,7 +1096,7 @@ JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads)
|
|||||||
|
|
||||||
InitMemorySubsystem();
|
InitMemorySubsystem();
|
||||||
|
|
||||||
if (!JS::TlsRuntime.init())
|
if (!js::TlsPerThreadData.init())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
js_NewRuntimeWasCalled = JS_TRUE;
|
js_NewRuntimeWasCalled = JS_TRUE;
|
||||||
|
@ -2889,8 +2889,6 @@ JS_IsInRequest(JSRuntime *rt);
|
|||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
extern mozilla::ThreadLocal<JSRuntime *> TlsRuntime;
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
IsPoisonedId(jsid iden)
|
IsPoisonedId(jsid iden)
|
||||||
{
|
{
|
||||||
|
@ -389,8 +389,70 @@ struct JSAtomState
|
|||||||
#define NAME_OFFSET(name) offsetof(JSAtomState, name)
|
#define NAME_OFFSET(name) offsetof(JSAtomState, name)
|
||||||
#define OFFSET_TO_NAME(rt,off) (*(js::FixedHeapPtr<js::PropertyName>*)((char*)&(rt)->atomState + (off)))
|
#define OFFSET_TO_NAME(rt,off) (*(js::FixedHeapPtr<js::PropertyName>*)((char*)&(rt)->atomState + (off)))
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encapsulates portions of the runtime/context that are tied to a
|
||||||
|
* single active thread. Normally, as most JS is single-threaded,
|
||||||
|
* there is only one instance of this struct, embedded in the
|
||||||
|
* JSRuntime as the field |mainThread|. During Parallel JS sections,
|
||||||
|
* however, there will be one instance per worker thread.
|
||||||
|
*
|
||||||
|
* The eventual plan is to designate thread-safe portions of the
|
||||||
|
* interpreter and runtime by having them take |PerThreadData*|
|
||||||
|
* arguments instead of |JSContext*| or |JSRuntime*|.
|
||||||
|
*/
|
||||||
|
class PerThreadData : public js::PerThreadDataFriendFields
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Backpointer to the full shared JSRuntime* with which this
|
||||||
|
* thread is associaed. This is private because accessing the
|
||||||
|
* fields of this runtime can provoke race conditions, so the
|
||||||
|
* intention is that access will be mediated through safe
|
||||||
|
* functions like |associatedWith()| below.
|
||||||
|
*/
|
||||||
|
JSRuntime *runtime_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* We save all conservative scanned roots in this vector so that
|
||||||
|
* conservative scanning can be "replayed" deterministically. In DEBUG mode,
|
||||||
|
* this allows us to run a non-incremental GC after every incremental GC to
|
||||||
|
* ensure that no objects were missed.
|
||||||
|
*/
|
||||||
|
#ifdef DEBUG
|
||||||
|
struct SavedGCRoot {
|
||||||
|
void *thing;
|
||||||
|
JSGCTraceKind kind;
|
||||||
|
|
||||||
|
SavedGCRoot(void *thing, JSGCTraceKind kind) : thing(thing), kind(kind) {}
|
||||||
|
};
|
||||||
|
js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
|
||||||
|
|
||||||
|
bool gcRelaxRootChecks;
|
||||||
|
int gcAssertNoGCDepth;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PerThreadData(JSRuntime *runtime);
|
||||||
|
|
||||||
|
bool associatedWith(const JSRuntime *rt) { return runtime_ == rt; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace js
|
||||||
|
|
||||||
struct JSRuntime : js::RuntimeFriendFields
|
struct JSRuntime : js::RuntimeFriendFields
|
||||||
{
|
{
|
||||||
|
/* Per-thread data for the main thread that is associated with
|
||||||
|
* this JSRuntime, as opposed to any worker threads used in
|
||||||
|
* parallel sections. See definition of |PerThreadData| struct
|
||||||
|
* above for more details.
|
||||||
|
*
|
||||||
|
* NB: This field is statically asserted to be at offset
|
||||||
|
* sizeof(RuntimeFriendFields). See
|
||||||
|
* PerThreadDataFriendFields::getMainThread.
|
||||||
|
*/
|
||||||
|
js::PerThreadData mainThread;
|
||||||
|
|
||||||
/* Default compartment. */
|
/* Default compartment. */
|
||||||
JSCompartment *atomsCompartment;
|
JSCompartment *atomsCompartment;
|
||||||
|
|
||||||
@ -654,25 +716,6 @@ struct JSRuntime : js::RuntimeFriendFields
|
|||||||
*/
|
*/
|
||||||
bool gcExactScanningEnabled;
|
bool gcExactScanningEnabled;
|
||||||
|
|
||||||
/*
|
|
||||||
* We save all conservative scanned roots in this vector so that
|
|
||||||
* conservative scanning can be "replayed" deterministically. In DEBUG mode,
|
|
||||||
* this allows us to run a non-incremental GC after every incremental GC to
|
|
||||||
* ensure that no objects were missed.
|
|
||||||
*/
|
|
||||||
#ifdef DEBUG
|
|
||||||
struct SavedGCRoot {
|
|
||||||
void *thing;
|
|
||||||
JSGCTraceKind kind;
|
|
||||||
|
|
||||||
SavedGCRoot(void *thing, JSGCTraceKind kind) : thing(thing), kind(kind) {}
|
|
||||||
};
|
|
||||||
js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
|
|
||||||
|
|
||||||
bool gcRelaxRootChecks;
|
|
||||||
int gcAssertNoGCDepth;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool gcPoke;
|
bool gcPoke;
|
||||||
|
|
||||||
enum HeapState {
|
enum HeapState {
|
||||||
|
@ -22,6 +22,16 @@
|
|||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace JS;
|
using namespace JS;
|
||||||
|
|
||||||
|
// Required by PerThreadDataFriendFields::getMainThread()
|
||||||
|
JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) == sizeof(RuntimeFriendFields));
|
||||||
|
|
||||||
|
PerThreadDataFriendFields::PerThreadDataFriendFields()
|
||||||
|
{
|
||||||
|
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||||
|
PodArrayZero(thingGCRooters);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook)
|
JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook)
|
||||||
{
|
{
|
||||||
|
@ -183,6 +183,8 @@ JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook);
|
|||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
extern mozilla::ThreadLocal<PerThreadData *> TlsPerThreadData;
|
||||||
|
|
||||||
inline JSRuntime *
|
inline JSRuntime *
|
||||||
GetRuntime(const JSContext *cx)
|
GetRuntime(const JSContext *cx)
|
||||||
{
|
{
|
||||||
|
@ -992,7 +992,7 @@ MarkExactStackRoots(JSTracer *trc)
|
|||||||
for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
|
for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
|
||||||
MarkExactStackRooters(trc, cx->thingGCRooters[i], ThingRootKind(i));
|
MarkExactStackRooters(trc, cx->thingGCRooters[i], ThingRootKind(i));
|
||||||
}
|
}
|
||||||
MarkExactStackRooters(trc, rt->thingGCRooters[i], ThingRootKind(i));
|
MarkExactStackRooters(trc, rt->mainThread.thingGCRooters[i], ThingRootKind(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* JSGC_USE_EXACT_ROOTING */
|
#endif /* JSGC_USE_EXACT_ROOTING */
|
||||||
@ -1125,7 +1125,8 @@ MarkIfGCThingWord(JSTracer *trc, uintptr_t w)
|
|||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (trc->runtime->gcIncrementalState == MARK_ROOTS)
|
if (trc->runtime->gcIncrementalState == MARK_ROOTS)
|
||||||
trc->runtime->gcSavedRoots.append(JSRuntime::SavedGCRoot(thing, traceKind));
|
trc->runtime->mainThread.gcSavedRoots.append(
|
||||||
|
PerThreadData::SavedGCRoot(thing, traceKind));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return CGCT_VALID;
|
return CGCT_VALID;
|
||||||
@ -1186,8 +1187,8 @@ MarkConservativeStackRoots(JSTracer *trc, bool useSavedRoots)
|
|||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (useSavedRoots) {
|
if (useSavedRoots) {
|
||||||
for (JSRuntime::SavedGCRoot *root = rt->gcSavedRoots.begin();
|
for (PerThreadData::SavedGCRoot *root = rt->mainThread.gcSavedRoots.begin();
|
||||||
root != rt->gcSavedRoots.end();
|
root != rt->mainThread.gcSavedRoots.end();
|
||||||
root++)
|
root++)
|
||||||
{
|
{
|
||||||
JS_SET_TRACING_NAME(trc, "cstack");
|
JS_SET_TRACING_NAME(trc, "cstack");
|
||||||
@ -1197,7 +1198,7 @@ MarkConservativeStackRoots(JSTracer *trc, bool useSavedRoots)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rt->gcIncrementalState == MARK_ROOTS)
|
if (rt->gcIncrementalState == MARK_ROOTS)
|
||||||
rt->gcSavedRoots.clearAndFree();
|
rt->mainThread.gcSavedRoots.clearAndFree();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ConservativeGCData *cgcd = &rt->conservativeGC;
|
ConservativeGCData *cgcd = &rt->conservativeGC;
|
||||||
@ -4912,7 +4913,8 @@ CheckStackRoot(JSTracer *trc, uintptr_t *w)
|
|||||||
bool matched = false;
|
bool matched = false;
|
||||||
JSRuntime *rt = trc->runtime;
|
JSRuntime *rt = trc->runtime;
|
||||||
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
|
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
|
||||||
CheckStackRootThings(w, rt->thingGCRooters[i], ThingRootKind(i), &matched);
|
CheckStackRootThings(w, rt->mainThread.thingGCRooters[i],
|
||||||
|
ThingRootKind(i), &matched);
|
||||||
for (ContextIter cx(rt); !cx.done(); cx.next()) {
|
for (ContextIter cx(rt); !cx.done(); cx.next()) {
|
||||||
CheckStackRootThings(w, cx->thingGCRooters[i], ThingRootKind(i), &matched);
|
CheckStackRootThings(w, cx->thingGCRooters[i], ThingRootKind(i), &matched);
|
||||||
SkipRoot *skip = cx->skipGCRooters;
|
SkipRoot *skip = cx->skipGCRooters;
|
||||||
|
@ -307,14 +307,6 @@ struct RuntimeFriendFields {
|
|||||||
/* Limit pointer for checking native stack consumption. */
|
/* Limit pointer for checking native stack consumption. */
|
||||||
uintptr_t nativeStackLimit;
|
uintptr_t nativeStackLimit;
|
||||||
|
|
||||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
|
||||||
/*
|
|
||||||
* Stack allocated GC roots for stack GC heap pointers, which may be
|
|
||||||
* overwritten if moved during a GC.
|
|
||||||
*/
|
|
||||||
Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RuntimeFriendFields()
|
RuntimeFriendFields()
|
||||||
: interrupt(0),
|
: interrupt(0),
|
||||||
nativeStackLimit(0) { }
|
nativeStackLimit(0) { }
|
||||||
@ -324,6 +316,32 @@ struct RuntimeFriendFields {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PerThreadData;
|
||||||
|
|
||||||
|
struct PerThreadDataFriendFields
|
||||||
|
{
|
||||||
|
PerThreadDataFriendFields();
|
||||||
|
|
||||||
|
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||||
|
/*
|
||||||
|
* Stack allocated GC roots for stack GC heap pointers, which may be
|
||||||
|
* overwritten if moved during a GC.
|
||||||
|
*/
|
||||||
|
Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static PerThreadDataFriendFields *get(js::PerThreadData *pt) {
|
||||||
|
return reinterpret_cast<PerThreadDataFriendFields *>(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PerThreadDataFriendFields *getMainThread(JSRuntime *rt) {
|
||||||
|
// mainThread must always appear directly after |RuntimeFriendFields|.
|
||||||
|
// Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp|
|
||||||
|
return reinterpret_cast<PerThreadDataFriendFields *>(
|
||||||
|
reinterpret_cast<char*>(rt) + sizeof(RuntimeFriendFields));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
@ -3417,7 +3417,7 @@ RelaxRootChecks(JSContext *cx, unsigned argc, jsval *vp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
cx->runtime->gcRelaxRootChecks = true;
|
cx->runtime->mainThread.gcRelaxRootChecks = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1402,7 +1402,8 @@ StackIter::settleOnNewState()
|
|||||||
}
|
}
|
||||||
|
|
||||||
StackIter::StackIter(JSContext *cx, SavedOption savedOption)
|
StackIter::StackIter(JSContext *cx, SavedOption savedOption)
|
||||||
: maybecx_(cx),
|
: perThread_(&cx->runtime->mainThread),
|
||||||
|
maybecx_(cx),
|
||||||
savedOption_(savedOption),
|
savedOption_(savedOption),
|
||||||
script_(cx, NULL)
|
script_(cx, NULL)
|
||||||
#ifdef JS_ION
|
#ifdef JS_ION
|
||||||
@ -1426,7 +1427,9 @@ StackIter::StackIter(JSContext *cx, SavedOption savedOption)
|
|||||||
}
|
}
|
||||||
|
|
||||||
StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
|
StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
|
||||||
: maybecx_(NULL), savedOption_(STOP_AT_SAVED),
|
: perThread_(&rt->mainThread),
|
||||||
|
maybecx_(NULL),
|
||||||
|
savedOption_(STOP_AT_SAVED),
|
||||||
script_(rt, NULL)
|
script_(rt, NULL)
|
||||||
#ifdef JS_ION
|
#ifdef JS_ION
|
||||||
, ionActivations_(rt),
|
, ionActivations_(rt),
|
||||||
@ -1444,14 +1447,15 @@ StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
StackIter::StackIter(const StackIter &other)
|
StackIter::StackIter(const StackIter &other)
|
||||||
: maybecx_(other.maybecx_),
|
: perThread_(other.perThread_),
|
||||||
|
maybecx_(other.maybecx_),
|
||||||
savedOption_(other.savedOption_),
|
savedOption_(other.savedOption_),
|
||||||
state_(other.state_),
|
state_(other.state_),
|
||||||
fp_(other.fp_),
|
fp_(other.fp_),
|
||||||
calls_(other.calls_),
|
calls_(other.calls_),
|
||||||
seg_(other.seg_),
|
seg_(other.seg_),
|
||||||
pc_(other.pc_),
|
pc_(other.pc_),
|
||||||
script_(other.maybecx_ ? other.maybecx_->runtime : TlsRuntime.get(), other.script_),
|
script_(perThread_, other.script_),
|
||||||
args_(other.args_)
|
args_(other.args_)
|
||||||
#ifdef JS_ION
|
#ifdef JS_ION
|
||||||
, ionActivations_(other.ionActivations_),
|
, ionActivations_(other.ionActivations_),
|
||||||
|
@ -1712,6 +1712,7 @@ class GeneratorFrameGuard : public FrameGuard
|
|||||||
class StackIter
|
class StackIter
|
||||||
{
|
{
|
||||||
friend class ContextStack;
|
friend class ContextStack;
|
||||||
|
PerThreadData *perThread_;
|
||||||
JSContext *maybecx_;
|
JSContext *maybecx_;
|
||||||
public:
|
public:
|
||||||
enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
|
enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
|
||||||
|
Loading…
Reference in New Issue
Block a user