@agoric/swingset-liveslots 0.10.3-other-dev-8f8782b.0 → 0.10.3-other-dev-3eb1a1d.0
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 +27 -19
- package/src/boyd-gc.js +598 -0
- package/src/cache.js +3 -2
- package/src/capdata.js +1 -2
- package/src/collectionManager.js +219 -103
- package/src/facetiousness.js +1 -1
- package/src/index.js +4 -2
- package/src/liveslots.js +131 -301
- package/src/message.js +5 -5
- package/src/parseVatSlots.js +1 -1
- package/src/types-index.d.ts +4 -0
- package/src/types-index.js +2 -0
- package/src/types.js +8 -2
- package/src/vatstore-iterators.js +2 -0
- package/src/virtualObjectManager.js +185 -71
- package/src/virtualReferences.js +135 -26
- package/src/watchedPromises.js +67 -17
- 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} +158 -14
- 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.js +1 -1
- package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +4 -4
- package/test/exo-utils.js +70 -0
- package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
- package/test/gc-and-finalize.js +30 -1
- package/test/gc-before-finalizer.test.js +230 -0
- package/test/gc-helpers.js +2 -3
- package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
- package/test/handled-promises.test.js +506 -0
- package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +2 -3
- package/test/liveslots-helpers.js +12 -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} +62 -37
- package/test/{test-liveslots.js → liveslots.test.js} +14 -15
- package/test/mock-gc.js +1 -0
- package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +2 -2
- 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.js +2 -2
- package/test/vat-environment.test.js +65 -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/{test-state-shape.js → state-shape.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +126 -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} +0 -1
- package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +105 -5
- package/test/waitUntilQuiescent.js +2 -1
- package/test/weakset-dropped-remotable.test.js +50 -0
- package/tools/fakeCollectionManager.js +44 -0
- package/tools/fakeVirtualObjectManager.js +62 -0
- package/tools/fakeVirtualSupport.js +389 -0
- package/tools/prepare-strict-test-env.js +124 -0
- package/tools/prepare-test-env.js +13 -0
- package/tools/setup-vat-data.js +96 -0
- package/tools/vo-test-harness.js +143 -0
- package/CHANGELOG.md +0 -61
- package/test/kmarshal.js +0 -79
- package/test/test-handled-promises.js +0 -360
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { makeVirtualObjectManager } from '../src/virtualObjectManager.js';
|
|
2
|
+
|
|
3
|
+
// Note: `fakeVirtualObjectManager` is something of a misnomer here. The
|
|
4
|
+
// virtual object manager being used to implement this realized by the actual
|
|
5
|
+
// virtual object manager code. What's being faked is everything else the
|
|
6
|
+
// virtual object manager is embedded in, i.e., the kernel and the rest of
|
|
7
|
+
// liveslots. In particular, this module can be (and is, and is intended to be)
|
|
8
|
+
// used for unit tests for the virtual object manager itself. What you get back
|
|
9
|
+
// from `makeFakeVirtualObjectManager` can't be used to program as if you were
|
|
10
|
+
// running in a vat because the rest of the vat environment is not present, but
|
|
11
|
+
// it *will* execute virtual object manager operations in the same way that the
|
|
12
|
+
// real one will because underneath it *is* the real one.
|
|
13
|
+
|
|
14
|
+
export function makeFakeVirtualObjectManager(vrm, fakeStuff) {
|
|
15
|
+
const {
|
|
16
|
+
initializeKindHandleKind,
|
|
17
|
+
defineKind,
|
|
18
|
+
defineKindMulti,
|
|
19
|
+
defineDurableKind,
|
|
20
|
+
defineDurableKindMulti,
|
|
21
|
+
makeKindHandle,
|
|
22
|
+
VirtualObjectAwareWeakMap,
|
|
23
|
+
VirtualObjectAwareWeakSet,
|
|
24
|
+
flushStateCache,
|
|
25
|
+
canBeDurable,
|
|
26
|
+
insistAllDurableKindsReconnected,
|
|
27
|
+
} = makeVirtualObjectManager(
|
|
28
|
+
fakeStuff.syscall,
|
|
29
|
+
vrm,
|
|
30
|
+
fakeStuff.allocateExportID,
|
|
31
|
+
fakeStuff.getSlotForVal,
|
|
32
|
+
fakeStuff.requiredValForSlot,
|
|
33
|
+
fakeStuff.registerEntry,
|
|
34
|
+
fakeStuff.marshal.serialize,
|
|
35
|
+
fakeStuff.marshal.unserialize,
|
|
36
|
+
fakeStuff.assertAcceptableSyscallCapdataSize,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const normalVOM = {
|
|
40
|
+
initializeKindHandleKind,
|
|
41
|
+
defineKind,
|
|
42
|
+
defineKindMulti,
|
|
43
|
+
defineDurableKind,
|
|
44
|
+
defineDurableKindMulti,
|
|
45
|
+
makeKindHandle,
|
|
46
|
+
canBeDurable,
|
|
47
|
+
insistAllDurableKindsReconnected,
|
|
48
|
+
VirtualObjectAwareWeakMap,
|
|
49
|
+
VirtualObjectAwareWeakSet,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const debugTools = {
|
|
53
|
+
getValForSlot: fakeStuff.getValForSlot,
|
|
54
|
+
setValForSlot: fakeStuff.setValForSlot,
|
|
55
|
+
registerEntry: fakeStuff.registerEntry,
|
|
56
|
+
deleteEntry: fakeStuff.deleteEntry,
|
|
57
|
+
flushStateCache,
|
|
58
|
+
dumpStore: fakeStuff.dumpStore,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return harden({ ...normalVOM, ...debugTools });
|
|
62
|
+
}
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/* global globalThis */
|
|
2
|
+
/* eslint-disable max-classes-per-file */
|
|
3
|
+
import { assert, Fail } from '@endo/errors';
|
|
4
|
+
import { makeMarshal } from '@endo/marshal';
|
|
5
|
+
import { isPromise } from '@endo/promise-kit';
|
|
6
|
+
|
|
7
|
+
import { parseVatSlot } from '../src/parseVatSlots.js';
|
|
8
|
+
import { makeVirtualReferenceManager } from '../src/virtualReferences.js';
|
|
9
|
+
import { makeWatchedPromiseManager } from '../src/watchedPromises.js';
|
|
10
|
+
import { makeFakeVirtualObjectManager } from './fakeVirtualObjectManager.js';
|
|
11
|
+
import { makeFakeCollectionManager } from './fakeCollectionManager.js';
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
WeakRef: RealWeakRef,
|
|
15
|
+
WeakMap: RealWeakMap,
|
|
16
|
+
WeakSet: RealWeakSet,
|
|
17
|
+
} = globalThis;
|
|
18
|
+
|
|
19
|
+
class FakeFinalizationRegistry {
|
|
20
|
+
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
21
|
+
constructor() {}
|
|
22
|
+
|
|
23
|
+
// eslint-disable-next-line class-methods-use-this
|
|
24
|
+
register(_target, _heldValue, _unregisterToken) {}
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line class-methods-use-this
|
|
27
|
+
unregister(_unregisterToken) {}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class FakeWeakRef {
|
|
31
|
+
#target;
|
|
32
|
+
|
|
33
|
+
constructor(target) {
|
|
34
|
+
this.#target = target;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
deref() {
|
|
38
|
+
return this.#target; // strong ref
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function makeFakeLiveSlotsStuff(options = {}) {
|
|
43
|
+
let vrm;
|
|
44
|
+
function setVrm(vrmToUse) {
|
|
45
|
+
assert(!vrm, 'vrm already configured');
|
|
46
|
+
vrmToUse.initializeIDCounters();
|
|
47
|
+
vrm = vrmToUse;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const {
|
|
51
|
+
fakeStore = new Map(),
|
|
52
|
+
weak = false,
|
|
53
|
+
log,
|
|
54
|
+
FinalizationRegistry = FakeFinalizationRegistry,
|
|
55
|
+
WeakRef = FakeWeakRef, // VRM uses this
|
|
56
|
+
WeakMap = RealWeakMap,
|
|
57
|
+
WeakSet = RealWeakSet,
|
|
58
|
+
addToPossiblyDeadSet = () => {},
|
|
59
|
+
addToPossiblyRetiredSet = () => {},
|
|
60
|
+
} = options;
|
|
61
|
+
|
|
62
|
+
let sortedKeys;
|
|
63
|
+
let priorKeyReturned;
|
|
64
|
+
let priorKeyIndex;
|
|
65
|
+
|
|
66
|
+
function s(v) {
|
|
67
|
+
switch (typeof v) {
|
|
68
|
+
case 'symbol':
|
|
69
|
+
return v.toString();
|
|
70
|
+
case 'bigint':
|
|
71
|
+
return `${v}n`;
|
|
72
|
+
default:
|
|
73
|
+
return `${v}`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function ensureSorted() {
|
|
78
|
+
if (!sortedKeys) {
|
|
79
|
+
sortedKeys = [];
|
|
80
|
+
for (const key of fakeStore.keys()) {
|
|
81
|
+
sortedKeys.push(key);
|
|
82
|
+
}
|
|
83
|
+
sortedKeys.sort((k1, k2) => k1.localeCompare(k2));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function clearGetNextKeyCache() {
|
|
88
|
+
priorKeyReturned = undefined;
|
|
89
|
+
priorKeyIndex = -1;
|
|
90
|
+
}
|
|
91
|
+
clearGetNextKeyCache();
|
|
92
|
+
|
|
93
|
+
function clearSorted() {
|
|
94
|
+
sortedKeys = undefined;
|
|
95
|
+
clearGetNextKeyCache();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function dumpStore() {
|
|
99
|
+
ensureSorted();
|
|
100
|
+
const result = [];
|
|
101
|
+
for (const key of sortedKeys) {
|
|
102
|
+
result.push([key, fakeStore.get(key)]);
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const syscall = {
|
|
108
|
+
vatstoreGet(key) {
|
|
109
|
+
const result = fakeStore.get(key);
|
|
110
|
+
if (log) {
|
|
111
|
+
log.push(`get ${s(key)} => ${s(result)}`);
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
},
|
|
115
|
+
vatstoreGetNextKey(priorKey) {
|
|
116
|
+
assert.typeof(priorKey, 'string');
|
|
117
|
+
ensureSorted();
|
|
118
|
+
// TODO: binary search for priorKey (maybe missing), then get
|
|
119
|
+
// the one after that. For now we go simple and slow. But cache
|
|
120
|
+
// a starting point, because the main use case is a full
|
|
121
|
+
// iteration. OTOH, the main use case also deletes everything,
|
|
122
|
+
// which will clobber the cache on each deletion, so it might
|
|
123
|
+
// not help.
|
|
124
|
+
const start = priorKeyReturned === priorKey ? priorKeyIndex : 0;
|
|
125
|
+
let result;
|
|
126
|
+
for (let i = start; i < sortedKeys.length; i += 1) {
|
|
127
|
+
const key = sortedKeys[i];
|
|
128
|
+
if (key > priorKey) {
|
|
129
|
+
priorKeyReturned = key;
|
|
130
|
+
priorKeyIndex = i;
|
|
131
|
+
result = key;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (!result) {
|
|
136
|
+
// reached end without finding the key, so clear our cache
|
|
137
|
+
clearGetNextKeyCache();
|
|
138
|
+
}
|
|
139
|
+
if (log) {
|
|
140
|
+
log.push(`getNextKey ${s(priorKey)} => ${s(result)}`);
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
},
|
|
144
|
+
vatstoreSet(key, value) {
|
|
145
|
+
if (log) {
|
|
146
|
+
log.push(`set ${s(key)} ${s(value)}`);
|
|
147
|
+
}
|
|
148
|
+
if (!fakeStore.has(key)) {
|
|
149
|
+
clearSorted();
|
|
150
|
+
}
|
|
151
|
+
fakeStore.set(key, value);
|
|
152
|
+
},
|
|
153
|
+
vatstoreDelete(key) {
|
|
154
|
+
if (log) {
|
|
155
|
+
log.push(`delete ${s(key)}`);
|
|
156
|
+
}
|
|
157
|
+
if (fakeStore.has(key)) {
|
|
158
|
+
clearSorted();
|
|
159
|
+
}
|
|
160
|
+
fakeStore.delete(key);
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
function allocateExportID() {
|
|
165
|
+
return vrm.allocateNextID('exportID');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function allocatePromiseID() {
|
|
169
|
+
return vrm.allocateNextID('promiseID');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function allocateCollectionID() {
|
|
173
|
+
return vrm.allocateNextID('collectionID');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// note: The real liveslots slotToVal() maps slots (vrefs) to a WeakRef,
|
|
177
|
+
// and the WeakRef may or may not contain the target value. Use
|
|
178
|
+
// options={weak:true} to match that behavior, or the default weak:false to
|
|
179
|
+
// keep strong references.
|
|
180
|
+
const WeakRefForSlot = weak ? RealWeakRef : FakeWeakRef;
|
|
181
|
+
const valToSlot = new WeakMap();
|
|
182
|
+
const slotToVal = new Map();
|
|
183
|
+
|
|
184
|
+
function getSlotForVal(val) {
|
|
185
|
+
return valToSlot.get(val);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function getValForSlot(slot) {
|
|
189
|
+
const d = slotToVal.get(slot);
|
|
190
|
+
return d && d.deref();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function requiredValForSlot(slot) {
|
|
194
|
+
const val = getValForSlot(slot);
|
|
195
|
+
assert(val, `${slot} must have a value`);
|
|
196
|
+
return val;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function setValForSlot(slot, val) {
|
|
200
|
+
slotToVal.set(slot, new WeakRefForSlot(val));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function convertValToSlot(val) {
|
|
204
|
+
if (!valToSlot.has(val)) {
|
|
205
|
+
const slot = isPromise(val)
|
|
206
|
+
? `p+${allocatePromiseID()}`
|
|
207
|
+
: `o+${allocateExportID()}`;
|
|
208
|
+
valToSlot.set(val, slot);
|
|
209
|
+
setValForSlot(slot, val);
|
|
210
|
+
}
|
|
211
|
+
return valToSlot.get(val);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function convertSlotToVal(slot) {
|
|
215
|
+
const { type, id, virtual, durable, facet, baseRef } = parseVatSlot(slot);
|
|
216
|
+
assert.equal(type, 'object');
|
|
217
|
+
let val = getValForSlot(baseRef);
|
|
218
|
+
if (val) {
|
|
219
|
+
if (virtual || durable) {
|
|
220
|
+
if (facet !== undefined) {
|
|
221
|
+
return vrm.getFacet(id, val, facet);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return val;
|
|
225
|
+
}
|
|
226
|
+
let result;
|
|
227
|
+
if (virtual || durable) {
|
|
228
|
+
if (vrm) {
|
|
229
|
+
val = vrm.reanimate(slot);
|
|
230
|
+
if (facet !== undefined) {
|
|
231
|
+
result = vrm.getFacet(id, val, facet);
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
assert.fail('fake liveSlots stuff configured without vrm');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
registerEntry(baseRef, val, facet !== undefined);
|
|
238
|
+
if (!result) {
|
|
239
|
+
result = val;
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const marshal = makeMarshal(convertValToSlot, convertSlotToVal, {
|
|
245
|
+
serializeBodyFormat: 'smallcaps',
|
|
246
|
+
marshalName: 'fakeLiveSlots',
|
|
247
|
+
errorIdNum: 80_000,
|
|
248
|
+
marshalSaveError: _err => {},
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
function registerEntry(baseRef, val, valIsCohort) {
|
|
252
|
+
const { facet } = parseVatSlot(baseRef);
|
|
253
|
+
!facet ||
|
|
254
|
+
Fail`registerEntry(${baseRef} should not receive individual facets`;
|
|
255
|
+
setValForSlot(baseRef, val);
|
|
256
|
+
if (valIsCohort) {
|
|
257
|
+
const { id } = parseVatSlot(baseRef);
|
|
258
|
+
for (const [index, name] of vrm.getFacetNames(id).entries()) {
|
|
259
|
+
valToSlot.set(val[name], `${baseRef}:${index}`);
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
valToSlot.set(val, baseRef);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function deleteEntry(slot, val) {
|
|
267
|
+
if (!val) {
|
|
268
|
+
val = getValForSlot(slot);
|
|
269
|
+
}
|
|
270
|
+
slotToVal.delete(slot);
|
|
271
|
+
valToSlot.delete(val);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function assertAcceptableSyscallCapdataSize(_capdatas) {}
|
|
275
|
+
|
|
276
|
+
const maybeExportPromise = _vref => false;
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
syscall,
|
|
280
|
+
allocateExportID,
|
|
281
|
+
allocatePromiseID,
|
|
282
|
+
allocateCollectionID,
|
|
283
|
+
getSlotForVal,
|
|
284
|
+
requiredValForSlot,
|
|
285
|
+
getValForSlot,
|
|
286
|
+
setValForSlot,
|
|
287
|
+
registerEntry,
|
|
288
|
+
valToSlot,
|
|
289
|
+
slotToVal,
|
|
290
|
+
convertValToSlot,
|
|
291
|
+
convertSlotToVal,
|
|
292
|
+
marshal,
|
|
293
|
+
deleteEntry,
|
|
294
|
+
FinalizationRegistry,
|
|
295
|
+
WeakRef,
|
|
296
|
+
WeakMap,
|
|
297
|
+
WeakSet,
|
|
298
|
+
addToPossiblyDeadSet,
|
|
299
|
+
addToPossiblyRetiredSet,
|
|
300
|
+
dumpStore,
|
|
301
|
+
setVrm,
|
|
302
|
+
assertAcceptableSyscallCapdataSize,
|
|
303
|
+
maybeExportPromise,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export function makeFakeVirtualReferenceManager(
|
|
308
|
+
fakeStuff,
|
|
309
|
+
relaxDurabilityRules = true,
|
|
310
|
+
) {
|
|
311
|
+
return makeVirtualReferenceManager(
|
|
312
|
+
fakeStuff.syscall,
|
|
313
|
+
fakeStuff.getSlotForVal,
|
|
314
|
+
fakeStuff.getValForSlot,
|
|
315
|
+
fakeStuff.FinalizationRegistry,
|
|
316
|
+
fakeStuff.WeakRef,
|
|
317
|
+
fakeStuff.addToPossiblyDeadSet,
|
|
318
|
+
fakeStuff.addToPossiblyRetiredSet,
|
|
319
|
+
relaxDurabilityRules,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export function makeFakeWatchedPromiseManager(
|
|
324
|
+
vrm,
|
|
325
|
+
vom,
|
|
326
|
+
collectionManager,
|
|
327
|
+
fakeStuff,
|
|
328
|
+
) {
|
|
329
|
+
return makeWatchedPromiseManager({
|
|
330
|
+
syscall: fakeStuff.syscall,
|
|
331
|
+
vrm,
|
|
332
|
+
vom,
|
|
333
|
+
collectionManager,
|
|
334
|
+
convertValToSlot: fakeStuff.convertValToSlot,
|
|
335
|
+
convertSlotToVal: fakeStuff.convertSlotToVal,
|
|
336
|
+
maybeExportPromise: fakeStuff.maybeExportPromise,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Configure virtual stuff with relaxed durability rules and fake liveslots
|
|
342
|
+
*
|
|
343
|
+
* @param {object} [options]
|
|
344
|
+
* @param {number} [options.cacheSize]
|
|
345
|
+
* @param {boolean} [options.relaxDurabilityRules]
|
|
346
|
+
* @param {Map<string, string>} [options.fakeStore]
|
|
347
|
+
* @param {WeakMapConstructor} [options.WeakMap]
|
|
348
|
+
* @param {WeakSetConstructor} [options.WeakSet]
|
|
349
|
+
* @param {boolean} [options.weak]
|
|
350
|
+
*/
|
|
351
|
+
export function makeFakeVirtualStuff(options = {}) {
|
|
352
|
+
const actualOptions = {
|
|
353
|
+
relaxDurabilityRules: true,
|
|
354
|
+
...options,
|
|
355
|
+
};
|
|
356
|
+
const { relaxDurabilityRules } = actualOptions;
|
|
357
|
+
const fakeStuff = makeFakeLiveSlotsStuff(actualOptions);
|
|
358
|
+
const vrm = makeFakeVirtualReferenceManager(fakeStuff, relaxDurabilityRules);
|
|
359
|
+
fakeStuff.setVrm(vrm);
|
|
360
|
+
const vom = makeFakeVirtualObjectManager(vrm, fakeStuff);
|
|
361
|
+
vom.initializeKindHandleKind();
|
|
362
|
+
const cm = makeFakeCollectionManager(vrm, fakeStuff, actualOptions);
|
|
363
|
+
const wpm = makeFakeWatchedPromiseManager(vrm, vom, cm, fakeStuff);
|
|
364
|
+
wpm.preparePromiseWatcherTables();
|
|
365
|
+
return { fakeStuff, vrm, vom, cm, wpm };
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export function makeStandaloneFakeVirtualObjectManager(options = {}) {
|
|
369
|
+
const fakeStuff = makeFakeLiveSlotsStuff(options);
|
|
370
|
+
const { relaxDurabilityRules = true } = options;
|
|
371
|
+
const vrm = makeFakeVirtualReferenceManager(fakeStuff, relaxDurabilityRules);
|
|
372
|
+
fakeStuff.setVrm(vrm);
|
|
373
|
+
const vom = makeFakeVirtualObjectManager(vrm, fakeStuff);
|
|
374
|
+
vom.initializeKindHandleKind();
|
|
375
|
+
return vom;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
export function makeStandaloneFakeCollectionManager(options = {}) {
|
|
379
|
+
const fakeStuff = makeFakeLiveSlotsStuff(options);
|
|
380
|
+
const { relaxDurabilityRules = true } = options;
|
|
381
|
+
const vrm = makeFakeVirtualReferenceManager(fakeStuff, relaxDurabilityRules);
|
|
382
|
+
fakeStuff.setVrm(vrm);
|
|
383
|
+
return makeFakeCollectionManager(vrm, fakeStuff, options);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export {
|
|
387
|
+
makeStandaloneFakeVirtualObjectManager as makeFakeVirtualObjectManager,
|
|
388
|
+
makeStandaloneFakeCollectionManager as makeFakeCollectionManager,
|
|
389
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepare Agoric SwingSet vat global strict environment for testing.
|
|
3
|
+
*
|
|
4
|
+
* Installs Hardened JS (and does lockdown), plus adds mocks for virtual objects
|
|
5
|
+
* and stores.
|
|
6
|
+
*
|
|
7
|
+
* Exports tools for simulating upgrades.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import '@agoric/internal/src/install-ses-debug.js';
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line import/order
|
|
13
|
+
import { reincarnate, flushIncarnation } from './setup-vat-data.js';
|
|
14
|
+
|
|
15
|
+
import { makePromiseKit } from '@endo/promise-kit';
|
|
16
|
+
import { Fail } from '@endo/errors';
|
|
17
|
+
import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js';
|
|
18
|
+
import { makeUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js';
|
|
19
|
+
|
|
20
|
+
export { flushIncarnation };
|
|
21
|
+
export { eventLoopIteration as nextCrank };
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @import { PromiseKit } from '@endo/promise-kit'
|
|
25
|
+
* @import { Baggage } from '@agoric/swingset-liveslots'
|
|
26
|
+
* @import { ReincarnateOptions } from './setup-vat-data.js'
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** @type {ReincarnateOptions} */
|
|
30
|
+
let incarnation;
|
|
31
|
+
let incarnationNumber = 0;
|
|
32
|
+
|
|
33
|
+
/** @param {Omit<ReincarnateOptions, 'fakeVomKit' | 'fakeStore'>} [options] */
|
|
34
|
+
export const annihilate = (options = {}) => {
|
|
35
|
+
// @ts-expect-error fakeStore and fakeVomKit don't exist on type, but drop them if they do at runtime
|
|
36
|
+
const { fakeStore: _fs, fakeVomKit: _fvk, ...opts } = options;
|
|
37
|
+
incarnation = reincarnate({ relaxDurabilityRules: false, ...opts });
|
|
38
|
+
incarnationNumber = 0;
|
|
39
|
+
return incarnation;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** @returns {Baggage} */
|
|
43
|
+
export const getBaggage = () => {
|
|
44
|
+
return incarnation.fakeVomKit.cm.provideBaggage();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {ReincarnateOptions} [fromIncarnation]
|
|
49
|
+
*/
|
|
50
|
+
export const nextLife = (fromIncarnation = incarnation) => {
|
|
51
|
+
incarnation = reincarnate(fromIncarnation);
|
|
52
|
+
incarnationNumber += 1;
|
|
53
|
+
return incarnation;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @template {(baggage: Baggage) => Promise<any> | any} B
|
|
58
|
+
* @param {B} build
|
|
59
|
+
* @param {(tools: Awaited<ReturnType<B>>) => Promise<void> | void} [run]
|
|
60
|
+
* @param {object} [options]
|
|
61
|
+
* @param {ReincarnateOptions} [options.fromIncarnation]
|
|
62
|
+
* @param {boolean} [options.cleanStart]
|
|
63
|
+
*/
|
|
64
|
+
export const startLife = async (
|
|
65
|
+
build,
|
|
66
|
+
run,
|
|
67
|
+
{ fromIncarnation, cleanStart } = {},
|
|
68
|
+
) => {
|
|
69
|
+
await eventLoopIteration();
|
|
70
|
+
if (cleanStart) annihilate();
|
|
71
|
+
const oldIncarnationNumber = incarnationNumber;
|
|
72
|
+
const oldIncarnation = incarnation;
|
|
73
|
+
const disconnectionObject = makeUpgradeDisconnection(
|
|
74
|
+
'vat upgraded',
|
|
75
|
+
oldIncarnationNumber,
|
|
76
|
+
);
|
|
77
|
+
const { fakeVomKit } = nextLife(fromIncarnation);
|
|
78
|
+
/** @type {Map<string, PromiseKit<any>>} */
|
|
79
|
+
const previouslyWatchedPromises = new Map();
|
|
80
|
+
let buildTools;
|
|
81
|
+
try {
|
|
82
|
+
buildTools = await build(getBaggage());
|
|
83
|
+
fakeVomKit.wpm.loadWatchedPromiseTable(vref => {
|
|
84
|
+
// See revivePromise in liveslots.js
|
|
85
|
+
const { getValForSlot, valToSlot, setValForSlot } = fakeVomKit.fakeStuff;
|
|
86
|
+
// Assume all promises were decided by the previous incarnation
|
|
87
|
+
!getValForSlot(vref) || Fail`Attempting to revive known promise ${vref}`;
|
|
88
|
+
const pk = makePromiseKit();
|
|
89
|
+
previouslyWatchedPromises.set(vref, pk);
|
|
90
|
+
const val = pk.promise;
|
|
91
|
+
valToSlot.set(val, vref);
|
|
92
|
+
setValForSlot(vref, val);
|
|
93
|
+
return val;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
fakeVomKit.vom.insistAllDurableKindsReconnected();
|
|
97
|
+
|
|
98
|
+
await eventLoopIteration();
|
|
99
|
+
// End of start crank
|
|
100
|
+
} catch (err) {
|
|
101
|
+
// Rollback upgrade
|
|
102
|
+
incarnation = oldIncarnation;
|
|
103
|
+
incarnationNumber = oldIncarnationNumber;
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Simulate a dispatch of previously decided promise rejections
|
|
108
|
+
// In real swingset this could happen after some deliveries
|
|
109
|
+
for (const { reject } of previouslyWatchedPromises.values()) {
|
|
110
|
+
reject(disconnectionObject);
|
|
111
|
+
}
|
|
112
|
+
await eventLoopIteration();
|
|
113
|
+
// End of resolution dispatch crank
|
|
114
|
+
|
|
115
|
+
if (run) {
|
|
116
|
+
await run(buildTools);
|
|
117
|
+
await eventLoopIteration();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return incarnation;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Setup the initial incarnation
|
|
124
|
+
annihilate();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepare Agoric SwingSet vat global environment for testing.
|
|
3
|
+
*
|
|
4
|
+
* Installs Hardened JS (and does lockdown), plus adds mocks for virtual objects
|
|
5
|
+
* and stores.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import '@agoric/internal/src/install-ses-debug.js';
|
|
9
|
+
|
|
10
|
+
import { reincarnate } from './setup-vat-data.js';
|
|
11
|
+
|
|
12
|
+
// Install the VatData globals.
|
|
13
|
+
reincarnate();
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/* global globalThis */
|
|
3
|
+
|
|
4
|
+
// This file produces the globalThis.VatData property outside of a
|
|
5
|
+
// running SwingSet so that it can be used by '@agoric/vat-data'
|
|
6
|
+
// (which only *consumes* `globalThis.VatData`) in code under test. It
|
|
7
|
+
// also populates the passStyleOf symbol-named property.
|
|
8
|
+
|
|
9
|
+
import { passStyleOf } from '@endo/pass-style';
|
|
10
|
+
import { PassStyleOfEndowmentSymbol } from '@endo/pass-style/endow.js';
|
|
11
|
+
import { makeFakeVirtualStuff } from './fakeVirtualSupport.js';
|
|
12
|
+
|
|
13
|
+
const { WeakMap, WeakSet } = globalThis;
|
|
14
|
+
|
|
15
|
+
/** @typedef {ReturnType<typeof makeFakeVirtualStuff>} FakeVomKit */
|
|
16
|
+
|
|
17
|
+
/** @type {FakeVomKit} */
|
|
18
|
+
let fakeVomKit;
|
|
19
|
+
|
|
20
|
+
globalThis.VatData = harden({
|
|
21
|
+
// @ts-expect-error spread argument for non-rest parameter
|
|
22
|
+
defineKind: (...args) => fakeVomKit.vom.defineKind(...args),
|
|
23
|
+
// @ts-expect-error spread argument for non-rest parameter
|
|
24
|
+
defineKindMulti: (...args) => fakeVomKit.vom.defineKindMulti(...args),
|
|
25
|
+
// @ts-expect-error spread argument for non-rest parameter
|
|
26
|
+
defineDurableKind: (...args) => fakeVomKit.vom.defineDurableKind(...args),
|
|
27
|
+
defineDurableKindMulti: (...args) =>
|
|
28
|
+
// @ts-expect-error spread argument for non-rest parameter
|
|
29
|
+
fakeVomKit.vom.defineDurableKindMulti(...args),
|
|
30
|
+
makeKindHandle: tag => fakeVomKit.vom.makeKindHandle(tag),
|
|
31
|
+
canBeDurable: (...args) => fakeVomKit.vom.canBeDurable(...args),
|
|
32
|
+
providePromiseWatcher: (...args) =>
|
|
33
|
+
// @ts-expect-error spread argument for non-rest parameter
|
|
34
|
+
fakeVomKit.wpm.providePromiseWatcher(...args),
|
|
35
|
+
watchPromise: (p, watcher, ...args) =>
|
|
36
|
+
fakeVomKit.wpm.watchPromise(p, watcher, ...args),
|
|
37
|
+
makeScalarBigMapStore: (...args) =>
|
|
38
|
+
fakeVomKit.cm.makeScalarBigMapStore(...args),
|
|
39
|
+
makeScalarBigWeakMapStore: (...args) =>
|
|
40
|
+
fakeVomKit.cm.makeScalarBigWeakMapStore(...args),
|
|
41
|
+
makeScalarBigSetStore: (...args) =>
|
|
42
|
+
fakeVomKit.cm.makeScalarBigSetStore(...args),
|
|
43
|
+
makeScalarBigWeakSetStore: (...args) =>
|
|
44
|
+
fakeVomKit.cm.makeScalarBigWeakSetStore(...args),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
globalThis[PassStyleOfEndowmentSymbol] = passStyleOf;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @typedef {import("@agoric/internal").Simplify<
|
|
51
|
+
* Omit<NonNullable<Parameters<typeof makeFakeVirtualStuff>[0]>, 'WeakMap' | 'WeakSet'> &
|
|
52
|
+
* { fakeVomKit: FakeVomKit; fakeStore: Map<string, string> }
|
|
53
|
+
* >} ReincarnateOptions
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @param {Partial<ReincarnateOptions>} options
|
|
59
|
+
* @returns {Omit<ReincarnateOptions, 'fakeVomKit'>}
|
|
60
|
+
*/
|
|
61
|
+
export const flushIncarnation = (options = {}) => {
|
|
62
|
+
const { fakeVomKit: fvk = fakeVomKit, ...fakeStuffOptions } = options;
|
|
63
|
+
|
|
64
|
+
if (fvk) {
|
|
65
|
+
fvk.vom.flushStateCache();
|
|
66
|
+
fvk.cm.flushSchemaCache();
|
|
67
|
+
fvk.vrm.flushIDCounters();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Clone previous fakeStore (if any) to avoid mutations from previous incarnation
|
|
71
|
+
const fakeStore = new Map(options.fakeStore);
|
|
72
|
+
|
|
73
|
+
return { ...fakeStuffOptions, fakeStore };
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
* @param {Partial<ReincarnateOptions>} options
|
|
79
|
+
* @returns {ReincarnateOptions}
|
|
80
|
+
*/
|
|
81
|
+
export const reincarnate = (options = {}) => {
|
|
82
|
+
const clonedIncarnation = flushIncarnation(options);
|
|
83
|
+
|
|
84
|
+
fakeVomKit = makeFakeVirtualStuff({
|
|
85
|
+
...clonedIncarnation,
|
|
86
|
+
WeakMap,
|
|
87
|
+
WeakSet,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// @ts-expect-error toStringTag set imperatively so it doesn't show up in the type
|
|
91
|
+
globalThis.WeakMap = fakeVomKit.vom.VirtualObjectAwareWeakMap;
|
|
92
|
+
// @ts-expect-error ditto
|
|
93
|
+
globalThis.WeakSet = fakeVomKit.vom.VirtualObjectAwareWeakSet;
|
|
94
|
+
|
|
95
|
+
return { ...clonedIncarnation, fakeVomKit };
|
|
96
|
+
};
|