@@ -307,25 +307,27 @@ export function makeState(syscall, identifierBase = 0) {
307
307
if ( mode === 'clist-import' || mode === 'data' ) {
308
308
const recognizable = changeRecognizable ( lref , - 1n ) ;
309
309
if ( ! recognizable ) {
310
- // maybeFree.add(lref);
310
+ maybeFree . add ( lref ) ;
311
311
}
312
312
}
313
313
if ( mode === 'data' ) {
314
314
const reachable = changeReachable ( lref , - 1n ) ;
315
315
if ( ! reachable ) {
316
- // maybeFree.add(lref);
316
+ maybeFree . add ( lref ) ;
317
317
}
318
318
}
319
319
}
320
320
}
321
321
322
322
/**
323
- * Delete any local promises that have zero references.
323
+ * Delete any local promises that have zero references. Return a list of
324
+ * work for unreachable/unrecognizable objects.
324
325
*
325
326
* Note that this should only be called *after* all work for a crank is done,
326
327
* because transient zero refCounts are possible during the middle of a crank.
327
328
*/
328
329
function processMaybeFree ( ) {
330
+ const actions = new Set ( ) ;
329
331
// We make a copy of the set, iterate over that, then try again, until
330
332
// the set is empty. TC39 went to a lot of trouble to make sure you can
331
333
// add things to a Set while iterating over it, but I think our
@@ -353,8 +355,44 @@ export function makeState(syscall, identifierBase = 0) {
353
355
}
354
356
}
355
357
}
358
+ if ( type === 'object' ) {
359
+ // don't do anything if importers can still reach it
360
+ const reaKey = `${ lref } .reachable` ;
361
+ const reachable = Nat ( BigInt ( store . getRequired ( reaKey ) ) ) ;
362
+ if ( ! reachable ) {
363
+ // the object is unreachable
364
+
365
+ // eslint-disable-next-line no-use-before-define
366
+ const { owner, isReachable, isRecognizable } = getOwnerAndStatus (
367
+ lref ,
368
+ ) ;
369
+ if ( isReachable ) {
370
+ // but the exporter doesn't realize it yet, so schedule a
371
+ // dropExport to them, which will clear the isReachable flag at
372
+ // the end of the turn
373
+ actions . add ( `${ owner } dropExport ${ lref } ` ) ;
374
+ }
375
+
376
+ const recKey = `${ lref } .recognizable` ;
377
+ const recognizable = Nat ( BigInt ( store . getRequired ( recKey ) ) ) ;
378
+ if ( ! recognizable && isRecognizable ) {
379
+ // all importers have given up, but the exporter is still
380
+ // exporting, so schedule a retireExport to them, which will
381
+ // delete the clist entry after it's translated.
382
+ actions . add ( `${ owner } retireExport ${ lref } ` ) ;
383
+ }
384
+ if ( ! isRecognizable ) {
385
+ // the exporter has given up, so tell all importers to give up
386
+ for ( const importer of getImporters ( lref ) ) {
387
+ actions . add ( `${ importer } retireImport ${ lref } ` ) ;
388
+ }
389
+ }
390
+ }
391
+ }
356
392
}
357
393
}
394
+
395
+ return actions ;
358
396
}
359
397
360
398
function mapFromKernel ( kfref ) {
@@ -482,6 +520,22 @@ export function makeState(syscall, identifierBase = 0) {
482
520
return lpid ;
483
521
}
484
522
523
+ function getOwnerAndStatus ( lref ) {
524
+ const owner = getObject ( lref ) ;
525
+ let isReachable ;
526
+ let isRecognizable ;
527
+ if ( owner === 'kernel' ) {
528
+ isReachable = isReachableByKernel ( lref ) ;
529
+ isRecognizable = ! ! mapToKernel ( lref ) ;
530
+ } else {
531
+ // eslint-disable-next-line no-use-before-define
532
+ const remote = getRemote ( owner ) ;
533
+ isReachable = remote . isReachable ( lref ) ;
534
+ isRecognizable = ! ! remote . mapToRemote ( lref ) ;
535
+ }
536
+ return { owner, isReachable, isRecognizable } ;
537
+ }
538
+
485
539
function deciderIsKernel ( lpid ) {
486
540
const decider = store . getRequired ( `${ lpid } .decider` ) ;
487
541
return decider === KERNEL ;
0 commit comments