Bug 1182647: Move setGCCallback to TestingFunctions.cpp; r=sfink

This commit is contained in:
Benjamin Bouvier 2015-07-16 21:17:41 +02:00
parent fa48f873e7
commit 90568a475d
2 changed files with 149 additions and 149 deletions

View File

@ -2508,6 +2508,149 @@ AllocationMarker(JSContext* cx, unsigned argc, jsval* vp)
return true;
}
namespace gcCallback {
struct MajorGC {
int32_t depth;
int32_t phases;
};
static void
majorGC(JSRuntime* rt, JSGCStatus status, void* data)
{
auto info = static_cast<MajorGC*>(data);
if (!(info->phases & (1 << status)))
return;
if (info->depth > 0) {
info->depth--;
JS::PrepareForFullGC(rt);
JS::GCForReason(rt, GC_NORMAL, JS::gcreason::API);
info->depth++;
}
}
struct MinorGC {
int32_t phases;
bool active;
};
static void
minorGC(JSRuntime* rt, JSGCStatus status, void* data)
{
auto info = static_cast<MinorGC*>(data);
if (!(info->phases & (1 << status)))
return;
if (info->active) {
info->active = false;
rt->gc.evictNursery(JS::gcreason::DEBUG_GC);
info->active = true;
}
}
// Process global, should really be runtime-local. Also, the final one of these
// is currently leaked, since they are only deleted when changing.
MajorGC* prevMajorGC = nullptr;
MinorGC* prevMinorGC = nullptr;
} /* namespace gcCallback */
static bool
SetGCCallback(JSContext* cx, unsigned argc, jsval* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 1) {
JS_ReportError(cx, "Wrong number of arguments");
return false;
}
RootedObject opts(cx, ToObject(cx, args[0]));
if (!opts)
return false;
RootedValue v(cx);
if (!JS_GetProperty(cx, opts, "action", &v))
return false;
JSString* str = JS::ToString(cx, v);
if (!str)
return false;
JSAutoByteString action(cx, str);
if (!action)
return false;
int32_t phases = 0;
if ((strcmp(action.ptr(), "minorGC") == 0) || (strcmp(action.ptr(), "majorGC") == 0)) {
if (!JS_GetProperty(cx, opts, "phases", &v))
return false;
if (v.isUndefined()) {
phases = (1 << JSGC_END);
} else {
JSString* str = JS::ToString(cx, v);
if (!str)
return false;
JSAutoByteString phasesStr(cx, str);
if (!phasesStr)
return false;
if (strcmp(phasesStr.ptr(), "begin") == 0)
phases = (1 << JSGC_BEGIN);
else if (strcmp(phasesStr.ptr(), "end") == 0)
phases = (1 << JSGC_END);
else if (strcmp(phasesStr.ptr(), "both") == 0)
phases = (1 << JSGC_BEGIN) | (1 << JSGC_END);
else {
JS_ReportError(cx, "Invalid callback phase");
return false;
}
}
}
if (gcCallback::prevMajorGC) {
JS_SetGCCallback(cx->runtime(), nullptr, nullptr);
js_delete<gcCallback::MajorGC>(gcCallback::prevMajorGC);
gcCallback::prevMajorGC = nullptr;
}
if (gcCallback::prevMinorGC) {
JS_SetGCCallback(cx->runtime(), nullptr, nullptr);
js_delete<gcCallback::MinorGC>(gcCallback::prevMinorGC);
gcCallback::prevMinorGC = nullptr;
}
if (strcmp(action.ptr(), "minorGC") == 0) {
auto info = js_new<gcCallback::MinorGC>();
info->phases = phases;
info->active = true;
JS_SetGCCallback(cx->runtime(), gcCallback::minorGC, info);
} else if (strcmp(action.ptr(), "majorGC") == 0) {
if (!JS_GetProperty(cx, opts, "depth", &v))
return false;
int32_t depth = 1;
if (!v.isUndefined()) {
if (!ToInt32(cx, v, &depth))
return false;
}
if (depth > int32_t(gcstats::Statistics::MAX_NESTING - 4)) {
JS_ReportError(cx, "Nesting depth too large, would overflow");
return false;
}
auto info = js_new<gcCallback::MajorGC>();
info->phases = phases;
info->depth = depth;
JS_SetGCCallback(cx->runtime(), gcCallback::majorGC, info);
} else {
JS_ReportError(cx, "Unknown GC callback action");
return false;
}
args.rval().setUndefined();
return true;
}
static const JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0,
"gc([obj] | 'compartment' [, 'shrinking'])",
@ -2932,6 +3075,12 @@ gc::ZealModeHelpText),
" to this function, never implicitly by the system, making them\n"
" suitable for use in allocation tooling tests.\n"),
JS_FN_HELP("setGCCallback", SetGCCallback, 1, 0,
"setGCCallback({action:\"...\", options...})",
" Set the GC callback. action may be:\n"
" 'minorGC' - run a nursery collection\n"
" 'majorGC' - run a major collection, nesting up to a given 'depth'\n"),
JS_FS_HELP_END
};

View File

@ -1552,149 +1552,6 @@ Quit(JSContext* cx, unsigned argc, jsval* vp)
return false;
}
namespace gcCallback {
struct MajorGC {
int32_t depth;
int32_t phases;
};
static void
majorGC(JSRuntime* rt, JSGCStatus status, void* data)
{
auto info = static_cast<MajorGC*>(data);
if (!(info->phases & (1 << status)))
return;
if (info->depth > 0) {
info->depth--;
JS::PrepareForFullGC(rt);
JS::GCForReason(rt, GC_NORMAL, JS::gcreason::API);
info->depth++;
}
}
struct MinorGC {
int32_t phases;
bool active;
};
static void
minorGC(JSRuntime* rt, JSGCStatus status, void* data)
{
auto info = static_cast<MinorGC*>(data);
if (!(info->phases & (1 << status)))
return;
if (info->active) {
info->active = false;
rt->gc.evictNursery(JS::gcreason::DEBUG_GC);
info->active = true;
}
}
// Process global, should really be runtime-local. Also, the final one of these
// is currently leaked, since they are only deleted when changing.
MajorGC* prevMajorGC = nullptr;
MinorGC* prevMinorGC = nullptr;
} /* namespace gcCallback */
static bool
SetGCCallback(JSContext* cx, unsigned argc, jsval* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 1) {
JS_ReportError(cx, "Wrong number of arguments");
return false;
}
RootedObject opts(cx, ToObject(cx, args[0]));
if (!opts)
return false;
RootedValue v(cx);
if (!JS_GetProperty(cx, opts, "action", &v))
return false;
JSString* str = JS::ToString(cx, v);
if (!str)
return false;
JSAutoByteString action(cx, str);
if (!action)
return false;
int32_t phases = 0;
if ((strcmp(action.ptr(), "minorGC") == 0) || (strcmp(action.ptr(), "majorGC") == 0)) {
if (!JS_GetProperty(cx, opts, "phases", &v))
return false;
if (v.isUndefined()) {
phases = (1 << JSGC_END);
} else {
JSString* str = JS::ToString(cx, v);
if (!str)
return false;
JSAutoByteString phasesStr(cx, str);
if (!phasesStr)
return false;
if (strcmp(phasesStr.ptr(), "begin") == 0)
phases = (1 << JSGC_BEGIN);
else if (strcmp(phasesStr.ptr(), "end") == 0)
phases = (1 << JSGC_END);
else if (strcmp(phasesStr.ptr(), "both") == 0)
phases = (1 << JSGC_BEGIN) | (1 << JSGC_END);
else {
JS_ReportError(cx, "Invalid callback phase");
return false;
}
}
}
if (gcCallback::prevMajorGC) {
JS_SetGCCallback(cx->runtime(), nullptr, nullptr);
js_delete<gcCallback::MajorGC>(gcCallback::prevMajorGC);
gcCallback::prevMajorGC = nullptr;
}
if (gcCallback::prevMinorGC) {
JS_SetGCCallback(cx->runtime(), nullptr, nullptr);
js_delete<gcCallback::MinorGC>(gcCallback::prevMinorGC);
gcCallback::prevMinorGC = nullptr;
}
if (strcmp(action.ptr(), "minorGC") == 0) {
auto info = js_new<gcCallback::MinorGC>();
info->phases = phases;
info->active = true;
JS_SetGCCallback(cx->runtime(), gcCallback::minorGC, info);
} else if (strcmp(action.ptr(), "majorGC") == 0) {
if (!JS_GetProperty(cx, opts, "depth", &v))
return false;
int32_t depth = 1;
if (!v.isUndefined()) {
if (!ToInt32(cx, v, &depth))
return false;
}
if (depth > int32_t(gcstats::Statistics::MAX_NESTING - 4)) {
JS_ReportError(cx, "Nesting depth too large, would overflow");
return false;
}
auto info = js_new<gcCallback::MajorGC>();
info->phases = phases;
info->depth = depth;
JS_SetGCCallback(cx->runtime(), gcCallback::majorGC, info);
} else {
JS_ReportError(cx, "Unknown GC callback action");
return false;
}
args.rval().setUndefined();
return true;
}
static bool
StartTimingMutator(JSContext* cx, unsigned argc, jsval* vp)
{
@ -4658,12 +4515,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
" Throw if the first two arguments are not the same (both +0 or both -0,\n"
" both NaN, or non-zero and ===)."),
JS_FN_HELP("setGCCallback", SetGCCallback, 1, 0,
"setGCCallback({action:\"...\", options...})",
" Set the GC callback. action may be:\n"
" 'minorGC' - run a nursery collection\n"
" 'majorGC' - run a major collection, nesting up to a given 'depth'\n"),
JS_FN_HELP("startTimingMutator", StartTimingMutator, 0, 0,
"startTimingMutator()",
" Start accounting time to mutator vs GC."),