diff --git a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectManager.js b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectManager.js index 4ac890b64cc..b369cc437ab 100644 --- a/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectManager.js +++ b/packages/swingset-liveslots/test/virtual-objects/test-virtualObjectManager.js @@ -587,12 +587,12 @@ test('durable kind IDs can be reanimated', t => { // Store it in the store without having used it placeToPutIt.init('savedKindID', kindHandle); - t.is(log.shift(), 'get vc.1.ssavedKindID => undefined'); + t.is(log.shift(), 'get vc.4.ssavedKindID => undefined'); t.is(log.shift(), `get vom.rc.${khid} => undefined`); t.is(log.shift(), `set vom.rc.${khid} 1`); - t.is(log.shift(), `set vc.1.ssavedKindID ${vstr(kind)}`); - t.is(log.shift(), 'get vc.1.|entryCount => 0'); - t.is(log.shift(), 'set vc.1.|entryCount 1'); + t.is(log.shift(), `set vc.4.ssavedKindID ${vstr(kind)}`); + t.is(log.shift(), 'get vc.4.|entryCount => 0'); + t.is(log.shift(), 'set vc.4.|entryCount 1'); t.deepEqual(log, []); // Forget its Representative @@ -606,7 +606,7 @@ test('durable kind IDs can be reanimated', t => { // Fetch it from the store, which should reanimate it const fetchedKindID = placeToPutIt.get('savedKindID'); - t.is(log.shift(), `get vc.1.ssavedKindID => ${vstr(kind)}`); + t.is(log.shift(), `get vc.4.ssavedKindID => ${vstr(kind)}`); t.is( log.shift(), 'get vom.dkind.10.descriptor => {"kindID":"10","tag":"testkind"}', @@ -654,9 +654,23 @@ test('virtual object gc', t => { ]; t.is(log.shift(), `get storeKindIDTable => undefined`); t.is(log.shift(), `set ${skit[0]} ${skit[1]}`); + t.is(log.shift(), 'set vc.1.|nextOrdinal 1'); + t.is(log.shift(), 'set vc.1.|entryCount 0'); + t.is(log.shift(), 'get watcherTableID => undefined'); + t.is(log.shift(), 'set vc.2.|nextOrdinal 1'); + t.is(log.shift(), 'set vc.2.|entryCount 0'); + t.is(log.shift(), 'set watcherTableID o+d6/2'); + t.is(log.shift(), 'get vom.rc.o+d6/2 => undefined'); + t.is(log.shift(), 'set vom.rc.o+d6/2 1'); + t.is(log.shift(), 'get watchedPromiseTableID => undefined'); + t.is(log.shift(), 'set vc.3.|nextOrdinal 1'); + t.is(log.shift(), 'set vc.3.|entryCount 0'); + t.is(log.shift(), 'set watchedPromiseTableID o+d6/3'); + t.is(log.shift(), 'get vom.rc.o+d6/3 => undefined'); + t.is(log.shift(), 'set vom.rc.o+d6/3 1'); t.is( log.shift(), - `set vom.vkind.10.descriptor {"kindID":"10","tag":"thing"}`, + 'set vom.vkind.10.descriptor {"kindID":"10","tag":"thing"}', ); t.is(log.shift(), `set vom.vkind.11.descriptor {"kindID":"11","tag":"ref"}`); t.deepEqual(log, []); @@ -682,6 +696,12 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.${tbase}/1`, minThing('thing #1')], [`vom.${tbase}/2`, minThing('thing #2')], [`vom.${tbase}/3`, minThing('thing #3')], @@ -691,8 +711,12 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); // This is what the finalizer would do if the local reference was dropped and GC'd @@ -718,6 +742,12 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.es.${tbase}/1`, 'r'], [`vom.${tbase}/1`, minThing('thing #1')], [`vom.${tbase}/2`, minThing('thing #2')], @@ -728,8 +758,12 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); // drop export -- should delete @@ -759,6 +793,12 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.${tbase}/2`, minThing('thing #2')], [`vom.${tbase}/3`, minThing('thing #3')], [`vom.${tbase}/4`, minThing('thing #4')], @@ -767,8 +807,12 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); // case 2: export, drop export, drop local ref @@ -786,6 +830,12 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.es.${tbase}/2`, 's'], [`vom.${tbase}/2`, minThing('thing #2')], [`vom.${tbase}/3`, minThing('thing #3')], @@ -795,8 +845,12 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); // drop local ref -- should delete @@ -817,6 +871,12 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.${tbase}/3`, minThing('thing #3')], [`vom.${tbase}/4`, minThing('thing #4')], [`vom.${tbase}/5`, minThing('thing #5')], @@ -824,8 +884,12 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); // case 3: drop local ref with no prior export @@ -847,14 +911,24 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.${tbase}/4`, minThing('thing #4')], [`vom.${tbase}/5`, minThing('thing #5')], [`vom.${tbase}/6`, minThing('thing #6')], [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); // case 4: ref virtually, export, drop local ref, drop export @@ -867,15 +941,25 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.${tbase}/4`, minThing('thing #4')], [`vom.${tbase}/5`, minThing('thing #5')], [`vom.${tbase}/6`, minThing('thing #6')], [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], [`vom.rc.${tbase}/4`, '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); // export setExportStatus(`${tbase}/4`, 'reachable'); @@ -909,6 +993,12 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.es.${tbase}/4`, 's'], [`vom.es.${tbase}/5`, 'r'], [`vom.${tbase}/4`, minThing('thing #4')], @@ -917,10 +1007,14 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], [`vom.rc.${tbase}/4`, '1'], [`vom.rc.${tbase}/5`, '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); // drop local ref -- should not delete because ref'd virtually AND exported pretendGC(`${tbase}/5`, false); @@ -944,6 +1038,12 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.es.${tbase}/4`, 's'], [`vom.es.${tbase}/5`, 's'], [`vom.${tbase}/4`, minThing('thing #4')], @@ -952,11 +1052,15 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], [`vom.rc.${tbase}/4`, '1'], [`vom.rc.${tbase}/5`, '1'], [`vom.rc.${tbase}/6`, '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); // drop local ref -- should not delete because ref'd virtually pretendGC(`${tbase}/6`, false); @@ -966,6 +1070,12 @@ test('virtual object gc', t => { t.deepEqual(dumpStore(), [ ['kindIDID', '1'], skit, + ['vc.1.|entryCount', '0'], + ['vc.1.|nextOrdinal', '1'], + ['vc.2.|entryCount', '0'], + ['vc.2.|nextOrdinal', '1'], + ['vc.3.|entryCount', '0'], + ['vc.3.|nextOrdinal', '1'], [`vom.es.${tbase}/4`, 's'], [`vom.es.${tbase}/5`, 's'], [`vom.${tbase}/4`, minThing('thing #4')], @@ -974,11 +1084,15 @@ test('virtual object gc', t => { [`vom.${tbase}/7`, minThing('thing #7')], [`vom.${tbase}/8`, minThing('thing #8')], [`vom.${tbase}/9`, minThing('thing #9')], + ['vom.rc.o+d6/2', '1'], + ['vom.rc.o+d6/3', '1'], [`vom.rc.${tbase}/4`, '1'], [`vom.rc.${tbase}/5`, '1'], [`vom.rc.${tbase}/6`, '1'], ['vom.vkind.10.descriptor', '{"kindID":"10","tag":"thing"}'], ['vom.vkind.11.descriptor', '{"kindID":"11","tag":"ref"}'], + ['watchedPromiseTableID', 'o+d6/3'], + ['watcherTableID', 'o+d6/2'], ]); }); diff --git a/packages/swingset-liveslots/tools/fakeVirtualSupport.js b/packages/swingset-liveslots/tools/fakeVirtualSupport.js index 6280ec6c6f5..ecf2eea18fa 100644 --- a/packages/swingset-liveslots/tools/fakeVirtualSupport.js +++ b/packages/swingset-liveslots/tools/fakeVirtualSupport.js @@ -2,8 +2,9 @@ /* eslint-disable max-classes-per-file */ import { makeMarshal } from '@endo/marshal'; import { assert } from '@agoric/assert'; -import { parseVatSlot } from '../src/parseVatSlots.js'; +import { isPromise } from '@endo/promise-kit'; +import { parseVatSlot } from '../src/parseVatSlots.js'; import { makeVirtualReferenceManager } from '../src/virtualReferences.js'; import { makeWatchedPromiseManager } from '../src/watchedPromises.js'; import { makeFakeVirtualObjectManager } from './fakeVirtualObjectManager.js'; @@ -158,6 +159,14 @@ export function makeFakeLiveSlotsStuff(options = {}) { return exportID; } + // different starting point for more distinct IDs + let nextPromiseID = 7; + function allocatePromiseID() { + const promiseID = nextPromiseID; + nextPromiseID += 1; + return promiseID; + } + let nextCollectionID = 1; function allocateCollectionID() { const collectionID = nextCollectionID; @@ -193,7 +202,9 @@ export function makeFakeLiveSlotsStuff(options = {}) { function convertValToSlot(val) { if (!valToSlot.has(val)) { - const slot = `o+${allocateExportID()}`; + const slot = isPromise(val) + ? `p+${allocatePromiseID()}` + : `o+${allocateExportID()}`; valToSlot.set(val, slot); setValForSlot(slot, val); } @@ -311,6 +322,7 @@ export function makeFakeWatchedPromiseManager( maybeExportPromise: fakeStuff.maybeExportPromise, }); } + /** * Configure virtual stuff with relaxed durability rules and fake liveslots * @@ -331,6 +343,7 @@ export function makeFakeVirtualStuff(options = {}) { fakeStuff.setVrm(vrm); const cm = makeFakeCollectionManager(vrm, fakeStuff, actualOptions); const wpm = makeFakeWatchedPromiseManager(vrm, vom, cm, fakeStuff); + wpm.preparePromiseWatcherTables(); return { fakeStuff, vrm, vom, cm, wpm }; }