@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,11 +1,13 @@
|
|
|
1
1
|
/* global globalThis */
|
|
2
|
-
/* eslint-disable
|
|
2
|
+
/* eslint-disable jsdoc/require-returns-type */
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { environmentOptionsListHas } from '@endo/env-options';
|
|
5
|
+
import { assert, Fail, q, b } from '@endo/errors';
|
|
5
6
|
import { assertPattern, mustMatch } from '@agoric/store';
|
|
6
7
|
import { defendPrototype, defendPrototypeKit } from '@endo/exo/tools.js';
|
|
7
8
|
import { Far, passStyleOf } from '@endo/marshal';
|
|
8
9
|
import { Nat } from '@endo/nat';
|
|
10
|
+
import { kindOf } from '@endo/patterns';
|
|
9
11
|
import { parseVatSlot, makeBaseRef } from './parseVatSlots.js';
|
|
10
12
|
import { enumerateKeysWithPrefix } from './vatstore-iterators.js';
|
|
11
13
|
import { makeCache } from './cache.js';
|
|
@@ -14,17 +16,24 @@ import {
|
|
|
14
16
|
checkAndUpdateFacetiousness,
|
|
15
17
|
} from './facetiousness.js';
|
|
16
18
|
|
|
17
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* @import {DurableKindHandle} from '@agoric/swingset-liveslots'
|
|
21
|
+
* @import {DefineKindOptions} from '@agoric/swingset-liveslots'
|
|
22
|
+
* @import {ClassContextProvider, KitContextProvider} from '@endo/exo'
|
|
23
|
+
* @import {ToCapData, FromCapData} from '@endo/marshal';
|
|
24
|
+
* @import {Pattern} from '@endo/patterns';
|
|
25
|
+
* @import {SwingSetCapData} from './types.js';
|
|
26
|
+
*/
|
|
18
27
|
|
|
19
|
-
const {
|
|
28
|
+
const {
|
|
29
|
+
hasOwn,
|
|
30
|
+
defineProperty,
|
|
31
|
+
getOwnPropertyNames,
|
|
32
|
+
values,
|
|
33
|
+
entries,
|
|
34
|
+
fromEntries,
|
|
35
|
+
} = Object;
|
|
20
36
|
const { ownKeys } = Reflect;
|
|
21
|
-
const { quote: q } = assert;
|
|
22
|
-
|
|
23
|
-
// import { kdebug } from './kdebug.js';
|
|
24
|
-
|
|
25
|
-
// TODO Use environment-options.js currently in ses/src after factoring it out
|
|
26
|
-
// to a new package.
|
|
27
|
-
const env = (globalThis.process || {}).env || {};
|
|
28
37
|
|
|
29
38
|
// Turn on to give each exo instance its own toStringTag value which exposes
|
|
30
39
|
// the SwingSet vref.
|
|
@@ -33,9 +42,7 @@ const env = (globalThis.process || {}).env || {};
|
|
|
33
42
|
// confidential object-creation activity, so this must not be something
|
|
34
43
|
// that unprivileged vat code (including unprivileged contracts) can do
|
|
35
44
|
// for themselves.
|
|
36
|
-
const LABEL_INSTANCES = (
|
|
37
|
-
.split(':')
|
|
38
|
-
.includes('label-instances');
|
|
45
|
+
const LABEL_INSTANCES = environmentOptionsListHas('DEBUG', 'label-instances');
|
|
39
46
|
|
|
40
47
|
// This file implements the "Virtual Objects" system, currently documented in
|
|
41
48
|
// {@link https://github.com/Agoric/agoric-sdk/blob/master/packages/SwingSet/docs/virtual-objects.md})
|
|
@@ -132,40 +139,6 @@ const makeContextCache = (makeState, makeContext) => {
|
|
|
132
139
|
return makeCache(readBacking, writeBacking, deleteBacking);
|
|
133
140
|
};
|
|
134
141
|
|
|
135
|
-
/**
|
|
136
|
-
* @typedef {import('@endo/exo/src/exo-tools.js').ContextProvider } ContextProvider
|
|
137
|
-
*/
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* @param {*} contextCache
|
|
141
|
-
* @param {*} getSlotForVal
|
|
142
|
-
* @returns {ContextProvider}
|
|
143
|
-
*/
|
|
144
|
-
const makeContextProvider = (contextCache, getSlotForVal) => {
|
|
145
|
-
return harden(rep => contextCache.get(getSlotForVal(rep)));
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const makeContextProviderKit = (contextCache, getSlotForVal, facetNames) => {
|
|
149
|
-
/** @type { Record<string, any> } */
|
|
150
|
-
const contextProviderKit = {};
|
|
151
|
-
for (const [index, name] of facetNames.entries()) {
|
|
152
|
-
contextProviderKit[name] = rep => {
|
|
153
|
-
const vref = getSlotForVal(rep);
|
|
154
|
-
const { baseRef, facet } = parseVatSlot(vref);
|
|
155
|
-
|
|
156
|
-
// Without this check, an attacker (with access to both cohort1.facetA
|
|
157
|
-
// and cohort2.facetB) could effectively forge access to cohort1.facetB
|
|
158
|
-
// and cohort2.facetA. They could not forge the identity of those two
|
|
159
|
-
// objects, but they could invoke all their equivalent methods, by using
|
|
160
|
-
// e.g. cohort1.facetA.foo.apply(cohort2.facetB, [...args])
|
|
161
|
-
Number(facet) === index || Fail`illegal cross-facet access`;
|
|
162
|
-
|
|
163
|
-
return harden(contextCache.get(baseRef));
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
return harden(contextProviderKit);
|
|
167
|
-
};
|
|
168
|
-
|
|
169
142
|
// The management of single Representatives (i.e. defineKind) is very similar
|
|
170
143
|
// to that of a cohort of facets (i.e. defineKindMulti). In this description,
|
|
171
144
|
// we use "self/facets" to refer to either 'self' or 'facets', as appropriate
|
|
@@ -260,32 +233,67 @@ const makeFacets = (
|
|
|
260
233
|
};
|
|
261
234
|
|
|
262
235
|
const insistDurableCapdata = (vrm, what, capdata, valueFor) => {
|
|
263
|
-
capdata.slots
|
|
236
|
+
for (const [idx, vref] of entries(capdata.slots)) {
|
|
264
237
|
if (!vrm.isDurable(vref)) {
|
|
265
238
|
if (valueFor) {
|
|
266
|
-
Fail`value for ${what} is not durable: slot ${
|
|
239
|
+
Fail`value for ${what} is not durable: slot ${b(idx)} of ${capdata}`;
|
|
267
240
|
} else {
|
|
268
|
-
Fail`${what} is not durable: slot ${
|
|
241
|
+
Fail`${what} is not durable: slot ${b(idx)} of ${capdata}`;
|
|
269
242
|
}
|
|
270
243
|
}
|
|
271
|
-
}
|
|
244
|
+
}
|
|
272
245
|
};
|
|
273
246
|
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
247
|
+
const isUndefinedPatt = patt =>
|
|
248
|
+
patt === undefined ||
|
|
249
|
+
(kindOf(patt) === 'match:kind' && patt.payload === 'undefined');
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Assert that a new stateShape either matches the old, or only differs in the
|
|
253
|
+
* addition of new clearly-optional top-level fields as conveyed by an
|
|
254
|
+
* [Endo `M.or`]{@link https://endojs.github.io/endo/interfaces/_endo_patterns.PatternMatchers.html#or}
|
|
255
|
+
* Pattern with at least one `undefined` alternative.
|
|
256
|
+
*
|
|
257
|
+
* @param {SwingSetCapData} oldCD
|
|
258
|
+
* @param {SwingSetCapData} newCD
|
|
259
|
+
* @param {{ newShape: Record<string, Pattern>, serialize: ToCapData<string>, unserialize: FromCapData<string> }} powers
|
|
260
|
+
*/
|
|
261
|
+
const insistCompatibleShapeCapData = (
|
|
262
|
+
oldCD,
|
|
263
|
+
newCD,
|
|
264
|
+
{ newShape, serialize, unserialize },
|
|
265
|
+
) => {
|
|
278
266
|
if (oldCD.body !== newCD.body) {
|
|
279
|
-
|
|
267
|
+
// Allow introduction of any clearly-optional new field at top level.
|
|
268
|
+
const oldShape =
|
|
269
|
+
unserialize(oldCD) ||
|
|
270
|
+
Fail`durable Kind stateShape mismatch (no old shape)`;
|
|
271
|
+
passStyleOf(oldShape) === 'copyRecord' ||
|
|
272
|
+
Fail`durable Kind stateShape mismatch (invalid old shape)`;
|
|
273
|
+
assertPattern(oldShape);
|
|
274
|
+
for (const [name, oldPatt] of Object.entries(oldShape)) {
|
|
275
|
+
// Assert presence and CapData shape, but save slots for their own clause.
|
|
276
|
+
(Object.hasOwn(newShape, name) &&
|
|
277
|
+
serialize(newShape[name]).body === serialize(oldPatt).body) ||
|
|
278
|
+
Fail`durable Kind stateShape mismatch (body ${name})`;
|
|
279
|
+
}
|
|
280
|
+
for (const [name, newPatt] of Object.entries(newShape)) {
|
|
281
|
+
if (Object.hasOwn(oldShape, name)) continue;
|
|
282
|
+
kindOf(newPatt) === 'match:or' ||
|
|
283
|
+
Fail`durable Kind stateShape mismatch (body new field ${name})`;
|
|
284
|
+
// @ts-expect-error A "match:or" pattern has a `payload` array of Patterns
|
|
285
|
+
newPatt.payload.some(patt => isUndefinedPatt(patt)) ||
|
|
286
|
+
Fail`durable Kind stateShape mismatch (body ${name})`;
|
|
287
|
+
}
|
|
280
288
|
}
|
|
281
289
|
if (oldCD.slots.length !== newCD.slots.length) {
|
|
282
290
|
Fail`durable Kind stateShape mismatch (slots.length)`;
|
|
283
291
|
}
|
|
284
|
-
oldCD.slots
|
|
292
|
+
for (const [idx, oldVref] of entries(oldCD.slots)) {
|
|
285
293
|
if (newCD.slots[idx] !== oldVref) {
|
|
286
294
|
Fail`durable Kind stateShape mismatch (slot[${idx}])`;
|
|
287
295
|
}
|
|
288
|
-
}
|
|
296
|
+
}
|
|
289
297
|
};
|
|
290
298
|
|
|
291
299
|
/**
|
|
@@ -302,11 +310,11 @@ const insistSameCapData = (oldCD, newCD) => {
|
|
|
302
310
|
* @param {(slot: string) => object} requiredValForSlot
|
|
303
311
|
* @param {*} registerValue Function to register a new slot+value in liveSlot's
|
|
304
312
|
* various tables
|
|
305
|
-
* @param {
|
|
306
|
-
* @param {
|
|
313
|
+
* @param {ToCapData<string>} serialize Serializer for this vat
|
|
314
|
+
* @param {FromCapData<string>} unserialize Unserializer for this vat
|
|
307
315
|
* @param {*} assertAcceptableSyscallCapdataSize Function to check for oversized
|
|
308
316
|
* syscall params
|
|
309
|
-
* @param {import('./types').LiveSlotsOptions} [liveSlotsOptions]
|
|
317
|
+
* @param {import('./types.js').LiveSlotsOptions} [liveSlotsOptions]
|
|
310
318
|
* @param {{ WeakMap: typeof WeakMap, WeakSet: typeof WeakSet }} [powers]
|
|
311
319
|
* Specifying the underlying WeakMap/WeakSet objects to wrap with
|
|
312
320
|
* VirtualObjectAwareWeakMap/Set. By default, capture the ones currently
|
|
@@ -314,7 +322,7 @@ const insistSameCapData = (oldCD, newCD) => {
|
|
|
314
322
|
* recursion if our returned WeakMap/WeakSet wrappers are subsequently installed
|
|
315
323
|
* on globalThis.
|
|
316
324
|
*
|
|
317
|
-
* @returns
|
|
325
|
+
* @returns a new virtual object manager.
|
|
318
326
|
*
|
|
319
327
|
* The virtual object manager allows the creation of persistent objects that do
|
|
320
328
|
* not need to occupy memory when they are not in use. It provides five
|
|
@@ -562,7 +570,7 @@ export const makeVirtualObjectManager = (
|
|
|
562
570
|
* tag: string,
|
|
563
571
|
* unfaceted?: boolean,
|
|
564
572
|
* facets?: string[],
|
|
565
|
-
* stateShapeCapData?:
|
|
573
|
+
* stateShapeCapData?: SwingSetCapData
|
|
566
574
|
* }} DurableKindDescriptor
|
|
567
575
|
*/
|
|
568
576
|
|
|
@@ -707,10 +715,18 @@ export const makeVirtualObjectManager = (
|
|
|
707
715
|
durableKindDescriptor = undefined, // only for durables
|
|
708
716
|
) => {
|
|
709
717
|
const {
|
|
710
|
-
finish,
|
|
718
|
+
finish = undefined,
|
|
711
719
|
stateShape = undefined,
|
|
720
|
+
receiveAmplifier = undefined,
|
|
721
|
+
receiveInstanceTester = undefined,
|
|
712
722
|
thisfulMethods = false,
|
|
723
|
+
} = options;
|
|
724
|
+
let {
|
|
725
|
+
// These are "let" rather than "const" only to accommodate code
|
|
726
|
+
// below that tolerates an old version of the vat-data package.
|
|
727
|
+
// See there for more explanation.
|
|
713
728
|
interfaceGuard = undefined,
|
|
729
|
+
interfaceGuardKit = undefined,
|
|
714
730
|
} = options;
|
|
715
731
|
|
|
716
732
|
const statePrototype = {}; // Not frozen yet
|
|
@@ -731,11 +747,35 @@ export const makeVirtualObjectManager = (
|
|
|
731
747
|
switch (assessFacetiousness(behavior)) {
|
|
732
748
|
case 'one': {
|
|
733
749
|
assert(!multifaceted);
|
|
750
|
+
interfaceGuardKit === undefined ||
|
|
751
|
+
Fail`Use an interfaceGuard, not interfaceGuardKit, to protect class ${q(
|
|
752
|
+
tag,
|
|
753
|
+
)}`;
|
|
734
754
|
proposedFacetNames = undefined;
|
|
735
755
|
break;
|
|
736
756
|
}
|
|
737
757
|
case 'many': {
|
|
738
758
|
assert(multifaceted);
|
|
759
|
+
|
|
760
|
+
if (interfaceGuard && interfaceGuardKit === undefined) {
|
|
761
|
+
// This if clause is for the purpose of tolerating versions
|
|
762
|
+
// of the vata-data package that precede
|
|
763
|
+
// https://github.com/Agoric/agoric-sdk/pull/8220 .
|
|
764
|
+
// Before that PR, the options name `interfaceGuard` would
|
|
765
|
+
// actually carry the InterfaceGuardKit.
|
|
766
|
+
//
|
|
767
|
+
// Tolerating the old vat-data with the new types.
|
|
768
|
+
// @ts-expect-error
|
|
769
|
+
interfaceGuardKit = interfaceGuard;
|
|
770
|
+
interfaceGuard = undefined;
|
|
771
|
+
// The rest of the code from here makes no further compromise
|
|
772
|
+
// for that old version of the vat-data package.
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
interfaceGuard === undefined ||
|
|
776
|
+
Fail`Use an interfaceGuardKit, not an interfaceGuard, to protect class kit ${q(
|
|
777
|
+
tag,
|
|
778
|
+
)}`;
|
|
739
779
|
proposedFacetNames = ownKeys(behavior).sort();
|
|
740
780
|
break;
|
|
741
781
|
}
|
|
@@ -763,6 +803,11 @@ export const makeVirtualObjectManager = (
|
|
|
763
803
|
Fail`A stateShape must be a copyRecord: ${q(stateShape)}`;
|
|
764
804
|
assertPattern(stateShape);
|
|
765
805
|
|
|
806
|
+
if (!multifaceted) {
|
|
807
|
+
receiveAmplifier === undefined ||
|
|
808
|
+
Fail`Only facets of an exo class kit can be amplified, not ${q(tag)}`;
|
|
809
|
+
}
|
|
810
|
+
|
|
766
811
|
let facetNames;
|
|
767
812
|
|
|
768
813
|
if (isDurable) {
|
|
@@ -796,7 +841,11 @@ export const makeVirtualObjectManager = (
|
|
|
796
841
|
|
|
797
842
|
const oldStateShapeSlots = oldShapeCD ? oldShapeCD.slots : [];
|
|
798
843
|
if (oldShapeCD && !allowStateShapeChanges) {
|
|
799
|
-
|
|
844
|
+
insistCompatibleShapeCapData(oldShapeCD, newShapeCD, {
|
|
845
|
+
newShape: /** @type {Record<string, Pattern>} */ (stateShape),
|
|
846
|
+
serialize,
|
|
847
|
+
unserialize,
|
|
848
|
+
});
|
|
800
849
|
}
|
|
801
850
|
const newStateShapeSlots = newShapeCD.slots;
|
|
802
851
|
vrm.updateReferenceCounts(oldStateShapeSlots, newStateShapeSlots);
|
|
@@ -850,9 +899,13 @@ export const makeVirtualObjectManager = (
|
|
|
850
899
|
return harden({
|
|
851
900
|
get() {
|
|
852
901
|
const baseRef = getBaseRef(this);
|
|
853
|
-
const
|
|
902
|
+
const record = dataCache.get(baseRef);
|
|
903
|
+
assert(record !== undefined);
|
|
904
|
+
const { capdatas, valueMap } = record;
|
|
854
905
|
if (!valueMap.has(prop)) {
|
|
855
|
-
const value =
|
|
906
|
+
const value = hasOwn(capdatas, prop)
|
|
907
|
+
? harden(unserialize(capdatas[prop]))
|
|
908
|
+
: undefined;
|
|
856
909
|
checkStatePropertyValue(value, prop);
|
|
857
910
|
valueMap.set(prop, value);
|
|
858
911
|
}
|
|
@@ -867,12 +920,20 @@ export const makeVirtualObjectManager = (
|
|
|
867
920
|
insistDurableCapdata(vrm, prop, capdata, true);
|
|
868
921
|
}
|
|
869
922
|
const record = dataCache.get(baseRef); // mutable
|
|
870
|
-
|
|
923
|
+
assert(record !== undefined);
|
|
924
|
+
const { capdatas, valueMap } = record;
|
|
925
|
+
const oldSlots = hasOwn(capdatas, prop) ? capdatas[prop].slots : [];
|
|
871
926
|
const newSlots = capdata.slots;
|
|
872
927
|
vrm.updateReferenceCounts(oldSlots, newSlots);
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
928
|
+
// modify in place, but mark as dirty
|
|
929
|
+
defineProperty(capdatas, prop, {
|
|
930
|
+
value: capdata,
|
|
931
|
+
writable: true,
|
|
932
|
+
enumerable: true,
|
|
933
|
+
configurable: false,
|
|
934
|
+
});
|
|
935
|
+
valueMap.set(prop, value);
|
|
936
|
+
dataCache.set(baseRef, record);
|
|
876
937
|
},
|
|
877
938
|
enumerable: true,
|
|
878
939
|
configurable: false,
|
|
@@ -890,7 +951,9 @@ export const makeVirtualObjectManager = (
|
|
|
890
951
|
const makeState = baseRef => {
|
|
891
952
|
const state = { __proto__: statePrototype };
|
|
892
953
|
if (stateShape === undefined) {
|
|
893
|
-
|
|
954
|
+
const record = dataCache.get(baseRef);
|
|
955
|
+
assert(record !== undefined);
|
|
956
|
+
for (const prop of ownKeys(record.capdatas)) {
|
|
894
957
|
assert(typeof prop === 'string');
|
|
895
958
|
checkStateProperty(prop);
|
|
896
959
|
defineProperty(state, prop, makeFieldDescriptor(prop));
|
|
@@ -940,18 +1003,57 @@ export const makeVirtualObjectManager = (
|
|
|
940
1003
|
// and into method-invocation time (which is not).
|
|
941
1004
|
|
|
942
1005
|
let proto;
|
|
1006
|
+
/** @type {ClassContextProvider | undefined} */
|
|
1007
|
+
let contextProviderVar;
|
|
1008
|
+
/** @type { Record<string, KitContextProvider> | undefined } */
|
|
1009
|
+
let contextProviderKitVar;
|
|
1010
|
+
|
|
943
1011
|
if (multifaceted) {
|
|
1012
|
+
contextProviderKitVar = fromEntries(
|
|
1013
|
+
facetNames.map((name, index) => [
|
|
1014
|
+
name,
|
|
1015
|
+
rep => {
|
|
1016
|
+
const vref = getSlotForVal(rep);
|
|
1017
|
+
if (vref === undefined) {
|
|
1018
|
+
return undefined;
|
|
1019
|
+
}
|
|
1020
|
+
const { baseRef, facet } = parseVatSlot(vref);
|
|
1021
|
+
|
|
1022
|
+
// Without this check, an attacker (with access to both
|
|
1023
|
+
// cohort1.facetA and cohort2.facetB)
|
|
1024
|
+
// could effectively forge access to
|
|
1025
|
+
// cohort1.facetB and cohort2.facetA.
|
|
1026
|
+
// They could not forge the identity of those two
|
|
1027
|
+
// objects, but they could invoke all their equivalent methods,
|
|
1028
|
+
// by using e.g.
|
|
1029
|
+
// cohort1.facetA.foo.apply(cohort2.facetB, [...args])
|
|
1030
|
+
if (Number(facet) !== index) {
|
|
1031
|
+
return undefined;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
return harden(contextCache.get(baseRef));
|
|
1035
|
+
},
|
|
1036
|
+
]),
|
|
1037
|
+
);
|
|
1038
|
+
|
|
944
1039
|
proto = defendPrototypeKit(
|
|
945
1040
|
tag,
|
|
946
|
-
|
|
1041
|
+
harden(contextProviderKitVar),
|
|
947
1042
|
behavior,
|
|
948
1043
|
thisfulMethods,
|
|
949
|
-
|
|
1044
|
+
interfaceGuardKit,
|
|
950
1045
|
);
|
|
951
1046
|
} else {
|
|
1047
|
+
contextProviderVar = rep => {
|
|
1048
|
+
const slot = getSlotForVal(rep);
|
|
1049
|
+
if (slot === undefined) {
|
|
1050
|
+
return undefined;
|
|
1051
|
+
}
|
|
1052
|
+
return harden(contextCache.get(slot));
|
|
1053
|
+
};
|
|
952
1054
|
proto = defendPrototype(
|
|
953
1055
|
tag,
|
|
954
|
-
|
|
1056
|
+
harden(contextProviderVar),
|
|
955
1057
|
behavior,
|
|
956
1058
|
thisfulMethods,
|
|
957
1059
|
interfaceGuard,
|
|
@@ -959,6 +1061,10 @@ export const makeVirtualObjectManager = (
|
|
|
959
1061
|
}
|
|
960
1062
|
harden(proto);
|
|
961
1063
|
|
|
1064
|
+
// All this to let typescript know that it won't vary during a closure
|
|
1065
|
+
const contextProvider = contextProviderVar;
|
|
1066
|
+
const contextProviderKit = contextProviderKitVar;
|
|
1067
|
+
|
|
962
1068
|
// this builds new Representatives, both when creating a new instance and
|
|
963
1069
|
// for reanimating an existing one when the old rep gets GCed
|
|
964
1070
|
|
|
@@ -973,10 +1079,11 @@ export const makeVirtualObjectManager = (
|
|
|
973
1079
|
const deleteStoredVO = baseRef => {
|
|
974
1080
|
let doMoreGC = false;
|
|
975
1081
|
const record = dataCache.get(baseRef);
|
|
1082
|
+
assert(record !== undefined);
|
|
976
1083
|
for (const valueCD of Object.values(record.capdatas)) {
|
|
977
|
-
valueCD.slots
|
|
1084
|
+
for (const vref of valueCD.slots) {
|
|
978
1085
|
doMoreGC = vrm.removeReachableVref(vref) || doMoreGC;
|
|
979
|
-
}
|
|
1086
|
+
}
|
|
980
1087
|
}
|
|
981
1088
|
dataCache.delete(baseRef);
|
|
982
1089
|
return doMoreGC;
|
|
@@ -1015,8 +1122,14 @@ export const makeVirtualObjectManager = (
|
|
|
1015
1122
|
if (isDurable) {
|
|
1016
1123
|
insistDurableCapdata(vrm, prop, valueCD, true);
|
|
1017
1124
|
}
|
|
1125
|
+
// eslint-disable-next-line github/array-foreach
|
|
1018
1126
|
valueCD.slots.forEach(vrm.addReachableVref);
|
|
1019
|
-
capdatas
|
|
1127
|
+
defineProperty(capdatas, prop, {
|
|
1128
|
+
value: valueCD,
|
|
1129
|
+
writable: true,
|
|
1130
|
+
enumerable: true,
|
|
1131
|
+
configurable: false,
|
|
1132
|
+
});
|
|
1020
1133
|
valueMap.set(prop, value);
|
|
1021
1134
|
}
|
|
1022
1135
|
// dataCache contents remain mutable: state setter modifies in-place
|
|
@@ -1030,10 +1143,63 @@ export const makeVirtualObjectManager = (
|
|
|
1030
1143
|
val = makeRepresentative(proto, baseRef);
|
|
1031
1144
|
}
|
|
1032
1145
|
registerValue(baseRef, val, multifaceted);
|
|
1033
|
-
finish
|
|
1146
|
+
finish && finish(contextCache.get(baseRef));
|
|
1034
1147
|
return val;
|
|
1035
1148
|
};
|
|
1036
1149
|
|
|
1150
|
+
if (receiveAmplifier) {
|
|
1151
|
+
assert(contextProviderKit);
|
|
1152
|
+
|
|
1153
|
+
// Amplify a facet to a cohort
|
|
1154
|
+
const amplify = exoFacet => {
|
|
1155
|
+
for (const cp of values(contextProviderKit)) {
|
|
1156
|
+
const context = cp(exoFacet);
|
|
1157
|
+
if (context !== undefined) {
|
|
1158
|
+
return context.facets;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
throw Fail`Must be a facet of ${q(tag)}: ${exoFacet}`;
|
|
1162
|
+
};
|
|
1163
|
+
harden(amplify);
|
|
1164
|
+
receiveAmplifier(amplify);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
if (receiveInstanceTester) {
|
|
1168
|
+
if (multifaceted) {
|
|
1169
|
+
assert(contextProviderKit);
|
|
1170
|
+
|
|
1171
|
+
const isInstance = (exoFacet, facetName = undefined) => {
|
|
1172
|
+
if (facetName === undefined) {
|
|
1173
|
+
// Is exoFacet and instance of any facet of this class kit?
|
|
1174
|
+
return values(contextProviderKit).some(
|
|
1175
|
+
cp => cp(exoFacet) !== undefined,
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
// Is this exoFacet an instance of this specific facet column
|
|
1179
|
+
// of this class kit?
|
|
1180
|
+
assert.typeof(facetName, 'string');
|
|
1181
|
+
const cp = contextProviderKit[facetName];
|
|
1182
|
+
cp !== undefined ||
|
|
1183
|
+
Fail`exo class kit ${q(tag)} has no facet named ${q(facetName)}`;
|
|
1184
|
+
return cp(exoFacet) !== undefined;
|
|
1185
|
+
};
|
|
1186
|
+
harden(isInstance);
|
|
1187
|
+
receiveInstanceTester(isInstance);
|
|
1188
|
+
} else {
|
|
1189
|
+
assert(contextProvider);
|
|
1190
|
+
// Is this exo an instance of this class?
|
|
1191
|
+
const isInstance = (exo, facetName = undefined) => {
|
|
1192
|
+
facetName === undefined ||
|
|
1193
|
+
Fail`facetName can only be used with an exo class kit: ${q(
|
|
1194
|
+
tag,
|
|
1195
|
+
)} has no facet ${q(facetName)}`;
|
|
1196
|
+
return contextProvider(exo) !== undefined;
|
|
1197
|
+
};
|
|
1198
|
+
harden(isInstance);
|
|
1199
|
+
receiveInstanceTester(isInstance);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1037
1203
|
return makeNewInstance;
|
|
1038
1204
|
};
|
|
1039
1205
|
|
|
@@ -1082,6 +1248,7 @@ export const makeVirtualObjectManager = (
|
|
|
1082
1248
|
return id;
|
|
1083
1249
|
};
|
|
1084
1250
|
|
|
1251
|
+
/** @type {import('./vatDataTypes').VatData['defineKind']} */
|
|
1085
1252
|
const defineKind = (tag, init, behavior, options) => {
|
|
1086
1253
|
const kindID = `${allocateExportID()}`;
|
|
1087
1254
|
saveVirtualKindDescriptor(kindID, { kindID, tag });
|
|
@@ -1097,6 +1264,7 @@ export const makeVirtualObjectManager = (
|
|
|
1097
1264
|
);
|
|
1098
1265
|
};
|
|
1099
1266
|
|
|
1267
|
+
/** @type {import('./vatDataTypes').VatData['defineKindMulti']} */
|
|
1100
1268
|
const defineKindMulti = (tag, init, behavior, options) => {
|
|
1101
1269
|
const kindID = `${allocateExportID()}`;
|
|
1102
1270
|
saveVirtualKindDescriptor(kindID, { kindID, tag });
|
|
@@ -1115,7 +1283,7 @@ export const makeVirtualObjectManager = (
|
|
|
1115
1283
|
/**
|
|
1116
1284
|
*
|
|
1117
1285
|
* @param {string} tag
|
|
1118
|
-
* @returns {
|
|
1286
|
+
* @returns {DurableKindHandle}
|
|
1119
1287
|
*/
|
|
1120
1288
|
const makeKindHandle = tag => {
|
|
1121
1289
|
assert(kindIDID, 'initializeKindHandleKind not called yet');
|
|
@@ -1126,9 +1294,9 @@ export const makeVirtualObjectManager = (
|
|
|
1126
1294
|
nextInstanceIDs.set(kindID, nextInstanceID);
|
|
1127
1295
|
saveDurableKindDescriptor(durableKindDescriptor);
|
|
1128
1296
|
saveNextInstanceID(kindID);
|
|
1129
|
-
/** @type {
|
|
1130
|
-
|
|
1131
|
-
// @ts-
|
|
1297
|
+
/** @type {DurableKindHandle} */
|
|
1298
|
+
|
|
1299
|
+
// @ts-expect-error cast
|
|
1132
1300
|
const kindHandle = Far('kind', {});
|
|
1133
1301
|
kindHandleToID.set(kindHandle, kindID);
|
|
1134
1302
|
const kindIDvref = makeBaseRef(kindIDID, kindID, true);
|
|
@@ -1136,6 +1304,7 @@ export const makeVirtualObjectManager = (
|
|
|
1136
1304
|
return kindHandle;
|
|
1137
1305
|
};
|
|
1138
1306
|
|
|
1307
|
+
/** @type {import('./vatDataTypes').VatData['defineDurableKind']} */
|
|
1139
1308
|
const defineDurableKind = (kindHandle, init, behavior, options) => {
|
|
1140
1309
|
kindHandleToID.has(kindHandle) || Fail`unknown handle ${kindHandle}`;
|
|
1141
1310
|
const kindID = kindHandleToID.get(kindHandle);
|
|
@@ -1158,6 +1327,7 @@ export const makeVirtualObjectManager = (
|
|
|
1158
1327
|
return maker;
|
|
1159
1328
|
};
|
|
1160
1329
|
|
|
1330
|
+
/** @type {import('./vatDataTypes').VatData['defineDurableKindMulti']} */
|
|
1161
1331
|
const defineDurableKindMulti = (kindHandle, init, behavior, options) => {
|
|
1162
1332
|
kindHandleToID.has(kindHandle) || Fail`unknown handle ${kindHandle}`;
|
|
1163
1333
|
const kindID = kindHandleToID.get(kindHandle);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {*} syscall Vat's syscall object, used to access the vatstore operations.
|
|
3
|
+
* @param {(val: object) => string | undefined} getSlotForVal A function that returns the
|
|
4
|
+
* object ID (vref) for a given object, if any. their corresponding export
|
|
5
|
+
* IDs
|
|
6
|
+
* @param {(slot: string) => object} requiredValForSlot A function that
|
|
7
|
+
* converts an object ID (vref) to an object.
|
|
8
|
+
* @param {*} FinalizationRegistry Powerful JavaScript intrinsic normally denied
|
|
9
|
+
* by SES
|
|
10
|
+
* @param {*} WeakRef Powerful JavaScript intrinsic normally denied
|
|
11
|
+
* by SES
|
|
12
|
+
* @param {*} addToPossiblyDeadSet Function to record objects whose deaths
|
|
13
|
+
* should be reinvestigated
|
|
14
|
+
* @param {*} addToPossiblyRetiredSet Function to record dead objects whose
|
|
15
|
+
* retirement should be reinvestigated
|
|
16
|
+
* @param {boolean} relaxDurabilityRules True IFF the associated swingset is
|
|
17
|
+
* running with relaxed durability rules
|
|
18
|
+
*/
|
|
19
|
+
export function makeVirtualReferenceManager(syscall: any, getSlotForVal: (val: object) => string | undefined, requiredValForSlot: (slot: string) => object, FinalizationRegistry: any, WeakRef: any, addToPossiblyDeadSet: any, addToPossiblyRetiredSet: any, relaxDurabilityRules: boolean): {
|
|
20
|
+
registerDroppedCollection: (target: any, descriptor: any) => void;
|
|
21
|
+
isDurable: (vref: string) => boolean;
|
|
22
|
+
isDurableKind: (kindID: string) => boolean;
|
|
23
|
+
registerKind: (kindID: string, reanimator?: (string: any, boolean: any) => object, deleter?: (string: any) => boolean, durable?: boolean) => void;
|
|
24
|
+
rememberFacetNames: (kindID: string, facetNames: string[] | null) => void;
|
|
25
|
+
getFacet: (kindID: any, facets: any, facetIndex: any) => any;
|
|
26
|
+
getFacetNames: (kindID: any) => any;
|
|
27
|
+
reanimate: (baseRef: string) => any;
|
|
28
|
+
addReachableVref: (vref: any) => void;
|
|
29
|
+
removeReachableVref: (vref: any) => boolean;
|
|
30
|
+
updateReferenceCounts: (beforeSlots: any, afterSlots: any) => void;
|
|
31
|
+
getReachablePromiseRefCount: (p: any) => number;
|
|
32
|
+
addRecognizableValue: (value: any, recognizer: string | (Map<string, any> | Set<string>), recognizerIsVirtual?: boolean) => void;
|
|
33
|
+
removeRecognizableVref: (vref: string, recognizer: string | (Map<string, any> | Set<string>), recognizerIsVirtual?: boolean) => void;
|
|
34
|
+
removeRecognizableValue: (value: any, recognizer: string | (Map<string, any> | Set<string>), recognizerIsVirtual?: boolean) => void;
|
|
35
|
+
vrefKey: (value: any) => string | undefined;
|
|
36
|
+
isPresenceReachable: (vref: string) => boolean;
|
|
37
|
+
isVrefRecognizable: (vref: any) => boolean;
|
|
38
|
+
setExportStatus: (vref: any, exportStatus: any) => void;
|
|
39
|
+
isVirtualObjectReachable: (baseRef: string) => boolean;
|
|
40
|
+
deleteVirtualObject: (baseRef: string) => [boolean, string[]];
|
|
41
|
+
ceaseRecognition: (vref: string) => boolean;
|
|
42
|
+
setDeleteCollectionEntry: (fn: any) => void;
|
|
43
|
+
getRetentionStats: () => {
|
|
44
|
+
remotableRefCounts: number;
|
|
45
|
+
vrefRecognizers: number;
|
|
46
|
+
kindInfoTable: number;
|
|
47
|
+
};
|
|
48
|
+
initializeIDCounters: () => void;
|
|
49
|
+
allocateNextID: (name: any) => number;
|
|
50
|
+
flushIDCounters: () => void;
|
|
51
|
+
testHooks: {
|
|
52
|
+
getReachableRefCount: (vref: any) => number | undefined;
|
|
53
|
+
countCollectionsForWeakKey: (vref: any) => number;
|
|
54
|
+
getDroppedCollectionRegistry: () => any;
|
|
55
|
+
remotableRefCounts: Map<any, number>;
|
|
56
|
+
vrefRecognizers: Map<string, Set<Map<string, any> | Set<string>>>;
|
|
57
|
+
kindInfoTable: Map<any, any>;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
export type VirtualReferenceManager = ReturnType<typeof makeVirtualReferenceManager>;
|
|
61
|
+
//# sourceMappingURL=virtualReferences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtualReferences.d.ts","sourceRoot":"","sources":["virtualReferences.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;GAiBG;AACH,qDAjBW,GAAC,iBACD,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,sBAGnC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,wBAExB,GAAC,WAED,GAAC,wBAED,GAAC,2BAED,GAAC,wBAED,OAAO;;sBAqQL,MAAM,KAEJ,OAAO;4BAfT,MAAM,KAEJ,OAAO;2BA9CT,MAAM,eACN,CAAC,MAAM,KAAA,EAAE,OAAO,KAAA,KAAK,MAAM,YAC3B,CAAC,MAAM,KAAA,KAAK,OAAO,YACnB,OAAO;iCASP,MAAM,cACN,MAAM,EAAE,GAAC,IAAI;;;yBA8Eb,MAAM;;;;;kCAmPN,GAAC,cACD,MAAM,mCAAW,wBACjB,OAAO;mCA2BP,MAAM,cACN,MAAM,mCAAW,wBACjB,OAAO;qCAgCP,GAAC,cACD,MAAM,mCAAW,wBACjB,OAAO;;gCAvIP,MAAM,KAEJ,OAAO;;;wCAzaT,MAAM,KAEJ,OAAO;mCAoBT,MAAM,KAEJ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;6BAwiBrB,MAAM,KAEJ,OAAO;;;;;;;;;;;;;;;;;;EA+LrB;sCACa,UAAU,CAAC,OAAO,2BAA2B,CAAC"}
|