github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/examples/multiple-runtimes/counter.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	_ "embed"
     6  	"fmt"
     7  	"log"
     8  	"os"
     9  
    10  	wazero "github.com/wasilibs/wazerox"
    11  	"github.com/wasilibs/wazerox/api"
    12  )
    13  
    14  // counterWasm was generated by the following:
    15  //
    16  //	cd testdata; wat2wasm --debug-names counter.wat
    17  //
    18  //go:embed testdata/counter.wasm
    19  var counterWasm []byte
    20  
    21  // main shows how to share the same compilation cache across the multiple runtimes.
    22  func main() {
    23  	// Choose the context to use for function calls.
    24  	ctx := context.Background()
    25  
    26  	// Prepare a cache directory.
    27  	cacheDir, err := os.MkdirTemp("", "example")
    28  	if err != nil {
    29  		log.Panicln(err)
    30  	}
    31  	defer os.RemoveAll(cacheDir)
    32  
    33  	// Initializes the new compilation cache with the cache directory.
    34  	// This allows the compilation caches to be shared even across multiple OS processes.
    35  	cache, err := wazero.NewCompilationCacheWithDir(cacheDir)
    36  	if err != nil {
    37  		log.Panicln(err)
    38  	}
    39  	defer cache.Close(ctx)
    40  
    41  	// Creates a shared runtime config to share the cache across multiple wazero.Runtime.
    42  	runtimeConfig := wazero.NewRuntimeConfig().WithCompilationCache(cache)
    43  
    44  	// Creates two wazero.Runtimes with the same compilation cache.
    45  	runtimeFoo := wazero.NewRuntimeWithConfig(ctx, runtimeConfig)
    46  	runtimeBar := wazero.NewRuntimeWithConfig(ctx, runtimeConfig)
    47  
    48  	// Instantiate two modules on separate Runtimes with identical configuration, which allows each instance
    49  	// has the isolated states of "env" module.
    50  	m1 := instantiateWithEnv(ctx, runtimeFoo)
    51  	m2 := instantiateWithEnv(ctx, runtimeBar)
    52  
    53  	for i := 0; i < 2; i++ {
    54  		fmt.Printf("m1 counter=%d\n", counterGet(ctx, m1))
    55  		fmt.Printf("m2 counter=%d\n", counterGet(ctx, m2))
    56  	}
    57  }
    58  
    59  // count calls "counter.get" in the given namespace
    60  func counterGet(ctx context.Context, mod api.Module) uint64 {
    61  	results, err := mod.ExportedFunction("get").Call(ctx)
    62  	if err != nil {
    63  		log.Panicln(err)
    64  	}
    65  	return results[0]
    66  }
    67  
    68  // counter is an example showing state that needs to be independent per importing module.
    69  type counter struct {
    70  	counter uint32
    71  }
    72  
    73  func (e *counter) getAndIncrement() (ret uint32) {
    74  	ret = e.counter
    75  	e.counter++
    76  	return
    77  }
    78  
    79  // instantiateWithEnv returns a module instance.
    80  func instantiateWithEnv(ctx context.Context, r wazero.Runtime) api.Module {
    81  	// Instantiate a new "env" module which exports a stateful function.
    82  	c := &counter{}
    83  	_, err := r.NewHostModuleBuilder("env").
    84  		NewFunctionBuilder().WithFunc(c.getAndIncrement).Export("next_i32").
    85  		Instantiate(ctx)
    86  	if err != nil {
    87  		log.Panicln(err)
    88  	}
    89  
    90  	// Instantiate the module that imports "env".
    91  	mod, err := r.Instantiate(ctx, counterWasm)
    92  	if err != nil {
    93  		log.Panicln(err)
    94  	}
    95  	return mod
    96  }