@agoric/swingset-liveslots 0.10.3-other-dev-1f26562.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.
Files changed (77) hide show
  1. package/README.md +2 -0
  2. package/package.json +27 -19
  3. package/src/boyd-gc.js +598 -0
  4. package/src/cache.js +3 -2
  5. package/src/capdata.js +1 -2
  6. package/src/collectionManager.js +219 -103
  7. package/src/facetiousness.js +1 -1
  8. package/src/index.js +4 -2
  9. package/src/liveslots.js +131 -301
  10. package/src/message.js +5 -5
  11. package/src/parseVatSlots.js +1 -1
  12. package/src/types-index.d.ts +4 -0
  13. package/src/types-index.js +2 -0
  14. package/src/types.js +8 -2
  15. package/src/vatstore-iterators.js +2 -0
  16. package/src/virtualObjectManager.js +185 -71
  17. package/src/virtualReferences.js +135 -26
  18. package/src/watchedPromises.js +67 -17
  19. package/test/{test-baggage.js → baggage.test.js} +1 -2
  20. package/test/{test-cache.js → cache.test.js} +0 -1
  21. package/test/clear-collection.test.js +586 -0
  22. package/test/{test-collection-schema-refcount.js → collection-schema-refcount.test.js} +1 -2
  23. package/test/{test-collection-upgrade.js → collection-upgrade.test.js} +1 -3
  24. package/test/{test-collections.js → collections.test.js} +158 -14
  25. package/test/{test-dropped-collection-weakrefs.js → dropped-collection-weakrefs.test.js} +1 -2
  26. package/test/dropped-weakset-9939.test.js +80 -0
  27. package/test/dummyMeterControl.js +1 -1
  28. package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +4 -4
  29. package/test/exo-utils.js +70 -0
  30. package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
  31. package/test/gc-and-finalize.js +30 -1
  32. package/test/gc-before-finalizer.test.js +230 -0
  33. package/test/gc-helpers.js +2 -3
  34. package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
  35. package/test/handled-promises.test.js +506 -0
  36. package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +2 -3
  37. package/test/liveslots-helpers.js +12 -7
  38. package/test/{test-liveslots-mock-gc.js → liveslots-mock-gc.test.js} +101 -2
  39. package/test/{test-liveslots-real-gc.js → liveslots-real-gc.test.js} +62 -37
  40. package/test/{test-liveslots.js → liveslots.test.js} +14 -15
  41. package/test/mock-gc.js +1 -0
  42. package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +2 -2
  43. package/test/storeGC/{test-refcount-management.js → refcount-management.test.js} +1 -2
  44. package/test/storeGC/{test-scalar-store-kind.js → scalar-store-kind.test.js} +0 -1
  45. package/test/storeGC/{test-weak-key.js → weak-key.test.js} +1 -2
  46. package/test/strict-test-env-upgrade.test.js +94 -0
  47. package/test/util.js +2 -2
  48. package/test/vat-environment.test.js +65 -0
  49. package/test/vat-util.js +2 -2
  50. package/test/virtual-objects/{test-cease-recognition.js → cease-recognition.test.js} +2 -2
  51. package/test/virtual-objects/{test-cross-facet.js → cross-facet.test.js} +5 -4
  52. package/test/virtual-objects/{test-empty-data.js → empty-data.test.js} +1 -2
  53. package/test/virtual-objects/{test-facets.js → facets.test.js} +1 -2
  54. package/test/virtual-objects/{test-kind-changes.js → kind-changes.test.js} +2 -2
  55. package/test/virtual-objects/{test-reachable-vrefs.js → reachable-vrefs.test.js} +2 -2
  56. package/test/virtual-objects/{test-rep-tostring.js → rep-tostring.test.js} +3 -5
  57. package/test/virtual-objects/{test-retain-remotable.js → retain-remotable.test.js} +25 -24
  58. package/test/virtual-objects/set-debug-label-instances.js +1 -1
  59. package/test/virtual-objects/{test-state-shape.js → state-shape.test.js} +2 -2
  60. package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +2 -2
  61. package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +126 -8
  62. package/test/virtual-objects/{test-vo-real-gc.js → vo-real-gc.test.js} +8 -8
  63. package/test/virtual-objects/{test-weakcollections-vref-handling.js → weakcollections-vref-handling.test.js} +1 -2
  64. package/test/{test-vo-test-harness.js → vo-test-harness.test.js} +0 -1
  65. package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +105 -5
  66. package/test/waitUntilQuiescent.js +2 -1
  67. package/test/weakset-dropped-remotable.test.js +50 -0
  68. package/tools/fakeCollectionManager.js +44 -0
  69. package/tools/fakeVirtualObjectManager.js +62 -0
  70. package/tools/fakeVirtualSupport.js +389 -0
  71. package/tools/prepare-strict-test-env.js +124 -0
  72. package/tools/prepare-test-env.js +13 -0
  73. package/tools/setup-vat-data.js +96 -0
  74. package/tools/vo-test-harness.js +143 -0
  75. package/CHANGELOG.md +0 -61
  76. package/test/kmarshal.js +0 -79
  77. package/test/test-handled-promises.js +0 -360
@@ -1,10 +1,9 @@
1
- import { assert, q, Fail } from '@agoric/assert';
1
+ import { assert, q, Fail } from '@endo/errors';
2
2
  import { Far, passStyleOf } from '@endo/far';
3
3
  import {
4
4
  zeroPad,
5
5
  makeEncodePassable,
6
6
  makeDecodePassable,
7
- isEncodedRemotable,
8
7
  compareRank,
9
8
  } from '@endo/marshal';
10
9
  import {
@@ -15,7 +14,10 @@ import {
15
14
  makeCopySet,
16
15
  makeCopyMap,
17
16
  getRankCover,
17
+ getCopyMapEntries,
18
+ getCopySetKeys,
18
19
  } from '@endo/patterns';
20
+ import { isCopyMap, isCopySet } from '@agoric/store';
19
21
  import { makeBaseRef, parseVatSlot } from './parseVatSlots.js';
20
22
  import {
21
23
  enumerateKeysStartEnd,
@@ -23,6 +25,10 @@ import {
23
25
  } from './vatstore-iterators.js';
24
26
  import { makeCache } from './cache.js';
25
27
 
28
+ /**
29
+ * @import {ToCapData, FromCapData} from '@endo/marshal';
30
+ */
31
+
26
32
  // XXX TODO: The following key length limit was put in place due to limitations
27
33
  // in LMDB. With the move away from LMDB, it is no longer relevant, but I'm
28
34
  // leaving it in place for the time being as a general defensive measure against
@@ -47,10 +53,24 @@ function throwNotDurable(value, slotIndex, serializedValue) {
47
53
  Fail`value is not durable: ${value} at slot ${q(slotIndex)} of ${serializedValue.body}`;
48
54
  }
49
55
 
56
+ function failNotFound(key, label) {
57
+ Fail`key ${key} not found in collection ${q(label)}`;
58
+ }
59
+
60
+ function failNotIterable(value) {
61
+ Fail`provided data source is not iterable: ${value}`;
62
+ }
63
+
50
64
  function prefixc(collectionID, dbEntryKey) {
51
65
  return `vc.${collectionID}.${dbEntryKey}`;
52
66
  }
53
67
 
68
+ export const collectionMetaKeys = new Set([
69
+ '|entryCount',
70
+ '|nextOrdinal',
71
+ '|schemata',
72
+ ]);
73
+
54
74
  /**
55
75
  * @typedef {object} SchemaCacheValue
56
76
  * @property {Pattern} keyShape
@@ -101,8 +121,8 @@ function makeSchemaCache(syscall, unserialize) {
101
121
  * @param {(val: any) => string | undefined} convertValToSlot
102
122
  * @param {*} convertSlotToVal
103
123
  * @param {*} registerValue
104
- * @param {import('@endo/marshal').ToCapData<string>} serialize
105
- * @param {import('@endo/marshal').FromCapData<string>} unserialize
124
+ * @param {ToCapData<string>} serialize
125
+ * @param {FromCapData<string>} unserialize
106
126
  * @param {(capDatas: any) => void} assertAcceptableSyscallCapdataSize
107
127
  */
108
128
  export function makeCollectionManager(
@@ -126,56 +146,48 @@ export function makeCollectionManager(
126
146
  scalarMapStore: {
127
147
  hasWeakKeys: false,
128
148
  kindID: 0,
129
- // eslint-disable-next-line no-use-before-define
130
149
  reanimator: reanimateMapStore,
131
150
  durable: false,
132
151
  },
133
152
  scalarWeakMapStore: {
134
153
  hasWeakKeys: true,
135
154
  kindID: 0,
136
- // eslint-disable-next-line no-use-before-define
137
155
  reanimator: reanimateWeakMapStore,
138
156
  durable: false,
139
157
  },
140
158
  scalarSetStore: {
141
159
  hasWeakKeys: false,
142
160
  kindID: 0,
143
- // eslint-disable-next-line no-use-before-define
144
161
  reanimator: reanimateSetStore,
145
162
  durable: false,
146
163
  },
147
164
  scalarWeakSetStore: {
148
165
  hasWeakKeys: true,
149
166
  kindID: 0,
150
- // eslint-disable-next-line no-use-before-define
151
167
  reanimator: reanimateWeakSetStore,
152
168
  durable: false,
153
169
  },
154
170
  scalarDurableMapStore: {
155
171
  hasWeakKeys: false,
156
172
  kindID: 0,
157
- // eslint-disable-next-line no-use-before-define
158
173
  reanimator: reanimateMapStore,
159
174
  durable: true,
160
175
  },
161
176
  scalarDurableWeakMapStore: {
162
177
  hasWeakKeys: true,
163
178
  kindID: 0,
164
- // eslint-disable-next-line no-use-before-define
165
179
  reanimator: reanimateWeakMapStore,
166
180
  durable: true,
167
181
  },
168
182
  scalarDurableSetStore: {
169
183
  hasWeakKeys: false,
170
184
  kindID: 0,
171
- // eslint-disable-next-line no-use-before-define
172
185
  reanimator: reanimateSetStore,
173
186
  durable: true,
174
187
  },
175
188
  scalarDurableWeakSetStore: {
176
189
  hasWeakKeys: true,
177
190
  kindID: 0,
178
- // eslint-disable-next-line no-use-before-define
179
191
  reanimator: reanimateWeakSetStore,
180
192
  durable: true,
181
193
  },
@@ -198,7 +210,6 @@ export function makeCollectionManager(
198
210
  vrm.registerKind(
199
211
  kindID,
200
212
  storeKindInfo[kind].reanimator,
201
- // eslint-disable-next-line no-use-before-define
202
213
  deleteCollection,
203
214
  storeKindInfo[kind].durable,
204
215
  );
@@ -244,7 +255,11 @@ export function makeCollectionManager(
244
255
  const kindInfo = storeKindInfo[kindName];
245
256
  kindInfo || Fail`unknown collection kind ${kindName}`;
246
257
  const { hasWeakKeys, durable } = kindInfo;
247
- const getSchema = () => schemaCache.get(collectionID);
258
+ const getSchema = () => {
259
+ const result = schemaCache.get(collectionID);
260
+ assert(result !== undefined);
261
+ return result;
262
+ };
248
263
  const dbKeyPrefix = `vc.${collectionID}.`;
249
264
  let currentGenerationNumber = 0;
250
265
 
@@ -274,8 +289,21 @@ export function makeCollectionManager(
274
289
  return `${dbKeyPrefix}${dbEntryKey}`;
275
290
  }
276
291
 
292
+ // A "vref" is a string like "o-4" or "o+d44/2:0"
293
+ // An "EncodedKey" is the output of encode-passable:
294
+ // * strings become `s${string}`, like "foo" -> "sfoo"
295
+ // * small positive BigInts become `p${len}:${digits}`, like 47n -> "p2:47"
296
+ // * refs are assigned an "ordinal" and use `r${fixedLengthOrdinal}:${vref}`
297
+ // * e.g. vref(o-4) becomes "r0000000001:o-4"
298
+ // A "DBKey" is used to index the vatstore. DBKeys for collection
299
+ // entries join a collection prefix and an EncodedKey. Some
300
+ // possible DBKeys for entries of collection "5", using collection
301
+ // prefix "vc.5.", are:
302
+ // * "foo" -> "vc.5.sfoo"
303
+ // * 47n -> "vc.5.p2:47"
304
+ // * vref(o-4) -> "vc.5.r0000000001:o-4"
305
+
277
306
  const encodeRemotable = remotable => {
278
- // eslint-disable-next-line no-use-before-define
279
307
  const ordinal = getOrdinal(remotable);
280
308
  ordinal !== undefined || Fail`no ordinal for ${remotable}`;
281
309
  const ordinalTag = zeroPad(ordinal, BIGINT_TAG_LEN);
@@ -289,10 +317,11 @@ export function makeCollectionManager(
289
317
  // the resulting function will encode only `Key` arguments.
290
318
  const encodeKey = makeEncodePassable({ encodeRemotable });
291
319
 
292
- const vrefFromDBKey = dbKey => dbKey.substring(BIGINT_TAG_LEN + 2);
320
+ const vrefFromEncodedKey = encodedKey =>
321
+ encodedKey.substring(1 + BIGINT_TAG_LEN + 1);
293
322
 
294
323
  const decodeRemotable = encodedKey =>
295
- convertSlotToVal(vrefFromDBKey(encodedKey));
324
+ convertSlotToVal(vrefFromEncodedKey(encodedKey));
296
325
 
297
326
  // `makeDecodePassable` has three named options:
298
327
  // `decodeRemotable`, `decodeError`, and `decodePromise`.
@@ -328,32 +357,40 @@ export function makeCollectionManager(
328
357
  }
329
358
 
330
359
  function dbKeyToKey(dbKey) {
360
+ // convert e.g. vc.5.r0000000001:o+v10/1 to r0000000001:o+v10/1
331
361
  const dbEntryKey = dbKey.substring(dbKeyPrefix.length);
332
362
  return decodeKey(dbEntryKey);
333
363
  }
334
364
 
365
+ function dbKeyToEncodedKey(dbKey) {
366
+ assert(dbKey.startsWith(dbKeyPrefix), dbKey);
367
+ return dbKey.substring(dbKeyPrefix.length);
368
+ }
369
+
335
370
  function has(key) {
336
371
  const { keyShape } = getSchema();
337
372
  if (!matches(key, keyShape)) {
338
373
  return false;
339
- }
340
- if (passStyleOf(key) === 'remotable') {
374
+ } else if (passStyleOf(key) === 'remotable') {
341
375
  return getOrdinal(key) !== undefined;
342
376
  } else {
343
377
  return syscall.vatstoreGet(keyToDBKey(key)) !== undefined;
344
378
  }
345
379
  }
346
380
 
381
+ function mustGet(key, label) {
382
+ if (passStyleOf(key) === 'remotable' && getOrdinal(key) === undefined) {
383
+ failNotFound(key, label);
384
+ }
385
+ const dbKey = keyToDBKey(key);
386
+ const result = syscall.vatstoreGet(dbKey) || failNotFound(key, label);
387
+ return { dbKey, result };
388
+ }
389
+
347
390
  function get(key) {
348
391
  const { keyShape, label } = getSchema();
349
392
  mustMatch(key, keyShape, makeInvalidKeyTypeMsg(label));
350
- if (passStyleOf(key) === 'remotable' && getOrdinal(key) === undefined) {
351
- throw Fail`key ${key} not found in collection ${q(label)}`;
352
- }
353
- const result = syscall.vatstoreGet(keyToDBKey(key));
354
- if (!result) {
355
- throw Fail`key ${key} not found in collection ${q(label)}`;
356
- }
393
+ const { result } = mustGet(key, label);
357
394
  return unserializeValue(JSON.parse(result));
358
395
  }
359
396
 
@@ -377,11 +414,11 @@ export function makeCollectionManager(
377
414
  currentGenerationNumber += 1;
378
415
  assertAcceptableSyscallCapdataSize([serializedValue]);
379
416
  if (durable) {
380
- serializedValue.slots.forEach((vref, slotIndex) => {
417
+ for (const [slotIndex, vref] of serializedValue.slots.entries()) {
381
418
  if (!vrm.isDurable(vref)) {
382
419
  throwNotDurable(value, slotIndex, serializedValue);
383
420
  }
384
- });
421
+ }
385
422
  }
386
423
  if (passStyleOf(key) === 'remotable') {
387
424
  /** @type {string} */
@@ -397,7 +434,9 @@ export function makeCollectionManager(
397
434
  vrm.addReachableVref(vref);
398
435
  }
399
436
  }
400
- serializedValue.slots.forEach(vrm.addReachableVref);
437
+ for (const vref of serializedValue.slots) {
438
+ vrm.addReachableVref(vref);
439
+ }
401
440
  syscall.vatstoreSet(keyToDBKey(key), JSON.stringify(serializedValue));
402
441
  updateEntryCount(1);
403
442
  };
@@ -416,15 +455,13 @@ export function makeCollectionManager(
416
455
  const after = serializeValue(harden(value));
417
456
  assertAcceptableSyscallCapdataSize([after]);
418
457
  if (durable) {
419
- after.slots.forEach((vref, i) => {
458
+ for (const [i, vref] of after.slots.entries()) {
420
459
  if (!vrm.isDurable(vref)) {
421
460
  throwNotDurable(value, i, after);
422
461
  }
423
- });
462
+ }
424
463
  }
425
- const dbKey = keyToDBKey(key);
426
- const rawBefore = syscall.vatstoreGet(dbKey);
427
- rawBefore || Fail`key ${key} not found in collection ${q(label)}`;
464
+ const { dbKey, result: rawBefore } = mustGet(key, label);
428
465
  const before = JSON.parse(rawBefore);
429
466
  vrm.updateReferenceCounts(before.slots, after.slots);
430
467
  syscall.vatstoreSet(dbKey, JSON.stringify(after));
@@ -433,12 +470,7 @@ export function makeCollectionManager(
433
470
  function deleteInternal(key) {
434
471
  const { keyShape, label } = getSchema();
435
472
  mustMatch(key, keyShape, makeInvalidKeyTypeMsg(label));
436
- if (passStyleOf(key) === 'remotable' && getOrdinal(key) === undefined) {
437
- throw Fail`key ${key} not found in collection ${q(label)}`;
438
- }
439
- const dbKey = keyToDBKey(key);
440
- const rawValue = syscall.vatstoreGet(dbKey);
441
- rawValue || Fail`key ${key} not found in collection ${q(label)}`;
473
+ const { dbKey, result: rawValue } = mustGet(key, label);
442
474
  const value = JSON.parse(rawValue);
443
475
  const doMoreGC1 = value.slots.map(vrm.removeReachableVref).some(b => b);
444
476
  syscall.vatstoreDelete(dbKey);
@@ -474,18 +506,15 @@ export function makeCollectionManager(
474
506
  const end = prefix(coverEnd); // exclusive
475
507
 
476
508
  const generationAtStart = currentGenerationNumber;
477
- function checkGen() {
478
- if (generationAtStart !== currentGenerationNumber) {
479
- Fail`keys in store cannot be added to during iteration`;
480
- }
481
- }
509
+ const checkGen = () =>
510
+ currentGenerationNumber === generationAtStart ||
511
+ Fail`keys in store cannot be added to during iteration`;
482
512
 
483
513
  const needToMatchKey = !matchAny(keyPatt);
484
514
  const needToMatchValue = !matchAny(valuePatt);
485
515
 
486
- // we always get the dbKey, but we might not need to unserialize it
516
+ // we might not need to unserialize the dbKey or get the dbValue
487
517
  const needKeys = yieldKeys || needToMatchKey;
488
- // we don't always need the dbValue
489
518
  const needValues = yieldValues || needToMatchValue;
490
519
 
491
520
  /**
@@ -513,7 +542,7 @@ export function makeCollectionManager(
513
542
  yield [yieldKeys ? key : undefined, yieldValues ? value : undefined];
514
543
  }
515
544
  }
516
-
545
+ harden(iter);
517
546
  return iter();
518
547
  }
519
548
 
@@ -523,6 +552,7 @@ export function makeCollectionManager(
523
552
  yield entry[0];
524
553
  }
525
554
  }
555
+ harden(iter);
526
556
  return iter();
527
557
  }
528
558
 
@@ -539,40 +569,58 @@ export function makeCollectionManager(
539
569
  */
540
570
  function clearInternalFull() {
541
571
  let doMoreGC = false;
542
- const [coverStart, coverEnd] = getRankCover(M.any(), encodeKey);
543
- const start = prefix(coverStart);
544
- const end = prefix(coverEnd);
545
-
546
- // this yields all keys for which (start <= key < end)
547
- for (const dbKey of enumerateKeysStartEnd(syscall, start, end)) {
548
- const value = JSON.parse(syscall.vatstoreGet(dbKey));
549
- doMoreGC =
550
- value.slots.map(vrm.removeReachableVref).some(b => b) || doMoreGC;
551
- syscall.vatstoreDelete(dbKey);
552
- if (isEncodedRemotable(dbKey)) {
553
- const keyVref = vrefFromDBKey(dbKey);
572
+
573
+ // visit every DB entry associated with the collection, which
574
+ // (due to sorting) will be collection entries first, and then a
575
+ // mixture of ordinal-assignment mappings and size-independent
576
+ // metadata (both of which start with "|").
577
+ for (const dbKey of enumerateKeysWithPrefix(syscall, dbKeyPrefix)) {
578
+ const encodedKey = dbKeyToEncodedKey(dbKey);
579
+
580
+ // preserve general metadata ("|entryCount" and friends are
581
+ // cleared by our caller)
582
+ if (collectionMetaKeys.has(encodedKey)) continue;
583
+
584
+ if (encodedKey.startsWith('|')) {
585
+ // ordinal assignment; decref or de-recognize its vref
586
+ const keyVref = encodedKey.substring(1);
587
+ parseVatSlot(keyVref);
554
588
  if (hasWeakKeys) {
555
589
  vrm.removeRecognizableVref(keyVref, `${collectionID}`, true);
556
590
  } else {
557
591
  doMoreGC = vrm.removeReachableVref(keyVref) || doMoreGC;
558
592
  }
559
- syscall.vatstoreDelete(prefix(`|${keyVref}`));
593
+ } else {
594
+ // a collection entry; decref slots from its value
595
+ const value = JSON.parse(syscall.vatstoreGet(dbKey));
596
+ doMoreGC =
597
+ value.slots.map(vrm.removeReachableVref).some(b => b) || doMoreGC;
560
598
  }
599
+
600
+ // in either case, delete the DB entry
601
+ syscall.vatstoreDelete(dbKey);
561
602
  }
603
+
562
604
  return doMoreGC;
563
605
  }
564
606
 
565
607
  function clearInternal(isDeleting, keyPatt, valuePatt) {
566
608
  let doMoreGC = false;
567
- if (isDeleting || (matchAny(keyPatt) && matchAny(valuePatt))) {
609
+ if (isDeleting) {
568
610
  doMoreGC = clearInternalFull();
611
+ // |entryCount will be deleted along with metadata keys
612
+ } else if (matchAny(keyPatt) && matchAny(valuePatt)) {
613
+ doMoreGC = clearInternalFull();
614
+ if (!hasWeakKeys) {
615
+ syscall.vatstoreSet(prefix('|entryCount'), '0');
616
+ }
569
617
  } else {
618
+ let numDeleted = 0;
570
619
  for (const k of keys(keyPatt, valuePatt)) {
620
+ numDeleted += 1;
571
621
  doMoreGC = deleteInternal(k) || doMoreGC;
572
622
  }
573
- }
574
- if (!hasWeakKeys && !isDeleting) {
575
- syscall.vatstoreSet(prefix('|entryCount'), '0');
623
+ updateEntryCount(-numDeleted);
576
624
  }
577
625
  return doMoreGC;
578
626
  }
@@ -587,6 +635,7 @@ export function makeCollectionManager(
587
635
  yield entry[1];
588
636
  }
589
637
  }
638
+ harden(iter);
590
639
  return iter();
591
640
  }
592
641
 
@@ -596,12 +645,13 @@ export function makeCollectionManager(
596
645
  yield entry;
597
646
  }
598
647
  }
648
+ harden(iter);
599
649
  return iter();
600
650
  }
601
651
 
602
652
  function countEntries(keyPatt, valuePatt) {
603
653
  let count = 0;
604
- // eslint-disable-next-line no-use-before-define, no-unused-vars
654
+ // eslint-disable-next-line no-unused-vars
605
655
  for (const k of keys(keyPatt, valuePatt)) {
606
656
  count += 1;
607
657
  }
@@ -624,6 +674,34 @@ export function makeCollectionManager(
624
674
  const snapshotMap = (keyPatt, valuePatt) =>
625
675
  makeCopyMap(entries(keyPatt, valuePatt));
626
676
 
677
+ const addAllToSet = elems => {
678
+ if (typeof elems[Symbol.iterator] !== 'function') {
679
+ elems =
680
+ Object.isFrozen(elems) && isCopySet(elems)
681
+ ? getCopySetKeys(elems)
682
+ : failNotIterable(elems);
683
+ }
684
+ for (const elem of elems) {
685
+ addToSet(elem);
686
+ }
687
+ };
688
+
689
+ const addAllToMap = mapEntries => {
690
+ if (typeof mapEntries[Symbol.iterator] !== 'function') {
691
+ mapEntries =
692
+ Object.isFrozen(mapEntries) && isCopyMap(mapEntries)
693
+ ? getCopyMapEntries(mapEntries)
694
+ : failNotIterable(mapEntries);
695
+ }
696
+ for (const [key, value] of mapEntries) {
697
+ if (has(key)) {
698
+ set(key, value);
699
+ } else {
700
+ doInit(key, value, true);
701
+ }
702
+ }
703
+ };
704
+
627
705
  return {
628
706
  has,
629
707
  get,
@@ -635,6 +713,8 @@ export function makeCollectionManager(
635
713
  keys,
636
714
  values,
637
715
  entries,
716
+ addAllToSet,
717
+ addAllToMap,
638
718
  snapshotSet,
639
719
  snapshotMap,
640
720
  sizeInternal,
@@ -647,12 +727,23 @@ export function makeCollectionManager(
647
727
  const hasWeakKeys = storeKindInfo[kindName].hasWeakKeys;
648
728
  const raw = summonCollectionInternal(initial, collectionID, kindName);
649
729
 
650
- const { has, get, init, addToSet, set, delete: del } = raw;
730
+ const {
731
+ has,
732
+ get,
733
+ init,
734
+ addToSet,
735
+ addAllToMap,
736
+ addAllToSet,
737
+ set,
738
+ delete: del,
739
+ } = raw;
651
740
  const weakMethods = {
652
741
  has,
653
742
  get,
654
743
  init,
655
744
  addToSet,
745
+ addAllToSet,
746
+ addAllToMap,
656
747
  set,
657
748
  delete: del,
658
749
  };
@@ -700,7 +791,9 @@ export function makeCollectionManager(
700
791
  const collection = summonCollectionInternal(false, collectionID, kindName);
701
792
 
702
793
  let doMoreGC = collection.clearInternal(true);
703
- const { schemataCapData } = schemaCache.get(collectionID);
794
+ const record = schemaCache.get(collectionID);
795
+ assert(record !== undefined);
796
+ const { schemataCapData } = record;
704
797
  doMoreGC =
705
798
  schemataCapData.slots.map(vrm.removeReachableVref).some(b => b) ||
706
799
  doMoreGC;
@@ -747,13 +840,15 @@ export function makeCollectionManager(
747
840
  }
748
841
  const schemataCapData = serialize(harden(schemata));
749
842
  if (isDurable) {
750
- schemataCapData.slots.forEach((vref, slotIndex) => {
843
+ for (const [slotIndex, vref] of schemataCapData.slots.entries()) {
751
844
  if (!vrm.isDurable(vref)) {
752
845
  throwNotDurable(vref, slotIndex, schemataCapData);
753
846
  }
754
- });
847
+ }
848
+ }
849
+ for (const vref of schemataCapData.slots) {
850
+ vrm.addReachableVref(vref);
755
851
  }
756
- schemataCapData.slots.forEach(vrm.addReachableVref);
757
852
 
758
853
  schemaCache.set(
759
854
  collectionID,
@@ -764,12 +859,48 @@ export function makeCollectionManager(
764
859
  }
765
860
 
766
861
  function collectionToMapStore(collection) {
767
- const { snapshotSet: _, snapshotMap, ...rest } = collection;
768
- return Far('mapStore', { snapshot: snapshotMap, ...rest });
862
+ const {
863
+ has,
864
+ get,
865
+ init,
866
+ set,
867
+ delete: del,
868
+ addAllToMap,
869
+ keys,
870
+ values,
871
+ entries,
872
+ snapshotMap,
873
+ getSize,
874
+ clear,
875
+ } = collection;
876
+ const mapStore = {
877
+ has,
878
+ get,
879
+ init,
880
+ set,
881
+ delete: del,
882
+ addAll: addAllToMap,
883
+ keys,
884
+ values,
885
+ entries,
886
+ snapshot: snapshotMap,
887
+ getSize,
888
+ clear,
889
+ };
890
+ return Far('mapStore', mapStore);
769
891
  }
770
892
 
771
893
  function collectionToWeakMapStore(collection) {
772
- return Far('weakMapStore', collection);
894
+ const { has, get, init, set, delete: del, addAllToMap } = collection;
895
+ const weakMapStore = {
896
+ has,
897
+ get,
898
+ init,
899
+ set,
900
+ delete: del,
901
+ addAll: addAllToMap,
902
+ };
903
+ return Far('weakMapStore', weakMapStore);
773
904
  }
774
905
 
775
906
  function collectionToSetStore(collection) {
@@ -777,50 +908,35 @@ export function makeCollectionManager(
777
908
  has,
778
909
  addToSet,
779
910
  delete: del,
911
+ addAllToSet,
780
912
  keys,
781
- getSize,
782
913
  snapshotSet,
914
+ getSize,
783
915
  clear,
784
916
  } = collection;
785
- function* entries(patt) {
786
- for (const k of keys(patt)) {
787
- yield [k, k];
788
- }
789
- }
790
- function addAll(elems) {
791
- for (const elem of elems) {
792
- addToSet(elem, null);
793
- }
794
- }
795
917
 
796
918
  const setStore = {
797
919
  has,
798
920
  add: addToSet,
799
- addAll,
800
921
  delete: del,
922
+ addAll: addAllToSet,
801
923
  keys: patt => keys(patt),
802
924
  values: patt => keys(patt),
803
- entries,
804
- getSize: patt => getSize(patt),
805
925
  snapshot: snapshotSet,
926
+ getSize: patt => getSize(patt),
806
927
  clear,
807
928
  };
808
929
  return Far('setStore', setStore);
809
930
  }
810
931
 
811
932
  function collectionToWeakSetStore(collection) {
812
- const { has, addToSet, delete: del } = collection;
813
- function addAll(elems) {
814
- for (const elem of elems) {
815
- addToSet(elem);
816
- }
817
- }
933
+ const { has, addToSet, delete: del, addAllToSet } = collection;
818
934
 
819
935
  const weakSetStore = {
820
936
  has,
821
937
  add: addToSet,
822
- addAll,
823
938
  delete: del,
939
+ addAll: addAllToSet,
824
940
  };
825
941
  return Far('weakSetStore', weakSetStore);
826
942
  }
@@ -829,7 +945,7 @@ export function makeCollectionManager(
829
945
  * Produce a big map.
830
946
  *
831
947
  * @template K,V
832
- * @param {string} [label='map'] - diagnostic label for the store
948
+ * @param {string} [label] - diagnostic label for the store
833
949
  * @param {StoreOptions} [options]
834
950
  * @returns {MapStore<K,V>}
835
951
  */
@@ -873,7 +989,7 @@ export function makeCollectionManager(
873
989
  * Produce a weak big map.
874
990
  *
875
991
  * @template K,V
876
- * @param {string} [label='weakMap'] - diagnostic label for the store
992
+ * @param {string} [label] - diagnostic label for the store
877
993
  * @param {StoreOptions} [options]
878
994
  * @returns {WeakMapStore<K,V>}
879
995
  */
@@ -902,7 +1018,7 @@ export function makeCollectionManager(
902
1018
  * Produce a big set.
903
1019
  *
904
1020
  * @template K
905
- * @param {string} [label='set'] - diagnostic label for the store
1021
+ * @param {string} [label] - diagnostic label for the store
906
1022
  * @param {StoreOptions} [options]
907
1023
  * @returns {SetStore<K>}
908
1024
  */
@@ -929,7 +1045,7 @@ export function makeCollectionManager(
929
1045
  * Produce a weak big set.
930
1046
  *
931
1047
  * @template K
932
- * @param {string} [label='weakSet'] - diagnostic label for the store
1048
+ * @param {string} [label] - diagnostic label for the store
933
1049
  * @param {StoreOptions} [options]
934
1050
  * @returns {WeakSetStore<K>}
935
1051
  */
@@ -1006,7 +1122,7 @@ export function makeCollectionManager(
1006
1122
  * remotables.
1007
1123
  *
1008
1124
  * @template K,V
1009
- * @param {string} [label='map'] - diagnostic label for the store
1125
+ * @param {string} [label] - diagnostic label for the store
1010
1126
  * @param {StoreOptions} [options]
1011
1127
  * @returns {MapStore<K,V>}
1012
1128
  */
@@ -1018,7 +1134,7 @@ export function makeCollectionManager(
1018
1134
  * primitives, or remotables.
1019
1135
  *
1020
1136
  * @template K,V
1021
- * @param {string} [label='weakMap'] - diagnostic label for the store
1137
+ * @param {string} [label] - diagnostic label for the store
1022
1138
  * @param {StoreOptions} [options]
1023
1139
  * @returns {WeakMapStore<K,V>}
1024
1140
  */
@@ -1030,7 +1146,7 @@ export function makeCollectionManager(
1030
1146
  * remotables.
1031
1147
  *
1032
1148
  * @template K
1033
- * @param {string} [label='set'] - diagnostic label for the store
1149
+ * @param {string} [label] - diagnostic label for the store
1034
1150
  * @param {StoreOptions} [options]
1035
1151
  * @returns {SetStore<K>}
1036
1152
  */
@@ -1042,7 +1158,7 @@ export function makeCollectionManager(
1042
1158
  * primitives, or remotables.
1043
1159
  *
1044
1160
  * @template K
1045
- * @param {string} [label='weakSet'] - diagnostic label for the store
1161
+ * @param {string} [label] - diagnostic label for the store
1046
1162
  * @param {StoreOptions} [options]
1047
1163
  * @returns {WeakSetStore<K>}
1048
1164
  */