Skip to content

Commit

Permalink
feat(xsnap): enable gc() in the start compartment
Browse files Browse the repository at this point in the history
Modify xsnap.c to add a `gc()` function to the globals of the
initial ("start") Compartment. This function should trigger an immediate,
synchronous, full GC sweep. As a non-standard global, the `gc()` function
will be filtered out of the globals in all child Compartments by SES as
usual.

Note that this changes the snapshot format: heap snapshots written before
this change cannot be read by code after this change. This happens because
`gc()` (which is implemented in C) is a new "callback" (a C function made
available to JS code), which is an "exit" from the reference graph. It must
be recognized during serialization, and re-attached during reload, and xsnap
cannot handle loading snapshots with a different set of exits, even purely
additive changes.

closes #2682
refs #2660
refs #2615
  • Loading branch information
warner committed Mar 19, 2021
1 parent 98dd129 commit ce568c9
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 8 deletions.
16 changes: 8 additions & 8 deletions packages/xsnap/src/xsnap.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ static void fx_Array_prototype_meter(xsMachine* the);
extern void fx_clearTimer(txMachine* the);
static void fx_destroyTimer(void* data);
// static void fx_evalScript(xsMachine* the);
// static void fx_gc(xsMachine* the);
static void fx_gc(xsMachine* the);
// static void fx_isPromiseJobQueueEmpty(xsMachine* the);
static void fx_markTimer(txMachine* the, void* it, txMarkRoot markRoot);
static void fx_print(xsMachine* the);
Expand All @@ -80,13 +80,13 @@ static char* fxWriteNetStringError(int code);
// The order of the callbacks materially affects how they are introduced to
// code that runs from a snapshot, so must be consistent in the face of
// upgrade.
#define mxSnapshotCallbackCount 4
#define mxSnapshotCallbackCount 5
txCallback gxSnapshotCallbacks[mxSnapshotCallbackCount] = {
fx_issueCommand, // 0
fx_Array_prototype_meter, // 1
fx_print, // 2
fx_setImmediate, // 3
// fx_gc,
fx_gc, // 4
// fx_evalScript,
// fx_isPromiseJobQueueEmpty,
// fx_setInterval,
Expand Down Expand Up @@ -517,7 +517,7 @@ void fxBuildAgent(xsMachine* the)
// slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearInterval"), XS_DONT_ENUM_FLAG);
// slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearTimeout"), XS_DONT_ENUM_FLAG);
// slot = fxNextHostFunctionProperty(the, slot, fx_evalScript, 1, xsID("evalScript"), XS_DONT_ENUM_FLAG);
// slot = fxNextHostFunctionProperty(the, slot, fx_gc, 1, xsID("gc"), XS_DONT_ENUM_FLAG);
slot = fxNextHostFunctionProperty(the, slot, fx_gc, 1, xsID("gc"), XS_DONT_ENUM_FLAG);
// slot = fxNextHostFunctionProperty(the, slot, fx_isPromiseJobQueueEmpty, 1, xsID("isPromiseJobQueueEmpty"), XS_DONT_ENUM_FLAG);
slot = fxNextHostFunctionProperty(the, slot, fx_print, 1, xsID("print"), XS_DONT_ENUM_FLAG);
slot = fxNextHostFunctionProperty(the, slot, fx_setImmediate, 1, xsID("setImmediate"), XS_DONT_ENUM_FLAG);
Expand Down Expand Up @@ -870,10 +870,10 @@ void fxPrintUsage()
// mxPullSlot(mxResult);
// }

// void fx_gc(xsMachine* the)
// {
// xsCollectGarbage();
// }
void fx_gc(xsMachine* the)
{
xsCollectGarbage();
}

// void fx_isPromiseJobQueueEmpty(txMachine* the)
// {
Expand Down
17 changes: 17 additions & 0 deletions packages/xsnap/test/test-xsnap.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,23 @@ test('print - start compartment only', async t => {
t.deepEqual(['no print in Compartment'], opts.messages);
});

test('gc - start compartment only', async t => {
const opts = options();
const vat = xsnap(opts);
await vat.evaluate(`
gc();
const send = it => issueCommand(ArrayBuffer.fromString(it));
print(123);
try {
(new Compartment()).evalate('gc()');
} catch (_err) {
send('no gc in Compartment');
}
`);
await vat.close();
t.deepEqual(['no gc in Compartment'], opts.messages);
});

test('run script until idle', async t => {
const opts = options();
const vat = xsnap(opts);
Expand Down

0 comments on commit ce568c9

Please sign in to comment.