-
Notifications
You must be signed in to change notification settings - Fork 226
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(swingset): add test of GC behavior in xs vat
This checks that our normal async / `await E()` pattern doesn't cause the target or its arguments to be retained longer than expected. refs #3406
- Loading branch information
Showing
3 changed files
with
117 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { Far } from '@agoric/marshal'; | ||
import { E } from '@agoric/eventual-send'; | ||
|
||
export function buildRootObject() { | ||
let A = Far('A', { hello() {} }); | ||
let B = Far('B', { hello() {} }); | ||
let target; | ||
|
||
return harden({ | ||
async bootstrap(vats) { | ||
target = vats.target; | ||
}, | ||
async one() { | ||
await E(target).two(A, B); | ||
}, | ||
drop() { | ||
A = null; | ||
B = null; | ||
}, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* global __dirname */ | ||
import { test } from '../../tools/prepare-test-env-ava.js'; | ||
|
||
// eslint-disable-next-line import/order | ||
import path from 'path'; | ||
import { provideHostStorage } from '../../src/hostStorage.js'; | ||
import { initializeSwingset, makeSwingsetController } from '../../src/index.js'; | ||
import { capargs } from '../util.js'; | ||
|
||
function dumpObjects(c) { | ||
const out = {}; | ||
for (const row of c.dump().objects) { | ||
const [koid, owner, reachable, recognizable] = row; | ||
out[koid] = [owner, reachable, recognizable]; | ||
} | ||
return out; | ||
} | ||
|
||
async function dropPresence(t, dropExport) { | ||
const config = { | ||
bootstrap: 'bootstrap', | ||
vats: { | ||
bootstrap: { | ||
sourceSpec: path.join(__dirname, 'bootstrap.js'), | ||
}, | ||
target: { | ||
sourceSpec: path.join(__dirname, 'vat-target.js'), | ||
creationOptions: { managerType: 'xs-worker' }, | ||
}, | ||
}, | ||
}; | ||
const hostStorage = provideHostStorage(); | ||
await initializeSwingset(config, [], hostStorage); | ||
const c = await makeSwingsetController(hostStorage); | ||
t.teardown(c.shutdown); | ||
await c.run(); | ||
|
||
const bootstrapID = c.vatNameToID('bootstrap'); | ||
c.queueToVatExport('bootstrap', 'o+0', 'one', capargs([])); | ||
if (dropExport) { | ||
c.queueToVatExport('bootstrap', 'o+0', 'drop', capargs([])); | ||
await c.step(); | ||
} | ||
await c.step(); | ||
|
||
// examine the run-queue to learn the krefs for objects A and B | ||
const rq = c.dump().runQueue; | ||
t.is(rq[0].type, 'send'); | ||
t.is(rq[0].msg.method, 'two'); | ||
const [krefA, krefB] = rq[0].msg.args.slots; | ||
t.is(krefA, 'ko26'); // arbitrary but this is what we currently expect | ||
t.is(krefB, 'ko27'); // same | ||
// both are exported by the bootstrap vat, and are reachable+recognizable | ||
// by the run-queue message, so the refcounts should both be 1,1 | ||
let objs = dumpObjects(c); | ||
t.deepEqual(objs[krefA], [bootstrapID, 1, 1]); | ||
t.deepEqual(objs[krefB], [bootstrapID, 1, 1]); | ||
|
||
// Now let everything complete, and those objects should be dropped by the | ||
// importing vat, which means the exporting vat will be told they've been | ||
// dropped too. The exporting vat still holds the Remotables strongly. | ||
await c.run(); | ||
objs = dumpObjects(c); | ||
|
||
if (dropExport) { | ||
// the exporter wasn't holding a strong ref, so when the drop arrives, | ||
// the exporter will retire, causing the importer to retire, causing the | ||
// object to disappear entirely | ||
t.is(objs[krefA], undefined); | ||
t.is(objs[krefB], undefined); | ||
} else { | ||
// until #3161 is fixed, the importing vat hasn't yet told the kernel that | ||
// the objects are unrecognizable, so the refcounts will be 0,1 | ||
t.deepEqual(objs[krefA], [bootstrapID, 0, 1]); | ||
t.deepEqual(objs[krefB], [bootstrapID, 0, 1]); | ||
|
||
// but when #3161 is fixed, the objects should be retired too, so the c-list | ||
// mappings and valToSlot tables will be empty. | ||
// t.is(objs[krefA], undefined); | ||
// t.is(objs[krefB], undefined); | ||
} | ||
} | ||
|
||
test('drop presence (export retains)', t => dropPresence(t, false)); | ||
test('drop presence (export drops)', t => dropPresence(t, true)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Far } from '@agoric/marshal'; | ||
import { E } from '@agoric/eventual-send'; | ||
|
||
export function buildRootObject() { | ||
return Far('root', { | ||
async two(A, B) { | ||
// A=ko26 B=ko27 | ||
await E(A).hello(B); | ||
}, | ||
}); | ||
} |