summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/engine.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/engine.go')
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/engine.go843
1 files changed, 0 insertions, 843 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/engine.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/engine.go
deleted file mode 100644
index a6df3e7e7..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/engine.go
+++ /dev/null
@@ -1,843 +0,0 @@
-package wazevo
-
-import (
- "context"
- "encoding/hex"
- "errors"
- "fmt"
- "runtime"
- "sort"
- "sync"
- "unsafe"
-
- "github.com/tetratelabs/wazero/api"
- "github.com/tetratelabs/wazero/experimental"
- "github.com/tetratelabs/wazero/internal/engine/wazevo/backend"
- "github.com/tetratelabs/wazero/internal/engine/wazevo/frontend"
- "github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
- "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
- "github.com/tetratelabs/wazero/internal/filecache"
- "github.com/tetratelabs/wazero/internal/platform"
- "github.com/tetratelabs/wazero/internal/version"
- "github.com/tetratelabs/wazero/internal/wasm"
-)
-
-type (
- // engine implements wasm.Engine.
- engine struct {
- wazeroVersion string
- fileCache filecache.Cache
- compiledModules map[wasm.ModuleID]*compiledModule
- // sortedCompiledModules is a list of compiled modules sorted by the initial address of the executable.
- sortedCompiledModules []*compiledModule
- mux sync.RWMutex
- // sharedFunctions is compiled functions shared by all modules.
- sharedFunctions *sharedFunctions
- // setFinalizer defaults to runtime.SetFinalizer, but overridable for tests.
- setFinalizer func(obj interface{}, finalizer interface{})
-
- // The followings are reused for compiling shared functions.
- machine backend.Machine
- be backend.Compiler
- }
-
- sharedFunctions struct {
- // memoryGrowExecutable is a compiled trampoline executable for memory.grow builtin function.
- memoryGrowExecutable []byte
- // checkModuleExitCode is a compiled trampoline executable for checking module instance exit code. This
- // is used when ensureTermination is true.
- checkModuleExitCode []byte
- // stackGrowExecutable is a compiled executable for growing stack builtin function.
- stackGrowExecutable []byte
- // tableGrowExecutable is a compiled trampoline executable for table.grow builtin function.
- tableGrowExecutable []byte
- // refFuncExecutable is a compiled trampoline executable for ref.func builtin function.
- refFuncExecutable []byte
- // memoryWait32Executable is a compiled trampoline executable for memory.wait32 builtin function
- memoryWait32Executable []byte
- // memoryWait64Executable is a compiled trampoline executable for memory.wait64 builtin function
- memoryWait64Executable []byte
- // memoryNotifyExecutable is a compiled trampoline executable for memory.notify builtin function
- memoryNotifyExecutable []byte
- listenerBeforeTrampolines map[*wasm.FunctionType][]byte
- listenerAfterTrampolines map[*wasm.FunctionType][]byte
- }
-
- // compiledModule is a compiled variant of a wasm.Module and ready to be used for instantiation.
- compiledModule struct {
- *executables
- // functionOffsets maps a local function index to the offset in the executable.
- functionOffsets []int
- parent *engine
- module *wasm.Module
- ensureTermination bool
- listeners []experimental.FunctionListener
- listenerBeforeTrampolines []*byte
- listenerAfterTrampolines []*byte
-
- // The followings are only available for non host modules.
-
- offsets wazevoapi.ModuleContextOffsetData
- sharedFunctions *sharedFunctions
- sourceMap sourceMap
- }
-
- executables struct {
- executable []byte
- entryPreambles [][]byte
- }
-)
-
-// sourceMap is a mapping from the offset of the executable to the offset of the original wasm binary.
-type sourceMap struct {
- // executableOffsets is a sorted list of offsets of the executable. This is index-correlated with wasmBinaryOffsets,
- // in other words executableOffsets[i] is the offset of the executable which corresponds to the offset of a Wasm
- // binary pointed by wasmBinaryOffsets[i].
- executableOffsets []uintptr
- // wasmBinaryOffsets is the counterpart of executableOffsets.
- wasmBinaryOffsets []uint64
-}
-
-var _ wasm.Engine = (*engine)(nil)
-
-// NewEngine returns the implementation of wasm.Engine.
-func NewEngine(ctx context.Context, _ api.CoreFeatures, fc filecache.Cache) wasm.Engine {
- machine := newMachine()
- be := backend.NewCompiler(ctx, machine, ssa.NewBuilder())
- e := &engine{
- compiledModules: make(map[wasm.ModuleID]*compiledModule),
- setFinalizer: runtime.SetFinalizer,
- machine: machine,
- be: be,
- fileCache: fc,
- wazeroVersion: version.GetWazeroVersion(),
- }
- e.compileSharedFunctions()
- return e
-}
-
-// CompileModule implements wasm.Engine.
-func (e *engine) CompileModule(ctx context.Context, module *wasm.Module, listeners []experimental.FunctionListener, ensureTermination bool) (err error) {
- if wazevoapi.PerfMapEnabled {
- wazevoapi.PerfMap.Lock()
- defer wazevoapi.PerfMap.Unlock()
- }
-
- if _, ok, err := e.getCompiledModule(module, listeners, ensureTermination); ok { // cache hit!
- return nil
- } else if err != nil {
- return err
- }
-
- if wazevoapi.DeterministicCompilationVerifierEnabled {
- ctx = wazevoapi.NewDeterministicCompilationVerifierContext(ctx, len(module.CodeSection))
- }
- cm, err := e.compileModule(ctx, module, listeners, ensureTermination)
- if err != nil {
- return err
- }
- if err = e.addCompiledModule(module, cm); err != nil {
- return err
- }
-
- if wazevoapi.DeterministicCompilationVerifierEnabled {
- for i := 0; i < wazevoapi.DeterministicCompilationVerifyingIter; i++ {
- _, err := e.compileModule(ctx, module, listeners, ensureTermination)
- if err != nil {
- return err
- }
- }
- }
-
- if len(listeners) > 0 {
- cm.listeners = listeners
- cm.listenerBeforeTrampolines = make([]*byte, len(module.TypeSection))
- cm.listenerAfterTrampolines = make([]*byte, len(module.TypeSection))
- for i := range module.TypeSection {
- typ := &module.TypeSection[i]
- before, after := e.getListenerTrampolineForType(typ)
- cm.listenerBeforeTrampolines[i] = before
- cm.listenerAfterTrampolines[i] = after
- }
- }
- return nil
-}
-
-func (exec *executables) compileEntryPreambles(m *wasm.Module, machine backend.Machine, be backend.Compiler) {
- exec.entryPreambles = make([][]byte, len(m.TypeSection))
- for i := range m.TypeSection {
- typ := &m.TypeSection[i]
- sig := frontend.SignatureForWasmFunctionType(typ)
- be.Init()
- buf := machine.CompileEntryPreamble(&sig)
- executable := mmapExecutable(buf)
- exec.entryPreambles[i] = executable
-
- if wazevoapi.PerfMapEnabled {
- wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&executable[0])),
- uint64(len(executable)), fmt.Sprintf("entry_preamble::type=%s", typ.String()))
- }
- }
-}
-
-func (e *engine) compileModule(ctx context.Context, module *wasm.Module, listeners []experimental.FunctionListener, ensureTermination bool) (*compiledModule, error) {
- withListener := len(listeners) > 0
- cm := &compiledModule{
- offsets: wazevoapi.NewModuleContextOffsetData(module, withListener), parent: e, module: module,
- ensureTermination: ensureTermination,
- executables: &executables{},
- }
-
- if module.IsHostModule {
- return e.compileHostModule(ctx, module, listeners)
- }
-
- importedFns, localFns := int(module.ImportFunctionCount), len(module.FunctionSection)
- if localFns == 0 {
- return cm, nil
- }
-
- rels := make([]backend.RelocationInfo, 0)
- refToBinaryOffset := make([]int, importedFns+localFns)
-
- if wazevoapi.DeterministicCompilationVerifierEnabled {
- // The compilation must be deterministic regardless of the order of functions being compiled.
- wazevoapi.DeterministicCompilationVerifierRandomizeIndexes(ctx)
- }
-
- needSourceInfo := module.DWARFLines != nil
-
- // Creates new compiler instances which are reused for each function.
- ssaBuilder := ssa.NewBuilder()
- fe := frontend.NewFrontendCompiler(module, ssaBuilder, &cm.offsets, ensureTermination, withListener, needSourceInfo)
- machine := newMachine()
- be := backend.NewCompiler(ctx, machine, ssaBuilder)
-
- cm.executables.compileEntryPreambles(module, machine, be)
-
- totalSize := 0 // Total binary size of the executable.
- cm.functionOffsets = make([]int, localFns)
- bodies := make([][]byte, localFns)
-
- // Trampoline relocation related variables.
- trampolineInterval, callTrampolineIslandSize, err := machine.CallTrampolineIslandInfo(localFns)
- if err != nil {
- return nil, err
- }
- needCallTrampoline := callTrampolineIslandSize > 0
- var callTrampolineIslandOffsets []int // Holds the offsets of trampoline islands.
-
- for i := range module.CodeSection {
- if wazevoapi.DeterministicCompilationVerifierEnabled {
- i = wazevoapi.DeterministicCompilationVerifierGetRandomizedLocalFunctionIndex(ctx, i)
- }
-
- fidx := wasm.Index(i + importedFns)
-
- if wazevoapi.NeedFunctionNameInContext {
- def := module.FunctionDefinition(fidx)
- name := def.DebugName()
- if len(def.ExportNames()) > 0 {
- name = def.ExportNames()[0]
- }
- ctx = wazevoapi.SetCurrentFunctionName(ctx, i, fmt.Sprintf("[%d/%d]%s", i, len(module.CodeSection)-1, name))
- }
-
- needListener := len(listeners) > 0 && listeners[i] != nil
- body, relsPerFunc, err := e.compileLocalWasmFunction(ctx, module, wasm.Index(i), fe, ssaBuilder, be, needListener)
- if err != nil {
- return nil, fmt.Errorf("compile function %d/%d: %v", i, len(module.CodeSection)-1, err)
- }
-
- // Align 16-bytes boundary.
- totalSize = (totalSize + 15) &^ 15
- cm.functionOffsets[i] = totalSize
-
- if needSourceInfo {
- // At the beginning of the function, we add the offset of the function body so that
- // we can resolve the source location of the call site of before listener call.
- cm.sourceMap.executableOffsets = append(cm.sourceMap.executableOffsets, uintptr(totalSize))
- cm.sourceMap.wasmBinaryOffsets = append(cm.sourceMap.wasmBinaryOffsets, module.CodeSection[i].BodyOffsetInCodeSection)
-
- for _, info := range be.SourceOffsetInfo() {
- cm.sourceMap.executableOffsets = append(cm.sourceMap.executableOffsets, uintptr(totalSize)+uintptr(info.ExecutableOffset))
- cm.sourceMap.wasmBinaryOffsets = append(cm.sourceMap.wasmBinaryOffsets, uint64(info.SourceOffset))
- }
- }
-
- fref := frontend.FunctionIndexToFuncRef(fidx)
- refToBinaryOffset[fref] = totalSize
-
- // At this point, relocation offsets are relative to the start of the function body,
- // so we adjust it to the start of the executable.
- for _, r := range relsPerFunc {
- r.Offset += int64(totalSize)
- rels = append(rels, r)
- }
-
- bodies[i] = body
- totalSize += len(body)
- if wazevoapi.PrintMachineCodeHexPerFunction {
- fmt.Printf("[[[machine code for %s]]]\n%s\n\n", wazevoapi.GetCurrentFunctionName(ctx), hex.EncodeToString(body))
- }
-
- if needCallTrampoline {
- // If the total size exceeds the trampoline interval, we need to add a trampoline island.
- if totalSize/trampolineInterval > len(callTrampolineIslandOffsets) {
- callTrampolineIslandOffsets = append(callTrampolineIslandOffsets, totalSize)
- totalSize += callTrampolineIslandSize
- }
- }
- }
-
- // Allocate executable memory and then copy the generated machine code.
- executable, err := platform.MmapCodeSegment(totalSize)
- if err != nil {
- panic(err)
- }
- cm.executable = executable
-
- for i, b := range bodies {
- offset := cm.functionOffsets[i]
- copy(executable[offset:], b)
- }
-
- if wazevoapi.PerfMapEnabled {
- wazevoapi.PerfMap.Flush(uintptr(unsafe.Pointer(&executable[0])), cm.functionOffsets)
- }
-
- if needSourceInfo {
- for i := range cm.sourceMap.executableOffsets {
- cm.sourceMap.executableOffsets[i] += uintptr(unsafe.Pointer(&cm.executable[0]))
- }
- }
-
- // Resolve relocations for local function calls.
- if len(rels) > 0 {
- machine.ResolveRelocations(refToBinaryOffset, importedFns, executable, rels, callTrampolineIslandOffsets)
- }
-
- if runtime.GOARCH == "arm64" {
- // On arm64, we cannot give all of rwx at the same time, so we change it to exec.
- if err = platform.MprotectRX(executable); err != nil {
- return nil, err
- }
- }
- cm.sharedFunctions = e.sharedFunctions
- e.setFinalizer(cm.executables, executablesFinalizer)
- return cm, nil
-}
-
-func (e *engine) compileLocalWasmFunction(
- ctx context.Context,
- module *wasm.Module,
- localFunctionIndex wasm.Index,
- fe *frontend.Compiler,
- ssaBuilder ssa.Builder,
- be backend.Compiler,
- needListener bool,
-) (body []byte, rels []backend.RelocationInfo, err error) {
- typIndex := module.FunctionSection[localFunctionIndex]
- typ := &module.TypeSection[typIndex]
- codeSeg := &module.CodeSection[localFunctionIndex]
-
- // Initializes both frontend and backend compilers.
- fe.Init(localFunctionIndex, typIndex, typ, codeSeg.LocalTypes, codeSeg.Body, needListener, codeSeg.BodyOffsetInCodeSection)
- be.Init()
-
- // Lower Wasm to SSA.
- fe.LowerToSSA()
- if wazevoapi.PrintSSA && wazevoapi.PrintEnabledIndex(ctx) {
- fmt.Printf("[[[SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
- }
-
- if wazevoapi.DeterministicCompilationVerifierEnabled {
- wazevoapi.VerifyOrSetDeterministicCompilationContextValue(ctx, "SSA", ssaBuilder.Format())
- }
-
- // Run SSA-level optimization passes.
- ssaBuilder.RunPasses()
-
- if wazevoapi.PrintOptimizedSSA && wazevoapi.PrintEnabledIndex(ctx) {
- fmt.Printf("[[[Optimized SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
- }
-
- if wazevoapi.DeterministicCompilationVerifierEnabled {
- wazevoapi.VerifyOrSetDeterministicCompilationContextValue(ctx, "Optimized SSA", ssaBuilder.Format())
- }
-
- // Now our ssaBuilder contains the necessary information to further lower them to
- // machine code.
- original, rels, err := be.Compile(ctx)
- if err != nil {
- return nil, nil, fmt.Errorf("ssa->machine code: %v", err)
- }
-
- // TODO: optimize as zero copy.
- copied := make([]byte, len(original))
- copy(copied, original)
- return copied, rels, nil
-}
-
-func (e *engine) compileHostModule(ctx context.Context, module *wasm.Module, listeners []experimental.FunctionListener) (*compiledModule, error) {
- machine := newMachine()
- be := backend.NewCompiler(ctx, machine, ssa.NewBuilder())
-
- num := len(module.CodeSection)
- cm := &compiledModule{module: module, listeners: listeners, executables: &executables{}}
- cm.functionOffsets = make([]int, num)
- totalSize := 0 // Total binary size of the executable.
- bodies := make([][]byte, num)
- var sig ssa.Signature
- for i := range module.CodeSection {
- totalSize = (totalSize + 15) &^ 15
- cm.functionOffsets[i] = totalSize
-
- typIndex := module.FunctionSection[i]
- typ := &module.TypeSection[typIndex]
-
- // We can relax until the index fits together in ExitCode as we do in wazevoapi.ExitCodeCallGoModuleFunctionWithIndex.
- // However, 1 << 16 should be large enough for a real use case.
- const hostFunctionNumMaximum = 1 << 16
- if i >= hostFunctionNumMaximum {
- return nil, fmt.Errorf("too many host functions (maximum %d)", hostFunctionNumMaximum)
- }
-
- sig.ID = ssa.SignatureID(typIndex) // This is important since we reuse the `machine` which caches the ABI based on the SignatureID.
- sig.Params = append(sig.Params[:0],
- ssa.TypeI64, // First argument must be exec context.
- ssa.TypeI64, // The second argument is the moduleContextOpaque of this host module.
- )
- for _, t := range typ.Params {
- sig.Params = append(sig.Params, frontend.WasmTypeToSSAType(t))
- }
-
- sig.Results = sig.Results[:0]
- for _, t := range typ.Results {
- sig.Results = append(sig.Results, frontend.WasmTypeToSSAType(t))
- }
-
- c := &module.CodeSection[i]
- if c.GoFunc == nil {
- panic("BUG: GoFunc must be set for host module")
- }
-
- withListener := len(listeners) > 0 && listeners[i] != nil
- var exitCode wazevoapi.ExitCode
- fn := c.GoFunc
- switch fn.(type) {
- case api.GoModuleFunction:
- exitCode = wazevoapi.ExitCodeCallGoModuleFunctionWithIndex(i, withListener)
- case api.GoFunction:
- exitCode = wazevoapi.ExitCodeCallGoFunctionWithIndex(i, withListener)
- }
-
- be.Init()
- machine.CompileGoFunctionTrampoline(exitCode, &sig, true)
- if err := be.Finalize(ctx); err != nil {
- return nil, err
- }
- body := be.Buf()
-
- if wazevoapi.PerfMapEnabled {
- name := module.FunctionDefinition(wasm.Index(i)).DebugName()
- wazevoapi.PerfMap.AddModuleEntry(i,
- int64(totalSize),
- uint64(len(body)),
- fmt.Sprintf("trampoline:%s", name))
- }
-
- // TODO: optimize as zero copy.
- copied := make([]byte, len(body))
- copy(copied, body)
- bodies[i] = copied
- totalSize += len(body)
- }
-
- if totalSize == 0 {
- // Empty module.
- return cm, nil
- }
-
- // Allocate executable memory and then copy the generated machine code.
- executable, err := platform.MmapCodeSegment(totalSize)
- if err != nil {
- panic(err)
- }
- cm.executable = executable
-
- for i, b := range bodies {
- offset := cm.functionOffsets[i]
- copy(executable[offset:], b)
- }
-
- if wazevoapi.PerfMapEnabled {
- wazevoapi.PerfMap.Flush(uintptr(unsafe.Pointer(&executable[0])), cm.functionOffsets)
- }
-
- if runtime.GOARCH == "arm64" {
- // On arm64, we cannot give all of rwx at the same time, so we change it to exec.
- if err = platform.MprotectRX(executable); err != nil {
- return nil, err
- }
- }
- e.setFinalizer(cm.executables, executablesFinalizer)
- return cm, nil
-}
-
-// Close implements wasm.Engine.
-func (e *engine) Close() (err error) {
- e.mux.Lock()
- defer e.mux.Unlock()
- e.sortedCompiledModules = nil
- e.compiledModules = nil
- e.sharedFunctions = nil
- return nil
-}
-
-// CompiledModuleCount implements wasm.Engine.
-func (e *engine) CompiledModuleCount() uint32 {
- e.mux.RLock()
- defer e.mux.RUnlock()
- return uint32(len(e.compiledModules))
-}
-
-// DeleteCompiledModule implements wasm.Engine.
-func (e *engine) DeleteCompiledModule(m *wasm.Module) {
- e.mux.Lock()
- defer e.mux.Unlock()
- cm, ok := e.compiledModules[m.ID]
- if ok {
- if len(cm.executable) > 0 {
- e.deleteCompiledModuleFromSortedList(cm)
- }
- delete(e.compiledModules, m.ID)
- }
-}
-
-func (e *engine) addCompiledModuleToSortedList(cm *compiledModule) {
- ptr := uintptr(unsafe.Pointer(&cm.executable[0]))
-
- index := sort.Search(len(e.sortedCompiledModules), func(i int) bool {
- return uintptr(unsafe.Pointer(&e.sortedCompiledModules[i].executable[0])) >= ptr
- })
- e.sortedCompiledModules = append(e.sortedCompiledModules, nil)
- copy(e.sortedCompiledModules[index+1:], e.sortedCompiledModules[index:])
- e.sortedCompiledModules[index] = cm
-}
-
-func (e *engine) deleteCompiledModuleFromSortedList(cm *compiledModule) {
- ptr := uintptr(unsafe.Pointer(&cm.executable[0]))
-
- index := sort.Search(len(e.sortedCompiledModules), func(i int) bool {
- return uintptr(unsafe.Pointer(&e.sortedCompiledModules[i].executable[0])) >= ptr
- })
- if index >= len(e.sortedCompiledModules) {
- return
- }
- copy(e.sortedCompiledModules[index:], e.sortedCompiledModules[index+1:])
- e.sortedCompiledModules = e.sortedCompiledModules[:len(e.sortedCompiledModules)-1]
-}
-
-func (e *engine) compiledModuleOfAddr(addr uintptr) *compiledModule {
- e.mux.RLock()
- defer e.mux.RUnlock()
-
- index := sort.Search(len(e.sortedCompiledModules), func(i int) bool {
- return uintptr(unsafe.Pointer(&e.sortedCompiledModules[i].executable[0])) > addr
- })
- index -= 1
- if index < 0 {
- return nil
- }
- candidate := e.sortedCompiledModules[index]
- if checkAddrInBytes(addr, candidate.executable) {
- // If a module is already deleted, the found module may have been wrong.
- return candidate
- }
- return nil
-}
-
-func checkAddrInBytes(addr uintptr, b []byte) bool {
- return uintptr(unsafe.Pointer(&b[0])) <= addr && addr <= uintptr(unsafe.Pointer(&b[len(b)-1]))
-}
-
-// NewModuleEngine implements wasm.Engine.
-func (e *engine) NewModuleEngine(m *wasm.Module, mi *wasm.ModuleInstance) (wasm.ModuleEngine, error) {
- me := &moduleEngine{}
-
- // Note: imported functions are resolved in moduleEngine.ResolveImportedFunction.
- me.importedFunctions = make([]importedFunction, m.ImportFunctionCount)
-
- compiled, ok := e.getCompiledModuleFromMemory(m)
- if !ok {
- return nil, errors.New("source module must be compiled before instantiation")
- }
- me.parent = compiled
- me.module = mi
- me.listeners = compiled.listeners
-
- if m.IsHostModule {
- me.opaque = buildHostModuleOpaque(m, compiled.listeners)
- me.opaquePtr = &me.opaque[0]
- } else {
- if size := compiled.offsets.TotalSize; size != 0 {
- opaque := newAlignedOpaque(size)
- me.opaque = opaque
- me.opaquePtr = &opaque[0]
- }
- }
- return me, nil
-}
-
-func (e *engine) compileSharedFunctions() {
- e.sharedFunctions = &sharedFunctions{
- listenerBeforeTrampolines: make(map[*wasm.FunctionType][]byte),
- listenerAfterTrampolines: make(map[*wasm.FunctionType][]byte),
- }
-
- e.be.Init()
- {
- src := e.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeGrowMemory, &ssa.Signature{
- Params: []ssa.Type{ssa.TypeI64 /* exec context */, ssa.TypeI32},
- Results: []ssa.Type{ssa.TypeI32},
- }, false)
- e.sharedFunctions.memoryGrowExecutable = mmapExecutable(src)
- if wazevoapi.PerfMapEnabled {
- exe := e.sharedFunctions.memoryGrowExecutable
- wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "memory_grow_trampoline")
- }
- }
-
- e.be.Init()
- {
- src := e.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeTableGrow, &ssa.Signature{
- Params: []ssa.Type{ssa.TypeI64 /* exec context */, ssa.TypeI32 /* table index */, ssa.TypeI32 /* num */, ssa.TypeI64 /* ref */},
- Results: []ssa.Type{ssa.TypeI32},
- }, false)
- e.sharedFunctions.tableGrowExecutable = mmapExecutable(src)
- if wazevoapi.PerfMapEnabled {
- exe := e.sharedFunctions.tableGrowExecutable
- wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "table_grow_trampoline")
- }
- }
-
- e.be.Init()
- {
- src := e.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeCheckModuleExitCode, &ssa.Signature{
- Params: []ssa.Type{ssa.TypeI32 /* exec context */},
- Results: []ssa.Type{ssa.TypeI32},
- }, false)
- e.sharedFunctions.checkModuleExitCode = mmapExecutable(src)
- if wazevoapi.PerfMapEnabled {
- exe := e.sharedFunctions.checkModuleExitCode
- wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "check_module_exit_code_trampoline")
- }
- }
-
- e.be.Init()
- {
- src := e.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeRefFunc, &ssa.Signature{
- Params: []ssa.Type{ssa.TypeI64 /* exec context */, ssa.TypeI32 /* function index */},
- Results: []ssa.Type{ssa.TypeI64}, // returns the function reference.
- }, false)
- e.sharedFunctions.refFuncExecutable = mmapExecutable(src)
- if wazevoapi.PerfMapEnabled {
- exe := e.sharedFunctions.refFuncExecutable
- wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "ref_func_trampoline")
- }
- }
-
- e.be.Init()
- {
- src := e.machine.CompileStackGrowCallSequence()
- e.sharedFunctions.stackGrowExecutable = mmapExecutable(src)
- if wazevoapi.PerfMapEnabled {
- exe := e.sharedFunctions.stackGrowExecutable
- wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "stack_grow_trampoline")
- }
- }
-
- e.be.Init()
- {
- src := e.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeMemoryWait32, &ssa.Signature{
- // exec context, timeout, expected, addr
- Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI32, ssa.TypeI64},
- // Returns the status.
- Results: []ssa.Type{ssa.TypeI32},
- }, false)
- e.sharedFunctions.memoryWait32Executable = mmapExecutable(src)
- if wazevoapi.PerfMapEnabled {
- exe := e.sharedFunctions.memoryWait32Executable
- wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "memory_wait32_trampoline")
- }
- }
-
- e.be.Init()
- {
- src := e.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeMemoryWait64, &ssa.Signature{
- // exec context, timeout, expected, addr
- Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI64, ssa.TypeI64},
- // Returns the status.
- Results: []ssa.Type{ssa.TypeI32},
- }, false)
- e.sharedFunctions.memoryWait64Executable = mmapExecutable(src)
- if wazevoapi.PerfMapEnabled {
- exe := e.sharedFunctions.memoryWait64Executable
- wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "memory_wait64_trampoline")
- }
- }
-
- e.be.Init()
- {
- src := e.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeMemoryNotify, &ssa.Signature{
- // exec context, count, addr
- Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32, ssa.TypeI64},
- // Returns the number notified.
- Results: []ssa.Type{ssa.TypeI32},
- }, false)
- e.sharedFunctions.memoryNotifyExecutable = mmapExecutable(src)
- if wazevoapi.PerfMapEnabled {
- exe := e.sharedFunctions.memoryNotifyExecutable
- wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "memory_notify_trampoline")
- }
- }
-
- e.setFinalizer(e.sharedFunctions, sharedFunctionsFinalizer)
-}
-
-func sharedFunctionsFinalizer(sf *sharedFunctions) {
- if err := platform.MunmapCodeSegment(sf.memoryGrowExecutable); err != nil {
- panic(err)
- }
- if err := platform.MunmapCodeSegment(sf.checkModuleExitCode); err != nil {
- panic(err)
- }
- if err := platform.MunmapCodeSegment(sf.stackGrowExecutable); err != nil {
- panic(err)
- }
- if err := platform.MunmapCodeSegment(sf.tableGrowExecutable); err != nil {
- panic(err)
- }
- if err := platform.MunmapCodeSegment(sf.refFuncExecutable); err != nil {
- panic(err)
- }
- if err := platform.MunmapCodeSegment(sf.memoryWait32Executable); err != nil {
- panic(err)
- }
- if err := platform.MunmapCodeSegment(sf.memoryWait64Executable); err != nil {
- panic(err)
- }
- if err := platform.MunmapCodeSegment(sf.memoryNotifyExecutable); err != nil {
- panic(err)
- }
- for _, f := range sf.listenerBeforeTrampolines {
- if err := platform.MunmapCodeSegment(f); err != nil {
- panic(err)
- }
- }
- for _, f := range sf.listenerAfterTrampolines {
- if err := platform.MunmapCodeSegment(f); err != nil {
- panic(err)
- }
- }
-
- sf.memoryGrowExecutable = nil
- sf.checkModuleExitCode = nil
- sf.stackGrowExecutable = nil
- sf.tableGrowExecutable = nil
- sf.refFuncExecutable = nil
- sf.memoryWait32Executable = nil
- sf.memoryWait64Executable = nil
- sf.memoryNotifyExecutable = nil
- sf.listenerBeforeTrampolines = nil
- sf.listenerAfterTrampolines = nil
-}
-
-func executablesFinalizer(exec *executables) {
- if len(exec.executable) > 0 {
- if err := platform.MunmapCodeSegment(exec.executable); err != nil {
- panic(err)
- }
- }
- exec.executable = nil
-
- for _, f := range exec.entryPreambles {
- if err := platform.MunmapCodeSegment(f); err != nil {
- panic(err)
- }
- }
- exec.entryPreambles = nil
-}
-
-func mmapExecutable(src []byte) []byte {
- executable, err := platform.MmapCodeSegment(len(src))
- if err != nil {
- panic(err)
- }
-
- copy(executable, src)
-
- if runtime.GOARCH == "arm64" {
- // On arm64, we cannot give all of rwx at the same time, so we change it to exec.
- if err = platform.MprotectRX(executable); err != nil {
- panic(err)
- }
- }
- return executable
-}
-
-func (cm *compiledModule) functionIndexOf(addr uintptr) wasm.Index {
- addr -= uintptr(unsafe.Pointer(&cm.executable[0]))
- offset := cm.functionOffsets
- index := sort.Search(len(offset), func(i int) bool {
- return offset[i] > int(addr)
- })
- index--
- if index < 0 {
- panic("BUG")
- }
- return wasm.Index(index)
-}
-
-func (e *engine) getListenerTrampolineForType(functionType *wasm.FunctionType) (before, after *byte) {
- e.mux.Lock()
- defer e.mux.Unlock()
-
- beforeBuf, ok := e.sharedFunctions.listenerBeforeTrampolines[functionType]
- afterBuf := e.sharedFunctions.listenerAfterTrampolines[functionType]
- if ok {
- return &beforeBuf[0], &afterBuf[0]
- }
-
- beforeSig, afterSig := frontend.SignatureForListener(functionType)
-
- e.be.Init()
- buf := e.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeCallListenerBefore, beforeSig, false)
- beforeBuf = mmapExecutable(buf)
-
- e.be.Init()
- buf = e.machine.CompileGoFunctionTrampoline(wazevoapi.ExitCodeCallListenerAfter, afterSig, false)
- afterBuf = mmapExecutable(buf)
-
- e.sharedFunctions.listenerBeforeTrampolines[functionType] = beforeBuf
- e.sharedFunctions.listenerAfterTrampolines[functionType] = afterBuf
- return &beforeBuf[0], &afterBuf[0]
-}
-
-func (cm *compiledModule) getSourceOffset(pc uintptr) uint64 {
- offsets := cm.sourceMap.executableOffsets
- if len(offsets) == 0 {
- return 0
- }
-
- index := sort.Search(len(offsets), func(i int) bool {
- return offsets[i] >= pc
- })
-
- index--
- if index < 0 {
- return 0
- }
- return cm.sourceMap.wasmBinaryOffsets[index]
-}