/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define ASSERT_MSG(cond, ...) \ do { \ if (!(cond)) { \
fprintf(stderr, __VA_ARGS__); \
MOZ_RELEASE_ASSERT(cond); \
} \
} while (false)
// Trigger some nested GCs to ensure that they get their own reasons and // fullGCRequested state. // // The callbacks will form the following tree: // // Begin(DEBUG_GC) // Begin(API) // End(API) // End(DEBUG_GC) // Begin(MEM_PRESSURE) // End(MEM_PRESSURE) // Begin(DOM_WINDOW_UTILS) // End(DOM_WINDOW_UTILS) // // JSGC_BEGIN and JSGC_END callbacks will be observed as a preorder traversal // of the above tree. // // Note that the ordering of the *slice* callbacks don't match up simply to the // ordering above. If a JSGC_BEGIN triggers another GC, we won't see the outer // GC's GC_CYCLE_BEGIN until the inner one is done. The slice callbacks are // reporting the actual order that the GCs are happening in. // // JSGC_END, on the other hand, won't be emitted until the GC is complete and // the GC_CYCLE_BEGIN callback has fired. So its ordering is straightforward. // staticvoid GCTreeCallback(JSContext* cx, JSGCStatus status,
JS::GCReason reason, void* data) { usingnamespace JS;
static constexpr struct {
GCProgress progress;
GCReason reason; bool isZonal;
} expectations[] = { // JSGC_BEGIN triggers a new GC before we get any slice callbacks from the // original outer GC. So the very first reason observed is API, not // DEBUG_GC.
{GC_CYCLE_BEGIN, GCReason::API, true},
{GC_SLICE_BEGIN, GCReason::API, true},
{GC_SLICE_END, GCReason::API, true},
{GC_SLICE_BEGIN, GCReason::API, true},
{GC_SLICE_END, GCReason::API, true},
{GC_CYCLE_END, GCReason::API, true}, // Now the "outer" GC runs. It requested a full GC.
{GC_CYCLE_BEGIN, GCReason::DEBUG_GC, false},
{GC_SLICE_BEGIN, GCReason::DEBUG_GC, false},
{GC_SLICE_END, GCReason::DEBUG_GC, false},
{GC_SLICE_BEGIN, GCReason::DEBUG_GC, false},
{GC_SLICE_END, GCReason::DEBUG_GC, false},
{GC_CYCLE_END, GCReason::DEBUG_GC, false}, // The outer JSGC_DEBUG GC's end callback triggers a full MEM_PRESSURE // GC, which runs next. (Its JSGC_BEGIN does not run a GC.)
{GC_CYCLE_BEGIN, GCReason::MEM_PRESSURE, false},
{GC_SLICE_BEGIN, GCReason::MEM_PRESSURE, false},
{GC_SLICE_END, GCReason::MEM_PRESSURE, false},
{GC_SLICE_BEGIN, GCReason::MEM_PRESSURE, false},
{GC_SLICE_END, GCReason::MEM_PRESSURE, false},
{GC_CYCLE_END, GCReason::MEM_PRESSURE, false}, // The MEM_PRESSURE's GC's end callback now triggers a (zonal) // DOM_WINDOW_UTILS GC.
{GC_CYCLE_BEGIN, GCReason::DOM_WINDOW_UTILS, true},
{GC_SLICE_BEGIN, GCReason::DOM_WINDOW_UTILS, true},
{GC_SLICE_END, GCReason::DOM_WINDOW_UTILS, true},
{GC_SLICE_BEGIN, GCReason::DOM_WINDOW_UTILS, true},
{GC_SLICE_END, GCReason::DOM_WINDOW_UTILS, true},
{GC_CYCLE_END, GCReason::DOM_WINDOW_UTILS, true}, // All done.
};
// Automate the callback clearing. Otherwise if a CHECK fails, it will get // cluttered with additional failures from the callback unexpectedly firing // during the final shutdown GC. auto byebye = mozilla::MakeScopeExit([=] {
JS::SetGCSliceCallback(cx, nullptr);
JS_SetGCCallback(cx, nullptr, nullptr);
});
// Outer GC is a full GC.
JS::PrepareForFullGC(cx);
JS::SliceBudget budget(JS::WorkBudget(1));
cx->runtime()->gc.startDebugGC(JS::GCOptions::Normal, budget);
CHECK(JS::IsIncrementalGCInProgress(cx));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.