From 125c42c7a74d09464619d1404dc203534f2c23ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sat, 27 Jul 2024 19:07:04 +0200 Subject: [PATCH] Add RegisterModule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some upstream (Hugo) benchmarks: ``` name old time/op new time/op delta KatexStartStop/PoolSize1-10 19.5ms ± 6% 19.4ms ± 3% ~ (p=1.000 n=4+4) KatexStartStop/PoolSize8-10 116ms ± 6% 55ms ± 3% -52.61% (p=0.029 n=4+4) KatexStartStop/PoolSize16-10 222ms ± 3% 95ms ± 6% -57.07% (p=0.029 n=4+4) name old alloc/op new alloc/op delta KatexStartStop/PoolSize1-10 12.2MB ± 0% 12.2MB ± 0% -0.22% (p=0.029 n=4+4) KatexStartStop/PoolSize8-10 97.9MB ± 0% 73.9MB ± 0% -24.46% (p=0.029 n=4+4) KatexStartStop/PoolSize16-10 196MB ± 0% 148MB ± 0% -24.15% (p=0.029 n=4+4) name old allocs/op new allocs/op delta KatexStartStop/PoolSize1-10 18.1k ± 0% 17.4k ± 0% -3.45% (p=0.029 n=4+4) KatexStartStop/PoolSize8-10 144k ± 0% 18k ± 0% -87.65% (p=0.029 n=4+4) KatexStartStop/PoolSize16-10 289k ± 0% 18k ± 0% -93.67% (p=0.029 n=4+4) ``` See #2293 --- internal/wasm/global_test.go | 2 +- internal/wasm/store.go | 19 +++++++++++++---- internal/wasm/store_module_list.go | 6 +++++- runtime.go | 34 +++++++++++++++++++++++++++++- 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/internal/wasm/global_test.go b/internal/wasm/global_test.go index da2d7a6d68..431f1880a3 100644 --- a/internal/wasm/global_test.go +++ b/internal/wasm/global_test.go @@ -341,7 +341,7 @@ func TestPublicModule_Global(t *testing.T) { s := newStore() t.Run(tc.name, func(t *testing.T) { // Instantiate the module and get the export of the above global - module, err := s.Instantiate(context.Background(), tc.module, t.Name(), nil, nil) + module, err := s.Instantiate(context.Background(), tc.module, t.Name(), nil, nil, nil) require.NoError(t, err) if global := module.ExportedGlobal("global"); tc.expected != nil { diff --git a/internal/wasm/store.go b/internal/wasm/store.go index 1db661e853..3e2656e6be 100644 --- a/internal/wasm/store.go +++ b/internal/wasm/store.go @@ -321,9 +321,10 @@ func (s *Store) Instantiate( name string, sys *internalsys.Context, typeIDs []FunctionTypeID, + lazyInstansiateImport func(moduleName string) (*ModuleInstance, error), ) (*ModuleInstance, error) { // Instantiate the module and add it to the store so that other modules can import it. - m, err := s.instantiate(ctx, module, name, sys, typeIDs) + m, err := s.instantiate(ctx, module, name, sys, typeIDs, lazyInstansiateImport) if err != nil { return nil, err } @@ -342,6 +343,7 @@ func (s *Store) instantiate( name string, sysCtx *internalsys.Context, typeIDs []FunctionTypeID, + lazyInstansiateImport func(moduleName string) (*ModuleInstance, error), ) (m *ModuleInstance, err error) { m = &ModuleInstance{ModuleName: name, TypeIDs: typeIDs, Sys: sysCtx, s: s, Source: module} @@ -352,7 +354,7 @@ func (s *Store) instantiate( return nil, err } - if err = m.resolveImports(module); err != nil { + if err = m.resolveImports(lazyInstansiateImport, module); err != nil { return nil, err } @@ -410,12 +412,21 @@ func (s *Store) instantiate( return } -func (m *ModuleInstance) resolveImports(module *Module) (err error) { +func (m *ModuleInstance) resolveImports(lazyInstansiateImport func(moduleName string) (*ModuleInstance, error), module *Module) (err error) { for moduleName, imports := range module.ImportPerModule { var importedModule *ModuleInstance importedModule, err = m.s.module(moduleName) if err != nil { - return err + if lazyInstansiateImport != nil { + importedModule, err = lazyInstansiateImport(moduleName) + // Add it to the store's module list so it can be closed. + /*if err = m.s.addToModuleList(importedModule); err != nil { + return + }*/ + } + if err != nil { + return err + } } for _, i := range imports { diff --git a/internal/wasm/store_module_list.go b/internal/wasm/store_module_list.go index ede3047deb..17baff71ad 100644 --- a/internal/wasm/store_module_list.go +++ b/internal/wasm/store_module_list.go @@ -68,7 +68,7 @@ func (s *Store) registerModule(m *ModuleInstance) error { if m.ModuleName != "" { if _, ok := s.nameToModule[m.ModuleName]; ok { - return fmt.Errorf("module[%s] has already been instantiated", m.ModuleName) + fmt.Errorf("module[%s] has already been instantiated", m.ModuleName) } s.nameToModule[m.ModuleName] = m if len(s.nameToModule) > s.nameToModuleCap { @@ -76,6 +76,10 @@ func (s *Store) registerModule(m *ModuleInstance) error { } } + return s.addToModuleList(m) +} + +func (s *Store) addToModuleList(m *ModuleInstance) error { // Add the newest node to the moduleNamesList as the head. m.next = s.moduleList if m.next != nil { diff --git a/runtime.go b/runtime.go index 34742289eb..b773a35ae5 100644 --- a/runtime.go +++ b/runtime.go @@ -69,6 +69,9 @@ type Runtime interface { // and/or compilation. InstantiateWithConfig(ctx context.Context, source []byte, config ModuleConfig) (api.Module, error) + // TODO1 + RegisterModule(ctx context.Context, name string, compiledModule CompiledModule) error + // NewHostModuleBuilder lets you create modules out of functions defined in Go. // // Below defines and instantiates a module named "env" with one function: @@ -162,6 +165,7 @@ func NewRuntimeWithConfig(ctx context.Context, rConfig RuntimeConfig) Runtime { return &runtime{ cache: cacheImpl, store: store, + namedCompiledModules: make(map[string]CompiledModule), enabledFeatures: config.enabledFeatures, memoryLimitPages: config.memoryLimitPages, memoryCapacityFromMax: config.memoryCapacityFromMax, @@ -181,6 +185,8 @@ type runtime struct { dwarfDisabled bool storeCustomSections bool + namedCompiledModules map[string]CompiledModule + // closed is the pointer used both to guard moduleEngine.CloseWithExitCode and to store the exit code. // // The update value is 1 + exitCode << 32. This ensures an exit code of zero isn't mistaken for never closed. @@ -192,6 +198,11 @@ type runtime struct { ensureTermination bool } +func (r *runtime) RegisterModule(ctx context.Context, name string, compiledModule CompiledModule) error { + r.namedCompiledModules[name] = compiledModule + return nil +} + // Module implements Runtime.Module. func (r *runtime) Module(moduleName string) api.Module { if len(moduleName) == 0 { @@ -314,8 +325,29 @@ func (r *runtime) InstantiateModule( name = code.module.NameSection.ModuleName } + var lazyInsansiateImport func(name string) (*wasm.ModuleInstance, error) + lazyInsansiateImport = func(name string) (*wasm.ModuleInstance, error) { + compiled, found := r.namedCompiledModules[name] + if !found { + return nil, fmt.Errorf("module[%s] not found", name) + } + code := compiled.(*compiledModule) + if sysCtx, err = config.toSysContext(); err != nil { + return nil, err + } + + mod, err = r.store.Instantiate(ctx, code.module, name, sysCtx, code.typeIDs, lazyInsansiateImport) + if err != nil { + if code.closeWithModule { + _ = code.Close(ctx) // don't overwrite the error + } + return nil, err + } + return mod.(*wasm.ModuleInstance), nil + } + // Instantiate the module. - mod, err = r.store.Instantiate(ctx, code.module, name, sysCtx, code.typeIDs) + mod, err = r.store.Instantiate(ctx, code.module, name, sysCtx, code.typeIDs, lazyInsansiateImport) if err != nil { // If there was an error, don't leak the compiled module. if code.closeWithModule {