@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
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
-
import '@endo/init/debug.js';
|
|
3
2
|
|
|
4
3
|
import { Far } from '@endo/far';
|
|
4
|
+
import { kunser } from '@agoric/kmarshal';
|
|
5
5
|
import { M } from '@agoric/store';
|
|
6
6
|
import { setupTestLiveslots } from './liveslots-helpers.js';
|
|
7
|
-
import { kunser } from './kmarshal.js';
|
|
8
7
|
|
|
9
8
|
function buildRootObject(vatPowers, vatParameters, baggage) {
|
|
10
9
|
const vd = vatPowers.VatData;
|
|
@@ -71,34 +70,28 @@ test('initial vatstore contents', async t => {
|
|
|
71
70
|
t.deepEqual(kunser(JSON.parse(get(`vc.1.|schemata`))), stringSchema);
|
|
72
71
|
|
|
73
72
|
// then three tables for the promise watcher (one virtual, two durable)
|
|
74
|
-
t.is(getLabel(`vc.
|
|
75
|
-
t.is(getLabel(`vc.
|
|
76
|
-
// the promiseRegistrations table is not durable, and only gets vc.2
|
|
77
|
-
// on the first incarnation: it will get a new ID on subsequent
|
|
78
|
-
// incarnations
|
|
79
|
-
t.is(getLabel(`vc.2.|schemata`), `promiseRegistrations`); // virtual
|
|
73
|
+
t.is(getLabel(`vc.2.|schemata`), 'promiseWatcherByKind'); // durable
|
|
74
|
+
t.is(getLabel(`vc.3.|schemata`), 'watchedPromises'); // durable
|
|
80
75
|
|
|
81
76
|
const watcherTableVref = get('watcherTableID');
|
|
82
77
|
const watchedPromiseTableVref = get('watchedPromiseTableID');
|
|
83
|
-
t.is(watcherTableVref, `${dmsBase}/
|
|
84
|
-
t.is(watchedPromiseTableVref, `${dmsBase}/
|
|
78
|
+
t.is(watcherTableVref, `${dmsBase}/2`);
|
|
79
|
+
t.is(watchedPromiseTableVref, `${dmsBase}/3`);
|
|
85
80
|
|
|
86
81
|
// baggage and the two durable promise-watcher tables are pinned
|
|
87
82
|
t.is(get(`vom.rc.${baggageVref}`), '1');
|
|
88
83
|
t.is(get(`vom.rc.${watcherTableVref}`), '1');
|
|
89
84
|
t.is(get(`vom.rc.${watchedPromiseTableVref}`), '1');
|
|
90
85
|
|
|
91
|
-
//
|
|
92
|
-
const scalarSchema2 = { label: 'promiseRegistrations', keyShape: M.scalar() };
|
|
86
|
+
// promiseWatcherByKind arbitrary scalars as keys
|
|
93
87
|
const scalarSchema3 = { label: 'promiseWatcherByKind', keyShape: M.scalar() };
|
|
94
|
-
t.deepEqual(kunser(JSON.parse(get(`vc.2.|schemata`))),
|
|
95
|
-
t.deepEqual(kunser(JSON.parse(get(`vc.3.|schemata`))), scalarSchema3);
|
|
88
|
+
t.deepEqual(kunser(JSON.parse(get(`vc.2.|schemata`))), scalarSchema3);
|
|
96
89
|
// watchedPromises uses vref (string) keys
|
|
97
90
|
const scalarStringSchema = {
|
|
98
91
|
label: 'watchedPromises',
|
|
99
92
|
keyShape: M.and(M.scalar(), M.string()),
|
|
100
93
|
};
|
|
101
|
-
t.deepEqual(kunser(JSON.parse(get(`vc.
|
|
94
|
+
t.deepEqual(kunser(JSON.parse(get(`vc.3.|schemata`))), scalarStringSchema);
|
|
102
95
|
});
|
|
103
96
|
|
|
104
97
|
test('vrefs', async t => {
|
|
@@ -142,11 +135,11 @@ test('vrefs', async t => {
|
|
|
142
135
|
const dh2Vref = (await run('getDinstance2')).slots[0];
|
|
143
136
|
t.is(dh2Vref, expectedDH2Vref);
|
|
144
137
|
|
|
145
|
-
// the liveslots-created collections consume vc.1 through vc.
|
|
146
|
-
// leaving vc.
|
|
147
|
-
t.is(getLabel('vc.
|
|
148
|
-
const expectedStore1Vref = `o+v${initialKindIDs.scalarMapStore}/
|
|
138
|
+
// the liveslots-created collections consume vc.1 through vc.3,
|
|
139
|
+
// leaving vc.4 for the first user-created collection
|
|
140
|
+
t.is(getLabel('vc.4.|schemata'), 'store1');
|
|
141
|
+
const expectedStore1Vref = `o+v${initialKindIDs.scalarMapStore}/4`;
|
|
149
142
|
const store1Vref = (await run('getStore1')).slots[0];
|
|
150
143
|
t.is(store1Vref, expectedStore1Vref);
|
|
151
|
-
t.
|
|
144
|
+
t.is(kunser(JSON.parse(fakestore.get(`vc.4.s${'key'}`))), 'value');
|
|
152
145
|
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {object} [options]
|
|
3
|
+
* @param {boolean} [options.skipLogging]
|
|
4
|
+
* @param {Map<string, string>} [options.kvStore]
|
|
5
|
+
*/
|
|
6
|
+
export function buildSyscall(options?: {
|
|
7
|
+
skipLogging?: boolean | undefined;
|
|
8
|
+
kvStore?: Map<string, string> | undefined;
|
|
9
|
+
}): {
|
|
10
|
+
syscall: {
|
|
11
|
+
send(targetSlot: any, methargs: any, resultSlot: any): void;
|
|
12
|
+
subscribe(target: any): void;
|
|
13
|
+
resolve(resolutions: any): void;
|
|
14
|
+
dropImports(slots: any): void;
|
|
15
|
+
retireImports(slots: any): void;
|
|
16
|
+
retireExports(slots: any): void;
|
|
17
|
+
exit(isFailure: any, info: any): void;
|
|
18
|
+
vatstoreGet(key: any): any;
|
|
19
|
+
vatstoreGetNextKey(priorKey: any): any;
|
|
20
|
+
vatstoreSet(key: any, value: any): void;
|
|
21
|
+
vatstoreDelete(key: any): void;
|
|
22
|
+
};
|
|
23
|
+
fakestore: Map<any, any>;
|
|
24
|
+
log: any[];
|
|
25
|
+
};
|
|
26
|
+
export function makeDispatch(syscall: any, build: any, vatID?: string, liveSlotsOptions?: {}, vatParameters?: undefined): Promise<{
|
|
27
|
+
dispatch: any;
|
|
28
|
+
testHooks: any;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* @param {import('ava').ExecutionContext} t
|
|
32
|
+
* @param {Function} buildRootObject
|
|
33
|
+
* @param {string} vatName
|
|
34
|
+
* @param {object} [options]
|
|
35
|
+
* @param {boolean} [options.forceGC]
|
|
36
|
+
* @param {Map<string, string>} [options.kvStore]
|
|
37
|
+
* @param {number} [options.nextPromiseImportNumber]
|
|
38
|
+
* @param {boolean} [options.skipLogging]
|
|
39
|
+
* @param {any} [options.vatParameters]
|
|
40
|
+
*/
|
|
41
|
+
export function setupTestLiveslots(t: import("ava").ExecutionContext, buildRootObject: Function, vatName: string, options?: {
|
|
42
|
+
forceGC?: boolean | undefined;
|
|
43
|
+
kvStore?: Map<string, string> | undefined;
|
|
44
|
+
nextPromiseImportNumber?: number | undefined;
|
|
45
|
+
skipLogging?: boolean | undefined;
|
|
46
|
+
vatParameters?: any;
|
|
47
|
+
}): Promise<{
|
|
48
|
+
v: {
|
|
49
|
+
t: import("ava").ExecutionContext<unknown>;
|
|
50
|
+
log: any[];
|
|
51
|
+
fakestore: Map<any, any>;
|
|
52
|
+
dumpFakestore: () => void;
|
|
53
|
+
};
|
|
54
|
+
dispatch: any;
|
|
55
|
+
dispatchMessage: (message: any, ...args: any[]) => Promise<string>;
|
|
56
|
+
dispatchMessageSuccessfully: (message: any, ...args: any[]) => Promise<any>;
|
|
57
|
+
dispatchDropExports: (...vrefs: any[]) => Promise<void>;
|
|
58
|
+
dispatchRetireExports: (...vrefs: any[]) => Promise<void>;
|
|
59
|
+
dispatchRetireImports: (...vrefs: any[]) => Promise<void>;
|
|
60
|
+
nextPImport: () => string;
|
|
61
|
+
testHooks: any;
|
|
62
|
+
}>;
|
|
63
|
+
export function findSyscallsByType(log: any, type: any): any;
|
|
64
|
+
//# sourceMappingURL=liveslots-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liveslots-helpers.d.ts","sourceRoot":"","sources":["liveslots-helpers.js"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,uCAHG;IAA0B,WAAW;IACC,OAAO;CAAC;;;;;;;;;;;;;;;;EA2GhD;AAED;;;GA2BC;AAUD;;;;;;;;;;GAUG;AACH,sCAVW,OAAO,KAAK,EAAE,gBAAgB,sCAE9B,MAAM,YAEd;IAA0B,OAAO;IACK,OAAO;IACpB,uBAAuB;IACtB,WAAW;IACf,aAAa,GAA3B,GAAG;CAAyB;;;;;;;;;;;;;;;GA6GtC;AAED,6DAEC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* global WeakRef, FinalizationRegistry */
|
|
2
|
-
import
|
|
2
|
+
import { kser } from '@agoric/kmarshal';
|
|
3
3
|
|
|
4
|
+
import engineGC from './engine-gc.js';
|
|
4
5
|
import { waitUntilQuiescent } from './waitUntilQuiescent.js';
|
|
5
6
|
import { makeGcAndFinalize } from './gc-and-finalize.js';
|
|
6
7
|
import { makeDummyMeterControl } from './dummyMeterControl.js';
|
|
@@ -12,12 +13,11 @@ import {
|
|
|
12
13
|
makeRetireExports,
|
|
13
14
|
makeBringOutYourDead,
|
|
14
15
|
} from './util.js';
|
|
15
|
-
import { kser } from './kmarshal.js';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* @param {object} [options]
|
|
19
|
-
* @param {boolean} [options.skipLogging
|
|
20
|
-
* @param {Map<string, string>} [options.kvStore
|
|
19
|
+
* @param {boolean} [options.skipLogging]
|
|
20
|
+
* @param {Map<string, string>} [options.kvStore]
|
|
21
21
|
*/
|
|
22
22
|
export function buildSyscall(options = {}) {
|
|
23
23
|
const { skipLogging = false, kvStore: fakestore = new Map() } = options;
|
|
@@ -131,6 +131,7 @@ export async function makeDispatch(
|
|
|
131
131
|
build,
|
|
132
132
|
vatID = 'vatA',
|
|
133
133
|
liveSlotsOptions = {},
|
|
134
|
+
vatParameters = undefined,
|
|
134
135
|
) {
|
|
135
136
|
const gcTools = harden({
|
|
136
137
|
WeakRef,
|
|
@@ -150,7 +151,7 @@ export async function makeDispatch(
|
|
|
150
151
|
return { buildRootObject: build };
|
|
151
152
|
},
|
|
152
153
|
);
|
|
153
|
-
await dispatch(['startVat', kser()]);
|
|
154
|
+
await dispatch(['startVat', kser(vatParameters)]);
|
|
154
155
|
return { dispatch, testHooks };
|
|
155
156
|
}
|
|
156
157
|
|
|
@@ -168,9 +169,10 @@ function makeRPMaker(nextNumber = 1) {
|
|
|
168
169
|
* @param {string} vatName
|
|
169
170
|
* @param {object} [options]
|
|
170
171
|
* @param {boolean} [options.forceGC]
|
|
171
|
-
* @param {Map<string, string>} [options.kvStore
|
|
172
|
+
* @param {Map<string, string>} [options.kvStore]
|
|
172
173
|
* @param {number} [options.nextPromiseImportNumber]
|
|
173
|
-
* @param {boolean} [options.skipLogging
|
|
174
|
+
* @param {boolean} [options.skipLogging]
|
|
175
|
+
* @param {any} [options.vatParameters]
|
|
174
176
|
*/
|
|
175
177
|
export async function setupTestLiveslots(
|
|
176
178
|
t,
|
|
@@ -183,6 +185,7 @@ export async function setupTestLiveslots(
|
|
|
183
185
|
kvStore = new Map(),
|
|
184
186
|
nextPromiseImportNumber,
|
|
185
187
|
skipLogging = false,
|
|
188
|
+
vatParameters,
|
|
186
189
|
} = options;
|
|
187
190
|
const { log, syscall, fakestore } = buildSyscall({ skipLogging, kvStore });
|
|
188
191
|
const nextRP = makeRPMaker(nextPromiseImportNumber);
|
|
@@ -190,6 +193,8 @@ export async function setupTestLiveslots(
|
|
|
190
193
|
syscall,
|
|
191
194
|
buildRootObject,
|
|
192
195
|
vatName,
|
|
196
|
+
{},
|
|
197
|
+
vatParameters,
|
|
193
198
|
);
|
|
194
199
|
|
|
195
200
|
async function dispatchMessage(message, ...args) {
|
|
@@ -273,6 +278,7 @@ export async function setupTestLiveslots(
|
|
|
273
278
|
dispatchDropExports,
|
|
274
279
|
dispatchRetireExports,
|
|
275
280
|
dispatchRetireImports,
|
|
281
|
+
nextPImport: nextRP,
|
|
276
282
|
testHooks,
|
|
277
283
|
};
|
|
278
284
|
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
import test from 'ava';
|
|
2
|
-
import '@endo/init/debug.js';
|
|
3
3
|
|
|
4
4
|
import { Far } from '@endo/marshal';
|
|
5
|
+
import { kslot, kser } from '@agoric/kmarshal';
|
|
5
6
|
import { makeLiveSlots } from '../src/liveslots.js';
|
|
6
7
|
import { parseVatSlot } from '../src/parseVatSlots.js';
|
|
7
|
-
import { kslot, kser } from './kmarshal.js';
|
|
8
8
|
import { buildSyscall } from './liveslots-helpers.js';
|
|
9
9
|
import {
|
|
10
10
|
makeMessage,
|
|
11
11
|
makeStartVat,
|
|
12
12
|
makeBringOutYourDead,
|
|
13
13
|
makeResolve,
|
|
14
|
+
makeRetireImports,
|
|
14
15
|
} from './util.js';
|
|
15
16
|
import { makeMockGC } from './mock-gc.js';
|
|
16
17
|
|
|
@@ -465,3 +466,101 @@ for (const firstType of ['object', 'collection']) {
|
|
|
465
466
|
}
|
|
466
467
|
|
|
467
468
|
// test('double-free', doublefreetest, { firstType: 'object', lastType: 'collection', order: 'first->last' });
|
|
469
|
+
|
|
470
|
+
test('retirement', async t => {
|
|
471
|
+
const { syscall, fakestore, log } = buildSyscall();
|
|
472
|
+
const gcTools = makeMockGC();
|
|
473
|
+
|
|
474
|
+
// A is a weak collection, with one entry, whose key is B (a
|
|
475
|
+
// Presence). We drop the RAM pillar for B and do a BOYD, which
|
|
476
|
+
// should provoke a syscall.dropImports. Then, when we delete A (by
|
|
477
|
+
// dropping the RAM pillar), the next BOYD should see a
|
|
478
|
+
// `syscall.retireImports`.
|
|
479
|
+
|
|
480
|
+
let weakmapA;
|
|
481
|
+
let presenceB;
|
|
482
|
+
|
|
483
|
+
function buildRootObject(vatPowers) {
|
|
484
|
+
const { VatData } = vatPowers;
|
|
485
|
+
const { makeScalarBigWeakMapStore } = VatData;
|
|
486
|
+
|
|
487
|
+
weakmapA = makeScalarBigWeakMapStore();
|
|
488
|
+
|
|
489
|
+
return Far('root', {
|
|
490
|
+
add: p => {
|
|
491
|
+
presenceB = p;
|
|
492
|
+
weakmapA.init(presenceB, 'value');
|
|
493
|
+
},
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const makeNS = () => ({ buildRootObject });
|
|
498
|
+
const ls = makeLiveSlots(syscall, 'vatA', {}, {}, gcTools, undefined, makeNS);
|
|
499
|
+
const { dispatch, testHooks } = ls;
|
|
500
|
+
const { valToSlot } = testHooks;
|
|
501
|
+
|
|
502
|
+
await dispatch(makeStartVat(kser()));
|
|
503
|
+
log.length = 0;
|
|
504
|
+
const weakmapAvref = valToSlot.get(weakmapA);
|
|
505
|
+
const { subid } = parseVatSlot(weakmapAvref);
|
|
506
|
+
const collectionID = String(subid);
|
|
507
|
+
|
|
508
|
+
const rootA = 'o+0';
|
|
509
|
+
const presenceBvref = 'o-1';
|
|
510
|
+
await dispatch(makeMessage(rootA, 'add', [kslot(presenceBvref)]));
|
|
511
|
+
log.length = 0;
|
|
512
|
+
|
|
513
|
+
// the fact that weakmapA can recognize presenceA is recorded in a
|
|
514
|
+
// vatstore key
|
|
515
|
+
const recognizerKey = `vom.ir.${presenceBvref}|${collectionID}`;
|
|
516
|
+
t.is(fakestore.get(recognizerKey), '1');
|
|
517
|
+
|
|
518
|
+
// tell mockGC that userspace has dropped presenceB
|
|
519
|
+
gcTools.kill(presenceB);
|
|
520
|
+
gcTools.flushAllFRs();
|
|
521
|
+
|
|
522
|
+
await dispatch(makeBringOutYourDead());
|
|
523
|
+
const priorKey = `vom.ir.${presenceBvref}|`;
|
|
524
|
+
|
|
525
|
+
t.deepEqual(log.splice(0), [
|
|
526
|
+
// when a Presence is dropped, scanForDeadObjects can't drop the
|
|
527
|
+
// underlying vref import until it knows that virtual data isn't
|
|
528
|
+
// holding a reference, so we expect a refcount check
|
|
529
|
+
{ type: 'vatstoreGet', key: `vom.rc.${presenceBvref}`, result: undefined },
|
|
530
|
+
|
|
531
|
+
// the vref is now in importsToDrop, but since this commonly means
|
|
532
|
+
// it can be retired too, scanForDeadObjects goes ahead and checks
|
|
533
|
+
// for recognizers
|
|
534
|
+
{ type: 'vatstoreGetNextKey', priorKey, result: recognizerKey },
|
|
535
|
+
|
|
536
|
+
// it found a recognizer, so the vref cannot be retired
|
|
537
|
+
// yet. scanForDeadObjects finishes the BOYD by emitting the
|
|
538
|
+
// dropImports, but should keep watching for an opportunity to
|
|
539
|
+
// retire it too
|
|
540
|
+
{ type: 'dropImports', slots: [presenceBvref] },
|
|
541
|
+
]);
|
|
542
|
+
|
|
543
|
+
// now tell mockGC that we're dropping the weakmap too
|
|
544
|
+
gcTools.kill(weakmapA);
|
|
545
|
+
gcTools.flushAllFRs();
|
|
546
|
+
|
|
547
|
+
// this will provoke the deletion of the collection and all its
|
|
548
|
+
// data. It should *also* trigger a syscall.retireImports of the
|
|
549
|
+
// no-longer-recognizable key
|
|
550
|
+
await dispatch(makeBringOutYourDead());
|
|
551
|
+
const retires = log.filter(e => e.type === 'retireImports');
|
|
552
|
+
|
|
553
|
+
t.deepEqual(retires, [{ type: 'retireImports', slots: [presenceBvref] }]);
|
|
554
|
+
|
|
555
|
+
// If the bug is present, the vat won't send `syscall.retireImports`
|
|
556
|
+
// to the kernel. In a full system, that means the kernel can
|
|
557
|
+
// eventually send a `dispatch.retireImports` into the vat, if/when
|
|
558
|
+
// the object's hosting vat decides to drop it. Make sure that won't
|
|
559
|
+
// cause a crash.
|
|
560
|
+
|
|
561
|
+
if (!retires.length) {
|
|
562
|
+
console.log(`testing kernel's dispatch.retireImports`);
|
|
563
|
+
await dispatch(makeRetireImports(presenceBvref));
|
|
564
|
+
console.log(`dispatch.retireImports did not crash`);
|
|
565
|
+
}
|
|
566
|
+
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/* global process */
|
|
2
3
|
import test from 'ava';
|
|
3
|
-
import '@endo/init/debug.js';
|
|
4
4
|
|
|
5
5
|
import { Far } from '@endo/marshal';
|
|
6
6
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
7
|
+
import { kslot, kser } from '@agoric/kmarshal';
|
|
8
|
+
import { avaRetry } from '@agoric/internal/tools/avaRetry.js';
|
|
7
9
|
import engineGC from './engine-gc.js';
|
|
8
|
-
import { makeGcAndFinalize } from './gc-and-finalize.js';
|
|
9
|
-
import { kslot, kser } from './kmarshal.js';
|
|
10
|
+
import { watchCollected, makeGcAndFinalize } from './gc-and-finalize.js';
|
|
10
11
|
import { buildSyscall, makeDispatch } from './liveslots-helpers.js';
|
|
11
12
|
import {
|
|
12
13
|
makeMessage,
|
|
@@ -26,15 +27,15 @@ const gcAndFinalize = makeGcAndFinalize(engineGC);
|
|
|
26
27
|
// inconsistent GC behavior under Node.js and AVA with tests running
|
|
27
28
|
// in parallel, so we mark them all with test.serial()
|
|
28
29
|
|
|
29
|
-
test.serial
|
|
30
|
+
avaRetry(test.serial, 'liveslots retains pending exported promise', async t => {
|
|
30
31
|
const { log, syscall } = buildSyscall();
|
|
31
|
-
let
|
|
32
|
+
let collected;
|
|
32
33
|
const success = [];
|
|
33
34
|
function build(_vatPowers) {
|
|
34
35
|
const root = Far('root', {
|
|
35
36
|
make() {
|
|
36
37
|
const pk = makePromiseKit();
|
|
37
|
-
|
|
38
|
+
collected = watchCollected(pk.promise);
|
|
38
39
|
// we export the Promise, but do not retain resolve/reject
|
|
39
40
|
return [pk.promise];
|
|
40
41
|
},
|
|
@@ -55,7 +56,7 @@ test.serial('liveslots retains pending exported promise', async t => {
|
|
|
55
56
|
const resultP = 'p-1';
|
|
56
57
|
await dispatch(makeMessage(rootA, 'make', [], resultP));
|
|
57
58
|
await gcAndFinalize();
|
|
58
|
-
t.
|
|
59
|
+
t.false(collected.result, 'Promise retained');
|
|
59
60
|
t.is(log[0].type, 'resolve');
|
|
60
61
|
const res0 = log[0].resolutions[0];
|
|
61
62
|
t.is(res0[0], resultP);
|
|
@@ -64,15 +65,15 @@ test.serial('liveslots retains pending exported promise', async t => {
|
|
|
64
65
|
t.deepEqual(success, ['yes']);
|
|
65
66
|
});
|
|
66
67
|
|
|
67
|
-
test.serial
|
|
68
|
+
avaRetry(test.serial, 'liveslots retains device nodes', async t => {
|
|
68
69
|
const { syscall } = buildSyscall();
|
|
69
|
-
let
|
|
70
|
+
let collected;
|
|
70
71
|
const recognize = new WeakSet(); // real WeakSet
|
|
71
72
|
const success = [];
|
|
72
73
|
function build(_vatPowers) {
|
|
73
74
|
const root = Far('root', {
|
|
74
75
|
first(dn) {
|
|
75
|
-
|
|
76
|
+
collected = watchCollected(dn);
|
|
76
77
|
recognize.add(dn);
|
|
77
78
|
},
|
|
78
79
|
second(dn) {
|
|
@@ -87,25 +88,24 @@ test.serial('liveslots retains device nodes', async t => {
|
|
|
87
88
|
const device = 'd-1';
|
|
88
89
|
await dispatch(makeMessage(rootA, 'first', [kslot(device)]));
|
|
89
90
|
await gcAndFinalize();
|
|
90
|
-
t.
|
|
91
|
+
t.false(collected.result, 'Device node retained');
|
|
91
92
|
await dispatch(makeMessage(rootA, 'second', [kslot(device)]));
|
|
92
93
|
t.deepEqual(success, [true]);
|
|
93
94
|
});
|
|
94
95
|
|
|
95
|
-
test.serial
|
|
96
|
+
avaRetry(test.serial, 'GC syscall.dropImports', async t => {
|
|
96
97
|
const { log, syscall } = buildSyscall();
|
|
97
|
-
let
|
|
98
|
+
let collected;
|
|
98
99
|
function build(_vatPowers) {
|
|
99
|
-
|
|
100
|
-
let presence1;
|
|
100
|
+
const holder = new Set();
|
|
101
101
|
const root = Far('root', {
|
|
102
102
|
one(arg) {
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
holder.add(arg);
|
|
104
|
+
collected = watchCollected(arg);
|
|
105
105
|
},
|
|
106
106
|
two() {},
|
|
107
107
|
three() {
|
|
108
|
-
|
|
108
|
+
holder.clear(); // drops the import
|
|
109
109
|
},
|
|
110
110
|
});
|
|
111
111
|
return root;
|
|
@@ -121,19 +121,29 @@ test.serial('GC syscall.dropImports', async t => {
|
|
|
121
121
|
// rp1 = root~.one(arg)
|
|
122
122
|
await dispatch(makeMessage(rootA, 'one', [kslot(arg)]));
|
|
123
123
|
await dispatch(makeBringOutYourDead());
|
|
124
|
-
t.
|
|
124
|
+
t.false(collected.result);
|
|
125
125
|
|
|
126
126
|
// an intermediate message will trigger GC, but the presence is still held
|
|
127
127
|
await dispatch(makeMessage(rootA, 'two', []));
|
|
128
128
|
await dispatch(makeBringOutYourDead());
|
|
129
|
-
t.
|
|
129
|
+
t.false(collected.result);
|
|
130
130
|
|
|
131
131
|
// now tell the vat to drop the 'arg' presence we gave them earlier
|
|
132
132
|
await dispatch(makeMessage(rootA, 'three', []));
|
|
133
133
|
await dispatch(makeBringOutYourDead());
|
|
134
134
|
|
|
135
|
+
const isV8 =
|
|
136
|
+
typeof process !== 'undefined' && 'v8' in (process.versions || {});
|
|
137
|
+
|
|
135
138
|
// the presence itself should be gone
|
|
136
|
-
|
|
139
|
+
if (!collected.result) {
|
|
140
|
+
if (isV8) {
|
|
141
|
+
// Flake in v8/node: https://github.com/Agoric/agoric-sdk/issues/8883
|
|
142
|
+
t.log('skipping flake in v8');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
t.fail('import not collected');
|
|
146
|
+
}
|
|
137
147
|
|
|
138
148
|
// first it will check that there are no VO's holding onto it
|
|
139
149
|
const l2 = log.shift();
|
|
@@ -168,7 +178,7 @@ test.serial('GC syscall.dropImports', async t => {
|
|
|
168
178
|
t.deepEqual(log, []);
|
|
169
179
|
});
|
|
170
180
|
|
|
171
|
-
test.serial
|
|
181
|
+
avaRetry(test.serial, 'GC dispatch.retireImports', async t => {
|
|
172
182
|
const { log, syscall } = buildSyscall();
|
|
173
183
|
function build(_vatPowers) {
|
|
174
184
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -201,7 +211,7 @@ test.serial('GC dispatch.retireImports', async t => {
|
|
|
201
211
|
// when we implement VOM.vrefIsRecognizable, this test might do more
|
|
202
212
|
});
|
|
203
213
|
|
|
204
|
-
test.serial
|
|
214
|
+
avaRetry(test.serial, 'GC dispatch.retireExports', async t => {
|
|
205
215
|
const { log, syscall } = buildSyscall();
|
|
206
216
|
function build(_vatPowers) {
|
|
207
217
|
const ex1 = Far('export', {});
|
|
@@ -244,14 +254,14 @@ test.serial('GC dispatch.retireExports', async t => {
|
|
|
244
254
|
t.deepEqual(log, []);
|
|
245
255
|
});
|
|
246
256
|
|
|
247
|
-
test.serial
|
|
257
|
+
avaRetry(test.serial, 'GC dispatch.dropExports', async t => {
|
|
248
258
|
const { log, syscall } = buildSyscall();
|
|
249
|
-
let
|
|
259
|
+
let collected;
|
|
250
260
|
function build(_vatPowers) {
|
|
251
261
|
const root = Far('root', {
|
|
252
262
|
one() {
|
|
253
263
|
const ex1 = Far('export', {});
|
|
254
|
-
|
|
264
|
+
collected = watchCollected(ex1);
|
|
255
265
|
return ex1;
|
|
256
266
|
// ex1 goes out of scope, dropping last userspace strongref
|
|
257
267
|
},
|
|
@@ -279,25 +289,33 @@ test.serial('GC dispatch.dropExports', async t => {
|
|
|
279
289
|
t.deepEqual(log.shift(), {
|
|
280
290
|
type: 'vatstoreSet',
|
|
281
291
|
key: 'idCounters',
|
|
282
|
-
value: '{"exportID":11,"collectionID":
|
|
292
|
+
value: '{"exportID":11,"collectionID":4,"promiseID":5}',
|
|
283
293
|
});
|
|
284
294
|
t.deepEqual(log, []);
|
|
285
295
|
|
|
286
296
|
// the exported Remotable should be held in place by exportedRemotables
|
|
287
297
|
// until we tell the vat we don't need it any more
|
|
288
|
-
t.
|
|
298
|
+
t.false(collected.result);
|
|
289
299
|
|
|
290
300
|
// an intermediate message will trigger GC, but the presence is still held
|
|
291
301
|
await dispatch(makeMessage(rootA, 'two', []));
|
|
292
302
|
await dispatch(makeBringOutYourDead());
|
|
293
|
-
t.
|
|
303
|
+
t.false(collected.result);
|
|
294
304
|
|
|
295
305
|
// now tell the vat we don't need a strong reference to that export.
|
|
296
306
|
await dispatch(makeDropExports(ex1));
|
|
297
307
|
await dispatch(makeBringOutYourDead());
|
|
298
308
|
|
|
299
309
|
// that should allow ex1 to be collected
|
|
300
|
-
t.
|
|
310
|
+
t.true(collected.result);
|
|
311
|
+
|
|
312
|
+
// upon collection, the vat should scan for local recognizers (weak
|
|
313
|
+
// collection keys) in case any need to be dropped, and find none
|
|
314
|
+
t.deepEqual(log.shift(), {
|
|
315
|
+
type: 'vatstoreGetNextKey',
|
|
316
|
+
priorKey: `vom.ir.${ex1}|`,
|
|
317
|
+
result: 'vom.rc.o+d6/1',
|
|
318
|
+
});
|
|
301
319
|
|
|
302
320
|
// and once it's collected, the vat should emit `syscall.retireExport`
|
|
303
321
|
// because nobody else will be able to recognize it again
|
|
@@ -309,23 +327,24 @@ test.serial('GC dispatch.dropExports', async t => {
|
|
|
309
327
|
t.deepEqual(log, []);
|
|
310
328
|
});
|
|
311
329
|
|
|
312
|
-
|
|
330
|
+
avaRetry(
|
|
331
|
+
test.serial,
|
|
313
332
|
'GC dispatch.retireExports inhibits syscall.retireExports',
|
|
314
333
|
async t => {
|
|
315
334
|
const { log, syscall } = buildSyscall();
|
|
316
|
-
let
|
|
335
|
+
let collected;
|
|
317
336
|
function build(_vatPowers) {
|
|
318
|
-
|
|
337
|
+
const holder = new Set();
|
|
319
338
|
const root = Far('root', {
|
|
320
339
|
hold() {
|
|
321
|
-
ex1 = Far('export', {});
|
|
322
|
-
|
|
340
|
+
const ex1 = Far('export', {});
|
|
341
|
+
holder.add(ex1);
|
|
342
|
+
collected = watchCollected(ex1);
|
|
323
343
|
return ex1;
|
|
324
344
|
},
|
|
325
345
|
two() {},
|
|
326
346
|
drop() {
|
|
327
|
-
//
|
|
328
|
-
ex1 = undefined; // drop the last userspace strongref
|
|
347
|
+
holder.clear(); // drop the last userspace strongref
|
|
329
348
|
},
|
|
330
349
|
});
|
|
331
350
|
return root;
|
|
@@ -350,25 +369,25 @@ test.serial(
|
|
|
350
369
|
t.deepEqual(log.shift(), {
|
|
351
370
|
type: 'vatstoreSet',
|
|
352
371
|
key: 'idCounters',
|
|
353
|
-
value: '{"exportID":11,"collectionID":
|
|
372
|
+
value: '{"exportID":11,"collectionID":4,"promiseID":5}',
|
|
354
373
|
});
|
|
355
374
|
t.deepEqual(log, []);
|
|
356
375
|
|
|
357
376
|
// the exported Remotable should be held in place by exportedRemotables
|
|
358
377
|
// until we tell the vat we don't need it any more
|
|
359
|
-
t.
|
|
378
|
+
t.false(collected.result);
|
|
360
379
|
|
|
361
380
|
// an intermediate message will trigger GC, but the presence is still held
|
|
362
381
|
await dispatch(makeMessage(rootA, 'two', []));
|
|
363
382
|
await dispatch(makeBringOutYourDead());
|
|
364
|
-
t.
|
|
383
|
+
t.false(collected.result);
|
|
365
384
|
|
|
366
385
|
// now tell the vat we don't need a strong reference to that export.
|
|
367
386
|
await dispatch(makeDropExports(ex1));
|
|
368
387
|
await dispatch(makeBringOutYourDead());
|
|
369
388
|
|
|
370
389
|
// that removes the liveslots strongref, but the vat's remains in place
|
|
371
|
-
t.
|
|
390
|
+
t.false(collected.result);
|
|
372
391
|
|
|
373
392
|
// now the kernel tells the vat we can't even recognize the export
|
|
374
393
|
await dispatch(makeRetireExports(ex1));
|
|
@@ -376,17 +395,25 @@ test.serial(
|
|
|
376
395
|
|
|
377
396
|
// that ought to delete the table entry, but doesn't affect the vat
|
|
378
397
|
// strongref
|
|
379
|
-
t.
|
|
398
|
+
t.false(collected.result);
|
|
380
399
|
|
|
381
400
|
// now tell the vat to drop its strongref
|
|
382
401
|
await dispatch(makeMessage(rootA, 'drop', []));
|
|
383
402
|
await dispatch(makeBringOutYourDead());
|
|
384
403
|
|
|
385
404
|
// which should let the export be collected
|
|
386
|
-
t.
|
|
405
|
+
t.true(collected.result);
|
|
406
|
+
|
|
407
|
+
// the vat should scan for local recognizers (weak collection
|
|
408
|
+
// keys) in case any need to be dropped, and find none
|
|
409
|
+
t.deepEqual(log.shift(), {
|
|
410
|
+
type: 'vatstoreGetNextKey',
|
|
411
|
+
priorKey: 'vom.ir.o+10|',
|
|
412
|
+
result: 'vom.rc.o+d6/1',
|
|
413
|
+
});
|
|
387
414
|
|
|
388
|
-
// the vat should *not* emit `syscall.retireExport`, because it
|
|
389
|
-
// received a dispatch.retireExport
|
|
415
|
+
// the vat should *not* emit `syscall.retireExport`, because it
|
|
416
|
+
// already received a dispatch.retireExport
|
|
390
417
|
t.deepEqual(log, []);
|
|
391
418
|
},
|
|
392
419
|
);
|