@agoric/swingset-liveslots 0.10.3-other-dev-8f8782b.0 → 0.10.3-other-dev-fbe72e7.0.fbe72e7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +34 -26
- package/src/boyd-gc.d.ts +12 -0
- package/src/boyd-gc.d.ts.map +1 -0
- package/src/boyd-gc.js +598 -0
- package/src/cache.d.ts +71 -0
- package/src/cache.d.ts.map +1 -0
- package/src/cache.js +3 -2
- package/src/capdata.d.ts +16 -0
- package/src/capdata.d.ts.map +1 -0
- package/src/capdata.js +17 -10
- package/src/collectionManager.d.ts +47 -0
- package/src/collectionManager.d.ts.map +1 -0
- package/src/collectionManager.js +220 -103
- package/src/facetiousness.d.ts +25 -0
- package/src/facetiousness.d.ts.map +1 -0
- package/src/facetiousness.js +1 -1
- package/src/index.d.ts +4 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +4 -2
- package/src/kdebug.d.ts +7 -0
- package/src/kdebug.d.ts.map +1 -0
- package/src/liveslots.d.ts +42 -0
- package/src/liveslots.d.ts.map +1 -0
- package/src/liveslots.js +137 -305
- package/src/message.d.ts +49 -0
- package/src/message.d.ts.map +1 -0
- package/src/message.js +9 -5
- package/src/parseVatSlots.d.ts +125 -0
- package/src/parseVatSlots.d.ts.map +1 -0
- package/src/parseVatSlots.js +1 -1
- package/src/types-index.d.ts +4 -0
- package/src/types-index.js +2 -0
- package/src/types.d.ts +81 -0
- package/src/types.d.ts.map +1 -0
- package/src/types.js +14 -7
- package/src/vatDataTypes.d.ts +170 -0
- package/src/vatDataTypes.d.ts.map +1 -0
- package/src/vatDataTypes.ts +272 -0
- package/src/vatstore-iterators.d.ts +4 -0
- package/src/vatstore-iterators.d.ts.map +1 -0
- package/src/vatstore-iterators.js +2 -0
- package/src/vatstore-usage.md +198 -0
- package/src/virtualObjectManager.d.ts +44 -0
- package/src/virtualObjectManager.d.ts.map +1 -0
- package/src/virtualObjectManager.js +254 -84
- package/src/virtualReferences.d.ts +61 -0
- package/src/virtualReferences.d.ts.map +1 -0
- package/src/virtualReferences.js +135 -26
- package/src/vpid-tracking.md +92 -0
- package/src/watchedPromises.d.ts +31 -0
- package/src/watchedPromises.d.ts.map +1 -0
- package/src/watchedPromises.js +81 -24
- package/test/{test-baggage.js → baggage.test.js} +1 -2
- package/test/{test-cache.js → cache.test.js} +0 -1
- package/test/clear-collection.test.js +586 -0
- package/test/{test-collection-schema-refcount.js → collection-schema-refcount.test.js} +1 -2
- package/test/{test-collection-upgrade.js → collection-upgrade.test.js} +1 -3
- package/test/{test-collections.js → collections.test.js} +183 -18
- package/test/{test-dropped-collection-weakrefs.js → dropped-collection-weakrefs.test.js} +1 -2
- package/test/dropped-weakset-9939.test.js +80 -0
- package/test/dummyMeterControl.d.ts +2 -0
- package/test/dummyMeterControl.d.ts.map +1 -0
- package/test/dummyMeterControl.js +1 -1
- package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +4 -4
- package/test/engine-gc.d.ts +3 -0
- package/test/engine-gc.d.ts.map +1 -0
- package/test/exo-utils.js +70 -0
- package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
- package/test/gc-and-finalize.d.ts +5 -0
- package/test/gc-and-finalize.d.ts.map +1 -0
- package/test/gc-and-finalize.js +30 -1
- package/test/gc-before-finalizer.test.js +230 -0
- package/test/gc-helpers.js +4 -5
- package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
- package/test/handled-promises.test.js +872 -0
- package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +13 -20
- package/test/liveslots-helpers.d.ts +64 -0
- package/test/liveslots-helpers.d.ts.map +1 -0
- package/test/liveslots-helpers.js +13 -7
- package/test/{test-liveslots-mock-gc.js → liveslots-mock-gc.test.js} +101 -2
- package/test/{test-liveslots-real-gc.js → liveslots-real-gc.test.js} +73 -46
- package/test/{test-liveslots.js → liveslots.test.js} +17 -18
- package/test/mock-gc.js +1 -0
- package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +15 -14
- package/test/storeGC/{test-refcount-management.js → refcount-management.test.js} +1 -2
- package/test/storeGC/{test-scalar-store-kind.js → scalar-store-kind.test.js} +0 -1
- package/test/storeGC/{test-weak-key.js → weak-key.test.js} +1 -2
- package/test/strict-test-env-upgrade.test.js +94 -0
- package/test/util.d.ts +25 -0
- package/test/util.d.ts.map +1 -0
- package/test/util.js +4 -4
- package/test/vat-environment.test.js +65 -0
- package/test/vat-util.d.ts +9 -0
- package/test/vat-util.d.ts.map +1 -0
- package/test/vat-util.js +2 -2
- package/test/virtual-objects/{test-cease-recognition.js → cease-recognition.test.js} +2 -2
- package/test/virtual-objects/{test-cross-facet.js → cross-facet.test.js} +5 -4
- package/test/virtual-objects/{test-empty-data.js → empty-data.test.js} +1 -2
- package/test/virtual-objects/{test-facets.js → facets.test.js} +1 -2
- package/test/virtual-objects/{test-kind-changes.js → kind-changes.test.js} +2 -2
- package/test/virtual-objects/{test-reachable-vrefs.js → reachable-vrefs.test.js} +2 -2
- package/test/virtual-objects/{test-rep-tostring.js → rep-tostring.test.js} +3 -5
- package/test/virtual-objects/{test-retain-remotable.js → retain-remotable.test.js} +25 -24
- package/test/virtual-objects/set-debug-label-instances.js +1 -1
- package/test/virtual-objects/state-shape.test.js +389 -0
- package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +39 -38
- package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +104 -8
- package/test/virtual-objects/{test-vo-real-gc.js → vo-real-gc.test.js} +8 -8
- package/test/virtual-objects/{test-weakcollections-vref-handling.js → weakcollections-vref-handling.test.js} +1 -2
- package/test/{test-vo-test-harness.js → vo-test-harness.test.js} +13 -10
- package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +105 -5
- package/test/waitUntilQuiescent.d.ts +3 -0
- package/test/waitUntilQuiescent.d.ts.map +1 -0
- package/test/waitUntilQuiescent.js +2 -1
- package/test/weakset-dropped-remotable.test.js +50 -0
- package/tools/fakeCollectionManager.d.ts +14 -0
- package/tools/fakeCollectionManager.d.ts.map +1 -0
- package/tools/fakeCollectionManager.js +44 -0
- package/tools/fakeVirtualObjectManager.d.ts +32 -0
- package/tools/fakeVirtualObjectManager.d.ts.map +1 -0
- package/tools/fakeVirtualObjectManager.js +62 -0
- package/tools/fakeVirtualSupport.d.ts +278 -0
- package/tools/fakeVirtualSupport.d.ts.map +1 -0
- package/tools/fakeVirtualSupport.js +389 -0
- package/tools/prepare-strict-test-env.d.ts +37 -0
- package/tools/prepare-strict-test-env.d.ts.map +1 -0
- package/tools/prepare-strict-test-env.js +124 -0
- package/tools/prepare-test-env.d.ts +2 -0
- package/tools/prepare-test-env.d.ts.map +1 -0
- package/tools/prepare-test-env.js +13 -0
- package/tools/setup-vat-data.d.ts +9 -0
- package/tools/setup-vat-data.d.ts.map +1 -0
- package/tools/setup-vat-data.js +95 -0
- package/tools/vo-test-harness.d.ts +33 -0
- package/tools/vo-test-harness.d.ts.map +1 -0
- package/tools/vo-test-harness.js +164 -0
- package/CHANGELOG.md +0 -61
- package/test/kmarshal.js +0 -79
- package/test/test-handled-promises.js +0 -360
- package/test/virtual-objects/test-state-shape.js +0 -298
package/src/liveslots.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
makeMarshal,
|
|
6
|
-
} from '@endo/marshal';
|
|
7
|
-
import { assert, Fail } from '@agoric/assert';
|
|
1
|
+
import { annotateError, assert, Fail, makeError, X } from '@endo/errors';
|
|
2
|
+
import { passStyleOf } from '@endo/pass-style';
|
|
3
|
+
import { PassStyleOfEndowmentSymbol } from '@endo/pass-style/endow.js';
|
|
4
|
+
import { Remotable, getInterfaceOf, makeMarshal } from '@endo/marshal';
|
|
8
5
|
import { isPromise } from '@endo/promise-kit';
|
|
9
6
|
import { E, HandledPromise } from '@endo/eventual-send';
|
|
10
7
|
import { insistVatType, makeVatSlot, parseVatSlot } from './parseVatSlots.js';
|
|
@@ -15,12 +12,13 @@ import { makeVirtualReferenceManager } from './virtualReferences.js';
|
|
|
15
12
|
import { makeVirtualObjectManager } from './virtualObjectManager.js';
|
|
16
13
|
import { makeCollectionManager } from './collectionManager.js';
|
|
17
14
|
import { makeWatchedPromiseManager } from './watchedPromises.js';
|
|
15
|
+
import { makeBOYDKit } from './boyd-gc.js';
|
|
16
|
+
|
|
17
|
+
/** @import {LimitedConsole} from '@agoric/internal/src/js-utils.js'; */
|
|
18
18
|
|
|
19
19
|
const SYSCALL_CAPDATA_BODY_SIZE_LIMIT = 10_000_000;
|
|
20
20
|
const SYSCALL_CAPDATA_SLOTS_LENGTH_LIMIT = 10_000;
|
|
21
21
|
|
|
22
|
-
const { details: X } = assert;
|
|
23
|
-
|
|
24
22
|
// 'makeLiveSlots' is a dispatcher which uses javascript Maps to keep track
|
|
25
23
|
// of local objects which have been exported. These cannot be persisted
|
|
26
24
|
// beyond the runtime of the javascript environment, so this mechanism is not
|
|
@@ -33,10 +31,10 @@ const { details: X } = assert;
|
|
|
33
31
|
* @param {*} syscall Kernel syscall interface that the vat will have access to
|
|
34
32
|
* @param {*} forVatID Vat ID label, for use in debug diagnostics
|
|
35
33
|
* @param {*} vatPowers
|
|
36
|
-
* @param {import('./types').LiveSlotsOptions} liveSlotsOptions
|
|
34
|
+
* @param {import('./types.js').LiveSlotsOptions} liveSlotsOptions
|
|
37
35
|
* @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent, gcAndFinalize,
|
|
38
36
|
* meterControl }
|
|
39
|
-
* @param {
|
|
37
|
+
* @param {LimitedConsole} console
|
|
40
38
|
* @param {*} buildVatNamespace
|
|
41
39
|
*
|
|
42
40
|
* @returns {*} { dispatch }
|
|
@@ -159,10 +157,8 @@ function build(
|
|
|
159
157
|
const { type, allocatedByVat, virtual, durable } = parseVatSlot(vref);
|
|
160
158
|
if (type === 'object' && allocatedByVat) {
|
|
161
159
|
if (virtual || durable) {
|
|
162
|
-
// eslint-disable-next-line no-use-before-define
|
|
163
160
|
vrm.setExportStatus(vref, 'reachable');
|
|
164
161
|
} else {
|
|
165
|
-
// eslint-disable-next-line no-use-before-define
|
|
166
162
|
const remotable = requiredValForSlot(vref);
|
|
167
163
|
exportedRemotables.add(remotable);
|
|
168
164
|
kernelRecognizableRemotables.add(vref);
|
|
@@ -170,52 +166,6 @@ function build(
|
|
|
170
166
|
}
|
|
171
167
|
}
|
|
172
168
|
|
|
173
|
-
/*
|
|
174
|
-
Imports are in one of 5 states: UNKNOWN, REACHABLE, UNREACHABLE,
|
|
175
|
-
COLLECTED, FINALIZED. Note that there's no actual state machine with those
|
|
176
|
-
values, and we can't observe all of the transitions from JavaScript, but
|
|
177
|
-
we can describe what operations could cause a transition, and what our
|
|
178
|
-
observations allow us to deduce about the state:
|
|
179
|
-
|
|
180
|
-
* UNKNOWN moves to REACHABLE when a crank introduces a new import
|
|
181
|
-
* userspace holds a reference only in REACHABLE
|
|
182
|
-
* REACHABLE moves to UNREACHABLE only during a userspace crank
|
|
183
|
-
* UNREACHABLE moves to COLLECTED when GC runs, which queues the finalizer
|
|
184
|
-
* COLLECTED moves to FINALIZED when a new turn runs the finalizer
|
|
185
|
-
* liveslots moves from FINALIZED to UNKNOWN by syscalling dropImports
|
|
186
|
-
|
|
187
|
-
convertSlotToVal either imports a vref for the first time, or
|
|
188
|
-
re-introduces a previously-seen vref. It transitions from:
|
|
189
|
-
|
|
190
|
-
* UNKNOWN to REACHABLE by creating a new Presence
|
|
191
|
-
* UNREACHABLE to REACHABLE by re-using the old Presence that userspace
|
|
192
|
-
forgot about
|
|
193
|
-
* COLLECTED/FINALIZED to REACHABLE by creating a new Presence
|
|
194
|
-
|
|
195
|
-
Our tracking tables hold data that depends on the current state:
|
|
196
|
-
|
|
197
|
-
* slotToVal holds a WeakRef in [REACHABLE, UNREACHABLE, COLLECTED]
|
|
198
|
-
* that WeakRef .deref()s into something in [REACHABLE, UNREACHABLE]
|
|
199
|
-
* deadSet holds the vref only in FINALIZED
|
|
200
|
-
* re-introduction must ensure the vref is not in the deadSet
|
|
201
|
-
|
|
202
|
-
Each state thus has a set of perhaps-measurable properties:
|
|
203
|
-
|
|
204
|
-
* UNKNOWN: slotToVal[baseRef] is missing, baseRef not in deadSet
|
|
205
|
-
* REACHABLE: slotToVal has live weakref, userspace can reach
|
|
206
|
-
* UNREACHABLE: slotToVal has live weakref, userspace cannot reach
|
|
207
|
-
* COLLECTED: slotToVal[baseRef] has dead weakref
|
|
208
|
-
* FINALIZED: slotToVal[baseRef] is missing, baseRef is in deadSet
|
|
209
|
-
|
|
210
|
-
Our finalizer callback is queued by the engine's transition from
|
|
211
|
-
UNREACHABLE to COLLECTED, but the baseRef might be re-introduced before the
|
|
212
|
-
callback has a chance to run. There might even be multiple copies of the
|
|
213
|
-
finalizer callback queued. So the callback must deduce the current state
|
|
214
|
-
and only perform cleanup (i.e. delete the slotToVal entry and add the
|
|
215
|
-
baseRef to the deadSet) in the COLLECTED state.
|
|
216
|
-
|
|
217
|
-
*/
|
|
218
|
-
|
|
219
169
|
function finalizeDroppedObject(baseRef) {
|
|
220
170
|
// TODO: Ideally this function should assert that it is not metered. This
|
|
221
171
|
// appears to be fine in practice, but it breaks a number of unit tests in
|
|
@@ -233,124 +183,12 @@ function build(
|
|
|
233
183
|
|
|
234
184
|
if (wr && !wr.deref()) {
|
|
235
185
|
// we're in the COLLECTED state, or FINALIZED after a re-introduction
|
|
236
|
-
// eslint-disable-next-line no-use-before-define
|
|
237
186
|
addToPossiblyDeadSet(baseRef);
|
|
238
187
|
slotToVal.delete(baseRef);
|
|
239
188
|
}
|
|
240
189
|
}
|
|
241
190
|
const vreffedObjectRegistry = new FinalizationRegistry(finalizeDroppedObject);
|
|
242
191
|
|
|
243
|
-
async function scanForDeadObjects() {
|
|
244
|
-
// `possiblyDeadSet` accumulates vrefs which have lost a supporting
|
|
245
|
-
// pillar (in-memory, export, or virtualized data refcount) since the
|
|
246
|
-
// last call to scanForDeadObjects. The vref might still be supported
|
|
247
|
-
// by a remaining pillar, or the pillar which was dropped might be back
|
|
248
|
-
// (e.g., given a new in-memory manifestation).
|
|
249
|
-
|
|
250
|
-
const importsToDrop = new Set();
|
|
251
|
-
const importsToRetire = new Set();
|
|
252
|
-
const exportsToRetire = new Set();
|
|
253
|
-
let doMore;
|
|
254
|
-
do {
|
|
255
|
-
doMore = false;
|
|
256
|
-
|
|
257
|
-
// Yes, we know this is an await inside a loop. Too bad. (Also, it's a
|
|
258
|
-
// `do {} while` loop, which means there's no conditional bypass of the
|
|
259
|
-
// await.)
|
|
260
|
-
// eslint-disable-next-line no-await-in-loop, @jessie.js/no-nested-await
|
|
261
|
-
await gcTools.gcAndFinalize();
|
|
262
|
-
|
|
263
|
-
// possiblyDeadSet contains a baseref for everything (Presences,
|
|
264
|
-
// Remotables, Representatives) that might have lost a
|
|
265
|
-
// pillar. The object might still be supported by other pillars,
|
|
266
|
-
// and the lost pillar might have been reinstantiated by the
|
|
267
|
-
// time we get here. The first step is to filter this down to a
|
|
268
|
-
// list of definitely dead baserefs.
|
|
269
|
-
|
|
270
|
-
const deadSet = new Set();
|
|
271
|
-
|
|
272
|
-
for (const baseRef of possiblyDeadSet) {
|
|
273
|
-
// eslint-disable-next-line no-use-before-define
|
|
274
|
-
if (slotToVal.has(baseRef)) {
|
|
275
|
-
continue; // RAM pillar remains
|
|
276
|
-
}
|
|
277
|
-
const { virtual, durable, type } = parseVatSlot(baseRef);
|
|
278
|
-
assert(type === 'object', `unprepared to track ${type}`);
|
|
279
|
-
if (virtual || durable) {
|
|
280
|
-
// eslint-disable-next-line no-use-before-define
|
|
281
|
-
if (vrm.isVirtualObjectReachable(baseRef)) {
|
|
282
|
-
continue; // vdata or export pillar remains
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
deadSet.add(baseRef);
|
|
286
|
-
}
|
|
287
|
-
possiblyDeadSet.clear();
|
|
288
|
-
|
|
289
|
-
// deadSet now contains objects which are certainly dead
|
|
290
|
-
|
|
291
|
-
// possiblyRetiredSet holds (a subset of??) baserefs which have
|
|
292
|
-
// lost a recognizer recently. TODO recheck this
|
|
293
|
-
|
|
294
|
-
for (const vref of possiblyRetiredSet) {
|
|
295
|
-
// eslint-disable-next-line no-use-before-define
|
|
296
|
-
if (!getValForSlot(vref) && !deadSet.has(vref)) {
|
|
297
|
-
// Don't retire things that haven't yet made the transition to dead,
|
|
298
|
-
// i.e., always drop before retiring
|
|
299
|
-
// eslint-disable-next-line no-use-before-define
|
|
300
|
-
if (!vrm.isVrefRecognizable(vref)) {
|
|
301
|
-
importsToRetire.add(vref);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
possiblyRetiredSet.clear();
|
|
306
|
-
|
|
307
|
-
const deadBaseRefs = Array.from(deadSet);
|
|
308
|
-
deadBaseRefs.sort();
|
|
309
|
-
for (const baseRef of deadBaseRefs) {
|
|
310
|
-
const { virtual, durable, allocatedByVat, type } =
|
|
311
|
-
parseVatSlot(baseRef);
|
|
312
|
-
type === 'object' || Fail`unprepared to track ${type}`;
|
|
313
|
-
if (virtual || durable) {
|
|
314
|
-
// Representative: send nothing, but perform refcount checking
|
|
315
|
-
// eslint-disable-next-line no-use-before-define
|
|
316
|
-
const [gcAgain, retirees] = vrm.deleteVirtualObject(baseRef);
|
|
317
|
-
if (retirees) {
|
|
318
|
-
retirees.map(retiree => exportsToRetire.add(retiree));
|
|
319
|
-
}
|
|
320
|
-
doMore = doMore || gcAgain;
|
|
321
|
-
} else if (allocatedByVat) {
|
|
322
|
-
// Remotable: send retireExport
|
|
323
|
-
// for remotables, vref === baseRef
|
|
324
|
-
if (kernelRecognizableRemotables.has(baseRef)) {
|
|
325
|
-
kernelRecognizableRemotables.delete(baseRef);
|
|
326
|
-
exportsToRetire.add(baseRef);
|
|
327
|
-
}
|
|
328
|
-
} else {
|
|
329
|
-
// Presence: send dropImport unless reachable by VOM
|
|
330
|
-
// eslint-disable-next-line no-lonely-if, no-use-before-define
|
|
331
|
-
if (!vrm.isPresenceReachable(baseRef)) {
|
|
332
|
-
importsToDrop.add(baseRef);
|
|
333
|
-
// eslint-disable-next-line no-use-before-define
|
|
334
|
-
if (!vrm.isVrefRecognizable(baseRef)) {
|
|
335
|
-
// for presences, baseRef === vref
|
|
336
|
-
importsToRetire.add(baseRef);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
} while (possiblyDeadSet.size > 0 || possiblyRetiredSet.size > 0 || doMore);
|
|
342
|
-
|
|
343
|
-
if (importsToDrop.size) {
|
|
344
|
-
syscall.dropImports(Array.from(importsToDrop).sort());
|
|
345
|
-
}
|
|
346
|
-
if (importsToRetire.size) {
|
|
347
|
-
syscall.retireImports(Array.from(importsToRetire).sort());
|
|
348
|
-
}
|
|
349
|
-
if (exportsToRetire.size) {
|
|
350
|
-
syscall.retireExports(Array.from(exportsToRetire).sort());
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
192
|
/**
|
|
355
193
|
* Remember disavowed Presences which will kill the vat if you try to talk
|
|
356
194
|
* to them
|
|
@@ -370,11 +208,9 @@ function build(
|
|
|
370
208
|
// Support: o~.[prop](...args) remote method invocation
|
|
371
209
|
lsdebug(`makeImportedPresence handler.applyMethod (${slot})`);
|
|
372
210
|
if (disavowedPresences.has(o)) {
|
|
373
|
-
// eslint-disable-next-line no-use-before-define
|
|
374
211
|
exitVatWithFailure(disavowalError);
|
|
375
212
|
throw disavowalError;
|
|
376
213
|
}
|
|
377
|
-
// eslint-disable-next-line no-use-before-define
|
|
378
214
|
return queueMessage(slot, prop, args, returnedP);
|
|
379
215
|
},
|
|
380
216
|
applyFunction(o, args, returnedP) {
|
|
@@ -383,7 +219,6 @@ function build(
|
|
|
383
219
|
get(o, prop) {
|
|
384
220
|
lsdebug(`makeImportedPresence handler.get (${slot})`);
|
|
385
221
|
if (disavowedPresences.has(o)) {
|
|
386
|
-
// eslint-disable-next-line no-use-before-define
|
|
387
222
|
exitVatWithFailure(disavowalError);
|
|
388
223
|
throw disavowalError;
|
|
389
224
|
}
|
|
@@ -455,7 +290,6 @@ function build(
|
|
|
455
290
|
console.error(`mIPromise handler called after resolution`);
|
|
456
291
|
Fail`mIPromise handler called after resolution`;
|
|
457
292
|
}
|
|
458
|
-
// eslint-disable-next-line no-use-before-define
|
|
459
293
|
return queueMessage(vpid, prop, args, returnedP);
|
|
460
294
|
},
|
|
461
295
|
get(p, prop) {
|
|
@@ -500,54 +334,6 @@ function build(
|
|
|
500
334
|
return Remotable(iface);
|
|
501
335
|
}
|
|
502
336
|
|
|
503
|
-
/**
|
|
504
|
-
* Counters to track the next number for various categories of allocation.
|
|
505
|
-
* `exportID` starts at 1 because 'o+0' is always automatically
|
|
506
|
-
* pre-assigned to the root object.
|
|
507
|
-
* `promiseID` starts at 5 as a very minor aid to debugging: when puzzling
|
|
508
|
-
* over trace logs and the like, it helps for the numbers in various species
|
|
509
|
-
* of IDs that are jumbled together to be a little out of sync and thus a
|
|
510
|
-
* little less similar to each other.
|
|
511
|
-
*/
|
|
512
|
-
const initialIDCounters = { exportID: 1, collectionID: 1, promiseID: 5 };
|
|
513
|
-
/** @type {Record<string, number>} */
|
|
514
|
-
let idCounters;
|
|
515
|
-
let idCountersAreDirty = false;
|
|
516
|
-
|
|
517
|
-
function initializeIDCounters() {
|
|
518
|
-
if (!idCounters) {
|
|
519
|
-
// the saved value might be missing, or from an older liveslots
|
|
520
|
-
// (with fewer counters), so merge it with our initial values
|
|
521
|
-
const saved = JSON.parse(syscall.vatstoreGet('idCounters') || '{}');
|
|
522
|
-
idCounters = { ...initialIDCounters, ...saved };
|
|
523
|
-
idCountersAreDirty = true;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
function allocateNextID(name) {
|
|
528
|
-
if (!idCounters) {
|
|
529
|
-
// Normally `initializeIDCounters` would be called from startVat, but some
|
|
530
|
-
// tests bypass that so this is a backstop. Note that the invocation from
|
|
531
|
-
// startVat is there to make vatStore access patterns a bit more
|
|
532
|
-
// consistent from one vat to another, principally as a confusion
|
|
533
|
-
// reduction measure in service of debugging; it is not a correctness
|
|
534
|
-
// issue.
|
|
535
|
-
initializeIDCounters();
|
|
536
|
-
}
|
|
537
|
-
const result = idCounters[name];
|
|
538
|
-
result !== undefined || Fail`unknown idCounters[${name}]`;
|
|
539
|
-
idCounters[name] += 1;
|
|
540
|
-
idCountersAreDirty = true;
|
|
541
|
-
return result;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
function flushIDCounters() {
|
|
545
|
-
if (idCountersAreDirty) {
|
|
546
|
-
syscall.vatstoreSet('idCounters', JSON.stringify(idCounters));
|
|
547
|
-
idCountersAreDirty = false;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
337
|
// TODO: fix awkward non-orthogonality: allocateExportID() returns a number,
|
|
552
338
|
// allocatePromiseID() returns a slot, registerPromise() uses the slot from
|
|
553
339
|
// allocatePromiseID(), exportPassByPresence() generates a slot itself using
|
|
@@ -556,15 +342,15 @@ function build(
|
|
|
556
342
|
// use a slot from the corresponding allocateX
|
|
557
343
|
|
|
558
344
|
function allocateExportID() {
|
|
559
|
-
return allocateNextID('exportID');
|
|
345
|
+
return vrm.allocateNextID('exportID');
|
|
560
346
|
}
|
|
561
347
|
|
|
562
348
|
function allocateCollectionID() {
|
|
563
|
-
return allocateNextID('collectionID');
|
|
349
|
+
return vrm.allocateNextID('collectionID');
|
|
564
350
|
}
|
|
565
351
|
|
|
566
352
|
function allocatePromiseID() {
|
|
567
|
-
const promiseID = allocateNextID('promiseID');
|
|
353
|
+
const promiseID = vrm.allocateNextID('promiseID');
|
|
568
354
|
return makeVatSlot('promise', true, promiseID);
|
|
569
355
|
}
|
|
570
356
|
|
|
@@ -591,10 +377,8 @@ function build(
|
|
|
591
377
|
// do a syscall.resolve when it fires. The caller must finish
|
|
592
378
|
// doing their syscall before this turn finishes, to ensure the
|
|
593
379
|
// kernel isn't surprised by a spurious resolution.
|
|
594
|
-
// eslint-disable-next-line no-use-before-define
|
|
595
380
|
const p = requiredValForSlot(vpid);
|
|
596
381
|
// if (!knownResolutions.has(p)) { // TODO really?
|
|
597
|
-
// eslint-disable-next-line no-use-before-define
|
|
598
382
|
followForKernel(vpid, p);
|
|
599
383
|
return true;
|
|
600
384
|
}
|
|
@@ -606,20 +390,18 @@ function build(
|
|
|
606
390
|
return makeVatSlot('object', true, exportID);
|
|
607
391
|
}
|
|
608
392
|
|
|
609
|
-
// eslint-disable-next-line no-use-before-define
|
|
610
393
|
const m = makeMarshal(convertValToSlot, convertSlotToVal, {
|
|
611
394
|
marshalName: `liveSlots:${forVatID}`,
|
|
612
395
|
serializeBodyFormat: 'smallcaps',
|
|
613
396
|
// TODO Temporary hack.
|
|
614
397
|
// See https://github.com/Agoric/agoric-sdk/issues/2780
|
|
615
|
-
errorIdNum:
|
|
398
|
+
errorIdNum: 70_000,
|
|
616
399
|
marshalSaveError: err =>
|
|
617
400
|
// By sending this to `console.warn`, under cosmic-swingset this is
|
|
618
401
|
// controlled by the `console` option given to makeLiveSlots.
|
|
619
402
|
console.warn('Logging sent error stack', err),
|
|
620
403
|
});
|
|
621
404
|
const unmeteredUnserialize = meterControl.unmetered(m.unserialize);
|
|
622
|
-
// eslint-disable-next-line no-use-before-define
|
|
623
405
|
const unmeteredConvertSlotToVal = meterControl.unmetered(convertSlotToVal);
|
|
624
406
|
|
|
625
407
|
function getSlotForVal(val) {
|
|
@@ -664,7 +446,6 @@ function build(
|
|
|
664
446
|
allocateExportID,
|
|
665
447
|
getSlotForVal,
|
|
666
448
|
requiredValForSlot,
|
|
667
|
-
// eslint-disable-next-line no-use-before-define
|
|
668
449
|
registerValue,
|
|
669
450
|
m.serialize,
|
|
670
451
|
unmeteredUnserialize,
|
|
@@ -677,10 +458,8 @@ function build(
|
|
|
677
458
|
vrm,
|
|
678
459
|
allocateExportID,
|
|
679
460
|
allocateCollectionID,
|
|
680
|
-
// eslint-disable-next-line no-use-before-define
|
|
681
461
|
convertValToSlot,
|
|
682
462
|
unmeteredConvertSlotToVal,
|
|
683
|
-
// eslint-disable-next-line no-use-before-define
|
|
684
463
|
registerValue,
|
|
685
464
|
m.serialize,
|
|
686
465
|
unmeteredUnserialize,
|
|
@@ -692,7 +471,6 @@ function build(
|
|
|
692
471
|
vrm,
|
|
693
472
|
vom,
|
|
694
473
|
collectionManager,
|
|
695
|
-
// eslint-disable-next-line no-use-before-define
|
|
696
474
|
convertValToSlot,
|
|
697
475
|
convertSlotToVal: unmeteredConvertSlotToVal,
|
|
698
476
|
maybeExportPromise,
|
|
@@ -722,7 +500,6 @@ function build(
|
|
|
722
500
|
slot = allocatePromiseID();
|
|
723
501
|
} else {
|
|
724
502
|
if (disavowedPresences.has(val)) {
|
|
725
|
-
// eslint-disable-next-line no-use-before-define
|
|
726
503
|
exitVatWithFailure(disavowalError);
|
|
727
504
|
throw disavowalError; // cannot reference a disavowed object
|
|
728
505
|
}
|
|
@@ -759,9 +536,9 @@ function build(
|
|
|
759
536
|
Fail`registerValue(${baseRef} should not receive individual facets`;
|
|
760
537
|
slotToVal.set(baseRef, new WeakRef(val));
|
|
761
538
|
if (valIsCohort) {
|
|
762
|
-
vrm.getFacetNames(id).
|
|
539
|
+
for (const [index, name] of vrm.getFacetNames(id).entries()) {
|
|
763
540
|
valToSlot.set(val[name], `${baseRef}:${index}`);
|
|
764
|
-
}
|
|
541
|
+
}
|
|
765
542
|
} else {
|
|
766
543
|
valToSlot.set(val, baseRef);
|
|
767
544
|
}
|
|
@@ -796,39 +573,50 @@ function build(
|
|
|
796
573
|
try {
|
|
797
574
|
val = vrm.reanimate(baseRef);
|
|
798
575
|
} catch (err) {
|
|
799
|
-
const wrappedError =
|
|
800
|
-
|
|
576
|
+
const wrappedError = makeError(X`failed to reanimate ${iface}`);
|
|
577
|
+
annotateError(wrappedError, X`Original error: ${err}`);
|
|
801
578
|
throw wrappedError;
|
|
802
579
|
}
|
|
803
580
|
if (facet !== undefined) {
|
|
804
581
|
result = vrm.getFacet(id, val, facet);
|
|
805
582
|
}
|
|
806
|
-
} else {
|
|
583
|
+
} else if (type === 'object') {
|
|
584
|
+
// Note: an abandonned (e.g. by an upgrade) exported ephemeral or virtual
|
|
585
|
+
// object would appear as an import if re-introduced. In the future we
|
|
586
|
+
// may need to change that if we want to keep recognizing such references
|
|
587
|
+
// In that case we'd need to create an imported presence for these
|
|
588
|
+
// unknown vrefs allocated by the vat.
|
|
589
|
+
// See https://github.com/Agoric/agoric-sdk/issues/9746
|
|
807
590
|
!allocatedByVat || Fail`I don't remember allocating ${slot}`;
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
val = makeDeviceNode(slot, iface);
|
|
828
|
-
importedDevices.add(val);
|
|
591
|
+
// this is a new import value
|
|
592
|
+
val = makeImportedPresence(slot, iface);
|
|
593
|
+
} else if (type === 'promise') {
|
|
594
|
+
// We unconditionally create a promise record, even if the promise looks
|
|
595
|
+
// like it was allocated by us. This can happen when re-importing a
|
|
596
|
+
// promise created by the previous incarnation. We may or may not have
|
|
597
|
+
// been the decider of the promise. If we were, the kernel will be
|
|
598
|
+
// rejecting the promise on our behalf. We may have previously been
|
|
599
|
+
// subscribed to that promise, but subscription is idempotent.
|
|
600
|
+
const pRec = makePipelinablePromise(slot);
|
|
601
|
+
importedVPIDs.set(slot, pRec);
|
|
602
|
+
val = pRec.promise;
|
|
603
|
+
// ideally we'd wait until .then is called on p before subscribing,
|
|
604
|
+
// but the current Promise API doesn't give us a way to discover
|
|
605
|
+
// this, so we must subscribe right away. If we were using Vows or
|
|
606
|
+
// some other then-able, we could just hook then() to notify us.
|
|
607
|
+
if (importedPromises) {
|
|
608
|
+
// leave the subscribe() up to dispatch.notify()
|
|
609
|
+
importedPromises.add(slot);
|
|
829
610
|
} else {
|
|
830
|
-
|
|
611
|
+
// probably in dispatch.deliver(), so subscribe now
|
|
612
|
+
syscall.subscribe(slot);
|
|
831
613
|
}
|
|
614
|
+
} else if (type === 'device') {
|
|
615
|
+
!allocatedByVat || Fail`unexpected device ${slot} allocated by vat`;
|
|
616
|
+
val = makeDeviceNode(slot, iface);
|
|
617
|
+
importedDevices.add(val);
|
|
618
|
+
} else {
|
|
619
|
+
Fail`unrecognized slot type '${type}'`;
|
|
832
620
|
}
|
|
833
621
|
registerValue(baseRef, val, facet !== undefined);
|
|
834
622
|
if (!result) {
|
|
@@ -841,7 +629,25 @@ function build(
|
|
|
841
629
|
meterControl.assertNotMetered();
|
|
842
630
|
const { type } = parseVatSlot(slot);
|
|
843
631
|
type === 'promise' || Fail`revivePromise called on non-promise ${slot}`;
|
|
844
|
-
|
|
632
|
+
const val = getValForSlot(slot);
|
|
633
|
+
if (val) {
|
|
634
|
+
// revivePromise is only called by loadWatchedPromiseTable, which runs
|
|
635
|
+
// after buildRootObject(), which is given the deserialized vatParameters.
|
|
636
|
+
// The only way revivePromise() might encounter a pre-existing vpid is if
|
|
637
|
+
// these vatParameters include a promise that the previous incarnation
|
|
638
|
+
// watched, but that `buildRootObject` in the new incarnation didn't
|
|
639
|
+
// explicitly watch again. This can be either a previously imported
|
|
640
|
+
// promise, or a promise the previous incarnation exported, regardless of
|
|
641
|
+
// who the decider now is.
|
|
642
|
+
//
|
|
643
|
+
// In that case convertSlotToVal() has already deserialized the vpid, but
|
|
644
|
+
// since `buildRootObject` didn't explicitely call watchPromise on it, no
|
|
645
|
+
// registration exists so loadWatchedPromiseTable attempts to revive the
|
|
646
|
+
// promise.
|
|
647
|
+
return val;
|
|
648
|
+
}
|
|
649
|
+
// NOTE: it is important that this code not do anything *more*
|
|
650
|
+
// than what convertSlotToVal(vpid) would do
|
|
845
651
|
const pRec = makePipelinablePromise(slot);
|
|
846
652
|
importedVPIDs.set(slot, pRec);
|
|
847
653
|
const p = pRec.promise;
|
|
@@ -863,7 +669,6 @@ function build(
|
|
|
863
669
|
const priorResolution = knownResolutions.get(p);
|
|
864
670
|
if (priorResolution && !doneResolutions.has(slot)) {
|
|
865
671
|
const [priorRejected, priorRes] = priorResolution;
|
|
866
|
-
// eslint-disable-next-line no-use-before-define
|
|
867
672
|
collect(slot, priorRejected, priorRes);
|
|
868
673
|
}
|
|
869
674
|
}
|
|
@@ -983,12 +788,21 @@ function build(
|
|
|
983
788
|
return null;
|
|
984
789
|
}
|
|
985
790
|
syscall.resolve(resolutions);
|
|
986
|
-
|
|
987
|
-
resolutionCD
|
|
988
|
-
|
|
989
|
-
|
|
791
|
+
for (const resolution of resolutions) {
|
|
792
|
+
const [_xvpid, _isReject, resolutionCD] = resolution;
|
|
793
|
+
for (const vref of resolutionCD.slots) {
|
|
794
|
+
maybeNewVPIDs.add(vref);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
for (const resolution of resolutions) {
|
|
798
|
+
const [xvpid] = resolution;
|
|
799
|
+
maybeNewVPIDs.delete(xvpid);
|
|
800
|
+
unregisterUnreferencedVPID(xvpid);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
for (const newVPID of Array.from(maybeNewVPIDs).sort()) {
|
|
804
|
+
maybeExportPromise(newVPID);
|
|
990
805
|
}
|
|
991
|
-
Array.from(maybeNewVPIDs).sort().forEach(maybeExportPromise);
|
|
992
806
|
|
|
993
807
|
// ideally we'd wait until .then is called on p before subscribing, but
|
|
994
808
|
// the current Promise API doesn't give us a way to discover this, so we
|
|
@@ -1141,7 +955,6 @@ function build(
|
|
|
1141
955
|
}
|
|
1142
956
|
// in both cases, we are now the decider, so treat it like an
|
|
1143
957
|
// exported promise
|
|
1144
|
-
// eslint-disable-next-line no-use-before-define
|
|
1145
958
|
followForKernel(resultVPID, p);
|
|
1146
959
|
}
|
|
1147
960
|
}
|
|
@@ -1190,16 +1003,23 @@ function build(
|
|
|
1190
1003
|
|
|
1191
1004
|
const maybeNewVPIDs = new Set();
|
|
1192
1005
|
// if we mention a vpid, we might need to track it
|
|
1193
|
-
|
|
1194
|
-
resolutionCD
|
|
1195
|
-
|
|
1006
|
+
for (const resolution of resolutions) {
|
|
1007
|
+
const [_xvpid, _isReject, resolutionCD] = resolution;
|
|
1008
|
+
for (const vref of resolutionCD.slots) {
|
|
1009
|
+
maybeNewVPIDs.add(vref);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1196
1012
|
// but not if we just resolved it (including the primary)
|
|
1197
|
-
|
|
1013
|
+
for (const resolution of resolutions) {
|
|
1014
|
+
const [xvpid] = resolution;
|
|
1015
|
+
maybeNewVPIDs.delete(xvpid);
|
|
1016
|
+
unregisterUnreferencedVPID(xvpid);
|
|
1017
|
+
}
|
|
1198
1018
|
// track everything that's left
|
|
1199
|
-
Array.from(maybeNewVPIDs).sort()
|
|
1019
|
+
for (const newVPID of Array.from(maybeNewVPIDs).sort()) {
|
|
1020
|
+
maybeExportPromise(newVPID);
|
|
1021
|
+
}
|
|
1200
1022
|
|
|
1201
|
-
// only the primary can possibly be newly resolved
|
|
1202
|
-
unregisterUnreferencedVPID(vpid);
|
|
1203
1023
|
exportedVPIDs.delete(vpid);
|
|
1204
1024
|
}
|
|
1205
1025
|
|
|
@@ -1254,11 +1074,11 @@ function build(
|
|
|
1254
1074
|
// 'imports' is an exclusively-owned Set that holds all new
|
|
1255
1075
|
// promise vpids, both resolved and unresolved
|
|
1256
1076
|
const imports = finishCollectingPromiseImports();
|
|
1257
|
-
|
|
1077
|
+
for (const vpid of retiredVPIDs) {
|
|
1258
1078
|
unregisterUnreferencedVPID(vpid); // unregisters if not in vdata
|
|
1259
1079
|
importedVPIDs.delete(vpid);
|
|
1260
1080
|
imports.delete(vpid); // resolved, so don't subscribe()
|
|
1261
|
-
}
|
|
1081
|
+
}
|
|
1262
1082
|
for (const vpid of Array.from(imports).sort()) {
|
|
1263
1083
|
syscall.subscribe(vpid);
|
|
1264
1084
|
}
|
|
@@ -1298,14 +1118,18 @@ function build(
|
|
|
1298
1118
|
|
|
1299
1119
|
function retireExports(vrefs) {
|
|
1300
1120
|
assert(Array.isArray(vrefs));
|
|
1301
|
-
vrefs
|
|
1121
|
+
for (const vref of vrefs) {
|
|
1122
|
+
retireOneExport(vref);
|
|
1123
|
+
}
|
|
1302
1124
|
}
|
|
1303
1125
|
|
|
1304
1126
|
function retireImports(vrefs) {
|
|
1305
1127
|
assert(Array.isArray(vrefs));
|
|
1306
1128
|
vrefs.map(vref => insistVatType('object', vref));
|
|
1307
1129
|
vrefs.map(vref => assert(!parseVatSlot(vref).allocatedByVat));
|
|
1308
|
-
vrefs
|
|
1130
|
+
for (const vref of vrefs) {
|
|
1131
|
+
vrm.ceaseRecognition(vref);
|
|
1132
|
+
}
|
|
1309
1133
|
}
|
|
1310
1134
|
|
|
1311
1135
|
// TODO: when we add notifyForward, guard against cycles
|
|
@@ -1370,6 +1194,7 @@ function build(
|
|
|
1370
1194
|
const inescapableGlobalProperties = harden({
|
|
1371
1195
|
WeakMap: vom.VirtualObjectAwareWeakMap,
|
|
1372
1196
|
WeakSet: vom.VirtualObjectAwareWeakSet,
|
|
1197
|
+
[PassStyleOfEndowmentSymbol]: passStyleOf,
|
|
1373
1198
|
});
|
|
1374
1199
|
|
|
1375
1200
|
function getRetentionStats() {
|
|
@@ -1405,7 +1230,6 @@ function build(
|
|
|
1405
1230
|
possiblyRetiredSet,
|
|
1406
1231
|
slotToVal,
|
|
1407
1232
|
valToSlot,
|
|
1408
|
-
// eslint-disable-next-line no-use-before-define
|
|
1409
1233
|
afterDispatchActions,
|
|
1410
1234
|
});
|
|
1411
1235
|
|
|
@@ -1450,7 +1274,7 @@ function build(
|
|
|
1450
1274
|
}
|
|
1451
1275
|
harden(vpow);
|
|
1452
1276
|
|
|
1453
|
-
initializeIDCounters();
|
|
1277
|
+
vrm.initializeIDCounters();
|
|
1454
1278
|
vom.initializeKindHandleKind();
|
|
1455
1279
|
collectionManager.initializeStoreKindInfo();
|
|
1456
1280
|
|
|
@@ -1496,8 +1320,8 @@ function build(
|
|
|
1496
1320
|
}
|
|
1497
1321
|
|
|
1498
1322
|
/**
|
|
1499
|
-
* @param {import('./types').VatDeliveryObject} delivery
|
|
1500
|
-
* @returns {
|
|
1323
|
+
* @param {import('./types.js').VatDeliveryObject} delivery
|
|
1324
|
+
* @returns {undefined | ReturnType<startVat>}
|
|
1501
1325
|
*/
|
|
1502
1326
|
function dispatchToUserspace(delivery) {
|
|
1503
1327
|
let result;
|
|
@@ -1549,19 +1373,18 @@ function build(
|
|
|
1549
1373
|
// metered
|
|
1550
1374
|
const unmeteredDispatch = meterControl.unmetered(dispatchToUserspace);
|
|
1551
1375
|
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
}
|
|
1376
|
+
const { scanForDeadObjects } = makeBOYDKit({
|
|
1377
|
+
gcTools,
|
|
1378
|
+
slotToVal,
|
|
1379
|
+
vrm,
|
|
1380
|
+
kernelRecognizableRemotables,
|
|
1381
|
+
syscall,
|
|
1382
|
+
possiblyDeadSet,
|
|
1383
|
+
possiblyRetiredSet,
|
|
1384
|
+
});
|
|
1562
1385
|
|
|
1563
1386
|
/**
|
|
1564
|
-
* @param { import('./types').SwingSetCapData } _disconnectObjectCapData
|
|
1387
|
+
* @param { import('./types.js').SwingSetCapData } _disconnectObjectCapData
|
|
1565
1388
|
* @returns {Promise<void>}
|
|
1566
1389
|
*/
|
|
1567
1390
|
async function stopVat(_disconnectObjectCapData) {
|
|
@@ -1573,11 +1396,21 @@ function build(
|
|
|
1573
1396
|
* dispatch has completed and user code has relinquished agency.
|
|
1574
1397
|
*/
|
|
1575
1398
|
function afterDispatchActions() {
|
|
1576
|
-
flushIDCounters();
|
|
1399
|
+
vrm.flushIDCounters();
|
|
1577
1400
|
collectionManager.flushSchemaCache();
|
|
1578
1401
|
vom.flushStateCache();
|
|
1579
1402
|
}
|
|
1580
1403
|
|
|
1404
|
+
const bringOutYourDead = async () => {
|
|
1405
|
+
await scanForDeadObjects();
|
|
1406
|
+
// Now flush all the vatstore changes (deletions and refcounts) we
|
|
1407
|
+
// made. dispatch() calls afterDispatchActions() automatically for
|
|
1408
|
+
// most methods, but not bringOutYourDead().
|
|
1409
|
+
afterDispatchActions();
|
|
1410
|
+
// XXX TODO: make this conditional on a config setting
|
|
1411
|
+
return getRetentionStats();
|
|
1412
|
+
};
|
|
1413
|
+
|
|
1581
1414
|
/**
|
|
1582
1415
|
* This 'dispatch' function is the entry point for the vat as a whole: the
|
|
1583
1416
|
* vat-worker supervisor gives us VatDeliveryObjects (like
|
|
@@ -1613,7 +1446,7 @@ function build(
|
|
|
1613
1446
|
* terminate the vat). Userspace should not be able to cause the delivery
|
|
1614
1447
|
* to fail: only a bug in liveslots should trigger a failure.
|
|
1615
1448
|
*
|
|
1616
|
-
* @param {import('./types').VatDeliveryObject} delivery
|
|
1449
|
+
* @param {import('./types.js').VatDeliveryObject} delivery
|
|
1617
1450
|
* @returns {Promise<void>}
|
|
1618
1451
|
*/
|
|
1619
1452
|
async function dispatch(delivery) {
|
|
@@ -1624,12 +1457,10 @@ function build(
|
|
|
1624
1457
|
} else if (delivery[0] === 'stopVat') {
|
|
1625
1458
|
return meterControl.runWithoutMeteringAsync(() => stopVat(delivery[1]));
|
|
1626
1459
|
} else {
|
|
1627
|
-
let complete = false;
|
|
1628
1460
|
// Start user code running, record any internal liveslots errors. We do
|
|
1629
1461
|
// *not* directly wait for the userspace function to complete, nor for
|
|
1630
1462
|
// any promise it returns to fire.
|
|
1631
1463
|
const p = Promise.resolve(delivery).then(unmeteredDispatch);
|
|
1632
|
-
p.finally(() => (complete = true));
|
|
1633
1464
|
|
|
1634
1465
|
// Instead, we wait for userspace to become idle by draining the
|
|
1635
1466
|
// promise queue. We clean up and then examine/return 'p' so any
|
|
@@ -1640,10 +1471,11 @@ function build(
|
|
|
1640
1471
|
return gcTools.waitUntilQuiescent().then(() => {
|
|
1641
1472
|
afterDispatchActions();
|
|
1642
1473
|
// eslint-disable-next-line prefer-promise-reject-errors
|
|
1643
|
-
return
|
|
1474
|
+
return Promise.race([p, Promise.reject('buildRootObject unresolved')]);
|
|
1644
1475
|
// the only delivery that pays attention to a user-provided
|
|
1645
1476
|
// Promise is startVat, so the error message is specialized to
|
|
1646
|
-
// the only user problem that could cause
|
|
1477
|
+
// the only user problem that could cause the promise to not be
|
|
1478
|
+
// settled.
|
|
1647
1479
|
});
|
|
1648
1480
|
}
|
|
1649
1481
|
}
|
|
@@ -1664,9 +1496,9 @@ function build(
|
|
|
1664
1496
|
* @param {*} syscall Kernel syscall interface that the vat will have access to
|
|
1665
1497
|
* @param {*} forVatID Vat ID label, for use in debug diagostics
|
|
1666
1498
|
* @param {*} vatPowers
|
|
1667
|
-
* @param {import('./types').LiveSlotsOptions} liveSlotsOptions
|
|
1499
|
+
* @param {import('./types.js').LiveSlotsOptions} liveSlotsOptions
|
|
1668
1500
|
* @param {*} gcTools { WeakRef, FinalizationRegistry, waitUntilQuiescent }
|
|
1669
|
-
* @param {
|
|
1501
|
+
* @param {LimitedConsole} [liveSlotsConsole]
|
|
1670
1502
|
* @param {*} [buildVatNamespace]
|
|
1671
1503
|
*
|
|
1672
1504
|
* @returns {*} { dispatch }
|