Bug 742570 - Improve GC testing functions (r=igor)

This commit is contained in:
Bill McCloskey 2012-04-03 14:07:38 -07:00
Родитель 3beb216ed0
Коммит 8a7780be96
4 изменённых файлов: 62 добавлений и 16 удалений

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

@ -21,19 +21,30 @@ using namespace JS;
static JSBool static JSBool
GC(JSContext *cx, unsigned argc, jsval *vp) GC(JSContext *cx, unsigned argc, jsval *vp)
{ {
JSCompartment *comp = NULL; /*
* If the first argument is 'compartment', we collect any compartments
* previously scheduled for GC via schedulegc. If the first argument is an
* object, we collect the object's compartment (any any other compartments
* scheduled for GC). Otherwise, we collect call compartments.
*/
JSBool compartment = false;
if (argc == 1) { if (argc == 1) {
Value arg = vp[2]; Value arg = vp[2];
if (arg.isObject()) if (arg.isString()) {
comp = UnwrapObject(&arg.toObject())->compartment(); if (!JS_StringEqualsAscii(cx, arg.toString(), "compartment", &compartment))
return false;
} else if (arg.isObject()) {
PrepareCompartmentForGC(UnwrapObject(&arg.toObject())->compartment());
compartment = true;
}
} }
#ifndef JS_MORE_DETERMINISTIC #ifndef JS_MORE_DETERMINISTIC
size_t preBytes = cx->runtime->gcBytes; size_t preBytes = cx->runtime->gcBytes;
#endif #endif
if (comp) if (compartment)
PrepareCompartmentForGC(comp); PrepareForDebugGC(cx->runtime);
else else
PrepareForFullGC(cx->runtime); PrepareForFullGC(cx->runtime);
GCForReason(cx, gcreason::API); GCForReason(cx, gcreason::API);
@ -177,16 +188,24 @@ GCZeal(JSContext *cx, unsigned argc, jsval *vp)
static JSBool static JSBool
ScheduleGC(JSContext *cx, unsigned argc, jsval *vp) ScheduleGC(JSContext *cx, unsigned argc, jsval *vp)
{ {
uint32_t count;
if (argc != 1) { if (argc != 1) {
ReportUsageError(cx, &JS_CALLEE(cx, vp).toObject(), "Wrong number of arguments"); ReportUsageError(cx, &JS_CALLEE(cx, vp).toObject(), "Wrong number of arguments");
return JS_FALSE; return JS_FALSE;
} }
if (!JS_ValueToECMAUint32(cx, vp[2], &count))
return JS_FALSE;
JS_ScheduleGC(cx, count); Value arg(vp[2]);
if (arg.isInt32()) {
/* Schedule a GC to happen after |arg| allocations. */
JS_ScheduleGC(cx, arg.toInt32());
} else if (arg.isObject()) {
/* Ensure that |comp| is collected during the next GC. */
JSCompartment *comp = UnwrapObject(&arg.toObject())->compartment();
PrepareCompartmentForGC(comp);
} else if (arg.isString()) {
/* This allows us to schedule atomsCompartment for GC. */
PrepareCompartmentForGC(arg.toString()->compartment());
}
*vp = JSVAL_VOID; *vp = JSVAL_VOID;
return JS_TRUE; return JS_TRUE;
} }
@ -473,8 +492,10 @@ Terminate(JSContext *cx, unsigned arg, jsval *vp)
static JSFunctionSpecWithHelp TestingFunctions[] = { static JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0, JS_FN_HELP("gc", ::GC, 0, 0,
"gc([obj])", "gc([obj] | 'compartment')",
" Run the garbage collector. When obj is given, GC only its compartment."), " Run the garbage collector. When obj is given, GC only its compartment.\n"
" If 'compartment' is given, GC any compartments that were scheduled for\n"
" GC via schedulegc."),
JS_FN_HELP("gcparam", GCParameter, 2, 0, JS_FN_HELP("gcparam", GCParameter, 2, 0,
"gcparam(name [, value])", "gcparam(name [, value])",
@ -511,8 +532,9 @@ static JSFunctionSpecWithHelp TestingFunctions[] = {
" Period specifies that collection happens every n allocations.\n"), " Period specifies that collection happens every n allocations.\n"),
JS_FN_HELP("schedulegc", ScheduleGC, 1, 0, JS_FN_HELP("schedulegc", ScheduleGC, 1, 0,
"schedulegc(num)", "schedulegc(num | obj)",
" Schedule a GC to happen after num allocations."), " If num is given, schedule a GC after num allocations.\n"
" If obj is given, schedule a GC of obj's compartment."),
JS_FN_HELP("verifybarriers", VerifyBarriers, 0, 0, JS_FN_HELP("verifybarriers", VerifyBarriers, 0, 0,
"verifybarriers()", "verifybarriers()",

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

@ -0,0 +1,9 @@
/* Make sure we don't collect the atoms compartment unless every compartment is marked. */
var g = newGlobal('new-compartment');
g.eval("var x = 'some-atom';");
schedulegc(this);
schedulegc('atoms');
gc('compartment');
print(g.x);

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

@ -3726,10 +3726,22 @@ GCSlice(JSContext *cx, JSGCInvocationKind gckind, gcreason::Reason reason)
void void
GCDebugSlice(JSContext *cx, int64_t objCount) GCDebugSlice(JSContext *cx, int64_t objCount)
{ {
PrepareForFullGC(cx->runtime); PrepareForDebugGC(cx->runtime);
Collect(cx, SliceBudget::WorkBudget(objCount), GC_NORMAL, gcreason::API); Collect(cx, SliceBudget::WorkBudget(objCount), GC_NORMAL, gcreason::API);
} }
/* Schedule a full GC unless a compartment will already be collected. */
void
PrepareForDebugGC(JSRuntime *rt)
{
for (CompartmentsIter c(rt); !c.done(); c.next()) {
if (c->isGCScheduled())
return;
}
PrepareForFullGC(rt);
}
void void
ShrinkGCBuffers(JSRuntime *rt) ShrinkGCBuffers(JSRuntime *rt)
{ {
@ -3919,7 +3931,7 @@ void
RunDebugGC(JSContext *cx) RunDebugGC(JSContext *cx)
{ {
#ifdef JS_GC_ZEAL #ifdef JS_GC_ZEAL
PrepareForFullGC(cx->runtime); PrepareForDebugGC(cx->runtime);
RunLastDitchGC(cx, gcreason::DEBUG_GC); RunLastDitchGC(cx, gcreason::DEBUG_GC);
#endif #endif
} }

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

@ -1406,6 +1406,9 @@ GCSlice(JSContext *cx, JSGCInvocationKind gckind, js::gcreason::Reason reason);
extern void extern void
GCDebugSlice(JSContext *cx, int64_t objCount); GCDebugSlice(JSContext *cx, int64_t objCount);
extern void
PrepareForDebugGC(JSRuntime *rt);
} /* namespace js */ } /* namespace js */
namespace js { namespace js {