зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset e74857ea8248 - this caused unit test failures on Mac
This commit is contained in:
Родитель
4b9a729294
Коммит
a741088d8f
|
@ -854,8 +854,24 @@ PrintWinCodebase(nsGlobalWindow *win)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The accumulated operation weight for DOM callback.
|
// The accumulated operation weight before we call MaybeGC
|
||||||
const PRUint32 DOM_CALLBACK_OPERATION_WEIGHT = 5000 * JS_OPERATION_WEIGHT_BASE;
|
const PRUint32 MAYBE_GC_OPERATION_WEIGHT = 5000 * JS_OPERATION_WEIGHT_BASE;
|
||||||
|
|
||||||
|
static void
|
||||||
|
MaybeGC(JSContext *cx)
|
||||||
|
{
|
||||||
|
size_t bytes = cx->runtime->gcBytes;
|
||||||
|
size_t lastBytes = cx->runtime->gcLastBytes;
|
||||||
|
|
||||||
|
if ((bytes > 8192 && bytes / 16 > lastBytes)
|
||||||
|
#ifdef DEBUG
|
||||||
|
|| cx->runtime->gcZeal > 0
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
++sGCCount;
|
||||||
|
JS_GC(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static already_AddRefed<nsIPrompt>
|
static already_AddRefed<nsIPrompt>
|
||||||
GetPromptFromContext(nsJSContext* ctx)
|
GetPromptFromContext(nsJSContext* ctx)
|
||||||
|
@ -888,8 +904,17 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX Save the operation callback time so we can restore it after the GC,
|
||||||
|
// because GCing can cause JS to run on our context, causing our
|
||||||
|
// ScriptEvaluated to be called, and clearing our operation callback time.
|
||||||
|
// See bug 302333.
|
||||||
PRTime callbackTime = ctx->mOperationCallbackTime;
|
PRTime callbackTime = ctx->mOperationCallbackTime;
|
||||||
|
|
||||||
|
MaybeGC(cx);
|
||||||
|
|
||||||
|
// Now restore the callback time and count, in case they got reset.
|
||||||
|
ctx->mOperationCallbackTime = callbackTime;
|
||||||
|
|
||||||
// Check to see if we are running OOM
|
// Check to see if we are running OOM
|
||||||
nsCOMPtr<nsIMemory> mem;
|
nsCOMPtr<nsIMemory> mem;
|
||||||
NS_GetMemoryManager(getter_AddRefs(mem));
|
NS_GetMemoryManager(getter_AddRefs(mem));
|
||||||
|
@ -911,24 +936,24 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
|
||||||
|
|
||||||
if (nsContentUtils::GetBoolPref("dom.prevent_oom_dialog", PR_FALSE))
|
if (nsContentUtils::GetBoolPref("dom.prevent_oom_dialog", PR_FALSE))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
nsCOMPtr<nsIPrompt> prompt = GetPromptFromContext(ctx);
|
nsCOMPtr<nsIPrompt> prompt = GetPromptFromContext(ctx);
|
||||||
|
|
||||||
nsXPIDLString title, msg;
|
nsXPIDLString title, msg;
|
||||||
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||||
"LowMemoryTitle",
|
"LowMemoryTitle",
|
||||||
title);
|
title);
|
||||||
|
|
||||||
rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||||
"LowMemoryMessage",
|
"LowMemoryMessage",
|
||||||
msg);
|
msg);
|
||||||
|
|
||||||
//GetStringFromName can return NS_OK and still give NULL string
|
//GetStringFromName can return NS_OK and still give NULL string
|
||||||
if (NS_FAILED(rv) || !title || !msg) {
|
if (NS_FAILED(rv) || !title || !msg) {
|
||||||
NS_ERROR("Failed to get localized strings.");
|
NS_ERROR("Failed to get localized strings.");
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
prompt->Alert(title, msg);
|
prompt->Alert(title, msg);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1226,7 +1251,7 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
|
||||||
this);
|
this);
|
||||||
|
|
||||||
::JS_SetOperationCallback(mContext, DOMOperationCallback,
|
::JS_SetOperationCallback(mContext, DOMOperationCallback,
|
||||||
DOM_CALLBACK_OPERATION_WEIGHT);
|
MAYBE_GC_OPERATION_WEIGHT);
|
||||||
|
|
||||||
static JSLocaleCallbacks localeCallbacks =
|
static JSLocaleCallbacks localeCallbacks =
|
||||||
{
|
{
|
||||||
|
@ -1239,6 +1264,7 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
|
||||||
::JS_SetLocaleCallbacks(mContext, &localeCallbacks);
|
::JS_SetLocaleCallbacks(mContext, &localeCallbacks);
|
||||||
}
|
}
|
||||||
mIsInitialized = PR_FALSE;
|
mIsInitialized = PR_FALSE;
|
||||||
|
mNumEvaluations = 0;
|
||||||
mTerminations = nsnull;
|
mTerminations = nsnull;
|
||||||
mScriptsEnabled = PR_TRUE;
|
mScriptsEnabled = PR_TRUE;
|
||||||
mOperationCallbackTime = LL_ZERO;
|
mOperationCallbackTime = LL_ZERO;
|
||||||
|
@ -3286,6 +3312,18 @@ nsJSContext::ScriptEvaluated(PRBool aTerminated)
|
||||||
delete start;
|
delete start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mNumEvaluations++;
|
||||||
|
|
||||||
|
#ifdef JS_GC_ZEAL
|
||||||
|
if (mContext->runtime->gcZeal >= 2) {
|
||||||
|
MaybeGC(mContext);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (mNumEvaluations > 20) {
|
||||||
|
mNumEvaluations = 0;
|
||||||
|
MaybeGC(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
if (aTerminated) {
|
if (aTerminated) {
|
||||||
mOperationCallbackTime = LL_ZERO;
|
mOperationCallbackTime = LL_ZERO;
|
||||||
}
|
}
|
||||||
|
@ -3372,29 +3410,19 @@ nsJSContext::CC()
|
||||||
#endif
|
#endif
|
||||||
sPreviousCCTime = PR_Now();
|
sPreviousCCTime = PR_Now();
|
||||||
sDelayedCCollectCount = 0;
|
sDelayedCCollectCount = 0;
|
||||||
sGCCount = JS_GetGCParameter(nsJSRuntime::sRuntime, JSGC_NUMBER);
|
sGCCount = 0;
|
||||||
sCCSuspectChanges = 0;
|
sCCSuspectChanges = 0;
|
||||||
// nsCycleCollector_collect() will run a ::JS_GC() indirectly, so
|
// nsCycleCollector_collect() will run a ::JS_GC() indirectly, so
|
||||||
// we do not explicitly call ::JS_GC() here.
|
// we do not explicitly call ::JS_GC() here.
|
||||||
sCollectedObjectsCounts = nsCycleCollector_collect();
|
sCollectedObjectsCounts = nsCycleCollector_collect();
|
||||||
sCCSuspectedCount = nsCycleCollector_suspectedCount();
|
sCCSuspectedCount = nsCycleCollector_suspectedCount();
|
||||||
#ifdef DEBUG_smaug
|
#ifdef DEBUG_smaug
|
||||||
printf("Collected %u objects, %u suspected objects\n",
|
printf("Collected %u objects, %u suspected objects, took %lldms\n",
|
||||||
sCollectedObjectsCounts, sCCSuspectedCount);
|
sCollectedObjectsCounts, sCCSuspectedCount,
|
||||||
|
(PR_Now() - sPreviousCCTime) / PR_USEC_PER_MSEC);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32
|
|
||||||
GetGCRunsCount()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The result value may overflow if sGCCount is close to the uint32
|
|
||||||
* maximum. It may cause additional invocations of the CC, which may
|
|
||||||
* reduce performance but cannot breach security.
|
|
||||||
*/
|
|
||||||
return JS_GetGCParameter(nsJSRuntime::sRuntime, JSGC_NUMBER) - sGCCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
//static
|
//static
|
||||||
PRBool
|
PRBool
|
||||||
nsJSContext::MaybeCC(PRBool aHigherProbability)
|
nsJSContext::MaybeCC(PRBool aHigherProbability)
|
||||||
|
@ -3403,7 +3431,7 @@ nsJSContext::MaybeCC(PRBool aHigherProbability)
|
||||||
|
|
||||||
// Don't check suspected count if CC will be called anyway.
|
// Don't check suspected count if CC will be called anyway.
|
||||||
if (sCCSuspectChanges <= NS_MIN_SUSPECT_CHANGES ||
|
if (sCCSuspectChanges <= NS_MIN_SUSPECT_CHANGES ||
|
||||||
GetGCRunsCount() <= NS_MAX_GC_COUNT) {
|
sGCCount <= NS_MAX_GC_COUNT) {
|
||||||
#ifdef DEBUG_smaug
|
#ifdef DEBUG_smaug
|
||||||
PRTime now = PR_Now();
|
PRTime now = PR_Now();
|
||||||
#endif
|
#endif
|
||||||
|
@ -3421,8 +3449,7 @@ nsJSContext::MaybeCC(PRBool aHigherProbability)
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_smaug
|
#ifdef DEBUG_smaug
|
||||||
printf("sCCSuspectChanges %u, sGCCount %u\n",
|
printf("sCCSuspectChanges %u, sGCCount %u\n",
|
||||||
sCCSuspectChanges,
|
sCCSuspectChanges, sGCCount);
|
||||||
GetGCRunsCount());
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Increase the probability also if the previous call to cycle collector
|
// Increase the probability also if the previous call to cycle collector
|
||||||
|
@ -3435,7 +3462,7 @@ nsJSContext::MaybeCC(PRBool aHigherProbability)
|
||||||
if (!sGCTimer &&
|
if (!sGCTimer &&
|
||||||
(sDelayedCCollectCount > NS_MAX_DELAYED_CCOLLECT) &&
|
(sDelayedCCollectCount > NS_MAX_DELAYED_CCOLLECT) &&
|
||||||
((sCCSuspectChanges > NS_MIN_SUSPECT_CHANGES &&
|
((sCCSuspectChanges > NS_MIN_SUSPECT_CHANGES &&
|
||||||
GetGCRunsCount() > NS_MAX_GC_COUNT) ||
|
sGCCount > NS_MAX_GC_COUNT) ||
|
||||||
(sCCSuspectChanges > NS_MAX_SUSPECT_CHANGES))) {
|
(sCCSuspectChanges > NS_MAX_SUSPECT_CHANGES))) {
|
||||||
if ((PR_Now() - sPreviousCCTime) >=
|
if ((PR_Now() - sPreviousCCTime) >=
|
||||||
PRTime(NS_MIN_CC_INTERVAL * PR_USEC_PER_MSEC)) {
|
PRTime(NS_MIN_CC_INTERVAL * PR_USEC_PER_MSEC)) {
|
||||||
|
|
|
@ -223,6 +223,7 @@ private:
|
||||||
void Unlink();
|
void Unlink();
|
||||||
|
|
||||||
JSContext *mContext;
|
JSContext *mContext;
|
||||||
|
PRUint32 mNumEvaluations;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct TerminationFuncHolder;
|
struct TerminationFuncHolder;
|
||||||
|
@ -275,7 +276,7 @@ protected:
|
||||||
nsJSContext* mContext;
|
nsJSContext* mContext;
|
||||||
TerminationFuncClosure* mTerminations;
|
TerminationFuncClosure* mTerminations;
|
||||||
};
|
};
|
||||||
|
|
||||||
TerminationFuncClosure* mTerminations;
|
TerminationFuncClosure* mTerminations;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -321,7 +322,7 @@ public:
|
||||||
|
|
||||||
virtual nsresult DropScriptObject(void *object);
|
virtual nsresult DropScriptObject(void *object);
|
||||||
virtual nsresult HoldScriptObject(void *object);
|
virtual nsresult HoldScriptObject(void *object);
|
||||||
|
|
||||||
static void Startup();
|
static void Startup();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
// Setup all the statics etc - safe to call multiple times after Startup()
|
// Setup all the statics etc - safe to call multiple times after Startup()
|
||||||
|
|
|
@ -2595,31 +2595,6 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
|
||||||
case JSGC_STACKPOOL_LIFESPAN:
|
case JSGC_STACKPOOL_LIFESPAN:
|
||||||
rt->gcEmptyArenaPoolLifespan = value;
|
rt->gcEmptyArenaPoolLifespan = value;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
|
|
||||||
JS_ASSERT(value >= 100);
|
|
||||||
rt->gcTriggerFactor = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_PUBLIC_API(uint32)
|
|
||||||
JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
|
|
||||||
{
|
|
||||||
switch (key) {
|
|
||||||
case JSGC_MAX_BYTES:
|
|
||||||
return rt->gcMaxBytes;
|
|
||||||
case JSGC_MAX_MALLOC_BYTES:
|
|
||||||
return rt->gcMaxMallocBytes;
|
|
||||||
case JSGC_STACKPOOL_LIFESPAN:
|
|
||||||
return rt->gcEmptyArenaPoolLifespan;
|
|
||||||
case JSGC_TRIGGER_FACTOR:
|
|
||||||
return rt->gcTriggerFactor;
|
|
||||||
case JSGC_BYTES:
|
|
||||||
return rt->gcBytes;
|
|
||||||
default:
|
|
||||||
JS_ASSERT(key == JSGC_NUMBER);
|
|
||||||
return rt->gcNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3837,7 +3812,7 @@ JS_HasUCProperty(JSContext *cx, JSObject *obj,
|
||||||
JSProperty *prop;
|
JSProperty *prop;
|
||||||
|
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
ok = LookupUCProperty(cx, obj, name, namelen,
|
ok = LookupUCProperty(cx, obj, name, namelen,
|
||||||
JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
|
JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
|
||||||
&obj2, &prop);
|
&obj2, &prop);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
|
|
|
@ -1137,31 +1137,12 @@ typedef enum JSGCParamKey {
|
||||||
JSGC_MAX_MALLOC_BYTES = 1,
|
JSGC_MAX_MALLOC_BYTES = 1,
|
||||||
|
|
||||||
/* Hoard stackPools for this long, in ms, default is 30 seconds. */
|
/* Hoard stackPools for this long, in ms, default is 30 seconds. */
|
||||||
JSGC_STACKPOOL_LIFESPAN = 2,
|
JSGC_STACKPOOL_LIFESPAN = 2
|
||||||
|
|
||||||
/*
|
|
||||||
* The factor that defines when the GC is invoked. The factor is a
|
|
||||||
* percent of the memory allocated by the GC after the last run of
|
|
||||||
* the GC. When the current memory allocated by the GC is more than
|
|
||||||
* this percent then the GC is invoked. The factor cannot be less
|
|
||||||
* than 100 since the current memory allocated by the GC cannot be less
|
|
||||||
* than the memory allocated after the last run of the GC.
|
|
||||||
*/
|
|
||||||
JSGC_TRIGGER_FACTOR = 3,
|
|
||||||
|
|
||||||
/* Amount of bytes allocated by the GC. */
|
|
||||||
JSGC_BYTES = 4,
|
|
||||||
|
|
||||||
/* Number of times when GC was invoked. */
|
|
||||||
JSGC_NUMBER = 5
|
|
||||||
} JSGCParamKey;
|
} JSGCParamKey;
|
||||||
|
|
||||||
extern JS_PUBLIC_API(void)
|
extern JS_PUBLIC_API(void)
|
||||||
JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value);
|
JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value);
|
||||||
|
|
||||||
extern JS_PUBLIC_API(uint32)
|
|
||||||
JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a finalizer for external strings created by JS_NewExternalString (see
|
* Add a finalizer for external strings created by JS_NewExternalString (see
|
||||||
* below) using a type-code returned from this function, and that understands
|
* below) using a type-code returned from this function, and that understands
|
||||||
|
|
|
@ -267,7 +267,6 @@ struct JSRuntime {
|
||||||
uint32 gcLevel;
|
uint32 gcLevel;
|
||||||
uint32 gcNumber;
|
uint32 gcNumber;
|
||||||
JSTracer *gcMarkingTracer;
|
JSTracer *gcMarkingTracer;
|
||||||
uint32 gcTriggerFactor;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NB: do not pack another flag here by claiming gcPadding unless the new
|
* NB: do not pack another flag here by claiming gcPadding unless the new
|
||||||
|
|
|
@ -1253,18 +1253,6 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
|
||||||
rt->gcMaxBytes = rt->gcMaxMallocBytes = maxbytes;
|
rt->gcMaxBytes = rt->gcMaxMallocBytes = maxbytes;
|
||||||
rt->gcEmptyArenaPoolLifespan = 30000;
|
rt->gcEmptyArenaPoolLifespan = 30000;
|
||||||
|
|
||||||
/*
|
|
||||||
* By default the trigger factor gets maximum possible value. This
|
|
||||||
* means that GC will not be triggered by growth of GC memory (gcBytes).
|
|
||||||
*/
|
|
||||||
rt->gcTriggerFactor = (uint32) -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The assigned value prevents GC from running when GC memory is too low
|
|
||||||
* (during JS engine start).
|
|
||||||
*/
|
|
||||||
rt->gcLastBytes = 8192;
|
|
||||||
|
|
||||||
METER(memset(&rt->gcStats, 0, sizeof rt->gcStats));
|
METER(memset(&rt->gcStats, 0, sizeof rt->gcStats));
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1769,17 +1757,6 @@ EnsureLocalFreeList(JSContext *cx)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static JS_INLINE JSBool
|
|
||||||
IsGCThresholdReached(JSRuntime *rt)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Since the initial value of the gcLastBytes parameter is not equal to
|
|
||||||
* zero (see the js_InitGC function) the return value is false when
|
|
||||||
* the gcBytes value is close to zero at the JS engine start.
|
|
||||||
*/
|
|
||||||
return rt->gcBytes / rt->gcTriggerFactor >= rt->gcLastBytes / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
|
js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
|
||||||
{
|
{
|
||||||
|
@ -1846,8 +1823,7 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
doGC = (rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke) ||
|
doGC = (rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke);
|
||||||
IsGCThresholdReached(rt);
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
doGC = doGC || rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke);
|
doGC = doGC || rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke);
|
||||||
# ifdef JS_TRACER
|
# ifdef JS_TRACER
|
||||||
|
@ -2080,10 +2056,9 @@ RefillDoubleFreeList(JSContext *cx)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke) ||
|
if (rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke
|
||||||
IsGCThresholdReached(rt)
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
|| (rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke))
|
&& (rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke))
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
goto do_gc;
|
goto do_gc;
|
||||||
|
@ -2282,8 +2257,7 @@ js_AddAsGCBytes(JSContext *cx, size_t sz)
|
||||||
|
|
||||||
rt = cx->runtime;
|
rt = cx->runtime;
|
||||||
if (rt->gcBytes >= rt->gcMaxBytes ||
|
if (rt->gcBytes >= rt->gcMaxBytes ||
|
||||||
sz > (size_t) (rt->gcMaxBytes - rt->gcBytes) ||
|
sz > (size_t) (rt->gcMaxBytes - rt->gcBytes)
|
||||||
IsGCThresholdReached(rt)
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
|| rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke)
|
|| rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -229,6 +229,9 @@ struct JSShellContextData {
|
||||||
PRIntervalTime timeout;
|
PRIntervalTime timeout;
|
||||||
volatile PRIntervalTime startTime; /* startTime + timeout is time when
|
volatile PRIntervalTime startTime; /* startTime + timeout is time when
|
||||||
script must be stopped */
|
script must be stopped */
|
||||||
|
PRIntervalTime maybeGCPeriod;
|
||||||
|
volatile PRIntervalTime lastMaybeGCTime;/* lastMaybeGCTime + maybeGCPeriod
|
||||||
|
is the time to call MaybeGC */
|
||||||
PRIntervalTime yieldPeriod;
|
PRIntervalTime yieldPeriod;
|
||||||
volatile PRIntervalTime lastYieldTime; /* lastYieldTime + yieldPeriod is
|
volatile PRIntervalTime lastYieldTime; /* lastYieldTime + yieldPeriod is
|
||||||
the time to call
|
the time to call
|
||||||
|
@ -236,6 +239,7 @@ struct JSShellContextData {
|
||||||
#else
|
#else
|
||||||
int64 stopTime; /* time when script must be
|
int64 stopTime; /* time when script must be
|
||||||
stopped */
|
stopped */
|
||||||
|
int64 nextMaybeGCTime;/* time to call JS_MaybeGC */
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -245,6 +249,7 @@ SetTimeoutValue(JSContext *cx, jsdouble t);
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
|
|
||||||
# define DEFAULT_YIELD_PERIOD() (PR_TicksPerSecond() / 50)
|
# define DEFAULT_YIELD_PERIOD() (PR_TicksPerSecond() / 50)
|
||||||
|
# define DEFAULT_MAYBEGC_PERIOD() (PR_TicksPerSecond() / 10)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The function assumes that the GC lock is already held on entry. On a
|
* The function assumes that the GC lock is already held on entry. On a
|
||||||
|
@ -256,6 +261,8 @@ RescheduleWatchdog(JSContext *cx, JSShellContextData *data, PRIntervalTime now);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
# define DEFAULT_MAYBEGC_PERIOD() (MICROSECONDS_PER_SECOND / 10)
|
||||||
|
|
||||||
const int64 MICROSECONDS_PER_SECOND = 1000000LL;
|
const int64 MICROSECONDS_PER_SECOND = 1000000LL;
|
||||||
const int64 MAX_TIME_VALUE = 0x7FFFFFFFFFFFFFFFLL;
|
const int64 MAX_TIME_VALUE = 0x7FFFFFFFFFFFFFFFLL;
|
||||||
|
|
||||||
|
@ -270,13 +277,16 @@ NewContextData()
|
||||||
return NULL;
|
return NULL;
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
data->timeout = PR_INTERVAL_NO_TIMEOUT;
|
data->timeout = PR_INTERVAL_NO_TIMEOUT;
|
||||||
|
data->maybeGCPeriod = PR_INTERVAL_NO_TIMEOUT;
|
||||||
data->yieldPeriod = PR_INTERVAL_NO_TIMEOUT;
|
data->yieldPeriod = PR_INTERVAL_NO_TIMEOUT;
|
||||||
# ifdef DEBUG
|
# ifdef DEBUG
|
||||||
data->startTime = 0;
|
data->startTime = 0;
|
||||||
|
data->lastMaybeGCTime = 0;
|
||||||
data->lastYieldTime = 0;
|
data->lastYieldTime = 0;
|
||||||
# endif
|
# endif
|
||||||
#else /* !JS_THREADSAFE */
|
#else /* !JS_THREADSAFE */
|
||||||
data->stopTime = MAX_TIME_VALUE;
|
data->stopTime = MAX_TIME_VALUE;
|
||||||
|
data->nextMaybeGCTime = MAX_TIME_VALUE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -296,6 +306,7 @@ ShellOperationCallback(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSShellContextData *data = GetContextData(cx);
|
JSShellContextData *data = GetContextData(cx);
|
||||||
JSBool doStop;
|
JSBool doStop;
|
||||||
|
JSBool doMaybeGC;
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JSBool doYield;
|
JSBool doYield;
|
||||||
PRIntervalTime now = PR_IntervalNow();
|
PRIntervalTime now = PR_IntervalNow();
|
||||||
|
@ -303,6 +314,11 @@ ShellOperationCallback(JSContext *cx)
|
||||||
doStop = (data->timeout != PR_INTERVAL_NO_TIMEOUT &&
|
doStop = (data->timeout != PR_INTERVAL_NO_TIMEOUT &&
|
||||||
now - data->startTime >= data->timeout);
|
now - data->startTime >= data->timeout);
|
||||||
|
|
||||||
|
doMaybeGC = (data->maybeGCPeriod != PR_INTERVAL_NO_TIMEOUT &&
|
||||||
|
now - data->lastMaybeGCTime >= data->maybeGCPeriod);
|
||||||
|
if (doMaybeGC)
|
||||||
|
data->lastMaybeGCTime = now;
|
||||||
|
|
||||||
doYield = (data->yieldPeriod != PR_INTERVAL_NO_TIMEOUT &&
|
doYield = (data->yieldPeriod != PR_INTERVAL_NO_TIMEOUT &&
|
||||||
now - data->lastYieldTime >= data->yieldPeriod);
|
now - data->lastYieldTime >= data->yieldPeriod);
|
||||||
if (doYield)
|
if (doYield)
|
||||||
|
@ -312,6 +328,9 @@ ShellOperationCallback(JSContext *cx)
|
||||||
int64 now = JS_Now();
|
int64 now = JS_Now();
|
||||||
|
|
||||||
doStop = (now >= data->stopTime);
|
doStop = (now >= data->stopTime);
|
||||||
|
doMaybeGC = (now >= data->nextMaybeGCTime);
|
||||||
|
if (doMaybeGC)
|
||||||
|
data->nextMaybeGCTime = now + DEFAULT_MAYBEGC_PERIOD();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (doStop) {
|
if (doStop) {
|
||||||
|
@ -319,6 +338,9 @@ ShellOperationCallback(JSContext *cx)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (doMaybeGC)
|
||||||
|
JS_MaybeGC(cx);
|
||||||
|
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
if (doYield)
|
if (doYield)
|
||||||
JS_YieldRequest(cx);
|
JS_YieldRequest(cx);
|
||||||
|
@ -1068,49 +1090,24 @@ GCParameter(JSContext *cx, uintN argc, jsval *vp)
|
||||||
param = JSGC_MAX_BYTES;
|
param = JSGC_MAX_BYTES;
|
||||||
} else if (strcmp(paramName, "maxMallocBytes") == 0) {
|
} else if (strcmp(paramName, "maxMallocBytes") == 0) {
|
||||||
param = JSGC_MAX_MALLOC_BYTES;
|
param = JSGC_MAX_MALLOC_BYTES;
|
||||||
} else if (strcmp(paramName, "gcStackpoolLifespan") == 0) {
|
|
||||||
param = JSGC_STACKPOOL_LIFESPAN;
|
|
||||||
} else if (strcmp(paramName, "gcBytes") == 0) {
|
|
||||||
param = JSGC_BYTES;
|
|
||||||
} else if (strcmp(paramName, "gcNumber") == 0) {
|
|
||||||
param = JSGC_NUMBER;
|
|
||||||
} else if (strcmp(paramName, "gcTriggerFactor") == 0) {
|
|
||||||
param = JSGC_TRIGGER_FACTOR;
|
|
||||||
} else {
|
} else {
|
||||||
JS_ReportError(cx,
|
JS_ReportError(cx,
|
||||||
"the first argument argument must be maxBytes, "
|
"the first argument argument must be either maxBytes "
|
||||||
"maxMallocBytes, gcStackpoolLifespan, gcBytes, "
|
"or maxMallocBytes");
|
||||||
"gcNumber or gcTriggerFactor");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 1) {
|
if (!JS_ValueToECMAUint32(cx, argc < 2 ? JSVAL_VOID : vp[3], &value))
|
||||||
value = JS_GetGCParameter(cx->runtime, param);
|
|
||||||
return JS_NewNumberValue(cx, value, &vp[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param == JSGC_NUMBER ||
|
|
||||||
param == JSGC_BYTES) {
|
|
||||||
JS_ReportError(cx, "Attempt to change read-only parameter %s",
|
|
||||||
paramName);
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
if (value == 0) {
|
||||||
|
|
||||||
if (!JS_ValueToECMAUint32(cx, vp[3], &value)) {
|
|
||||||
JS_ReportError(cx,
|
JS_ReportError(cx,
|
||||||
"the second argument must be convertable to uint32 "
|
"the second argument must be convertable to uint32 with "
|
||||||
"with non-zero value");
|
"non-zero value");
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
if (param == JSGC_TRIGGER_FACTOR && value < 100) {
|
|
||||||
JS_ReportError(cx,
|
|
||||||
"the gcTriggerFactor value must be >= 100");
|
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
JS_SetGCParameter(cx->runtime, param, value);
|
JS_SetGCParameter(cx->runtime, param, value);
|
||||||
*vp = JSVAL_VOID;
|
*vp = JSVAL_VOID;
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
|
@ -3145,6 +3142,8 @@ CheckCallbackTime(JSContext *cx, JSShellContextData *data, PRIntervalTime now,
|
||||||
|
|
||||||
UpdateSleepDuration(now, data->startTime, data->timeout,
|
UpdateSleepDuration(now, data->startTime, data->timeout,
|
||||||
sleepDuration, expired);
|
sleepDuration, expired);
|
||||||
|
UpdateSleepDuration(now, data->lastMaybeGCTime, data->maybeGCPeriod,
|
||||||
|
sleepDuration, expired);
|
||||||
UpdateSleepDuration(now, data->lastYieldTime, data->yieldPeriod,
|
UpdateSleepDuration(now, data->lastYieldTime, data->yieldPeriod,
|
||||||
sleepDuration, expired);
|
sleepDuration, expired);
|
||||||
if (expired) {
|
if (expired) {
|
||||||
|
@ -3248,15 +3247,24 @@ SetTimeoutValue(JSContext *cx, jsdouble t)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For compatibility periodic MaybeGC calls are enabled only when the
|
||||||
|
* execution time is bounded.
|
||||||
|
*/
|
||||||
JSShellContextData *data = GetContextData(cx);
|
JSShellContextData *data = GetContextData(cx);
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
JS_LOCK_GC(cx->runtime);
|
JS_LOCK_GC(cx->runtime);
|
||||||
if (t < 0) {
|
if (t < 0) {
|
||||||
data->timeout = PR_INTERVAL_NO_TIMEOUT;
|
data->timeout = PR_INTERVAL_NO_TIMEOUT;
|
||||||
|
data->maybeGCPeriod = PR_INTERVAL_NO_TIMEOUT;
|
||||||
} else {
|
} else {
|
||||||
PRIntervalTime now = PR_IntervalNow();
|
PRIntervalTime now = PR_IntervalNow();
|
||||||
data->timeout = PRIntervalTime(t * PR_TicksPerSecond());
|
data->timeout = PRIntervalTime(t * PR_TicksPerSecond());
|
||||||
data->startTime = now;
|
data->startTime = now;
|
||||||
|
if (data->maybeGCPeriod == PR_INTERVAL_NO_TIMEOUT) {
|
||||||
|
data->maybeGCPeriod = DEFAULT_MAYBEGC_PERIOD();
|
||||||
|
data->lastMaybeGCTime = now;
|
||||||
|
}
|
||||||
if (!RescheduleWatchdog(cx, data, now)) {
|
if (!RescheduleWatchdog(cx, data, now)) {
|
||||||
/* The GC lock is already released here. */
|
/* The GC lock is already released here. */
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
@ -3267,10 +3275,13 @@ SetTimeoutValue(JSContext *cx, jsdouble t)
|
||||||
#else /* !JS_THREADSAFE */
|
#else /* !JS_THREADSAFE */
|
||||||
if (t < 0) {
|
if (t < 0) {
|
||||||
data->stopTime = MAX_TIME_VALUE;
|
data->stopTime = MAX_TIME_VALUE;
|
||||||
|
data->nextMaybeGCTime = MAX_TIME_VALUE;
|
||||||
JS_SetOperationLimit(cx, JS_MAX_OPERATION_LIMIT);
|
JS_SetOperationLimit(cx, JS_MAX_OPERATION_LIMIT);
|
||||||
} else {
|
} else {
|
||||||
int64 now = JS_Now();
|
int64 now = JS_Now();
|
||||||
data->stopTime = now + int64(t * MICROSECONDS_PER_SECOND);
|
data->stopTime = now + int64(t * MICROSECONDS_PER_SECOND);
|
||||||
|
if (data->nextMaybeGCTime == MAX_TIME_VALUE)
|
||||||
|
data->nextMaybeGCTime = now + DEFAULT_MAYBEGC_PERIOD();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call the callback infrequently enough to avoid the overhead of
|
* Call the callback infrequently enough to avoid the overhead of
|
||||||
|
|
|
@ -1572,10 +1572,6 @@ main(int argc, char **argv, char **envp)
|
||||||
|
|
||||||
gOldJSContextCallback = JS_SetContextCallback(rt, ContextCallback);
|
gOldJSContextCallback = JS_SetContextCallback(rt, ContextCallback);
|
||||||
|
|
||||||
//Set the GC trigger factor back to the initial value.
|
|
||||||
//See the bug 474312.
|
|
||||||
JS_SetGCParameter(rt, JSGC_TRIGGER_FACTOR, (uint32) -1);
|
|
||||||
|
|
||||||
cx = JS_NewContext(rt, 8192);
|
cx = JS_NewContext(rt, 8192);
|
||||||
if (!cx) {
|
if (!cx) {
|
||||||
printf("JS_NewContext failed!\n");
|
printf("JS_NewContext failed!\n");
|
||||||
|
|
|
@ -217,7 +217,7 @@ static JSDHashOperator
|
||||||
DetachedWrappedNativeProtoMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
DetachedWrappedNativeProtoMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
||||||
uint32 number, void *arg)
|
uint32 number, void *arg)
|
||||||
{
|
{
|
||||||
XPCWrappedNativeProto* proto =
|
XPCWrappedNativeProto* proto =
|
||||||
(XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
|
(XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
|
||||||
|
|
||||||
proto->Mark();
|
proto->Mark();
|
||||||
|
@ -310,7 +310,7 @@ void XPCJSRuntime::TraceJS(JSTracer* trc, void* data)
|
||||||
// them here.
|
// them here.
|
||||||
for(XPCRootSetElem *e = self->mObjectHolderRoots; e ; e = e->GetNextRoot())
|
for(XPCRootSetElem *e = self->mObjectHolderRoots; e ; e = e->GetNextRoot())
|
||||||
static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
|
static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
|
||||||
|
|
||||||
if(self->GetXPConnect()->ShouldTraceRoots())
|
if(self->GetXPConnect()->ShouldTraceRoots())
|
||||||
{
|
{
|
||||||
// Only trace these if we're not cycle-collecting, the cycle collector
|
// Only trace these if we're not cycle-collecting, the cycle collector
|
||||||
|
@ -498,7 +498,7 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||||
case JSGC_MARK_END:
|
case JSGC_MARK_END:
|
||||||
{
|
{
|
||||||
NS_ASSERTION(!self->mDoingFinalization, "bad state");
|
NS_ASSERTION(!self->mDoingFinalization, "bad state");
|
||||||
|
|
||||||
// mThreadRunningGC indicates that GC is running
|
// mThreadRunningGC indicates that GC is running
|
||||||
{ // scoped lock
|
{ // scoped lock
|
||||||
XPCAutoLock lock(self->GetMapLock());
|
XPCAutoLock lock(self->GetMapLock());
|
||||||
|
@ -521,8 +521,8 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||||
Enumerate(WrappedJSDyingJSObjectFinder, &data);
|
Enumerate(WrappedJSDyingJSObjectFinder, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do cleanup in NativeInterfaces. This part just finds
|
// Do cleanup in NativeInterfaces. This part just finds
|
||||||
// member cloned function objects that are about to be
|
// member cloned function objects that are about to be
|
||||||
// collected. It does not deal with collection of interfaces or
|
// collected. It does not deal with collection of interfaces or
|
||||||
// sets at this point.
|
// sets at this point.
|
||||||
CX_AND_XPCRT_Data data = {cx, self};
|
CX_AND_XPCRT_Data data = {cx, self};
|
||||||
|
@ -689,7 +689,7 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||||
if(threadLock)
|
if(threadLock)
|
||||||
{
|
{
|
||||||
// Do the marking...
|
// Do the marking...
|
||||||
|
|
||||||
{ // scoped lock
|
{ // scoped lock
|
||||||
nsAutoLock lock(threadLock);
|
nsAutoLock lock(threadLock);
|
||||||
|
|
||||||
|
@ -708,7 +708,7 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||||
// possibly be valid.
|
// possibly be valid.
|
||||||
if(ccxp->CanGetTearOff())
|
if(ccxp->CanGetTearOff())
|
||||||
{
|
{
|
||||||
XPCWrappedNativeTearOff* to =
|
XPCWrappedNativeTearOff* to =
|
||||||
ccxp->GetTearOff();
|
ccxp->GetTearOff();
|
||||||
if(to)
|
if(to)
|
||||||
to->Mark();
|
to->Mark();
|
||||||
|
@ -717,7 +717,7 @@ JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the sweeping...
|
// Do the sweeping...
|
||||||
XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs();
|
XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs();
|
||||||
}
|
}
|
||||||
|
@ -823,7 +823,7 @@ static JSDHashOperator
|
||||||
DetachedWrappedNativeProtoShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
DetachedWrappedNativeProtoShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
||||||
uint32 number, void *arg)
|
uint32 number, void *arg)
|
||||||
{
|
{
|
||||||
XPCWrappedNativeProto* proto =
|
XPCWrappedNativeProto* proto =
|
||||||
(XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
|
(XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
|
||||||
|
|
||||||
proto->SystemIsBeingShutDown((JSContext*)arg);
|
proto->SystemIsBeingShutDown((JSContext*)arg);
|
||||||
|
@ -1057,10 +1057,6 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
||||||
JS_SetContextCallback(mJSRuntime, ContextCallback);
|
JS_SetContextCallback(mJSRuntime, ContextCallback);
|
||||||
JS_SetGCCallbackRT(mJSRuntime, GCCallback);
|
JS_SetGCCallbackRT(mJSRuntime, GCCallback);
|
||||||
JS_SetExtraGCRoots(mJSRuntime, TraceJS, this);
|
JS_SetExtraGCRoots(mJSRuntime, TraceJS, this);
|
||||||
|
|
||||||
// GC will be called when gcBytes is 1600% of gcLastBytes.
|
|
||||||
JS_SetGCParameter(mJSRuntime, JSGC_TRIGGER_FACTOR, 1600);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
|
if(!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче