@agoric/swingset-liveslots 0.10.3-u16.0 → 0.10.3-u17.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.
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-use-before-define, jsdoc/require-returns-type */
2
2
 
3
- import { assert, Fail } from '@agoric/assert';
3
+ import { assert, Fail } from '@endo/errors';
4
4
  import { Nat } from '@endo/nat';
5
5
  import { parseVatSlot } from './parseVatSlots.js';
6
6
  import {
@@ -290,7 +290,10 @@ export function makeVirtualReferenceManager(
290
290
  */
291
291
  function isDurable(vref) {
292
292
  const { type, id, virtual, durable, allocatedByVat } = parseVatSlot(vref);
293
- if (relaxDurabilityRules) {
293
+ if (type === 'promise') {
294
+ // promises are not durable even if `relaxDurabilityRules === true`
295
+ return false;
296
+ } else if (relaxDurabilityRules) {
294
297
  // we'll pretend an object is durable if running with relaxed rules
295
298
  return true;
296
299
  } else if (type === 'device') {
@@ -497,26 +500,51 @@ export function makeVirtualReferenceManager(
497
500
  }
498
501
 
499
502
  /**
500
- * A vref is "recognizable" when it is used as the key of a weak Map
501
- * or Set: that Map/Set can be used to query whether a future
502
- * specimen matches the original or not, without holding onto the
503
- * original.
503
+ * A vref is "recognizable" when it is used as the key of a weak
504
+ * collection, like a virtual/durable WeakMapStore or WeakSetStore,
505
+ * or the ephemeral voAwareWeakMap/Set that we impose upon userspace
506
+ * as "WeakMap/WeakSet". The collection can be used to query whether
507
+ * a future specimen matches the original or not, without holding
508
+ * onto the original.
509
+ *
510
+ * We need "recognition records" to map from the vref to the
511
+ * collection that can recognize it. When the vref is retired, we
512
+ * use the record to find all the collections from which we need to
513
+ * delete entries, so we can release the matching values. This might
514
+ * happen because the vref was for a Presence and the kernel just
515
+ * told us the upstream vat has deleted it (dispatch.retireImports),
516
+ * or because it was for a locally-managed object (an ephemeral
517
+ * Remotable or a virtual/durable Representative) and we decided to
518
+ * delete it.
519
+ *
520
+ * The virtual/durable collections track their "recognition records"
521
+ * in the vatstore, in keys like "vom.ir.${vref}|${collectionID}".
522
+ * These records do not contribute to our RAM usage.
523
+ *
524
+ * voAwareWeakMap and voAwareWeakSet store their recognition records
525
+ * in RAM, using this Map named 'vrefRecognizers'. Each key is a
526
+ * vref, and the value is a Set of recognizers. Each recognizer is
527
+ * the internal 'virtualObjectMap' in which the collection maps from
528
+ * vref to value. These in-RAM collections only use virtualObjectMap
529
+ * to track Presence-style (imports) and Representative-style
530
+ * (virtual/durable) vrefs: any Remotable-style keys are stored in
531
+ * the collection's internal (real) WeakMap under the Remotable
532
+ * object itself (because the engine handles the bookkeeping, and
533
+ * there is no virtual data in the value that we need to clean up at
534
+ * deletion time).
504
535
  *
505
- * This 'vrefRecognizers' is a Map from those vrefs to the set of
506
- * recognizing weak collections, for virtual keys and non-virtual
507
- * collections. Specifically, the vrefs correspond to imported
508
- * Presences or virtual-object Representatives (Remotables do not
509
- * participate: they are keyed by the actual Remotable object, not
510
- * its vref). The collections are either a VirtualObjectAwareWeakMap
511
- * or a VirtualObjectAwareWeakSet. We remove the entry when the key
512
- * is removed from the collection, and when the entire collection is
513
- * deleted.
536
+ * Each voAwareWeakMap/Set must have a distinct recognizer, so we
537
+ * can remove the key from the right ones. The recognizer is held
538
+ * strongly by the recognition record, so it must not be the
539
+ * voAwareWeakMap/Set itself (which would inhibit GC).
514
540
  *
515
- * It is critical that each collection have exactly one recognizer that is
516
- * unique to that collection, because the recognizers themselves will be
517
- * tracked by their object identities, but the recognizer cannot be the
518
- * collection itself else it would prevent the collection from being garbage
519
- * collected.
541
+ * When an individual entry is deleted from the weak collection, we
542
+ * must also delete the recognition record. When the collection
543
+ * itself is deleted (i.e. because nothing was referencing it), we
544
+ * must both delete all recognition records and also notify the
545
+ * kernel about any Presence-style vrefs that we can no longer
546
+ * recognize (syscall.retireImports). The kernel doesn't care about
547
+ * Remotable- or Representative- style vrefs, only the imports.
520
548
  *
521
549
  * TODO: all the "recognizers" in principle could be, and probably should be,
522
550
  * reduced to deleter functions. However, since the VirtualObjectAware
@@ -532,14 +560,24 @@ export function makeVirtualReferenceManager(
532
560
  /** @type {Map<string, Set<Recognizer>>} */
533
561
  const vrefRecognizers = new Map();
534
562
 
563
+ /**
564
+ * @param {*} value The vref-bearing object used as the collection key
565
+ * @param {string|Recognizer} recognizer The collectionID or virtualObjectMap for the collection
566
+ * @param {boolean} [recognizerIsVirtual] true for virtual/durable Stores, false for voAwareWeakMap/Set
567
+ */
535
568
  function addRecognizableValue(value, recognizer, recognizerIsVirtual) {
536
569
  const vref = getSlotForVal(value);
537
570
  if (vref) {
538
571
  const { type, allocatedByVat, virtual, durable } = parseVatSlot(vref);
539
- if (type === 'object' && (!allocatedByVat || virtual || durable)) {
572
+ if (type === 'object') {
573
+ // recognizerSet (voAwareWeakMap/Set) doesn't track Remotables
574
+ const notRemotable = !allocatedByVat || virtual || durable;
575
+
540
576
  if (recognizerIsVirtual) {
577
+ assert.typeof(recognizer, 'string');
541
578
  syscall.vatstoreSet(`vom.ir.${vref}|${recognizer}`, '1');
542
- } else {
579
+ } else if (notRemotable) {
580
+ assert.typeof(recognizer, 'object');
543
581
  let recognizerSet = vrefRecognizers.get(vref);
544
582
  if (!recognizerSet) {
545
583
  recognizerSet = new Set();
@@ -551,18 +589,33 @@ export function makeVirtualReferenceManager(
551
589
  }
552
590
  }
553
591
 
592
+ /**
593
+ * @param {string} vref The vref or the object used as the collection key
594
+ * @param {string|Recognizer} recognizer The collectionID or virtualObjectMap for the collection
595
+ * @param {boolean} [recognizerIsVirtual] true for virtual/durable Stores, false for voAwareWeakMap/Set
596
+ */
554
597
  function removeRecognizableVref(vref, recognizer, recognizerIsVirtual) {
555
598
  const { type, allocatedByVat, virtual, durable } = parseVatSlot(vref);
556
- if (type === 'object' && (!allocatedByVat || virtual || durable)) {
599
+ if (type === 'object') {
600
+ // addToPossiblyDeadSet only needs Presence-style vrefs
601
+ const isPresence = !allocatedByVat;
602
+ // recognizerSet (voAwareWeakMap/Set) doesn't track Remotables
603
+ const notRemotable = !allocatedByVat || virtual || durable;
604
+
557
605
  if (recognizerIsVirtual) {
606
+ assert.typeof(recognizer, 'string');
558
607
  syscall.vatstoreDelete(`vom.ir.${vref}|${recognizer}`);
559
- } else {
608
+ if (isPresence) {
609
+ addToPossiblyRetiredSet(vref);
610
+ }
611
+ } else if (notRemotable) {
612
+ assert.typeof(recognizer, 'object');
560
613
  const recognizerSet = vrefRecognizers.get(vref);
561
614
  assert(recognizerSet && recognizerSet.has(recognizer));
562
615
  recognizerSet.delete(recognizer);
563
616
  if (recognizerSet.size === 0) {
564
617
  vrefRecognizers.delete(vref);
565
- if (!allocatedByVat) {
618
+ if (isPresence) {
566
619
  addToPossiblyRetiredSet(vref);
567
620
  }
568
621
  }
@@ -570,6 +623,11 @@ export function makeVirtualReferenceManager(
570
623
  }
571
624
  }
572
625
 
626
+ /**
627
+ * @param {*} value The vref-bearing object used as the collection key
628
+ * @param {string|Recognizer} recognizer The collectionID or virtualObjectMap for the collection
629
+ * @param {boolean} [recognizerIsVirtual] true for virtual/durable Stores, false for voAwareWeakMap/Set
630
+ */
573
631
  function removeRecognizableValue(value, recognizer, recognizerIsVirtual) {
574
632
  const vref = getSlotForVal(value);
575
633
  if (vref) {
@@ -2,9 +2,8 @@
2
2
  // no-lonely-if is a stupid rule that really should be disabled globally
3
3
  /* eslint-disable no-lonely-if */
4
4
 
5
- import { Fail } from '@endo/errors';
5
+ import { Fail, assert } from '@endo/errors';
6
6
  import { E } from '@endo/eventual-send';
7
- import { assert } from '@agoric/assert';
8
7
  import { initEmpty, M } from '@agoric/store';
9
8
  import { parseVatSlot } from './parseVatSlots.js';
10
9
 
@@ -140,6 +139,12 @@ export function makeWatchedPromiseManager({
140
139
  */
141
140
  function loadWatchedPromiseTable(revivePromise) {
142
141
  for (const vpid of watchedPromiseTable.keys()) {
142
+ if (promiseRegistrations.has(vpid)) {
143
+ // We're only interested in reconnecting the promises from the previous
144
+ // incarnation. Any promise watched during buildRootObject would have
145
+ // already created a registration.
146
+ continue;
147
+ }
143
148
  const p = revivePromise(vpid);
144
149
  promiseRegistrations.init(vpid, p);
145
150
  pseudoThen(p, vpid);