@agoric/swingset-liveslots 0.10.3-dev-5dc325b.0 → 0.10.3-getting-started-dev-d127d1d.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/package.json +17 -23
  3. package/src/collectionManager.js +66 -135
  4. package/src/index.js +1 -2
  5. package/src/liveslots.js +74 -47
  6. package/src/virtualObjectManager.js +15 -61
  7. package/src/virtualReferences.js +0 -51
  8. package/src/watchedPromises.js +0 -6
  9. package/test/gc-helpers.js +1 -1
  10. package/test/kmarshal.js +79 -0
  11. package/test/liveslots-helpers.js +6 -6
  12. package/test/mock-gc.js +0 -1
  13. package/test/storeGC/test-lifecycle.js +2 -2
  14. package/test/storeGC/test-refcount-management.js +2 -1
  15. package/test/storeGC/test-scalar-store-kind.js +1 -0
  16. package/test/storeGC/test-weak-key.js +2 -1
  17. package/test/test-baggage.js +2 -1
  18. package/test/test-cache.js +1 -0
  19. package/test/test-collection-schema-refcount.js +2 -1
  20. package/test/test-collection-upgrade.js +3 -1
  21. package/test/test-collections.js +14 -117
  22. package/test/test-dropped-collection-weakrefs.js +2 -1
  23. package/test/test-durabilityChecks.js +3 -3
  24. package/test/test-facetiousness.js +2 -1
  25. package/test/test-gc-sensitivity.js +2 -2
  26. package/test/test-handled-promises.js +7 -5
  27. package/test/test-initial-vrefs.js +3 -2
  28. package/test/test-liveslots-mock-gc.js +2 -2
  29. package/test/test-liveslots-real-gc.js +2 -2
  30. package/test/test-liveslots.js +14 -13
  31. package/test/test-vo-test-harness.js +1 -0
  32. package/test/test-vpid-liveslots.js +4 -3
  33. package/test/util.js +2 -2
  34. package/test/vat-util.js +1 -1
  35. package/test/virtual-objects/test-cease-recognition.js +2 -2
  36. package/test/virtual-objects/test-cross-facet.js +2 -1
  37. package/test/virtual-objects/test-empty-data.js +2 -1
  38. package/test/virtual-objects/test-facets.js +2 -1
  39. package/test/virtual-objects/test-kind-changes.js +2 -2
  40. package/test/virtual-objects/test-reachable-vrefs.js +2 -2
  41. package/test/virtual-objects/test-rep-tostring.js +3 -2
  42. package/test/virtual-objects/test-retain-remotable.js +1 -1
  43. package/test/virtual-objects/test-state-shape.js +2 -2
  44. package/test/virtual-objects/test-virtualObjectGC.js +2 -2
  45. package/test/virtual-objects/test-virtualObjectManager.js +2 -6
  46. package/test/virtual-objects/test-vo-real-gc.js +2 -2
  47. package/test/virtual-objects/test-weakcollections-vref-handling.js +2 -1
  48. package/tools/fakeVirtualSupport.js +19 -37
  49. package/src/vatDataTypes.d.ts +0 -234
  50. package/src/vatDataTypes.js +0 -2
  51. package/tools/prepare-test-env.js +0 -13
  52. package/tools/setup-vat-data.js +0 -61
package/src/liveslots.js CHANGED
@@ -1,4 +1,3 @@
1
- /* eslint @typescript-eslint/no-floating-promises: "warn" */
2
1
  import {
3
2
  Remotable,
4
3
  passStyleOf,
@@ -252,10 +251,13 @@ function build(
252
251
  const importsToRetire = new Set();
253
252
  const exportsToRetire = new Set();
254
253
  let doMore;
255
- await null;
256
254
  do {
257
255
  doMore = false;
258
256
 
257
+ // Yes, we know this is an await inside a loop. Too bad. (Also, it's a
258
+ // `do {} while` loop, which means there's no conditional bypass of the
259
+ // await.)
260
+ // eslint-disable-next-line no-await-in-loop, @jessie.js/no-nested-await
259
261
  await gcTools.gcAndFinalize();
260
262
 
261
263
  // possiblyDeadSet contains a baseref for everything (Presences,
@@ -498,6 +500,54 @@ function build(
498
500
  return Remotable(iface);
499
501
  }
500
502
 
503
+ /**
504
+ * Counters to track the next number for various categories of allocation.
505
+ * `exportID` starts at 1 because 'o+0' is always automatically
506
+ * pre-assigned to the root object.
507
+ * `promiseID` starts at 5 as a very minor aid to debugging: when puzzling
508
+ * over trace logs and the like, it helps for the numbers in various species
509
+ * of IDs that are jumbled together to be a little out of sync and thus a
510
+ * little less similar to each other.
511
+ */
512
+ const initialIDCounters = { exportID: 1, collectionID: 1, promiseID: 5 };
513
+ /** @type {Record<string, number>} */
514
+ let idCounters;
515
+ let idCountersAreDirty = false;
516
+
517
+ function initializeIDCounters() {
518
+ if (!idCounters) {
519
+ // the saved value might be missing, or from an older liveslots
520
+ // (with fewer counters), so merge it with our initial values
521
+ const saved = JSON.parse(syscall.vatstoreGet('idCounters') || '{}');
522
+ idCounters = { ...initialIDCounters, ...saved };
523
+ idCountersAreDirty = true;
524
+ }
525
+ }
526
+
527
+ function allocateNextID(name) {
528
+ if (!idCounters) {
529
+ // Normally `initializeIDCounters` would be called from startVat, but some
530
+ // tests bypass that so this is a backstop. Note that the invocation from
531
+ // startVat is there to make vatStore access patterns a bit more
532
+ // consistent from one vat to another, principally as a confusion
533
+ // reduction measure in service of debugging; it is not a correctness
534
+ // issue.
535
+ initializeIDCounters();
536
+ }
537
+ const result = idCounters[name];
538
+ result !== undefined || Fail`unknown idCounters[${name}]`;
539
+ idCounters[name] += 1;
540
+ idCountersAreDirty = true;
541
+ return result;
542
+ }
543
+
544
+ function flushIDCounters() {
545
+ if (idCountersAreDirty) {
546
+ syscall.vatstoreSet('idCounters', JSON.stringify(idCounters));
547
+ idCountersAreDirty = false;
548
+ }
549
+ }
550
+
501
551
  // TODO: fix awkward non-orthogonality: allocateExportID() returns a number,
502
552
  // allocatePromiseID() returns a slot, registerPromise() uses the slot from
503
553
  // allocatePromiseID(), exportPassByPresence() generates a slot itself using
@@ -506,18 +556,15 @@ function build(
506
556
  // use a slot from the corresponding allocateX
507
557
 
508
558
  function allocateExportID() {
509
- // eslint-disable-next-line no-use-before-define
510
- return vrm.allocateNextID('exportID');
559
+ return allocateNextID('exportID');
511
560
  }
512
561
 
513
562
  function allocateCollectionID() {
514
- // eslint-disable-next-line no-use-before-define
515
- return vrm.allocateNextID('collectionID');
563
+ return allocateNextID('collectionID');
516
564
  }
517
565
 
518
566
  function allocatePromiseID() {
519
- // eslint-disable-next-line no-use-before-define
520
- const promiseID = vrm.allocateNextID('promiseID');
567
+ const promiseID = allocateNextID('promiseID');
521
568
  return makeVatSlot('promise', true, promiseID);
522
569
  }
523
570
 
@@ -712,9 +759,9 @@ function build(
712
759
  Fail`registerValue(${baseRef} should not receive individual facets`;
713
760
  slotToVal.set(baseRef, new WeakRef(val));
714
761
  if (valIsCohort) {
715
- for (const [index, name] of vrm.getFacetNames(id).entries()) {
762
+ vrm.getFacetNames(id).forEach((name, index) => {
716
763
  valToSlot.set(val[name], `${baseRef}:${index}`);
717
- }
764
+ });
718
765
  } else {
719
766
  valToSlot.set(val, baseRef);
720
767
  }
@@ -936,20 +983,12 @@ function build(
936
983
  return null;
937
984
  }
938
985
  syscall.resolve(resolutions);
939
- for (const resolution of resolutions) {
940
- const [_xvpid, _isReject, resolutionCD] = resolution;
941
- for (const vref of resolutionCD.slots) {
942
- maybeNewVPIDs.add(vref);
943
- }
944
- }
945
- for (const resolution of resolutions) {
946
- const [xvpid] = resolution;
947
- maybeNewVPIDs.delete(xvpid);
948
- }
949
- }
950
- for (const newVPID of Array.from(maybeNewVPIDs).sort()) {
951
- maybeExportPromise(newVPID);
986
+ resolutions.forEach(([_xvpid, _isReject, resolutionCD]) => {
987
+ resolutionCD.slots.forEach(vref => maybeNewVPIDs.add(vref));
988
+ });
989
+ resolutions.forEach(([xvpid]) => maybeNewVPIDs.delete(xvpid));
952
990
  }
991
+ Array.from(maybeNewVPIDs).sort().forEach(maybeExportPromise);
953
992
 
954
993
  // ideally we'd wait until .then is called on p before subscribing, but
955
994
  // the current Promise API doesn't give us a way to discover this, so we
@@ -1151,21 +1190,13 @@ function build(
1151
1190
 
1152
1191
  const maybeNewVPIDs = new Set();
1153
1192
  // if we mention a vpid, we might need to track it
1154
- for (const resolution of resolutions) {
1155
- const [_xvpid, _isReject, resolutionCD] = resolution;
1156
- for (const vref of resolutionCD.slots) {
1157
- maybeNewVPIDs.add(vref);
1158
- }
1159
- }
1193
+ resolutions.forEach(([_xvpid, _isReject, resolutionCD]) => {
1194
+ resolutionCD.slots.forEach(vref => maybeNewVPIDs.add(vref));
1195
+ });
1160
1196
  // but not if we just resolved it (including the primary)
1161
- for (const resolution of resolutions) {
1162
- const [xvpid] = resolution;
1163
- maybeNewVPIDs.delete(xvpid);
1164
- }
1197
+ resolutions.forEach(([xvpid]) => maybeNewVPIDs.delete(xvpid));
1165
1198
  // track everything that's left
1166
- for (const newVPID of Array.from(maybeNewVPIDs).sort()) {
1167
- maybeExportPromise(newVPID);
1168
- }
1199
+ Array.from(maybeNewVPIDs).sort().forEach(maybeExportPromise);
1169
1200
 
1170
1201
  // only the primary can possibly be newly resolved
1171
1202
  unregisterUnreferencedVPID(vpid);
@@ -1223,11 +1254,11 @@ function build(
1223
1254
  // 'imports' is an exclusively-owned Set that holds all new
1224
1255
  // promise vpids, both resolved and unresolved
1225
1256
  const imports = finishCollectingPromiseImports();
1226
- for (const vpid of retiredVPIDs) {
1257
+ retiredVPIDs.forEach(vpid => {
1227
1258
  unregisterUnreferencedVPID(vpid); // unregisters if not in vdata
1228
1259
  importedVPIDs.delete(vpid);
1229
1260
  imports.delete(vpid); // resolved, so don't subscribe()
1230
- }
1261
+ });
1231
1262
  for (const vpid of Array.from(imports).sort()) {
1232
1263
  syscall.subscribe(vpid);
1233
1264
  }
@@ -1267,18 +1298,14 @@ function build(
1267
1298
 
1268
1299
  function retireExports(vrefs) {
1269
1300
  assert(Array.isArray(vrefs));
1270
- for (const vref of vrefs) {
1271
- retireOneExport(vref);
1272
- }
1301
+ vrefs.forEach(retireOneExport);
1273
1302
  }
1274
1303
 
1275
1304
  function retireImports(vrefs) {
1276
1305
  assert(Array.isArray(vrefs));
1277
1306
  vrefs.map(vref => insistVatType('object', vref));
1278
1307
  vrefs.map(vref => assert(!parseVatSlot(vref).allocatedByVat));
1279
- for (const vref of vrefs) {
1280
- vrm.ceaseRecognition(vref);
1281
- }
1308
+ vrefs.forEach(vrm.ceaseRecognition);
1282
1309
  }
1283
1310
 
1284
1311
  // TODO: when we add notifyForward, guard against cycles
@@ -1423,7 +1450,7 @@ function build(
1423
1450
  }
1424
1451
  harden(vpow);
1425
1452
 
1426
- vrm.initializeIDCounters();
1453
+ initializeIDCounters();
1427
1454
  vom.initializeKindHandleKind();
1428
1455
  collectionManager.initializeStoreKindInfo();
1429
1456
 
@@ -1546,7 +1573,7 @@ function build(
1546
1573
  * dispatch has completed and user code has relinquished agency.
1547
1574
  */
1548
1575
  function afterDispatchActions() {
1549
- vrm.flushIDCounters();
1576
+ flushIDCounters();
1550
1577
  collectionManager.flushSchemaCache();
1551
1578
  vom.flushStateCache();
1552
1579
  }
@@ -1602,7 +1629,7 @@ function build(
1602
1629
  // *not* directly wait for the userspace function to complete, nor for
1603
1630
  // any promise it returns to fire.
1604
1631
  const p = Promise.resolve(delivery).then(unmeteredDispatch);
1605
- void p.finally(() => (complete = true));
1632
+ p.finally(() => (complete = true));
1606
1633
 
1607
1634
  // Instead, we wait for userspace to become idle by draining the
1608
1635
  // promise queue. We clean up and then examine/return 'p' so any
@@ -16,19 +16,10 @@ import {
16
16
 
17
17
  /** @template T @typedef {import('@agoric/vat-data').DefineKindOptions<T>} DefineKindOptions */
18
18
 
19
- const { hasOwn, defineProperty, getOwnPropertyNames, entries } = Object;
19
+ const { hasOwn, defineProperty, getOwnPropertyNames } = Object;
20
20
  const { ownKeys } = Reflect;
21
21
  const { quote: q } = assert;
22
22
 
23
- // See https://github.com/Agoric/agoric-sdk/issues/8005
24
- // Once agoric-sdk is upgraded to depend on endo post
25
- // https://github.com/endojs/endo/pull/1606 then remove this
26
- // definition of `b` and say instead
27
- // ```js
28
- // const { quote: q, base: b } = assert;
29
- // ```
30
- const b = index => q(Number(index));
31
-
32
23
  // import { kdebug } from './kdebug.js';
33
24
 
34
25
  // TODO Use environment-options.js currently in ses/src after factoring it out
@@ -150,8 +141,9 @@ const makeContextCache = (makeState, makeContext) => {
150
141
  * @param {*} getSlotForVal
151
142
  * @returns {ContextProvider}
152
143
  */
153
- const makeContextProvider = (contextCache, getSlotForVal) =>
154
- harden(rep => contextCache.get(getSlotForVal(rep)));
144
+ const makeContextProvider = (contextCache, getSlotForVal) => {
145
+ return harden(rep => contextCache.get(getSlotForVal(rep)));
146
+ };
155
147
 
156
148
  const makeContextProviderKit = (contextCache, getSlotForVal, facetNames) => {
157
149
  /** @type { Record<string, any> } */
@@ -268,15 +260,15 @@ const makeFacets = (
268
260
  };
269
261
 
270
262
  const insistDurableCapdata = (vrm, what, capdata, valueFor) => {
271
- for (const [idx, vref] of entries(capdata.slots)) {
263
+ capdata.slots.forEach((vref, idx) => {
272
264
  if (!vrm.isDurable(vref)) {
273
265
  if (valueFor) {
274
- Fail`value for ${what} is not durable: slot ${b(idx)} of ${capdata}`;
266
+ Fail`value for ${what} is not durable: slot ${q(idx)} of ${capdata}`;
275
267
  } else {
276
- Fail`${what} is not durable: slot ${b(idx)} of ${capdata}`;
268
+ Fail`${what} is not durable: slot ${q(idx)} of ${capdata}`;
277
269
  }
278
270
  }
279
- }
271
+ });
280
272
  };
281
273
 
282
274
  const insistSameCapData = (oldCD, newCD) => {
@@ -289,11 +281,11 @@ const insistSameCapData = (oldCD, newCD) => {
289
281
  if (oldCD.slots.length !== newCD.slots.length) {
290
282
  Fail`durable Kind stateShape mismatch (slots.length)`;
291
283
  }
292
- for (const [idx, oldVref] of entries(oldCD.slots)) {
284
+ oldCD.slots.forEach((oldVref, idx) => {
293
285
  if (newCD.slots[idx] !== oldVref) {
294
286
  Fail`durable Kind stateShape mismatch (slot[${idx}])`;
295
287
  }
296
- }
288
+ });
297
289
  };
298
290
 
299
291
  /**
@@ -322,7 +314,7 @@ const insistSameCapData = (oldCD, newCD) => {
322
314
  * recursion if our returned WeakMap/WeakSet wrappers are subsequently installed
323
315
  * on globalThis.
324
316
  *
325
- * @returns a new virtual object manager.
317
+ * @returns {object} a new virtual object manager.
326
318
  *
327
319
  * The virtual object manager allows the creation of persistent objects that do
328
320
  * not need to occupy memory when they are not in use. It provides five
@@ -715,16 +707,10 @@ export const makeVirtualObjectManager = (
715
707
  durableKindDescriptor = undefined, // only for durables
716
708
  ) => {
717
709
  const {
718
- finish = undefined,
710
+ finish,
719
711
  stateShape = undefined,
720
712
  thisfulMethods = false,
721
- } = options;
722
- let {
723
- // These are "let" rather than "const" only to accommodate code
724
- // below that tolerates an old version of the vat-data package.
725
- // See there for more explanation.
726
713
  interfaceGuard = undefined,
727
- interfaceGuardKit = undefined,
728
714
  } = options;
729
715
 
730
716
  const statePrototype = {}; // Not frozen yet
@@ -745,38 +731,11 @@ export const makeVirtualObjectManager = (
745
731
  switch (assessFacetiousness(behavior)) {
746
732
  case 'one': {
747
733
  assert(!multifaceted);
748
- interfaceGuardKit === undefined ||
749
- Fail`Use an interfaceGuard, not interfaceGuardKit, to protect class ${q(
750
- tag,
751
- )}`;
752
734
  proposedFacetNames = undefined;
753
735
  break;
754
736
  }
755
737
  case 'many': {
756
738
  assert(multifaceted);
757
-
758
- if (interfaceGuard && interfaceGuardKit === undefined) {
759
- // This if clause is for the purpose of tolerating versions
760
- // of the vata-data package that precede
761
- // https://github.com/Agoric/agoric-sdk/pull/8220 .
762
- // Before that PR, the options name `interfaceGuard` would
763
- // actually carry the InterfaceGuardKit.
764
- //
765
- // Tolerating the old vat-data with the new types.
766
- // at-expect-error here causes inconsistent reports, so
767
- // doing the at-ts-ignore-error ritual instead.
768
- // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
769
- // @ts-ignore
770
- interfaceGuardKit = interfaceGuard;
771
- interfaceGuard = undefined;
772
- // The rest of the code from here makes no further compromise
773
- // for that old version of the vat-data package.
774
- }
775
-
776
- interfaceGuard === undefined ||
777
- Fail`Use an interfaceGuardKit, not an interfaceGuard, to protect class kit ${q(
778
- tag,
779
- )}`;
780
739
  proposedFacetNames = ownKeys(behavior).sort();
781
740
  break;
782
741
  }
@@ -987,7 +946,7 @@ export const makeVirtualObjectManager = (
987
946
  makeContextProviderKit(contextCache, getSlotForVal, facetNames),
988
947
  behavior,
989
948
  thisfulMethods,
990
- interfaceGuardKit,
949
+ interfaceGuard,
991
950
  );
992
951
  } else {
993
952
  proto = defendPrototype(
@@ -1015,9 +974,9 @@ export const makeVirtualObjectManager = (
1015
974
  let doMoreGC = false;
1016
975
  const record = dataCache.get(baseRef);
1017
976
  for (const valueCD of Object.values(record.capdatas)) {
1018
- for (const vref of valueCD.slots) {
977
+ valueCD.slots.forEach(vref => {
1019
978
  doMoreGC = vrm.removeReachableVref(vref) || doMoreGC;
1020
- }
979
+ });
1021
980
  }
1022
981
  dataCache.delete(baseRef);
1023
982
  return doMoreGC;
@@ -1056,7 +1015,6 @@ export const makeVirtualObjectManager = (
1056
1015
  if (isDurable) {
1057
1016
  insistDurableCapdata(vrm, prop, valueCD, true);
1058
1017
  }
1059
- // eslint-disable-next-line github/array-foreach
1060
1018
  valueCD.slots.forEach(vrm.addReachableVref);
1061
1019
  capdatas[prop] = valueCD;
1062
1020
  valueMap.set(prop, value);
@@ -1124,7 +1082,6 @@ export const makeVirtualObjectManager = (
1124
1082
  return id;
1125
1083
  };
1126
1084
 
1127
- /** @type {import('./vatDataTypes').VatData['defineKind']} */
1128
1085
  const defineKind = (tag, init, behavior, options) => {
1129
1086
  const kindID = `${allocateExportID()}`;
1130
1087
  saveVirtualKindDescriptor(kindID, { kindID, tag });
@@ -1140,7 +1097,6 @@ export const makeVirtualObjectManager = (
1140
1097
  );
1141
1098
  };
1142
1099
 
1143
- /** @type {import('./vatDataTypes').VatData['defineKindMulti']} */
1144
1100
  const defineKindMulti = (tag, init, behavior, options) => {
1145
1101
  const kindID = `${allocateExportID()}`;
1146
1102
  saveVirtualKindDescriptor(kindID, { kindID, tag });
@@ -1180,7 +1136,6 @@ export const makeVirtualObjectManager = (
1180
1136
  return kindHandle;
1181
1137
  };
1182
1138
 
1183
- /** @type {import('./vatDataTypes').VatData['defineDurableKind']} */
1184
1139
  const defineDurableKind = (kindHandle, init, behavior, options) => {
1185
1140
  kindHandleToID.has(kindHandle) || Fail`unknown handle ${kindHandle}`;
1186
1141
  const kindID = kindHandleToID.get(kindHandle);
@@ -1203,7 +1158,6 @@ export const makeVirtualObjectManager = (
1203
1158
  return maker;
1204
1159
  };
1205
1160
 
1206
- /** @type {import('./vatDataTypes').VatData['defineDurableKindMulti']} */
1207
1161
  const defineDurableKindMulti = (kindHandle, init, behavior, options) => {
1208
1162
  kindHandleToID.has(kindHandle) || Fail`unknown handle ${kindHandle}`;
1209
1163
  const kindID = kindHandleToID.get(kindHandle);
@@ -682,54 +682,6 @@ export function makeVirtualReferenceManager(
682
682
  return size;
683
683
  }
684
684
 
685
- /**
686
- * Counters to track the next number for various categories of allocation.
687
- * `exportID` starts at 1 because 'o+0' is always automatically
688
- * pre-assigned to the root object.
689
- * `promiseID` starts at 5 as a very minor aid to debugging: when puzzling
690
- * over trace logs and the like, it helps for the numbers in various species
691
- * of IDs that are jumbled together to be a little out of sync and thus a
692
- * little less similar to each other.
693
- */
694
- const initialIDCounters = { exportID: 1, collectionID: 1, promiseID: 5 };
695
- /** @type {Record<string, number>} */
696
- let idCounters;
697
- let idCountersAreDirty = false;
698
-
699
- function initializeIDCounters() {
700
- if (!idCounters) {
701
- // the saved value might be missing, or from an older liveslots
702
- // (with fewer counters), so merge it with our initial values
703
- const saved = JSON.parse(syscall.vatstoreGet('idCounters') || '{}');
704
- idCounters = { ...initialIDCounters, ...saved };
705
- idCountersAreDirty = true;
706
- }
707
- }
708
-
709
- function allocateNextID(name) {
710
- if (!idCounters) {
711
- // Normally `initializeIDCounters` would be called from startVat, but some
712
- // tests bypass that so this is a backstop. Note that the invocation from
713
- // startVat is there to make vatStore access patterns a bit more
714
- // consistent from one vat to another, principally as a confusion
715
- // reduction measure in service of debugging; it is not a correctness
716
- // issue.
717
- initializeIDCounters();
718
- }
719
- const result = idCounters[name];
720
- result !== undefined || Fail`unknown idCounters[${name}]`;
721
- idCounters[name] += 1;
722
- idCountersAreDirty = true;
723
- return result;
724
- }
725
-
726
- function flushIDCounters() {
727
- if (idCountersAreDirty) {
728
- syscall.vatstoreSet('idCounters', JSON.stringify(idCounters));
729
- idCountersAreDirty = false;
730
- }
731
- }
732
-
733
685
  const testHooks = {
734
686
  getReachableRefCount,
735
687
  countCollectionsForWeakKey,
@@ -774,9 +726,6 @@ export function makeVirtualReferenceManager(
774
726
  ceaseRecognition,
775
727
  setDeleteCollectionEntry,
776
728
  getRetentionStats,
777
- initializeIDCounters,
778
- allocateNextID,
779
- flushIDCounters,
780
729
  testHooks,
781
730
  });
782
731
  }
@@ -147,12 +147,6 @@ export function makeWatchedPromiseManager({
147
147
  }
148
148
  }
149
149
 
150
- /**
151
- *
152
- * @param {Promise} p
153
- * @param {{onFulfilled?: Function, onRejected?: Function}} watcher
154
- * @param {...any} args
155
- */
156
150
  function watchPromise(p, watcher, ...args) {
157
151
  // The following wrapping defers setting up the promise watcher itself to a
158
152
  // later turn so that if the promise to be watched was the return value from
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { Far } from '@endo/marshal';
4
4
  import { M } from '@agoric/store';
5
- import { kslot, kser } from '@agoric/kmarshal';
5
+ import { kslot, kser } from './kmarshal.js';
6
6
  import { parseVatSlot } from '../src/parseVatSlots.js';
7
7
 
8
8
  // These tests follow the model described in
@@ -0,0 +1,79 @@
1
+ import { Far, makeMarshal, passStyleOf } from '@endo/marshal';
2
+ import { assert } from '@agoric/assert';
3
+
4
+ // Simple wrapper for serializing and unserializing marshalled values inside the
5
+ // kernel, where we don't actually want to use clists nor actually allocate real
6
+ // objects, but instead to stay entirely within the domain of krefs. This is
7
+ // used to enable syntactic manipulation of serialized values while remaining
8
+ // agnostic about the internal details of the serialization encoding.
9
+
10
+ const refMap = new WeakMap();
11
+
12
+ export const kslot = (kref, iface) => {
13
+ assert.typeof(kref, 'string');
14
+ if (iface && iface.startsWith('Alleged: ')) {
15
+ // Encoder prepends "Alleged: " to iface string, but the decoder doesn't strip it
16
+ // Unclear whether it's the decoder or me who is wrong
17
+ iface = iface.slice(9);
18
+ }
19
+ if (
20
+ kref.startsWith('p') ||
21
+ kref.startsWith('kp') ||
22
+ kref.startsWith('lp') ||
23
+ kref.startsWith('rp')
24
+ ) {
25
+ // TODO: temporary hack because smallcaps encodes promise references
26
+ // differently from remotable object references, and the current version of
27
+ // the smallcaps decoder annoyingly insists that if the encoded body string
28
+ // says a slot is a promise, then convertSlotToVal had better by damn return
29
+ // an actual Promise, even if, as in the intended use case here, we neither
30
+ // want nor need a promise, nor the overhead of a map to keep track of it
31
+ // with. This behavior is in service of defense against a hypothesized
32
+ // security issue whose exact nature has largely been forgotton in the
33
+ // months since it was first encountered. MarkM is currently researching
34
+ // what the problem was thought to have been, to see if it is real and to
35
+ // understand it if so. This will eventually result in either changes to
36
+ // the smallcaps encoding or to the marshal setup API to support the purely
37
+ // manipulative use case. In the meantime, this ugliness...
38
+ const p = new Promise(() => undefined);
39
+ refMap.set(p, kref);
40
+ return harden(p);
41
+ } else {
42
+ const o = Far(iface, {
43
+ iface: () => iface,
44
+ getKref: () => `${kref}`,
45
+ });
46
+ return o;
47
+ }
48
+ };
49
+
50
+ export const krefOf = obj => {
51
+ const fromMap = refMap.get(obj);
52
+ if (fromMap) {
53
+ return fromMap;
54
+ }
55
+ // When krefOf() is called as part of kmarshal.serialize, marshal
56
+ // will only give it things that are 'remotable' (Promises and the
57
+ // Far objects created by kslot()). When krefOf() is called by
58
+ // kernel code (as part of extractSingleSlot() or the vat-comms
59
+ // equivalent), it ought to throw if 'obj' is not one of the Far
60
+ // objects created by our kslot().
61
+ assert.equal(passStyleOf(obj), 'remotable', obj);
62
+ const getKref = obj.getKref;
63
+ assert.typeof(getKref, 'function');
64
+ return getKref();
65
+ };
66
+
67
+ const kmarshal = makeMarshal(krefOf, kslot, {
68
+ serializeBodyFormat: 'smallcaps',
69
+ errorTagging: 'off',
70
+ });
71
+
72
+ export const kser = value => kmarshal.serialize(harden(value));
73
+
74
+ export const kunser = serializedValue => kmarshal.unserialize(serializedValue);
75
+
76
+ export function makeError(message) {
77
+ assert.typeof(message, 'string');
78
+ return kser(Error(message));
79
+ }
@@ -1,7 +1,6 @@
1
1
  /* global WeakRef, FinalizationRegistry */
2
- import { kser } from '@agoric/kmarshal';
3
-
4
2
  import engineGC from './engine-gc.js';
3
+
5
4
  import { waitUntilQuiescent } from './waitUntilQuiescent.js';
6
5
  import { makeGcAndFinalize } from './gc-and-finalize.js';
7
6
  import { makeDummyMeterControl } from './dummyMeterControl.js';
@@ -13,11 +12,12 @@ import {
13
12
  makeRetireExports,
14
13
  makeBringOutYourDead,
15
14
  } 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 = false]
20
+ * @param {Map<string, string>} [options.kvStore = new Map()]
21
21
  */
22
22
  export function buildSyscall(options = {}) {
23
23
  const { skipLogging = false, kvStore: fakestore = new Map() } = options;
@@ -168,9 +168,9 @@ function makeRPMaker(nextNumber = 1) {
168
168
  * @param {string} vatName
169
169
  * @param {object} [options]
170
170
  * @param {boolean} [options.forceGC]
171
- * @param {Map<string, string>} [options.kvStore]
171
+ * @param {Map<string, string>} [options.kvStore = new Map()]
172
172
  * @param {number} [options.nextPromiseImportNumber]
173
- * @param {boolean} [options.skipLogging]
173
+ * @param {boolean} [options.skipLogging = false]
174
174
  */
175
175
  export async function setupTestLiveslots(
176
176
  t,
package/test/mock-gc.js CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-nocheck
2
1
  import { waitUntilQuiescent } from './waitUntilQuiescent.js';
3
2
  import { makeDummyMeterControl } from './dummyMeterControl.js';
4
3
 
@@ -1,12 +1,12 @@
1
- // @ts-nocheck
2
1
  import test from 'ava';
2
+ import '@endo/init/debug.js';
3
3
 
4
- import { kslot, kunser } from '@agoric/kmarshal';
5
4
  import {
6
5
  setupTestLiveslots,
7
6
  findSyscallsByType,
8
7
  } from '../liveslots-helpers.js';
9
8
  import { buildRootObject, mainHeldIdx, mapRef } from '../gc-helpers.js';
9
+ import { kslot, kunser } from '../kmarshal.js';
10
10
  import { parseVatSlot } from '../../src/parseVatSlots.js';
11
11
 
12
12
  // These tests follow the model described in
@@ -1,6 +1,6 @@
1
1
  import test from 'ava';
2
+ import '@endo/init/debug.js';
2
3
 
3
- import { kslot } from '@agoric/kmarshal';
4
4
  import {
5
5
  findSyscallsByType,
6
6
  setupTestLiveslots,
@@ -12,6 +12,7 @@ import {
12
12
  refValString,
13
13
  assertCollectionDeleted,
14
14
  } from '../gc-helpers.js';
15
+ import { kslot } from '../kmarshal.js';
15
16
  import { vstr } from '../util.js';
16
17
 
17
18
  // These tests follow the model described in
@@ -1,4 +1,5 @@
1
1
  import test from 'ava';
2
+ import '@endo/init/debug.js';
2
3
 
3
4
  import { setupTestLiveslots } from '../liveslots-helpers.js';
4
5
  import { buildRootObject, mapRef } from '../gc-helpers.js';
@@ -1,6 +1,6 @@
1
1
  import test from 'ava';
2
+ import '@endo/init/debug.js';
2
3
 
3
- import { kslot } from '@agoric/kmarshal';
4
4
  import { setupTestLiveslots } from '../liveslots-helpers.js';
5
5
  import {
6
6
  buildRootObject,
@@ -8,6 +8,7 @@ import {
8
8
  assertCollectionDeleted,
9
9
  deduceCollectionID,
10
10
  } from '../gc-helpers.js';
11
+ import { kslot } from '../kmarshal.js';
11
12
  import { vstr } from '../util.js';
12
13
 
13
14
  // These tests follow the model described in test-virtualObjectGC.js