{"version":3,"file":"gc.cjs","sourceRoot":"","sources":["../../../src/store/methods/gc.ts"],"names":[],"mappings":"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","sourcesContent":["import { Fail } from '@endo/errors';\n\nimport { getBaseMethods } from './base.ts';\nimport { getObjectMethods } from './object.ts';\nimport { getPromiseMethods } from './promise.ts';\nimport { getReachableMethods } from './reachable.ts';\nimport { getRefCountMethods } from './refcount.ts';\nimport { getSubclusterMethods } from './subclusters.ts';\nimport { getVatMethods } from './vat.ts';\nimport type {\n  VatId,\n  KRef,\n  GCAction,\n  RunQueueItemBringOutYourDead,\n} from '../../types.ts';\nimport { insistGCActionType, insistVatId } from '../../types.ts';\nimport type { StoreContext } from '../types.ts';\nimport { insistKernelType, parseKernelSlot } from '../utils/kernel-slots.ts';\n\n/**\n * Create a store for garbage collection.\n *\n * @param ctx - The store context.\n * @returns The GC store.\n */\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nexport function getGCMethods(ctx: StoreContext) {\n  const { getSlotKey, getOwnerKey } = getBaseMethods(ctx.kv);\n  const { getRefCount, decrementRefCount } = getRefCountMethods(ctx);\n  const { getObjectRefCount, deleteKernelObject } = getObjectMethods(ctx);\n  const { getKernelPromise, deleteKernelPromise } = getPromiseMethods(ctx);\n  const { getImporters, isVatTerminated } = getVatMethods(ctx);\n  const { getReachableFlag, getReachableAndVatSlot } = getReachableMethods(ctx);\n  const { clearEmptySubclusters } = getSubclusterMethods(ctx);\n\n  /**\n   * Get the set of GC actions to perform.\n   *\n   * @returns The set of GC actions to perform.\n   */\n  function getGCActions(): Set<GCAction> {\n    return new Set(JSON.parse(ctx.gcActions.get() ?? '[]'));\n  }\n\n  /**\n   * Set the set of GC actions to perform.\n   *\n   * @param actions - The set of GC actions to perform.\n   */\n  function setGCActions(actions: Set<GCAction>): void {\n    const a = Array.from(actions);\n    a.sort();\n    ctx.gcActions.set(JSON.stringify(a));\n  }\n\n  /**\n   * Add a new GC action to the set of GC actions to perform.\n   *\n   * @param newActions - The new GC action to add.\n   */\n  function addGCActions(newActions: GCAction[]): void {\n    const actions = getGCActions();\n    for (const action of newActions) {\n      assert.typeof(action, 'string', 'addGCActions given bad action');\n      const [vatId, type, kref] = action.split(' ');\n      insistVatId(vatId);\n      insistGCActionType(type);\n      insistKernelType('object', kref);\n      actions.add(action);\n    }\n    setGCActions(actions);\n  }\n\n  /**\n   * Schedule a vat for reaping.\n   *\n   * @param vatId - The vat to schedule for reaping.\n   */\n  function scheduleReap(vatId: VatId): void {\n    const queue = JSON.parse(ctx.reapQueue.get() ?? '[]');\n    if (!queue.includes(vatId)) {\n      queue.push(vatId);\n      ctx.reapQueue.set(JSON.stringify(queue));\n    }\n  }\n\n  /**\n   * Get the next reap action.\n   *\n   * @returns The next reap action, or undefined if the queue is empty.\n   */\n  function nextReapAction(): RunQueueItemBringOutYourDead | undefined {\n    const queue = JSON.parse(ctx.reapQueue.get() ?? '[]');\n    if (queue.length > 0) {\n      const vatId = queue.shift();\n      ctx.reapQueue.set(JSON.stringify(queue));\n      return harden({ type: 'bringOutYourDead', vatId });\n    }\n    return undefined;\n  }\n\n  /**\n   * Retires kernel objects by notifying importers and removing the objects.\n   *\n   * @param koids - Array of kernel object IDs to retire.\n   */\n  function retireKernelObjects(koids: KRef[]): void {\n    Array.isArray(koids) || Fail`retireExports given non-Array ${koids}`;\n    const newActions: GCAction[] = [];\n    for (const koid of koids) {\n      const importers = getImporters(koid);\n      for (const vatID of importers) {\n        newActions.push(`${vatID} retireImport ${koid}`);\n      }\n      deleteKernelObject(koid);\n    }\n    addGCActions(newActions);\n  }\n\n  /**\n   * Processes reference counts for kernel resources and performs garbage collection actions\n   * for resources that are no longer referenced or should be retired.\n   */\n  function collectGarbage(): void {\n    const actions: Set<GCAction> = new Set();\n    for (const kref of ctx.maybeFreeKrefs.values()) {\n      const { type } = parseKernelSlot(kref);\n      if (type === 'promise') {\n        const kpid = kref;\n        const kp = getKernelPromise(kpid);\n        const refCount = getRefCount(kpid);\n        if (refCount === 0) {\n          if (kp.state === 'fulfilled' || kp.state === 'rejected') {\n            // https://github.com/Agoric/agoric-sdk/issues/9888 don't assume promise is settled\n            for (const slot of kp.value?.slots ?? []) {\n              // Note: the following decrement can result in an addition to the\n              // maybeFreeKrefs set, which we are in the midst of iterating.\n              // TC39 went to a lot of trouble to ensure that this is kosher.\n              decrementRefCount(slot, 'gc|promise|slot');\n            }\n          }\n          deleteKernelPromise(kpid);\n        }\n      }\n\n      if (type === 'object') {\n        const { reachable, recognizable } = getObjectRefCount(kref);\n        if (reachable === 0) {\n          const ownerKey = getOwnerKey(kref);\n          let ownerVatID = ctx.kv.get(ownerKey);\n          const terminated = isVatTerminated(ownerVatID as VatId);\n\n          // Some objects that are still owned, but the owning vat\n          // might still alive, or might be terminated and in the\n          // process of being deleted. These two clauses are\n          // mutually exclusive.\n          if (ownerVatID && !terminated) {\n            const vatConsidersReachable = getReachableFlag(ownerVatID, kref);\n            if (vatConsidersReachable) {\n              // the reachable count is zero, but the vat doesn't realize it\n              actions.add(`${ownerVatID} dropExport ${kref}`);\n            }\n            if (recognizable === 0) {\n              // TODO: rethink this assert\n              // assert.equal(vatConsidersReachable, false, `${kref} is reachable but not recognizable`);\n              actions.add(`${ownerVatID} retireExport ${kref}`);\n            }\n          } else if (ownerVatID && terminated) {\n            // When we're slowly deleting a vat, and one of its\n            // exports becomes unreferenced, we obviously must not\n            // send dropExports or retireExports into the dead vat.\n            // We fast-forward the abandonment that slow-deletion\n            // would have done, then treat the object as orphaned.\n\n            const { vatSlot } = getReachableAndVatSlot(ownerVatID, kref);\n            // delete directly, not orphanKernelObject(), which\n            // would re-submit to maybeFreeKrefs\n            ctx.kv.delete(ownerKey);\n            ctx.kv.delete(getSlotKey(ownerVatID, kref));\n            ctx.kv.delete(getSlotKey(ownerVatID, vatSlot));\n            // now fall through to the orphaned case\n            ownerVatID = undefined;\n          }\n\n          // Now handle objects which were orphaned. NOTE: this\n          // includes objects which were owned by a terminated (but\n          // not fully deleted) vat, where `ownerVatID` was cleared\n          // in the last line of that previous clause (the\n          // fall-through case). Don't try to change this `if\n          // (!ownerVatID)` into an `else if`: the two clauses are\n          // *not* mutually-exclusive.\n          if (!ownerVatID) {\n            // orphaned and unreachable, so retire it. If the kref\n            // is recognizable, then we need retireKernelObjects()\n            // to scan for importers and send retireImports (and\n            // delete), else we can call deleteKernelObject directly\n            if (recognizable) {\n              retireKernelObjects([kref]);\n            } else {\n              deleteKernelObject(kref);\n            }\n          }\n        }\n      }\n    }\n    addGCActions([...actions]);\n    ctx.maybeFreeKrefs.clear();\n    clearEmptySubclusters();\n  }\n\n  return {\n    getGCActions,\n    setGCActions,\n    addGCActions,\n    scheduleReap,\n    nextReapAction,\n    retireKernelObjects,\n    collectGarbage,\n  };\n}\n"]}