Skip to content

Commit

Permalink
fix(swingset): refactor dispatch()
Browse files Browse the repository at this point in the history
This changes the raw vat API: instead of an object named `dispatch` with
methods like `dispatch.deliver` and `dispatch.notify`, vats export a
`dispatch()` *function* which always takes a `VatDeliveryObject`. This VDO
contains a `type: 'message'` or `type: 'notify'` (among others). This paves
the way for low-level vats to get control when their userspace code becomes
quiescent, so they can perform GC activity at end-of-crank. The comms
vat (our only non-liveslots "raw" vat) was changed to match.

The various vat managers and supervisors were refactored around a "manager
kit" and "supervisor kit", to centralize transcript replay and error
handling. Each different type of manager is responsible for launching the
worker and delivering VatDeliveryObjects / VatDeliveryResults over whatever
form of "wire" they use, and likewise for VatSyscallObject /
VatSyscallResults. But the `dispatch()` presented to the kernel (on one
side), and the `dispatch`/`syscall` attached to the low-level vat (on the
other) are both handled by common code, regardless of the type of manager.
This removes a lot of boilerplate and should fix some of the accidental
non-feature-parity between manager types. It should also help with the return
of meter-consumed data from the worker, eventually. The manager-type
-specific code no longer attempts to inspect/dissect/reassemble
VatDeliveryObjects or VatSyscallObjects.

The manager types are split into two categories: those for which syscalls can
return data, and those which cannot. Local and XS workers can block until the
kernel returns the syscall results, so they can use `syscall.invoke` and
`syscall.vatstoreGet`, which are necessary for device calls and virtual
objects, respectively. NodeWorker (i.e. threads) cannot block, and Node
subprocess workers do not block (we could make them block, but it's more work
than we care to invest).

The creation of Vat Managers was shuffled to provide the `vatSyscallHandler`
as an argument up-front, rather than passing it into a callback function
later. We needed the old (and annoying) arrangement to deal with a cyclic
dependency, but that was removed some time ago, so now we can finally clean
it up.

The transcript format was changed to include the VatDeliveryObject,
VatSyscallObject, and VatSyscallResult objects more directly. Several
syscall-handling paths were rewritten to do the same. This causes
test-kernel.js to change slightly, in the parts which examine the transcript
directly.

A lot of typescript annotations were added (mostly in `src/types.js`), and
many type-asserting functions were added to `src/message.js`.

All unit tests that interacted with liveslots or the comms vat
directly (using `dispatch.deliver()`) were changed to use `dispatch()`, along
with helper functions to create the VatDeliveryObjects it now takes.
  • Loading branch information
warner committed Apr 23, 2021
1 parent 4887515 commit ec2e993
Show file tree
Hide file tree
Showing 34 changed files with 1,409 additions and 1,129 deletions.
1 change: 0 additions & 1 deletion packages/SwingSet/jsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"declaration": true,
"emitDeclarationOnly": true,
*/
"downlevelIteration": true,
"strictNullChecks": true,
"moduleResolution": "node",
},
Expand Down
1 change: 1 addition & 0 deletions packages/SwingSet/src/initializeSwingset.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { assert, details as X } from '@agoric/assert';
import bundleSource from '@agoric/bundle-source';
import { initSwingStore } from '@agoric/swing-store-simple';

import './types';
import { insistStorageAPI } from './storageAPI';
import { initializeKernel } from './kernel/initializeKernel';

Expand Down
18 changes: 7 additions & 11 deletions packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ import { insistKernelType, parseKernelSlot } from './parseKernelSlots';
import { parseVatSlot } from '../parseVatSlots';
import { insistStorageAPI } from '../storageAPI';
import { insistCapData } from '../capdata';
import { insistMessage } from '../message';
import { insistMessage, insistVatDeliveryResult } from '../message';
import { insistDeviceID, insistVatID } from './id';
import { makeMeterManager } from './metering';
import { makeKernelSyscallHandler, doSend } from './kernelSyscall';
import { makeSlogger, makeDummySlogger } from './slogger';
import { getKpidsToRetire } from './cleanup';

import { makeVatLoader } from './loadVat';
import { makeVatTranslators } from './vatTranslator';
import { makeDeviceTranslators } from './deviceTranslator';

function abbreviateReplacer(_, arg) {
Expand All @@ -33,6 +32,7 @@ function abbreviateReplacer(_, arg) {
}

function makeError(message, name = 'Error') {
assert.typeof(message, 'string');
const err = { '@qclass': 'error', name, message };
return harden({ body: JSON.stringify(err), slots: [] });
}
Expand Down Expand Up @@ -369,6 +369,7 @@ export default function buildKernel(
);
try {
const deliveryResult = await vat.manager.deliver(vatDelivery);
insistVatDeliveryResult(deliveryResult);
finish(deliveryResult);
const [status, problem] = deliveryResult;
if (status !== 'ok') {
Expand Down Expand Up @@ -572,15 +573,14 @@ export default function buildKernel(
}
}

const gcTools = harden({ WeakRef, FinalizationRegistry });
const gcTools = harden({ WeakRef, FinalizationRegistry, waitUntilQuiescent });
const vatManagerFactory = makeVatManagerFactory({
allVatPowers,
kernelKeeper,
vatEndowments,
meterManager,
testLog,
transformMetering,
waitUntilQuiescent,
makeNodeWorker,
startSubprocessWorkerNode,
startXSnap,
Expand Down Expand Up @@ -656,18 +656,16 @@ export default function buildKernel(
* might tell the manager to replay the transcript later, if it notices
* we're reloading a saved state vector.
*/
function addVatManager(vatID, manager, managerOptions) {
function addVatManager(vatID, manager, translators, managerOptions) {
// addVatManager takes a manager, not a promise for one
assert(
manager.deliver && manager.setVatSyscallHandler,
manager.deliver,
`manager lacks .deliver, isPromise=${manager instanceof Promise}`,
);
const {
enablePipelining = false,
notifyTermination = () => {},
} = managerOptions;
kernelKeeper.getVatKeeper(vatID);
const translators = makeVatTranslators(vatID, kernelKeeper);

ephemeral.vats.set(
vatID,
Expand All @@ -678,9 +676,6 @@ export default function buildKernel(
enablePipelining: Boolean(enablePipelining),
}),
);

const vatSyscallHandler = buildVatSyscallHandler(vatID, translators);
manager.setVatSyscallHandler(vatSyscallHandler);
}

const {
Expand All @@ -699,6 +694,7 @@ export default function buildKernel(
queueToExport,
kernelKeeper,
panic,
buildVatSyscallHandler,
});

/**
Expand Down
29 changes: 27 additions & 2 deletions packages/SwingSet/src/kernel/liveSlots.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { assert, details as X } from '@agoric/assert';
import { isPromise } from '@agoric/promise-kit';
import { insistVatType, makeVatSlot, parseVatSlot } from '../parseVatSlots';
import { insistCapData } from '../capdata';
import { insistMessage } from '../message';
import { makeVirtualObjectManager } from './virtualObjectManager';

const DEFAULT_VIRTUAL_OBJECT_CACHE_SIZE = 3; // XXX ridiculously small value to force churn for testing
Expand Down Expand Up @@ -679,12 +680,36 @@ function build(
const rootObject = buildRootObject(harden(vpow), harden(vatParameters));
assert.equal(passStyleOf(rootObject), REMOTE_STYLE);

const rootSlot = makeVatSlot('object', true, 0n);
const rootSlot = makeVatSlot('object', true, BigInt(0));
valToSlot.set(rootObject, rootSlot);
slotToVal.set(rootSlot, rootObject);
}

const dispatch = harden({ deliver, notify, dropExports });
function dispatch(vatDeliveryObject) {
const [type, ...args] = vatDeliveryObject;
switch (type) {
case 'message': {
const [targetSlot, msg] = args;
insistMessage(msg);
deliver(targetSlot, msg.method, msg.args, msg.result);
break;
}
case 'notify': {
const [resolutions] = args;
notify(resolutions);
break;
}
case 'dropExports': {
const [vrefs] = args;
dropExports(vrefs);
break;
}
default:
assert.fail(X`unknown delivery type ${type}`);
}
}
harden(dispatch);

return harden({ vatGlobals, setBuildRootObject, dispatch, m });
}

Expand Down
22 changes: 18 additions & 4 deletions packages/SwingSet/src/kernel/loadVat.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { assert, details as X } from '@agoric/assert';
import { assertKnownOptions } from '../assertOptions';
import { makeVatSlot } from '../parseVatSlots';
import { insistCapData } from '../capdata';
import { makeVatTranslators } from './vatTranslator';

export function makeVatRootObjectSlot() {
return makeVatSlot('object', true, 0n);
Expand All @@ -19,6 +20,7 @@ export function makeVatLoader(stuff) {
queueToExport,
kernelKeeper,
panic,
buildVatSyscallHandler,
} = stuff;

/**
Expand Down Expand Up @@ -229,11 +231,17 @@ export function makeVatLoader(stuff) {
// object) and for the spawner vat (not so easy). To avoid deeper changes,
// we enable it for *all* static vats here. Once #1343 is fixed, remove
// this addition and all support for internal metering.
const translators = makeVatTranslators(vatID, kernelKeeper);
const vatSyscallHandler = buildVatSyscallHandler(vatID, translators);

const finish = kernelSlog.startup(vatID);
const manager = await vatManagerFactory(vatID, managerOptions);
const manager = await vatManagerFactory(
vatID,
managerOptions,
vatSyscallHandler,
);
finish();
addVatManager(vatID, manager, managerOptions);
addVatManager(vatID, manager, translators, managerOptions);
}

function makeSuccessResponse() {
Expand Down Expand Up @@ -304,8 +312,14 @@ export function makeVatLoader(stuff) {
enableSetup: true,
managerType: 'local',
};
const manager = await vatManagerFactory(vatID, managerOptions);
addVatManager(vatID, manager, managerOptions);
const translators = makeVatTranslators(vatID, kernelKeeper);
const vatSyscallHandler = buildVatSyscallHandler(vatID, translators);
const manager = await vatManagerFactory(
vatID,
managerOptions,
vatSyscallHandler,
);
addVatManager(vatID, manager, translators, managerOptions);
}

return harden({
Expand Down
153 changes: 0 additions & 153 deletions packages/SwingSet/src/kernel/vatManager/deliver.js

This file was deleted.

Loading

0 comments on commit ec2e993

Please sign in to comment.