@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.
- package/README.md +2 -0
- package/package.json +27 -19
- package/src/boyd-gc.js +598 -0
- package/src/cache.js +3 -2
- package/src/capdata.js +1 -2
- package/src/collectionManager.js +219 -103
- package/src/facetiousness.js +1 -1
- package/src/index.js +4 -2
- package/src/liveslots.js +131 -301
- package/src/message.js +5 -5
- package/src/parseVatSlots.js +1 -1
- package/src/types-index.d.ts +4 -0
- package/src/types-index.js +2 -0
- package/src/types.js +8 -2
- package/src/vatstore-iterators.js +2 -0
- package/src/virtualObjectManager.js +185 -71
- package/src/virtualReferences.js +135 -26
- package/src/watchedPromises.js +67 -17
- package/test/{test-baggage.js → baggage.test.js} +1 -2
- package/test/{test-cache.js → cache.test.js} +0 -1
- package/test/clear-collection.test.js +586 -0
- package/test/{test-collection-schema-refcount.js → collection-schema-refcount.test.js} +1 -2
- package/test/{test-collection-upgrade.js → collection-upgrade.test.js} +1 -3
- package/test/{test-collections.js → collections.test.js} +158 -14
- package/test/{test-dropped-collection-weakrefs.js → dropped-collection-weakrefs.test.js} +1 -2
- package/test/dropped-weakset-9939.test.js +80 -0
- package/test/dummyMeterControl.js +1 -1
- package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +4 -4
- package/test/exo-utils.js +70 -0
- package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
- package/test/gc-and-finalize.js +30 -1
- package/test/gc-before-finalizer.test.js +230 -0
- package/test/gc-helpers.js +2 -3
- package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
- package/test/handled-promises.test.js +506 -0
- package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +2 -3
- package/test/liveslots-helpers.js +12 -7
- package/test/{test-liveslots-mock-gc.js → liveslots-mock-gc.test.js} +101 -2
- package/test/{test-liveslots-real-gc.js → liveslots-real-gc.test.js} +62 -37
- package/test/{test-liveslots.js → liveslots.test.js} +14 -15
- package/test/mock-gc.js +1 -0
- package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +2 -2
- package/test/storeGC/{test-refcount-management.js → refcount-management.test.js} +1 -2
- package/test/storeGC/{test-scalar-store-kind.js → scalar-store-kind.test.js} +0 -1
- package/test/storeGC/{test-weak-key.js → weak-key.test.js} +1 -2
- package/test/strict-test-env-upgrade.test.js +94 -0
- package/test/util.js +2 -2
- package/test/vat-environment.test.js +65 -0
- package/test/vat-util.js +2 -2
- package/test/virtual-objects/{test-cease-recognition.js → cease-recognition.test.js} +2 -2
- package/test/virtual-objects/{test-cross-facet.js → cross-facet.test.js} +5 -4
- package/test/virtual-objects/{test-empty-data.js → empty-data.test.js} +1 -2
- package/test/virtual-objects/{test-facets.js → facets.test.js} +1 -2
- package/test/virtual-objects/{test-kind-changes.js → kind-changes.test.js} +2 -2
- package/test/virtual-objects/{test-reachable-vrefs.js → reachable-vrefs.test.js} +2 -2
- package/test/virtual-objects/{test-rep-tostring.js → rep-tostring.test.js} +3 -5
- package/test/virtual-objects/{test-retain-remotable.js → retain-remotable.test.js} +25 -24
- package/test/virtual-objects/set-debug-label-instances.js +1 -1
- package/test/virtual-objects/{test-state-shape.js → state-shape.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +2 -2
- package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +126 -8
- package/test/virtual-objects/{test-vo-real-gc.js → vo-real-gc.test.js} +8 -8
- package/test/virtual-objects/{test-weakcollections-vref-handling.js → weakcollections-vref-handling.test.js} +1 -2
- package/test/{test-vo-test-harness.js → vo-test-harness.test.js} +0 -1
- package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +105 -5
- package/test/waitUntilQuiescent.js +2 -1
- package/test/weakset-dropped-remotable.test.js +50 -0
- package/tools/fakeCollectionManager.js +44 -0
- package/tools/fakeVirtualObjectManager.js +62 -0
- package/tools/fakeVirtualSupport.js +389 -0
- package/tools/prepare-strict-test-env.js +124 -0
- package/tools/prepare-test-env.js +13 -0
- package/tools/setup-vat-data.js +96 -0
- package/tools/vo-test-harness.js +143 -0
- package/CHANGELOG.md +0 -61
- package/test/kmarshal.js +0 -79
- package/test/test-handled-promises.js +0 -360
package/src/virtualReferences.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/* eslint-disable
|
|
1
|
+
/* eslint-disable jsdoc/require-returns-type */
|
|
2
2
|
|
|
3
|
-
import { assert, Fail } from '@
|
|
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 (
|
|
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
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
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
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
*
|
|
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
|
-
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
519
|
-
*
|
|
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'
|
|
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'
|
|
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
|
-
|
|
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 (
|
|
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) {
|
|
@@ -682,6 +740,54 @@ export function makeVirtualReferenceManager(
|
|
|
682
740
|
return size;
|
|
683
741
|
}
|
|
684
742
|
|
|
743
|
+
/**
|
|
744
|
+
* Counters to track the next number for various categories of allocation.
|
|
745
|
+
* `exportID` starts at 1 because 'o+0' is always automatically
|
|
746
|
+
* pre-assigned to the root object.
|
|
747
|
+
* `promiseID` starts at 5 as a very minor aid to debugging: when puzzling
|
|
748
|
+
* over trace logs and the like, it helps for the numbers in various species
|
|
749
|
+
* of IDs that are jumbled together to be a little out of sync and thus a
|
|
750
|
+
* little less similar to each other.
|
|
751
|
+
*/
|
|
752
|
+
const initialIDCounters = { exportID: 1, collectionID: 1, promiseID: 5 };
|
|
753
|
+
/** @type {Record<string, number>} */
|
|
754
|
+
let idCounters;
|
|
755
|
+
let idCountersAreDirty = false;
|
|
756
|
+
|
|
757
|
+
function initializeIDCounters() {
|
|
758
|
+
if (!idCounters) {
|
|
759
|
+
// the saved value might be missing, or from an older liveslots
|
|
760
|
+
// (with fewer counters), so merge it with our initial values
|
|
761
|
+
const saved = JSON.parse(syscall.vatstoreGet('idCounters') || '{}');
|
|
762
|
+
idCounters = { ...initialIDCounters, ...saved };
|
|
763
|
+
idCountersAreDirty = true;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
function allocateNextID(name) {
|
|
768
|
+
if (!idCounters) {
|
|
769
|
+
// Normally `initializeIDCounters` would be called from startVat, but some
|
|
770
|
+
// tests bypass that so this is a backstop. Note that the invocation from
|
|
771
|
+
// startVat is there to make vatStore access patterns a bit more
|
|
772
|
+
// consistent from one vat to another, principally as a confusion
|
|
773
|
+
// reduction measure in service of debugging; it is not a correctness
|
|
774
|
+
// issue.
|
|
775
|
+
initializeIDCounters();
|
|
776
|
+
}
|
|
777
|
+
const result = idCounters[name];
|
|
778
|
+
result !== undefined || Fail`unknown idCounters[${name}]`;
|
|
779
|
+
idCounters[name] += 1;
|
|
780
|
+
idCountersAreDirty = true;
|
|
781
|
+
return result;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function flushIDCounters() {
|
|
785
|
+
if (idCountersAreDirty) {
|
|
786
|
+
syscall.vatstoreSet('idCounters', JSON.stringify(idCounters));
|
|
787
|
+
idCountersAreDirty = false;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
685
791
|
const testHooks = {
|
|
686
792
|
getReachableRefCount,
|
|
687
793
|
countCollectionsForWeakKey,
|
|
@@ -726,6 +832,9 @@ export function makeVirtualReferenceManager(
|
|
|
726
832
|
ceaseRecognition,
|
|
727
833
|
setDeleteCollectionEntry,
|
|
728
834
|
getRetentionStats,
|
|
835
|
+
initializeIDCounters,
|
|
836
|
+
allocateNextID,
|
|
837
|
+
flushIDCounters,
|
|
729
838
|
testHooks,
|
|
730
839
|
});
|
|
731
840
|
}
|
package/src/watchedPromises.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
// no-lonely-if is a stupid rule that really should be disabled globally
|
|
2
3
|
/* eslint-disable no-lonely-if */
|
|
3
4
|
|
|
4
|
-
import { assert } from '@
|
|
5
|
-
import { initEmpty, M } from '@agoric/store';
|
|
5
|
+
import { Fail, assert } from '@endo/errors';
|
|
6
6
|
import { E } from '@endo/eventual-send';
|
|
7
|
+
import { initEmpty, M } from '@agoric/store';
|
|
7
8
|
import { parseVatSlot } from './parseVatSlots.js';
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @template V
|
|
12
|
+
* @template {any[]} [A=unknown[]]
|
|
13
|
+
* @typedef {[watcher: import('./types.js').PromiseWatcher<V, A>, ...args: A]} PromiseWatcherTuple
|
|
14
|
+
*/
|
|
15
|
+
|
|
9
16
|
/**
|
|
10
17
|
* @param {object} options
|
|
11
18
|
* @param {*} options.syscall
|
|
@@ -28,17 +35,28 @@ export function makeWatchedPromiseManager({
|
|
|
28
35
|
const { makeScalarBigMapStore } = collectionManager;
|
|
29
36
|
const { defineDurableKind } = vom;
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
/**
|
|
39
|
+
* virtual Store (not durable) mapping vpid to Promise objects, to
|
|
40
|
+
* maintain the slotToVal registration until resolution. Without
|
|
41
|
+
* this, slotToVal would forget local Promises that aren't exported.
|
|
42
|
+
*
|
|
43
|
+
* @type {MapStore<string, Promise<unknown>>}
|
|
44
|
+
*/
|
|
34
45
|
let promiseRegistrations;
|
|
35
46
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
/**
|
|
48
|
+
* watched promises by vpid: each entry is an array of watches on the
|
|
49
|
+
* corresponding vpid; each of these is in turn an array of a watcher object
|
|
50
|
+
* and the arguments associated with it by `watchPromise`.
|
|
51
|
+
* @type {MapStore<string, PromiseWatcherTuple<unknown>[]>}
|
|
52
|
+
*/
|
|
39
53
|
let watchedPromiseTable;
|
|
40
54
|
|
|
41
|
-
|
|
55
|
+
/**
|
|
56
|
+
* defined promise watcher objects indexed by kindHandle
|
|
57
|
+
*
|
|
58
|
+
* @type {MapStore<import('./vatDataTypes.js').DurableKindHandle, import('./types.js').PromiseWatcher<unknown>>}
|
|
59
|
+
*/
|
|
42
60
|
let promiseWatcherByKindTable;
|
|
43
61
|
|
|
44
62
|
function preparePromiseWatcherTables() {
|
|
@@ -73,11 +91,17 @@ export function makeWatchedPromiseManager({
|
|
|
73
91
|
}
|
|
74
92
|
|
|
75
93
|
/**
|
|
76
|
-
*
|
|
77
|
-
* @param {Promise<
|
|
94
|
+
* @template T
|
|
95
|
+
* @param {Promise<T>} p
|
|
78
96
|
* @param {string} vpid
|
|
97
|
+
* @returns {void}
|
|
79
98
|
*/
|
|
80
99
|
function pseudoThen(p, vpid) {
|
|
100
|
+
/**
|
|
101
|
+
*
|
|
102
|
+
* @param {T} value
|
|
103
|
+
* @param {boolean} wasFulfilled
|
|
104
|
+
*/
|
|
81
105
|
function settle(value, wasFulfilled) {
|
|
82
106
|
const watches = watchedPromiseTable.get(vpid);
|
|
83
107
|
watchedPromiseTable.delete(vpid);
|
|
@@ -115,26 +139,46 @@ export function makeWatchedPromiseManager({
|
|
|
115
139
|
*/
|
|
116
140
|
function loadWatchedPromiseTable(revivePromise) {
|
|
117
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
|
+
}
|
|
118
148
|
const p = revivePromise(vpid);
|
|
119
149
|
promiseRegistrations.init(vpid, p);
|
|
120
150
|
pseudoThen(p, vpid);
|
|
121
151
|
}
|
|
122
152
|
}
|
|
123
153
|
|
|
154
|
+
/**
|
|
155
|
+
* @template V
|
|
156
|
+
* @template {any[]} A]
|
|
157
|
+
* @param {import('./vatDataTypes.js').DurableKindHandle} kindHandle
|
|
158
|
+
* @param {(value: V, ...args: A) => void} fulfillHandler
|
|
159
|
+
* @param {(reason: any, ...args: A) => void} rejectHandler
|
|
160
|
+
* @returns {import('./types.js').PromiseWatcher<V, A>}
|
|
161
|
+
*/
|
|
124
162
|
function providePromiseWatcher(
|
|
125
163
|
kindHandle,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
164
|
+
// @ts-expect-error xxx rest params in typedef
|
|
165
|
+
fulfillHandler = _value => {
|
|
166
|
+
// It's fine to not pass the value through since promise watchers are not chainable
|
|
167
|
+
},
|
|
168
|
+
// @ts-expect-error xxx rest params in typedef
|
|
169
|
+
rejectHandler = reason => {
|
|
170
|
+
// Replicate the unhandled rejection that would have happened if the
|
|
171
|
+
// watcher had not implemented an `onRejected` method. See `settle` above
|
|
172
|
+
throw reason;
|
|
129
173
|
},
|
|
130
174
|
) {
|
|
131
175
|
assert.typeof(fulfillHandler, 'function');
|
|
132
176
|
assert.typeof(rejectHandler, 'function');
|
|
133
177
|
|
|
134
178
|
const makeWatcher = defineDurableKind(kindHandle, initEmpty, {
|
|
135
|
-
|
|
179
|
+
/** @type {(context: unknown, res: V, ...args: A) => void} */
|
|
136
180
|
onFulfilled: (_context, res, ...args) => fulfillHandler(res, ...args),
|
|
137
|
-
|
|
181
|
+
/** @type {(context: unknown, rej: unknown, ...args: A) => void} */
|
|
138
182
|
onRejected: (_context, rej, ...args) => rejectHandler(rej, ...args),
|
|
139
183
|
});
|
|
140
184
|
|
|
@@ -147,6 +191,9 @@ export function makeWatchedPromiseManager({
|
|
|
147
191
|
}
|
|
148
192
|
}
|
|
149
193
|
|
|
194
|
+
/**
|
|
195
|
+
* @type {<P extends Promise<any>, A extends any[]>(p: P, watcher: import('./types.js').PromiseWatcher<Awaited<P>, A>, ...args: A) => void}
|
|
196
|
+
*/
|
|
150
197
|
function watchPromise(p, watcher, ...args) {
|
|
151
198
|
// The following wrapping defers setting up the promise watcher itself to a
|
|
152
199
|
// later turn so that if the promise to be watched was the return value from
|
|
@@ -163,7 +210,10 @@ export function makeWatchedPromiseManager({
|
|
|
163
210
|
const watcherVref = convertValToSlot(watcher);
|
|
164
211
|
assert(watcherVref, 'invalid watcher');
|
|
165
212
|
const { virtual, durable } = parseVatSlot(watcherVref);
|
|
166
|
-
|
|
213
|
+
virtual ||
|
|
214
|
+
durable ||
|
|
215
|
+
// separate line so easy to breakpoint on
|
|
216
|
+
Fail`promise watcher must be a virtual object`;
|
|
167
217
|
if (watcher.onFulfilled) {
|
|
168
218
|
assert.typeof(watcher.onFulfilled, 'function');
|
|
169
219
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
-
import '@endo/init/debug.js';
|
|
3
2
|
|
|
4
3
|
import { Far } from '@endo/marshal';
|
|
4
|
+
import { kunser } from '@agoric/kmarshal';
|
|
5
5
|
import { setupTestLiveslots } from './liveslots-helpers.js';
|
|
6
6
|
import { vstr } from './util.js';
|
|
7
|
-
import { kunser } from './kmarshal.js';
|
|
8
7
|
import { parseVatSlot } from '../src/parseVatSlots.js';
|
|
9
8
|
|
|
10
9
|
function buildRootObject(vatPowers, vatParameters, baggage) {
|