bug 730234 - remove GC locking from activities, operation callbacks-related code and for code that accesses the JSContext list. r=luke

This commit is contained in:
Igor Bukanov 2012-02-24 12:03:28 +01:00
Родитель 56ec12d66e
Коммит c5c7623497
14 изменённых файлов: 154 добавлений и 245 удалений

Просмотреть файл

@ -2925,7 +2925,7 @@ WorkerPrivate::Dispatch(WorkerRunnable* aEvent, EventQueue* aQueue)
}
if (aQueue == &mControlQueue && mJSContext) {
JS_TriggerOperationCallback(mJSContext);
JS_TriggerOperationCallback(JS_GetRuntime(mJSContext));
}
mCondVar.Notify();

Просмотреть файл

@ -1014,8 +1014,6 @@ StartRequest(JSContext *cx)
if (rt->requestDepth) {
rt->requestDepth++;
} else {
AutoLockGC lock(rt);
/* Indicate that a request is running. */
rt->requestDepth = 1;
@ -1034,10 +1032,6 @@ StopRequest(JSContext *cx)
rt->requestDepth--;
} else {
rt->conservativeGC.updateForRequestEnd(rt->suspendCount);
/* Lock before clearing to interlock with ClaimScope, in jslock.c. */
AutoLockGC lock(rt);
rt->requestDepth = 0;
if (rt->activityCallback)
@ -1307,14 +1301,12 @@ SetOptionsCommon(JSContext *cx, unsigned options)
JS_PUBLIC_API(uint32_t)
JS_SetOptions(JSContext *cx, uint32_t options)
{
AutoLockGC lock(cx->runtime);
return SetOptionsCommon(cx, options);
}
JS_PUBLIC_API(uint32_t)
JS_ToggleOptions(JSContext *cx, uint32_t options)
{
AutoLockGC lock(cx->runtime);
unsigned oldopts = cx->allOptions();
unsigned newopts = oldopts ^ options;
return SetOptionsCommon(cx, newopts);
@ -2896,7 +2888,6 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value)
{
switch (key) {
case JSGC_MAX_BYTES: {
AutoLockGC lock(rt);
JS_ASSERT(value >= rt->gcBytes);
rt->gcMaxBytes = value;
break;
@ -5523,20 +5514,8 @@ JS_GetOperationCallback(JSContext *cx)
}
JS_PUBLIC_API(void)
JS_TriggerOperationCallback(JSContext *cx)
JS_TriggerOperationCallback(JSRuntime *rt)
{
#ifdef JS_THREADSAFE
AutoLockGC lock(cx->runtime);
#endif
cx->runtime->triggerOperationCallback();
}
JS_PUBLIC_API(void)
JS_TriggerRuntimeOperationCallback(JSRuntime *rt)
{
#ifdef JS_THREADSAFE
AutoLockGC lock(rt);
#endif
rt->triggerOperationCallback();
}

Просмотреть файл

@ -4504,21 +4504,17 @@ JS_BEGIN_EXTERN_C
/*
* These functions allow setting an operation callback that will be called
* from the thread the context is associated with some time after any thread
* triggered the callback using JS_TriggerOperationCallback(cx).
* from the JS thread some time after any thread triggered the callback using
* JS_TriggerOperationCallback(rt).
*
* In a threadsafe build the engine internally triggers operation callbacks
* under certain circumstances (i.e. GC and title transfer) to force the
* context to yield its current request, which the engine always
* automatically does immediately prior to calling the callback function.
* The embedding should thus not rely on callbacks being triggered through
* the external API only.
* To schedule the GC and for other activities the engine internally triggers
* operation callbacks. The embedding should thus not rely on callbacks being
* triggered through the external API only.
*
* Important note: Additional callbacks can occur inside the callback handler
* if it re-enters the JS engine. The embedding must ensure that the callback
* is disconnected before attempting such re-entry.
*/
extern JS_PUBLIC_API(JSOperationCallback)
JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback);
@ -4526,10 +4522,7 @@ extern JS_PUBLIC_API(JSOperationCallback)
JS_GetOperationCallback(JSContext *cx);
extern JS_PUBLIC_API(void)
JS_TriggerOperationCallback(JSContext *cx);
extern JS_PUBLIC_API(void)
JS_TriggerRuntimeOperationCallback(JSRuntime *rt);
JS_TriggerOperationCallback(JSRuntime *rt);
extern JS_PUBLIC_API(JSBool)
JS_IsRunning(JSContext *cx);

Просмотреть файл

@ -118,7 +118,7 @@ JSRuntime::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, s
*gcMarkerSize = gcMarker.sizeOfExcludingThis(mallocSizeOf);
}
JS_FRIEND_API(void)
void
JSRuntime::triggerOperationCallback()
{
/*
@ -250,49 +250,48 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
}
}
JS_LOCK_GC(rt);
JS_REMOVE_LINK(&cx->link);
bool last = !rt->hasContexts();
if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC) {
if (last) {
JS_ASSERT(!rt->gcRunning);
#ifdef JS_THREADSAFE
rt->gcHelperThread.waitBackgroundSweepEnd();
#endif
JS_UNLOCK_GC(rt);
if (last) {
/*
* Dump remaining type inference results first. This printing
* depends on atoms still existing.
*/
{
AutoLockGC lock(rt);
for (CompartmentsIter c(rt); !c.done(); c.next())
c->types.print(cx, false);
}
/* Unpin all common atoms before final GC. */
js_FinishCommonAtoms(cx);
/* Clear debugging state to remove GC roots. */
for (CompartmentsIter c(rt); !c.done(); c.next())
c->clearTraps(cx);
JS_ClearAllWatchPoints(cx);
GC(cx, NULL, GC_NORMAL, gcreason::LAST_CONTEXT);
} else if (mode == JSDCM_FORCE_GC) {
GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
} else if (mode == JSDCM_MAYBE_GC) {
JS_MaybeGC(cx);
{
AutoLockGC lock(rt);
rt->gcHelperThread.waitBackgroundSweepEnd();
}
JS_LOCK_GC(rt);
}
#ifdef JS_THREADSAFE
rt->gcHelperThread.waitBackgroundSweepEnd();
#endif
JS_UNLOCK_GC(rt);
/*
* Dump remaining type inference results first. This printing
* depends on atoms still existing.
*/
for (CompartmentsIter c(rt); !c.done(); c.next())
c->types.print(cx, false);
/* Unpin all common atoms before final GC. */
js_FinishCommonAtoms(cx);
/* Clear debugging state to remove GC roots. */
for (CompartmentsIter c(rt); !c.done(); c.next())
c->clearTraps(cx);
JS_ClearAllWatchPoints(cx);
GC(cx, NULL, GC_NORMAL, gcreason::LAST_CONTEXT);
} else if (mode == JSDCM_FORCE_GC) {
JS_ASSERT(!rt->gcRunning);
GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
} else if (mode == JSDCM_MAYBE_GC) {
JS_ASSERT(!rt->gcRunning);
JS_MaybeGC(cx);
}
#ifdef JS_THREADSAFE
{
AutoLockGC lock(rt);
rt->gcHelperThread.waitBackgroundSweepEnd();
}
#endif
Foreground::delete_(cx);
}

Просмотреть файл

@ -686,7 +686,7 @@ struct JSRuntime : js::RuntimeFriendFields
*/
JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes, JSContext *cx);
JS_FRIEND_API(void) triggerOperationCallback();
void triggerOperationCallback();
void setJitHardening(bool enabled);
bool getJitHardening() const {
@ -1247,6 +1247,40 @@ class AutoXMLRooter : private AutoGCRooter {
# define JS_UNLOCK_GC(rt)
#endif
class AutoLockGC
{
public:
explicit AutoLockGC(JSRuntime *rt = NULL
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: runtime(rt)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (rt)
JS_LOCK_GC(rt);
}
~AutoLockGC()
{
if (runtime)
JS_UNLOCK_GC(runtime);
}
bool locked() const {
return !!runtime;
}
void lock(JSRuntime *rt) {
JS_ASSERT(rt);
JS_ASSERT(!runtime);
runtime = rt;
JS_LOCK_GC(rt);
}
private:
JSRuntime *runtime;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class AutoUnlockGC {
private:
JSRuntime *rt;

Просмотреть файл

@ -609,29 +609,6 @@ js::DumpHeapComplete(JSRuntime *rt, FILE *fp)
namespace js {
/* static */ void
AutoLockGC::LockGC(JSRuntime *rt)
{
JS_ASSERT(rt);
JS_LOCK_GC(rt);
}
/* static */ void
AutoLockGC::UnlockGC(JSRuntime *rt)
{
JS_ASSERT(rt);
JS_UNLOCK_GC(rt);
}
void
AutoLockGC::lock(JSRuntime *rt)
{
JS_ASSERT(rt);
JS_ASSERT(!runtime);
runtime = rt;
JS_LOCK_GC(rt);
}
JS_FRIEND_API(const JSStructuredCloneCallbacks *)
GetContextStructuredCloneCallbacks(JSContext *cx)
{
@ -674,12 +651,6 @@ GetContextOutstandingRequests(const JSContext *cx)
return cx->outstandingRequests;
}
JS_FRIEND_API(PRLock *)
GetRuntimeGCLock(const JSRuntime *rt)
{
return rt->gcLock;
}
AutoSkipConservativeScan::AutoSkipConservativeScan(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: context(cx)
@ -726,12 +697,6 @@ IsContextRunningJS(JSContext *cx)
return !cx->stack.empty();
}
JS_FRIEND_API(void)
TriggerOperationCallback(JSRuntime *rt)
{
rt->triggerOperationCallback();
}
JS_FRIEND_API(const CompartmentVector&)
GetRuntimeCompartments(JSRuntime *rt)
{

Просмотреть файл

@ -187,8 +187,6 @@ JS_END_EXTERN_C
#ifdef __cplusplus
struct PRLock;
namespace js {
struct ContextFriendFields {
@ -573,9 +571,6 @@ GetOwnerThread(const JSContext *cx);
JS_FRIEND_API(unsigned)
GetContextOutstandingRequests(const JSContext *cx);
JS_FRIEND_API(PRLock *)
GetRuntimeGCLock(const JSRuntime *rt);
class JS_FRIEND_API(AutoSkipConservativeScan)
{
public:
@ -600,43 +595,11 @@ typedef void
/*
* Sets a callback that is run whenever the runtime goes idle - the
* last active request ceases - and begins activity - when it was
* idle and a request begins. Note: The callback is called under the
* GC lock.
* idle and a request begins.
*/
JS_FRIEND_API(void)
SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg);
class JS_FRIEND_API(AutoLockGC)
{
public:
explicit AutoLockGC(JSRuntime *rt = NULL
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: runtime(rt)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (rt)
LockGC(rt);
}
~AutoLockGC()
{
if (runtime)
UnlockGC(runtime);
}
bool locked() const {
return !!runtime;
}
void lock(JSRuntime *rt);
private:
static void LockGC(JSRuntime *rt);
static void UnlockGC(JSRuntime *rt);
JSRuntime *runtime;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
extern JS_FRIEND_API(const JSStructuredCloneCallbacks *)
GetContextStructuredCloneCallbacks(JSContext *cx);
@ -652,10 +615,6 @@ CallContextDebugHandler(JSContext *cx, JSScript *script, jsbytecode *bc, Value *
extern JS_FRIEND_API(bool)
IsContextRunningJS(JSContext *cx);
/* Must be called with GC lock taken. */
extern JS_FRIEND_API(void)
TriggerOperationCallback(JSRuntime *rt);
class SystemAllocPolicy;
typedef Vector<JSCompartment*, 0, SystemAllocPolicy> CompartmentVector;
extern JS_FRIEND_API(const CompartmentVector&)

Просмотреть файл

@ -1308,15 +1308,6 @@ js_AddGCThingRoot(JSContext *cx, void **rp, const char *name)
JS_FRIEND_API(JSBool)
js_AddRootRT(JSRuntime *rt, jsval *vp, const char *name)
{
/*
* Due to the long-standing, but now removed, use of rt->gcLock across the
* bulk of js::GC, API users have come to depend on JS_AddRoot etc. locking
* properly with a racing GC, without calling JS_AddRoot from a request.
* We have to preserve API compatibility here, now that we avoid holding
* rt->gcLock across the mark phase (including the root hashtable mark).
*/
AutoLockGC lock(rt);
return !!rt->gcRootsHash.put((void *)vp,
RootInfo(name, JS_GC_ROOT_VALUE_PTR));
}
@ -1324,15 +1315,6 @@ js_AddRootRT(JSRuntime *rt, jsval *vp, const char *name)
JS_FRIEND_API(JSBool)
js_AddGCThingRootRT(JSRuntime *rt, void **rp, const char *name)
{
/*
* Due to the long-standing, but now removed, use of rt->gcLock across the
* bulk of js::GC, API users have come to depend on JS_AddRoot etc. locking
* properly with a racing GC, without calling JS_AddRoot from a request.
* We have to preserve API compatibility here, now that we avoid holding
* rt->gcLock across the mark phase (including the root hashtable mark).
*/
AutoLockGC lock(rt);
return !!rt->gcRootsHash.put((void *)rp,
RootInfo(name, JS_GC_ROOT_GCTHING_PTR));
}
@ -1340,11 +1322,6 @@ js_AddGCThingRootRT(JSRuntime *rt, void **rp, const char *name)
JS_FRIEND_API(JSBool)
js_RemoveRoot(JSRuntime *rt, void *rp)
{
/*
* Due to the JS_RemoveRootRT API, we may be called outside of a request.
* Same synchronization drill as above in js_AddRoot.
*/
AutoLockGC lock(rt);
rt->gcRootsHash.remove(rp);
rt->gcPoke = JS_TRUE;
return JS_TRUE;
@ -1404,7 +1381,6 @@ js_DumpNamedRoots(JSRuntime *rt,
uint32_t
js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
{
AutoLockGC lock(rt);
int ct = 0;
for (RootEnum e(rt->gcRootsHash); !e.empty(); e.popFront()) {
RootEntry &entry = e.front();
@ -1795,7 +1771,6 @@ js_LockGCThingRT(JSRuntime *rt, void *thing)
if (!thing)
return true;
AutoLockGC lock(rt);
if (GCLocks::Ptr p = rt->gcLocksHash.lookupWithDefault(thing, 0)) {
p->value++;
return true;
@ -1810,10 +1785,7 @@ js_UnlockGCThingRT(JSRuntime *rt, void *thing)
if (!thing)
return;
AutoLockGC lock(rt);
GCLocks::Ptr p = rt->gcLocksHash.lookup(thing);
if (p) {
if (GCLocks::Ptr p = rt->gcLocksHash.lookup(thing)) {
rt->gcPoke = true;
if (--p->value == 0)
rt->gcLocksHash.remove(p);
@ -2417,6 +2389,7 @@ MarkRuntime(JSTracer *trc, bool useSavedRoots = false)
}
}
}
void
TriggerGC(JSRuntime *rt, gcreason::Reason reason)
{
@ -2463,7 +2436,7 @@ TriggerCompartmentGC(JSCompartment *comp, gcreason::Reason reason)
rt->gcIsNeeded = true;
rt->gcTriggerCompartment = comp;
rt->gcTriggerReason = reason;
comp->rt->triggerOperationCallback();
rt->triggerOperationCallback();
}
void
@ -4516,7 +4489,6 @@ JS_FRIEND_API(void)
StartPCCountProfiling(JSContext *cx)
{
JSRuntime *rt = cx->runtime;
AutoLockGC lock(rt);
if (rt->profilingScripts)
return;
@ -4533,7 +4505,6 @@ JS_FRIEND_API(void)
StopPCCountProfiling(JSContext *cx)
{
JSRuntime *rt = cx->runtime;
AutoLockGC lock(rt);
if (!rt->profilingScripts)
return;
@ -4566,7 +4537,6 @@ JS_FRIEND_API(void)
PurgePCCounts(JSContext *cx)
{
JSRuntime *rt = cx->runtime;
AutoLockGC lock(rt);
if (!rt->scriptPCCounters)
return;
@ -4585,6 +4555,10 @@ JS_IterateCompartments(JSRuntime *rt, void *data,
AutoLockGC lock(rt);
AutoHeapSession session(rt);
#ifdef JS_THREADSAFE
rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
#endif
AutoUnlockGC unlock(rt);
for (CompartmentsIter c(rt); !c.done(); c.next())
(*compartmentCallback)(rt, data, c);

Просмотреть файл

@ -2179,17 +2179,6 @@ TypeCompartment::nukeTypes(JSContext *cx)
pendingRecompiles = NULL;
}
/*
* We may or may not be under the GC. In either case don't allocate, and
* acquire the GC lock so we can update inferenceEnabled for all contexts.
*/
#ifdef JS_THREADSAFE
AutoLockGC maybeLock;
if (!cx->runtime->gcRunning)
maybeLock.lock(cx->runtime);
#endif
inferenceEnabled = false;
/* Update the cached inferenceEnabled bit in all contexts. */

Просмотреть файл

@ -3134,7 +3134,7 @@ CancelExecution(JSRuntime *rt)
if (gWorkerThreadPool)
js::workers::terminateAll(gWorkerThreadPool);
#endif
JS_TriggerRuntimeOperationCallback(rt);
JS_TriggerOperationCallback(rt);
static const char msg[] = "Script runs for too long, terminating.\n";
#if defined(XP_UNIX) && !defined(JS_THREADSAFE)

Просмотреть файл

@ -827,7 +827,7 @@ class Worker MOZ_FINAL : public WorkerParent
AutoLock hold(lock);
terminateFlag = true;
if (current)
JS_TriggerOperationCallback(context);
JS_TriggerOperationCallback(runtime);
}
void notifyTerminating() {

Просмотреть файл

@ -429,7 +429,6 @@ Debugger::Debugger(JSContext *cx, JSObject *dbg)
assertSameCompartment(cx, dbg);
JSRuntime *rt = cx->runtime;
AutoLockGC lock(rt);
JS_APPEND_LINK(&link, &rt->debuggerList);
JS_INIT_CLIST(&breakpoints);
}

Просмотреть файл

@ -926,6 +926,20 @@ XPCJSRuntime::FinalizeCallback(JSContext *cx, JSFinalizeStatus status)
}
}
class AutoLockWatchdog {
XPCJSRuntime* const mRuntime;
public:
AutoLockWatchdog(XPCJSRuntime* aRuntime)
: mRuntime(aRuntime) {
PR_Lock(mRuntime->mWatchdogLock);
}
~AutoLockWatchdog() {
PR_Unlock(mRuntime->mWatchdogLock);
}
};
//static
void
XPCJSRuntime::WatchdogMain(void *arg)
@ -933,7 +947,7 @@ XPCJSRuntime::WatchdogMain(void *arg)
XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
// Lock lasts until we return
js::AutoLockGC lock(self->mJSRuntime);
AutoLockWatchdog lock(self);
PRIntervalTime sleepInterval;
while (self->mWatchdogThread) {
@ -944,12 +958,8 @@ XPCJSRuntime::WatchdogMain(void *arg)
sleepInterval = PR_INTERVAL_NO_TIMEOUT;
self->mWatchdogHibernating = true;
}
#ifdef DEBUG
PRStatus status =
#endif
PR_WaitCondVar(self->mWatchdogWakeup, sleepInterval);
JS_ASSERT(status == PR_SUCCESS);
js::TriggerOperationCallback(self->mJSRuntime);
MOZ_ALWAYS_TRUE(PR_WaitCondVar(self->mWatchdogWakeup, sleepInterval) == PR_SUCCESS);
JS_TriggerOperationCallback(self->mJSRuntime);
}
/* Wake up the main thread waiting for the watchdog to terminate. */
@ -961,6 +971,9 @@ void
XPCJSRuntime::ActivityCallback(void *arg, JSBool active)
{
XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
AutoLockWatchdog lock(self);
if (active) {
self->mLastActiveTime = -1;
if (self->mWatchdogHibernating) {
@ -1058,7 +1071,7 @@ XPCJSRuntime::~XPCJSRuntime()
// must release the lock before calling PR_DestroyCondVar, we use an
// extra block here.
{
js::AutoLockGC lock(mJSRuntime);
AutoLockWatchdog lock(this);
if (mWatchdogThread) {
mWatchdogThread = nsnull;
PR_NotifyCondVar(mWatchdogWakeup);
@ -1066,6 +1079,7 @@ XPCJSRuntime::~XPCJSRuntime()
}
}
PR_DestroyCondVar(mWatchdogWakeup);
PR_DestroyLock(mWatchdogLock);
mWatchdogWakeup = nsnull;
}
@ -2029,6 +2043,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
mVariantRoots(nsnull),
mWrappedJSRoots(nsnull),
mObjectHolderRoots(nsnull),
mWatchdogLock(nsnull),
mWatchdogWakeup(nsnull),
mWatchdogThread(nsnull),
mWatchdogHibernating(false),
@ -2053,47 +2068,40 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
if (!mJSRuntime)
NS_RUNTIMEABORT("JS_NewRuntime failed.");
{
// Unconstrain the runtime's threshold on nominal heap size, to avoid
// triggering GC too often if operating continuously near an arbitrary
// finite threshold (0xffffffff is infinity for uint32_t parameters).
// This leaves the maximum-JS_malloc-bytes threshold still in effect
// to cause period, and we hope hygienic, last-ditch GCs from within
// the GC's allocator.
JS_SetGCParameter(mJSRuntime, JSGC_MAX_BYTES, 0xffffffff);
// Unconstrain the runtime's threshold on nominal heap size, to avoid
// triggering GC too often if operating continuously near an arbitrary
// finite threshold (0xffffffff is infinity for uint32_t parameters).
// This leaves the maximum-JS_malloc-bytes threshold still in effect
// to cause period, and we hope hygienic, last-ditch GCs from within
// the GC's allocator.
JS_SetGCParameter(mJSRuntime, JSGC_MAX_BYTES, 0xffffffff);
#ifdef MOZ_ASAN
// ASan requires more stack space due to redzones
JS_SetNativeStackQuota(mJSRuntime, 2 * 128 * sizeof(size_t) * 1024);
// ASan requires more stack space due to redzones
JS_SetNativeStackQuota(mJSRuntime, 2 * 128 * sizeof(size_t) * 1024);
#else
JS_SetNativeStackQuota(mJSRuntime, 128 * sizeof(size_t) * 1024);
JS_SetNativeStackQuota(mJSRuntime, 128 * sizeof(size_t) * 1024);
#endif
JS_SetContextCallback(mJSRuntime, ContextCallback);
JS_SetCompartmentCallback(mJSRuntime, CompartmentCallback);
JS_SetGCCallback(mJSRuntime, GCCallback);
JS_SetFinalizeCallback(mJSRuntime, FinalizeCallback);
JS_SetExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this);
JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
JS_SetWrapObjectCallbacks(mJSRuntime,
xpc::WrapperFactory::Rewrap,
xpc::WrapperFactory::PrepareForWrapping);
js::SetPreserveWrapperCallback(mJSRuntime, PreserveWrapper);
JS_SetContextCallback(mJSRuntime, ContextCallback);
JS_SetCompartmentCallback(mJSRuntime, CompartmentCallback);
JS_SetGCCallback(mJSRuntime, GCCallback);
JS_SetFinalizeCallback(mJSRuntime, FinalizeCallback);
JS_SetExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this);
JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
JS_SetWrapObjectCallbacks(mJSRuntime,
xpc::WrapperFactory::Rewrap,
xpc::WrapperFactory::PrepareForWrapping);
js::SetPreserveWrapperCallback(mJSRuntime, PreserveWrapper);
#ifdef MOZ_CRASHREPORTER
JS_EnumerateDiagnosticMemoryRegions(DiagnosticMemoryCallback);
JS_EnumerateDiagnosticMemoryRegions(DiagnosticMemoryCallback);
#endif
JS_SetAccumulateTelemetryCallback(mJSRuntime, AccumulateTelemetryCallback);
mWatchdogWakeup = PR_NewCondVar(js::GetRuntimeGCLock(mJSRuntime));
if (!mWatchdogWakeup)
NS_RUNTIMEABORT("PR_NewCondVar failed.");
js::SetActivityCallback(mJSRuntime, ActivityCallback, this);
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
NS_RegisterMemoryMultiReporter(new JSMemoryMultiReporter);
NS_RegisterMemoryMultiReporter(new JSCompartmentsMultiReporter);
}
JS_SetAccumulateTelemetryCallback(mJSRuntime, AccumulateTelemetryCallback);
js::SetActivityCallback(mJSRuntime, ActivityCallback, this);
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
NS_RegisterMemoryMultiReporter(new JSMemoryMultiReporter);
NS_RegisterMemoryMultiReporter(new JSCompartmentsMultiReporter);
if (!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
sizeof(ObjectHolder), 512))
@ -2103,12 +2111,19 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
// Install a JavaScript 'debugger' keyword handler in debug builds only
#ifdef DEBUG
if (mJSRuntime && !JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler)
if (!JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler)
xpc_InstallJSDebuggerKeywordHandler(mJSRuntime);
#endif
if (mWatchdogWakeup) {
js::AutoLockGC lock(mJSRuntime);
mWatchdogLock = PR_NewLock();
if (!mWatchdogLock)
NS_RUNTIMEABORT("PR_NewLock failed.");
mWatchdogWakeup = PR_NewCondVar(mWatchdogLock);
if (!mWatchdogWakeup)
NS_RUNTIMEABORT("PR_NewCondVar failed.");
{
AutoLockWatchdog lock(this);
mWatchdogThread = PR_CreateThread(PR_USER_THREAD, WatchdogMain, this,
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,

Просмотреть файл

@ -837,11 +837,14 @@ private:
XPCRootSetElem *mWrappedJSRoots;
XPCRootSetElem *mObjectHolderRoots;
JSDHashTable mJSHolders;
PRLock *mWatchdogLock;
PRCondVar *mWatchdogWakeup;
PRThread *mWatchdogThread;
nsTArray<JSGCCallback> extraGCCallbacks;
bool mWatchdogHibernating;
PRTime mLastActiveTime; // -1 if active NOW
friend class AutoLockWatchdog;
};
/***************************************************************************/