From f5726a2abb362942119e64caa1150efbd03ea593 Mon Sep 17 00:00:00 2001 From: CharlesKWON Date: Tue, 16 Jun 2026 08:57:22 +0900 Subject: [PATCH] feat(hbrt): LibRegistrySnapshotAndDrain for VM pooling Returns the lib-module + dynamic-func registry and clears it, so the same symbol set can be installed into multiple VMs (a request pool). RegisterLibModules drains the global registry, which would otherwise leave only the first pooled VM with FN_HANDLE and the registered HB_FUNCs. Co-Authored-By: Claude Opus 4.8 (1M context) --- hbrt/vm.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/hbrt/vm.go b/hbrt/vm.go index 01b32b8..b4ac4dc 100644 --- a/hbrt/vm.go +++ b/hbrt/vm.go @@ -60,6 +60,23 @@ func RegisterDynamicFunc(name string, fn func(*Thread)) { libRegistryMu.Unlock() } +// LibRegistrySnapshotAndDrain returns the registered lib modules and dynamic +// functions and clears the global registry. Use to install the SAME symbol set +// into multiple VMs (a VM pool): snapshot once, then RegisterModule / +// RegisterSymbol into each VM. Modules hold only function pointers + metadata +// (per-VM mutable state — statics/threads/memvars — lives on the VM), so the +// same *Module is safe to share across VMs. Draining prevents VM.Run from +// re-registering libModules into whichever VM happens to run first. +func LibRegistrySnapshotAndDrain() ([]*Module, []Symbol) { + libRegistryMu.Lock() + defer libRegistryMu.Unlock() + mods := libModules + dyns := dynamicFuncs + libModules = nil + dynamicFuncs = nil + return mods, dyns +} + // RegisterLibModules registers any pending lib modules and dynamic functions. func (vm *VM) RegisterLibModules() { libRegistryMu.Lock()