wa-lang.org/wazero@v1.0.2/imports/go/gojs.go (about)

     1  // Package gojs allows you to run wasm binaries compiled by Go when `GOOS=js`
     2  // and `GOARCH=wasm`. See https://wazero.io/languages/go/ for more.
     3  //
     4  // # Experimental
     5  //
     6  // Go defines js "EXPERIMENTAL... exempt from the Go compatibility promise."
     7  // Accordingly, wazero cannot guarantee this will work from release to release,
     8  // or that usage will be relatively free of bugs. Due to this and the
     9  // relatively high implementation overhead, most will choose TinyGo instead.
    10  package gojs
    11  
    12  import (
    13  	"context"
    14  	"net/http"
    15  
    16  	"wa-lang.org/wazero"
    17  	. "wa-lang.org/wazero/internal/gojs"
    18  	"wa-lang.org/wazero/internal/wasm"
    19  )
    20  
    21  // WithRoundTripper sets the http.RoundTripper used to Run Wasm.
    22  //
    23  // For example, if the code compiled via `GOARCH=wasm GOOS=js` uses
    24  // http.RoundTripper, you can avoid failures by assigning an implementation
    25  // like so:
    26  //
    27  //	ctx = gojs.WithRoundTripper(ctx, http.DefaultTransport)
    28  //	err = gojs.Run(ctx, r, compiled, config)
    29  func WithRoundTripper(ctx context.Context, rt http.RoundTripper) context.Context {
    30  	return context.WithValue(ctx, RoundTripperKey{}, rt)
    31  }
    32  
    33  // Run instantiates a new module and calls "run" with the given config.
    34  //
    35  // # Parameters
    36  //
    37  //   - ctx: context to use when instantiating the module and calling "run".
    38  //   - r: runtime to instantiate both the host and guest (compiled) module in.
    39  //   - compiled: guest binary compiled with `GOARCH=wasm GOOS=js`
    40  //   - config: the configuration such as args, env or filesystem to use.
    41  //
    42  // # Example
    43  //
    44  // After compiling your Wasm binary with wazero.Runtime's `CompileModule`, run
    45  // it like below:
    46  //
    47  //	// Use compilation cache to reduce performance penalty of multiple runs.
    48  //	ctx = experimental.WithCompilationCacheDirName(ctx, ".build")
    49  //	// Execute the "run" function, which corresponds to "main" in stars/main.go.
    50  //	err = gojs.Run(ctx, r, compiled, config)
    51  //	if exitErr, ok := err.(*sys.ExitError); ok && exitErr.ExitCode() != 0 {
    52  //		log.Panicln(err)
    53  //	} else if !ok {
    54  //		log.Panicln(err)
    55  //	}
    56  //
    57  // # Notes
    58  //
    59  //   - Use wazero.RuntimeConfig `WithWasmCore2` to avoid needing to pick >1.0
    60  //     features set by `GOWASM` or used internally by Run.
    61  //   - Wasm generated by `GOARCH=wasm GOOS=js` is very slow to compile.
    62  //     Use experimental.WithCompilationCacheDirName to improve performance.
    63  //   - Both the host and guest module are closed after being run.
    64  func Run(ctx context.Context, r wazero.Runtime, compiled wazero.CompiledModule, config wazero.ModuleConfig) error {
    65  	// Instantiate the imports needed by go-compiled wasm.
    66  	js, err := hostModuleBuilder(r).Instantiate(ctx, r)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	defer js.Close(ctx)
    71  
    72  	// Instantiate the module compiled by go, noting it has no init function.
    73  	mod, err := r.InstantiateModule(ctx, compiled, config)
    74  	if err != nil {
    75  		return err
    76  	}
    77  	defer mod.Close(ctx)
    78  
    79  	// Extract the args and env from the module config and write it to memory.
    80  	ctx = WithState(ctx)
    81  	argc, argv, err := WriteArgsAndEnviron(ctx, mod)
    82  	if err != nil {
    83  		return err
    84  	}
    85  	// Invoke the run function.
    86  	_, err = mod.ExportedFunction("run").Call(ctx, uint64(argc), uint64(argv))
    87  	return err
    88  }
    89  
    90  // hostModuleBuilder returns a new wazero.HostModuleBuilder
    91  func hostModuleBuilder(r wazero.Runtime) (builder wazero.HostModuleBuilder) {
    92  	builder = r.NewHostModuleBuilder("go")
    93  	hfExporter := builder.(wasm.HostFuncExporter)
    94  	pfExporter := builder.(wasm.ProxyFuncExporter)
    95  
    96  	pfExporter.ExportProxyFunc(GetRandomData)
    97  	pfExporter.ExportProxyFunc(Nanotime1)
    98  	pfExporter.ExportProxyFunc(WasmExit)
    99  	pfExporter.ExportProxyFunc(CopyBytesToJS)
   100  	pfExporter.ExportProxyFunc(ValueCall)
   101  	pfExporter.ExportProxyFunc(ValueGet)
   102  	pfExporter.ExportProxyFunc(ValueIndex)
   103  	pfExporter.ExportProxyFunc(ValueLength)
   104  	pfExporter.ExportProxyFunc(ValueNew)
   105  	pfExporter.ExportProxyFunc(ValueSet)
   106  	pfExporter.ExportProxyFunc(WasmWrite)
   107  	hfExporter.ExportHostFunc(ResetMemoryDataView)
   108  	pfExporter.ExportProxyFunc(Walltime)
   109  	hfExporter.ExportHostFunc(ScheduleTimeoutEvent)
   110  	hfExporter.ExportHostFunc(ClearTimeoutEvent)
   111  	pfExporter.ExportProxyFunc(FinalizeRef)
   112  	pfExporter.ExportProxyFunc(StringVal)
   113  	hfExporter.ExportHostFunc(ValueDelete)
   114  	hfExporter.ExportHostFunc(ValueSetIndex)
   115  	hfExporter.ExportHostFunc(ValueInvoke)
   116  	pfExporter.ExportProxyFunc(ValuePrepareString)
   117  	hfExporter.ExportHostFunc(ValueInstanceOf)
   118  	pfExporter.ExportProxyFunc(ValueLoadString)
   119  	pfExporter.ExportProxyFunc(CopyBytesToGo)
   120  	hfExporter.ExportHostFunc(Debug)
   121  	return
   122  }