Backed out changeset e74857ea8248 - this caused unit test failures on Mac

This commit is contained in:
Igor Bukanov 2009-01-20 17:11:09 +01:00
Родитель 4b9a729294
Коммит a741088d8f
9 изменённых файлов: 113 добавлений и 153 удалений

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

@ -854,8 +854,24 @@ PrintWinCodebase(nsGlobalWindow *win)
}
#endif
// The accumulated operation weight for DOM callback.
const PRUint32 DOM_CALLBACK_OPERATION_WEIGHT = 5000 * JS_OPERATION_WEIGHT_BASE;
// The accumulated operation weight before we call MaybeGC
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>
GetPromptFromContext(nsJSContext* ctx)
@ -888,8 +904,17 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
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;
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
nsCOMPtr<nsIMemory> mem;
NS_GetMemoryManager(getter_AddRefs(mem));
@ -1226,7 +1251,7 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
this);
::JS_SetOperationCallback(mContext, DOMOperationCallback,
DOM_CALLBACK_OPERATION_WEIGHT);
MAYBE_GC_OPERATION_WEIGHT);
static JSLocaleCallbacks localeCallbacks =
{
@ -1239,6 +1264,7 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
::JS_SetLocaleCallbacks(mContext, &localeCallbacks);
}
mIsInitialized = PR_FALSE;
mNumEvaluations = 0;
mTerminations = nsnull;
mScriptsEnabled = PR_TRUE;
mOperationCallbackTime = LL_ZERO;
@ -3286,6 +3312,18 @@ nsJSContext::ScriptEvaluated(PRBool aTerminated)
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) {
mOperationCallbackTime = LL_ZERO;
}
@ -3372,29 +3410,19 @@ nsJSContext::CC()
#endif
sPreviousCCTime = PR_Now();
sDelayedCCollectCount = 0;
sGCCount = JS_GetGCParameter(nsJSRuntime::sRuntime, JSGC_NUMBER);
sGCCount = 0;
sCCSuspectChanges = 0;
// nsCycleCollector_collect() will run a ::JS_GC() indirectly, so
// we do not explicitly call ::JS_GC() here.
sCollectedObjectsCounts = nsCycleCollector_collect();
sCCSuspectedCount = nsCycleCollector_suspectedCount();
#ifdef DEBUG_smaug
printf("Collected %u objects, %u suspected objects\n",
sCollectedObjectsCounts, sCCSuspectedCount);
printf("Collected %u objects, %u suspected objects, took %lldms\n",
sCollectedObjectsCounts, sCCSuspectedCount,
(PR_Now() - sPreviousCCTime) / PR_USEC_PER_MSEC);
#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
PRBool
nsJSContext::MaybeCC(PRBool aHigherProbability)
@ -3403,7 +3431,7 @@ nsJSContext::MaybeCC(PRBool aHigherProbability)
// Don't check suspected count if CC will be called anyway.
if (sCCSuspectChanges <= NS_MIN_SUSPECT_CHANGES ||
GetGCRunsCount() <= NS_MAX_GC_COUNT) {
sGCCount <= NS_MAX_GC_COUNT) {
#ifdef DEBUG_smaug
PRTime now = PR_Now();
#endif
@ -3421,8 +3449,7 @@ nsJSContext::MaybeCC(PRBool aHigherProbability)
}
#ifdef DEBUG_smaug
printf("sCCSuspectChanges %u, sGCCount %u\n",
sCCSuspectChanges,
GetGCRunsCount());
sCCSuspectChanges, sGCCount);
#endif
// Increase the probability also if the previous call to cycle collector
@ -3435,7 +3462,7 @@ nsJSContext::MaybeCC(PRBool aHigherProbability)
if (!sGCTimer &&
(sDelayedCCollectCount > NS_MAX_DELAYED_CCOLLECT) &&
((sCCSuspectChanges > NS_MIN_SUSPECT_CHANGES &&
GetGCRunsCount() > NS_MAX_GC_COUNT) ||
sGCCount > NS_MAX_GC_COUNT) ||
(sCCSuspectChanges > NS_MAX_SUSPECT_CHANGES))) {
if ((PR_Now() - sPreviousCCTime) >=
PRTime(NS_MIN_CC_INTERVAL * PR_USEC_PER_MSEC)) {

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

@ -223,6 +223,7 @@ private:
void Unlink();
JSContext *mContext;
PRUint32 mNumEvaluations;
protected:
struct TerminationFuncHolder;

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

@ -2595,31 +2595,6 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
case JSGC_STACKPOOL_LIFESPAN:
rt->gcEmptyArenaPoolLifespan = value;
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;
}
}

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

@ -1137,31 +1137,12 @@ typedef enum JSGCParamKey {
JSGC_MAX_MALLOC_BYTES = 1,
/* Hoard stackPools for this long, in ms, default is 30 seconds. */
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
JSGC_STACKPOOL_LIFESPAN = 2
} JSGCParamKey;
extern JS_PUBLIC_API(void)
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
* below) using a type-code returned from this function, and that understands

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

@ -267,7 +267,6 @@ struct JSRuntime {
uint32 gcLevel;
uint32 gcNumber;
JSTracer *gcMarkingTracer;
uint32 gcTriggerFactor;
/*
* 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->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));
return JS_TRUE;
}
@ -1769,17 +1757,6 @@ EnsureLocalFreeList(JSContext *cx)
#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 *
js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
{
@ -1846,8 +1823,7 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
return NULL;
}
doGC = (rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke) ||
IsGCThresholdReached(rt);
doGC = (rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke);
#ifdef JS_GC_ZEAL
doGC = doGC || rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke);
# ifdef JS_TRACER
@ -2080,10 +2056,9 @@ RefillDoubleFreeList(JSContext *cx)
return NULL;
}
if ((rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke) ||
IsGCThresholdReached(rt)
if (rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke
#ifdef JS_GC_ZEAL
|| (rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke))
&& (rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke))
#endif
) {
goto do_gc;
@ -2282,8 +2257,7 @@ js_AddAsGCBytes(JSContext *cx, size_t sz)
rt = cx->runtime;
if (rt->gcBytes >= rt->gcMaxBytes ||
sz > (size_t) (rt->gcMaxBytes - rt->gcBytes) ||
IsGCThresholdReached(rt)
sz > (size_t) (rt->gcMaxBytes - rt->gcBytes)
#ifdef JS_GC_ZEAL
|| rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke)
#endif

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

@ -229,6 +229,9 @@ struct JSShellContextData {
PRIntervalTime timeout;
volatile PRIntervalTime startTime; /* startTime + timeout is time when
script must be stopped */
PRIntervalTime maybeGCPeriod;
volatile PRIntervalTime lastMaybeGCTime;/* lastMaybeGCTime + maybeGCPeriod
is the time to call MaybeGC */
PRIntervalTime yieldPeriod;
volatile PRIntervalTime lastYieldTime; /* lastYieldTime + yieldPeriod is
the time to call
@ -236,6 +239,7 @@ struct JSShellContextData {
#else
int64 stopTime; /* time when script must be
stopped */
int64 nextMaybeGCTime;/* time to call JS_MaybeGC */
#endif
};
@ -245,6 +249,7 @@ SetTimeoutValue(JSContext *cx, jsdouble t);
#ifdef JS_THREADSAFE
# 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
@ -256,6 +261,8 @@ RescheduleWatchdog(JSContext *cx, JSShellContextData *data, PRIntervalTime now);
#else
# define DEFAULT_MAYBEGC_PERIOD() (MICROSECONDS_PER_SECOND / 10)
const int64 MICROSECONDS_PER_SECOND = 1000000LL;
const int64 MAX_TIME_VALUE = 0x7FFFFFFFFFFFFFFFLL;
@ -270,13 +277,16 @@ NewContextData()
return NULL;
#ifdef JS_THREADSAFE
data->timeout = PR_INTERVAL_NO_TIMEOUT;
data->maybeGCPeriod = PR_INTERVAL_NO_TIMEOUT;
data->yieldPeriod = PR_INTERVAL_NO_TIMEOUT;
# ifdef DEBUG
data->startTime = 0;
data->lastMaybeGCTime = 0;
data->lastYieldTime = 0;
# endif
#else /* !JS_THREADSAFE */
data->stopTime = MAX_TIME_VALUE;
data->nextMaybeGCTime = MAX_TIME_VALUE;
#endif
return data;
@ -296,6 +306,7 @@ ShellOperationCallback(JSContext *cx)
{
JSShellContextData *data = GetContextData(cx);
JSBool doStop;
JSBool doMaybeGC;
#ifdef JS_THREADSAFE
JSBool doYield;
PRIntervalTime now = PR_IntervalNow();
@ -303,6 +314,11 @@ ShellOperationCallback(JSContext *cx)
doStop = (data->timeout != PR_INTERVAL_NO_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 &&
now - data->lastYieldTime >= data->yieldPeriod);
if (doYield)
@ -312,6 +328,9 @@ ShellOperationCallback(JSContext *cx)
int64 now = JS_Now();
doStop = (now >= data->stopTime);
doMaybeGC = (now >= data->nextMaybeGCTime);
if (doMaybeGC)
data->nextMaybeGCTime = now + DEFAULT_MAYBEGC_PERIOD();
#endif
if (doStop) {
@ -319,6 +338,9 @@ ShellOperationCallback(JSContext *cx)
return JS_FALSE;
}
if (doMaybeGC)
JS_MaybeGC(cx);
#ifdef JS_THREADSAFE
if (doYield)
JS_YieldRequest(cx);
@ -1068,49 +1090,24 @@ GCParameter(JSContext *cx, uintN argc, jsval *vp)
param = JSGC_MAX_BYTES;
} else if (strcmp(paramName, "maxMallocBytes") == 0) {
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 {
JS_ReportError(cx,
"the first argument argument must be maxBytes, "
"maxMallocBytes, gcStackpoolLifespan, gcBytes, "
"gcNumber or gcTriggerFactor");
"the first argument argument must be either maxBytes "
"or maxMallocBytes");
return JS_FALSE;
}
if (argc == 1) {
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);
if (!JS_ValueToECMAUint32(cx, argc < 2 ? JSVAL_VOID : vp[3], &value))
return JS_FALSE;
}
if (!JS_ValueToECMAUint32(cx, vp[3], &value)) {
if (value == 0) {
JS_ReportError(cx,
"the second argument must be convertable to uint32 "
"with non-zero value");
return JS_FALSE;
}
if (param == JSGC_TRIGGER_FACTOR && value < 100) {
JS_ReportError(cx,
"the gcTriggerFactor value must be >= 100");
"the second argument must be convertable to uint32 with "
"non-zero value");
return JS_FALSE;
}
JS_SetGCParameter(cx->runtime, param, value);
*vp = JSVAL_VOID;
return JS_TRUE;
}
#ifdef JS_GC_ZEAL
@ -3145,6 +3142,8 @@ CheckCallbackTime(JSContext *cx, JSShellContextData *data, PRIntervalTime now,
UpdateSleepDuration(now, data->startTime, data->timeout,
sleepDuration, expired);
UpdateSleepDuration(now, data->lastMaybeGCTime, data->maybeGCPeriod,
sleepDuration, expired);
UpdateSleepDuration(now, data->lastYieldTime, data->yieldPeriod,
sleepDuration, expired);
if (expired) {
@ -3248,15 +3247,24 @@ SetTimeoutValue(JSContext *cx, jsdouble t)
return JS_FALSE;
}
/*
* For compatibility periodic MaybeGC calls are enabled only when the
* execution time is bounded.
*/
JSShellContextData *data = GetContextData(cx);
#ifdef JS_THREADSAFE
JS_LOCK_GC(cx->runtime);
if (t < 0) {
data->timeout = PR_INTERVAL_NO_TIMEOUT;
data->maybeGCPeriod = PR_INTERVAL_NO_TIMEOUT;
} else {
PRIntervalTime now = PR_IntervalNow();
data->timeout = PRIntervalTime(t * PR_TicksPerSecond());
data->startTime = now;
if (data->maybeGCPeriod == PR_INTERVAL_NO_TIMEOUT) {
data->maybeGCPeriod = DEFAULT_MAYBEGC_PERIOD();
data->lastMaybeGCTime = now;
}
if (!RescheduleWatchdog(cx, data, now)) {
/* The GC lock is already released here. */
return JS_FALSE;
@ -3267,10 +3275,13 @@ SetTimeoutValue(JSContext *cx, jsdouble t)
#else /* !JS_THREADSAFE */
if (t < 0) {
data->stopTime = MAX_TIME_VALUE;
data->nextMaybeGCTime = MAX_TIME_VALUE;
JS_SetOperationLimit(cx, JS_MAX_OPERATION_LIMIT);
} else {
int64 now = JS_Now();
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

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

@ -1572,10 +1572,6 @@ main(int argc, char **argv, char **envp)
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);
if (!cx) {
printf("JS_NewContext failed!\n");

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

@ -1057,10 +1057,6 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
JS_SetContextCallback(mJSRuntime, ContextCallback);
JS_SetGCCallbackRT(mJSRuntime, GCCallback);
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,