mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1182647: Move setGCCallback to TestingFunctions.cpp; r=sfink
This commit is contained in:
parent
fa48f873e7
commit
90568a475d
@ -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
|
||||
};
|
||||
|
||||
|
@ -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."),
|
||||
|
Loading…
Reference in New Issue
Block a user