-
Notifications
You must be signed in to change notification settings - Fork 244
/
emscripten.go
132 lines (117 loc) · 4.33 KB
/
emscripten.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Package emscripten contains Go-defined special functions imported by
// Emscripten under the module name "env".
//
// Emscripten has many imports which are triggered on build flags. Use
// FunctionExporter, instead of Instantiate, to define more "env" functions.
//
// # Relationship to WASI
//
// Emscripten typically requires wasi_snapshot_preview1 to implement exit.
//
// See wasi_snapshot_preview1.Instantiate and
// https://github.com/emscripten-core/emscripten/wiki/WebAssembly-Standalone
package emscripten
import (
"context"
"strings"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
internal "github.com/tetratelabs/wazero/internal/emscripten"
"github.com/tetratelabs/wazero/internal/wasm"
)
const i32 = wasm.ValueTypeI32
// MustInstantiate calls Instantiate or panics on error.
//
// This is a simpler function for those who know the module "env" is not
// already instantiated, and don't need to unload it.
//
// Deprecated: Due to Emscripten dynamic import generation, InstantiateForModule should be used instead.
func MustInstantiate(ctx context.Context, r wazero.Runtime) {
if _, err := Instantiate(ctx, r); err != nil {
panic(err)
}
}
// Instantiate instantiates the "env" module used by Emscripten into the
// runtime.
//
// # Notes
//
// - Failure cases are documented on wazero.Runtime InstantiateModule.
// - Closing the wazero.Runtime has the same effect as closing the result.
// - To add more functions to the "env" module, use FunctionExporter.
//
// Deprecated: Due to Emscripten dynamic import generation, InstantiateForModule should be used instead.
func Instantiate(ctx context.Context, r wazero.Runtime) (api.Closer, error) {
builder := r.NewHostModuleBuilder("env")
NewFunctionExporter().ExportFunctions(builder)
return builder.Instantiate(ctx)
}
// FunctionExporter configures the functions in the "env" module used by
// Emscripten.
//
// # Notes
//
// - This is an interface for decoupling, not third-party implementations.
// All implementations are in wazero.
type FunctionExporter interface {
// ExportFunctions builds functions to export with a wazero.HostModuleBuilder
// named "env".
ExportFunctions(wazero.HostModuleBuilder)
}
// NewFunctionExporter returns a FunctionExporter object with trace disabled.
// Deprecated: Due to Emscripten dynamic import generation, NewFunctionExporterForModule should be used instead.
func NewFunctionExporter() FunctionExporter {
return &functionExporter{}
}
type functionExporter struct{}
// ExportFunctions implements FunctionExporter.ExportFunctions
func (functionExporter) ExportFunctions(builder wazero.HostModuleBuilder) {
exporter := builder.(wasm.HostFuncExporter)
exporter.ExportHostFunc(internal.NotifyMemoryGrowth)
}
type emscriptenFns []*wasm.HostFunc
// InstantiateForModule instantiates a module named "env" populated with any
// known functions used in emscripten.
func InstantiateForModule(ctx context.Context, r wazero.Runtime, guest wazero.CompiledModule) (api.Closer, error) {
// Create the exporter for the supplied wasm
exporter, err := NewFunctionExporterForModule(guest)
if err != nil {
return nil, err
}
// Instantiate it!
env := r.NewHostModuleBuilder("env")
exporter.ExportFunctions(env)
return env.Instantiate(ctx)
}
// NewFunctionExporterForModule returns a guest-specific FunctionExporter,
// populated with any known functions used in emscripten.
func NewFunctionExporterForModule(guest wazero.CompiledModule) (FunctionExporter, error) {
ret := emscriptenFns{}
for _, fn := range guest.ImportedFunctions() {
importModule, importName, isImport := fn.Import()
if !isImport || importModule != "env" {
continue // not emscripten
}
if importName == internal.FunctionNotifyMemoryGrowth {
ret = append(ret, internal.NotifyMemoryGrowth)
continue
}
if importName == internal.FunctionThrowLongjmp {
ret = append(ret, internal.ThrowLongjmp)
continue
}
if !strings.HasPrefix(importName, internal.InvokePrefix) {
continue // not invoke, and maybe not emscripten
}
hf := internal.NewInvokeFunc(importName, fn.ParamTypes(), fn.ResultTypes())
ret = append(ret, hf)
}
return ret, nil
}
// ExportFunctions implements FunctionExporter.ExportFunctions
func (i emscriptenFns) ExportFunctions(builder wazero.HostModuleBuilder) {
exporter := builder.(wasm.HostFuncExporter)
for _, fn := range i {
exporter.ExportHostFunc(fn)
}
}