зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
56ec12d66e
Коммит
c5c7623497
|
@ -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;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
|
Загрузка…
Ссылка в новой задаче