summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/wasm')
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/code.go100
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/const_expr.go105
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/custom.go22
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/data.go79
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/decoder.go193
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/element.go269
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/errors.go11
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/export.go32
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/function.go56
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/global.go50
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/header.go9
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/import.go52
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/limits.go47
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/memory.go42
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/names.go151
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/section.go226
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/table.go43
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/binary/value.go60
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/counts.go51
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/engine.go72
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/func_validation.go2340
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/function_definition.go188
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/global.go55
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go279
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/host.go179
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/instruction.go1866
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/memory.go461
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/memory_definition.go128
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/module.go1083
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance.go251
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go73
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/store.go668
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/store_module_list.go97
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/wasm/table.go339
34 files changed, 9677 insertions, 0 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/code.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/code.go
new file mode 100644
index 000000000..2fac9196c
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/code.go
@@ -0,0 +1,100 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "math"
+
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+func decodeCode(r *bytes.Reader, codeSectionStart uint64, ret *wasm.Code) (err error) {
+ ss, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return fmt.Errorf("get the size of code: %w", err)
+ }
+ remaining := int64(ss)
+
+ // Parse #locals.
+ ls, bytesRead, err := leb128.DecodeUint32(r)
+ remaining -= int64(bytesRead)
+ if err != nil {
+ return fmt.Errorf("get the size locals: %v", err)
+ } else if remaining < 0 {
+ return io.EOF
+ }
+
+ // Validate the locals.
+ bytesRead = 0
+ var sum uint64
+ for i := uint32(0); i < ls; i++ {
+ num, n, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return fmt.Errorf("read n of locals: %v", err)
+ } else if remaining < 0 {
+ return io.EOF
+ }
+
+ sum += uint64(num)
+
+ b, err := r.ReadByte()
+ if err != nil {
+ return fmt.Errorf("read type of local: %v", err)
+ }
+
+ bytesRead += n + 1
+ switch vt := b; vt {
+ case wasm.ValueTypeI32, wasm.ValueTypeF32, wasm.ValueTypeI64, wasm.ValueTypeF64,
+ wasm.ValueTypeFuncref, wasm.ValueTypeExternref, wasm.ValueTypeV128:
+ default:
+ return fmt.Errorf("invalid local type: 0x%x", vt)
+ }
+ }
+
+ if sum > math.MaxUint32 {
+ return fmt.Errorf("too many locals: %d", sum)
+ }
+
+ // Rewind the buffer.
+ _, err = r.Seek(-int64(bytesRead), io.SeekCurrent)
+ if err != nil {
+ return err
+ }
+
+ localTypes := make([]wasm.ValueType, 0, sum)
+ for i := uint32(0); i < ls; i++ {
+ num, bytesRead, err := leb128.DecodeUint32(r)
+ remaining -= int64(bytesRead) + 1 // +1 for the subsequent ReadByte
+ if err != nil {
+ return fmt.Errorf("read n of locals: %v", err)
+ } else if remaining < 0 {
+ return io.EOF
+ }
+
+ b, err := r.ReadByte()
+ if err != nil {
+ return fmt.Errorf("read type of local: %v", err)
+ }
+
+ for j := uint32(0); j < num; j++ {
+ localTypes = append(localTypes, b)
+ }
+ }
+
+ bodyOffsetInCodeSection := codeSectionStart - uint64(r.Len())
+ body := make([]byte, remaining)
+ if _, err = io.ReadFull(r, body); err != nil {
+ return fmt.Errorf("read body: %w", err)
+ }
+
+ if endIndex := len(body) - 1; endIndex < 0 || body[endIndex] != wasm.OpcodeEnd {
+ return fmt.Errorf("expr not end with OpcodeEnd")
+ }
+
+ ret.BodyOffsetInCodeSection = bodyOffsetInCodeSection
+ ret.LocalTypes = localTypes
+ ret.Body = body
+ return nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/const_expr.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/const_expr.go
new file mode 100644
index 000000000..edfc0a086
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/const_expr.go
@@ -0,0 +1,105 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/ieee754"
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+func decodeConstantExpression(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret *wasm.ConstantExpression) error {
+ b, err := r.ReadByte()
+ if err != nil {
+ return fmt.Errorf("read opcode: %v", err)
+ }
+
+ remainingBeforeData := int64(r.Len())
+ offsetAtData := r.Size() - remainingBeforeData
+
+ opcode := b
+ switch opcode {
+ case wasm.OpcodeI32Const:
+ // Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
+ _, _, err = leb128.DecodeInt32(r)
+ case wasm.OpcodeI64Const:
+ // Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
+ _, _, err = leb128.DecodeInt64(r)
+ case wasm.OpcodeF32Const:
+ buf := make([]byte, 4)
+ if _, err := io.ReadFull(r, buf); err != nil {
+ return fmt.Errorf("read f32 constant: %v", err)
+ }
+ _, err = ieee754.DecodeFloat32(buf)
+ case wasm.OpcodeF64Const:
+ buf := make([]byte, 8)
+ if _, err := io.ReadFull(r, buf); err != nil {
+ return fmt.Errorf("read f64 constant: %v", err)
+ }
+ _, err = ieee754.DecodeFloat64(buf)
+ case wasm.OpcodeGlobalGet:
+ _, _, err = leb128.DecodeUint32(r)
+ case wasm.OpcodeRefNull:
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
+ return fmt.Errorf("ref.null is not supported as %w", err)
+ }
+ reftype, err := r.ReadByte()
+ if err != nil {
+ return fmt.Errorf("read reference type for ref.null: %w", err)
+ } else if reftype != wasm.RefTypeFuncref && reftype != wasm.RefTypeExternref {
+ return fmt.Errorf("invalid type for ref.null: 0x%x", reftype)
+ }
+ case wasm.OpcodeRefFunc:
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
+ return fmt.Errorf("ref.func is not supported as %w", err)
+ }
+ // Parsing index.
+ _, _, err = leb128.DecodeUint32(r)
+ case wasm.OpcodeVecPrefix:
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureSIMD); err != nil {
+ return fmt.Errorf("vector instructions are not supported as %w", err)
+ }
+ opcode, err = r.ReadByte()
+ if err != nil {
+ return fmt.Errorf("read vector instruction opcode suffix: %w", err)
+ }
+
+ if opcode != wasm.OpcodeVecV128Const {
+ return fmt.Errorf("invalid vector opcode for const expression: %#x", opcode)
+ }
+
+ remainingBeforeData = int64(r.Len())
+ offsetAtData = r.Size() - remainingBeforeData
+
+ n, err := r.Read(make([]byte, 16))
+ if err != nil {
+ return fmt.Errorf("read vector const instruction immediates: %w", err)
+ } else if n != 16 {
+ return fmt.Errorf("read vector const instruction immediates: needs 16 bytes but was %d bytes", n)
+ }
+ default:
+ return fmt.Errorf("%v for const expression opt code: %#x", ErrInvalidByte, b)
+ }
+
+ if err != nil {
+ return fmt.Errorf("read value: %v", err)
+ }
+
+ if b, err = r.ReadByte(); err != nil {
+ return fmt.Errorf("look for end opcode: %v", err)
+ }
+
+ if b != wasm.OpcodeEnd {
+ return fmt.Errorf("constant expression has been not terminated")
+ }
+
+ ret.Data = make([]byte, remainingBeforeData-int64(r.Len())-1)
+ if _, err = r.ReadAt(ret.Data, offsetAtData); err != nil {
+ return fmt.Errorf("error re-buffering ConstantExpression.Data")
+ }
+ ret.Opcode = opcode
+ return nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/custom.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/custom.go
new file mode 100644
index 000000000..771f8c327
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/custom.go
@@ -0,0 +1,22 @@
+package binary
+
+import (
+ "bytes"
+
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+// decodeCustomSection deserializes the data **not** associated with the "name" key in SectionIDCustom.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0
+func decodeCustomSection(r *bytes.Reader, name string, limit uint64) (result *wasm.CustomSection, err error) {
+ buf := make([]byte, limit)
+ _, err = r.Read(buf)
+
+ result = &wasm.CustomSection{
+ Name: name,
+ Data: buf,
+ }
+
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/data.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/data.go
new file mode 100644
index 000000000..054ccb3c6
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/data.go
@@ -0,0 +1,79 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+// dataSegmentPrefix represents three types of data segments.
+//
+// https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-section
+type dataSegmentPrefix = uint32
+
+const (
+ // dataSegmentPrefixActive is the prefix for the version 1.0 compatible data segment, which is classified as "active" in 2.0.
+ dataSegmentPrefixActive dataSegmentPrefix = 0x0
+ // dataSegmentPrefixPassive prefixes the "passive" data segment as in version 2.0 specification.
+ dataSegmentPrefixPassive dataSegmentPrefix = 0x1
+ // dataSegmentPrefixActiveWithMemoryIndex is the active prefix with memory index encoded which is defined for futur use as of 2.0.
+ dataSegmentPrefixActiveWithMemoryIndex dataSegmentPrefix = 0x2
+)
+
+func decodeDataSegment(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret *wasm.DataSegment) (err error) {
+ dataSegmentPrefx, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ err = fmt.Errorf("read data segment prefix: %w", err)
+ return
+ }
+
+ if dataSegmentPrefx != dataSegmentPrefixActive {
+ if err = enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
+ err = fmt.Errorf("non-zero prefix for data segment is invalid as %w", err)
+ return
+ }
+ }
+
+ switch dataSegmentPrefx {
+ case dataSegmentPrefixActive,
+ dataSegmentPrefixActiveWithMemoryIndex:
+ // Active data segment as in
+ // https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-section
+ if dataSegmentPrefx == 0x2 {
+ d, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return fmt.Errorf("read memory index: %v", err)
+ } else if d != 0 {
+ return fmt.Errorf("memory index must be zero but was %d", d)
+ }
+ }
+
+ err = decodeConstantExpression(r, enabledFeatures, &ret.OffsetExpression)
+ if err != nil {
+ return fmt.Errorf("read offset expression: %v", err)
+ }
+ case dataSegmentPrefixPassive:
+ // Passive data segment doesn't need const expr nor memory index encoded.
+ // https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-section
+ ret.Passive = true
+ default:
+ err = fmt.Errorf("invalid data segment prefix: 0x%x", dataSegmentPrefx)
+ return
+ }
+
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ err = fmt.Errorf("get the size of vector: %v", err)
+ return
+ }
+
+ ret.Init = make([]byte, vs)
+ if _, err = io.ReadFull(r, ret.Init); err != nil {
+ err = fmt.Errorf("read bytes for init: %v", err)
+ }
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/decoder.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/decoder.go
new file mode 100644
index 000000000..c4191dae9
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/decoder.go
@@ -0,0 +1,193 @@
+package binary
+
+import (
+ "bytes"
+ "debug/dwarf"
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+ "github.com/tetratelabs/wazero/internal/wasmdebug"
+)
+
+// DecodeModule implements wasm.DecodeModule for the WebAssembly 1.0 (20191205) Binary Format
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-format%E2%91%A0
+func DecodeModule(
+ binary []byte,
+ enabledFeatures api.CoreFeatures,
+ memoryLimitPages uint32,
+ memoryCapacityFromMax,
+ dwarfEnabled, storeCustomSections bool,
+) (*wasm.Module, error) {
+ r := bytes.NewReader(binary)
+
+ // Magic number.
+ buf := make([]byte, 4)
+ if _, err := io.ReadFull(r, buf); err != nil || !bytes.Equal(buf, Magic) {
+ return nil, ErrInvalidMagicNumber
+ }
+
+ // Version.
+ if _, err := io.ReadFull(r, buf); err != nil || !bytes.Equal(buf, version) {
+ return nil, ErrInvalidVersion
+ }
+
+ memSizer := newMemorySizer(memoryLimitPages, memoryCapacityFromMax)
+
+ m := &wasm.Module{}
+ var info, line, str, abbrev, ranges []byte // For DWARF Data.
+ for {
+ // TODO: except custom sections, all others are required to be in order, but we aren't checking yet.
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A0%E2%93%AA
+ sectionID, err := r.ReadByte()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return nil, fmt.Errorf("read section id: %w", err)
+ }
+
+ sectionSize, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("get size of section %s: %v", wasm.SectionIDName(sectionID), err)
+ }
+
+ sectionContentStart := r.Len()
+ switch sectionID {
+ case wasm.SectionIDCustom:
+ // First, validate the section and determine if the section for this name has already been set
+ name, nameSize, decodeErr := decodeUTF8(r, "custom section name")
+ if decodeErr != nil {
+ err = decodeErr
+ break
+ } else if sectionSize < nameSize {
+ err = fmt.Errorf("malformed custom section %s", name)
+ break
+ } else if name == "name" && m.NameSection != nil {
+ err = fmt.Errorf("redundant custom section %s", name)
+ break
+ }
+
+ // Now, either decode the NameSection or CustomSection
+ limit := sectionSize - nameSize
+
+ var c *wasm.CustomSection
+ if name != "name" {
+ if storeCustomSections || dwarfEnabled {
+ c, err = decodeCustomSection(r, name, uint64(limit))
+ if err != nil {
+ return nil, fmt.Errorf("failed to read custom section name[%s]: %w", name, err)
+ }
+ m.CustomSections = append(m.CustomSections, c)
+ if dwarfEnabled {
+ switch name {
+ case ".debug_info":
+ info = c.Data
+ case ".debug_line":
+ line = c.Data
+ case ".debug_str":
+ str = c.Data
+ case ".debug_abbrev":
+ abbrev = c.Data
+ case ".debug_ranges":
+ ranges = c.Data
+ }
+ }
+ } else {
+ if _, err = io.CopyN(io.Discard, r, int64(limit)); err != nil {
+ return nil, fmt.Errorf("failed to skip name[%s]: %w", name, err)
+ }
+ }
+ } else {
+ m.NameSection, err = decodeNameSection(r, uint64(limit))
+ }
+ case wasm.SectionIDType:
+ m.TypeSection, err = decodeTypeSection(enabledFeatures, r)
+ case wasm.SectionIDImport:
+ m.ImportSection, m.ImportPerModule, m.ImportFunctionCount, m.ImportGlobalCount, m.ImportMemoryCount, m.ImportTableCount, err = decodeImportSection(r, memSizer, memoryLimitPages, enabledFeatures)
+ if err != nil {
+ return nil, err // avoid re-wrapping the error.
+ }
+ case wasm.SectionIDFunction:
+ m.FunctionSection, err = decodeFunctionSection(r)
+ case wasm.SectionIDTable:
+ m.TableSection, err = decodeTableSection(r, enabledFeatures)
+ case wasm.SectionIDMemory:
+ m.MemorySection, err = decodeMemorySection(r, enabledFeatures, memSizer, memoryLimitPages)
+ case wasm.SectionIDGlobal:
+ if m.GlobalSection, err = decodeGlobalSection(r, enabledFeatures); err != nil {
+ return nil, err // avoid re-wrapping the error.
+ }
+ case wasm.SectionIDExport:
+ m.ExportSection, m.Exports, err = decodeExportSection(r)
+ case wasm.SectionIDStart:
+ if m.StartSection != nil {
+ return nil, errors.New("multiple start sections are invalid")
+ }
+ m.StartSection, err = decodeStartSection(r)
+ case wasm.SectionIDElement:
+ m.ElementSection, err = decodeElementSection(r, enabledFeatures)
+ case wasm.SectionIDCode:
+ m.CodeSection, err = decodeCodeSection(r)
+ case wasm.SectionIDData:
+ m.DataSection, err = decodeDataSection(r, enabledFeatures)
+ case wasm.SectionIDDataCount:
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
+ return nil, fmt.Errorf("data count section not supported as %v", err)
+ }
+ m.DataCountSection, err = decodeDataCountSection(r)
+ default:
+ err = ErrInvalidSectionID
+ }
+
+ readBytes := sectionContentStart - r.Len()
+ if err == nil && int(sectionSize) != readBytes {
+ err = fmt.Errorf("invalid section length: expected to be %d but got %d", sectionSize, readBytes)
+ }
+
+ if err != nil {
+ return nil, fmt.Errorf("section %s: %v", wasm.SectionIDName(sectionID), err)
+ }
+ }
+
+ if dwarfEnabled {
+ d, _ := dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+ m.DWARFLines = wasmdebug.NewDWARFLines(d)
+ }
+
+ functionCount, codeCount := m.SectionElementCount(wasm.SectionIDFunction), m.SectionElementCount(wasm.SectionIDCode)
+ if functionCount != codeCount {
+ return nil, fmt.Errorf("function and code section have inconsistent lengths: %d != %d", functionCount, codeCount)
+ }
+ return m, nil
+}
+
+// memorySizer derives min, capacity and max pages from decoded wasm.
+type memorySizer func(minPages uint32, maxPages *uint32) (min uint32, capacity uint32, max uint32)
+
+// newMemorySizer sets capacity to minPages unless max is defined and
+// memoryCapacityFromMax is true.
+func newMemorySizer(memoryLimitPages uint32, memoryCapacityFromMax bool) memorySizer {
+ return func(minPages uint32, maxPages *uint32) (min, capacity, max uint32) {
+ if maxPages != nil {
+ if memoryCapacityFromMax {
+ return minPages, *maxPages, *maxPages
+ }
+ // This is an invalid value: let it propagate, we will fail later.
+ if *maxPages > wasm.MemoryLimitPages {
+ return minPages, minPages, *maxPages
+ }
+ // This is a valid value, but it goes over the run-time limit: return the limit.
+ if *maxPages > memoryLimitPages {
+ return minPages, minPages, memoryLimitPages
+ }
+ return minPages, minPages, *maxPages
+ }
+ if memoryCapacityFromMax {
+ return minPages, memoryLimitPages, memoryLimitPages
+ }
+ return minPages, minPages, memoryLimitPages
+ }
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/element.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/element.go
new file mode 100644
index 000000000..7ab4b48eb
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/element.go
@@ -0,0 +1,269 @@
+package binary
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+func ensureElementKindFuncRef(r *bytes.Reader) error {
+ elemKind, err := r.ReadByte()
+ if err != nil {
+ return fmt.Errorf("read element prefix: %w", err)
+ }
+ if elemKind != 0x0 { // ElemKind is fixed to 0x0 now: https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#element-section
+ return fmt.Errorf("element kind must be zero but was 0x%x", elemKind)
+ }
+ return nil
+}
+
+func decodeElementInitValueVector(r *bytes.Reader) ([]wasm.Index, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("get size of vector: %w", err)
+ }
+
+ vec := make([]wasm.Index, vs)
+ for i := range vec {
+ u32, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("read function index: %w", err)
+ }
+
+ if u32 >= wasm.MaximumFunctionIndex {
+ return nil, fmt.Errorf("too large function index in Element init: %d", u32)
+ }
+ vec[i] = u32
+ }
+ return vec, nil
+}
+
+func decodeElementConstExprVector(r *bytes.Reader, elemType wasm.RefType, enabledFeatures api.CoreFeatures) ([]wasm.Index, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get the size of constexpr vector: %w", err)
+ }
+ vec := make([]wasm.Index, vs)
+ for i := range vec {
+ var expr wasm.ConstantExpression
+ err := decodeConstantExpression(r, enabledFeatures, &expr)
+ if err != nil {
+ return nil, err
+ }
+ switch expr.Opcode {
+ case wasm.OpcodeRefFunc:
+ if elemType != wasm.RefTypeFuncref {
+ return nil, fmt.Errorf("element type mismatch: want %s, but constexpr has funcref", wasm.RefTypeName(elemType))
+ }
+ v, _, _ := leb128.LoadUint32(expr.Data)
+ if v >= wasm.MaximumFunctionIndex {
+ return nil, fmt.Errorf("too large function index in Element init: %d", v)
+ }
+ vec[i] = v
+ case wasm.OpcodeRefNull:
+ if elemType != expr.Data[0] {
+ return nil, fmt.Errorf("element type mismatch: want %s, but constexpr has %s",
+ wasm.RefTypeName(elemType), wasm.RefTypeName(expr.Data[0]))
+ }
+ vec[i] = wasm.ElementInitNullReference
+ case wasm.OpcodeGlobalGet:
+ i32, _, _ := leb128.LoadInt32(expr.Data)
+ // Resolving the reference type from globals is done at instantiation phase. See the comment on
+ // wasm.elementInitImportedGlobalReferenceType.
+ vec[i] = wasm.WrapGlobalIndexAsElementInit(wasm.Index(i32))
+ default:
+ return nil, fmt.Errorf("const expr must be either ref.null or ref.func but was %s", wasm.InstructionName(expr.Opcode))
+ }
+ }
+ return vec, nil
+}
+
+func decodeElementRefType(r *bytes.Reader) (ret wasm.RefType, err error) {
+ ret, err = r.ReadByte()
+ if err != nil {
+ err = fmt.Errorf("read element ref type: %w", err)
+ return
+ }
+ if ret != wasm.RefTypeFuncref && ret != wasm.RefTypeExternref {
+ return 0, errors.New("ref type must be funcref or externref for element as of WebAssembly 2.0")
+ }
+ return
+}
+
+const (
+ // The prefix is explained at https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#element-section
+
+ // elementSegmentPrefixLegacy is the legacy prefix and is only valid one before CoreFeatureBulkMemoryOperations.
+ elementSegmentPrefixLegacy = iota
+ // elementSegmentPrefixPassiveFuncrefValueVector is the passive element whose indexes are encoded as vec(varint), and reftype is fixed to funcref.
+ elementSegmentPrefixPassiveFuncrefValueVector
+ // elementSegmentPrefixActiveFuncrefValueVectorWithTableIndex is the same as elementSegmentPrefixPassiveFuncrefValueVector but active and table index is encoded.
+ elementSegmentPrefixActiveFuncrefValueVectorWithTableIndex
+ // elementSegmentPrefixDeclarativeFuncrefValueVector is the same as elementSegmentPrefixPassiveFuncrefValueVector but declarative.
+ elementSegmentPrefixDeclarativeFuncrefValueVector
+ // elementSegmentPrefixActiveFuncrefConstExprVector is active whoce reftype is fixed to funcref and indexes are encoded as vec(const_expr).
+ elementSegmentPrefixActiveFuncrefConstExprVector
+ // elementSegmentPrefixPassiveConstExprVector is passive whoce indexes are encoded as vec(const_expr), and reftype is encoded.
+ elementSegmentPrefixPassiveConstExprVector
+ // elementSegmentPrefixPassiveConstExprVector is active whoce indexes are encoded as vec(const_expr), and reftype and table index are encoded.
+ elementSegmentPrefixActiveConstExprVector
+ // elementSegmentPrefixDeclarativeConstExprVector is declarative whoce indexes are encoded as vec(const_expr), and reftype is encoded.
+ elementSegmentPrefixDeclarativeConstExprVector
+)
+
+func decodeElementSegment(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret *wasm.ElementSegment) error {
+ prefix, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return fmt.Errorf("read element prefix: %w", err)
+ }
+
+ if prefix != elementSegmentPrefixLegacy {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
+ return fmt.Errorf("non-zero prefix for element segment is invalid as %w", err)
+ }
+ }
+
+ // Encoding depends on the prefix and described at https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#element-section
+ switch prefix {
+ case elementSegmentPrefixLegacy:
+ // Legacy prefix which is WebAssembly 1.0 compatible.
+ err = decodeConstantExpression(r, enabledFeatures, &ret.OffsetExpr)
+ if err != nil {
+ return fmt.Errorf("read expr for offset: %w", err)
+ }
+
+ ret.Init, err = decodeElementInitValueVector(r)
+ if err != nil {
+ return err
+ }
+
+ ret.Mode = wasm.ElementModeActive
+ ret.Type = wasm.RefTypeFuncref
+ return nil
+ case elementSegmentPrefixPassiveFuncrefValueVector:
+ // Prefix 1 requires funcref.
+ if err = ensureElementKindFuncRef(r); err != nil {
+ return err
+ }
+
+ ret.Init, err = decodeElementInitValueVector(r)
+ if err != nil {
+ return err
+ }
+ ret.Mode = wasm.ElementModePassive
+ ret.Type = wasm.RefTypeFuncref
+ return nil
+ case elementSegmentPrefixActiveFuncrefValueVectorWithTableIndex:
+ ret.TableIndex, _, err = leb128.DecodeUint32(r)
+ if err != nil {
+ return fmt.Errorf("get size of vector: %w", err)
+ }
+
+ if ret.TableIndex != 0 {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("table index must be zero but was %d: %w", ret.TableIndex, err)
+ }
+ }
+
+ err := decodeConstantExpression(r, enabledFeatures, &ret.OffsetExpr)
+ if err != nil {
+ return fmt.Errorf("read expr for offset: %w", err)
+ }
+
+ // Prefix 2 requires funcref.
+ if err = ensureElementKindFuncRef(r); err != nil {
+ return err
+ }
+
+ ret.Init, err = decodeElementInitValueVector(r)
+ if err != nil {
+ return err
+ }
+
+ ret.Mode = wasm.ElementModeActive
+ ret.Type = wasm.RefTypeFuncref
+ return nil
+ case elementSegmentPrefixDeclarativeFuncrefValueVector:
+ // Prefix 3 requires funcref.
+ if err = ensureElementKindFuncRef(r); err != nil {
+ return err
+ }
+ ret.Init, err = decodeElementInitValueVector(r)
+ if err != nil {
+ return err
+ }
+ ret.Type = wasm.RefTypeFuncref
+ ret.Mode = wasm.ElementModeDeclarative
+ return nil
+ case elementSegmentPrefixActiveFuncrefConstExprVector:
+ err := decodeConstantExpression(r, enabledFeatures, &ret.OffsetExpr)
+ if err != nil {
+ return fmt.Errorf("read expr for offset: %w", err)
+ }
+
+ ret.Init, err = decodeElementConstExprVector(r, wasm.RefTypeFuncref, enabledFeatures)
+ if err != nil {
+ return err
+ }
+ ret.Mode = wasm.ElementModeActive
+ ret.Type = wasm.RefTypeFuncref
+ return nil
+ case elementSegmentPrefixPassiveConstExprVector:
+ ret.Type, err = decodeElementRefType(r)
+ if err != nil {
+ return err
+ }
+ ret.Init, err = decodeElementConstExprVector(r, ret.Type, enabledFeatures)
+ if err != nil {
+ return err
+ }
+ ret.Mode = wasm.ElementModePassive
+ return nil
+ case elementSegmentPrefixActiveConstExprVector:
+ ret.TableIndex, _, err = leb128.DecodeUint32(r)
+ if err != nil {
+ return fmt.Errorf("get size of vector: %w", err)
+ }
+
+ if ret.TableIndex != 0 {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("table index must be zero but was %d: %w", ret.TableIndex, err)
+ }
+ }
+ err := decodeConstantExpression(r, enabledFeatures, &ret.OffsetExpr)
+ if err != nil {
+ return fmt.Errorf("read expr for offset: %w", err)
+ }
+
+ ret.Type, err = decodeElementRefType(r)
+ if err != nil {
+ return err
+ }
+
+ ret.Init, err = decodeElementConstExprVector(r, ret.Type, enabledFeatures)
+ if err != nil {
+ return err
+ }
+
+ ret.Mode = wasm.ElementModeActive
+ return nil
+ case elementSegmentPrefixDeclarativeConstExprVector:
+ ret.Type, err = decodeElementRefType(r)
+ if err != nil {
+ return err
+ }
+ ret.Init, err = decodeElementConstExprVector(r, ret.Type, enabledFeatures)
+ if err != nil {
+ return err
+ }
+
+ ret.Mode = wasm.ElementModeDeclarative
+ return nil
+ default:
+ return fmt.Errorf("invalid element segment prefix: 0x%x", prefix)
+ }
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/errors.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/errors.go
new file mode 100644
index 000000000..b9125b038
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/errors.go
@@ -0,0 +1,11 @@
+package binary
+
+import "errors"
+
+var (
+ ErrInvalidByte = errors.New("invalid byte")
+ ErrInvalidMagicNumber = errors.New("invalid magic number")
+ ErrInvalidVersion = errors.New("invalid version header")
+ ErrInvalidSectionID = errors.New("invalid section id")
+ ErrCustomSectionNotFound = errors.New("custom section not found")
+)
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/export.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/export.go
new file mode 100644
index 000000000..925e9c499
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/export.go
@@ -0,0 +1,32 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+func decodeExport(r *bytes.Reader, ret *wasm.Export) (err error) {
+ if ret.Name, _, err = decodeUTF8(r, "export name"); err != nil {
+ return
+ }
+
+ b, err := r.ReadByte()
+ if err != nil {
+ err = fmt.Errorf("error decoding export kind: %w", err)
+ return
+ }
+
+ ret.Type = b
+ switch ret.Type {
+ case wasm.ExternTypeFunc, wasm.ExternTypeTable, wasm.ExternTypeMemory, wasm.ExternTypeGlobal:
+ if ret.Index, _, err = leb128.DecodeUint32(r); err != nil {
+ err = fmt.Errorf("error decoding export index: %w", err)
+ }
+ default:
+ err = fmt.Errorf("%w: invalid byte for exportdesc: %#x", ErrInvalidByte, b)
+ }
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/function.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/function.go
new file mode 100644
index 000000000..bb9e2b649
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/function.go
@@ -0,0 +1,56 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+func decodeFunctionType(enabledFeatures api.CoreFeatures, r *bytes.Reader, ret *wasm.FunctionType) (err error) {
+ b, err := r.ReadByte()
+ if err != nil {
+ return fmt.Errorf("read leading byte: %w", err)
+ }
+
+ if b != 0x60 {
+ return fmt.Errorf("%w: %#x != 0x60", ErrInvalidByte, b)
+ }
+
+ paramCount, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return fmt.Errorf("could not read parameter count: %w", err)
+ }
+
+ paramTypes, err := decodeValueTypes(r, paramCount)
+ if err != nil {
+ return fmt.Errorf("could not read parameter types: %w", err)
+ }
+
+ resultCount, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return fmt.Errorf("could not read result count: %w", err)
+ }
+
+ // Guard >1.0 feature multi-value
+ if resultCount > 1 {
+ if err = enabledFeatures.RequireEnabled(api.CoreFeatureMultiValue); err != nil {
+ return fmt.Errorf("multiple result types invalid as %v", err)
+ }
+ }
+
+ resultTypes, err := decodeValueTypes(r, resultCount)
+ if err != nil {
+ return fmt.Errorf("could not read result types: %w", err)
+ }
+
+ ret.Params = paramTypes
+ ret.Results = resultTypes
+
+ // cache the key for the function type
+ _ = ret.String()
+
+ return nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/global.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/global.go
new file mode 100644
index 000000000..4e1c16fda
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/global.go
@@ -0,0 +1,50 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+// decodeGlobal returns the api.Global decoded with the WebAssembly 1.0 (20191205) Binary Format.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-global
+func decodeGlobal(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret *wasm.Global) (err error) {
+ ret.Type, err = decodeGlobalType(r)
+ if err != nil {
+ return err
+ }
+
+ err = decodeConstantExpression(r, enabledFeatures, &ret.Init)
+ return
+}
+
+// decodeGlobalType returns the wasm.GlobalType decoded with the WebAssembly 1.0 (20191205) Binary Format.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-globaltype
+func decodeGlobalType(r *bytes.Reader) (wasm.GlobalType, error) {
+ vt, err := decodeValueTypes(r, 1)
+ if err != nil {
+ return wasm.GlobalType{}, fmt.Errorf("read value type: %w", err)
+ }
+
+ ret := wasm.GlobalType{
+ ValType: vt[0],
+ }
+
+ b, err := r.ReadByte()
+ if err != nil {
+ return wasm.GlobalType{}, fmt.Errorf("read mutablity: %w", err)
+ }
+
+ switch mut := b; mut {
+ case 0x00: // not mutable
+ case 0x01: // mutable
+ ret.Mutable = true
+ default:
+ return wasm.GlobalType{}, fmt.Errorf("%w for mutability: %#x != 0x00 or 0x01", ErrInvalidByte, mut)
+ }
+ return ret, nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/header.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/header.go
new file mode 100644
index 000000000..29ba1b599
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/header.go
@@ -0,0 +1,9 @@
+package binary
+
+// Magic is the 4 byte preamble (literally "\0asm") of the binary format
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-magic
+var Magic = []byte{0x00, 0x61, 0x73, 0x6D}
+
+// version is format version and doesn't change between known specification versions
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-version
+var version = []byte{0x01, 0x00, 0x00, 0x00}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/import.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/import.go
new file mode 100644
index 000000000..39d310c55
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/import.go
@@ -0,0 +1,52 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+func decodeImport(
+ r *bytes.Reader,
+ idx uint32,
+ memorySizer memorySizer,
+ memoryLimitPages uint32,
+ enabledFeatures api.CoreFeatures,
+ ret *wasm.Import,
+) (err error) {
+ if ret.Module, _, err = decodeUTF8(r, "import module"); err != nil {
+ err = fmt.Errorf("import[%d] error decoding module: %w", idx, err)
+ return
+ }
+
+ if ret.Name, _, err = decodeUTF8(r, "import name"); err != nil {
+ err = fmt.Errorf("import[%d] error decoding name: %w", idx, err)
+ return
+ }
+
+ b, err := r.ReadByte()
+ if err != nil {
+ err = fmt.Errorf("import[%d] error decoding type: %w", idx, err)
+ return
+ }
+ ret.Type = b
+ switch ret.Type {
+ case wasm.ExternTypeFunc:
+ ret.DescFunc, _, err = leb128.DecodeUint32(r)
+ case wasm.ExternTypeTable:
+ err = decodeTable(r, enabledFeatures, &ret.DescTable)
+ case wasm.ExternTypeMemory:
+ ret.DescMem, err = decodeMemory(r, enabledFeatures, memorySizer, memoryLimitPages)
+ case wasm.ExternTypeGlobal:
+ ret.DescGlobal, err = decodeGlobalType(r)
+ default:
+ err = fmt.Errorf("%w: invalid byte for importdesc: %#x", ErrInvalidByte, b)
+ }
+ if err != nil {
+ err = fmt.Errorf("import[%d] %s[%s.%s]: %w", idx, wasm.ExternTypeName(ret.Type), ret.Module, ret.Name, err)
+ }
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/limits.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/limits.go
new file mode 100644
index 000000000..ff2d73b5f
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/limits.go
@@ -0,0 +1,47 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/internal/leb128"
+)
+
+// decodeLimitsType returns the `limitsType` (min, max) decoded with the WebAssembly 1.0 (20191205) Binary Format.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#limits%E2%91%A6
+//
+// Extended in threads proposal: https://webassembly.github.io/threads/core/binary/types.html#limits
+func decodeLimitsType(r *bytes.Reader) (min uint32, max *uint32, shared bool, err error) {
+ var flag byte
+ if flag, err = r.ReadByte(); err != nil {
+ err = fmt.Errorf("read leading byte: %v", err)
+ return
+ }
+
+ switch flag {
+ case 0x00, 0x02:
+ min, _, err = leb128.DecodeUint32(r)
+ if err != nil {
+ err = fmt.Errorf("read min of limit: %v", err)
+ }
+ case 0x01, 0x03:
+ min, _, err = leb128.DecodeUint32(r)
+ if err != nil {
+ err = fmt.Errorf("read min of limit: %v", err)
+ return
+ }
+ var m uint32
+ if m, _, err = leb128.DecodeUint32(r); err != nil {
+ err = fmt.Errorf("read max of limit: %v", err)
+ } else {
+ max = &m
+ }
+ default:
+ err = fmt.Errorf("%v for limits: %#x not in (0x00, 0x01, 0x02, 0x03)", ErrInvalidByte, flag)
+ }
+
+ shared = flag == 0x02 || flag == 0x03
+
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/memory.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/memory.go
new file mode 100644
index 000000000..e1b175123
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/memory.go
@@ -0,0 +1,42 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/experimental"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+// decodeMemory returns the api.Memory decoded with the WebAssembly 1.0 (20191205) Binary Format.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-memory
+func decodeMemory(
+ r *bytes.Reader,
+ enabledFeatures api.CoreFeatures,
+ memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
+ memoryLimitPages uint32,
+) (*wasm.Memory, error) {
+ min, maxP, shared, err := decodeLimitsType(r)
+ if err != nil {
+ return nil, err
+ }
+
+ if shared {
+ if !enabledFeatures.IsEnabled(experimental.CoreFeaturesThreads) {
+ return nil, fmt.Errorf("shared memory requested but threads feature not enabled")
+ }
+
+ // This restriction may be lifted in the future.
+ // https://webassembly.github.io/threads/core/binary/types.html#memory-types
+ if maxP == nil {
+ return nil, fmt.Errorf("shared memory requires a maximum size to be specified")
+ }
+ }
+
+ min, capacity, max := memorySizer(min, maxP)
+ mem := &wasm.Memory{Min: min, Cap: capacity, Max: max, IsMaxEncoded: maxP != nil, IsShared: shared}
+
+ return mem, mem.Validate(memoryLimitPages)
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/names.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/names.go
new file mode 100644
index 000000000..56fb96dc8
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/names.go
@@ -0,0 +1,151 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+const (
+ // subsectionIDModuleName contains only the module name.
+ subsectionIDModuleName = uint8(0)
+ // subsectionIDFunctionNames is a map of indices to function names, in ascending order by function index
+ subsectionIDFunctionNames = uint8(1)
+ // subsectionIDLocalNames contain a map of function indices to a map of local indices to their names, in ascending
+ // order by function and local index
+ subsectionIDLocalNames = uint8(2)
+)
+
+// decodeNameSection deserializes the data associated with the "name" key in SectionIDCustom according to the
+// standard:
+//
+// * ModuleName decode from subsection 0
+// * FunctionNames decode from subsection 1
+// * LocalNames decode from subsection 2
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-namesec
+func decodeNameSection(r *bytes.Reader, limit uint64) (result *wasm.NameSection, err error) {
+ // TODO: add leb128 functions that work on []byte and offset. While using a reader allows us to reuse reader-based
+ // leb128 functions, it is less efficient, causes untestable code and in some cases more complex vs plain []byte.
+ result = &wasm.NameSection{}
+
+ // subsectionID is decoded if known, and skipped if not
+ var subsectionID uint8
+ // subsectionSize is the length to skip when the subsectionID is unknown
+ var subsectionSize uint32
+ var bytesRead uint64
+ for limit > 0 {
+ if subsectionID, err = r.ReadByte(); err != nil {
+ if err == io.EOF {
+ return result, nil
+ }
+ // TODO: untestable as this can't fail for a reason beside EOF reading a byte from a buffer
+ return nil, fmt.Errorf("failed to read a subsection ID: %w", err)
+ }
+ limit--
+
+ if subsectionSize, bytesRead, err = leb128.DecodeUint32(r); err != nil {
+ return nil, fmt.Errorf("failed to read the size of subsection[%d]: %w", subsectionID, err)
+ }
+ limit -= bytesRead
+
+ switch subsectionID {
+ case subsectionIDModuleName:
+ if result.ModuleName, _, err = decodeUTF8(r, "module name"); err != nil {
+ return nil, err
+ }
+ case subsectionIDFunctionNames:
+ if result.FunctionNames, err = decodeFunctionNames(r); err != nil {
+ return nil, err
+ }
+ case subsectionIDLocalNames:
+ if result.LocalNames, err = decodeLocalNames(r); err != nil {
+ return nil, err
+ }
+ default: // Skip other subsections.
+ // Note: Not Seek because it doesn't err when given an offset past EOF. Rather, it leads to undefined state.
+ if _, err = io.CopyN(io.Discard, r, int64(subsectionSize)); err != nil {
+ return nil, fmt.Errorf("failed to skip subsection[%d]: %w", subsectionID, err)
+ }
+ }
+ limit -= uint64(subsectionSize)
+ }
+ return
+}
+
+func decodeFunctionNames(r *bytes.Reader) (wasm.NameMap, error) {
+ functionCount, err := decodeFunctionCount(r, subsectionIDFunctionNames)
+ if err != nil {
+ return nil, err
+ }
+
+ result := make(wasm.NameMap, functionCount)
+ for i := uint32(0); i < functionCount; i++ {
+ functionIndex, err := decodeFunctionIndex(r, subsectionIDFunctionNames)
+ if err != nil {
+ return nil, err
+ }
+
+ name, _, err := decodeUTF8(r, "function[%d] name", functionIndex)
+ if err != nil {
+ return nil, err
+ }
+ result[i] = wasm.NameAssoc{Index: functionIndex, Name: name}
+ }
+ return result, nil
+}
+
+func decodeLocalNames(r *bytes.Reader) (wasm.IndirectNameMap, error) {
+ functionCount, err := decodeFunctionCount(r, subsectionIDLocalNames)
+ if err != nil {
+ return nil, err
+ }
+
+ result := make(wasm.IndirectNameMap, functionCount)
+ for i := uint32(0); i < functionCount; i++ {
+ functionIndex, err := decodeFunctionIndex(r, subsectionIDLocalNames)
+ if err != nil {
+ return nil, err
+ }
+
+ localCount, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read the local count for function[%d]: %w", functionIndex, err)
+ }
+
+ locals := make(wasm.NameMap, localCount)
+ for j := uint32(0); j < localCount; j++ {
+ localIndex, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read a local index of function[%d]: %w", functionIndex, err)
+ }
+
+ name, _, err := decodeUTF8(r, "function[%d] local[%d] name", functionIndex, localIndex)
+ if err != nil {
+ return nil, err
+ }
+ locals[j] = wasm.NameAssoc{Index: localIndex, Name: name}
+ }
+ result[i] = wasm.NameMapAssoc{Index: functionIndex, NameMap: locals}
+ }
+ return result, nil
+}
+
+func decodeFunctionIndex(r *bytes.Reader, subsectionID uint8) (uint32, error) {
+ functionIndex, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return 0, fmt.Errorf("failed to read a function index in subsection[%d]: %w", subsectionID, err)
+ }
+ return functionIndex, nil
+}
+
+func decodeFunctionCount(r *bytes.Reader, subsectionID uint8) (uint32, error) {
+ functionCount, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return 0, fmt.Errorf("failed to read the function count of subsection[%d]: %w", subsectionID, err)
+ }
+ return functionCount, nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/section.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/section.go
new file mode 100644
index 000000000..622ee5923
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/section.go
@@ -0,0 +1,226 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+func decodeTypeSection(enabledFeatures api.CoreFeatures, r *bytes.Reader) ([]wasm.FunctionType, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("get size of vector: %w", err)
+ }
+
+ result := make([]wasm.FunctionType, vs)
+ for i := uint32(0); i < vs; i++ {
+ if err = decodeFunctionType(enabledFeatures, r, &result[i]); err != nil {
+ return nil, fmt.Errorf("read %d-th type: %v", i, err)
+ }
+ }
+ return result, nil
+}
+
+// decodeImportSection decodes the decoded import segments plus the count per wasm.ExternType.
+func decodeImportSection(
+ r *bytes.Reader,
+ memorySizer memorySizer,
+ memoryLimitPages uint32,
+ enabledFeatures api.CoreFeatures,
+) (result []wasm.Import,
+ perModule map[string][]*wasm.Import,
+ funcCount, globalCount, memoryCount, tableCount wasm.Index, err error,
+) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ err = fmt.Errorf("get size of vector: %w", err)
+ return
+ }
+
+ perModule = make(map[string][]*wasm.Import)
+ result = make([]wasm.Import, vs)
+ for i := uint32(0); i < vs; i++ {
+ imp := &result[i]
+ if err = decodeImport(r, i, memorySizer, memoryLimitPages, enabledFeatures, imp); err != nil {
+ return
+ }
+ switch imp.Type {
+ case wasm.ExternTypeFunc:
+ imp.IndexPerType = funcCount
+ funcCount++
+ case wasm.ExternTypeGlobal:
+ imp.IndexPerType = globalCount
+ globalCount++
+ case wasm.ExternTypeMemory:
+ imp.IndexPerType = memoryCount
+ memoryCount++
+ case wasm.ExternTypeTable:
+ imp.IndexPerType = tableCount
+ tableCount++
+ }
+ perModule[imp.Module] = append(perModule[imp.Module], imp)
+ }
+ return
+}
+
+func decodeFunctionSection(r *bytes.Reader) ([]uint32, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("get size of vector: %w", err)
+ }
+
+ result := make([]uint32, vs)
+ for i := uint32(0); i < vs; i++ {
+ if result[i], _, err = leb128.DecodeUint32(r); err != nil {
+ return nil, fmt.Errorf("get type index: %w", err)
+ }
+ }
+ return result, err
+}
+
+func decodeTableSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]wasm.Table, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("error reading size")
+ }
+ if vs > 1 {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return nil, fmt.Errorf("at most one table allowed in module as %w", err)
+ }
+ }
+
+ ret := make([]wasm.Table, vs)
+ for i := range ret {
+ err = decodeTable(r, enabledFeatures, &ret[i])
+ if err != nil {
+ return nil, err
+ }
+ }
+ return ret, nil
+}
+
+func decodeMemorySection(
+ r *bytes.Reader,
+ enabledFeatures api.CoreFeatures,
+ memorySizer memorySizer,
+ memoryLimitPages uint32,
+) (*wasm.Memory, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("error reading size")
+ }
+ if vs > 1 {
+ return nil, fmt.Errorf("at most one memory allowed in module, but read %d", vs)
+ } else if vs == 0 {
+ // memory count can be zero.
+ return nil, nil
+ }
+
+ return decodeMemory(r, enabledFeatures, memorySizer, memoryLimitPages)
+}
+
+func decodeGlobalSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]wasm.Global, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("get size of vector: %w", err)
+ }
+
+ result := make([]wasm.Global, vs)
+ for i := uint32(0); i < vs; i++ {
+ if err = decodeGlobal(r, enabledFeatures, &result[i]); err != nil {
+ return nil, fmt.Errorf("global[%d]: %w", i, err)
+ }
+ }
+ return result, nil
+}
+
+func decodeExportSection(r *bytes.Reader) ([]wasm.Export, map[string]*wasm.Export, error) {
+ vs, _, sizeErr := leb128.DecodeUint32(r)
+ if sizeErr != nil {
+ return nil, nil, fmt.Errorf("get size of vector: %v", sizeErr)
+ }
+
+ exportMap := make(map[string]*wasm.Export, vs)
+ exportSection := make([]wasm.Export, vs)
+ for i := wasm.Index(0); i < vs; i++ {
+ export := &exportSection[i]
+ err := decodeExport(r, export)
+ if err != nil {
+ return nil, nil, fmt.Errorf("read export: %w", err)
+ }
+ if _, ok := exportMap[export.Name]; ok {
+ return nil, nil, fmt.Errorf("export[%d] duplicates name %q", i, export.Name)
+ } else {
+ exportMap[export.Name] = export
+ }
+ }
+ return exportSection, exportMap, nil
+}
+
+func decodeStartSection(r *bytes.Reader) (*wasm.Index, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("get function index: %w", err)
+ }
+ return &vs, nil
+}
+
+func decodeElementSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]wasm.ElementSegment, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("get size of vector: %w", err)
+ }
+
+ result := make([]wasm.ElementSegment, vs)
+ for i := uint32(0); i < vs; i++ {
+ if err = decodeElementSegment(r, enabledFeatures, &result[i]); err != nil {
+ return nil, fmt.Errorf("read element: %w", err)
+ }
+ }
+ return result, nil
+}
+
+func decodeCodeSection(r *bytes.Reader) ([]wasm.Code, error) {
+ codeSectionStart := uint64(r.Len())
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("get size of vector: %w", err)
+ }
+
+ result := make([]wasm.Code, vs)
+ for i := uint32(0); i < vs; i++ {
+ err = decodeCode(r, codeSectionStart, &result[i])
+ if err != nil {
+ return nil, fmt.Errorf("read %d-th code segment: %v", i, err)
+ }
+ }
+ return result, nil
+}
+
+func decodeDataSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]wasm.DataSegment, error) {
+ vs, _, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return nil, fmt.Errorf("get size of vector: %w", err)
+ }
+
+ result := make([]wasm.DataSegment, vs)
+ for i := uint32(0); i < vs; i++ {
+ if err = decodeDataSegment(r, enabledFeatures, &result[i]); err != nil {
+ return nil, fmt.Errorf("read data segment: %w", err)
+ }
+ }
+ return result, nil
+}
+
+func decodeDataCountSection(r *bytes.Reader) (count *uint32, err error) {
+ v, _, err := leb128.DecodeUint32(r)
+ if err != nil && err != io.EOF {
+ // data count is optional, so EOF is fine.
+ return nil, err
+ }
+ return &v, nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/table.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/table.go
new file mode 100644
index 000000000..353ec7566
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/table.go
@@ -0,0 +1,43 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+// decodeTable returns the wasm.Table decoded with the WebAssembly 1.0 (20191205) Binary Format.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-table
+func decodeTable(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret *wasm.Table) (err error) {
+ ret.Type, err = r.ReadByte()
+ if err != nil {
+ return fmt.Errorf("read leading byte: %v", err)
+ }
+
+ if ret.Type != wasm.RefTypeFuncref {
+ if err = enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("table type funcref is invalid: %w", err)
+ }
+ }
+
+ var shared bool
+ ret.Min, ret.Max, shared, err = decodeLimitsType(r)
+ if err != nil {
+ return fmt.Errorf("read limits: %v", err)
+ }
+ if ret.Min > wasm.MaximumFunctionIndex {
+ return fmt.Errorf("table min must be at most %d", wasm.MaximumFunctionIndex)
+ }
+ if ret.Max != nil {
+ if *ret.Max < ret.Min {
+ return fmt.Errorf("table size minimum must not be greater than maximum")
+ }
+ }
+ if shared {
+ return fmt.Errorf("tables cannot be marked as shared")
+ }
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/value.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/value.go
new file mode 100644
index 000000000..755ee5ea3
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/value.go
@@ -0,0 +1,60 @@
+package binary
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "unicode/utf8"
+ "unsafe"
+
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasm"
+)
+
+func decodeValueTypes(r *bytes.Reader, num uint32) ([]wasm.ValueType, error) {
+ if num == 0 {
+ return nil, nil
+ }
+
+ ret := make([]wasm.ValueType, num)
+ _, err := io.ReadFull(r, ret)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, v := range ret {
+ switch v {
+ case wasm.ValueTypeI32, wasm.ValueTypeF32, wasm.ValueTypeI64, wasm.ValueTypeF64,
+ wasm.ValueTypeExternref, wasm.ValueTypeFuncref, wasm.ValueTypeV128:
+ default:
+ return nil, fmt.Errorf("invalid value type: %d", v)
+ }
+ }
+ return ret, nil
+}
+
+// decodeUTF8 decodes a size prefixed string from the reader, returning it and the count of bytes read.
+// contextFormat and contextArgs apply an error format when present
+func decodeUTF8(r *bytes.Reader, contextFormat string, contextArgs ...interface{}) (string, uint32, error) {
+ size, sizeOfSize, err := leb128.DecodeUint32(r)
+ if err != nil {
+ return "", 0, fmt.Errorf("failed to read %s size: %w", fmt.Sprintf(contextFormat, contextArgs...), err)
+ }
+
+ if size == 0 {
+ return "", uint32(sizeOfSize), nil
+ }
+
+ buf := make([]byte, size)
+ if _, err = io.ReadFull(r, buf); err != nil {
+ return "", 0, fmt.Errorf("failed to read %s: %w", fmt.Sprintf(contextFormat, contextArgs...), err)
+ }
+
+ if !utf8.Valid(buf) {
+ return "", 0, fmt.Errorf("%s is not valid UTF-8", fmt.Sprintf(contextFormat, contextArgs...))
+ }
+
+ // TODO: use unsafe.String after flooring Go 1.20.
+ ret := *(*string)(unsafe.Pointer(&buf))
+ return ret, size + uint32(sizeOfSize), nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/counts.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/counts.go
new file mode 100644
index 000000000..685a40941
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/counts.go
@@ -0,0 +1,51 @@
+package wasm
+
+import "fmt"
+
+// SectionElementCount returns the count of elements in a given section ID
+//
+// For example...
+// * SectionIDType returns the count of FunctionType
+// * SectionIDCustom returns the count of CustomSections plus one if NameSection is present
+// * SectionIDHostFunction returns the count of HostFunctionSection
+// * SectionIDExport returns the count of unique export names
+func (m *Module) SectionElementCount(sectionID SectionID) uint32 { // element as in vector elements!
+ switch sectionID {
+ case SectionIDCustom:
+ numCustomSections := uint32(len(m.CustomSections))
+ if m.NameSection != nil {
+ numCustomSections++
+ }
+ return numCustomSections
+ case SectionIDType:
+ return uint32(len(m.TypeSection))
+ case SectionIDImport:
+ return uint32(len(m.ImportSection))
+ case SectionIDFunction:
+ return uint32(len(m.FunctionSection))
+ case SectionIDTable:
+ return uint32(len(m.TableSection))
+ case SectionIDMemory:
+ if m.MemorySection != nil {
+ return 1
+ }
+ return 0
+ case SectionIDGlobal:
+ return uint32(len(m.GlobalSection))
+ case SectionIDExport:
+ return uint32(len(m.ExportSection))
+ case SectionIDStart:
+ if m.StartSection != nil {
+ return 1
+ }
+ return 0
+ case SectionIDElement:
+ return uint32(len(m.ElementSection))
+ case SectionIDCode:
+ return uint32(len(m.CodeSection))
+ case SectionIDData:
+ return uint32(len(m.DataSection))
+ default:
+ panic(fmt.Errorf("BUG: unknown section: %d", sectionID))
+ }
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/engine.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/engine.go
new file mode 100644
index 000000000..58a458217
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/engine.go
@@ -0,0 +1,72 @@
+package wasm
+
+import (
+ "context"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/experimental"
+)
+
+// Engine is a Store-scoped mechanism to compile functions declared or imported by a module.
+// This is a top-level type implemented by an interpreter or compiler.
+type Engine interface {
+ // Close closes this engine, and releases all the compiled cache.
+ Close() (err error)
+
+ // CompileModule implements the same method as documented on wasm.Engine.
+ CompileModule(ctx context.Context, module *Module, listeners []experimental.FunctionListener, ensureTermination bool) error
+
+ // CompiledModuleCount is exported for testing, to track the size of the compilation cache.
+ CompiledModuleCount() uint32
+
+ // DeleteCompiledModule releases compilation caches for the given module (source).
+ // Note: it is safe to call this function for a module from which module instances are instantiated even when these
+ // module instances have outstanding calls.
+ DeleteCompiledModule(module *Module)
+
+ // NewModuleEngine compiles down the function instances in a module, and returns ModuleEngine for the module.
+ //
+ // * module is the source module from which moduleFunctions are instantiated. This is used for caching.
+ // * instance is the *ModuleInstance which is created from `module`.
+ //
+ // Note: Input parameters must be pre-validated with wasm.Module Validate, to ensure no fields are invalid
+ // due to reasons such as out-of-bounds.
+ NewModuleEngine(module *Module, instance *ModuleInstance) (ModuleEngine, error)
+}
+
+// ModuleEngine implements function calls for a given module.
+type ModuleEngine interface {
+ // DoneInstantiation is called at the end of the instantiation of the module.
+ DoneInstantiation()
+
+ // NewFunction returns an api.Function for the given function pointed by the given Index.
+ NewFunction(index Index) api.Function
+
+ // ResolveImportedFunction is used to add imported functions needed to make this ModuleEngine fully functional.
+ // - `index` is the function Index of this imported function.
+ // - `indexInImportedModule` is the function Index of the imported function in the imported module.
+ // - `importedModuleEngine` is the ModuleEngine for the imported ModuleInstance.
+ ResolveImportedFunction(index, indexInImportedModule Index, importedModuleEngine ModuleEngine)
+
+ // ResolveImportedMemory is called when this module imports a memory from another module.
+ ResolveImportedMemory(importedModuleEngine ModuleEngine)
+
+ // LookupFunction returns the FunctionModule and the Index of the function in the returned ModuleInstance at the given offset in the table.
+ LookupFunction(t *TableInstance, typeId FunctionTypeID, tableOffset Index) (*ModuleInstance, Index)
+
+ // GetGlobalValue returns the value of the global variable at the given Index.
+ // Only called when OwnsGlobals() returns true, and must not be called for imported globals
+ GetGlobalValue(idx Index) (lo, hi uint64)
+
+ // SetGlobalValue sets the value of the global variable at the given Index.
+ // Only called when OwnsGlobals() returns true, and must not be called for imported globals
+ SetGlobalValue(idx Index, lo, hi uint64)
+
+ // OwnsGlobals returns true if this ModuleEngine owns the global variables. If true, wasm.GlobalInstance's Val,ValHi should
+ // not be accessed directly.
+ OwnsGlobals() bool
+
+ // FunctionInstanceReference returns Reference for the given Index for a FunctionInstance. The returned values are used by
+ // the initialization via ElementSegment.
+ FunctionInstanceReference(funcIndex Index) Reference
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/func_validation.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/func_validation.go
new file mode 100644
index 000000000..8da689076
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/func_validation.go
@@ -0,0 +1,2340 @@
+package wasm
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/experimental"
+ "github.com/tetratelabs/wazero/internal/leb128"
+)
+
+// The wazero specific limitation described at RATIONALE.md.
+const maximumValuesOnStack = 1 << 27
+
+// validateFunction validates the instruction sequence of a function.
+// following the specification https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#instructions%E2%91%A2.
+//
+// * idx is the index in the FunctionSection
+// * functions are the function index, which is prefixed by imports. The value is the TypeSection index.
+// * globals are the global index, which is prefixed by imports.
+// * memory is the potentially imported memory and can be nil.
+// * table is the potentially imported table and can be nil.
+// * declaredFunctionIndexes is the set of function indexes declared by declarative element segments which can be acceed by OpcodeRefFunc instruction.
+//
+// Returns an error if the instruction sequence is not valid,
+// or potentially it can exceed the maximum number of values on the stack.
+func (m *Module) validateFunction(sts *stacks, enabledFeatures api.CoreFeatures, idx Index, functions []Index,
+ globals []GlobalType, memory *Memory, tables []Table, declaredFunctionIndexes map[Index]struct{}, br *bytes.Reader,
+) error {
+ return m.validateFunctionWithMaxStackValues(sts, enabledFeatures, idx, functions, globals, memory, tables, maximumValuesOnStack, declaredFunctionIndexes, br)
+}
+
+func readMemArg(pc uint64, body []byte) (align, offset uint32, read uint64, err error) {
+ align, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ err = fmt.Errorf("read memory align: %v", err)
+ return
+ }
+ read += num
+
+ offset, num, err = leb128.LoadUint32(body[pc+num:])
+ if err != nil {
+ err = fmt.Errorf("read memory offset: %v", err)
+ return
+ }
+
+ read += num
+ return align, offset, read, nil
+}
+
+// validateFunctionWithMaxStackValues is like validateFunction, but allows overriding maxStackValues for testing.
+//
+// * stacks is to track the state of Wasm value and control frame stacks at anypoint of execution, and reused to reduce allocation.
+// * maxStackValues is the maximum height of values stack which the target is allowed to reach.
+func (m *Module) validateFunctionWithMaxStackValues(
+ sts *stacks,
+ enabledFeatures api.CoreFeatures,
+ idx Index,
+ functions []Index,
+ globals []GlobalType,
+ memory *Memory,
+ tables []Table,
+ maxStackValues int,
+ declaredFunctionIndexes map[Index]struct{},
+ br *bytes.Reader,
+) error {
+ nonStaticLocals := make(map[Index]struct{})
+ if len(m.NonStaticLocals) > 0 {
+ m.NonStaticLocals[idx] = nonStaticLocals
+ }
+
+ functionType := &m.TypeSection[m.FunctionSection[idx]]
+ code := &m.CodeSection[idx]
+ body := code.Body
+ localTypes := code.LocalTypes
+
+ sts.reset(functionType)
+ valueTypeStack := &sts.vs
+ // We start with the outermost control block which is for function return if the code branches into it.
+ controlBlockStack := &sts.cs
+
+ // Now start walking through all the instructions in the body while tracking
+ // control blocks and value types to check the validity of all instructions.
+ for pc := uint64(0); pc < uint64(len(body)); pc++ {
+ op := body[pc]
+ if false {
+ var instName string
+ if op == OpcodeMiscPrefix {
+ instName = MiscInstructionName(body[pc+1])
+ } else if op == OpcodeVecPrefix {
+ instName = VectorInstructionName(body[pc+1])
+ } else if op == OpcodeAtomicPrefix {
+ instName = AtomicInstructionName(body[pc+1])
+ } else {
+ instName = InstructionName(op)
+ }
+ fmt.Printf("handling %s, stack=%s, blocks: %v\n", instName, valueTypeStack.stack, controlBlockStack)
+ }
+
+ if len(controlBlockStack.stack) == 0 {
+ return fmt.Errorf("unexpected end of function at pc=%#x", pc)
+ }
+
+ if OpcodeI32Load <= op && op <= OpcodeI64Store32 {
+ if memory == nil {
+ return fmt.Errorf("memory must exist for %s", InstructionName(op))
+ }
+ pc++
+ align, _, read, err := readMemArg(pc, body)
+ if err != nil {
+ return err
+ }
+ pc += read - 1
+ switch op {
+ case OpcodeI32Load:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeF32Load:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeF32)
+ case OpcodeI32Store:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeF32Store:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeI64Load:
+ if 1<<align > 64/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeF64Load:
+ if 1<<align > 64/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeF64)
+ case OpcodeI64Store:
+ if 1<<align > 64/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeF64Store:
+ if 1<<align > 64/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeI32Load8S:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI32Load8U:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI64Load8S, OpcodeI64Load8U:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeI32Store8:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeI64Store8:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeI32Load16S, OpcodeI32Load16U:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI64Load16S, OpcodeI64Load16U:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeI32Store16:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeI64Store16:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeI64Load32S, OpcodeI64Load32U:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeI64Store32:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ }
+ } else if OpcodeMemorySize <= op && op <= OpcodeMemoryGrow {
+ if memory == nil {
+ return fmt.Errorf("memory must exist for %s", InstructionName(op))
+ }
+ pc++
+ val, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read immediate: %v", err)
+ }
+ if val != 0 || num != 1 {
+ return fmt.Errorf("memory instruction reserved bytes not zero with 1 byte")
+ }
+ switch Opcode(op) {
+ case OpcodeMemoryGrow:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeMemorySize:
+ valueTypeStack.push(ValueTypeI32)
+ }
+ pc += num - 1
+ } else if OpcodeI32Const <= op && op <= OpcodeF64Const {
+ pc++
+ switch Opcode(op) {
+ case OpcodeI32Const:
+ _, num, err := leb128.LoadInt32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read i32 immediate: %s", err)
+ }
+ pc += num - 1
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI64Const:
+ _, num, err := leb128.LoadInt64(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read i64 immediate: %v", err)
+ }
+ valueTypeStack.push(ValueTypeI64)
+ pc += num - 1
+ case OpcodeF32Const:
+ valueTypeStack.push(ValueTypeF32)
+ pc += 3
+ case OpcodeF64Const:
+ valueTypeStack.push(ValueTypeF64)
+ pc += 7
+ }
+ } else if OpcodeLocalGet <= op && op <= OpcodeGlobalSet {
+ pc++
+ index, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read immediate: %v", err)
+ }
+ pc += num - 1
+ switch op {
+ case OpcodeLocalGet:
+ inputLen := uint32(len(functionType.Params))
+ if l := uint32(len(localTypes)) + inputLen; index >= l {
+ return fmt.Errorf("invalid local index for %s %d >= %d(=len(locals)+len(parameters))",
+ OpcodeLocalGetName, index, l)
+ }
+ if index < inputLen {
+ valueTypeStack.push(functionType.Params[index])
+ } else {
+ valueTypeStack.push(localTypes[index-inputLen])
+ }
+ case OpcodeLocalSet:
+ inputLen := uint32(len(functionType.Params))
+ if l := uint32(len(localTypes)) + inputLen; index >= l {
+ return fmt.Errorf("invalid local index for %s %d >= %d(=len(locals)+len(parameters))",
+ OpcodeLocalSetName, index, l)
+ }
+ nonStaticLocals[index] = struct{}{}
+ var expType ValueType
+ if index < inputLen {
+ expType = functionType.Params[index]
+ } else {
+ expType = localTypes[index-inputLen]
+ }
+ if err := valueTypeStack.popAndVerifyType(expType); err != nil {
+ return err
+ }
+ case OpcodeLocalTee:
+ inputLen := uint32(len(functionType.Params))
+ if l := uint32(len(localTypes)) + inputLen; index >= l {
+ return fmt.Errorf("invalid local index for %s %d >= %d(=len(locals)+len(parameters))",
+ OpcodeLocalTeeName, index, l)
+ }
+ nonStaticLocals[index] = struct{}{}
+ var expType ValueType
+ if index < inputLen {
+ expType = functionType.Params[index]
+ } else {
+ expType = localTypes[index-inputLen]
+ }
+ if err := valueTypeStack.popAndVerifyType(expType); err != nil {
+ return err
+ }
+ valueTypeStack.push(expType)
+ case OpcodeGlobalGet:
+ if index >= uint32(len(globals)) {
+ return fmt.Errorf("invalid index for %s", OpcodeGlobalGetName)
+ }
+ valueTypeStack.push(globals[index].ValType)
+ case OpcodeGlobalSet:
+ if index >= uint32(len(globals)) {
+ return fmt.Errorf("invalid global index")
+ } else if !globals[index].Mutable {
+ return fmt.Errorf("%s when not mutable", OpcodeGlobalSetName)
+ } else if err := valueTypeStack.popAndVerifyType(
+ globals[index].ValType); err != nil {
+ return err
+ }
+ }
+ } else if op == OpcodeBr {
+ pc++
+ index, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read immediate: %v", err)
+ } else if int(index) >= len(controlBlockStack.stack) {
+ return fmt.Errorf("invalid %s operation: index out of range", OpcodeBrName)
+ }
+ pc += num - 1
+ // Check type soundness.
+ target := &controlBlockStack.stack[len(controlBlockStack.stack)-int(index)-1]
+ var targetResultType []ValueType
+ if target.op == OpcodeLoop {
+ targetResultType = target.blockType.Params
+ } else {
+ targetResultType = target.blockType.Results
+ }
+ if err = valueTypeStack.popResults(op, targetResultType, false); err != nil {
+ return err
+ }
+ // br instruction is stack-polymorphic.
+ valueTypeStack.unreachable()
+ } else if op == OpcodeBrIf {
+ pc++
+ index, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read immediate: %v", err)
+ } else if int(index) >= len(controlBlockStack.stack) {
+ return fmt.Errorf(
+ "invalid ln param given for %s: index=%d with %d for the current label stack length",
+ OpcodeBrIfName, index, len(controlBlockStack.stack))
+ }
+ pc += num - 1
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the required operand for %s", OpcodeBrIfName)
+ }
+ // Check type soundness.
+ target := &controlBlockStack.stack[len(controlBlockStack.stack)-int(index)-1]
+ var targetResultType []ValueType
+ if target.op == OpcodeLoop {
+ targetResultType = target.blockType.Params
+ } else {
+ targetResultType = target.blockType.Results
+ }
+ if err := valueTypeStack.popResults(op, targetResultType, false); err != nil {
+ return err
+ }
+ // Push back the result
+ for _, t := range targetResultType {
+ valueTypeStack.push(t)
+ }
+ } else if op == OpcodeBrTable {
+ pc++
+ br.Reset(body[pc:])
+ nl, num, err := leb128.DecodeUint32(br)
+ if err != nil {
+ return fmt.Errorf("read immediate: %w", err)
+ }
+
+ list := make([]uint32, nl)
+ for i := uint32(0); i < nl; i++ {
+ l, n, err := leb128.DecodeUint32(br)
+ if err != nil {
+ return fmt.Errorf("read immediate: %w", err)
+ }
+ num += n
+ list[i] = l
+ }
+ ln, n, err := leb128.DecodeUint32(br)
+ if err != nil {
+ return fmt.Errorf("read immediate: %w", err)
+ } else if int(ln) >= len(controlBlockStack.stack) {
+ return fmt.Errorf(
+ "invalid ln param given for %s: ln=%d with %d for the current label stack length",
+ OpcodeBrTableName, ln, len(controlBlockStack.stack))
+ }
+ pc += n + num - 1
+ // Check type soundness.
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the required operand for %s", OpcodeBrTableName)
+ }
+ lnLabel := &controlBlockStack.stack[len(controlBlockStack.stack)-1-int(ln)]
+ var defaultLabelType []ValueType
+ // Below, we might modify the slice in case of unreachable. Therefore,
+ // we have to copy the content of block result types, otherwise the original
+ // function type might result in invalid value types if the block is the outermost label
+ // which equals the function's type.
+ if lnLabel.op != OpcodeLoop { // Loop operation doesn't require results since the continuation is the beginning of the loop.
+ defaultLabelType = make([]ValueType, len(lnLabel.blockType.Results))
+ copy(defaultLabelType, lnLabel.blockType.Results)
+ } else {
+ defaultLabelType = make([]ValueType, len(lnLabel.blockType.Params))
+ copy(defaultLabelType, lnLabel.blockType.Params)
+ }
+
+ if enabledFeatures.IsEnabled(api.CoreFeatureReferenceTypes) {
+ // As of reference-types proposal, br_table on unreachable state
+ // can choose unknown types for expected parameter types for each label.
+ // https://github.com/WebAssembly/reference-types/pull/116
+ for i := range defaultLabelType {
+ index := len(defaultLabelType) - 1 - i
+ exp := defaultLabelType[index]
+ actual, err := valueTypeStack.pop()
+ if err != nil {
+ return err
+ }
+ if actual == valueTypeUnknown {
+ // Re-assign the expected type to unknown.
+ defaultLabelType[index] = valueTypeUnknown
+ } else if actual != exp {
+ return typeMismatchError(true, OpcodeBrTableName, actual, exp, i)
+ }
+ }
+ } else {
+ if err = valueTypeStack.popResults(op, defaultLabelType, false); err != nil {
+ return err
+ }
+ }
+
+ for _, l := range list {
+ if int(l) >= len(controlBlockStack.stack) {
+ return fmt.Errorf("invalid l param given for %s", OpcodeBrTableName)
+ }
+ label := &controlBlockStack.stack[len(controlBlockStack.stack)-1-int(l)]
+ var tableLabelType []ValueType
+ if label.op != OpcodeLoop {
+ tableLabelType = label.blockType.Results
+ } else {
+ tableLabelType = label.blockType.Params
+ }
+ if len(defaultLabelType) != len(tableLabelType) {
+ return fmt.Errorf("inconsistent block type length for %s at %d; %v (ln=%d) != %v (l=%d)", OpcodeBrTableName, l, defaultLabelType, ln, tableLabelType, l)
+ }
+ for i := range defaultLabelType {
+ if defaultLabelType[i] != valueTypeUnknown && defaultLabelType[i] != tableLabelType[i] {
+ return fmt.Errorf("incosistent block type for %s at %d", OpcodeBrTableName, l)
+ }
+ }
+ }
+
+ // br_table instruction is stack-polymorphic.
+ valueTypeStack.unreachable()
+ } else if op == OpcodeCall {
+ pc++
+ index, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read immediate: %v", err)
+ }
+ pc += num - 1
+ if int(index) >= len(functions) {
+ return fmt.Errorf("invalid function index")
+ }
+ funcType := &m.TypeSection[functions[index]]
+ for i := 0; i < len(funcType.Params); i++ {
+ if err := valueTypeStack.popAndVerifyType(funcType.Params[len(funcType.Params)-1-i]); err != nil {
+ return fmt.Errorf("type mismatch on %s operation param type: %v", OpcodeCallName, err)
+ }
+ }
+ for _, exp := range funcType.Results {
+ valueTypeStack.push(exp)
+ }
+ } else if op == OpcodeCallIndirect {
+ pc++
+ typeIndex, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read immediate: %v", err)
+ }
+ pc += num
+
+ if int(typeIndex) >= len(m.TypeSection) {
+ return fmt.Errorf("invalid type index at %s: %d", OpcodeCallIndirectName, typeIndex)
+ }
+
+ tableIndex, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read table index: %v", err)
+ }
+ pc += num - 1
+ if tableIndex != 0 {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("table index must be zero but was %d: %w", tableIndex, err)
+ }
+ }
+
+ if tableIndex >= uint32(len(tables)) {
+ return fmt.Errorf("unknown table index: %d", tableIndex)
+ }
+
+ table := tables[tableIndex]
+ if table.Type != RefTypeFuncref {
+ return fmt.Errorf("table is not funcref type but was %s for %s", RefTypeName(table.Type), OpcodeCallIndirectName)
+ }
+
+ if err = valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the offset in table for %s", OpcodeCallIndirectName)
+ }
+ funcType := &m.TypeSection[typeIndex]
+ for i := 0; i < len(funcType.Params); i++ {
+ if err = valueTypeStack.popAndVerifyType(funcType.Params[len(funcType.Params)-1-i]); err != nil {
+ return fmt.Errorf("type mismatch on %s operation input type", OpcodeCallIndirectName)
+ }
+ }
+ for _, exp := range funcType.Results {
+ valueTypeStack.push(exp)
+ }
+ } else if OpcodeI32Eqz <= op && op <= OpcodeI64Extend32S {
+ switch op {
+ case OpcodeI32Eqz:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI32EqzName, err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI32Eq, OpcodeI32Ne, OpcodeI32LtS,
+ OpcodeI32LtU, OpcodeI32GtS, OpcodeI32GtU, OpcodeI32LeS,
+ OpcodeI32LeU, OpcodeI32GeS, OpcodeI32GeU:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the 1st i32 operand for %s: %v", InstructionName(op), err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the 2nd i32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI64Eqz:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI64EqzName, err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI64Eq, OpcodeI64Ne, OpcodeI64LtS,
+ OpcodeI64LtU, OpcodeI64GtS, OpcodeI64GtU,
+ OpcodeI64LeS, OpcodeI64LeU, OpcodeI64GeS, OpcodeI64GeU:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the 1st i64 operand for %s: %v", InstructionName(op), err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the 2nd i64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeF32Eq, OpcodeF32Ne, OpcodeF32Lt, OpcodeF32Gt, OpcodeF32Le, OpcodeF32Ge:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return fmt.Errorf("cannot pop the 1st f32 operand for %s: %v", InstructionName(op), err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return fmt.Errorf("cannot pop the 2nd f32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeF64Eq, OpcodeF64Ne, OpcodeF64Lt, OpcodeF64Gt, OpcodeF64Le, OpcodeF64Ge:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return fmt.Errorf("cannot pop the 1st f64 operand for %s: %v", InstructionName(op), err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return fmt.Errorf("cannot pop the 2nd f64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI32Clz, OpcodeI32Ctz, OpcodeI32Popcnt:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI32Add, OpcodeI32Sub, OpcodeI32Mul, OpcodeI32DivS,
+ OpcodeI32DivU, OpcodeI32RemS, OpcodeI32RemU, OpcodeI32And,
+ OpcodeI32Or, OpcodeI32Xor, OpcodeI32Shl, OpcodeI32ShrS,
+ OpcodeI32ShrU, OpcodeI32Rotl, OpcodeI32Rotr:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the 1st operand for %s: %v", InstructionName(op), err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the 2nd operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI64Clz, OpcodeI64Ctz, OpcodeI64Popcnt:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the i64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeI64Add, OpcodeI64Sub, OpcodeI64Mul, OpcodeI64DivS,
+ OpcodeI64DivU, OpcodeI64RemS, OpcodeI64RemU, OpcodeI64And,
+ OpcodeI64Or, OpcodeI64Xor, OpcodeI64Shl, OpcodeI64ShrS,
+ OpcodeI64ShrU, OpcodeI64Rotl, OpcodeI64Rotr:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the 1st i64 operand for %s: %v", InstructionName(op), err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the 2nd i64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeF32Abs, OpcodeF32Neg, OpcodeF32Ceil,
+ OpcodeF32Floor, OpcodeF32Trunc, OpcodeF32Nearest,
+ OpcodeF32Sqrt:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return fmt.Errorf("cannot pop the 1st f32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeF32)
+ case OpcodeF32Add, OpcodeF32Sub, OpcodeF32Mul,
+ OpcodeF32Div, OpcodeF32Min, OpcodeF32Max,
+ OpcodeF32Copysign:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return fmt.Errorf("cannot pop the 1st f32 operand for %s: %v", InstructionName(op), err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return fmt.Errorf("cannot pop the 2nd f32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeF32)
+ case OpcodeF64Abs, OpcodeF64Neg, OpcodeF64Ceil,
+ OpcodeF64Floor, OpcodeF64Trunc, OpcodeF64Nearest,
+ OpcodeF64Sqrt:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return fmt.Errorf("cannot pop the 1st f64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeF64)
+ case OpcodeF64Add, OpcodeF64Sub, OpcodeF64Mul,
+ OpcodeF64Div, OpcodeF64Min, OpcodeF64Max,
+ OpcodeF64Copysign:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return fmt.Errorf("cannot pop the 1st f64 operand for %s: %v", InstructionName(op), err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return fmt.Errorf("cannot pop the 2nd f64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeF64)
+ case OpcodeI32WrapI64:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI32WrapI64Name, err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI32TruncF32S, OpcodeI32TruncF32U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return fmt.Errorf("cannot pop the f32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI32TruncF64S, OpcodeI32TruncF64U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return fmt.Errorf("cannot pop the f64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI64ExtendI32S, OpcodeI64ExtendI32U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeI64TruncF32S, OpcodeI64TruncF32U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return fmt.Errorf("cannot pop the f32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeI64TruncF64S, OpcodeI64TruncF64U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return fmt.Errorf("cannot pop the f64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeF32ConvertI32S, OpcodeF32ConvertI32U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeF32)
+ case OpcodeF32ConvertI64S, OpcodeF32ConvertI64U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the i64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeF32)
+ case OpcodeF32DemoteF64:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF32DemoteF64Name, err)
+ }
+ valueTypeStack.push(ValueTypeF32)
+ case OpcodeF64ConvertI32S, OpcodeF64ConvertI32U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeF64)
+ case OpcodeF64ConvertI64S, OpcodeF64ConvertI64U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the i64 operand for %s: %v", InstructionName(op), err)
+ }
+ valueTypeStack.push(ValueTypeF64)
+ case OpcodeF64PromoteF32:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF64PromoteF32Name, err)
+ }
+ valueTypeStack.push(ValueTypeF64)
+ case OpcodeI32ReinterpretF32:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI32ReinterpretF32Name, err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI64ReinterpretF64:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI64ReinterpretF64Name, err)
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeF32ReinterpretI32:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF32ReinterpretI32Name, err)
+ }
+ valueTypeStack.push(ValueTypeF32)
+ case OpcodeF64ReinterpretI64:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF64ReinterpretI64Name, err)
+ }
+ valueTypeStack.push(ValueTypeF64)
+ case OpcodeI32Extend8S, OpcodeI32Extend16S:
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureSignExtensionOps); err != nil {
+ return fmt.Errorf("%s invalid as %v", instructionNames[op], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", instructionNames[op], err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeI64Extend8S, OpcodeI64Extend16S, OpcodeI64Extend32S:
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureSignExtensionOps); err != nil {
+ return fmt.Errorf("%s invalid as %v", instructionNames[op], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", instructionNames[op], err)
+ }
+ valueTypeStack.push(ValueTypeI64)
+ default:
+ return fmt.Errorf("invalid numeric instruction 0x%x", op)
+ }
+ } else if op >= OpcodeRefNull && op <= OpcodeRefFunc {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("%s invalid as %v", instructionNames[op], err)
+ }
+ switch op {
+ case OpcodeRefNull:
+ pc++
+ switch reftype := body[pc]; reftype {
+ case ValueTypeExternref:
+ valueTypeStack.push(ValueTypeExternref)
+ case ValueTypeFuncref:
+ valueTypeStack.push(ValueTypeFuncref)
+ default:
+ return fmt.Errorf("unknown type for ref.null: 0x%x", reftype)
+ }
+ case OpcodeRefIsNull:
+ tp, err := valueTypeStack.pop()
+ if err != nil {
+ return fmt.Errorf("cannot pop the operand for ref.is_null: %v", err)
+ } else if !isReferenceValueType(tp) && tp != valueTypeUnknown {
+ return fmt.Errorf("type mismatch: expected reference type but was %s", ValueTypeName(tp))
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeRefFunc:
+ pc++
+ index, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read function index for ref.func: %v", err)
+ }
+ if _, ok := declaredFunctionIndexes[index]; !ok {
+ return fmt.Errorf("undeclared function index %d for ref.func", index)
+ }
+ pc += num - 1
+ valueTypeStack.push(ValueTypeFuncref)
+ }
+ } else if op == OpcodeTableGet || op == OpcodeTableSet {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("%s is invalid as %v", InstructionName(op), err)
+ }
+ pc++
+ tableIndex, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("read immediate: %v", err)
+ }
+ if tableIndex >= uint32(len(tables)) {
+ return fmt.Errorf("table of index %d not found", tableIndex)
+ }
+
+ refType := tables[tableIndex].Type
+ if op == OpcodeTableGet {
+ if err := valueTypeStack.popAndVerifyType(api.ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for table.get: %v", err)
+ }
+ valueTypeStack.push(refType)
+ } else {
+ if err := valueTypeStack.popAndVerifyType(refType); err != nil {
+ return fmt.Errorf("cannot pop the operand for table.set: %v", err)
+ }
+ if err := valueTypeStack.popAndVerifyType(api.ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for table.set: %v", err)
+ }
+ }
+ pc += num - 1
+ } else if op == OpcodeMiscPrefix {
+ pc++
+ // A misc opcode is encoded as an unsigned variable 32-bit integer.
+ miscOp32, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read misc opcode: %v", err)
+ }
+ pc += num - 1
+ miscOpcode := byte(miscOp32)
+ // If the misc opcode is beyond byte range, it is highly likely this is an invalid binary, or
+ // it is due to the new opcode from a new proposal. In the latter case, we have to
+ // change the alias type of OpcodeMisc (which is currently byte) to uint32.
+ if uint32(byte(miscOp32)) != miscOp32 {
+ return fmt.Errorf("invalid misc opcode: %#x", miscOp32)
+ }
+ if miscOpcode >= OpcodeMiscI32TruncSatF32S && miscOpcode <= OpcodeMiscI64TruncSatF64U {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureNonTrappingFloatToIntConversion); err != nil {
+ return fmt.Errorf("%s invalid as %v", miscInstructionNames[miscOpcode], err)
+ }
+ var inType, outType ValueType
+ switch miscOpcode {
+ case OpcodeMiscI32TruncSatF32S, OpcodeMiscI32TruncSatF32U:
+ inType, outType = ValueTypeF32, ValueTypeI32
+ case OpcodeMiscI32TruncSatF64S, OpcodeMiscI32TruncSatF64U:
+ inType, outType = ValueTypeF64, ValueTypeI32
+ case OpcodeMiscI64TruncSatF32S, OpcodeMiscI64TruncSatF32U:
+ inType, outType = ValueTypeF32, ValueTypeI64
+ case OpcodeMiscI64TruncSatF64S, OpcodeMiscI64TruncSatF64U:
+ inType, outType = ValueTypeF64, ValueTypeI64
+ }
+ if err := valueTypeStack.popAndVerifyType(inType); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", miscInstructionNames[miscOpcode], err)
+ }
+ valueTypeStack.push(outType)
+ } else if miscOpcode >= OpcodeMiscMemoryInit && miscOpcode <= OpcodeMiscTableCopy {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
+ return fmt.Errorf("%s invalid as %v", miscInstructionNames[miscOpcode], err)
+ }
+ var params []ValueType
+ // Handle opcodes added in bulk-memory-operations/WebAssembly 2.0.
+ switch miscOpcode {
+ case OpcodeMiscDataDrop:
+ if m.DataCountSection == nil {
+ return fmt.Errorf("%s requires data count section", MiscInstructionName(miscOpcode))
+ }
+
+ // We need to read the index to the data section.
+ pc++
+ index, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(miscOpcode), err)
+ }
+ if int(index) >= len(m.DataSection) {
+ return fmt.Errorf("index %d out of range of data section(len=%d)", index, len(m.DataSection))
+ }
+ pc += num - 1
+ case OpcodeMiscMemoryInit, OpcodeMiscMemoryCopy, OpcodeMiscMemoryFill:
+ if memory == nil {
+ return fmt.Errorf("memory must exist for %s", MiscInstructionName(miscOpcode))
+ }
+ params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
+
+ if miscOpcode == OpcodeMiscMemoryInit {
+ if m.DataCountSection == nil {
+ return fmt.Errorf("%s requires data count section", MiscInstructionName(miscOpcode))
+ }
+
+ // We need to read the index to the data section.
+ pc++
+ index, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(miscOpcode), err)
+ }
+ if int(index) >= len(m.DataSection) {
+ return fmt.Errorf("index %d out of range of data section(len=%d)", index, len(m.DataSection))
+ }
+ pc += num - 1
+ }
+
+ pc++
+ val, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(miscOpcode), err)
+ }
+ if val != 0 || num != 1 {
+ return fmt.Errorf("%s reserved byte must be zero encoded with 1 byte", MiscInstructionName(miscOpcode))
+ }
+ if miscOpcode == OpcodeMiscMemoryCopy {
+ pc++
+ // memory.copy needs two memory index which are reserved as zero.
+ val, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(miscOpcode), err)
+ }
+ if val != 0 || num != 1 {
+ return fmt.Errorf("%s reserved byte must be zero encoded with 1 byte", MiscInstructionName(miscOpcode))
+ }
+ }
+
+ case OpcodeMiscTableInit:
+ params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
+ pc++
+ elementIndex, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(miscOpcode), err)
+ }
+ if int(elementIndex) >= len(m.ElementSection) {
+ return fmt.Errorf("index %d out of range of element section(len=%d)", elementIndex, len(m.ElementSection))
+ }
+ pc += num
+
+ tableIndex, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(miscOpcode), err)
+ }
+ if tableIndex != 0 {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("source table index must be zero for %s as %v", MiscInstructionName(miscOpcode), err)
+ }
+ }
+ if tableIndex >= uint32(len(tables)) {
+ return fmt.Errorf("table of index %d not found", tableIndex)
+ }
+
+ if m.ElementSection[elementIndex].Type != tables[tableIndex].Type {
+ return fmt.Errorf("type mismatch for table.init: element type %s does not match table type %s",
+ RefTypeName(m.ElementSection[elementIndex].Type),
+ RefTypeName(tables[tableIndex].Type),
+ )
+ }
+ pc += num - 1
+ case OpcodeMiscElemDrop:
+ pc++
+ elementIndex, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(miscOpcode), err)
+ } else if int(elementIndex) >= len(m.ElementSection) {
+ return fmt.Errorf("index %d out of range of element section(len=%d)", elementIndex, len(m.ElementSection))
+ }
+ pc += num - 1
+ case OpcodeMiscTableCopy:
+ params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
+ pc++
+
+ dstTableIndex, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read destination table index for %s: %v", MiscInstructionName(miscOpcode), err)
+ }
+ if dstTableIndex != 0 {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("destination table index must be zero for %s as %v", MiscInstructionName(miscOpcode), err)
+ }
+ }
+ if dstTableIndex >= uint32(len(tables)) {
+ return fmt.Errorf("table of index %d not found", dstTableIndex)
+ }
+ pc += num
+
+ srcTableIndex, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(miscOpcode), err)
+ }
+ if srcTableIndex != 0 {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("source table index must be zero for %s as %v", MiscInstructionName(miscOpcode), err)
+ }
+ }
+ if srcTableIndex >= uint32(len(tables)) {
+ return fmt.Errorf("table of index %d not found", srcTableIndex)
+ }
+
+ if tables[srcTableIndex].Type != tables[dstTableIndex].Type {
+ return fmt.Errorf("table type mismatch for table.copy: %s (src) != %s (dst)",
+ RefTypeName(tables[srcTableIndex].Type), RefTypeName(tables[dstTableIndex].Type))
+ }
+
+ pc += num - 1
+ }
+ for _, p := range params {
+ if err := valueTypeStack.popAndVerifyType(p); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", miscInstructionNames[miscOpcode], err)
+ }
+ }
+ } else if miscOpcode >= OpcodeMiscTableGrow && miscOpcode <= OpcodeMiscTableFill {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("%s invalid as %v", miscInstructionNames[miscOpcode], err)
+ }
+
+ pc++
+ tableIndex, num, err := leb128.LoadUint32(body[pc:])
+ if err != nil {
+ return fmt.Errorf("failed to read table index for %s: %v", MiscInstructionName(miscOpcode), err)
+ }
+ if tableIndex >= uint32(len(tables)) {
+ return fmt.Errorf("table of index %d not found", tableIndex)
+ }
+ pc += num - 1
+
+ var params, results []ValueType
+ reftype := tables[tableIndex].Type
+ if miscOpcode == OpcodeMiscTableGrow {
+ params = []ValueType{ValueTypeI32, reftype}
+ results = []ValueType{ValueTypeI32}
+ } else if miscOpcode == OpcodeMiscTableSize {
+ results = []ValueType{ValueTypeI32}
+ } else if miscOpcode == OpcodeMiscTableFill {
+ params = []ValueType{ValueTypeI32, reftype, ValueTypeI32}
+ }
+
+ for _, p := range params {
+ if err := valueTypeStack.popAndVerifyType(p); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", miscInstructionNames[miscOpcode], err)
+ }
+ }
+ for _, r := range results {
+ valueTypeStack.push(r)
+ }
+ } else {
+ return fmt.Errorf("unknown misc opcode %#x", miscOpcode)
+ }
+ } else if op == OpcodeVecPrefix {
+ pc++
+ // Vector instructions come with two bytes where the first byte is always OpcodeVecPrefix,
+ // and the second byte determines the actual instruction.
+ vecOpcode := body[pc]
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureSIMD); err != nil {
+ return fmt.Errorf("%s invalid as %v", vectorInstructionName[vecOpcode], err)
+ }
+
+ switch vecOpcode {
+ case OpcodeVecV128Const:
+ // Read 128-bit = 16 bytes constants
+ if int(pc+16) >= len(body) {
+ return fmt.Errorf("cannot read constant vector value for %s", vectorInstructionName[vecOpcode])
+ }
+ pc += 16
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecV128AnyTrue, OpcodeVecI8x16AllTrue, OpcodeVecI16x8AllTrue, OpcodeVecI32x4AllTrue, OpcodeVecI64x2AllTrue,
+ OpcodeVecI8x16BitMask, OpcodeVecI16x8BitMask, OpcodeVecI32x4BitMask, OpcodeVecI64x2BitMask:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeVecV128Load, OpcodeVecV128Load8x8s, OpcodeVecV128Load8x8u, OpcodeVecV128Load16x4s, OpcodeVecV128Load16x4u,
+ OpcodeVecV128Load32x2s, OpcodeVecV128Load32x2u, OpcodeVecV128Load8Splat, OpcodeVecV128Load16Splat,
+ OpcodeVecV128Load32Splat, OpcodeVecV128Load64Splat,
+ OpcodeVecV128Load32zero, OpcodeVecV128Load64zero:
+ if memory == nil {
+ return fmt.Errorf("memory must exist for %s", VectorInstructionName(vecOpcode))
+ }
+ pc++
+ align, _, read, err := readMemArg(pc, body)
+ if err != nil {
+ return err
+ }
+ pc += read - 1
+ var maxAlign uint32
+ switch vecOpcode {
+ case OpcodeVecV128Load:
+ maxAlign = 128 / 8
+ case OpcodeVecV128Load8x8s, OpcodeVecV128Load8x8u, OpcodeVecV128Load16x4s, OpcodeVecV128Load16x4u,
+ OpcodeVecV128Load32x2s, OpcodeVecV128Load32x2u:
+ maxAlign = 64 / 8
+ case OpcodeVecV128Load8Splat:
+ maxAlign = 1
+ case OpcodeVecV128Load16Splat:
+ maxAlign = 16 / 8
+ case OpcodeVecV128Load32Splat:
+ maxAlign = 32 / 8
+ case OpcodeVecV128Load64Splat:
+ maxAlign = 64 / 8
+ case OpcodeVecV128Load32zero:
+ maxAlign = 32 / 8
+ case OpcodeVecV128Load64zero:
+ maxAlign = 64 / 8
+ }
+
+ if 1<<align > maxAlign {
+ return fmt.Errorf("invalid memory alignment %d for %s", align, VectorInstructionName(vecOpcode))
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", VectorInstructionName(vecOpcode), err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecV128Store:
+ if memory == nil {
+ return fmt.Errorf("memory must exist for %s", VectorInstructionName(vecOpcode))
+ }
+ pc++
+ align, _, read, err := readMemArg(pc, body)
+ if err != nil {
+ return err
+ }
+ pc += read - 1
+ if 1<<align > 128/8 {
+ return fmt.Errorf("invalid memory alignment %d for %s", align, OpcodeVecV128StoreName)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeVecV128StoreName, err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeVecV128StoreName, err)
+ }
+ case OpcodeVecV128Load8Lane, OpcodeVecV128Load16Lane, OpcodeVecV128Load32Lane, OpcodeVecV128Load64Lane:
+ if memory == nil {
+ return fmt.Errorf("memory must exist for %s", VectorInstructionName(vecOpcode))
+ }
+ attr := vecLoadLanes[vecOpcode]
+ pc++
+ align, _, read, err := readMemArg(pc, body)
+ if err != nil {
+ return err
+ }
+ if 1<<align > attr.alignMax {
+ return fmt.Errorf("invalid memory alignment %d for %s", align, vectorInstructionName[vecOpcode])
+ }
+ pc += read
+ if pc >= uint64(len(body)) {
+ return fmt.Errorf("lane for %s not found", OpcodeVecV128Load64LaneName)
+ }
+ lane := body[pc]
+ if lane >= attr.laneCeil {
+ return fmt.Errorf("invalid lane index %d >= %d for %s", lane, attr.laneCeil, vectorInstructionName[vecOpcode])
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecV128Store8Lane, OpcodeVecV128Store16Lane, OpcodeVecV128Store32Lane, OpcodeVecV128Store64Lane:
+ if memory == nil {
+ return fmt.Errorf("memory must exist for %s", VectorInstructionName(vecOpcode))
+ }
+ attr := vecStoreLanes[vecOpcode]
+ pc++
+ align, _, read, err := readMemArg(pc, body)
+ if err != nil {
+ return err
+ }
+ if 1<<align > attr.alignMax {
+ return fmt.Errorf("invalid memory alignment %d for %s", align, vectorInstructionName[vecOpcode])
+ }
+ pc += read
+ if pc >= uint64(len(body)) {
+ return fmt.Errorf("lane for %s not found", vectorInstructionName[vecOpcode])
+ }
+ lane := body[pc]
+ if lane >= attr.laneCeil {
+ return fmt.Errorf("invalid lane index %d >= %d for %s", lane, attr.laneCeil, vectorInstructionName[vecOpcode])
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ case OpcodeVecI8x16ExtractLaneS,
+ OpcodeVecI8x16ExtractLaneU,
+ OpcodeVecI16x8ExtractLaneS,
+ OpcodeVecI16x8ExtractLaneU,
+ OpcodeVecI32x4ExtractLane,
+ OpcodeVecI64x2ExtractLane,
+ OpcodeVecF32x4ExtractLane,
+ OpcodeVecF64x2ExtractLane:
+ pc++
+ if pc >= uint64(len(body)) {
+ return fmt.Errorf("lane for %s not found", vectorInstructionName[vecOpcode])
+ }
+ attr := vecExtractLanes[vecOpcode]
+ lane := body[pc]
+ if lane >= attr.laneCeil {
+ return fmt.Errorf("invalid lane index %d >= %d for %s", lane, attr.laneCeil, vectorInstructionName[vecOpcode])
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(attr.resultType)
+ case OpcodeVecI8x16ReplaceLane, OpcodeVecI16x8ReplaceLane, OpcodeVecI32x4ReplaceLane,
+ OpcodeVecI64x2ReplaceLane, OpcodeVecF32x4ReplaceLane, OpcodeVecF64x2ReplaceLane:
+ pc++
+ if pc >= uint64(len(body)) {
+ return fmt.Errorf("lane for %s not found", vectorInstructionName[vecOpcode])
+ }
+ attr := vecReplaceLanes[vecOpcode]
+ lane := body[pc]
+ if lane >= attr.laneCeil {
+ return fmt.Errorf("invalid lane index %d >= %d for %s", lane, attr.laneCeil, vectorInstructionName[vecOpcode])
+ }
+ if err := valueTypeStack.popAndVerifyType(attr.paramType); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecI8x16Splat, OpcodeVecI16x8Splat, OpcodeVecI32x4Splat,
+ OpcodeVecI64x2Splat, OpcodeVecF32x4Splat, OpcodeVecF64x2Splat:
+ tp := vecSplatValueTypes[vecOpcode]
+ if err := valueTypeStack.popAndVerifyType(tp); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecI8x16Swizzle, OpcodeVecV128And, OpcodeVecV128Or, OpcodeVecV128Xor, OpcodeVecV128AndNot:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecV128Bitselect:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecV128Not:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecV128i8x16Shuffle:
+ pc++
+ if pc+15 >= uint64(len(body)) {
+ return fmt.Errorf("16 lane indexes for %s not found", vectorInstructionName[vecOpcode])
+ }
+ lanes := body[pc : pc+16]
+ for i, l := range lanes {
+ if l >= 32 {
+ return fmt.Errorf("invalid lane index[%d] %d >= %d for %s", i, l, 32, vectorInstructionName[vecOpcode])
+ }
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ pc += 15
+ case OpcodeVecI8x16Shl, OpcodeVecI8x16ShrS, OpcodeVecI8x16ShrU,
+ OpcodeVecI16x8Shl, OpcodeVecI16x8ShrS, OpcodeVecI16x8ShrU,
+ OpcodeVecI32x4Shl, OpcodeVecI32x4ShrS, OpcodeVecI32x4ShrU,
+ OpcodeVecI64x2Shl, OpcodeVecI64x2ShrS, OpcodeVecI64x2ShrU:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecI8x16Eq, OpcodeVecI8x16Ne, OpcodeVecI8x16LtS, OpcodeVecI8x16LtU, OpcodeVecI8x16GtS,
+ OpcodeVecI8x16GtU, OpcodeVecI8x16LeS, OpcodeVecI8x16LeU, OpcodeVecI8x16GeS, OpcodeVecI8x16GeU,
+ OpcodeVecI16x8Eq, OpcodeVecI16x8Ne, OpcodeVecI16x8LtS, OpcodeVecI16x8LtU, OpcodeVecI16x8GtS,
+ OpcodeVecI16x8GtU, OpcodeVecI16x8LeS, OpcodeVecI16x8LeU, OpcodeVecI16x8GeS, OpcodeVecI16x8GeU,
+ OpcodeVecI32x4Eq, OpcodeVecI32x4Ne, OpcodeVecI32x4LtS, OpcodeVecI32x4LtU, OpcodeVecI32x4GtS,
+ OpcodeVecI32x4GtU, OpcodeVecI32x4LeS, OpcodeVecI32x4LeU, OpcodeVecI32x4GeS, OpcodeVecI32x4GeU,
+ OpcodeVecI64x2Eq, OpcodeVecI64x2Ne, OpcodeVecI64x2LtS, OpcodeVecI64x2GtS, OpcodeVecI64x2LeS,
+ OpcodeVecI64x2GeS, OpcodeVecF32x4Eq, OpcodeVecF32x4Ne, OpcodeVecF32x4Lt, OpcodeVecF32x4Gt,
+ OpcodeVecF32x4Le, OpcodeVecF32x4Ge, OpcodeVecF64x2Eq, OpcodeVecF64x2Ne, OpcodeVecF64x2Lt,
+ OpcodeVecF64x2Gt, OpcodeVecF64x2Le, OpcodeVecF64x2Ge,
+ OpcodeVecI32x4DotI16x8S,
+ OpcodeVecI8x16NarrowI16x8S, OpcodeVecI8x16NarrowI16x8U, OpcodeVecI16x8NarrowI32x4S, OpcodeVecI16x8NarrowI32x4U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ case OpcodeVecI8x16Neg, OpcodeVecI16x8Neg, OpcodeVecI32x4Neg, OpcodeVecI64x2Neg, OpcodeVecF32x4Neg, OpcodeVecF64x2Neg,
+ OpcodeVecF32x4Sqrt, OpcodeVecF64x2Sqrt,
+ OpcodeVecI8x16Abs, OpcodeVecI8x16Popcnt, OpcodeVecI16x8Abs, OpcodeVecI32x4Abs, OpcodeVecI64x2Abs,
+ OpcodeVecF32x4Abs, OpcodeVecF64x2Abs,
+ OpcodeVecF32x4Ceil, OpcodeVecF32x4Floor, OpcodeVecF32x4Trunc, OpcodeVecF32x4Nearest,
+ OpcodeVecF64x2Ceil, OpcodeVecF64x2Floor, OpcodeVecF64x2Trunc, OpcodeVecF64x2Nearest,
+ OpcodeVecI16x8ExtendLowI8x16S, OpcodeVecI16x8ExtendHighI8x16S, OpcodeVecI16x8ExtendLowI8x16U, OpcodeVecI16x8ExtendHighI8x16U,
+ OpcodeVecI32x4ExtendLowI16x8S, OpcodeVecI32x4ExtendHighI16x8S, OpcodeVecI32x4ExtendLowI16x8U, OpcodeVecI32x4ExtendHighI16x8U,
+ OpcodeVecI64x2ExtendLowI32x4S, OpcodeVecI64x2ExtendHighI32x4S, OpcodeVecI64x2ExtendLowI32x4U, OpcodeVecI64x2ExtendHighI32x4U,
+ OpcodeVecI16x8ExtaddPairwiseI8x16S, OpcodeVecI16x8ExtaddPairwiseI8x16U,
+ OpcodeVecI32x4ExtaddPairwiseI16x8S, OpcodeVecI32x4ExtaddPairwiseI16x8U,
+ OpcodeVecF64x2PromoteLowF32x4Zero, OpcodeVecF32x4DemoteF64x2Zero,
+ OpcodeVecF32x4ConvertI32x4S, OpcodeVecF32x4ConvertI32x4U,
+ OpcodeVecF64x2ConvertLowI32x4S, OpcodeVecF64x2ConvertLowI32x4U,
+ OpcodeVecI32x4TruncSatF32x4S, OpcodeVecI32x4TruncSatF32x4U, OpcodeVecI32x4TruncSatF64x2SZero, OpcodeVecI32x4TruncSatF64x2UZero:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+
+ case OpcodeVecI8x16Add, OpcodeVecI8x16AddSatS, OpcodeVecI8x16AddSatU, OpcodeVecI8x16Sub, OpcodeVecI8x16SubSatS, OpcodeVecI8x16SubSatU,
+ OpcodeVecI16x8Add, OpcodeVecI16x8AddSatS, OpcodeVecI16x8AddSatU, OpcodeVecI16x8Sub, OpcodeVecI16x8SubSatS, OpcodeVecI16x8SubSatU, OpcodeVecI16x8Mul,
+ OpcodeVecI32x4Add, OpcodeVecI32x4Sub, OpcodeVecI32x4Mul,
+ OpcodeVecI64x2Add, OpcodeVecI64x2Sub, OpcodeVecI64x2Mul,
+ OpcodeVecF32x4Add, OpcodeVecF32x4Sub, OpcodeVecF32x4Mul, OpcodeVecF32x4Div,
+ OpcodeVecF64x2Add, OpcodeVecF64x2Sub, OpcodeVecF64x2Mul, OpcodeVecF64x2Div,
+ OpcodeVecI8x16MinS, OpcodeVecI8x16MinU, OpcodeVecI8x16MaxS, OpcodeVecI8x16MaxU,
+ OpcodeVecI8x16AvgrU,
+ OpcodeVecI16x8MinS, OpcodeVecI16x8MinU, OpcodeVecI16x8MaxS, OpcodeVecI16x8MaxU,
+ OpcodeVecI16x8AvgrU,
+ OpcodeVecI32x4MinS, OpcodeVecI32x4MinU, OpcodeVecI32x4MaxS, OpcodeVecI32x4MaxU,
+ OpcodeVecF32x4Min, OpcodeVecF32x4Max, OpcodeVecF64x2Min, OpcodeVecF64x2Max,
+ OpcodeVecF32x4Pmin, OpcodeVecF32x4Pmax, OpcodeVecF64x2Pmin, OpcodeVecF64x2Pmax,
+ OpcodeVecI16x8Q15mulrSatS,
+ OpcodeVecI16x8ExtMulLowI8x16S, OpcodeVecI16x8ExtMulHighI8x16S, OpcodeVecI16x8ExtMulLowI8x16U, OpcodeVecI16x8ExtMulHighI8x16U,
+ OpcodeVecI32x4ExtMulLowI16x8S, OpcodeVecI32x4ExtMulHighI16x8S, OpcodeVecI32x4ExtMulLowI16x8U, OpcodeVecI32x4ExtMulHighI16x8U,
+ OpcodeVecI64x2ExtMulLowI32x4S, OpcodeVecI64x2ExtMulHighI32x4S, OpcodeVecI64x2ExtMulLowI32x4U, OpcodeVecI64x2ExtMulHighI32x4U:
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
+ return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
+ }
+ valueTypeStack.push(ValueTypeV128)
+ default:
+ return fmt.Errorf("unknown SIMD instruction %s", vectorInstructionName[vecOpcode])
+ }
+ } else if op == OpcodeBlock {
+ br.Reset(body[pc+1:])
+ bt, num, err := DecodeBlockType(m.TypeSection, br, enabledFeatures)
+ if err != nil {
+ return fmt.Errorf("read block: %w", err)
+ }
+ controlBlockStack.push(pc, 0, 0, bt, num, 0)
+ if err = valueTypeStack.popParams(op, bt.Params, false); err != nil {
+ return err
+ }
+ // Plus we have to push any block params again.
+ for _, p := range bt.Params {
+ valueTypeStack.push(p)
+ }
+ valueTypeStack.pushStackLimit(len(bt.Params))
+ pc += num
+ } else if op == OpcodeAtomicPrefix {
+ pc++
+ // Atomic instructions come with two bytes where the first byte is always OpcodeAtomicPrefix,
+ // and the second byte determines the actual instruction.
+ atomicOpcode := body[pc]
+ if err := enabledFeatures.RequireEnabled(experimental.CoreFeaturesThreads); err != nil {
+ return fmt.Errorf("%s invalid as %v", atomicInstructionName[atomicOpcode], err)
+ }
+ pc++
+
+ if atomicOpcode == OpcodeAtomicFence {
+ // No memory requirement and no arguments or return, however the immediate byte value must be 0.
+ imm := body[pc]
+ if imm != 0x0 {
+ return fmt.Errorf("invalid immediate value for %s", AtomicInstructionName(atomicOpcode))
+ }
+ continue
+ }
+
+ // All atomic operations except fence (checked above) require memory
+ if memory == nil {
+ return fmt.Errorf("memory must exist for %s", AtomicInstructionName(atomicOpcode))
+ }
+ align, _, read, err := readMemArg(pc, body)
+ if err != nil {
+ return err
+ }
+ pc += read - 1
+ switch atomicOpcode {
+ case OpcodeAtomicMemoryNotify:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicMemoryWait32:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicMemoryWait64:
+ if 1<<align > 64/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI32Load:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI64Load:
+ if 1<<align > 64/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI32Load8U:
+ if 1<<align != 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI32Load16U:
+ if 1<<align != 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI64Load8U:
+ if 1<<align != 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI64Load16U:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI64Load32U:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI32Store:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeAtomicI64Store:
+ if 1<<align > 64/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeAtomicI32Store8:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeAtomicI32Store16:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeAtomicI64Store8:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeAtomicI64Store16:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeAtomicI64Store32:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ case OpcodeAtomicI32RmwAdd, OpcodeAtomicI32RmwSub, OpcodeAtomicI32RmwAnd, OpcodeAtomicI32RmwOr, OpcodeAtomicI32RmwXor, OpcodeAtomicI32RmwXchg:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI32Rmw8AddU, OpcodeAtomicI32Rmw8SubU, OpcodeAtomicI32Rmw8AndU, OpcodeAtomicI32Rmw8OrU, OpcodeAtomicI32Rmw8XorU, OpcodeAtomicI32Rmw8XchgU:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI32Rmw16AddU, OpcodeAtomicI32Rmw16SubU, OpcodeAtomicI32Rmw16AndU, OpcodeAtomicI32Rmw16OrU, OpcodeAtomicI32Rmw16XorU, OpcodeAtomicI32Rmw16XchgU:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI64RmwAdd, OpcodeAtomicI64RmwSub, OpcodeAtomicI64RmwAnd, OpcodeAtomicI64RmwOr, OpcodeAtomicI64RmwXor, OpcodeAtomicI64RmwXchg:
+ if 1<<align > 64/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI64Rmw8AddU, OpcodeAtomicI64Rmw8SubU, OpcodeAtomicI64Rmw8AndU, OpcodeAtomicI64Rmw8OrU, OpcodeAtomicI64Rmw8XorU, OpcodeAtomicI64Rmw8XchgU:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI64Rmw16AddU, OpcodeAtomicI64Rmw16SubU, OpcodeAtomicI64Rmw16AndU, OpcodeAtomicI64Rmw16OrU, OpcodeAtomicI64Rmw16XorU, OpcodeAtomicI64Rmw16XchgU:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI64Rmw32AddU, OpcodeAtomicI64Rmw32SubU, OpcodeAtomicI64Rmw32AndU, OpcodeAtomicI64Rmw32OrU, OpcodeAtomicI64Rmw32XorU, OpcodeAtomicI64Rmw32XchgU:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI32RmwCmpxchg:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI32Rmw8CmpxchgU:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI32Rmw16CmpxchgU:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI32)
+ case OpcodeAtomicI64RmwCmpxchg:
+ if 1<<align > 64/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI64Rmw8CmpxchgU:
+ if 1<<align > 1 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI64Rmw16CmpxchgU:
+ if 1<<align > 16/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ case OpcodeAtomicI64Rmw32CmpxchgU:
+ if 1<<align > 32/8 {
+ return fmt.Errorf("invalid memory alignment")
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
+ return err
+ }
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return err
+ }
+ valueTypeStack.push(ValueTypeI64)
+ default:
+ return fmt.Errorf("invalid atomic opcode: 0x%x", atomicOpcode)
+ }
+ } else if op == OpcodeLoop {
+ br.Reset(body[pc+1:])
+ bt, num, err := DecodeBlockType(m.TypeSection, br, enabledFeatures)
+ if err != nil {
+ return fmt.Errorf("read block: %w", err)
+ }
+ controlBlockStack.push(pc, 0, 0, bt, num, op)
+ if err = valueTypeStack.popParams(op, bt.Params, false); err != nil {
+ return err
+ }
+ // Plus we have to push any block params again.
+ for _, p := range bt.Params {
+ valueTypeStack.push(p)
+ }
+ valueTypeStack.pushStackLimit(len(bt.Params))
+ pc += num
+ } else if op == OpcodeIf {
+ br.Reset(body[pc+1:])
+ bt, num, err := DecodeBlockType(m.TypeSection, br, enabledFeatures)
+ if err != nil {
+ return fmt.Errorf("read block: %w", err)
+ }
+ controlBlockStack.push(pc, 0, 0, bt, num, op)
+ if err = valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("cannot pop the operand for 'if': %v", err)
+ }
+ if err = valueTypeStack.popParams(op, bt.Params, false); err != nil {
+ return err
+ }
+ // Plus we have to push any block params again.
+ for _, p := range bt.Params {
+ valueTypeStack.push(p)
+ }
+ valueTypeStack.pushStackLimit(len(bt.Params))
+ pc += num
+ } else if op == OpcodeElse {
+ bl := &controlBlockStack.stack[len(controlBlockStack.stack)-1]
+ if bl.op != OpcodeIf {
+ return fmt.Errorf("else instruction must be used in if block: %#x", pc)
+ }
+ bl.op = OpcodeElse
+ bl.elseAt = pc
+ // Check the type soundness of the instructions *before* entering this else Op.
+ if err := valueTypeStack.popResults(OpcodeIf, bl.blockType.Results, true); err != nil {
+ return err
+ }
+ // Before entering instructions inside else, we pop all the values pushed by then block.
+ valueTypeStack.resetAtStackLimit()
+ // Plus we have to push any block params again.
+ for _, p := range bl.blockType.Params {
+ valueTypeStack.push(p)
+ }
+ } else if op == OpcodeEnd {
+ bl := controlBlockStack.pop()
+ bl.endAt = pc
+
+ // OpcodeEnd can end a block or the function itself. Check to see what it is:
+
+ ifMissingElse := bl.op == OpcodeIf && bl.elseAt <= bl.startAt
+ if ifMissingElse {
+ // If this is the end of block without else, the number of block's results and params must be same.
+ // Otherwise, the value stack would result in the inconsistent state at runtime.
+ if !bytes.Equal(bl.blockType.Results, bl.blockType.Params) {
+ return typeCountError(false, OpcodeElseName, bl.blockType.Params, bl.blockType.Results)
+ }
+ // -1 skips else, to handle if block without else properly.
+ bl.elseAt = bl.endAt - 1
+ }
+
+ // Determine the block context
+ ctx := "" // the outer-most block: the function return
+ if bl.op == OpcodeIf && !ifMissingElse && bl.elseAt > 0 {
+ ctx = OpcodeElseName
+ } else if bl.op != 0 {
+ ctx = InstructionName(bl.op)
+ }
+
+ // Check return types match
+ if err := valueTypeStack.requireStackValues(false, ctx, bl.blockType.Results, true); err != nil {
+ return err
+ }
+
+ // Put the result types at the end after resetting at the stack limit
+ // since we might have Any type between the limit and the current top.
+ valueTypeStack.resetAtStackLimit()
+ for _, exp := range bl.blockType.Results {
+ valueTypeStack.push(exp)
+ }
+ // We exit if/loop/block, so reset the constraints on the stack manipulation
+ // on values previously pushed by outer blocks.
+ valueTypeStack.popStackLimit()
+ } else if op == OpcodeReturn {
+ // Same formatting as OpcodeEnd on the outer-most block
+ if err := valueTypeStack.requireStackValues(false, "", functionType.Results, false); err != nil {
+ return err
+ }
+ // return instruction is stack-polymorphic.
+ valueTypeStack.unreachable()
+ } else if op == OpcodeDrop {
+ _, err := valueTypeStack.pop()
+ if err != nil {
+ return fmt.Errorf("invalid drop: %v", err)
+ }
+ } else if op == OpcodeSelect || op == OpcodeTypedSelect {
+ if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
+ return fmt.Errorf("type mismatch on 3rd select operand: %v", err)
+ }
+ v1, err := valueTypeStack.pop()
+ if err != nil {
+ return fmt.Errorf("invalid select: %v", err)
+ }
+ v2, err := valueTypeStack.pop()
+ if err != nil {
+ return fmt.Errorf("invalid select: %v", err)
+ }
+
+ if op == OpcodeTypedSelect {
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
+ return fmt.Errorf("%s is invalid as %w", InstructionName(op), err)
+ }
+ pc++
+ if numTypeImmeidates := body[pc]; numTypeImmeidates != 1 {
+ return fmt.Errorf("too many type immediates for %s", InstructionName(op))
+ }
+ pc++
+ tp := body[pc]
+ if tp != ValueTypeI32 && tp != ValueTypeI64 && tp != ValueTypeF32 && tp != ValueTypeF64 &&
+ tp != api.ValueTypeExternref && tp != ValueTypeFuncref && tp != ValueTypeV128 {
+ return fmt.Errorf("invalid type %s for %s", ValueTypeName(tp), OpcodeTypedSelectName)
+ }
+ } else if isReferenceValueType(v1) || isReferenceValueType(v2) {
+ return fmt.Errorf("reference types cannot be used for non typed select instruction")
+ }
+
+ if v1 != v2 && v1 != valueTypeUnknown && v2 != valueTypeUnknown {
+ return fmt.Errorf("type mismatch on 1st and 2nd select operands")
+ }
+ if v1 == valueTypeUnknown {
+ valueTypeStack.push(v2)
+ } else {
+ valueTypeStack.push(v1)
+ }
+ } else if op == OpcodeUnreachable {
+ // unreachable instruction is stack-polymorphic.
+ valueTypeStack.unreachable()
+ } else if op == OpcodeNop {
+ } else {
+ return fmt.Errorf("invalid instruction 0x%x", op)
+ }
+ }
+
+ if len(controlBlockStack.stack) > 0 {
+ return fmt.Errorf("ill-nested block exists")
+ }
+ if valueTypeStack.maximumStackPointer > maxStackValues {
+ return fmt.Errorf("function may have %d stack values, which exceeds limit %d", valueTypeStack.maximumStackPointer, maxStackValues)
+ }
+ return nil
+}
+
+var vecExtractLanes = [...]struct {
+ laneCeil byte
+ resultType ValueType
+}{
+ OpcodeVecI8x16ExtractLaneS: {laneCeil: 16, resultType: ValueTypeI32},
+ OpcodeVecI8x16ExtractLaneU: {laneCeil: 16, resultType: ValueTypeI32},
+ OpcodeVecI16x8ExtractLaneS: {laneCeil: 8, resultType: ValueTypeI32},
+ OpcodeVecI16x8ExtractLaneU: {laneCeil: 8, resultType: ValueTypeI32},
+ OpcodeVecI32x4ExtractLane: {laneCeil: 4, resultType: ValueTypeI32},
+ OpcodeVecI64x2ExtractLane: {laneCeil: 2, resultType: ValueTypeI64},
+ OpcodeVecF32x4ExtractLane: {laneCeil: 4, resultType: ValueTypeF32},
+ OpcodeVecF64x2ExtractLane: {laneCeil: 2, resultType: ValueTypeF64},
+}
+
+var vecReplaceLanes = [...]struct {
+ laneCeil byte
+ paramType ValueType
+}{
+ OpcodeVecI8x16ReplaceLane: {laneCeil: 16, paramType: ValueTypeI32},
+ OpcodeVecI16x8ReplaceLane: {laneCeil: 8, paramType: ValueTypeI32},
+ OpcodeVecI32x4ReplaceLane: {laneCeil: 4, paramType: ValueTypeI32},
+ OpcodeVecI64x2ReplaceLane: {laneCeil: 2, paramType: ValueTypeI64},
+ OpcodeVecF32x4ReplaceLane: {laneCeil: 4, paramType: ValueTypeF32},
+ OpcodeVecF64x2ReplaceLane: {laneCeil: 2, paramType: ValueTypeF64},
+}
+
+var vecStoreLanes = [...]struct {
+ alignMax uint32
+ laneCeil byte
+}{
+ OpcodeVecV128Store64Lane: {alignMax: 64 / 8, laneCeil: 128 / 64},
+ OpcodeVecV128Store32Lane: {alignMax: 32 / 8, laneCeil: 128 / 32},
+ OpcodeVecV128Store16Lane: {alignMax: 16 / 8, laneCeil: 128 / 16},
+ OpcodeVecV128Store8Lane: {alignMax: 1, laneCeil: 128 / 8},
+}
+
+var vecLoadLanes = [...]struct {
+ alignMax uint32
+ laneCeil byte
+}{
+ OpcodeVecV128Load64Lane: {alignMax: 64 / 8, laneCeil: 128 / 64},
+ OpcodeVecV128Load32Lane: {alignMax: 32 / 8, laneCeil: 128 / 32},
+ OpcodeVecV128Load16Lane: {alignMax: 16 / 8, laneCeil: 128 / 16},
+ OpcodeVecV128Load8Lane: {alignMax: 1, laneCeil: 128 / 8},
+}
+
+var vecSplatValueTypes = [...]ValueType{
+ OpcodeVecI8x16Splat: ValueTypeI32,
+ OpcodeVecI16x8Splat: ValueTypeI32,
+ OpcodeVecI32x4Splat: ValueTypeI32,
+ OpcodeVecI64x2Splat: ValueTypeI64,
+ OpcodeVecF32x4Splat: ValueTypeF32,
+ OpcodeVecF64x2Splat: ValueTypeF64,
+}
+
+type stacks struct {
+ vs valueTypeStack
+ cs controlBlockStack
+}
+
+func (sts *stacks) reset(functionType *FunctionType) {
+ // Reset valueStack for reuse.
+ sts.vs.stack = sts.vs.stack[:0]
+ sts.vs.stackLimits = sts.vs.stackLimits[:0]
+ sts.vs.maximumStackPointer = 0
+ sts.cs.stack = sts.cs.stack[:0]
+ sts.cs.stack = append(sts.cs.stack, controlBlock{blockType: functionType})
+}
+
+type controlBlockStack struct {
+ stack []controlBlock
+}
+
+func (s *controlBlockStack) pop() *controlBlock {
+ tail := len(s.stack) - 1
+ ret := &s.stack[tail]
+ s.stack = s.stack[:tail]
+ return ret
+}
+
+func (s *controlBlockStack) push(startAt, elseAt, endAt uint64, blockType *FunctionType, blockTypeBytes uint64, op Opcode) {
+ s.stack = append(s.stack, controlBlock{
+ startAt: startAt,
+ elseAt: elseAt,
+ endAt: endAt,
+ blockType: blockType,
+ blockTypeBytes: blockTypeBytes,
+ op: op,
+ })
+}
+
+type valueTypeStack struct {
+ stack []ValueType
+ stackLimits []int
+ maximumStackPointer int
+ // requireStackValuesTmp is used in requireStackValues function to reduce the allocation.
+ requireStackValuesTmp []ValueType
+}
+
+// Only used in the analyzeFunction below.
+const valueTypeUnknown = ValueType(0xFF)
+
+func (s *valueTypeStack) tryPop() (vt ValueType, limit int, ok bool) {
+ if len(s.stackLimits) > 0 {
+ limit = s.stackLimits[len(s.stackLimits)-1]
+ }
+ stackLen := len(s.stack)
+ if stackLen <= limit {
+ return
+ } else if stackLen == limit+1 && s.stack[limit] == valueTypeUnknown {
+ vt = valueTypeUnknown
+ ok = true
+ return
+ } else {
+ vt = s.stack[stackLen-1]
+ s.stack = s.stack[:stackLen-1]
+ ok = true
+ return
+ }
+}
+
+func (s *valueTypeStack) pop() (ValueType, error) {
+ if vt, limit, ok := s.tryPop(); ok {
+ return vt, nil
+ } else {
+ return 0, fmt.Errorf("invalid operation: trying to pop at %d with limit %d", len(s.stack), limit)
+ }
+}
+
+// popAndVerifyType returns an error if the stack value is unexpected.
+func (s *valueTypeStack) popAndVerifyType(expected ValueType) error {
+ have, _, ok := s.tryPop()
+ if !ok {
+ return fmt.Errorf("%s missing", ValueTypeName(expected))
+ }
+ if have != expected && have != valueTypeUnknown && expected != valueTypeUnknown {
+ return fmt.Errorf("type mismatch: expected %s, but was %s", ValueTypeName(expected), ValueTypeName(have))
+ }
+ return nil
+}
+
+func (s *valueTypeStack) push(v ValueType) {
+ s.stack = append(s.stack, v)
+ if sp := len(s.stack); sp > s.maximumStackPointer {
+ s.maximumStackPointer = sp
+ }
+}
+
+func (s *valueTypeStack) unreachable() {
+ s.resetAtStackLimit()
+ s.stack = append(s.stack, valueTypeUnknown)
+}
+
+func (s *valueTypeStack) resetAtStackLimit() {
+ if len(s.stackLimits) != 0 {
+ s.stack = s.stack[:s.stackLimits[len(s.stackLimits)-1]]
+ } else {
+ s.stack = s.stack[:0]
+ }
+}
+
+func (s *valueTypeStack) popStackLimit() {
+ if len(s.stackLimits) != 0 {
+ s.stackLimits = s.stackLimits[:len(s.stackLimits)-1]
+ }
+}
+
+// pushStackLimit pushes the control frame's bottom of the stack.
+func (s *valueTypeStack) pushStackLimit(params int) {
+ limit := len(s.stack) - params
+ s.stackLimits = append(s.stackLimits, limit)
+}
+
+func (s *valueTypeStack) popParams(oc Opcode, want []ValueType, checkAboveLimit bool) error {
+ return s.requireStackValues(true, InstructionName(oc), want, checkAboveLimit)
+}
+
+func (s *valueTypeStack) popResults(oc Opcode, want []ValueType, checkAboveLimit bool) error {
+ return s.requireStackValues(false, InstructionName(oc), want, checkAboveLimit)
+}
+
+func (s *valueTypeStack) requireStackValues(
+ isParam bool,
+ context string,
+ want []ValueType,
+ checkAboveLimit bool,
+) error {
+ limit := 0
+ if len(s.stackLimits) > 0 {
+ limit = s.stackLimits[len(s.stackLimits)-1]
+ }
+ // Iterate backwards as we are comparing the desired slice against stack value types.
+ countWanted := len(want)
+
+ // First, check if there are enough values on the stack.
+ s.requireStackValuesTmp = s.requireStackValuesTmp[:0]
+ for i := countWanted - 1; i >= 0; i-- {
+ popped, _, ok := s.tryPop()
+ if !ok {
+ if len(s.requireStackValuesTmp) > len(want) {
+ return typeCountError(isParam, context, s.requireStackValuesTmp, want)
+ }
+ return typeCountError(isParam, context, s.requireStackValuesTmp, want)
+ }
+ s.requireStackValuesTmp = append(s.requireStackValuesTmp, popped)
+ }
+
+ // Now, check if there are too many values.
+ if checkAboveLimit {
+ if !(limit == len(s.stack) || (limit+1 == len(s.stack) && s.stack[limit] == valueTypeUnknown)) {
+ return typeCountError(isParam, context, append(s.stack, want...), want)
+ }
+ }
+
+ // Finally, check the types of the values:
+ for i, v := range s.requireStackValuesTmp {
+ nextWant := want[countWanted-i-1] // have is in reverse order (stack)
+ if v != nextWant && v != valueTypeUnknown && nextWant != valueTypeUnknown {
+ return typeMismatchError(isParam, context, v, nextWant, i)
+ }
+ }
+ return nil
+}
+
+// typeMismatchError returns an error similar to go compiler's error on type mismatch.
+func typeMismatchError(isParam bool, context string, have ValueType, want ValueType, i int) error {
+ var ret strings.Builder
+ ret.WriteString("cannot use ")
+ ret.WriteString(ValueTypeName(have))
+ if context != "" {
+ ret.WriteString(" in ")
+ ret.WriteString(context)
+ ret.WriteString(" block")
+ }
+ if isParam {
+ ret.WriteString(" as param")
+ } else {
+ ret.WriteString(" as result")
+ }
+ ret.WriteString("[")
+ ret.WriteString(strconv.Itoa(i))
+ ret.WriteString("] type ")
+ ret.WriteString(ValueTypeName(want))
+ return errors.New(ret.String())
+}
+
+// typeCountError returns an error similar to go compiler's error on type count mismatch.
+func typeCountError(isParam bool, context string, have []ValueType, want []ValueType) error {
+ var ret strings.Builder
+ if len(have) > len(want) {
+ ret.WriteString("too many ")
+ } else {
+ ret.WriteString("not enough ")
+ }
+ if isParam {
+ ret.WriteString("params")
+ } else {
+ ret.WriteString("results")
+ }
+ if context != "" {
+ if isParam {
+ ret.WriteString(" for ")
+ } else {
+ ret.WriteString(" in ")
+ }
+ ret.WriteString(context)
+ ret.WriteString(" block")
+ }
+ ret.WriteString("\n\thave (")
+ writeValueTypes(have, &ret)
+ ret.WriteString(")\n\twant (")
+ writeValueTypes(want, &ret)
+ ret.WriteByte(')')
+ return errors.New(ret.String())
+}
+
+func writeValueTypes(vts []ValueType, ret *strings.Builder) {
+ switch len(vts) {
+ case 0:
+ case 1:
+ ret.WriteString(ValueTypeName(vts[0]))
+ default:
+ ret.WriteString(ValueTypeName(vts[0]))
+ for _, vt := range vts[1:] {
+ ret.WriteString(", ")
+ ret.WriteString(ValueTypeName(vt))
+ }
+ }
+}
+
+func (s *valueTypeStack) String() string {
+ var typeStrs, limits []string
+ for _, v := range s.stack {
+ var str string
+ if v == valueTypeUnknown {
+ str = "unknown"
+ } else {
+ str = ValueTypeName(v)
+ }
+ typeStrs = append(typeStrs, str)
+ }
+ for _, d := range s.stackLimits {
+ limits = append(limits, fmt.Sprintf("%d", d))
+ }
+ return fmt.Sprintf("{stack: [%s], limits: [%s]}",
+ strings.Join(typeStrs, ", "), strings.Join(limits, ","))
+}
+
+type controlBlock struct {
+ startAt, elseAt, endAt uint64
+ blockType *FunctionType
+ blockTypeBytes uint64
+ // op is zero when the outermost block
+ op Opcode
+}
+
+// DecodeBlockType decodes the type index from a positive 33-bit signed integer. Negative numbers indicate up to one
+// WebAssembly 1.0 (20191205) compatible result type. Positive numbers are decoded when `enabledFeatures` include
+// CoreFeatureMultiValue and include an index in the Module.TypeSection.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-blocktype
+// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md
+func DecodeBlockType(types []FunctionType, r *bytes.Reader, enabledFeatures api.CoreFeatures) (*FunctionType, uint64, error) {
+ raw, num, err := leb128.DecodeInt33AsInt64(r)
+ if err != nil {
+ return nil, 0, fmt.Errorf("decode int33: %w", err)
+ }
+
+ var ret *FunctionType
+ switch raw {
+ case -64: // 0x40 in original byte = nil
+ ret = blockType_v_v
+ case -1: // 0x7f in original byte = i32
+ ret = blockType_v_i32
+ case -2: // 0x7e in original byte = i64
+ ret = blockType_v_i64
+ case -3: // 0x7d in original byte = f32
+ ret = blockType_v_f32
+ case -4: // 0x7c in original byte = f64
+ ret = blockType_v_f64
+ case -5: // 0x7b in original byte = v128
+ ret = blockType_v_v128
+ case -16: // 0x70 in original byte = funcref
+ ret = blockType_v_funcref
+ case -17: // 0x6f in original byte = externref
+ ret = blockType_v_externref
+ default:
+ if err = enabledFeatures.RequireEnabled(api.CoreFeatureMultiValue); err != nil {
+ return nil, num, fmt.Errorf("block with function type return invalid as %v", err)
+ }
+ if raw < 0 || (raw >= int64(len(types))) {
+ return nil, 0, fmt.Errorf("type index out of range: %d", raw)
+ }
+ ret = &types[raw]
+ }
+ return ret, num, err
+}
+
+// These block types are defined as globals in order to avoid allocations in DecodeBlockType.
+var (
+ blockType_v_v = &FunctionType{}
+ blockType_v_i32 = &FunctionType{Results: []ValueType{ValueTypeI32}, ResultNumInUint64: 1}
+ blockType_v_i64 = &FunctionType{Results: []ValueType{ValueTypeI64}, ResultNumInUint64: 1}
+ blockType_v_f32 = &FunctionType{Results: []ValueType{ValueTypeF32}, ResultNumInUint64: 1}
+ blockType_v_f64 = &FunctionType{Results: []ValueType{ValueTypeF64}, ResultNumInUint64: 1}
+ blockType_v_v128 = &FunctionType{Results: []ValueType{ValueTypeV128}, ResultNumInUint64: 2}
+ blockType_v_funcref = &FunctionType{Results: []ValueType{ValueTypeFuncref}, ResultNumInUint64: 1}
+ blockType_v_externref = &FunctionType{Results: []ValueType{ValueTypeExternref}, ResultNumInUint64: 1}
+)
+
+// SplitCallStack returns the input stack resliced to the count of params and
+// results, or errors if it isn't long enough for either.
+func SplitCallStack(ft *FunctionType, stack []uint64) (params []uint64, results []uint64, err error) {
+ stackLen := len(stack)
+ if n := ft.ParamNumInUint64; n > stackLen {
+ return nil, nil, fmt.Errorf("need %d params, but stack size is %d", n, stackLen)
+ } else if n > 0 {
+ params = stack[:n]
+ }
+ if n := ft.ResultNumInUint64; n > stackLen {
+ return nil, nil, fmt.Errorf("need %d results, but stack size is %d", n, stackLen)
+ } else if n > 0 {
+ results = stack[:n]
+ }
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/function_definition.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/function_definition.go
new file mode 100644
index 000000000..c5f6e9121
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/function_definition.go
@@ -0,0 +1,188 @@
+package wasm
+
+import (
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/internalapi"
+ "github.com/tetratelabs/wazero/internal/wasmdebug"
+)
+
+// ImportedFunctions returns the definitions of each imported function.
+//
+// Note: Unlike ExportedFunctions, there is no unique constraint on imports.
+func (m *Module) ImportedFunctions() (ret []api.FunctionDefinition) {
+ for i := uint32(0); i < m.ImportFunctionCount; i++ {
+ ret = append(ret, m.FunctionDefinition(i))
+ }
+ return
+}
+
+// ExportedFunctions returns the definitions of each exported function.
+func (m *Module) ExportedFunctions() map[string]api.FunctionDefinition {
+ ret := map[string]api.FunctionDefinition{}
+ for i := range m.ExportSection {
+ exp := &m.ExportSection[i]
+ if exp.Type == ExternTypeFunc {
+ d := m.FunctionDefinition(exp.Index)
+ ret[exp.Name] = d
+ }
+ }
+ return ret
+}
+
+// FunctionDefinition returns the FunctionDefinition for the given `index`.
+func (m *Module) FunctionDefinition(index Index) *FunctionDefinition {
+ // TODO: function initialization is lazy, but bulk. Make it per function.
+ m.buildFunctionDefinitions()
+ return &m.FunctionDefinitionSection[index]
+}
+
+// buildFunctionDefinitions generates function metadata that can be parsed from
+// the module. This must be called after all validation.
+func (m *Module) buildFunctionDefinitions() {
+ m.functionDefinitionSectionInitOnce.Do(m.buildFunctionDefinitionsOnce)
+}
+
+func (m *Module) buildFunctionDefinitionsOnce() {
+ var moduleName string
+ var functionNames NameMap
+ var localNames, resultNames IndirectNameMap
+ if m.NameSection != nil {
+ moduleName = m.NameSection.ModuleName
+ functionNames = m.NameSection.FunctionNames
+ localNames = m.NameSection.LocalNames
+ resultNames = m.NameSection.ResultNames
+ }
+
+ importCount := m.ImportFunctionCount
+ m.FunctionDefinitionSection = make([]FunctionDefinition, importCount+uint32(len(m.FunctionSection)))
+
+ importFuncIdx := Index(0)
+ for i := range m.ImportSection {
+ imp := &m.ImportSection[i]
+ if imp.Type != ExternTypeFunc {
+ continue
+ }
+
+ def := &m.FunctionDefinitionSection[importFuncIdx]
+ def.importDesc = imp
+ def.index = importFuncIdx
+ def.Functype = &m.TypeSection[imp.DescFunc]
+ importFuncIdx++
+ }
+
+ for codeIndex, typeIndex := range m.FunctionSection {
+ code := &m.CodeSection[codeIndex]
+ idx := importFuncIdx + Index(codeIndex)
+ def := &m.FunctionDefinitionSection[idx]
+ def.index = idx
+ def.Functype = &m.TypeSection[typeIndex]
+ def.goFunc = code.GoFunc
+ }
+
+ n, nLen := 0, len(functionNames)
+ for i := range m.FunctionDefinitionSection {
+ d := &m.FunctionDefinitionSection[i]
+ // The function name section begins with imports, but can be sparse.
+ // This keeps track of how far in the name section we've searched.
+ funcIdx := d.index
+ var funcName string
+ for ; n < nLen; n++ {
+ next := &functionNames[n]
+ if next.Index > funcIdx {
+ break // we have function names, but starting at a later index.
+ } else if next.Index == funcIdx {
+ funcName = next.Name
+ break
+ }
+ }
+
+ d.moduleName = moduleName
+ d.name = funcName
+ d.Debugname = wasmdebug.FuncName(moduleName, funcName, funcIdx)
+ d.paramNames = paramNames(localNames, funcIdx, len(d.Functype.Params))
+ d.resultNames = paramNames(resultNames, funcIdx, len(d.Functype.Results))
+
+ for i := range m.ExportSection {
+ e := &m.ExportSection[i]
+ if e.Type == ExternTypeFunc && e.Index == funcIdx {
+ d.exportNames = append(d.exportNames, e.Name)
+ }
+ }
+ }
+}
+
+// FunctionDefinition implements api.FunctionDefinition
+type FunctionDefinition struct {
+ internalapi.WazeroOnlyType
+ moduleName string
+ index Index
+ name string
+ // Debugname is exported for testing purpose.
+ Debugname string
+ goFunc interface{}
+ // Functype is exported for testing purpose.
+ Functype *FunctionType
+ importDesc *Import
+ exportNames []string
+ paramNames []string
+ resultNames []string
+}
+
+// ModuleName implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) ModuleName() string {
+ return f.moduleName
+}
+
+// Index implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) Index() uint32 {
+ return f.index
+}
+
+// Name implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) Name() string {
+ return f.name
+}
+
+// DebugName implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) DebugName() string {
+ return f.Debugname
+}
+
+// Import implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) Import() (moduleName, name string, isImport bool) {
+ if f.importDesc != nil {
+ importDesc := f.importDesc
+ moduleName, name, isImport = importDesc.Module, importDesc.Name, true
+ }
+ return
+}
+
+// ExportNames implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) ExportNames() []string {
+ return f.exportNames
+}
+
+// GoFunction implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) GoFunction() interface{} {
+ return f.goFunc
+}
+
+// ParamTypes implements api.FunctionDefinition ParamTypes.
+func (f *FunctionDefinition) ParamTypes() []ValueType {
+ return f.Functype.Params
+}
+
+// ParamNames implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) ParamNames() []string {
+ return f.paramNames
+}
+
+// ResultTypes implements api.FunctionDefinition ResultTypes.
+func (f *FunctionDefinition) ResultTypes() []ValueType {
+ return f.Functype.Results
+}
+
+// ResultNames implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) ResultNames() []string {
+ return f.resultNames
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/global.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/global.go
new file mode 100644
index 000000000..abaa2d1f9
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/global.go
@@ -0,0 +1,55 @@
+package wasm
+
+import (
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/internalapi"
+)
+
+// constantGlobal wraps GlobalInstance to implement api.Global.
+type constantGlobal struct {
+ internalapi.WazeroOnlyType
+ g *GlobalInstance
+}
+
+// Type implements api.Global.
+func (g constantGlobal) Type() api.ValueType {
+ return g.g.Type.ValType
+}
+
+// Get implements api.Global.
+func (g constantGlobal) Get() uint64 {
+ ret, _ := g.g.Value()
+ return ret
+}
+
+// String implements api.Global.
+func (g constantGlobal) String() string {
+ return g.g.String()
+}
+
+// mutableGlobal extends constantGlobal to allow updates.
+type mutableGlobal struct {
+ internalapi.WazeroOnlyType
+ g *GlobalInstance
+}
+
+// Type implements api.Global.
+func (g mutableGlobal) Type() api.ValueType {
+ return g.g.Type.ValType
+}
+
+// Get implements api.Global.
+func (g mutableGlobal) Get() uint64 {
+ ret, _ := g.g.Value()
+ return ret
+}
+
+// String implements api.Global.
+func (g mutableGlobal) String() string {
+ return g.g.String()
+}
+
+// Set implements the same method as documented on api.MutableGlobal.
+func (g mutableGlobal) Set(v uint64) {
+ g.g.SetValue(v, 0)
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go
new file mode 100644
index 000000000..9510c2588
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go
@@ -0,0 +1,279 @@
+package wasm
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "math"
+ "reflect"
+
+ "github.com/tetratelabs/wazero/api"
+)
+
+type paramsKind byte
+
+const (
+ paramsKindNoContext paramsKind = iota
+ paramsKindContext
+ paramsKindContextModule
+)
+
+// Below are reflection code to get the interface type used to parse functions and set values.
+
+var (
+ moduleType = reflect.TypeOf((*api.Module)(nil)).Elem()
+ goContextType = reflect.TypeOf((*context.Context)(nil)).Elem()
+ errorType = reflect.TypeOf((*error)(nil)).Elem()
+)
+
+// compile-time check to ensure reflectGoModuleFunction implements
+// api.GoModuleFunction.
+var _ api.GoModuleFunction = (*reflectGoModuleFunction)(nil)
+
+type reflectGoModuleFunction struct {
+ fn *reflect.Value
+ params, results []ValueType
+}
+
+// Call implements the same method as documented on api.GoModuleFunction.
+func (f *reflectGoModuleFunction) Call(ctx context.Context, mod api.Module, stack []uint64) {
+ callGoFunc(ctx, mod, f.fn, stack)
+}
+
+// EqualTo is exposed for testing.
+func (f *reflectGoModuleFunction) EqualTo(that interface{}) bool {
+ if f2, ok := that.(*reflectGoModuleFunction); !ok {
+ return false
+ } else {
+ // TODO compare reflect pointers
+ return bytes.Equal(f.params, f2.params) && bytes.Equal(f.results, f2.results)
+ }
+}
+
+// compile-time check to ensure reflectGoFunction implements api.GoFunction.
+var _ api.GoFunction = (*reflectGoFunction)(nil)
+
+type reflectGoFunction struct {
+ fn *reflect.Value
+ pk paramsKind
+ params, results []ValueType
+}
+
+// EqualTo is exposed for testing.
+func (f *reflectGoFunction) EqualTo(that interface{}) bool {
+ if f2, ok := that.(*reflectGoFunction); !ok {
+ return false
+ } else {
+ // TODO compare reflect pointers
+ return f.pk == f2.pk &&
+ bytes.Equal(f.params, f2.params) && bytes.Equal(f.results, f2.results)
+ }
+}
+
+// Call implements the same method as documented on api.GoFunction.
+func (f *reflectGoFunction) Call(ctx context.Context, stack []uint64) {
+ if f.pk == paramsKindNoContext {
+ ctx = nil
+ }
+ callGoFunc(ctx, nil, f.fn, stack)
+}
+
+// callGoFunc executes the reflective function by converting params to Go
+// types. The results of the function call are converted back to api.ValueType.
+func callGoFunc(ctx context.Context, mod api.Module, fn *reflect.Value, stack []uint64) {
+ tp := fn.Type()
+
+ var in []reflect.Value
+ pLen := tp.NumIn()
+ if pLen != 0 {
+ in = make([]reflect.Value, pLen)
+
+ i := 0
+ if ctx != nil {
+ in[0] = newContextVal(ctx)
+ i++
+ }
+ if mod != nil {
+ in[1] = newModuleVal(mod)
+ i++
+ }
+
+ for j := 0; i < pLen; i++ {
+ next := tp.In(i)
+ val := reflect.New(next).Elem()
+ k := next.Kind()
+ raw := stack[j]
+ j++
+
+ switch k {
+ case reflect.Float32:
+ val.SetFloat(float64(math.Float32frombits(uint32(raw))))
+ case reflect.Float64:
+ val.SetFloat(math.Float64frombits(raw))
+ case reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ val.SetUint(raw)
+ case reflect.Int32, reflect.Int64:
+ val.SetInt(int64(raw))
+ default:
+ panic(fmt.Errorf("BUG: param[%d] has an invalid type: %v", i, k))
+ }
+ in[i] = val
+ }
+ }
+
+ // Execute the host function and push back the call result onto the stack.
+ for i, ret := range fn.Call(in) {
+ switch ret.Kind() {
+ case reflect.Float32:
+ stack[i] = uint64(math.Float32bits(float32(ret.Float())))
+ case reflect.Float64:
+ stack[i] = math.Float64bits(ret.Float())
+ case reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ stack[i] = ret.Uint()
+ case reflect.Int32, reflect.Int64:
+ stack[i] = uint64(ret.Int())
+ default:
+ panic(fmt.Errorf("BUG: result[%d] has an invalid type: %v", i, ret.Kind()))
+ }
+ }
+}
+
+func newContextVal(ctx context.Context) reflect.Value {
+ val := reflect.New(goContextType).Elem()
+ val.Set(reflect.ValueOf(ctx))
+ return val
+}
+
+func newModuleVal(m api.Module) reflect.Value {
+ val := reflect.New(moduleType).Elem()
+ val.Set(reflect.ValueOf(m))
+ return val
+}
+
+// MustParseGoReflectFuncCode parses Code from the go function or panics.
+//
+// Exposing this simplifies FunctionDefinition of host functions in built-in host
+// modules and tests.
+func MustParseGoReflectFuncCode(fn interface{}) Code {
+ _, _, code, err := parseGoReflectFunc(fn)
+ if err != nil {
+ panic(err)
+ }
+ return code
+}
+
+func parseGoReflectFunc(fn interface{}) (params, results []ValueType, code Code, err error) {
+ fnV := reflect.ValueOf(fn)
+ p := fnV.Type()
+
+ if fnV.Kind() != reflect.Func {
+ err = fmt.Errorf("kind != func: %s", fnV.Kind().String())
+ return
+ }
+
+ pk, kindErr := kind(p)
+ if kindErr != nil {
+ err = kindErr
+ return
+ }
+
+ pOffset := 0
+ switch pk {
+ case paramsKindNoContext:
+ case paramsKindContext:
+ pOffset = 1
+ case paramsKindContextModule:
+ pOffset = 2
+ }
+
+ pCount := p.NumIn() - pOffset
+ if pCount > 0 {
+ params = make([]ValueType, pCount)
+ }
+ for i := 0; i < len(params); i++ {
+ pI := p.In(i + pOffset)
+ if t, ok := getTypeOf(pI.Kind()); ok {
+ params[i] = t
+ continue
+ }
+
+ // Now, we will definitely err, decide which message is best
+ var arg0Type reflect.Type
+ if hc := pI.Implements(moduleType); hc {
+ arg0Type = moduleType
+ } else if gc := pI.Implements(goContextType); gc {
+ arg0Type = goContextType
+ }
+
+ if arg0Type != nil {
+ err = fmt.Errorf("param[%d] is a %s, which may be defined only once as param[0]", i+pOffset, arg0Type)
+ } else {
+ err = fmt.Errorf("param[%d] is unsupported: %s", i+pOffset, pI.Kind())
+ }
+ return
+ }
+
+ rCount := p.NumOut()
+ if rCount > 0 {
+ results = make([]ValueType, rCount)
+ }
+ for i := 0; i < len(results); i++ {
+ rI := p.Out(i)
+ if t, ok := getTypeOf(rI.Kind()); ok {
+ results[i] = t
+ continue
+ }
+
+ // Now, we will definitely err, decide which message is best
+ if rI.Implements(errorType) {
+ err = fmt.Errorf("result[%d] is an error, which is unsupported", i)
+ } else {
+ err = fmt.Errorf("result[%d] is unsupported: %s", i, rI.Kind())
+ }
+ return
+ }
+
+ code = Code{}
+ if pk == paramsKindContextModule {
+ code.GoFunc = &reflectGoModuleFunction{fn: &fnV, params: params, results: results}
+ } else {
+ code.GoFunc = &reflectGoFunction{pk: pk, fn: &fnV, params: params, results: results}
+ }
+ return
+}
+
+func kind(p reflect.Type) (paramsKind, error) {
+ pCount := p.NumIn()
+ if pCount > 0 && p.In(0).Kind() == reflect.Interface {
+ p0 := p.In(0)
+ if p0.Implements(moduleType) {
+ return 0, errors.New("invalid signature: api.Module parameter must be preceded by context.Context")
+ } else if p0.Implements(goContextType) {
+ if pCount >= 2 && p.In(1).Implements(moduleType) {
+ return paramsKindContextModule, nil
+ }
+ return paramsKindContext, nil
+ }
+ }
+ // Without context param allows portability with reflective runtimes.
+ // This allows people to more easily port to wazero.
+ return paramsKindNoContext, nil
+}
+
+func getTypeOf(kind reflect.Kind) (ValueType, bool) {
+ switch kind {
+ case reflect.Float64:
+ return ValueTypeF64, true
+ case reflect.Float32:
+ return ValueTypeF32, true
+ case reflect.Int32, reflect.Uint32:
+ return ValueTypeI32, true
+ case reflect.Int64, reflect.Uint64:
+ return ValueTypeI64, true
+ case reflect.Uintptr:
+ return ValueTypeExternref, true
+ default:
+ return 0x00, false
+ }
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/host.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/host.go
new file mode 100644
index 000000000..bca686d1d
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/host.go
@@ -0,0 +1,179 @@
+package wasm
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/wasmdebug"
+)
+
+type HostFuncExporter interface {
+ ExportHostFunc(*HostFunc)
+}
+
+// HostFunc is a function with an inlined type, used for NewHostModule.
+// Any corresponding FunctionType will be reused or added to the Module.
+type HostFunc struct {
+ // ExportName is the only value returned by api.FunctionDefinition.
+ ExportName string
+
+ // Name is equivalent to the same method on api.FunctionDefinition.
+ Name string
+
+ // ParamTypes is equivalent to the same method on api.FunctionDefinition.
+ ParamTypes []ValueType
+
+ // ParamNames is equivalent to the same method on api.FunctionDefinition.
+ ParamNames []string
+
+ // ResultTypes is equivalent to the same method on api.FunctionDefinition.
+ ResultTypes []ValueType
+
+ // ResultNames is equivalent to the same method on api.FunctionDefinition.
+ ResultNames []string
+
+ // Code is the equivalent function in the SectionIDCode.
+ Code Code
+}
+
+// WithGoModuleFunc returns a copy of the function, replacing its Code.GoFunc.
+func (f *HostFunc) WithGoModuleFunc(fn api.GoModuleFunc) *HostFunc {
+ ret := *f
+ ret.Code.GoFunc = fn
+ return &ret
+}
+
+// NewHostModule is defined internally for use in WASI tests and to keep the code size in the root directory small.
+func NewHostModule(
+ moduleName string,
+ exportNames []string,
+ nameToHostFunc map[string]*HostFunc,
+ enabledFeatures api.CoreFeatures,
+) (m *Module, err error) {
+ if moduleName != "" {
+ m = &Module{NameSection: &NameSection{ModuleName: moduleName}}
+ } else {
+ return nil, errors.New("a module name must not be empty")
+ }
+
+ if exportCount := uint32(len(nameToHostFunc)); exportCount > 0 {
+ m.ExportSection = make([]Export, 0, exportCount)
+ m.Exports = make(map[string]*Export, exportCount)
+ if err = addFuncs(m, exportNames, nameToHostFunc, enabledFeatures); err != nil {
+ return
+ }
+ }
+
+ m.IsHostModule = true
+ // Uses the address of *wasm.Module as the module ID so that host functions can have each state per compilation.
+ // Downside of this is that compilation cache on host functions (trampoline codes for Go functions and
+ // Wasm codes for Wasm-implemented host functions) are not available and compiles each time. On the other hand,
+ // compilation of host modules is not costly as it's merely small trampolines vs the real-world native Wasm binary.
+ // TODO: refactor engines so that we can properly cache compiled machine codes for host modules.
+ m.AssignModuleID([]byte(fmt.Sprintf("@@@@@@@@%p", m)), // @@@@@@@@ = any 8 bytes different from Wasm header.
+ nil, false)
+ return
+}
+
+func addFuncs(
+ m *Module,
+ exportNames []string,
+ nameToHostFunc map[string]*HostFunc,
+ enabledFeatures api.CoreFeatures,
+) (err error) {
+ if m.NameSection == nil {
+ m.NameSection = &NameSection{}
+ }
+ moduleName := m.NameSection.ModuleName
+
+ for _, k := range exportNames {
+ hf := nameToHostFunc[k]
+ if hf.Name == "" {
+ hf.Name = k // default name to export name
+ }
+ switch hf.Code.GoFunc.(type) {
+ case api.GoModuleFunction, api.GoFunction:
+ continue // already parsed
+ }
+
+ // Resolve the code using reflection
+ hf.ParamTypes, hf.ResultTypes, hf.Code, err = parseGoReflectFunc(hf.Code.GoFunc)
+ if err != nil {
+ return fmt.Errorf("func[%s.%s] %w", moduleName, k, err)
+ }
+
+ // Assign names to the function, if they exist.
+ params := hf.ParamTypes
+ if paramNames := hf.ParamNames; paramNames != nil {
+ if paramNamesLen := len(paramNames); paramNamesLen != len(params) {
+ return fmt.Errorf("func[%s.%s] has %d params, but %d params names", moduleName, k, paramNamesLen, len(params))
+ }
+ }
+
+ results := hf.ResultTypes
+ if resultNames := hf.ResultNames; resultNames != nil {
+ if resultNamesLen := len(resultNames); resultNamesLen != len(results) {
+ return fmt.Errorf("func[%s.%s] has %d results, but %d results names", moduleName, k, resultNamesLen, len(results))
+ }
+ }
+ }
+
+ funcCount := uint32(len(exportNames))
+ m.NameSection.FunctionNames = make([]NameAssoc, 0, funcCount)
+ m.FunctionSection = make([]Index, 0, funcCount)
+ m.CodeSection = make([]Code, 0, funcCount)
+
+ idx := Index(0)
+ for _, name := range exportNames {
+ hf := nameToHostFunc[name]
+ debugName := wasmdebug.FuncName(moduleName, name, idx)
+ typeIdx, typeErr := m.maybeAddType(hf.ParamTypes, hf.ResultTypes, enabledFeatures)
+ if typeErr != nil {
+ return fmt.Errorf("func[%s] %v", debugName, typeErr)
+ }
+ m.FunctionSection = append(m.FunctionSection, typeIdx)
+ m.CodeSection = append(m.CodeSection, hf.Code)
+
+ export := hf.ExportName
+ m.ExportSection = append(m.ExportSection, Export{Type: ExternTypeFunc, Name: export, Index: idx})
+ m.Exports[export] = &m.ExportSection[len(m.ExportSection)-1]
+ m.NameSection.FunctionNames = append(m.NameSection.FunctionNames, NameAssoc{Index: idx, Name: hf.Name})
+
+ if len(hf.ParamNames) > 0 {
+ localNames := NameMapAssoc{Index: idx}
+ for i, n := range hf.ParamNames {
+ localNames.NameMap = append(localNames.NameMap, NameAssoc{Index: Index(i), Name: n})
+ }
+ m.NameSection.LocalNames = append(m.NameSection.LocalNames, localNames)
+ }
+ if len(hf.ResultNames) > 0 {
+ resultNames := NameMapAssoc{Index: idx}
+ for i, n := range hf.ResultNames {
+ resultNames.NameMap = append(resultNames.NameMap, NameAssoc{Index: Index(i), Name: n})
+ }
+ m.NameSection.ResultNames = append(m.NameSection.ResultNames, resultNames)
+ }
+ idx++
+ }
+ return nil
+}
+
+func (m *Module) maybeAddType(params, results []ValueType, enabledFeatures api.CoreFeatures) (Index, error) {
+ if len(results) > 1 {
+ // Guard >1.0 feature multi-value
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureMultiValue); err != nil {
+ return 0, fmt.Errorf("multiple result types invalid as %v", err)
+ }
+ }
+ for i := range m.TypeSection {
+ t := &m.TypeSection[i]
+ if t.EqualsSignature(params, results) {
+ return Index(i), nil
+ }
+ }
+
+ result := m.SectionElementCount(SectionIDType)
+ m.TypeSection = append(m.TypeSection, FunctionType{Params: params, Results: results})
+ return result, nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/instruction.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/instruction.go
new file mode 100644
index 000000000..67f196b8b
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/instruction.go
@@ -0,0 +1,1866 @@
+package wasm
+
+// Opcode is the binary Opcode of an instruction. See also InstructionName
+type Opcode = byte
+
+const (
+ // OpcodeUnreachable causes an unconditional trap.
+ OpcodeUnreachable Opcode = 0x00
+ // OpcodeNop does nothing
+ OpcodeNop Opcode = 0x01
+ // OpcodeBlock brackets a sequence of instructions. A branch instruction on an if label breaks out to after its
+ // OpcodeEnd.
+ OpcodeBlock Opcode = 0x02
+ // OpcodeLoop brackets a sequence of instructions. A branch instruction on a loop label will jump back to the
+ // beginning of its block.
+ OpcodeLoop Opcode = 0x03
+ // OpcodeIf brackets a sequence of instructions. When the top of the stack evaluates to 1, the block is executed.
+ // Zero jumps to the optional OpcodeElse. A branch instruction on an if label breaks out to after its OpcodeEnd.
+ OpcodeIf Opcode = 0x04
+ // OpcodeElse brackets a sequence of instructions enclosed by an OpcodeIf. A branch instruction on a then label
+ // breaks out to after the OpcodeEnd on the enclosing OpcodeIf.
+ OpcodeElse Opcode = 0x05
+ // OpcodeEnd terminates a control instruction OpcodeBlock, OpcodeLoop or OpcodeIf.
+ OpcodeEnd Opcode = 0x0b
+
+ // OpcodeBr is a stack-polymorphic opcode that performs an unconditional branch. How the stack is modified depends
+ // on whether the "br" is enclosed by a loop, and if CoreFeatureMultiValue is enabled.
+ //
+ // Here are the rules in pseudocode about how the stack is modified based on the "br" operand L (label):
+ // if L is loop: append(L.originalStackWithoutInputs, N-values popped from the stack) where N == L.inputs
+ // else: append(L.originalStackWithoutInputs, N-values popped from the stack) where N == L.results
+ //
+ // In WebAssembly 1.0 (20191205), N can be zero or one. When CoreFeatureMultiValue is enabled, N can be more than one,
+ // depending on the type use of the label L.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#-hrefsyntax-instr-controlmathsfbrl
+ OpcodeBr Opcode = 0x0c
+
+ OpcodeBrIf Opcode = 0x0d
+ OpcodeBrTable Opcode = 0x0e
+ OpcodeReturn Opcode = 0x0f
+ OpcodeCall Opcode = 0x10
+ OpcodeCallIndirect Opcode = 0x11
+
+ // parametric instructions
+
+ OpcodeDrop Opcode = 0x1a
+ OpcodeSelect Opcode = 0x1b
+ OpcodeTypedSelect Opcode = 0x1c
+
+ // variable instructions
+
+ OpcodeLocalGet Opcode = 0x20
+ OpcodeLocalSet Opcode = 0x21
+ OpcodeLocalTee Opcode = 0x22
+ OpcodeGlobalGet Opcode = 0x23
+ OpcodeGlobalSet Opcode = 0x24
+
+ // Below are toggled with CoreFeatureReferenceTypes
+
+ OpcodeTableGet Opcode = 0x25
+ OpcodeTableSet Opcode = 0x26
+
+ // memory instructions
+
+ OpcodeI32Load Opcode = 0x28
+ OpcodeI64Load Opcode = 0x29
+ OpcodeF32Load Opcode = 0x2a
+ OpcodeF64Load Opcode = 0x2b
+ OpcodeI32Load8S Opcode = 0x2c
+ OpcodeI32Load8U Opcode = 0x2d
+ OpcodeI32Load16S Opcode = 0x2e
+ OpcodeI32Load16U Opcode = 0x2f
+ OpcodeI64Load8S Opcode = 0x30
+ OpcodeI64Load8U Opcode = 0x31
+ OpcodeI64Load16S Opcode = 0x32
+ OpcodeI64Load16U Opcode = 0x33
+ OpcodeI64Load32S Opcode = 0x34
+ OpcodeI64Load32U Opcode = 0x35
+ OpcodeI32Store Opcode = 0x36
+ OpcodeI64Store Opcode = 0x37
+ OpcodeF32Store Opcode = 0x38
+ OpcodeF64Store Opcode = 0x39
+ OpcodeI32Store8 Opcode = 0x3a
+ OpcodeI32Store16 Opcode = 0x3b
+ OpcodeI64Store8 Opcode = 0x3c
+ OpcodeI64Store16 Opcode = 0x3d
+ OpcodeI64Store32 Opcode = 0x3e
+ OpcodeMemorySize Opcode = 0x3f
+ OpcodeMemoryGrow Opcode = 0x40
+
+ // const instructions
+
+ OpcodeI32Const Opcode = 0x41
+ OpcodeI64Const Opcode = 0x42
+ OpcodeF32Const Opcode = 0x43
+ OpcodeF64Const Opcode = 0x44
+
+ // numeric instructions
+
+ OpcodeI32Eqz Opcode = 0x45
+ OpcodeI32Eq Opcode = 0x46
+ OpcodeI32Ne Opcode = 0x47
+ OpcodeI32LtS Opcode = 0x48
+ OpcodeI32LtU Opcode = 0x49
+ OpcodeI32GtS Opcode = 0x4a
+ OpcodeI32GtU Opcode = 0x4b
+ OpcodeI32LeS Opcode = 0x4c
+ OpcodeI32LeU Opcode = 0x4d
+ OpcodeI32GeS Opcode = 0x4e
+ OpcodeI32GeU Opcode = 0x4f
+
+ OpcodeI64Eqz Opcode = 0x50
+ OpcodeI64Eq Opcode = 0x51
+ OpcodeI64Ne Opcode = 0x52
+ OpcodeI64LtS Opcode = 0x53
+ OpcodeI64LtU Opcode = 0x54
+ OpcodeI64GtS Opcode = 0x55
+ OpcodeI64GtU Opcode = 0x56
+ OpcodeI64LeS Opcode = 0x57
+ OpcodeI64LeU Opcode = 0x58
+ OpcodeI64GeS Opcode = 0x59
+ OpcodeI64GeU Opcode = 0x5a
+
+ OpcodeF32Eq Opcode = 0x5b
+ OpcodeF32Ne Opcode = 0x5c
+ OpcodeF32Lt Opcode = 0x5d
+ OpcodeF32Gt Opcode = 0x5e
+ OpcodeF32Le Opcode = 0x5f
+ OpcodeF32Ge Opcode = 0x60
+
+ OpcodeF64Eq Opcode = 0x61
+ OpcodeF64Ne Opcode = 0x62
+ OpcodeF64Lt Opcode = 0x63
+ OpcodeF64Gt Opcode = 0x64
+ OpcodeF64Le Opcode = 0x65
+ OpcodeF64Ge Opcode = 0x66
+
+ OpcodeI32Clz Opcode = 0x67
+ OpcodeI32Ctz Opcode = 0x68
+ OpcodeI32Popcnt Opcode = 0x69
+ OpcodeI32Add Opcode = 0x6a
+ OpcodeI32Sub Opcode = 0x6b
+ OpcodeI32Mul Opcode = 0x6c
+ OpcodeI32DivS Opcode = 0x6d
+ OpcodeI32DivU Opcode = 0x6e
+ OpcodeI32RemS Opcode = 0x6f
+ OpcodeI32RemU Opcode = 0x70
+ OpcodeI32And Opcode = 0x71
+ OpcodeI32Or Opcode = 0x72
+ OpcodeI32Xor Opcode = 0x73
+ OpcodeI32Shl Opcode = 0x74
+ OpcodeI32ShrS Opcode = 0x75
+ OpcodeI32ShrU Opcode = 0x76
+ OpcodeI32Rotl Opcode = 0x77
+ OpcodeI32Rotr Opcode = 0x78
+
+ OpcodeI64Clz Opcode = 0x79
+ OpcodeI64Ctz Opcode = 0x7a
+ OpcodeI64Popcnt Opcode = 0x7b
+ OpcodeI64Add Opcode = 0x7c
+ OpcodeI64Sub Opcode = 0x7d
+ OpcodeI64Mul Opcode = 0x7e
+ OpcodeI64DivS Opcode = 0x7f
+ OpcodeI64DivU Opcode = 0x80
+ OpcodeI64RemS Opcode = 0x81
+ OpcodeI64RemU Opcode = 0x82
+ OpcodeI64And Opcode = 0x83
+ OpcodeI64Or Opcode = 0x84
+ OpcodeI64Xor Opcode = 0x85
+ OpcodeI64Shl Opcode = 0x86
+ OpcodeI64ShrS Opcode = 0x87
+ OpcodeI64ShrU Opcode = 0x88
+ OpcodeI64Rotl Opcode = 0x89
+ OpcodeI64Rotr Opcode = 0x8a
+
+ OpcodeF32Abs Opcode = 0x8b
+ OpcodeF32Neg Opcode = 0x8c
+ OpcodeF32Ceil Opcode = 0x8d
+ OpcodeF32Floor Opcode = 0x8e
+ OpcodeF32Trunc Opcode = 0x8f
+ OpcodeF32Nearest Opcode = 0x90
+ OpcodeF32Sqrt Opcode = 0x91
+ OpcodeF32Add Opcode = 0x92
+ OpcodeF32Sub Opcode = 0x93
+ OpcodeF32Mul Opcode = 0x94
+ OpcodeF32Div Opcode = 0x95
+ OpcodeF32Min Opcode = 0x96
+ OpcodeF32Max Opcode = 0x97
+ OpcodeF32Copysign Opcode = 0x98
+
+ OpcodeF64Abs Opcode = 0x99
+ OpcodeF64Neg Opcode = 0x9a
+ OpcodeF64Ceil Opcode = 0x9b
+ OpcodeF64Floor Opcode = 0x9c
+ OpcodeF64Trunc Opcode = 0x9d
+ OpcodeF64Nearest Opcode = 0x9e
+ OpcodeF64Sqrt Opcode = 0x9f
+ OpcodeF64Add Opcode = 0xa0
+ OpcodeF64Sub Opcode = 0xa1
+ OpcodeF64Mul Opcode = 0xa2
+ OpcodeF64Div Opcode = 0xa3
+ OpcodeF64Min Opcode = 0xa4
+ OpcodeF64Max Opcode = 0xa5
+ OpcodeF64Copysign Opcode = 0xa6
+
+ OpcodeI32WrapI64 Opcode = 0xa7
+ OpcodeI32TruncF32S Opcode = 0xa8
+ OpcodeI32TruncF32U Opcode = 0xa9
+ OpcodeI32TruncF64S Opcode = 0xaa
+ OpcodeI32TruncF64U Opcode = 0xab
+
+ OpcodeI64ExtendI32S Opcode = 0xac
+ OpcodeI64ExtendI32U Opcode = 0xad
+ OpcodeI64TruncF32S Opcode = 0xae
+ OpcodeI64TruncF32U Opcode = 0xaf
+ OpcodeI64TruncF64S Opcode = 0xb0
+ OpcodeI64TruncF64U Opcode = 0xb1
+
+ OpcodeF32ConvertI32S Opcode = 0xb2
+ OpcodeF32ConvertI32U Opcode = 0xb3
+ OpcodeF32ConvertI64S Opcode = 0xb4
+ OpcodeF32ConvertI64U Opcode = 0xb5
+ OpcodeF32DemoteF64 Opcode = 0xb6
+
+ OpcodeF64ConvertI32S Opcode = 0xb7
+ OpcodeF64ConvertI32U Opcode = 0xb8
+ OpcodeF64ConvertI64S Opcode = 0xb9
+ OpcodeF64ConvertI64U Opcode = 0xba
+ OpcodeF64PromoteF32 Opcode = 0xbb
+
+ OpcodeI32ReinterpretF32 Opcode = 0xbc
+ OpcodeI64ReinterpretF64 Opcode = 0xbd
+ OpcodeF32ReinterpretI32 Opcode = 0xbe
+ OpcodeF64ReinterpretI64 Opcode = 0xbf
+
+ // OpcodeRefNull pushes a null reference value whose type is specified by immediate to this opcode.
+ // This is defined in the reference-types proposal, but necessary for CoreFeatureBulkMemoryOperations as well.
+ //
+ // Currently only supported in the constant expression in element segments.
+ OpcodeRefNull = 0xd0
+ // OpcodeRefIsNull pops a reference value, and pushes 1 if it is null, 0 otherwise.
+ // This is defined in the reference-types proposal, but necessary for CoreFeatureBulkMemoryOperations as well.
+ //
+ // Currently not supported.
+ OpcodeRefIsNull = 0xd1
+ // OpcodeRefFunc pushes a funcref value whose index equals the immediate to this opcode.
+ // This is defined in the reference-types proposal, but necessary for CoreFeatureBulkMemoryOperations as well.
+ //
+ // Currently, this is only supported in the constant expression in element segments.
+ OpcodeRefFunc = 0xd2
+
+ // Below are toggled with CoreFeatureSignExtensionOps
+
+ // OpcodeI32Extend8S extends a signed 8-bit integer to a 32-bit integer.
+ // Note: This is dependent on the flag CoreFeatureSignExtensionOps
+ OpcodeI32Extend8S Opcode = 0xc0
+
+ // OpcodeI32Extend16S extends a signed 16-bit integer to a 32-bit integer.
+ // Note: This is dependent on the flag CoreFeatureSignExtensionOps
+ OpcodeI32Extend16S Opcode = 0xc1
+
+ // OpcodeI64Extend8S extends a signed 8-bit integer to a 64-bit integer.
+ // Note: This is dependent on the flag CoreFeatureSignExtensionOps
+ OpcodeI64Extend8S Opcode = 0xc2
+
+ // OpcodeI64Extend16S extends a signed 16-bit integer to a 64-bit integer.
+ // Note: This is dependent on the flag CoreFeatureSignExtensionOps
+ OpcodeI64Extend16S Opcode = 0xc3
+
+ // OpcodeI64Extend32S extends a signed 32-bit integer to a 64-bit integer.
+ // Note: This is dependent on the flag CoreFeatureSignExtensionOps
+ OpcodeI64Extend32S Opcode = 0xc4
+
+ // OpcodeMiscPrefix is the prefix of various multi-byte opcodes.
+ // Introduced in CoreFeatureNonTrappingFloatToIntConversion, but used in other
+ // features, such as CoreFeatureBulkMemoryOperations.
+ OpcodeMiscPrefix Opcode = 0xfc
+
+ // OpcodeVecPrefix is the prefix of all vector isntructions introduced in
+ // CoreFeatureSIMD.
+ OpcodeVecPrefix Opcode = 0xfd
+
+ // OpcodeAtomicPrefix is the prefix of all atomic instructions introduced in
+ // CoreFeatureThreads.
+ OpcodeAtomicPrefix Opcode = 0xfe
+)
+
+// OpcodeMisc represents opcodes of the miscellaneous operations.
+// Such an operations has multi-byte encoding which is prefixed by OpcodeMiscPrefix.
+type OpcodeMisc = byte
+
+const (
+ // Below are toggled with CoreFeatureNonTrappingFloatToIntConversion.
+ // https://github.com/WebAssembly/spec/blob/ce4b6c4d47eb06098cc7ab2e81f24748da822f20/proposals/nontrapping-float-to-int-conversion/Overview.md
+
+ OpcodeMiscI32TruncSatF32S OpcodeMisc = 0x00
+ OpcodeMiscI32TruncSatF32U OpcodeMisc = 0x01
+ OpcodeMiscI32TruncSatF64S OpcodeMisc = 0x02
+ OpcodeMiscI32TruncSatF64U OpcodeMisc = 0x03
+ OpcodeMiscI64TruncSatF32S OpcodeMisc = 0x04
+ OpcodeMiscI64TruncSatF32U OpcodeMisc = 0x05
+ OpcodeMiscI64TruncSatF64S OpcodeMisc = 0x06
+ OpcodeMiscI64TruncSatF64U OpcodeMisc = 0x07
+
+ // Below are toggled with CoreFeatureBulkMemoryOperations.
+ // Opcodes are those new in document/core/appendix/index-instructions.rst (the commit that merged the feature).
+ // See https://github.com/WebAssembly/spec/commit/7fa2f20a6df4cf1c114582c8cb60f5bfcdbf1be1
+ // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
+
+ OpcodeMiscMemoryInit OpcodeMisc = 0x08
+ OpcodeMiscDataDrop OpcodeMisc = 0x09
+ OpcodeMiscMemoryCopy OpcodeMisc = 0x0a
+ OpcodeMiscMemoryFill OpcodeMisc = 0x0b
+ OpcodeMiscTableInit OpcodeMisc = 0x0c
+ OpcodeMiscElemDrop OpcodeMisc = 0x0d
+ OpcodeMiscTableCopy OpcodeMisc = 0x0e
+
+ // Below are toggled with CoreFeatureReferenceTypes
+
+ OpcodeMiscTableGrow OpcodeMisc = 0x0f
+ OpcodeMiscTableSize OpcodeMisc = 0x10
+ OpcodeMiscTableFill OpcodeMisc = 0x11
+)
+
+// OpcodeVec represents an opcode of a vector instructions which has
+// multi-byte encoding and is prefixed by OpcodeMiscPrefix.
+//
+// These opcodes are toggled with CoreFeatureSIMD.
+type OpcodeVec = byte
+
+const (
+ // Loads and stores.
+
+ OpcodeVecV128Load OpcodeVec = 0x00
+ OpcodeVecV128Load8x8s OpcodeVec = 0x01
+ OpcodeVecV128Load8x8u OpcodeVec = 0x02
+ OpcodeVecV128Load16x4s OpcodeVec = 0x03
+ OpcodeVecV128Load16x4u OpcodeVec = 0x04
+ OpcodeVecV128Load32x2s OpcodeVec = 0x05
+ OpcodeVecV128Load32x2u OpcodeVec = 0x06
+ OpcodeVecV128Load8Splat OpcodeVec = 0x07
+ OpcodeVecV128Load16Splat OpcodeVec = 0x08
+ OpcodeVecV128Load32Splat OpcodeVec = 0x09
+ OpcodeVecV128Load64Splat OpcodeVec = 0x0a
+
+ OpcodeVecV128Load32zero OpcodeVec = 0x5c
+ OpcodeVecV128Load64zero OpcodeVec = 0x5d
+
+ OpcodeVecV128Store OpcodeVec = 0x0b
+ OpcodeVecV128Load8Lane OpcodeVec = 0x54
+ OpcodeVecV128Load16Lane OpcodeVec = 0x55
+ OpcodeVecV128Load32Lane OpcodeVec = 0x56
+ OpcodeVecV128Load64Lane OpcodeVec = 0x57
+ OpcodeVecV128Store8Lane OpcodeVec = 0x58
+ OpcodeVecV128Store16Lane OpcodeVec = 0x59
+ OpcodeVecV128Store32Lane OpcodeVec = 0x5a
+ OpcodeVecV128Store64Lane OpcodeVec = 0x5b
+
+ // OpcodeVecV128Const is the vector const instruction.
+ OpcodeVecV128Const OpcodeVec = 0x0c
+
+ // OpcodeVecV128i8x16Shuffle is the vector shuffle instruction.
+ OpcodeVecV128i8x16Shuffle OpcodeVec = 0x0d
+
+ // Extrac and replaces.
+
+ OpcodeVecI8x16ExtractLaneS OpcodeVec = 0x15
+ OpcodeVecI8x16ExtractLaneU OpcodeVec = 0x16
+ OpcodeVecI8x16ReplaceLane OpcodeVec = 0x17
+ OpcodeVecI16x8ExtractLaneS OpcodeVec = 0x18
+ OpcodeVecI16x8ExtractLaneU OpcodeVec = 0x19
+ OpcodeVecI16x8ReplaceLane OpcodeVec = 0x1a
+ OpcodeVecI32x4ExtractLane OpcodeVec = 0x1b
+ OpcodeVecI32x4ReplaceLane OpcodeVec = 0x1c
+ OpcodeVecI64x2ExtractLane OpcodeVec = 0x1d
+ OpcodeVecI64x2ReplaceLane OpcodeVec = 0x1e
+ OpcodeVecF32x4ExtractLane OpcodeVec = 0x1f
+ OpcodeVecF32x4ReplaceLane OpcodeVec = 0x20
+ OpcodeVecF64x2ExtractLane OpcodeVec = 0x21
+ OpcodeVecF64x2ReplaceLane OpcodeVec = 0x22
+
+ // Splat and swizzle.
+
+ OpcodeVecI8x16Swizzle OpcodeVec = 0x0e
+ OpcodeVecI8x16Splat OpcodeVec = 0x0f
+ OpcodeVecI16x8Splat OpcodeVec = 0x10
+ OpcodeVecI32x4Splat OpcodeVec = 0x11
+ OpcodeVecI64x2Splat OpcodeVec = 0x12
+ OpcodeVecF32x4Splat OpcodeVec = 0x13
+ OpcodeVecF64x2Splat OpcodeVec = 0x14
+
+ // i8 comparisons.
+
+ OpcodeVecI8x16Eq OpcodeVec = 0x23
+ OpcodeVecI8x16Ne OpcodeVec = 0x24
+ OpcodeVecI8x16LtS OpcodeVec = 0x25
+ OpcodeVecI8x16LtU OpcodeVec = 0x26
+ OpcodeVecI8x16GtS OpcodeVec = 0x27
+ OpcodeVecI8x16GtU OpcodeVec = 0x28
+ OpcodeVecI8x16LeS OpcodeVec = 0x29
+ OpcodeVecI8x16LeU OpcodeVec = 0x2a
+ OpcodeVecI8x16GeS OpcodeVec = 0x2b
+ OpcodeVecI8x16GeU OpcodeVec = 0x2c
+
+ // i16 comparisons.
+
+ OpcodeVecI16x8Eq OpcodeVec = 0x2d
+ OpcodeVecI16x8Ne OpcodeVec = 0x2e
+ OpcodeVecI16x8LtS OpcodeVec = 0x2f
+ OpcodeVecI16x8LtU OpcodeVec = 0x30
+ OpcodeVecI16x8GtS OpcodeVec = 0x31
+ OpcodeVecI16x8GtU OpcodeVec = 0x32
+ OpcodeVecI16x8LeS OpcodeVec = 0x33
+ OpcodeVecI16x8LeU OpcodeVec = 0x34
+ OpcodeVecI16x8GeS OpcodeVec = 0x35
+ OpcodeVecI16x8GeU OpcodeVec = 0x36
+
+ // i32 comparisons.
+
+ OpcodeVecI32x4Eq OpcodeVec = 0x37
+ OpcodeVecI32x4Ne OpcodeVec = 0x38
+ OpcodeVecI32x4LtS OpcodeVec = 0x39
+ OpcodeVecI32x4LtU OpcodeVec = 0x3a
+ OpcodeVecI32x4GtS OpcodeVec = 0x3b
+ OpcodeVecI32x4GtU OpcodeVec = 0x3c
+ OpcodeVecI32x4LeS OpcodeVec = 0x3d
+ OpcodeVecI32x4LeU OpcodeVec = 0x3e
+ OpcodeVecI32x4GeS OpcodeVec = 0x3f
+ OpcodeVecI32x4GeU OpcodeVec = 0x40
+
+ // i64 comparisons.
+
+ OpcodeVecI64x2Eq OpcodeVec = 0xd6
+ OpcodeVecI64x2Ne OpcodeVec = 0xd7
+ OpcodeVecI64x2LtS OpcodeVec = 0xd8
+ OpcodeVecI64x2GtS OpcodeVec = 0xd9
+ OpcodeVecI64x2LeS OpcodeVec = 0xda
+ OpcodeVecI64x2GeS OpcodeVec = 0xdb
+
+ // f32 comparisons.
+
+ OpcodeVecF32x4Eq OpcodeVec = 0x41
+ OpcodeVecF32x4Ne OpcodeVec = 0x42
+ OpcodeVecF32x4Lt OpcodeVec = 0x43
+ OpcodeVecF32x4Gt OpcodeVec = 0x44
+ OpcodeVecF32x4Le OpcodeVec = 0x45
+ OpcodeVecF32x4Ge OpcodeVec = 0x46
+
+ // f64 comparisons.
+
+ OpcodeVecF64x2Eq OpcodeVec = 0x47
+ OpcodeVecF64x2Ne OpcodeVec = 0x48
+ OpcodeVecF64x2Lt OpcodeVec = 0x49
+ OpcodeVecF64x2Gt OpcodeVec = 0x4a
+ OpcodeVecF64x2Le OpcodeVec = 0x4b
+ OpcodeVecF64x2Ge OpcodeVec = 0x4c
+
+ // v128 logical instructions.
+
+ OpcodeVecV128Not OpcodeVec = 0x4d
+ OpcodeVecV128And OpcodeVec = 0x4e
+ OpcodeVecV128AndNot OpcodeVec = 0x4f
+ OpcodeVecV128Or OpcodeVec = 0x50
+ OpcodeVecV128Xor OpcodeVec = 0x51
+ OpcodeVecV128Bitselect OpcodeVec = 0x52
+ OpcodeVecV128AnyTrue OpcodeVec = 0x53
+
+ // i8 misc.
+
+ OpcodeVecI8x16Abs OpcodeVec = 0x60
+ OpcodeVecI8x16Neg OpcodeVec = 0x61
+ OpcodeVecI8x16Popcnt OpcodeVec = 0x62
+ OpcodeVecI8x16AllTrue OpcodeVec = 0x63
+ OpcodeVecI8x16BitMask OpcodeVec = 0x64
+ OpcodeVecI8x16NarrowI16x8S OpcodeVec = 0x65
+ OpcodeVecI8x16NarrowI16x8U OpcodeVec = 0x66
+
+ OpcodeVecI8x16Shl OpcodeVec = 0x6b
+ OpcodeVecI8x16ShrS OpcodeVec = 0x6c
+ OpcodeVecI8x16ShrU OpcodeVec = 0x6d
+ OpcodeVecI8x16Add OpcodeVec = 0x6e
+ OpcodeVecI8x16AddSatS OpcodeVec = 0x6f
+
+ OpcodeVecI8x16AddSatU OpcodeVec = 0x70
+ OpcodeVecI8x16Sub OpcodeVec = 0x71
+ OpcodeVecI8x16SubSatS OpcodeVec = 0x72
+ OpcodeVecI8x16SubSatU OpcodeVec = 0x73
+ OpcodeVecI8x16MinS OpcodeVec = 0x76
+ OpcodeVecI8x16MinU OpcodeVec = 0x77
+ OpcodeVecI8x16MaxS OpcodeVec = 0x78
+ OpcodeVecI8x16MaxU OpcodeVec = 0x79
+ OpcodeVecI8x16AvgrU OpcodeVec = 0x7b
+
+ // i16 misc.
+
+ OpcodeVecI16x8ExtaddPairwiseI8x16S OpcodeVec = 0x7c
+ OpcodeVecI16x8ExtaddPairwiseI8x16U OpcodeVec = 0x7d
+ OpcodeVecI16x8Abs OpcodeVec = 0x80
+ OpcodeVecI16x8Neg OpcodeVec = 0x81
+ OpcodeVecI16x8Q15mulrSatS OpcodeVec = 0x82
+ OpcodeVecI16x8AllTrue OpcodeVec = 0x83
+ OpcodeVecI16x8BitMask OpcodeVec = 0x84
+ OpcodeVecI16x8NarrowI32x4S OpcodeVec = 0x85
+ OpcodeVecI16x8NarrowI32x4U OpcodeVec = 0x86
+ OpcodeVecI16x8ExtendLowI8x16S OpcodeVec = 0x87
+ OpcodeVecI16x8ExtendHighI8x16S OpcodeVec = 0x88
+ OpcodeVecI16x8ExtendLowI8x16U OpcodeVec = 0x89
+ OpcodeVecI16x8ExtendHighI8x16U OpcodeVec = 0x8a
+ OpcodeVecI16x8Shl OpcodeVec = 0x8b
+ OpcodeVecI16x8ShrS OpcodeVec = 0x8c
+ OpcodeVecI16x8ShrU OpcodeVec = 0x8d
+ OpcodeVecI16x8Add OpcodeVec = 0x8e
+ OpcodeVecI16x8AddSatS OpcodeVec = 0x8f
+ OpcodeVecI16x8AddSatU OpcodeVec = 0x90
+ OpcodeVecI16x8Sub OpcodeVec = 0x91
+ OpcodeVecI16x8SubSatS OpcodeVec = 0x92
+ OpcodeVecI16x8SubSatU OpcodeVec = 0x93
+ OpcodeVecI16x8Mul OpcodeVec = 0x95
+ OpcodeVecI16x8MinS OpcodeVec = 0x96
+ OpcodeVecI16x8MinU OpcodeVec = 0x97
+ OpcodeVecI16x8MaxS OpcodeVec = 0x98
+ OpcodeVecI16x8MaxU OpcodeVec = 0x99
+ OpcodeVecI16x8AvgrU OpcodeVec = 0x9b
+ OpcodeVecI16x8ExtMulLowI8x16S OpcodeVec = 0x9c
+ OpcodeVecI16x8ExtMulHighI8x16S OpcodeVec = 0x9d
+ OpcodeVecI16x8ExtMulLowI8x16U OpcodeVec = 0x9e
+ OpcodeVecI16x8ExtMulHighI8x16U OpcodeVec = 0x9f
+
+ // i32 misc.
+
+ OpcodeVecI32x4ExtaddPairwiseI16x8S OpcodeVec = 0x7e
+ OpcodeVecI32x4ExtaddPairwiseI16x8U OpcodeVec = 0x7f
+ OpcodeVecI32x4Abs OpcodeVec = 0xa0
+ OpcodeVecI32x4Neg OpcodeVec = 0xa1
+ OpcodeVecI32x4AllTrue OpcodeVec = 0xa3
+ OpcodeVecI32x4BitMask OpcodeVec = 0xa4
+ OpcodeVecI32x4ExtendLowI16x8S OpcodeVec = 0xa7
+ OpcodeVecI32x4ExtendHighI16x8S OpcodeVec = 0xa8
+ OpcodeVecI32x4ExtendLowI16x8U OpcodeVec = 0xa9
+ OpcodeVecI32x4ExtendHighI16x8U OpcodeVec = 0xaa
+ OpcodeVecI32x4Shl OpcodeVec = 0xab
+ OpcodeVecI32x4ShrS OpcodeVec = 0xac
+ OpcodeVecI32x4ShrU OpcodeVec = 0xad
+ OpcodeVecI32x4Add OpcodeVec = 0xae
+ OpcodeVecI32x4Sub OpcodeVec = 0xb1
+ OpcodeVecI32x4Mul OpcodeVec = 0xb5
+ OpcodeVecI32x4MinS OpcodeVec = 0xb6
+ OpcodeVecI32x4MinU OpcodeVec = 0xb7
+ OpcodeVecI32x4MaxS OpcodeVec = 0xb8
+ OpcodeVecI32x4MaxU OpcodeVec = 0xb9
+ OpcodeVecI32x4DotI16x8S OpcodeVec = 0xba
+ OpcodeVecI32x4ExtMulLowI16x8S OpcodeVec = 0xbc
+ OpcodeVecI32x4ExtMulHighI16x8S OpcodeVec = 0xbd
+ OpcodeVecI32x4ExtMulLowI16x8U OpcodeVec = 0xbe
+ OpcodeVecI32x4ExtMulHighI16x8U OpcodeVec = 0xbf
+
+ // i64 misc.
+
+ OpcodeVecI64x2Abs OpcodeVec = 0xc0
+ OpcodeVecI64x2Neg OpcodeVec = 0xc1
+ OpcodeVecI64x2AllTrue OpcodeVec = 0xc3
+ OpcodeVecI64x2BitMask OpcodeVec = 0xc4
+ OpcodeVecI64x2ExtendLowI32x4S OpcodeVec = 0xc7
+ OpcodeVecI64x2ExtendHighI32x4S OpcodeVec = 0xc8
+ OpcodeVecI64x2ExtendLowI32x4U OpcodeVec = 0xc9
+ OpcodeVecI64x2ExtendHighI32x4U OpcodeVec = 0xca
+ OpcodeVecI64x2Shl OpcodeVec = 0xcb
+ OpcodeVecI64x2ShrS OpcodeVec = 0xcc
+ OpcodeVecI64x2ShrU OpcodeVec = 0xcd
+ OpcodeVecI64x2Add OpcodeVec = 0xce
+ OpcodeVecI64x2Sub OpcodeVec = 0xd1
+ OpcodeVecI64x2Mul OpcodeVec = 0xd5
+ OpcodeVecI64x2ExtMulLowI32x4S OpcodeVec = 0xdc
+ OpcodeVecI64x2ExtMulHighI32x4S OpcodeVec = 0xdd
+ OpcodeVecI64x2ExtMulLowI32x4U OpcodeVec = 0xde
+ OpcodeVecI64x2ExtMulHighI32x4U OpcodeVec = 0xdf
+
+ // f32 misc.
+
+ OpcodeVecF32x4Ceil OpcodeVec = 0x67
+ OpcodeVecF32x4Floor OpcodeVec = 0x68
+ OpcodeVecF32x4Trunc OpcodeVec = 0x69
+ OpcodeVecF32x4Nearest OpcodeVec = 0x6a
+ OpcodeVecF32x4Abs OpcodeVec = 0xe0
+ OpcodeVecF32x4Neg OpcodeVec = 0xe1
+ OpcodeVecF32x4Sqrt OpcodeVec = 0xe3
+ OpcodeVecF32x4Add OpcodeVec = 0xe4
+ OpcodeVecF32x4Sub OpcodeVec = 0xe5
+ OpcodeVecF32x4Mul OpcodeVec = 0xe6
+ OpcodeVecF32x4Div OpcodeVec = 0xe7
+ OpcodeVecF32x4Min OpcodeVec = 0xe8
+ OpcodeVecF32x4Max OpcodeVec = 0xe9
+ OpcodeVecF32x4Pmin OpcodeVec = 0xea
+ OpcodeVecF32x4Pmax OpcodeVec = 0xeb
+
+ // f64 misc.
+
+ OpcodeVecF64x2Ceil OpcodeVec = 0x74
+ OpcodeVecF64x2Floor OpcodeVec = 0x75
+ OpcodeVecF64x2Trunc OpcodeVec = 0x7a
+ OpcodeVecF64x2Nearest OpcodeVec = 0x94
+ OpcodeVecF64x2Abs OpcodeVec = 0xec
+ OpcodeVecF64x2Neg OpcodeVec = 0xed
+ OpcodeVecF64x2Sqrt OpcodeVec = 0xef
+ OpcodeVecF64x2Add OpcodeVec = 0xf0
+ OpcodeVecF64x2Sub OpcodeVec = 0xf1
+ OpcodeVecF64x2Mul OpcodeVec = 0xf2
+ OpcodeVecF64x2Div OpcodeVec = 0xf3
+ OpcodeVecF64x2Min OpcodeVec = 0xf4
+ OpcodeVecF64x2Max OpcodeVec = 0xf5
+ OpcodeVecF64x2Pmin OpcodeVec = 0xf6
+ OpcodeVecF64x2Pmax OpcodeVec = 0xf7
+
+ // conversions.
+
+ OpcodeVecI32x4TruncSatF32x4S OpcodeVec = 0xf8
+ OpcodeVecI32x4TruncSatF32x4U OpcodeVec = 0xf9
+ OpcodeVecF32x4ConvertI32x4S OpcodeVec = 0xfa
+ OpcodeVecF32x4ConvertI32x4U OpcodeVec = 0xfb
+ OpcodeVecI32x4TruncSatF64x2SZero OpcodeVec = 0xfc
+ OpcodeVecI32x4TruncSatF64x2UZero OpcodeVec = 0xfd
+ OpcodeVecF64x2ConvertLowI32x4S OpcodeVec = 0xfe
+ OpcodeVecF64x2ConvertLowI32x4U OpcodeVec = 0xff
+ OpcodeVecF32x4DemoteF64x2Zero OpcodeVec = 0x5e
+ OpcodeVecF64x2PromoteLowF32x4Zero OpcodeVec = 0x5f
+)
+
+// OpcodeAtomic represents an opcode of atomic instructions which has
+// multi-byte encoding and is prefixed by OpcodeAtomicPrefix.
+//
+// These opcodes are toggled with CoreFeaturesThreads.
+type OpcodeAtomic = byte
+
+const (
+ // OpcodeAtomicMemoryNotify represents the instruction memory.atomic.notify.
+ OpcodeAtomicMemoryNotify OpcodeAtomic = 0x00
+ // OpcodeAtomicMemoryWait32 represents the instruction memory.atomic.wait32.
+ OpcodeAtomicMemoryWait32 OpcodeAtomic = 0x01
+ // OpcodeAtomicMemoryWait64 represents the instruction memory.atomic.wait64.
+ OpcodeAtomicMemoryWait64 OpcodeAtomic = 0x02
+ // OpcodeAtomicFence represents the instruction atomic.fence.
+ OpcodeAtomicFence OpcodeAtomic = 0x03
+
+ // OpcodeAtomicI32Load represents the instruction i32.atomic.load.
+ OpcodeAtomicI32Load OpcodeAtomic = 0x10
+ // OpcodeAtomicI64Load represents the instruction i64.atomic.load.
+ OpcodeAtomicI64Load OpcodeAtomic = 0x11
+ // OpcodeAtomicI32Load8U represents the instruction i32.atomic.load8_u.
+ OpcodeAtomicI32Load8U OpcodeAtomic = 0x12
+ // OpcodeAtomicI32Load16U represents the instruction i32.atomic.load16_u.
+ OpcodeAtomicI32Load16U OpcodeAtomic = 0x13
+ // OpcodeAtomicI64Load8U represents the instruction i64.atomic.load8_u.
+ OpcodeAtomicI64Load8U OpcodeAtomic = 0x14
+ // OpcodeAtomicI64Load16U represents the instruction i64.atomic.load16_u.
+ OpcodeAtomicI64Load16U OpcodeAtomic = 0x15
+ // OpcodeAtomicI64Load32U represents the instruction i64.atomic.load32_u.
+ OpcodeAtomicI64Load32U OpcodeAtomic = 0x16
+ // OpcodeAtomicI32Store represents the instruction i32.atomic.store.
+ OpcodeAtomicI32Store OpcodeAtomic = 0x17
+ // OpcodeAtomicI64Store represents the instruction i64.atomic.store.
+ OpcodeAtomicI64Store OpcodeAtomic = 0x18
+ // OpcodeAtomicI32Store8 represents the instruction i32.atomic.store8.
+ OpcodeAtomicI32Store8 OpcodeAtomic = 0x19
+ // OpcodeAtomicI32Store16 represents the instruction i32.atomic.store16.
+ OpcodeAtomicI32Store16 OpcodeAtomic = 0x1a
+ // OpcodeAtomicI64Store8 represents the instruction i64.atomic.store8.
+ OpcodeAtomicI64Store8 OpcodeAtomic = 0x1b
+ // OpcodeAtomicI64Store16 represents the instruction i64.atomic.store16.
+ OpcodeAtomicI64Store16 OpcodeAtomic = 0x1c
+ // OpcodeAtomicI64Store32 represents the instruction i64.atomic.store32.
+ OpcodeAtomicI64Store32 OpcodeAtomic = 0x1d
+
+ // OpcodeAtomicI32RmwAdd represents the instruction i32.atomic.rmw.add.
+ OpcodeAtomicI32RmwAdd OpcodeAtomic = 0x1e
+ // OpcodeAtomicI64RmwAdd represents the instruction i64.atomic.rmw.add.
+ OpcodeAtomicI64RmwAdd OpcodeAtomic = 0x1f
+ // OpcodeAtomicI32Rmw8AddU represents the instruction i32.atomic.rmw8.add_u.
+ OpcodeAtomicI32Rmw8AddU OpcodeAtomic = 0x20
+ // OpcodeAtomicI32Rmw16AddU represents the instruction i32.atomic.rmw16.add_u.
+ OpcodeAtomicI32Rmw16AddU OpcodeAtomic = 0x21
+ // OpcodeAtomicI64Rmw8AddU represents the instruction i64.atomic.rmw8.add_u.
+ OpcodeAtomicI64Rmw8AddU OpcodeAtomic = 0x22
+ // OpcodeAtomicI64Rmw16AddU represents the instruction i64.atomic.rmw16.add_u.
+ OpcodeAtomicI64Rmw16AddU OpcodeAtomic = 0x23
+ // OpcodeAtomicI64Rmw32AddU represents the instruction i64.atomic.rmw32.add_u.
+ OpcodeAtomicI64Rmw32AddU OpcodeAtomic = 0x24
+
+ // OpcodeAtomicI32RmwSub represents the instruction i32.atomic.rmw.sub.
+ OpcodeAtomicI32RmwSub OpcodeAtomic = 0x25
+ // OpcodeAtomicI64RmwSub represents the instruction i64.atomic.rmw.sub.
+ OpcodeAtomicI64RmwSub OpcodeAtomic = 0x26
+ // OpcodeAtomicI32Rmw8SubU represents the instruction i32.atomic.rmw8.sub_u.
+ OpcodeAtomicI32Rmw8SubU OpcodeAtomic = 0x27
+ // OpcodeAtomicI32Rmw16SubU represents the instruction i32.atomic.rmw16.sub_u.
+ OpcodeAtomicI32Rmw16SubU OpcodeAtomic = 0x28
+ // OpcodeAtomicI64Rmw8SubU represents the instruction i64.atomic.rmw8.sub_u.
+ OpcodeAtomicI64Rmw8SubU OpcodeAtomic = 0x29
+ // OpcodeAtomicI64Rmw16SubU represents the instruction i64.atomic.rmw16.sub_u.
+ OpcodeAtomicI64Rmw16SubU OpcodeAtomic = 0x2a
+ // OpcodeAtomicI64Rmw32SubU represents the instruction i64.atomic.rmw32.sub_u.
+ OpcodeAtomicI64Rmw32SubU OpcodeAtomic = 0x2b
+
+ // OpcodeAtomicI32RmwAnd represents the instruction i32.atomic.rmw.and.
+ OpcodeAtomicI32RmwAnd OpcodeAtomic = 0x2c
+ // OpcodeAtomicI64RmwAnd represents the instruction i64.atomic.rmw.and.
+ OpcodeAtomicI64RmwAnd OpcodeAtomic = 0x2d
+ // OpcodeAtomicI32Rmw8AndU represents the instruction i32.atomic.rmw8.and_u.
+ OpcodeAtomicI32Rmw8AndU OpcodeAtomic = 0x2e
+ // OpcodeAtomicI32Rmw16AndU represents the instruction i32.atomic.rmw16.and_u.
+ OpcodeAtomicI32Rmw16AndU OpcodeAtomic = 0x2f
+ // OpcodeAtomicI64Rmw8AndU represents the instruction i64.atomic.rmw8.and_u.
+ OpcodeAtomicI64Rmw8AndU OpcodeAtomic = 0x30
+ // OpcodeAtomicI64Rmw16AndU represents the instruction i64.atomic.rmw16.and_u.
+ OpcodeAtomicI64Rmw16AndU OpcodeAtomic = 0x31
+ // OpcodeAtomicI64Rmw32AndU represents the instruction i64.atomic.rmw32.and_u.
+ OpcodeAtomicI64Rmw32AndU OpcodeAtomic = 0x32
+
+ // OpcodeAtomicI32RmwOr represents the instruction i32.atomic.rmw.or.
+ OpcodeAtomicI32RmwOr OpcodeAtomic = 0x33
+ // OpcodeAtomicI64RmwOr represents the instruction i64.atomic.rmw.or.
+ OpcodeAtomicI64RmwOr OpcodeAtomic = 0x34
+ // OpcodeAtomicI32Rmw8OrU represents the instruction i32.atomic.rmw8.or_u.
+ OpcodeAtomicI32Rmw8OrU OpcodeAtomic = 0x35
+ // OpcodeAtomicI32Rmw16OrU represents the instruction i32.atomic.rmw16.or_u.
+ OpcodeAtomicI32Rmw16OrU OpcodeAtomic = 0x36
+ // OpcodeAtomicI64Rmw8OrU represents the instruction i64.atomic.rmw8.or_u.
+ OpcodeAtomicI64Rmw8OrU OpcodeAtomic = 0x37
+ // OpcodeAtomicI64Rmw16OrU represents the instruction i64.atomic.rmw16.or_u.
+ OpcodeAtomicI64Rmw16OrU OpcodeAtomic = 0x38
+ // OpcodeAtomicI64Rmw32OrU represents the instruction i64.atomic.rmw32.or_u.
+ OpcodeAtomicI64Rmw32OrU OpcodeAtomic = 0x39
+
+ // OpcodeAtomicI32RmwXor represents the instruction i32.atomic.rmw.xor.
+ OpcodeAtomicI32RmwXor OpcodeAtomic = 0x3a
+ // OpcodeAtomicI64RmwXor represents the instruction i64.atomic.rmw.xor.
+ OpcodeAtomicI64RmwXor OpcodeAtomic = 0x3b
+ // OpcodeAtomicI32Rmw8XorU represents the instruction i32.atomic.rmw8.xor_u.
+ OpcodeAtomicI32Rmw8XorU OpcodeAtomic = 0x3c
+ // OpcodeAtomicI32Rmw16XorU represents the instruction i32.atomic.rmw16.xor_u.
+ OpcodeAtomicI32Rmw16XorU OpcodeAtomic = 0x3d
+ // OpcodeAtomicI64Rmw8XorU represents the instruction i64.atomic.rmw8.xor_u.
+ OpcodeAtomicI64Rmw8XorU OpcodeAtomic = 0x3e
+ // OpcodeAtomicI64Rmw16XorU represents the instruction i64.atomic.rmw16.xor_u.
+ OpcodeAtomicI64Rmw16XorU OpcodeAtomic = 0x3f
+ // OpcodeAtomicI64Rmw32XorU represents the instruction i64.atomic.rmw32.xor_u.
+ OpcodeAtomicI64Rmw32XorU OpcodeAtomic = 0x40
+
+ // OpcodeAtomicI32RmwXchg represents the instruction i32.atomic.rmw.xchg.
+ OpcodeAtomicI32RmwXchg OpcodeAtomic = 0x41
+ // OpcodeAtomicI64RmwXchg represents the instruction i64.atomic.rmw.xchg.
+ OpcodeAtomicI64RmwXchg OpcodeAtomic = 0x42
+ // OpcodeAtomicI32Rmw8XchgU represents the instruction i32.atomic.rmw8.xchg_u.
+ OpcodeAtomicI32Rmw8XchgU OpcodeAtomic = 0x43
+ // OpcodeAtomicI32Rmw16XchgU represents the instruction i32.atomic.rmw16.xchg_u.
+ OpcodeAtomicI32Rmw16XchgU OpcodeAtomic = 0x44
+ // OpcodeAtomicI64Rmw8XchgU represents the instruction i64.atomic.rmw8.xchg_u.
+ OpcodeAtomicI64Rmw8XchgU OpcodeAtomic = 0x45
+ // OpcodeAtomicI64Rmw16XchgU represents the instruction i64.atomic.rmw16.xchg_u.
+ OpcodeAtomicI64Rmw16XchgU OpcodeAtomic = 0x46
+ // OpcodeAtomicI64Rmw32XchgU represents the instruction i64.atomic.rmw32.xchg_u.
+ OpcodeAtomicI64Rmw32XchgU OpcodeAtomic = 0x47
+
+ // OpcodeAtomicI32RmwCmpxchg represents the instruction i32.atomic.rmw.cmpxchg.
+ OpcodeAtomicI32RmwCmpxchg OpcodeAtomic = 0x48
+ // OpcodeAtomicI64RmwCmpxchg represents the instruction i64.atomic.rmw.cmpxchg.
+ OpcodeAtomicI64RmwCmpxchg OpcodeAtomic = 0x49
+ // OpcodeAtomicI32Rmw8CmpxchgU represents the instruction i32.atomic.rmw8.cmpxchg_u.
+ OpcodeAtomicI32Rmw8CmpxchgU OpcodeAtomic = 0x4a
+ // OpcodeAtomicI32Rmw16CmpxchgU represents the instruction i32.atomic.rmw16.cmpxchg_u.
+ OpcodeAtomicI32Rmw16CmpxchgU OpcodeAtomic = 0x4b
+ // OpcodeAtomicI64Rmw8CmpxchgU represents the instruction i64.atomic.rmw8.cmpxchg_u.
+ OpcodeAtomicI64Rmw8CmpxchgU OpcodeAtomic = 0x4c
+ // OpcodeAtomicI64Rmw16CmpxchgU represents the instruction i64.atomic.rmw16.cmpxchg_u.
+ OpcodeAtomicI64Rmw16CmpxchgU OpcodeAtomic = 0x4d
+ // OpcodeAtomicI64Rmw32CmpxchgU represents the instruction i64.atomic.rmw32.cmpxchg_u.
+ OpcodeAtomicI64Rmw32CmpxchgU OpcodeAtomic = 0x4e
+)
+
+const (
+ OpcodeUnreachableName = "unreachable"
+ OpcodeNopName = "nop"
+ OpcodeBlockName = "block"
+ OpcodeLoopName = "loop"
+ OpcodeIfName = "if"
+ OpcodeElseName = "else"
+ OpcodeEndName = "end"
+ OpcodeBrName = "br"
+ OpcodeBrIfName = "br_if"
+ OpcodeBrTableName = "br_table"
+ OpcodeReturnName = "return"
+ OpcodeCallName = "call"
+ OpcodeCallIndirectName = "call_indirect"
+ OpcodeDropName = "drop"
+ OpcodeSelectName = "select"
+ OpcodeTypedSelectName = "typed_select"
+ OpcodeLocalGetName = "local.get"
+ OpcodeLocalSetName = "local.set"
+ OpcodeLocalTeeName = "local.tee"
+ OpcodeGlobalGetName = "global.get"
+ OpcodeGlobalSetName = "global.set"
+ OpcodeI32LoadName = "i32.load"
+ OpcodeI64LoadName = "i64.load"
+ OpcodeF32LoadName = "f32.load"
+ OpcodeF64LoadName = "f64.load"
+ OpcodeI32Load8SName = "i32.load8_s"
+ OpcodeI32Load8UName = "i32.load8_u"
+ OpcodeI32Load16SName = "i32.load16_s"
+ OpcodeI32Load16UName = "i32.load16_u"
+ OpcodeI64Load8SName = "i64.load8_s"
+ OpcodeI64Load8UName = "i64.load8_u"
+ OpcodeI64Load16SName = "i64.load16_s"
+ OpcodeI64Load16UName = "i64.load16_u"
+ OpcodeI64Load32SName = "i64.load32_s"
+ OpcodeI64Load32UName = "i64.load32_u"
+ OpcodeI32StoreName = "i32.store"
+ OpcodeI64StoreName = "i64.store"
+ OpcodeF32StoreName = "f32.store"
+ OpcodeF64StoreName = "f64.store"
+ OpcodeI32Store8Name = "i32.store8"
+ OpcodeI32Store16Name = "i32.store16"
+ OpcodeI64Store8Name = "i64.store8"
+ OpcodeI64Store16Name = "i64.store16"
+ OpcodeI64Store32Name = "i64.store32"
+ OpcodeMemorySizeName = "memory.size"
+ OpcodeMemoryGrowName = "memory.grow"
+ OpcodeI32ConstName = "i32.const"
+ OpcodeI64ConstName = "i64.const"
+ OpcodeF32ConstName = "f32.const"
+ OpcodeF64ConstName = "f64.const"
+ OpcodeI32EqzName = "i32.eqz"
+ OpcodeI32EqName = "i32.eq"
+ OpcodeI32NeName = "i32.ne"
+ OpcodeI32LtSName = "i32.lt_s"
+ OpcodeI32LtUName = "i32.lt_u"
+ OpcodeI32GtSName = "i32.gt_s"
+ OpcodeI32GtUName = "i32.gt_u"
+ OpcodeI32LeSName = "i32.le_s"
+ OpcodeI32LeUName = "i32.le_u"
+ OpcodeI32GeSName = "i32.ge_s"
+ OpcodeI32GeUName = "i32.ge_u"
+ OpcodeI64EqzName = "i64.eqz"
+ OpcodeI64EqName = "i64.eq"
+ OpcodeI64NeName = "i64.ne"
+ OpcodeI64LtSName = "i64.lt_s"
+ OpcodeI64LtUName = "i64.lt_u"
+ OpcodeI64GtSName = "i64.gt_s"
+ OpcodeI64GtUName = "i64.gt_u"
+ OpcodeI64LeSName = "i64.le_s"
+ OpcodeI64LeUName = "i64.le_u"
+ OpcodeI64GeSName = "i64.ge_s"
+ OpcodeI64GeUName = "i64.ge_u"
+ OpcodeF32EqName = "f32.eq"
+ OpcodeF32NeName = "f32.ne"
+ OpcodeF32LtName = "f32.lt"
+ OpcodeF32GtName = "f32.gt"
+ OpcodeF32LeName = "f32.le"
+ OpcodeF32GeName = "f32.ge"
+ OpcodeF64EqName = "f64.eq"
+ OpcodeF64NeName = "f64.ne"
+ OpcodeF64LtName = "f64.lt"
+ OpcodeF64GtName = "f64.gt"
+ OpcodeF64LeName = "f64.le"
+ OpcodeF64GeName = "f64.ge"
+ OpcodeI32ClzName = "i32.clz"
+ OpcodeI32CtzName = "i32.ctz"
+ OpcodeI32PopcntName = "i32.popcnt"
+ OpcodeI32AddName = "i32.add"
+ OpcodeI32SubName = "i32.sub"
+ OpcodeI32MulName = "i32.mul"
+ OpcodeI32DivSName = "i32.div_s"
+ OpcodeI32DivUName = "i32.div_u"
+ OpcodeI32RemSName = "i32.rem_s"
+ OpcodeI32RemUName = "i32.rem_u"
+ OpcodeI32AndName = "i32.and"
+ OpcodeI32OrName = "i32.or"
+ OpcodeI32XorName = "i32.xor"
+ OpcodeI32ShlName = "i32.shl"
+ OpcodeI32ShrSName = "i32.shr_s"
+ OpcodeI32ShrUName = "i32.shr_u"
+ OpcodeI32RotlName = "i32.rotl"
+ OpcodeI32RotrName = "i32.rotr"
+ OpcodeI64ClzName = "i64.clz"
+ OpcodeI64CtzName = "i64.ctz"
+ OpcodeI64PopcntName = "i64.popcnt"
+ OpcodeI64AddName = "i64.add"
+ OpcodeI64SubName = "i64.sub"
+ OpcodeI64MulName = "i64.mul"
+ OpcodeI64DivSName = "i64.div_s"
+ OpcodeI64DivUName = "i64.div_u"
+ OpcodeI64RemSName = "i64.rem_s"
+ OpcodeI64RemUName = "i64.rem_u"
+ OpcodeI64AndName = "i64.and"
+ OpcodeI64OrName = "i64.or"
+ OpcodeI64XorName = "i64.xor"
+ OpcodeI64ShlName = "i64.shl"
+ OpcodeI64ShrSName = "i64.shr_s"
+ OpcodeI64ShrUName = "i64.shr_u"
+ OpcodeI64RotlName = "i64.rotl"
+ OpcodeI64RotrName = "i64.rotr"
+ OpcodeF32AbsName = "f32.abs"
+ OpcodeF32NegName = "f32.neg"
+ OpcodeF32CeilName = "f32.ceil"
+ OpcodeF32FloorName = "f32.floor"
+ OpcodeF32TruncName = "f32.trunc"
+ OpcodeF32NearestName = "f32.nearest"
+ OpcodeF32SqrtName = "f32.sqrt"
+ OpcodeF32AddName = "f32.add"
+ OpcodeF32SubName = "f32.sub"
+ OpcodeF32MulName = "f32.mul"
+ OpcodeF32DivName = "f32.div"
+ OpcodeF32MinName = "f32.min"
+ OpcodeF32MaxName = "f32.max"
+ OpcodeF32CopysignName = "f32.copysign"
+ OpcodeF64AbsName = "f64.abs"
+ OpcodeF64NegName = "f64.neg"
+ OpcodeF64CeilName = "f64.ceil"
+ OpcodeF64FloorName = "f64.floor"
+ OpcodeF64TruncName = "f64.trunc"
+ OpcodeF64NearestName = "f64.nearest"
+ OpcodeF64SqrtName = "f64.sqrt"
+ OpcodeF64AddName = "f64.add"
+ OpcodeF64SubName = "f64.sub"
+ OpcodeF64MulName = "f64.mul"
+ OpcodeF64DivName = "f64.div"
+ OpcodeF64MinName = "f64.min"
+ OpcodeF64MaxName = "f64.max"
+ OpcodeF64CopysignName = "f64.copysign"
+ OpcodeI32WrapI64Name = "i32.wrap_i64"
+ OpcodeI32TruncF32SName = "i32.trunc_f32_s"
+ OpcodeI32TruncF32UName = "i32.trunc_f32_u"
+ OpcodeI32TruncF64SName = "i32.trunc_f64_s"
+ OpcodeI32TruncF64UName = "i32.trunc_f64_u"
+ OpcodeI64ExtendI32SName = "i64.extend_i32_s"
+ OpcodeI64ExtendI32UName = "i64.extend_i32_u"
+ OpcodeI64TruncF32SName = "i64.trunc_f32_s"
+ OpcodeI64TruncF32UName = "i64.trunc_f32_u"
+ OpcodeI64TruncF64SName = "i64.trunc_f64_s"
+ OpcodeI64TruncF64UName = "i64.trunc_f64_u"
+ OpcodeF32ConvertI32SName = "f32.convert_i32_s"
+ OpcodeF32ConvertI32UName = "f32.convert_i32_u"
+ OpcodeF32ConvertI64SName = "f32.convert_i64_s"
+ OpcodeF32ConvertI64UName = "f32.convert_i64u"
+ OpcodeF32DemoteF64Name = "f32.demote_f64"
+ OpcodeF64ConvertI32SName = "f64.convert_i32_s"
+ OpcodeF64ConvertI32UName = "f64.convert_i32_u"
+ OpcodeF64ConvertI64SName = "f64.convert_i64_s"
+ OpcodeF64ConvertI64UName = "f64.convert_i64_u"
+ OpcodeF64PromoteF32Name = "f64.promote_f32"
+ OpcodeI32ReinterpretF32Name = "i32.reinterpret_f32"
+ OpcodeI64ReinterpretF64Name = "i64.reinterpret_f64"
+ OpcodeF32ReinterpretI32Name = "f32.reinterpret_i32"
+ OpcodeF64ReinterpretI64Name = "f64.reinterpret_i64"
+
+ OpcodeRefNullName = "ref.null"
+ OpcodeRefIsNullName = "ref.is_null"
+ OpcodeRefFuncName = "ref.func"
+
+ OpcodeTableGetName = "table.get"
+ OpcodeTableSetName = "table.set"
+
+ // Below are toggled with CoreFeatureSignExtensionOps
+
+ OpcodeI32Extend8SName = "i32.extend8_s"
+ OpcodeI32Extend16SName = "i32.extend16_s"
+ OpcodeI64Extend8SName = "i64.extend8_s"
+ OpcodeI64Extend16SName = "i64.extend16_s"
+ OpcodeI64Extend32SName = "i64.extend32_s"
+
+ OpcodeMiscPrefixName = "misc_prefix"
+ OpcodeVecPrefixName = "vector_prefix"
+ OpcodeAtomicPrefixName = "atomic_prefix"
+)
+
+var instructionNames = [256]string{
+ OpcodeUnreachable: OpcodeUnreachableName,
+ OpcodeNop: OpcodeNopName,
+ OpcodeBlock: OpcodeBlockName,
+ OpcodeLoop: OpcodeLoopName,
+ OpcodeIf: OpcodeIfName,
+ OpcodeElse: OpcodeElseName,
+ OpcodeEnd: OpcodeEndName,
+ OpcodeBr: OpcodeBrName,
+ OpcodeBrIf: OpcodeBrIfName,
+ OpcodeBrTable: OpcodeBrTableName,
+ OpcodeReturn: OpcodeReturnName,
+ OpcodeCall: OpcodeCallName,
+ OpcodeCallIndirect: OpcodeCallIndirectName,
+ OpcodeDrop: OpcodeDropName,
+ OpcodeSelect: OpcodeSelectName,
+ OpcodeTypedSelect: OpcodeTypedSelectName,
+ OpcodeLocalGet: OpcodeLocalGetName,
+ OpcodeLocalSet: OpcodeLocalSetName,
+ OpcodeLocalTee: OpcodeLocalTeeName,
+ OpcodeGlobalGet: OpcodeGlobalGetName,
+ OpcodeGlobalSet: OpcodeGlobalSetName,
+ OpcodeI32Load: OpcodeI32LoadName,
+ OpcodeI64Load: OpcodeI64LoadName,
+ OpcodeF32Load: OpcodeF32LoadName,
+ OpcodeF64Load: OpcodeF64LoadName,
+ OpcodeI32Load8S: OpcodeI32Load8SName,
+ OpcodeI32Load8U: OpcodeI32Load8UName,
+ OpcodeI32Load16S: OpcodeI32Load16SName,
+ OpcodeI32Load16U: OpcodeI32Load16UName,
+ OpcodeI64Load8S: OpcodeI64Load8SName,
+ OpcodeI64Load8U: OpcodeI64Load8UName,
+ OpcodeI64Load16S: OpcodeI64Load16SName,
+ OpcodeI64Load16U: OpcodeI64Load16UName,
+ OpcodeI64Load32S: OpcodeI64Load32SName,
+ OpcodeI64Load32U: OpcodeI64Load32UName,
+ OpcodeI32Store: OpcodeI32StoreName,
+ OpcodeI64Store: OpcodeI64StoreName,
+ OpcodeF32Store: OpcodeF32StoreName,
+ OpcodeF64Store: OpcodeF64StoreName,
+ OpcodeI32Store8: OpcodeI32Store8Name,
+ OpcodeI32Store16: OpcodeI32Store16Name,
+ OpcodeI64Store8: OpcodeI64Store8Name,
+ OpcodeI64Store16: OpcodeI64Store16Name,
+ OpcodeI64Store32: OpcodeI64Store32Name,
+ OpcodeMemorySize: OpcodeMemorySizeName,
+ OpcodeMemoryGrow: OpcodeMemoryGrowName,
+ OpcodeI32Const: OpcodeI32ConstName,
+ OpcodeI64Const: OpcodeI64ConstName,
+ OpcodeF32Const: OpcodeF32ConstName,
+ OpcodeF64Const: OpcodeF64ConstName,
+ OpcodeI32Eqz: OpcodeI32EqzName,
+ OpcodeI32Eq: OpcodeI32EqName,
+ OpcodeI32Ne: OpcodeI32NeName,
+ OpcodeI32LtS: OpcodeI32LtSName,
+ OpcodeI32LtU: OpcodeI32LtUName,
+ OpcodeI32GtS: OpcodeI32GtSName,
+ OpcodeI32GtU: OpcodeI32GtUName,
+ OpcodeI32LeS: OpcodeI32LeSName,
+ OpcodeI32LeU: OpcodeI32LeUName,
+ OpcodeI32GeS: OpcodeI32GeSName,
+ OpcodeI32GeU: OpcodeI32GeUName,
+ OpcodeI64Eqz: OpcodeI64EqzName,
+ OpcodeI64Eq: OpcodeI64EqName,
+ OpcodeI64Ne: OpcodeI64NeName,
+ OpcodeI64LtS: OpcodeI64LtSName,
+ OpcodeI64LtU: OpcodeI64LtUName,
+ OpcodeI64GtS: OpcodeI64GtSName,
+ OpcodeI64GtU: OpcodeI64GtUName,
+ OpcodeI64LeS: OpcodeI64LeSName,
+ OpcodeI64LeU: OpcodeI64LeUName,
+ OpcodeI64GeS: OpcodeI64GeSName,
+ OpcodeI64GeU: OpcodeI64GeUName,
+ OpcodeF32Eq: OpcodeF32EqName,
+ OpcodeF32Ne: OpcodeF32NeName,
+ OpcodeF32Lt: OpcodeF32LtName,
+ OpcodeF32Gt: OpcodeF32GtName,
+ OpcodeF32Le: OpcodeF32LeName,
+ OpcodeF32Ge: OpcodeF32GeName,
+ OpcodeF64Eq: OpcodeF64EqName,
+ OpcodeF64Ne: OpcodeF64NeName,
+ OpcodeF64Lt: OpcodeF64LtName,
+ OpcodeF64Gt: OpcodeF64GtName,
+ OpcodeF64Le: OpcodeF64LeName,
+ OpcodeF64Ge: OpcodeF64GeName,
+ OpcodeI32Clz: OpcodeI32ClzName,
+ OpcodeI32Ctz: OpcodeI32CtzName,
+ OpcodeI32Popcnt: OpcodeI32PopcntName,
+ OpcodeI32Add: OpcodeI32AddName,
+ OpcodeI32Sub: OpcodeI32SubName,
+ OpcodeI32Mul: OpcodeI32MulName,
+ OpcodeI32DivS: OpcodeI32DivSName,
+ OpcodeI32DivU: OpcodeI32DivUName,
+ OpcodeI32RemS: OpcodeI32RemSName,
+ OpcodeI32RemU: OpcodeI32RemUName,
+ OpcodeI32And: OpcodeI32AndName,
+ OpcodeI32Or: OpcodeI32OrName,
+ OpcodeI32Xor: OpcodeI32XorName,
+ OpcodeI32Shl: OpcodeI32ShlName,
+ OpcodeI32ShrS: OpcodeI32ShrSName,
+ OpcodeI32ShrU: OpcodeI32ShrUName,
+ OpcodeI32Rotl: OpcodeI32RotlName,
+ OpcodeI32Rotr: OpcodeI32RotrName,
+ OpcodeI64Clz: OpcodeI64ClzName,
+ OpcodeI64Ctz: OpcodeI64CtzName,
+ OpcodeI64Popcnt: OpcodeI64PopcntName,
+ OpcodeI64Add: OpcodeI64AddName,
+ OpcodeI64Sub: OpcodeI64SubName,
+ OpcodeI64Mul: OpcodeI64MulName,
+ OpcodeI64DivS: OpcodeI64DivSName,
+ OpcodeI64DivU: OpcodeI64DivUName,
+ OpcodeI64RemS: OpcodeI64RemSName,
+ OpcodeI64RemU: OpcodeI64RemUName,
+ OpcodeI64And: OpcodeI64AndName,
+ OpcodeI64Or: OpcodeI64OrName,
+ OpcodeI64Xor: OpcodeI64XorName,
+ OpcodeI64Shl: OpcodeI64ShlName,
+ OpcodeI64ShrS: OpcodeI64ShrSName,
+ OpcodeI64ShrU: OpcodeI64ShrUName,
+ OpcodeI64Rotl: OpcodeI64RotlName,
+ OpcodeI64Rotr: OpcodeI64RotrName,
+ OpcodeF32Abs: OpcodeF32AbsName,
+ OpcodeF32Neg: OpcodeF32NegName,
+ OpcodeF32Ceil: OpcodeF32CeilName,
+ OpcodeF32Floor: OpcodeF32FloorName,
+ OpcodeF32Trunc: OpcodeF32TruncName,
+ OpcodeF32Nearest: OpcodeF32NearestName,
+ OpcodeF32Sqrt: OpcodeF32SqrtName,
+ OpcodeF32Add: OpcodeF32AddName,
+ OpcodeF32Sub: OpcodeF32SubName,
+ OpcodeF32Mul: OpcodeF32MulName,
+ OpcodeF32Div: OpcodeF32DivName,
+ OpcodeF32Min: OpcodeF32MinName,
+ OpcodeF32Max: OpcodeF32MaxName,
+ OpcodeF32Copysign: OpcodeF32CopysignName,
+ OpcodeF64Abs: OpcodeF64AbsName,
+ OpcodeF64Neg: OpcodeF64NegName,
+ OpcodeF64Ceil: OpcodeF64CeilName,
+ OpcodeF64Floor: OpcodeF64FloorName,
+ OpcodeF64Trunc: OpcodeF64TruncName,
+ OpcodeF64Nearest: OpcodeF64NearestName,
+ OpcodeF64Sqrt: OpcodeF64SqrtName,
+ OpcodeF64Add: OpcodeF64AddName,
+ OpcodeF64Sub: OpcodeF64SubName,
+ OpcodeF64Mul: OpcodeF64MulName,
+ OpcodeF64Div: OpcodeF64DivName,
+ OpcodeF64Min: OpcodeF64MinName,
+ OpcodeF64Max: OpcodeF64MaxName,
+ OpcodeF64Copysign: OpcodeF64CopysignName,
+ OpcodeI32WrapI64: OpcodeI32WrapI64Name,
+ OpcodeI32TruncF32S: OpcodeI32TruncF32SName,
+ OpcodeI32TruncF32U: OpcodeI32TruncF32UName,
+ OpcodeI32TruncF64S: OpcodeI32TruncF64SName,
+ OpcodeI32TruncF64U: OpcodeI32TruncF64UName,
+ OpcodeI64ExtendI32S: OpcodeI64ExtendI32SName,
+ OpcodeI64ExtendI32U: OpcodeI64ExtendI32UName,
+ OpcodeI64TruncF32S: OpcodeI64TruncF32SName,
+ OpcodeI64TruncF32U: OpcodeI64TruncF32UName,
+ OpcodeI64TruncF64S: OpcodeI64TruncF64SName,
+ OpcodeI64TruncF64U: OpcodeI64TruncF64UName,
+ OpcodeF32ConvertI32S: OpcodeF32ConvertI32SName,
+ OpcodeF32ConvertI32U: OpcodeF32ConvertI32UName,
+ OpcodeF32ConvertI64S: OpcodeF32ConvertI64SName,
+ OpcodeF32ConvertI64U: OpcodeF32ConvertI64UName,
+ OpcodeF32DemoteF64: OpcodeF32DemoteF64Name,
+ OpcodeF64ConvertI32S: OpcodeF64ConvertI32SName,
+ OpcodeF64ConvertI32U: OpcodeF64ConvertI32UName,
+ OpcodeF64ConvertI64S: OpcodeF64ConvertI64SName,
+ OpcodeF64ConvertI64U: OpcodeF64ConvertI64UName,
+ OpcodeF64PromoteF32: OpcodeF64PromoteF32Name,
+ OpcodeI32ReinterpretF32: OpcodeI32ReinterpretF32Name,
+ OpcodeI64ReinterpretF64: OpcodeI64ReinterpretF64Name,
+ OpcodeF32ReinterpretI32: OpcodeF32ReinterpretI32Name,
+ OpcodeF64ReinterpretI64: OpcodeF64ReinterpretI64Name,
+
+ OpcodeRefNull: OpcodeRefNullName,
+ OpcodeRefIsNull: OpcodeRefIsNullName,
+ OpcodeRefFunc: OpcodeRefFuncName,
+
+ OpcodeTableGet: OpcodeTableGetName,
+ OpcodeTableSet: OpcodeTableSetName,
+
+ // Below are toggled with CoreFeatureSignExtensionOps
+
+ OpcodeI32Extend8S: OpcodeI32Extend8SName,
+ OpcodeI32Extend16S: OpcodeI32Extend16SName,
+ OpcodeI64Extend8S: OpcodeI64Extend8SName,
+ OpcodeI64Extend16S: OpcodeI64Extend16SName,
+ OpcodeI64Extend32S: OpcodeI64Extend32SName,
+
+ OpcodeMiscPrefix: OpcodeMiscPrefixName,
+ OpcodeVecPrefix: OpcodeVecPrefixName,
+}
+
+// InstructionName returns the instruction corresponding to this binary Opcode.
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#a7-index-of-instructions
+func InstructionName(oc Opcode) string {
+ return instructionNames[oc]
+}
+
+const (
+ OpcodeI32TruncSatF32SName = "i32.trunc_sat_f32_s"
+ OpcodeI32TruncSatF32UName = "i32.trunc_sat_f32_u"
+ OpcodeI32TruncSatF64SName = "i32.trunc_sat_f64_s"
+ OpcodeI32TruncSatF64UName = "i32.trunc_sat_f64_u"
+ OpcodeI64TruncSatF32SName = "i64.trunc_sat_f32_s"
+ OpcodeI64TruncSatF32UName = "i64.trunc_sat_f32_u"
+ OpcodeI64TruncSatF64SName = "i64.trunc_sat_f64_s"
+ OpcodeI64TruncSatF64UName = "i64.trunc_sat_f64_u"
+
+ OpcodeMemoryInitName = "memory.init"
+ OpcodeDataDropName = "data.drop"
+ OpcodeMemoryCopyName = "memory.copy"
+ OpcodeMemoryFillName = "memory.fill"
+ OpcodeTableInitName = "table.init"
+ OpcodeElemDropName = "elem.drop"
+ OpcodeTableCopyName = "table.copy"
+ OpcodeTableGrowName = "table.grow"
+ OpcodeTableSizeName = "table.size"
+ OpcodeTableFillName = "table.fill"
+)
+
+var miscInstructionNames = [256]string{
+ OpcodeMiscI32TruncSatF32S: OpcodeI32TruncSatF32SName,
+ OpcodeMiscI32TruncSatF32U: OpcodeI32TruncSatF32UName,
+ OpcodeMiscI32TruncSatF64S: OpcodeI32TruncSatF64SName,
+ OpcodeMiscI32TruncSatF64U: OpcodeI32TruncSatF64UName,
+ OpcodeMiscI64TruncSatF32S: OpcodeI64TruncSatF32SName,
+ OpcodeMiscI64TruncSatF32U: OpcodeI64TruncSatF32UName,
+ OpcodeMiscI64TruncSatF64S: OpcodeI64TruncSatF64SName,
+ OpcodeMiscI64TruncSatF64U: OpcodeI64TruncSatF64UName,
+
+ OpcodeMiscMemoryInit: OpcodeMemoryInitName,
+ OpcodeMiscDataDrop: OpcodeDataDropName,
+ OpcodeMiscMemoryCopy: OpcodeMemoryCopyName,
+ OpcodeMiscMemoryFill: OpcodeMemoryFillName,
+ OpcodeMiscTableInit: OpcodeTableInitName,
+ OpcodeMiscElemDrop: OpcodeElemDropName,
+ OpcodeMiscTableCopy: OpcodeTableCopyName,
+ OpcodeMiscTableGrow: OpcodeTableGrowName,
+ OpcodeMiscTableSize: OpcodeTableSizeName,
+ OpcodeMiscTableFill: OpcodeTableFillName,
+}
+
+// MiscInstructionName returns the instruction corresponding to this miscellaneous Opcode.
+func MiscInstructionName(oc OpcodeMisc) string {
+ return miscInstructionNames[oc]
+}
+
+const (
+ OpcodeVecV128LoadName = "v128.load"
+ OpcodeVecV128Load8x8SName = "v128.load8x8_s"
+ OpcodeVecV128Load8x8UName = "v128.load8x8_u"
+ OpcodeVecV128Load16x4SName = "v128.load16x4_s"
+ OpcodeVecV128Load16x4UName = "v128.load16x4_u"
+ OpcodeVecV128Load32x2SName = "v128.load32x2_s"
+ OpcodeVecV128Load32x2UName = "v128.load32x2_u"
+ OpcodeVecV128Load8SplatName = "v128.load8_splat"
+ OpcodeVecV128Load16SplatName = "v128.load16_splat"
+ OpcodeVecV128Load32SplatName = "v128.load32_splat"
+ OpcodeVecV128Load64SplatName = "v128.load64_splat"
+ OpcodeVecV128Load32zeroName = "v128.load32_zero"
+ OpcodeVecV128Load64zeroName = "v128.load64_zero"
+ OpcodeVecV128StoreName = "v128.store"
+ OpcodeVecV128Load8LaneName = "v128.load8_lane"
+ OpcodeVecV128Load16LaneName = "v128.load16_lane"
+ OpcodeVecV128Load32LaneName = "v128.load32_lane"
+ OpcodeVecV128Load64LaneName = "v128.load64_lane"
+ OpcodeVecV128Store8LaneName = "v128.store8_lane"
+ OpcodeVecV128Store16LaneName = "v128.store16_lane"
+ OpcodeVecV128Store32LaneName = "v128.store32_lane"
+ OpcodeVecV128Store64LaneName = "v128.store64_lane"
+ OpcodeVecV128ConstName = "v128.const"
+ OpcodeVecV128i8x16ShuffleName = "v128.shuffle"
+ OpcodeVecI8x16ExtractLaneSName = "i8x16.extract_lane_s"
+ OpcodeVecI8x16ExtractLaneUName = "i8x16.extract_lane_u"
+ OpcodeVecI8x16ReplaceLaneName = "i8x16.replace_lane"
+ OpcodeVecI16x8ExtractLaneSName = "i16x8.extract_lane_s"
+ OpcodeVecI16x8ExtractLaneUName = "i16x8.extract_lane_u"
+ OpcodeVecI16x8ReplaceLaneName = "i16x8.replace_lane"
+ OpcodeVecI32x4ExtractLaneName = "i32x4.extract_lane"
+ OpcodeVecI32x4ReplaceLaneName = "i32x4.replace_lane"
+ OpcodeVecI64x2ExtractLaneName = "i64x2.extract_lane"
+ OpcodeVecI64x2ReplaceLaneName = "i64x2.replace_lane"
+ OpcodeVecF32x4ExtractLaneName = "f32x4.extract_lane"
+ OpcodeVecF32x4ReplaceLaneName = "f32x4.replace_lane"
+ OpcodeVecF64x2ExtractLaneName = "f64x2.extract_lane"
+ OpcodeVecF64x2ReplaceLaneName = "f64x2.replace_lane"
+ OpcodeVecI8x16SwizzleName = "i8x16.swizzle"
+ OpcodeVecI8x16SplatName = "i8x16.splat"
+ OpcodeVecI16x8SplatName = "i16x8.splat"
+ OpcodeVecI32x4SplatName = "i32x4.splat"
+ OpcodeVecI64x2SplatName = "i64x2.splat"
+ OpcodeVecF32x4SplatName = "f32x4.splat"
+ OpcodeVecF64x2SplatName = "f64x2.splat"
+ OpcodeVecI8x16EqName = "i8x16.eq"
+ OpcodeVecI8x16NeName = "i8x16.ne"
+ OpcodeVecI8x16LtSName = "i8x16.lt_s"
+ OpcodeVecI8x16LtUName = "i8x16.lt_u"
+ OpcodeVecI8x16GtSName = "i8x16.gt_s"
+ OpcodeVecI8x16GtUName = "i8x16.gt_u"
+ OpcodeVecI8x16LeSName = "i8x16.le_s"
+ OpcodeVecI8x16LeUName = "i8x16.le_u"
+ OpcodeVecI8x16GeSName = "i8x16.ge_s"
+ OpcodeVecI8x16GeUName = "i8x16.ge_u"
+ OpcodeVecI16x8EqName = "i16x8.eq"
+ OpcodeVecI16x8NeName = "i16x8.ne"
+ OpcodeVecI16x8LtSName = "i16x8.lt_s"
+ OpcodeVecI16x8LtUName = "i16x8.lt_u"
+ OpcodeVecI16x8GtSName = "i16x8.gt_s"
+ OpcodeVecI16x8GtUName = "i16x8.gt_u"
+ OpcodeVecI16x8LeSName = "i16x8.le_s"
+ OpcodeVecI16x8LeUName = "i16x8.le_u"
+ OpcodeVecI16x8GeSName = "i16x8.ge_s"
+ OpcodeVecI16x8GeUName = "i16x8.ge_u"
+ OpcodeVecI32x4EqName = "i32x4.eq"
+ OpcodeVecI32x4NeName = "i32x4.ne"
+ OpcodeVecI32x4LtSName = "i32x4.lt_s"
+ OpcodeVecI32x4LtUName = "i32x4.lt_u"
+ OpcodeVecI32x4GtSName = "i32x4.gt_s"
+ OpcodeVecI32x4GtUName = "i32x4.gt_u"
+ OpcodeVecI32x4LeSName = "i32x4.le_s"
+ OpcodeVecI32x4LeUName = "i32x4.le_u"
+ OpcodeVecI32x4GeSName = "i32x4.ge_s"
+ OpcodeVecI32x4GeUName = "i32x4.ge_u"
+ OpcodeVecI64x2EqName = "i64x2.eq"
+ OpcodeVecI64x2NeName = "i64x2.ne"
+ OpcodeVecI64x2LtSName = "i64x2.lt"
+ OpcodeVecI64x2GtSName = "i64x2.gt"
+ OpcodeVecI64x2LeSName = "i64x2.le"
+ OpcodeVecI64x2GeSName = "i64x2.ge"
+ OpcodeVecF32x4EqName = "f32x4.eq"
+ OpcodeVecF32x4NeName = "f32x4.ne"
+ OpcodeVecF32x4LtName = "f32x4.lt"
+ OpcodeVecF32x4GtName = "f32x4.gt"
+ OpcodeVecF32x4LeName = "f32x4.le"
+ OpcodeVecF32x4GeName = "f32x4.ge"
+ OpcodeVecF64x2EqName = "f64x2.eq"
+ OpcodeVecF64x2NeName = "f64x2.ne"
+ OpcodeVecF64x2LtName = "f64x2.lt"
+ OpcodeVecF64x2GtName = "f64x2.gt"
+ OpcodeVecF64x2LeName = "f64x2.le"
+ OpcodeVecF64x2GeName = "f64x2.ge"
+ OpcodeVecV128NotName = "v128.not"
+ OpcodeVecV128AndName = "v128.and"
+ OpcodeVecV128AndNotName = "v128.andnot"
+ OpcodeVecV128OrName = "v128.or"
+ OpcodeVecV128XorName = "v128.xor"
+ OpcodeVecV128BitselectName = "v128.bitselect"
+ OpcodeVecV128AnyTrueName = "v128.any_true"
+ OpcodeVecI8x16AbsName = "i8x16.abs"
+ OpcodeVecI8x16NegName = "i8x16.neg"
+ OpcodeVecI8x16PopcntName = "i8x16.popcnt"
+ OpcodeVecI8x16AllTrueName = "i8x16.all_true"
+ OpcodeVecI8x16BitMaskName = "i8x16.bitmask"
+ OpcodeVecI8x16NarrowI16x8SName = "i8x16.narrow_i16x8_s"
+ OpcodeVecI8x16NarrowI16x8UName = "i8x16.narrow_i16x8_u"
+ OpcodeVecI8x16ShlName = "i8x16.shl"
+ OpcodeVecI8x16ShrSName = "i8x16.shr_s"
+ OpcodeVecI8x16ShrUName = "i8x16.shr_u"
+ OpcodeVecI8x16AddName = "i8x16.add"
+ OpcodeVecI8x16AddSatSName = "i8x16.add_sat_s"
+ OpcodeVecI8x16AddSatUName = "i8x16.add_sat_u"
+ OpcodeVecI8x16SubName = "i8x16.sub"
+ OpcodeVecI8x16SubSatSName = "i8x16.sub_s"
+ OpcodeVecI8x16SubSatUName = "i8x16.sub_u"
+ OpcodeVecI8x16MinSName = "i8x16.min_s"
+ OpcodeVecI8x16MinUName = "i8x16.min_u"
+ OpcodeVecI8x16MaxSName = "i8x16.max_s"
+ OpcodeVecI8x16MaxUName = "i8x16.max_u"
+ OpcodeVecI8x16AvgrUName = "i8x16.avgr_u"
+ OpcodeVecI16x8ExtaddPairwiseI8x16SName = "i16x8.extadd_pairwise_i8x16_s"
+ OpcodeVecI16x8ExtaddPairwiseI8x16UName = "i16x8.extadd_pairwise_i8x16_u"
+ OpcodeVecI16x8AbsName = "i16x8.abs"
+ OpcodeVecI16x8NegName = "i16x8.neg"
+ OpcodeVecI16x8Q15mulrSatSName = "i16x8.q15mulr_sat_s"
+ OpcodeVecI16x8AllTrueName = "i16x8.all_true"
+ OpcodeVecI16x8BitMaskName = "i16x8.bitmask"
+ OpcodeVecI16x8NarrowI32x4SName = "i16x8.narrow_i32x4_s"
+ OpcodeVecI16x8NarrowI32x4UName = "i16x8.narrow_i32x4_u"
+ OpcodeVecI16x8ExtendLowI8x16SName = "i16x8.extend_low_i8x16_s"
+ OpcodeVecI16x8ExtendHighI8x16SName = "i16x8.extend_high_i8x16_s"
+ OpcodeVecI16x8ExtendLowI8x16UName = "i16x8.extend_low_i8x16_u"
+ OpcodeVecI16x8ExtendHighI8x16UName = "i16x8.extend_high_i8x16_u"
+ OpcodeVecI16x8ShlName = "i16x8.shl"
+ OpcodeVecI16x8ShrSName = "i16x8.shr_s"
+ OpcodeVecI16x8ShrUName = "i16x8.shr_u"
+ OpcodeVecI16x8AddName = "i16x8.add"
+ OpcodeVecI16x8AddSatSName = "i16x8.add_sat_s"
+ OpcodeVecI16x8AddSatUName = "i16x8.add_sat_u"
+ OpcodeVecI16x8SubName = "i16x8.sub"
+ OpcodeVecI16x8SubSatSName = "i16x8.sub_sat_s"
+ OpcodeVecI16x8SubSatUName = "i16x8.sub_sat_u"
+ OpcodeVecI16x8MulName = "i16x8.mul"
+ OpcodeVecI16x8MinSName = "i16x8.min_s"
+ OpcodeVecI16x8MinUName = "i16x8.min_u"
+ OpcodeVecI16x8MaxSName = "i16x8.max_s"
+ OpcodeVecI16x8MaxUName = "i16x8.max_u"
+ OpcodeVecI16x8AvgrUName = "i16x8.avgr_u"
+ OpcodeVecI16x8ExtMulLowI8x16SName = "i16x8.extmul_low_i8x16_s"
+ OpcodeVecI16x8ExtMulHighI8x16SName = "i16x8.extmul_high_i8x16_s"
+ OpcodeVecI16x8ExtMulLowI8x16UName = "i16x8.extmul_low_i8x16_u"
+ OpcodeVecI16x8ExtMulHighI8x16UName = "i16x8.extmul_high_i8x16_u"
+ OpcodeVecI32x4ExtaddPairwiseI16x8SName = "i32x4.extadd_pairwise_i16x8_s"
+ OpcodeVecI32x4ExtaddPairwiseI16x8UName = "i32x4.extadd_pairwise_i16x8_u"
+ OpcodeVecI32x4AbsName = "i32x4.abs"
+ OpcodeVecI32x4NegName = "i32x4.neg"
+ OpcodeVecI32x4AllTrueName = "i32x4.all_true"
+ OpcodeVecI32x4BitMaskName = "i32x4.bitmask"
+ OpcodeVecI32x4ExtendLowI16x8SName = "i32x4.extend_low_i16x8_s"
+ OpcodeVecI32x4ExtendHighI16x8SName = "i32x4.extend_high_i16x8_s"
+ OpcodeVecI32x4ExtendLowI16x8UName = "i32x4.extend_low_i16x8_u"
+ OpcodeVecI32x4ExtendHighI16x8UName = "i32x4.extend_high_i16x8_u"
+ OpcodeVecI32x4ShlName = "i32x4.shl"
+ OpcodeVecI32x4ShrSName = "i32x4.shr_s"
+ OpcodeVecI32x4ShrUName = "i32x4.shr_u"
+ OpcodeVecI32x4AddName = "i32x4.add"
+ OpcodeVecI32x4SubName = "i32x4.sub"
+ OpcodeVecI32x4MulName = "i32x4.mul"
+ OpcodeVecI32x4MinSName = "i32x4.min_s"
+ OpcodeVecI32x4MinUName = "i32x4.min_u"
+ OpcodeVecI32x4MaxSName = "i32x4.max_s"
+ OpcodeVecI32x4MaxUName = "i32x4.max_u"
+ OpcodeVecI32x4DotI16x8SName = "i32x4.dot_i16x8_s"
+ OpcodeVecI32x4ExtMulLowI16x8SName = "i32x4.extmul_low_i16x8_s"
+ OpcodeVecI32x4ExtMulHighI16x8SName = "i32x4.extmul_high_i16x8_s"
+ OpcodeVecI32x4ExtMulLowI16x8UName = "i32x4.extmul_low_i16x8_u"
+ OpcodeVecI32x4ExtMulHighI16x8UName = "i32x4.extmul_high_i16x8_u"
+ OpcodeVecI64x2AbsName = "i64x2.abs"
+ OpcodeVecI64x2NegName = "i64x2.neg"
+ OpcodeVecI64x2AllTrueName = "i64x2.all_true"
+ OpcodeVecI64x2BitMaskName = "i64x2.bitmask"
+ OpcodeVecI64x2ExtendLowI32x4SName = "i64x2.extend_low_i32x4_s"
+ OpcodeVecI64x2ExtendHighI32x4SName = "i64x2.extend_high_i32x4_s"
+ OpcodeVecI64x2ExtendLowI32x4UName = "i64x2.extend_low_i32x4_u"
+ OpcodeVecI64x2ExtendHighI32x4UName = "i64x2.extend_high_i32x4_u"
+ OpcodeVecI64x2ShlName = "i64x2.shl"
+ OpcodeVecI64x2ShrSName = "i64x2.shr_s"
+ OpcodeVecI64x2ShrUName = "i64x2.shr_u"
+ OpcodeVecI64x2AddName = "i64x2.add"
+ OpcodeVecI64x2SubName = "i64x2.sub"
+ OpcodeVecI64x2MulName = "i64x2.mul"
+ OpcodeVecI64x2ExtMulLowI32x4SName = "i64x2.extmul_low_i32x4_s"
+ OpcodeVecI64x2ExtMulHighI32x4SName = "i64x2.extmul_high_i32x4_s"
+ OpcodeVecI64x2ExtMulLowI32x4UName = "i64x2.extmul_low_i32x4_u"
+ OpcodeVecI64x2ExtMulHighI32x4UName = "i64x2.extmul_high_i32x4_u"
+ OpcodeVecF32x4CeilName = "f32x4.ceil"
+ OpcodeVecF32x4FloorName = "f32x4.floor"
+ OpcodeVecF32x4TruncName = "f32x4.trunc"
+ OpcodeVecF32x4NearestName = "f32x4.nearest"
+ OpcodeVecF32x4AbsName = "f32x4.abs"
+ OpcodeVecF32x4NegName = "f32x4.neg"
+ OpcodeVecF32x4SqrtName = "f32x4.sqrt"
+ OpcodeVecF32x4AddName = "f32x4.add"
+ OpcodeVecF32x4SubName = "f32x4.sub"
+ OpcodeVecF32x4MulName = "f32x4.mul"
+ OpcodeVecF32x4DivName = "f32x4.div"
+ OpcodeVecF32x4MinName = "f32x4.min"
+ OpcodeVecF32x4MaxName = "f32x4.max"
+ OpcodeVecF32x4PminName = "f32x4.pmin"
+ OpcodeVecF32x4PmaxName = "f32x4.pmax"
+ OpcodeVecF64x2CeilName = "f64x2.ceil"
+ OpcodeVecF64x2FloorName = "f64x2.floor"
+ OpcodeVecF64x2TruncName = "f64x2.trunc"
+ OpcodeVecF64x2NearestName = "f64x2.nearest"
+ OpcodeVecF64x2AbsName = "f64x2.abs"
+ OpcodeVecF64x2NegName = "f64x2.neg"
+ OpcodeVecF64x2SqrtName = "f64x2.sqrt"
+ OpcodeVecF64x2AddName = "f64x2.add"
+ OpcodeVecF64x2SubName = "f64x2.sub"
+ OpcodeVecF64x2MulName = "f64x2.mul"
+ OpcodeVecF64x2DivName = "f64x2.div"
+ OpcodeVecF64x2MinName = "f64x2.min"
+ OpcodeVecF64x2MaxName = "f64x2.max"
+ OpcodeVecF64x2PminName = "f64x2.pmin"
+ OpcodeVecF64x2PmaxName = "f64x2.pmax"
+ OpcodeVecI32x4TruncSatF32x4SName = "i32x4.trunc_sat_f32x4_s"
+ OpcodeVecI32x4TruncSatF32x4UName = "i32x4.trunc_sat_f32x4_u"
+ OpcodeVecF32x4ConvertI32x4SName = "f32x4.convert_i32x4_s"
+ OpcodeVecF32x4ConvertI32x4UName = "f32x4.convert_i32x4_u"
+ OpcodeVecI32x4TruncSatF64x2SZeroName = "i32x4.trunc_sat_f64x2_s_zero"
+ OpcodeVecI32x4TruncSatF64x2UZeroName = "i32x4.trunc_sat_f64x2_u_zero"
+ OpcodeVecF64x2ConvertLowI32x4SName = "f64x2.convert_low_i32x4_s"
+ OpcodeVecF64x2ConvertLowI32x4UName = "f64x2.convert_low_i32x4_u"
+ OpcodeVecF32x4DemoteF64x2ZeroName = "f32x4.demote_f64x2_zero"
+ OpcodeVecF64x2PromoteLowF32x4ZeroName = "f64x2.promote_low_f32x4"
+)
+
+var vectorInstructionName = map[OpcodeVec]string{
+ OpcodeVecV128Load: OpcodeVecV128LoadName,
+ OpcodeVecV128Load8x8s: OpcodeVecV128Load8x8SName,
+ OpcodeVecV128Load8x8u: OpcodeVecV128Load8x8UName,
+ OpcodeVecV128Load16x4s: OpcodeVecV128Load16x4SName,
+ OpcodeVecV128Load16x4u: OpcodeVecV128Load16x4UName,
+ OpcodeVecV128Load32x2s: OpcodeVecV128Load32x2SName,
+ OpcodeVecV128Load32x2u: OpcodeVecV128Load32x2UName,
+ OpcodeVecV128Load8Splat: OpcodeVecV128Load8SplatName,
+ OpcodeVecV128Load16Splat: OpcodeVecV128Load16SplatName,
+ OpcodeVecV128Load32Splat: OpcodeVecV128Load32SplatName,
+ OpcodeVecV128Load64Splat: OpcodeVecV128Load64SplatName,
+ OpcodeVecV128Load32zero: OpcodeVecV128Load32zeroName,
+ OpcodeVecV128Load64zero: OpcodeVecV128Load64zeroName,
+ OpcodeVecV128Store: OpcodeVecV128StoreName,
+ OpcodeVecV128Load8Lane: OpcodeVecV128Load8LaneName,
+ OpcodeVecV128Load16Lane: OpcodeVecV128Load16LaneName,
+ OpcodeVecV128Load32Lane: OpcodeVecV128Load32LaneName,
+ OpcodeVecV128Load64Lane: OpcodeVecV128Load64LaneName,
+ OpcodeVecV128Store8Lane: OpcodeVecV128Store8LaneName,
+ OpcodeVecV128Store16Lane: OpcodeVecV128Store16LaneName,
+ OpcodeVecV128Store32Lane: OpcodeVecV128Store32LaneName,
+ OpcodeVecV128Store64Lane: OpcodeVecV128Store64LaneName,
+ OpcodeVecV128Const: OpcodeVecV128ConstName,
+ OpcodeVecV128i8x16Shuffle: OpcodeVecV128i8x16ShuffleName,
+ OpcodeVecI8x16ExtractLaneS: OpcodeVecI8x16ExtractLaneSName,
+ OpcodeVecI8x16ExtractLaneU: OpcodeVecI8x16ExtractLaneUName,
+ OpcodeVecI8x16ReplaceLane: OpcodeVecI8x16ReplaceLaneName,
+ OpcodeVecI16x8ExtractLaneS: OpcodeVecI16x8ExtractLaneSName,
+ OpcodeVecI16x8ExtractLaneU: OpcodeVecI16x8ExtractLaneUName,
+ OpcodeVecI16x8ReplaceLane: OpcodeVecI16x8ReplaceLaneName,
+ OpcodeVecI32x4ExtractLane: OpcodeVecI32x4ExtractLaneName,
+ OpcodeVecI32x4ReplaceLane: OpcodeVecI32x4ReplaceLaneName,
+ OpcodeVecI64x2ExtractLane: OpcodeVecI64x2ExtractLaneName,
+ OpcodeVecI64x2ReplaceLane: OpcodeVecI64x2ReplaceLaneName,
+ OpcodeVecF32x4ExtractLane: OpcodeVecF32x4ExtractLaneName,
+ OpcodeVecF32x4ReplaceLane: OpcodeVecF32x4ReplaceLaneName,
+ OpcodeVecF64x2ExtractLane: OpcodeVecF64x2ExtractLaneName,
+ OpcodeVecF64x2ReplaceLane: OpcodeVecF64x2ReplaceLaneName,
+ OpcodeVecI8x16Swizzle: OpcodeVecI8x16SwizzleName,
+ OpcodeVecI8x16Splat: OpcodeVecI8x16SplatName,
+ OpcodeVecI16x8Splat: OpcodeVecI16x8SplatName,
+ OpcodeVecI32x4Splat: OpcodeVecI32x4SplatName,
+ OpcodeVecI64x2Splat: OpcodeVecI64x2SplatName,
+ OpcodeVecF32x4Splat: OpcodeVecF32x4SplatName,
+ OpcodeVecF64x2Splat: OpcodeVecF64x2SplatName,
+ OpcodeVecI8x16Eq: OpcodeVecI8x16EqName,
+ OpcodeVecI8x16Ne: OpcodeVecI8x16NeName,
+ OpcodeVecI8x16LtS: OpcodeVecI8x16LtSName,
+ OpcodeVecI8x16LtU: OpcodeVecI8x16LtUName,
+ OpcodeVecI8x16GtS: OpcodeVecI8x16GtSName,
+ OpcodeVecI8x16GtU: OpcodeVecI8x16GtUName,
+ OpcodeVecI8x16LeS: OpcodeVecI8x16LeSName,
+ OpcodeVecI8x16LeU: OpcodeVecI8x16LeUName,
+ OpcodeVecI8x16GeS: OpcodeVecI8x16GeSName,
+ OpcodeVecI8x16GeU: OpcodeVecI8x16GeUName,
+ OpcodeVecI16x8Eq: OpcodeVecI16x8EqName,
+ OpcodeVecI16x8Ne: OpcodeVecI16x8NeName,
+ OpcodeVecI16x8LtS: OpcodeVecI16x8LtSName,
+ OpcodeVecI16x8LtU: OpcodeVecI16x8LtUName,
+ OpcodeVecI16x8GtS: OpcodeVecI16x8GtSName,
+ OpcodeVecI16x8GtU: OpcodeVecI16x8GtUName,
+ OpcodeVecI16x8LeS: OpcodeVecI16x8LeSName,
+ OpcodeVecI16x8LeU: OpcodeVecI16x8LeUName,
+ OpcodeVecI16x8GeS: OpcodeVecI16x8GeSName,
+ OpcodeVecI16x8GeU: OpcodeVecI16x8GeUName,
+ OpcodeVecI32x4Eq: OpcodeVecI32x4EqName,
+ OpcodeVecI32x4Ne: OpcodeVecI32x4NeName,
+ OpcodeVecI32x4LtS: OpcodeVecI32x4LtSName,
+ OpcodeVecI32x4LtU: OpcodeVecI32x4LtUName,
+ OpcodeVecI32x4GtS: OpcodeVecI32x4GtSName,
+ OpcodeVecI32x4GtU: OpcodeVecI32x4GtUName,
+ OpcodeVecI32x4LeS: OpcodeVecI32x4LeSName,
+ OpcodeVecI32x4LeU: OpcodeVecI32x4LeUName,
+ OpcodeVecI32x4GeS: OpcodeVecI32x4GeSName,
+ OpcodeVecI32x4GeU: OpcodeVecI32x4GeUName,
+ OpcodeVecI64x2Eq: OpcodeVecI64x2EqName,
+ OpcodeVecI64x2Ne: OpcodeVecI64x2NeName,
+ OpcodeVecI64x2LtS: OpcodeVecI64x2LtSName,
+ OpcodeVecI64x2GtS: OpcodeVecI64x2GtSName,
+ OpcodeVecI64x2LeS: OpcodeVecI64x2LeSName,
+ OpcodeVecI64x2GeS: OpcodeVecI64x2GeSName,
+ OpcodeVecF32x4Eq: OpcodeVecF32x4EqName,
+ OpcodeVecF32x4Ne: OpcodeVecF32x4NeName,
+ OpcodeVecF32x4Lt: OpcodeVecF32x4LtName,
+ OpcodeVecF32x4Gt: OpcodeVecF32x4GtName,
+ OpcodeVecF32x4Le: OpcodeVecF32x4LeName,
+ OpcodeVecF32x4Ge: OpcodeVecF32x4GeName,
+ OpcodeVecF64x2Eq: OpcodeVecF64x2EqName,
+ OpcodeVecF64x2Ne: OpcodeVecF64x2NeName,
+ OpcodeVecF64x2Lt: OpcodeVecF64x2LtName,
+ OpcodeVecF64x2Gt: OpcodeVecF64x2GtName,
+ OpcodeVecF64x2Le: OpcodeVecF64x2LeName,
+ OpcodeVecF64x2Ge: OpcodeVecF64x2GeName,
+ OpcodeVecV128Not: OpcodeVecV128NotName,
+ OpcodeVecV128And: OpcodeVecV128AndName,
+ OpcodeVecV128AndNot: OpcodeVecV128AndNotName,
+ OpcodeVecV128Or: OpcodeVecV128OrName,
+ OpcodeVecV128Xor: OpcodeVecV128XorName,
+ OpcodeVecV128Bitselect: OpcodeVecV128BitselectName,
+ OpcodeVecV128AnyTrue: OpcodeVecV128AnyTrueName,
+ OpcodeVecI8x16Abs: OpcodeVecI8x16AbsName,
+ OpcodeVecI8x16Neg: OpcodeVecI8x16NegName,
+ OpcodeVecI8x16Popcnt: OpcodeVecI8x16PopcntName,
+ OpcodeVecI8x16AllTrue: OpcodeVecI8x16AllTrueName,
+ OpcodeVecI8x16BitMask: OpcodeVecI8x16BitMaskName,
+ OpcodeVecI8x16NarrowI16x8S: OpcodeVecI8x16NarrowI16x8SName,
+ OpcodeVecI8x16NarrowI16x8U: OpcodeVecI8x16NarrowI16x8UName,
+ OpcodeVecI8x16Shl: OpcodeVecI8x16ShlName,
+ OpcodeVecI8x16ShrS: OpcodeVecI8x16ShrSName,
+ OpcodeVecI8x16ShrU: OpcodeVecI8x16ShrUName,
+ OpcodeVecI8x16Add: OpcodeVecI8x16AddName,
+ OpcodeVecI8x16AddSatS: OpcodeVecI8x16AddSatSName,
+ OpcodeVecI8x16AddSatU: OpcodeVecI8x16AddSatUName,
+ OpcodeVecI8x16Sub: OpcodeVecI8x16SubName,
+ OpcodeVecI8x16SubSatS: OpcodeVecI8x16SubSatSName,
+ OpcodeVecI8x16SubSatU: OpcodeVecI8x16SubSatUName,
+ OpcodeVecI8x16MinS: OpcodeVecI8x16MinSName,
+ OpcodeVecI8x16MinU: OpcodeVecI8x16MinUName,
+ OpcodeVecI8x16MaxS: OpcodeVecI8x16MaxSName,
+ OpcodeVecI8x16MaxU: OpcodeVecI8x16MaxUName,
+ OpcodeVecI8x16AvgrU: OpcodeVecI8x16AvgrUName,
+ OpcodeVecI16x8ExtaddPairwiseI8x16S: OpcodeVecI16x8ExtaddPairwiseI8x16SName,
+ OpcodeVecI16x8ExtaddPairwiseI8x16U: OpcodeVecI16x8ExtaddPairwiseI8x16UName,
+ OpcodeVecI16x8Abs: OpcodeVecI16x8AbsName,
+ OpcodeVecI16x8Neg: OpcodeVecI16x8NegName,
+ OpcodeVecI16x8Q15mulrSatS: OpcodeVecI16x8Q15mulrSatSName,
+ OpcodeVecI16x8AllTrue: OpcodeVecI16x8AllTrueName,
+ OpcodeVecI16x8BitMask: OpcodeVecI16x8BitMaskName,
+ OpcodeVecI16x8NarrowI32x4S: OpcodeVecI16x8NarrowI32x4SName,
+ OpcodeVecI16x8NarrowI32x4U: OpcodeVecI16x8NarrowI32x4UName,
+ OpcodeVecI16x8ExtendLowI8x16S: OpcodeVecI16x8ExtendLowI8x16SName,
+ OpcodeVecI16x8ExtendHighI8x16S: OpcodeVecI16x8ExtendHighI8x16SName,
+ OpcodeVecI16x8ExtendLowI8x16U: OpcodeVecI16x8ExtendLowI8x16UName,
+ OpcodeVecI16x8ExtendHighI8x16U: OpcodeVecI16x8ExtendHighI8x16UName,
+ OpcodeVecI16x8Shl: OpcodeVecI16x8ShlName,
+ OpcodeVecI16x8ShrS: OpcodeVecI16x8ShrSName,
+ OpcodeVecI16x8ShrU: OpcodeVecI16x8ShrUName,
+ OpcodeVecI16x8Add: OpcodeVecI16x8AddName,
+ OpcodeVecI16x8AddSatS: OpcodeVecI16x8AddSatSName,
+ OpcodeVecI16x8AddSatU: OpcodeVecI16x8AddSatUName,
+ OpcodeVecI16x8Sub: OpcodeVecI16x8SubName,
+ OpcodeVecI16x8SubSatS: OpcodeVecI16x8SubSatSName,
+ OpcodeVecI16x8SubSatU: OpcodeVecI16x8SubSatUName,
+ OpcodeVecI16x8Mul: OpcodeVecI16x8MulName,
+ OpcodeVecI16x8MinS: OpcodeVecI16x8MinSName,
+ OpcodeVecI16x8MinU: OpcodeVecI16x8MinUName,
+ OpcodeVecI16x8MaxS: OpcodeVecI16x8MaxSName,
+ OpcodeVecI16x8MaxU: OpcodeVecI16x8MaxUName,
+ OpcodeVecI16x8AvgrU: OpcodeVecI16x8AvgrUName,
+ OpcodeVecI16x8ExtMulLowI8x16S: OpcodeVecI16x8ExtMulLowI8x16SName,
+ OpcodeVecI16x8ExtMulHighI8x16S: OpcodeVecI16x8ExtMulHighI8x16SName,
+ OpcodeVecI16x8ExtMulLowI8x16U: OpcodeVecI16x8ExtMulLowI8x16UName,
+ OpcodeVecI16x8ExtMulHighI8x16U: OpcodeVecI16x8ExtMulHighI8x16UName,
+ OpcodeVecI32x4ExtaddPairwiseI16x8S: OpcodeVecI32x4ExtaddPairwiseI16x8SName,
+ OpcodeVecI32x4ExtaddPairwiseI16x8U: OpcodeVecI32x4ExtaddPairwiseI16x8UName,
+ OpcodeVecI32x4Abs: OpcodeVecI32x4AbsName,
+ OpcodeVecI32x4Neg: OpcodeVecI32x4NegName,
+ OpcodeVecI32x4AllTrue: OpcodeVecI32x4AllTrueName,
+ OpcodeVecI32x4BitMask: OpcodeVecI32x4BitMaskName,
+ OpcodeVecI32x4ExtendLowI16x8S: OpcodeVecI32x4ExtendLowI16x8SName,
+ OpcodeVecI32x4ExtendHighI16x8S: OpcodeVecI32x4ExtendHighI16x8SName,
+ OpcodeVecI32x4ExtendLowI16x8U: OpcodeVecI32x4ExtendLowI16x8UName,
+ OpcodeVecI32x4ExtendHighI16x8U: OpcodeVecI32x4ExtendHighI16x8UName,
+ OpcodeVecI32x4Shl: OpcodeVecI32x4ShlName,
+ OpcodeVecI32x4ShrS: OpcodeVecI32x4ShrSName,
+ OpcodeVecI32x4ShrU: OpcodeVecI32x4ShrUName,
+ OpcodeVecI32x4Add: OpcodeVecI32x4AddName,
+ OpcodeVecI32x4Sub: OpcodeVecI32x4SubName,
+ OpcodeVecI32x4Mul: OpcodeVecI32x4MulName,
+ OpcodeVecI32x4MinS: OpcodeVecI32x4MinSName,
+ OpcodeVecI32x4MinU: OpcodeVecI32x4MinUName,
+ OpcodeVecI32x4MaxS: OpcodeVecI32x4MaxSName,
+ OpcodeVecI32x4MaxU: OpcodeVecI32x4MaxUName,
+ OpcodeVecI32x4DotI16x8S: OpcodeVecI32x4DotI16x8SName,
+ OpcodeVecI32x4ExtMulLowI16x8S: OpcodeVecI32x4ExtMulLowI16x8SName,
+ OpcodeVecI32x4ExtMulHighI16x8S: OpcodeVecI32x4ExtMulHighI16x8SName,
+ OpcodeVecI32x4ExtMulLowI16x8U: OpcodeVecI32x4ExtMulLowI16x8UName,
+ OpcodeVecI32x4ExtMulHighI16x8U: OpcodeVecI32x4ExtMulHighI16x8UName,
+ OpcodeVecI64x2Abs: OpcodeVecI64x2AbsName,
+ OpcodeVecI64x2Neg: OpcodeVecI64x2NegName,
+ OpcodeVecI64x2AllTrue: OpcodeVecI64x2AllTrueName,
+ OpcodeVecI64x2BitMask: OpcodeVecI64x2BitMaskName,
+ OpcodeVecI64x2ExtendLowI32x4S: OpcodeVecI64x2ExtendLowI32x4SName,
+ OpcodeVecI64x2ExtendHighI32x4S: OpcodeVecI64x2ExtendHighI32x4SName,
+ OpcodeVecI64x2ExtendLowI32x4U: OpcodeVecI64x2ExtendLowI32x4UName,
+ OpcodeVecI64x2ExtendHighI32x4U: OpcodeVecI64x2ExtendHighI32x4UName,
+ OpcodeVecI64x2Shl: OpcodeVecI64x2ShlName,
+ OpcodeVecI64x2ShrS: OpcodeVecI64x2ShrSName,
+ OpcodeVecI64x2ShrU: OpcodeVecI64x2ShrUName,
+ OpcodeVecI64x2Add: OpcodeVecI64x2AddName,
+ OpcodeVecI64x2Sub: OpcodeVecI64x2SubName,
+ OpcodeVecI64x2Mul: OpcodeVecI64x2MulName,
+ OpcodeVecI64x2ExtMulLowI32x4S: OpcodeVecI64x2ExtMulLowI32x4SName,
+ OpcodeVecI64x2ExtMulHighI32x4S: OpcodeVecI64x2ExtMulHighI32x4SName,
+ OpcodeVecI64x2ExtMulLowI32x4U: OpcodeVecI64x2ExtMulLowI32x4UName,
+ OpcodeVecI64x2ExtMulHighI32x4U: OpcodeVecI64x2ExtMulHighI32x4UName,
+ OpcodeVecF32x4Ceil: OpcodeVecF32x4CeilName,
+ OpcodeVecF32x4Floor: OpcodeVecF32x4FloorName,
+ OpcodeVecF32x4Trunc: OpcodeVecF32x4TruncName,
+ OpcodeVecF32x4Nearest: OpcodeVecF32x4NearestName,
+ OpcodeVecF32x4Abs: OpcodeVecF32x4AbsName,
+ OpcodeVecF32x4Neg: OpcodeVecF32x4NegName,
+ OpcodeVecF32x4Sqrt: OpcodeVecF32x4SqrtName,
+ OpcodeVecF32x4Add: OpcodeVecF32x4AddName,
+ OpcodeVecF32x4Sub: OpcodeVecF32x4SubName,
+ OpcodeVecF32x4Mul: OpcodeVecF32x4MulName,
+ OpcodeVecF32x4Div: OpcodeVecF32x4DivName,
+ OpcodeVecF32x4Min: OpcodeVecF32x4MinName,
+ OpcodeVecF32x4Max: OpcodeVecF32x4MaxName,
+ OpcodeVecF32x4Pmin: OpcodeVecF32x4PminName,
+ OpcodeVecF32x4Pmax: OpcodeVecF32x4PmaxName,
+ OpcodeVecF64x2Ceil: OpcodeVecF64x2CeilName,
+ OpcodeVecF64x2Floor: OpcodeVecF64x2FloorName,
+ OpcodeVecF64x2Trunc: OpcodeVecF64x2TruncName,
+ OpcodeVecF64x2Nearest: OpcodeVecF64x2NearestName,
+ OpcodeVecF64x2Abs: OpcodeVecF64x2AbsName,
+ OpcodeVecF64x2Neg: OpcodeVecF64x2NegName,
+ OpcodeVecF64x2Sqrt: OpcodeVecF64x2SqrtName,
+ OpcodeVecF64x2Add: OpcodeVecF64x2AddName,
+ OpcodeVecF64x2Sub: OpcodeVecF64x2SubName,
+ OpcodeVecF64x2Mul: OpcodeVecF64x2MulName,
+ OpcodeVecF64x2Div: OpcodeVecF64x2DivName,
+ OpcodeVecF64x2Min: OpcodeVecF64x2MinName,
+ OpcodeVecF64x2Max: OpcodeVecF64x2MaxName,
+ OpcodeVecF64x2Pmin: OpcodeVecF64x2PminName,
+ OpcodeVecF64x2Pmax: OpcodeVecF64x2PmaxName,
+ OpcodeVecI32x4TruncSatF32x4S: OpcodeVecI32x4TruncSatF32x4SName,
+ OpcodeVecI32x4TruncSatF32x4U: OpcodeVecI32x4TruncSatF32x4UName,
+ OpcodeVecF32x4ConvertI32x4S: OpcodeVecF32x4ConvertI32x4SName,
+ OpcodeVecF32x4ConvertI32x4U: OpcodeVecF32x4ConvertI32x4UName,
+ OpcodeVecI32x4TruncSatF64x2SZero: OpcodeVecI32x4TruncSatF64x2SZeroName,
+ OpcodeVecI32x4TruncSatF64x2UZero: OpcodeVecI32x4TruncSatF64x2UZeroName,
+ OpcodeVecF64x2ConvertLowI32x4S: OpcodeVecF64x2ConvertLowI32x4SName,
+ OpcodeVecF64x2ConvertLowI32x4U: OpcodeVecF64x2ConvertLowI32x4UName,
+ OpcodeVecF32x4DemoteF64x2Zero: OpcodeVecF32x4DemoteF64x2ZeroName,
+ OpcodeVecF64x2PromoteLowF32x4Zero: OpcodeVecF64x2PromoteLowF32x4ZeroName,
+}
+
+// VectorInstructionName returns the instruction name corresponding to the vector Opcode.
+func VectorInstructionName(oc OpcodeVec) (ret string) {
+ return vectorInstructionName[oc]
+}
+
+const (
+ OpcodeAtomicMemoryNotifyName = "memory.atomic.notify"
+ OpcodeAtomicMemoryWait32Name = "memory.atomic.wait32"
+ OpcodeAtomicMemoryWait64Name = "memory.atomic.wait64"
+ OpcodeAtomicFenceName = "atomic.fence"
+
+ OpcodeAtomicI32LoadName = "i32.atomic.load"
+ OpcodeAtomicI64LoadName = "i64.atomic.load"
+ OpcodeAtomicI32Load8UName = "i32.atomic.load8_u"
+ OpcodeAtomicI32Load16UName = "i32.atomic.load16_u"
+ OpcodeAtomicI64Load8UName = "i64.atomic.load8_u"
+ OpcodeAtomicI64Load16UName = "i64.atomic.load16_u"
+ OpcodeAtomicI64Load32UName = "i64.atomic.load32_u"
+ OpcodeAtomicI32StoreName = "i32.atomic.store"
+ OpcodeAtomicI64StoreName = "i64.atomic.store"
+ OpcodeAtomicI32Store8Name = "i32.atomic.store8"
+ OpcodeAtomicI32Store16Name = "i32.atomic.store16"
+ OpcodeAtomicI64Store8Name = "i64.atomic.store8"
+ OpcodeAtomicI64Store16Name = "i64.atomic.store16"
+ OpcodeAtomicI64Store32Name = "i64.atomic.store32"
+
+ OpcodeAtomicI32RmwAddName = "i32.atomic.rmw.add"
+ OpcodeAtomicI64RmwAddName = "i64.atomic.rmw.add"
+ OpcodeAtomicI32Rmw8AddUName = "i32.atomic.rmw8.add_u"
+ OpcodeAtomicI32Rmw16AddUName = "i32.atomic.rmw16.add_u"
+ OpcodeAtomicI64Rmw8AddUName = "i64.atomic.rmw8.add_u"
+ OpcodeAtomicI64Rmw16AddUName = "i64.atomic.rmw16.add_u"
+ OpcodeAtomicI64Rmw32AddUName = "i64.atomic.rmw32.add_u"
+
+ OpcodeAtomicI32RmwSubName = "i32.atomic.rmw.sub"
+ OpcodeAtomicI64RmwSubName = "i64.atomic.rmw.sub"
+ OpcodeAtomicI32Rmw8SubUName = "i32.atomic.rmw8.sub_u"
+ OpcodeAtomicI32Rmw16SubUName = "i32.atomic.rmw16.sub_u"
+ OpcodeAtomicI64Rmw8SubUName = "i64.atomic.rmw8.sub_u"
+ OpcodeAtomicI64Rmw16SubUName = "i64.atomic.rmw16.sub_u"
+ OpcodeAtomicI64Rmw32SubUName = "i64.atomic.rmw32.sub_u"
+
+ OpcodeAtomicI32RmwAndName = "i32.atomic.rmw.and"
+ OpcodeAtomicI64RmwAndName = "i64.atomic.rmw.and"
+ OpcodeAtomicI32Rmw8AndUName = "i32.atomic.rmw8.and_u"
+ OpcodeAtomicI32Rmw16AndUName = "i32.atomic.rmw16.and_u"
+ OpcodeAtomicI64Rmw8AndUName = "i64.atomic.rmw8.and_u"
+ OpcodeAtomicI64Rmw16AndUName = "i64.atomic.rmw16.and_u"
+ OpcodeAtomicI64Rmw32AndUName = "i64.atomic.rmw32.and_u"
+
+ OpcodeAtomicI32RmwOrName = "i32.atomic.rmw.or"
+ OpcodeAtomicI64RmwOrName = "i64.atomic.rmw.or"
+ OpcodeAtomicI32Rmw8OrUName = "i32.atomic.rmw8.or_u"
+ OpcodeAtomicI32Rmw16OrUName = "i32.atomic.rmw16.or_u"
+ OpcodeAtomicI64Rmw8OrUName = "i64.atomic.rmw8.or_u"
+ OpcodeAtomicI64Rmw16OrUName = "i64.atomic.rmw16.or_u"
+ OpcodeAtomicI64Rmw32OrUName = "i64.atomic.rmw32.or_u"
+
+ OpcodeAtomicI32RmwXorName = "i32.atomic.rmw.xor"
+ OpcodeAtomicI64RmwXorName = "i64.atomic.rmw.xor"
+ OpcodeAtomicI32Rmw8XorUName = "i32.atomic.rmw8.xor_u"
+ OpcodeAtomicI32Rmw16XorUName = "i32.atomic.rmw16.xor_u"
+ OpcodeAtomicI64Rmw8XorUName = "i64.atomic.rmw8.xor_u"
+ OpcodeAtomicI64Rmw16XorUName = "i64.atomic.rmw16.xor_u"
+ OpcodeAtomicI64Rmw32XorUName = "i64.atomic.rmw32.xor_u"
+
+ OpcodeAtomicI32RmwXchgName = "i32.atomic.rmw.xchg"
+ OpcodeAtomicI64RmwXchgName = "i64.atomic.rmw.xchg"
+ OpcodeAtomicI32Rmw8XchgUName = "i32.atomic.rmw8.xchg_u"
+ OpcodeAtomicI32Rmw16XchgUName = "i32.atomic.rmw16.xchg_u"
+ OpcodeAtomicI64Rmw8XchgUName = "i64.atomic.rmw8.xchg_u"
+ OpcodeAtomicI64Rmw16XchgUName = "i64.atomic.rmw16.xchg_u"
+ OpcodeAtomicI64Rmw32XchgUName = "i64.atomic.rmw32.xchg_u"
+
+ OpcodeAtomicI32RmwCmpxchgName = "i32.atomic.rmw.cmpxchg"
+ OpcodeAtomicI64RmwCmpxchgName = "i64.atomic.rmw.cmpxchg"
+ OpcodeAtomicI32Rmw8CmpxchgUName = "i32.atomic.rmw8.cmpxchg_u"
+ OpcodeAtomicI32Rmw16CmpxchgUName = "i32.atomic.rmw16.cmpxchg_u"
+ OpcodeAtomicI64Rmw8CmpxchgUName = "i64.atomic.rmw8.cmpxchg_u"
+ OpcodeAtomicI64Rmw16CmpxchgUName = "i64.atomic.rmw16.cmpxchg_u"
+ OpcodeAtomicI64Rmw32CmpxchgUName = "i64.atomic.rmw32.cmpxchg_u"
+)
+
+var atomicInstructionName = map[OpcodeAtomic]string{
+ OpcodeAtomicMemoryNotify: OpcodeAtomicMemoryNotifyName,
+ OpcodeAtomicMemoryWait32: OpcodeAtomicMemoryWait32Name,
+ OpcodeAtomicMemoryWait64: OpcodeAtomicMemoryWait64Name,
+ OpcodeAtomicFence: OpcodeAtomicFenceName,
+
+ OpcodeAtomicI32Load: OpcodeAtomicI32LoadName,
+ OpcodeAtomicI64Load: OpcodeAtomicI64LoadName,
+ OpcodeAtomicI32Load8U: OpcodeAtomicI32Load8UName,
+ OpcodeAtomicI32Load16U: OpcodeAtomicI32Load16UName,
+ OpcodeAtomicI64Load8U: OpcodeAtomicI64Load8UName,
+ OpcodeAtomicI64Load16U: OpcodeAtomicI64Load16UName,
+ OpcodeAtomicI64Load32U: OpcodeAtomicI64Load32UName,
+ OpcodeAtomicI32Store: OpcodeAtomicI32StoreName,
+ OpcodeAtomicI64Store: OpcodeAtomicI64StoreName,
+ OpcodeAtomicI32Store8: OpcodeAtomicI32Store8Name,
+ OpcodeAtomicI32Store16: OpcodeAtomicI32Store16Name,
+ OpcodeAtomicI64Store8: OpcodeAtomicI64Store8Name,
+ OpcodeAtomicI64Store16: OpcodeAtomicI64Store16Name,
+ OpcodeAtomicI64Store32: OpcodeAtomicI64Store32Name,
+
+ OpcodeAtomicI32RmwAdd: OpcodeAtomicI32RmwAddName,
+ OpcodeAtomicI64RmwAdd: OpcodeAtomicI64RmwAddName,
+ OpcodeAtomicI32Rmw8AddU: OpcodeAtomicI32Rmw8AddUName,
+ OpcodeAtomicI32Rmw16AddU: OpcodeAtomicI32Rmw16AddUName,
+ OpcodeAtomicI64Rmw8AddU: OpcodeAtomicI64Rmw8AddUName,
+ OpcodeAtomicI64Rmw16AddU: OpcodeAtomicI64Rmw16AddUName,
+ OpcodeAtomicI64Rmw32AddU: OpcodeAtomicI64Rmw32AddUName,
+
+ OpcodeAtomicI32RmwSub: OpcodeAtomicI32RmwSubName,
+ OpcodeAtomicI64RmwSub: OpcodeAtomicI64RmwSubName,
+ OpcodeAtomicI32Rmw8SubU: OpcodeAtomicI32Rmw8SubUName,
+ OpcodeAtomicI32Rmw16SubU: OpcodeAtomicI32Rmw16SubUName,
+ OpcodeAtomicI64Rmw8SubU: OpcodeAtomicI64Rmw8SubUName,
+ OpcodeAtomicI64Rmw16SubU: OpcodeAtomicI64Rmw16SubUName,
+ OpcodeAtomicI64Rmw32SubU: OpcodeAtomicI64Rmw32SubUName,
+
+ OpcodeAtomicI32RmwAnd: OpcodeAtomicI32RmwAndName,
+ OpcodeAtomicI64RmwAnd: OpcodeAtomicI64RmwAndName,
+ OpcodeAtomicI32Rmw8AndU: OpcodeAtomicI32Rmw8AndUName,
+ OpcodeAtomicI32Rmw16AndU: OpcodeAtomicI32Rmw16AndUName,
+ OpcodeAtomicI64Rmw8AndU: OpcodeAtomicI64Rmw8AndUName,
+ OpcodeAtomicI64Rmw16AndU: OpcodeAtomicI64Rmw16AndUName,
+ OpcodeAtomicI64Rmw32AndU: OpcodeAtomicI64Rmw32AndUName,
+
+ OpcodeAtomicI32RmwOr: OpcodeAtomicI32RmwOrName,
+ OpcodeAtomicI64RmwOr: OpcodeAtomicI64RmwOrName,
+ OpcodeAtomicI32Rmw8OrU: OpcodeAtomicI32Rmw8OrUName,
+ OpcodeAtomicI32Rmw16OrU: OpcodeAtomicI32Rmw16OrUName,
+ OpcodeAtomicI64Rmw8OrU: OpcodeAtomicI64Rmw8OrUName,
+ OpcodeAtomicI64Rmw16OrU: OpcodeAtomicI64Rmw16OrUName,
+ OpcodeAtomicI64Rmw32OrU: OpcodeAtomicI64Rmw32OrUName,
+
+ OpcodeAtomicI32RmwXor: OpcodeAtomicI32RmwXorName,
+ OpcodeAtomicI64RmwXor: OpcodeAtomicI64RmwXorName,
+ OpcodeAtomicI32Rmw8XorU: OpcodeAtomicI32Rmw8XorUName,
+ OpcodeAtomicI32Rmw16XorU: OpcodeAtomicI32Rmw16XorUName,
+ OpcodeAtomicI64Rmw8XorU: OpcodeAtomicI64Rmw8XorUName,
+ OpcodeAtomicI64Rmw16XorU: OpcodeAtomicI64Rmw16XorUName,
+ OpcodeAtomicI64Rmw32XorU: OpcodeAtomicI64Rmw32XorUName,
+
+ OpcodeAtomicI32RmwXchg: OpcodeAtomicI32RmwXchgName,
+ OpcodeAtomicI64RmwXchg: OpcodeAtomicI64RmwXchgName,
+ OpcodeAtomicI32Rmw8XchgU: OpcodeAtomicI32Rmw8XchgUName,
+ OpcodeAtomicI32Rmw16XchgU: OpcodeAtomicI32Rmw16XchgUName,
+ OpcodeAtomicI64Rmw8XchgU: OpcodeAtomicI64Rmw8XchgUName,
+ OpcodeAtomicI64Rmw16XchgU: OpcodeAtomicI64Rmw16XchgUName,
+ OpcodeAtomicI64Rmw32XchgU: OpcodeAtomicI64Rmw32XchgUName,
+
+ OpcodeAtomicI32RmwCmpxchg: OpcodeAtomicI32RmwCmpxchgName,
+ OpcodeAtomicI64RmwCmpxchg: OpcodeAtomicI64RmwCmpxchgName,
+ OpcodeAtomicI32Rmw8CmpxchgU: OpcodeAtomicI32Rmw8CmpxchgUName,
+ OpcodeAtomicI32Rmw16CmpxchgU: OpcodeAtomicI32Rmw16CmpxchgUName,
+ OpcodeAtomicI64Rmw8CmpxchgU: OpcodeAtomicI64Rmw8CmpxchgUName,
+ OpcodeAtomicI64Rmw16CmpxchgU: OpcodeAtomicI64Rmw16CmpxchgUName,
+ OpcodeAtomicI64Rmw32CmpxchgU: OpcodeAtomicI64Rmw32CmpxchgUName,
+}
+
+// AtomicInstructionName returns the instruction name corresponding to the atomic Opcode.
+func AtomicInstructionName(oc OpcodeAtomic) (ret string) {
+ return atomicInstructionName[oc]
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/memory.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/memory.go
new file mode 100644
index 000000000..5cc5012da
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/memory.go
@@ -0,0 +1,461 @@
+package wasm
+
+import (
+ "container/list"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "reflect"
+ "sync"
+ "sync/atomic"
+ "time"
+ "unsafe"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/experimental"
+ "github.com/tetratelabs/wazero/internal/internalapi"
+ "github.com/tetratelabs/wazero/internal/wasmruntime"
+)
+
+const (
+ // MemoryPageSize is the unit of memory length in WebAssembly,
+ // and is defined as 2^16 = 65536.
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-instances%E2%91%A0
+ MemoryPageSize = uint32(65536)
+ // MemoryLimitPages is maximum number of pages defined (2^16).
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem
+ MemoryLimitPages = uint32(65536)
+ // MemoryPageSizeInBits satisfies the relation: "1 << MemoryPageSizeInBits == MemoryPageSize".
+ MemoryPageSizeInBits = 16
+)
+
+// compile-time check to ensure MemoryInstance implements api.Memory
+var _ api.Memory = &MemoryInstance{}
+
+type waiters struct {
+ mux sync.Mutex
+ l *list.List
+}
+
+// MemoryInstance represents a memory instance in a store, and implements api.Memory.
+//
+// Note: In WebAssembly 1.0 (20191205), there may be up to one Memory per store, which means the precise memory is always
+// wasm.Store Memories index zero: `store.Memories[0]`
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-instances%E2%91%A0.
+type MemoryInstance struct {
+ internalapi.WazeroOnlyType
+
+ Buffer []byte
+ Min, Cap, Max uint32
+ Shared bool
+ // definition is known at compile time.
+ definition api.MemoryDefinition
+
+ // Mux is used in interpreter mode to prevent overlapping calls to atomic instructions,
+ // introduced with WebAssembly threads proposal.
+ Mux sync.Mutex
+
+ // waiters implements atomic wait and notify. It is implemented similarly to golang.org/x/sync/semaphore,
+ // with a fixed weight of 1 and no spurious notifications.
+ waiters sync.Map
+
+ expBuffer experimental.LinearMemory
+}
+
+// NewMemoryInstance creates a new instance based on the parameters in the SectionIDMemory.
+func NewMemoryInstance(memSec *Memory, allocator experimental.MemoryAllocator) *MemoryInstance {
+ minBytes := MemoryPagesToBytesNum(memSec.Min)
+ capBytes := MemoryPagesToBytesNum(memSec.Cap)
+ maxBytes := MemoryPagesToBytesNum(memSec.Max)
+
+ var buffer []byte
+ var expBuffer experimental.LinearMemory
+ if allocator != nil {
+ expBuffer = allocator.Allocate(capBytes, maxBytes)
+ buffer = expBuffer.Reallocate(minBytes)
+ } else if memSec.IsShared {
+ // Shared memory needs a fixed buffer, so allocate with the maximum size.
+ //
+ // The rationale as to why we can simply use make([]byte) to a fixed buffer is that Go's GC is non-relocating.
+ // That is not a part of Go spec, but is well-known thing in Go community (wazero's compiler heavily relies on it!)
+ // * https://github.com/go4org/unsafe-assume-no-moving-gc
+ //
+ // Also, allocating Max here isn't harmful as the Go runtime uses mmap for large allocations, therefore,
+ // the memory buffer allocation here is virtual and doesn't consume physical memory until it's used.
+ // * https://github.com/golang/go/blob/8121604559035734c9677d5281bbdac8b1c17a1e/src/runtime/malloc.go#L1059
+ // * https://github.com/golang/go/blob/8121604559035734c9677d5281bbdac8b1c17a1e/src/runtime/malloc.go#L1165
+ buffer = make([]byte, minBytes, maxBytes)
+ } else {
+ buffer = make([]byte, minBytes, capBytes)
+ }
+ return &MemoryInstance{
+ Buffer: buffer,
+ Min: memSec.Min,
+ Cap: memoryBytesNumToPages(uint64(cap(buffer))),
+ Max: memSec.Max,
+ Shared: memSec.IsShared,
+ expBuffer: expBuffer,
+ }
+}
+
+// Definition implements the same method as documented on api.Memory.
+func (m *MemoryInstance) Definition() api.MemoryDefinition {
+ return m.definition
+}
+
+// Size implements the same method as documented on api.Memory.
+func (m *MemoryInstance) Size() uint32 {
+ return uint32(len(m.Buffer))
+}
+
+// ReadByte implements the same method as documented on api.Memory.
+func (m *MemoryInstance) ReadByte(offset uint32) (byte, bool) {
+ if !m.hasSize(offset, 1) {
+ return 0, false
+ }
+ return m.Buffer[offset], true
+}
+
+// ReadUint16Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) ReadUint16Le(offset uint32) (uint16, bool) {
+ if !m.hasSize(offset, 2) {
+ return 0, false
+ }
+ return binary.LittleEndian.Uint16(m.Buffer[offset : offset+2]), true
+}
+
+// ReadUint32Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) ReadUint32Le(offset uint32) (uint32, bool) {
+ return m.readUint32Le(offset)
+}
+
+// ReadFloat32Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) ReadFloat32Le(offset uint32) (float32, bool) {
+ v, ok := m.readUint32Le(offset)
+ if !ok {
+ return 0, false
+ }
+ return math.Float32frombits(v), true
+}
+
+// ReadUint64Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) ReadUint64Le(offset uint32) (uint64, bool) {
+ return m.readUint64Le(offset)
+}
+
+// ReadFloat64Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) ReadFloat64Le(offset uint32) (float64, bool) {
+ v, ok := m.readUint64Le(offset)
+ if !ok {
+ return 0, false
+ }
+ return math.Float64frombits(v), true
+}
+
+// Read implements the same method as documented on api.Memory.
+func (m *MemoryInstance) Read(offset, byteCount uint32) ([]byte, bool) {
+ if !m.hasSize(offset, uint64(byteCount)) {
+ return nil, false
+ }
+ return m.Buffer[offset : offset+byteCount : offset+byteCount], true
+}
+
+// WriteByte implements the same method as documented on api.Memory.
+func (m *MemoryInstance) WriteByte(offset uint32, v byte) bool {
+ if !m.hasSize(offset, 1) {
+ return false
+ }
+ m.Buffer[offset] = v
+ return true
+}
+
+// WriteUint16Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) WriteUint16Le(offset uint32, v uint16) bool {
+ if !m.hasSize(offset, 2) {
+ return false
+ }
+ binary.LittleEndian.PutUint16(m.Buffer[offset:], v)
+ return true
+}
+
+// WriteUint32Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) WriteUint32Le(offset, v uint32) bool {
+ return m.writeUint32Le(offset, v)
+}
+
+// WriteFloat32Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) WriteFloat32Le(offset uint32, v float32) bool {
+ return m.writeUint32Le(offset, math.Float32bits(v))
+}
+
+// WriteUint64Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) WriteUint64Le(offset uint32, v uint64) bool {
+ return m.writeUint64Le(offset, v)
+}
+
+// WriteFloat64Le implements the same method as documented on api.Memory.
+func (m *MemoryInstance) WriteFloat64Le(offset uint32, v float64) bool {
+ return m.writeUint64Le(offset, math.Float64bits(v))
+}
+
+// Write implements the same method as documented on api.Memory.
+func (m *MemoryInstance) Write(offset uint32, val []byte) bool {
+ if !m.hasSize(offset, uint64(len(val))) {
+ return false
+ }
+ copy(m.Buffer[offset:], val)
+ return true
+}
+
+// WriteString implements the same method as documented on api.Memory.
+func (m *MemoryInstance) WriteString(offset uint32, val string) bool {
+ if !m.hasSize(offset, uint64(len(val))) {
+ return false
+ }
+ copy(m.Buffer[offset:], val)
+ return true
+}
+
+// MemoryPagesToBytesNum converts the given pages into the number of bytes contained in these pages.
+func MemoryPagesToBytesNum(pages uint32) (bytesNum uint64) {
+ return uint64(pages) << MemoryPageSizeInBits
+}
+
+// Grow implements the same method as documented on api.Memory.
+func (m *MemoryInstance) Grow(delta uint32) (result uint32, ok bool) {
+ currentPages := m.Pages()
+ if delta == 0 {
+ return currentPages, true
+ }
+
+ // If exceeds the max of memory size, we push -1 according to the spec.
+ newPages := currentPages + delta
+ if newPages > m.Max || int32(delta) < 0 {
+ return 0, false
+ } else if m.expBuffer != nil {
+ buffer := m.expBuffer.Reallocate(MemoryPagesToBytesNum(newPages))
+ if m.Shared {
+ if unsafe.SliceData(buffer) != unsafe.SliceData(m.Buffer) {
+ panic("shared memory cannot move, this is a bug in the memory allocator")
+ }
+ // We assume grow is called under a guest lock.
+ // But the memory length is accessed elsewhere,
+ // so use atomic to make the new length visible across threads.
+ atomicStoreLengthAndCap(&m.Buffer, uintptr(len(buffer)), uintptr(cap(buffer)))
+ m.Cap = memoryBytesNumToPages(uint64(cap(buffer)))
+ } else {
+ m.Buffer = buffer
+ m.Cap = newPages
+ }
+ return currentPages, true
+ } else if newPages > m.Cap { // grow the memory.
+ if m.Shared {
+ panic("shared memory cannot be grown, this is a bug in wazero")
+ }
+ m.Buffer = append(m.Buffer, make([]byte, MemoryPagesToBytesNum(delta))...)
+ m.Cap = newPages
+ return currentPages, true
+ } else { // We already have the capacity we need.
+ if m.Shared {
+ // We assume grow is called under a guest lock.
+ // But the memory length is accessed elsewhere,
+ // so use atomic to make the new length visible across threads.
+ atomicStoreLength(&m.Buffer, uintptr(MemoryPagesToBytesNum(newPages)))
+ } else {
+ m.Buffer = m.Buffer[:MemoryPagesToBytesNum(newPages)]
+ }
+ return currentPages, true
+ }
+}
+
+// Pages implements the same method as documented on api.Memory.
+func (m *MemoryInstance) Pages() (result uint32) {
+ return memoryBytesNumToPages(uint64(len(m.Buffer)))
+}
+
+// PagesToUnitOfBytes converts the pages to a human-readable form similar to what's specified. e.g. 1 -> "64Ki"
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-instances%E2%91%A0
+func PagesToUnitOfBytes(pages uint32) string {
+ k := pages * 64
+ if k < 1024 {
+ return fmt.Sprintf("%d Ki", k)
+ }
+ m := k / 1024
+ if m < 1024 {
+ return fmt.Sprintf("%d Mi", m)
+ }
+ g := m / 1024
+ if g < 1024 {
+ return fmt.Sprintf("%d Gi", g)
+ }
+ return fmt.Sprintf("%d Ti", g/1024)
+}
+
+// Below are raw functions used to implement the api.Memory API:
+
+// Uses atomic write to update the length of a slice.
+func atomicStoreLengthAndCap(slice *[]byte, length uintptr, cap uintptr) {
+ slicePtr := (*reflect.SliceHeader)(unsafe.Pointer(slice))
+ capPtr := (*uintptr)(unsafe.Pointer(&slicePtr.Cap))
+ atomic.StoreUintptr(capPtr, cap)
+ lenPtr := (*uintptr)(unsafe.Pointer(&slicePtr.Len))
+ atomic.StoreUintptr(lenPtr, length)
+}
+
+// Uses atomic write to update the length of a slice.
+func atomicStoreLength(slice *[]byte, length uintptr) {
+ slicePtr := (*reflect.SliceHeader)(unsafe.Pointer(slice))
+ lenPtr := (*uintptr)(unsafe.Pointer(&slicePtr.Len))
+ atomic.StoreUintptr(lenPtr, length)
+}
+
+// memoryBytesNumToPages converts the given number of bytes into the number of pages.
+func memoryBytesNumToPages(bytesNum uint64) (pages uint32) {
+ return uint32(bytesNum >> MemoryPageSizeInBits)
+}
+
+// hasSize returns true if Len is sufficient for byteCount at the given offset.
+//
+// Note: This is always fine, because memory can grow, but never shrink.
+func (m *MemoryInstance) hasSize(offset uint32, byteCount uint64) bool {
+ return uint64(offset)+byteCount <= uint64(len(m.Buffer)) // uint64 prevents overflow on add
+}
+
+// readUint32Le implements ReadUint32Le without using a context. This is extracted as both ints and floats are stored in
+// memory as uint32le.
+func (m *MemoryInstance) readUint32Le(offset uint32) (uint32, bool) {
+ if !m.hasSize(offset, 4) {
+ return 0, false
+ }
+ return binary.LittleEndian.Uint32(m.Buffer[offset : offset+4]), true
+}
+
+// readUint64Le implements ReadUint64Le without using a context. This is extracted as both ints and floats are stored in
+// memory as uint64le.
+func (m *MemoryInstance) readUint64Le(offset uint32) (uint64, bool) {
+ if !m.hasSize(offset, 8) {
+ return 0, false
+ }
+ return binary.LittleEndian.Uint64(m.Buffer[offset : offset+8]), true
+}
+
+// writeUint32Le implements WriteUint32Le without using a context. This is extracted as both ints and floats are stored
+// in memory as uint32le.
+func (m *MemoryInstance) writeUint32Le(offset uint32, v uint32) bool {
+ if !m.hasSize(offset, 4) {
+ return false
+ }
+ binary.LittleEndian.PutUint32(m.Buffer[offset:], v)
+ return true
+}
+
+// writeUint64Le implements WriteUint64Le without using a context. This is extracted as both ints and floats are stored
+// in memory as uint64le.
+func (m *MemoryInstance) writeUint64Le(offset uint32, v uint64) bool {
+ if !m.hasSize(offset, 8) {
+ return false
+ }
+ binary.LittleEndian.PutUint64(m.Buffer[offset:], v)
+ return true
+}
+
+// Wait32 suspends the caller until the offset is notified by a different agent.
+func (m *MemoryInstance) Wait32(offset uint32, exp uint32, timeout int64, reader func(mem *MemoryInstance, offset uint32) uint32) uint64 {
+ w := m.getWaiters(offset)
+ w.mux.Lock()
+
+ cur := reader(m, offset)
+ if cur != exp {
+ w.mux.Unlock()
+ return 1
+ }
+
+ return m.wait(w, timeout)
+}
+
+// Wait64 suspends the caller until the offset is notified by a different agent.
+func (m *MemoryInstance) Wait64(offset uint32, exp uint64, timeout int64, reader func(mem *MemoryInstance, offset uint32) uint64) uint64 {
+ w := m.getWaiters(offset)
+ w.mux.Lock()
+
+ cur := reader(m, offset)
+ if cur != exp {
+ w.mux.Unlock()
+ return 1
+ }
+
+ return m.wait(w, timeout)
+}
+
+func (m *MemoryInstance) wait(w *waiters, timeout int64) uint64 {
+ if w.l == nil {
+ w.l = list.New()
+ }
+
+ // The specification requires a trap if the number of existing waiters + 1 == 2^32, so we add a check here.
+ // In practice, it is unlikely the application would ever accumulate such a large number of waiters as it
+ // indicates several GB of RAM used just for the list of waiters.
+ // https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#wait
+ if uint64(w.l.Len()+1) == 1<<32 {
+ w.mux.Unlock()
+ panic(wasmruntime.ErrRuntimeTooManyWaiters)
+ }
+
+ ready := make(chan struct{})
+ elem := w.l.PushBack(ready)
+ w.mux.Unlock()
+
+ if timeout < 0 {
+ <-ready
+ return 0
+ } else {
+ select {
+ case <-ready:
+ return 0
+ case <-time.After(time.Duration(timeout)):
+ // While we could see if the channel completed by now and ignore the timeout, similar to x/sync/semaphore,
+ // the Wasm spec doesn't specify this behavior, so we keep things simple by prioritizing the timeout.
+ w.mux.Lock()
+ w.l.Remove(elem)
+ w.mux.Unlock()
+ return 2
+ }
+ }
+}
+
+func (m *MemoryInstance) getWaiters(offset uint32) *waiters {
+ wAny, ok := m.waiters.Load(offset)
+ if !ok {
+ // The first time an address is waited on, simultaneous waits will cause extra allocations.
+ // Further operations will be loaded above, which is also the general pattern of usage with
+ // mutexes.
+ wAny, _ = m.waiters.LoadOrStore(offset, &waiters{})
+ }
+
+ return wAny.(*waiters)
+}
+
+// Notify wakes up at most count waiters at the given offset.
+func (m *MemoryInstance) Notify(offset uint32, count uint32) uint32 {
+ wAny, ok := m.waiters.Load(offset)
+ if !ok {
+ return 0
+ }
+ w := wAny.(*waiters)
+
+ w.mux.Lock()
+ defer w.mux.Unlock()
+ if w.l == nil {
+ return 0
+ }
+
+ res := uint32(0)
+ for num := w.l.Len(); num > 0 && res < count; num = w.l.Len() {
+ w := w.l.Remove(w.l.Front()).(chan struct{})
+ close(w)
+ res++
+ }
+
+ return res
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/memory_definition.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/memory_definition.go
new file mode 100644
index 000000000..03d6fd303
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/memory_definition.go
@@ -0,0 +1,128 @@
+package wasm
+
+import (
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/internalapi"
+)
+
+// ImportedMemories implements the same method as documented on wazero.CompiledModule.
+func (m *Module) ImportedMemories() (ret []api.MemoryDefinition) {
+ for i := range m.MemoryDefinitionSection {
+ d := &m.MemoryDefinitionSection[i]
+ if d.importDesc != nil {
+ ret = append(ret, d)
+ }
+ }
+ return
+}
+
+// ExportedMemories implements the same method as documented on wazero.CompiledModule.
+func (m *Module) ExportedMemories() map[string]api.MemoryDefinition {
+ ret := map[string]api.MemoryDefinition{}
+ for i := range m.MemoryDefinitionSection {
+ d := &m.MemoryDefinitionSection[i]
+ for _, e := range d.exportNames {
+ ret[e] = d
+ }
+ }
+ return ret
+}
+
+// BuildMemoryDefinitions generates memory metadata that can be parsed from
+// the module. This must be called after all validation.
+//
+// Note: This is exported for wazero.Runtime `CompileModule`.
+func (m *Module) BuildMemoryDefinitions() {
+ var moduleName string
+ if m.NameSection != nil {
+ moduleName = m.NameSection.ModuleName
+ }
+
+ memoryCount := m.ImportMemoryCount
+ if m.MemorySection != nil {
+ memoryCount++
+ }
+
+ if memoryCount == 0 {
+ return
+ }
+
+ m.MemoryDefinitionSection = make([]MemoryDefinition, 0, memoryCount)
+ importMemIdx := Index(0)
+ for i := range m.ImportSection {
+ imp := &m.ImportSection[i]
+ if imp.Type != ExternTypeMemory {
+ continue
+ }
+
+ m.MemoryDefinitionSection = append(m.MemoryDefinitionSection, MemoryDefinition{
+ importDesc: &[2]string{imp.Module, imp.Name},
+ index: importMemIdx,
+ memory: imp.DescMem,
+ })
+ importMemIdx++
+ }
+
+ if m.MemorySection != nil {
+ m.MemoryDefinitionSection = append(m.MemoryDefinitionSection, MemoryDefinition{
+ index: importMemIdx,
+ memory: m.MemorySection,
+ })
+ }
+
+ for i := range m.MemoryDefinitionSection {
+ d := &m.MemoryDefinitionSection[i]
+ d.moduleName = moduleName
+ for i := range m.ExportSection {
+ e := &m.ExportSection[i]
+ if e.Type == ExternTypeMemory && e.Index == d.index {
+ d.exportNames = append(d.exportNames, e.Name)
+ }
+ }
+ }
+}
+
+// MemoryDefinition implements api.MemoryDefinition
+type MemoryDefinition struct {
+ internalapi.WazeroOnlyType
+ moduleName string
+ index Index
+ importDesc *[2]string
+ exportNames []string
+ memory *Memory
+}
+
+// ModuleName implements the same method as documented on api.MemoryDefinition.
+func (f *MemoryDefinition) ModuleName() string {
+ return f.moduleName
+}
+
+// Index implements the same method as documented on api.MemoryDefinition.
+func (f *MemoryDefinition) Index() uint32 {
+ return f.index
+}
+
+// Import implements the same method as documented on api.MemoryDefinition.
+func (f *MemoryDefinition) Import() (moduleName, name string, isImport bool) {
+ if importDesc := f.importDesc; importDesc != nil {
+ moduleName, name, isImport = importDesc[0], importDesc[1], true
+ }
+ return
+}
+
+// ExportNames implements the same method as documented on api.MemoryDefinition.
+func (f *MemoryDefinition) ExportNames() []string {
+ return f.exportNames
+}
+
+// Min implements the same method as documented on api.MemoryDefinition.
+func (f *MemoryDefinition) Min() uint32 {
+ return f.memory.Min
+}
+
+// Max implements the same method as documented on api.MemoryDefinition.
+func (f *MemoryDefinition) Max() (max uint32, encoded bool) {
+ max = f.memory.Max
+ encoded = f.memory.IsMaxEncoded
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/module.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/module.go
new file mode 100644
index 000000000..68573b918
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/module.go
@@ -0,0 +1,1083 @@
+package wasm
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "sort"
+ "strings"
+ "sync"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/experimental"
+ "github.com/tetratelabs/wazero/internal/ieee754"
+ "github.com/tetratelabs/wazero/internal/leb128"
+ "github.com/tetratelabs/wazero/internal/wasmdebug"
+)
+
+// Module is a WebAssembly binary representation.
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A8
+//
+// Differences from the specification:
+// * NameSection is the only key ("name") decoded from the SectionIDCustom.
+// * ExportSection is represented as a map for lookup convenience.
+// * Code.GoFunc is contains any go `func`. It may be present when Code.Body is not.
+type Module struct {
+ // TypeSection contains the unique FunctionType of functions imported or defined in this module.
+ //
+ // Note: Currently, there is no type ambiguity in the index as WebAssembly 1.0 only defines function type.
+ // In the future, other types may be introduced to support CoreFeatures such as module linking.
+ //
+ // Note: In the Binary Format, this is SectionIDType.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#types%E2%91%A0%E2%91%A0
+ TypeSection []FunctionType
+
+ // ImportSection contains imported functions, tables, memories or globals required for instantiation
+ // (Store.Instantiate).
+ //
+ // Note: there are no unique constraints relating to the two-level namespace of Import.Module and Import.Name.
+ //
+ // Note: In the Binary Format, this is SectionIDImport.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0
+ ImportSection []Import
+ // ImportFunctionCount ImportGlobalCount ImportMemoryCount, and ImportTableCount are
+ // the cached import count per ExternType set during decoding.
+ ImportFunctionCount,
+ ImportGlobalCount,
+ ImportMemoryCount,
+ ImportTableCount Index
+ // ImportPerModule maps a module name to the list of Import to be imported from the module.
+ // This is used to do fast import resolution during instantiation.
+ ImportPerModule map[string][]*Import
+
+ // FunctionSection contains the index in TypeSection of each function defined in this module.
+ //
+ // Note: The function Index space begins with imported functions and ends with those defined in this module.
+ // For example, if there are two imported functions and one defined in this module, the function Index 3 is defined
+ // in this module at FunctionSection[0].
+ //
+ // Note: FunctionSection is index correlated with the CodeSection. If given the same position, e.g. 2, a function
+ // type is at TypeSection[FunctionSection[2]], while its locals and body are at CodeSection[2].
+ //
+ // Note: In the Binary Format, this is SectionIDFunction.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0
+ FunctionSection []Index
+
+ // TableSection contains each table defined in this module.
+ //
+ // Note: The table Index space begins with imported tables and ends with those defined in this module.
+ // For example, if there are two imported tables and one defined in this module, the table Index 3 is defined in
+ // this module at TableSection[0].
+ //
+ // Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one table definition per module, so the
+ // length of the TableSection can be zero or one, and can only be one if there is no imported table.
+ //
+ // Note: In the Binary Format, this is SectionIDTable.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0
+ TableSection []Table
+
+ // MemorySection contains each memory defined in this module.
+ //
+ // Note: The memory Index space begins with imported memories and ends with those defined in this module.
+ // For example, if there are two imported memories and one defined in this module, the memory Index 3 is defined in
+ // this module at TableSection[0].
+ //
+ // Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one memory definition per module, so the
+ // length of the MemorySection can be zero or one, and can only be one if there is no imported memory.
+ //
+ // Note: In the Binary Format, this is SectionIDMemory.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
+ MemorySection *Memory
+
+ // GlobalSection contains each global defined in this module.
+ //
+ // Global indexes are offset by any imported globals because the global index begins with imports, followed by
+ // ones defined in this module. For example, if there are two imported globals and three defined in this module, the
+ // global at index 3 is defined in this module at GlobalSection[0].
+ //
+ // Note: In the Binary Format, this is SectionIDGlobal.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0
+ GlobalSection []Global
+
+ // ExportSection contains each export defined in this module.
+ //
+ // Note: In the Binary Format, this is SectionIDExport.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A0
+ ExportSection []Export
+ // Exports maps a name to Export, and is convenient for fast look up of exported instances at runtime.
+ // Each item of this map points to an element of ExportSection.
+ Exports map[string]*Export
+
+ // StartSection is the index of a function to call before returning from Store.Instantiate.
+ //
+ // Note: The index here is not the position in the FunctionSection, rather in the function index, which
+ // begins with imported functions.
+ //
+ // Note: In the Binary Format, this is SectionIDStart.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0
+ StartSection *Index
+
+ // Note: In the Binary Format, this is SectionIDElement.
+ ElementSection []ElementSegment
+
+ // CodeSection is index-correlated with FunctionSection and contains each
+ // function's locals and body.
+ //
+ // When present, the HostFunctionSection of the same index must be nil.
+ //
+ // Note: In the Binary Format, this is SectionIDCode.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0
+ CodeSection []Code
+
+ // Note: In the Binary Format, this is SectionIDData.
+ DataSection []DataSegment
+
+ // NameSection is set when the SectionIDCustom "name" was successfully decoded from the binary format.
+ //
+ // Note: This is the only SectionIDCustom defined in the WebAssembly 1.0 (20191205) Binary Format.
+ // Others are skipped as they are not used in wazero.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0
+ NameSection *NameSection
+
+ // CustomSections are set when the SectionIDCustom other than "name" were successfully decoded from the binary format.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0
+ CustomSections []*CustomSection
+
+ // DataCountSection is the optional section and holds the number of data segments in the data section.
+ //
+ // Note: This may exist in WebAssembly 2.0 or WebAssembly 1.0 with CoreFeatureBulkMemoryOperations.
+ // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section
+ // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
+ DataCountSection *uint32
+
+ // ID is the sha256 value of the source wasm plus the configurations which affect the runtime representation of
+ // Wasm binary. This is only used for caching.
+ ID ModuleID
+
+ // IsHostModule true if this is the host module, false otherwise.
+ IsHostModule bool
+
+ // functionDefinitionSectionInitOnce guards FunctionDefinitionSection so that it is initialized exactly once.
+ functionDefinitionSectionInitOnce sync.Once
+
+ // FunctionDefinitionSection is a wazero-specific section.
+ FunctionDefinitionSection []FunctionDefinition
+
+ // MemoryDefinitionSection is a wazero-specific section.
+ MemoryDefinitionSection []MemoryDefinition
+
+ // DWARFLines is used to emit DWARF based stack trace. This is created from the multiple custom sections
+ // as described in https://yurydelendik.github.io/webassembly-dwarf/, though it is not specified in the Wasm
+ // specification: https://github.com/WebAssembly/debugging/issues/1
+ DWARFLines *wasmdebug.DWARFLines
+
+ // NonStaticLocals collects the local indexes that will change its value through either local.get or local.tee.
+ NonStaticLocals []map[Index]struct{}
+}
+
+// ModuleID represents sha256 hash value uniquely assigned to Module.
+type ModuleID = [sha256.Size]byte
+
+// The wazero specific limitation described at RATIONALE.md.
+// TL;DR; We multiply by 8 (to get offsets in bytes) and the multiplication result must be less than 32bit max
+const (
+ MaximumGlobals = uint32(1 << 27)
+ MaximumFunctionIndex = uint32(1 << 27)
+ MaximumTableIndex = uint32(1 << 27)
+)
+
+// AssignModuleID calculates a sha256 checksum on `wasm` and other args, and set Module.ID to the result.
+// See the doc on Module.ID on what it's used for.
+func (m *Module) AssignModuleID(wasm []byte, listeners []experimental.FunctionListener, withEnsureTermination bool) {
+ h := sha256.New()
+ h.Write(wasm)
+ // Use the pre-allocated space backed by m.ID below.
+
+ // Write the existence of listeners to the checksum per function.
+ for i, l := range listeners {
+ binary.LittleEndian.PutUint32(m.ID[:], uint32(i))
+ m.ID[4] = boolToByte(l != nil)
+ h.Write(m.ID[:5])
+ }
+ // Write the flag of ensureTermination to the checksum.
+ m.ID[0] = boolToByte(withEnsureTermination)
+ h.Write(m.ID[:1])
+ // Get checksum by passing the slice underlying m.ID.
+ h.Sum(m.ID[:0])
+}
+
+func boolToByte(b bool) (ret byte) {
+ if b {
+ ret = 1
+ }
+ return
+}
+
+// typeOfFunction returns the wasm.FunctionType for the given function space index or nil.
+func (m *Module) typeOfFunction(funcIdx Index) *FunctionType {
+ typeSectionLength, importedFunctionCount := uint32(len(m.TypeSection)), m.ImportFunctionCount
+ if funcIdx < importedFunctionCount {
+ // Imports are not exclusively functions. This is the current function index in the loop.
+ cur := Index(0)
+ for i := range m.ImportSection {
+ imp := &m.ImportSection[i]
+ if imp.Type != ExternTypeFunc {
+ continue
+ }
+ if funcIdx == cur {
+ if imp.DescFunc >= typeSectionLength {
+ return nil
+ }
+ return &m.TypeSection[imp.DescFunc]
+ }
+ cur++
+ }
+ }
+
+ funcSectionIdx := funcIdx - m.ImportFunctionCount
+ if funcSectionIdx >= uint32(len(m.FunctionSection)) {
+ return nil
+ }
+ typeIdx := m.FunctionSection[funcSectionIdx]
+ if typeIdx >= typeSectionLength {
+ return nil
+ }
+ return &m.TypeSection[typeIdx]
+}
+
+func (m *Module) Validate(enabledFeatures api.CoreFeatures) error {
+ for i := range m.TypeSection {
+ tp := &m.TypeSection[i]
+ tp.CacheNumInUint64()
+ }
+
+ if err := m.validateStartSection(); err != nil {
+ return err
+ }
+
+ functions, globals, memory, tables, err := m.AllDeclarations()
+ if err != nil {
+ return err
+ }
+
+ if err = m.validateImports(enabledFeatures); err != nil {
+ return err
+ }
+
+ if err = m.validateGlobals(globals, uint32(len(functions)), MaximumGlobals); err != nil {
+ return err
+ }
+
+ if err = m.validateMemory(memory, globals, enabledFeatures); err != nil {
+ return err
+ }
+
+ if err = m.validateExports(enabledFeatures, functions, globals, memory, tables); err != nil {
+ return err
+ }
+
+ if m.CodeSection != nil {
+ if err = m.validateFunctions(enabledFeatures, functions, globals, memory, tables, MaximumFunctionIndex); err != nil {
+ return err
+ }
+ } // No need to validate host functions as NewHostModule validates
+
+ if err = m.validateTable(enabledFeatures, tables, MaximumTableIndex); err != nil {
+ return err
+ }
+
+ if err = m.validateDataCountSection(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (m *Module) validateStartSection() error {
+ // Check the start function is valid.
+ // TODO: this should be verified during decode so that errors have the correct source positions
+ if m.StartSection != nil {
+ startIndex := *m.StartSection
+ ft := m.typeOfFunction(startIndex)
+ if ft == nil { // TODO: move this check to decoder so that a module can never be decoded invalidly
+ return fmt.Errorf("invalid start function: func[%d] has an invalid type", startIndex)
+ }
+ if len(ft.Params) > 0 || len(ft.Results) > 0 {
+ return fmt.Errorf("invalid start function: func[%d] must have an empty (nullary) signature: %s", startIndex, ft)
+ }
+ }
+ return nil
+}
+
+func (m *Module) validateGlobals(globals []GlobalType, numFuncts, maxGlobals uint32) error {
+ if uint32(len(globals)) > maxGlobals {
+ return fmt.Errorf("too many globals in a module")
+ }
+
+ // Global initialization constant expression can only reference the imported globals.
+ // See the note on https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#constant-expressions%E2%91%A0
+ importedGlobals := globals[:m.ImportGlobalCount]
+ for i := range m.GlobalSection {
+ g := &m.GlobalSection[i]
+ if err := validateConstExpression(importedGlobals, numFuncts, &g.Init, g.Type.ValType); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (m *Module) validateFunctions(enabledFeatures api.CoreFeatures, functions []Index, globals []GlobalType, memory *Memory, tables []Table, maximumFunctionIndex uint32) error {
+ if uint32(len(functions)) > maximumFunctionIndex {
+ return fmt.Errorf("too many functions (%d) in a module", len(functions))
+ }
+
+ functionCount := m.SectionElementCount(SectionIDFunction)
+ codeCount := m.SectionElementCount(SectionIDCode)
+ if functionCount == 0 && codeCount == 0 {
+ return nil
+ }
+
+ typeCount := m.SectionElementCount(SectionIDType)
+ if codeCount != functionCount {
+ return fmt.Errorf("code count (%d) != function count (%d)", codeCount, functionCount)
+ }
+
+ declaredFuncIndexes, err := m.declaredFunctionIndexes()
+ if err != nil {
+ return err
+ }
+
+ // Create bytes.Reader once as it causes allocation, and
+ // we frequently need it (e.g. on every If instruction).
+ br := bytes.NewReader(nil)
+ // Also, we reuse the stacks across multiple function validations to reduce allocations.
+ vs := &stacks{}
+ // Non-static locals are gathered during validation and used in the down-stream compilation.
+ m.NonStaticLocals = make([]map[Index]struct{}, len(m.FunctionSection))
+ for idx, typeIndex := range m.FunctionSection {
+ if typeIndex >= typeCount {
+ return fmt.Errorf("invalid %s: type section index %d out of range", m.funcDesc(SectionIDFunction, Index(idx)), typeIndex)
+ }
+ c := &m.CodeSection[idx]
+ if c.GoFunc != nil {
+ continue
+ }
+ if err = m.validateFunction(vs, enabledFeatures, Index(idx), functions, globals, memory, tables, declaredFuncIndexes, br); err != nil {
+ return fmt.Errorf("invalid %s: %w", m.funcDesc(SectionIDFunction, Index(idx)), err)
+ }
+ }
+ return nil
+}
+
+// declaredFunctionIndexes returns a set of function indexes that can be used as an immediate for OpcodeRefFunc instruction.
+//
+// The criteria for which function indexes can be available for that instruction is vague in the spec:
+//
+// - "References: the list of function indices that occur in the module outside functions and can hence be used to form references inside them."
+// - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/conventions.html#contexts
+// - "Ref is the set funcidx(module with functions=ε, start=ε) , i.e., the set of function indices occurring in the module, except in its functions or start function."
+// - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/modules.html#valid-module
+//
+// To clarify, we reverse-engineer logic required to pass the WebAssembly Core specification 2.0 test suite:
+// https://github.com/WebAssembly/spec/blob/d39195773112a22b245ffbe864bab6d1182ccb06/test/core/ref_func.wast#L78-L115
+//
+// To summarize, the function indexes OpcodeRefFunc can refer include:
+// - existing in an element section regardless of its mode (active, passive, declarative).
+// - defined as globals whose value type is ValueRefFunc.
+// - used as an exported function.
+//
+// See https://github.com/WebAssembly/reference-types/issues/31
+// See https://github.com/WebAssembly/reference-types/issues/76
+func (m *Module) declaredFunctionIndexes() (ret map[Index]struct{}, err error) {
+ ret = map[uint32]struct{}{}
+
+ for i := range m.ExportSection {
+ exp := &m.ExportSection[i]
+ if exp.Type == ExternTypeFunc {
+ ret[exp.Index] = struct{}{}
+ }
+ }
+
+ for i := range m.GlobalSection {
+ g := &m.GlobalSection[i]
+ if g.Init.Opcode == OpcodeRefFunc {
+ var index uint32
+ index, _, err = leb128.LoadUint32(g.Init.Data)
+ if err != nil {
+ err = fmt.Errorf("%s[%d] failed to initialize: %w", SectionIDName(SectionIDGlobal), i, err)
+ return
+ }
+ ret[index] = struct{}{}
+ }
+ }
+
+ for i := range m.ElementSection {
+ elem := &m.ElementSection[i]
+ for _, index := range elem.Init {
+ if index != ElementInitNullReference {
+ ret[index] = struct{}{}
+ }
+ }
+ }
+ return
+}
+
+func (m *Module) funcDesc(sectionID SectionID, sectionIndex Index) string {
+ // Try to improve the error message by collecting any exports:
+ var exportNames []string
+ funcIdx := sectionIndex + m.ImportFunctionCount
+ for i := range m.ExportSection {
+ exp := &m.ExportSection[i]
+ if exp.Index == funcIdx && exp.Type == ExternTypeFunc {
+ exportNames = append(exportNames, fmt.Sprintf("%q", exp.Name))
+ }
+ }
+ sectionIDName := SectionIDName(sectionID)
+ if exportNames == nil {
+ return fmt.Sprintf("%s[%d]", sectionIDName, sectionIndex)
+ }
+ sort.Strings(exportNames) // go map keys do not iterate consistently
+ return fmt.Sprintf("%s[%d] export[%s]", sectionIDName, sectionIndex, strings.Join(exportNames, ","))
+}
+
+func (m *Module) validateMemory(memory *Memory, globals []GlobalType, _ api.CoreFeatures) error {
+ var activeElementCount int
+ for i := range m.DataSection {
+ d := &m.DataSection[i]
+ if !d.IsPassive() {
+ activeElementCount++
+ }
+ }
+ if activeElementCount > 0 && memory == nil {
+ return fmt.Errorf("unknown memory")
+ }
+
+ // Constant expression can only reference imported globals.
+ // https://github.com/WebAssembly/spec/blob/5900d839f38641989a9d8df2df4aee0513365d39/test/core/data.wast#L84-L91
+ importedGlobals := globals[:m.ImportGlobalCount]
+ for i := range m.DataSection {
+ d := &m.DataSection[i]
+ if !d.IsPassive() {
+ if err := validateConstExpression(importedGlobals, 0, &d.OffsetExpression, ValueTypeI32); err != nil {
+ return fmt.Errorf("calculate offset: %w", err)
+ }
+ }
+ }
+ return nil
+}
+
+func (m *Module) validateImports(enabledFeatures api.CoreFeatures) error {
+ for i := range m.ImportSection {
+ imp := &m.ImportSection[i]
+ if imp.Module == "" {
+ return fmt.Errorf("import[%d] has an empty module name", i)
+ }
+ switch imp.Type {
+ case ExternTypeFunc:
+ if int(imp.DescFunc) >= len(m.TypeSection) {
+ return fmt.Errorf("invalid import[%q.%q] function: type index out of range", imp.Module, imp.Name)
+ }
+ case ExternTypeGlobal:
+ if !imp.DescGlobal.Mutable {
+ continue
+ }
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureMutableGlobal); err != nil {
+ return fmt.Errorf("invalid import[%q.%q] global: %w", imp.Module, imp.Name, err)
+ }
+ }
+ }
+ return nil
+}
+
+func (m *Module) validateExports(enabledFeatures api.CoreFeatures, functions []Index, globals []GlobalType, memory *Memory, tables []Table) error {
+ for i := range m.ExportSection {
+ exp := &m.ExportSection[i]
+ index := exp.Index
+ switch exp.Type {
+ case ExternTypeFunc:
+ if index >= uint32(len(functions)) {
+ return fmt.Errorf("unknown function for export[%q]", exp.Name)
+ }
+ case ExternTypeGlobal:
+ if index >= uint32(len(globals)) {
+ return fmt.Errorf("unknown global for export[%q]", exp.Name)
+ }
+ if !globals[index].Mutable {
+ continue
+ }
+ if err := enabledFeatures.RequireEnabled(api.CoreFeatureMutableGlobal); err != nil {
+ return fmt.Errorf("invalid export[%q] global[%d]: %w", exp.Name, index, err)
+ }
+ case ExternTypeMemory:
+ if index > 0 || memory == nil {
+ return fmt.Errorf("memory for export[%q] out of range", exp.Name)
+ }
+ case ExternTypeTable:
+ if index >= uint32(len(tables)) {
+ return fmt.Errorf("table for export[%q] out of range", exp.Name)
+ }
+ }
+ }
+ return nil
+}
+
+func validateConstExpression(globals []GlobalType, numFuncs uint32, expr *ConstantExpression, expectedType ValueType) (err error) {
+ var actualType ValueType
+ switch expr.Opcode {
+ case OpcodeI32Const:
+ // Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
+ _, _, err = leb128.LoadInt32(expr.Data)
+ if err != nil {
+ return fmt.Errorf("read i32: %w", err)
+ }
+ actualType = ValueTypeI32
+ case OpcodeI64Const:
+ // Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
+ _, _, err = leb128.LoadInt64(expr.Data)
+ if err != nil {
+ return fmt.Errorf("read i64: %w", err)
+ }
+ actualType = ValueTypeI64
+ case OpcodeF32Const:
+ _, err = ieee754.DecodeFloat32(expr.Data)
+ if err != nil {
+ return fmt.Errorf("read f32: %w", err)
+ }
+ actualType = ValueTypeF32
+ case OpcodeF64Const:
+ _, err = ieee754.DecodeFloat64(expr.Data)
+ if err != nil {
+ return fmt.Errorf("read f64: %w", err)
+ }
+ actualType = ValueTypeF64
+ case OpcodeGlobalGet:
+ id, _, err := leb128.LoadUint32(expr.Data)
+ if err != nil {
+ return fmt.Errorf("read index of global: %w", err)
+ }
+ if uint32(len(globals)) <= id {
+ return fmt.Errorf("global index out of range")
+ }
+ actualType = globals[id].ValType
+ case OpcodeRefNull:
+ if len(expr.Data) == 0 {
+ return fmt.Errorf("read reference type for ref.null: %w", io.ErrShortBuffer)
+ }
+ reftype := expr.Data[0]
+ if reftype != RefTypeFuncref && reftype != RefTypeExternref {
+ return fmt.Errorf("invalid type for ref.null: 0x%x", reftype)
+ }
+ actualType = reftype
+ case OpcodeRefFunc:
+ index, _, err := leb128.LoadUint32(expr.Data)
+ if err != nil {
+ return fmt.Errorf("read i32: %w", err)
+ } else if index >= numFuncs {
+ return fmt.Errorf("ref.func index out of range [%d] with length %d", index, numFuncs-1)
+ }
+ actualType = ValueTypeFuncref
+ case OpcodeVecV128Const:
+ if len(expr.Data) != 16 {
+ return fmt.Errorf("%s needs 16 bytes but was %d bytes", OpcodeVecV128ConstName, len(expr.Data))
+ }
+ actualType = ValueTypeV128
+ default:
+ return fmt.Errorf("invalid opcode for const expression: 0x%x", expr.Opcode)
+ }
+
+ if actualType != expectedType {
+ return fmt.Errorf("const expression type mismatch expected %s but got %s",
+ ValueTypeName(expectedType), ValueTypeName(actualType))
+ }
+ return nil
+}
+
+func (m *Module) validateDataCountSection() (err error) {
+ if m.DataCountSection != nil && int(*m.DataCountSection) != len(m.DataSection) {
+ err = fmt.Errorf("data count section (%d) doesn't match the length of data section (%d)",
+ *m.DataCountSection, len(m.DataSection))
+ }
+ return
+}
+
+func (m *ModuleInstance) buildGlobals(module *Module, funcRefResolver func(funcIndex Index) Reference) {
+ importedGlobals := m.Globals[:module.ImportGlobalCount]
+
+ me := m.Engine
+ engineOwnGlobal := me.OwnsGlobals()
+ for i := Index(0); i < Index(len(module.GlobalSection)); i++ {
+ gs := &module.GlobalSection[i]
+ g := &GlobalInstance{}
+ if engineOwnGlobal {
+ g.Me = me
+ g.Index = i + module.ImportGlobalCount
+ }
+ m.Globals[i+module.ImportGlobalCount] = g
+ g.Type = gs.Type
+ g.initialize(importedGlobals, &gs.Init, funcRefResolver)
+ }
+}
+
+func paramNames(localNames IndirectNameMap, funcIdx uint32, paramLen int) []string {
+ for i := range localNames {
+ nm := &localNames[i]
+ // Only build parameter names if we have one for each.
+ if nm.Index != funcIdx || len(nm.NameMap) < paramLen {
+ continue
+ }
+
+ ret := make([]string, paramLen)
+ for j := range nm.NameMap {
+ p := &nm.NameMap[j]
+ if int(p.Index) < paramLen {
+ ret[p.Index] = p.Name
+ }
+ }
+ return ret
+ }
+ return nil
+}
+
+func (m *ModuleInstance) buildMemory(module *Module, allocator experimental.MemoryAllocator) {
+ memSec := module.MemorySection
+ if memSec != nil {
+ m.MemoryInstance = NewMemoryInstance(memSec, allocator)
+ m.MemoryInstance.definition = &module.MemoryDefinitionSection[0]
+ }
+}
+
+// Index is the offset in an index, not necessarily an absolute position in a Module section. This is because
+// indexs are often preceded by a corresponding type in the Module.ImportSection.
+//
+// For example, the function index starts with any ExternTypeFunc in the Module.ImportSection followed by
+// the Module.FunctionSection
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-index
+type Index = uint32
+
+// FunctionType is a possibly empty function signature.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-types%E2%91%A0
+type FunctionType struct {
+ // Params are the possibly empty sequence of value types accepted by a function with this signature.
+ Params []ValueType
+
+ // Results are the possibly empty sequence of value types returned by a function with this signature.
+ //
+ // Note: In WebAssembly 1.0 (20191205), there can be at most one result.
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#result-types%E2%91%A0
+ Results []ValueType
+
+ // string is cached as it is used both for String and key
+ string string
+
+ // ParamNumInUint64 is the number of uint64 values requires to represent the Wasm param type.
+ ParamNumInUint64 int
+
+ // ResultsNumInUint64 is the number of uint64 values requires to represent the Wasm result type.
+ ResultNumInUint64 int
+}
+
+func (f *FunctionType) CacheNumInUint64() {
+ if f.ParamNumInUint64 == 0 {
+ for _, tp := range f.Params {
+ f.ParamNumInUint64++
+ if tp == ValueTypeV128 {
+ f.ParamNumInUint64++
+ }
+ }
+ }
+
+ if f.ResultNumInUint64 == 0 {
+ for _, tp := range f.Results {
+ f.ResultNumInUint64++
+ if tp == ValueTypeV128 {
+ f.ResultNumInUint64++
+ }
+ }
+ }
+}
+
+// EqualsSignature returns true if the function type has the same parameters and results.
+func (f *FunctionType) EqualsSignature(params []ValueType, results []ValueType) bool {
+ return bytes.Equal(f.Params, params) && bytes.Equal(f.Results, results)
+}
+
+// key gets or generates the key for Store.typeIDs. e.g. "i32_v" for one i32 parameter and no (void) result.
+func (f *FunctionType) key() string {
+ if f.string != "" {
+ return f.string
+ }
+ var ret string
+ for _, b := range f.Params {
+ ret += ValueTypeName(b)
+ }
+ if len(f.Params) == 0 {
+ ret += "v_"
+ } else {
+ ret += "_"
+ }
+ for _, b := range f.Results {
+ ret += ValueTypeName(b)
+ }
+ if len(f.Results) == 0 {
+ ret += "v"
+ }
+ f.string = ret
+ return ret
+}
+
+// String implements fmt.Stringer.
+func (f *FunctionType) String() string {
+ return f.key()
+}
+
+// Import is the binary representation of an import indicated by Type
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-import
+type Import struct {
+ Type ExternType
+ // Module is the possibly empty primary namespace of this import
+ Module string
+ // Module is the possibly empty secondary namespace of this import
+ Name string
+ // DescFunc is the index in Module.TypeSection when Type equals ExternTypeFunc
+ DescFunc Index
+ // DescTable is the inlined Table when Type equals ExternTypeTable
+ DescTable Table
+ // DescMem is the inlined Memory when Type equals ExternTypeMemory
+ DescMem *Memory
+ // DescGlobal is the inlined GlobalType when Type equals ExternTypeGlobal
+ DescGlobal GlobalType
+ // IndexPerType has the index of this import per ExternType.
+ IndexPerType Index
+}
+
+// Memory describes the limits of pages (64KB) in a memory.
+type Memory struct {
+ Min, Cap, Max uint32
+ // IsMaxEncoded true if the Max is encoded in the original binary.
+ IsMaxEncoded bool
+ // IsShared true if the memory is shared for access from multiple agents.
+ IsShared bool
+}
+
+// Validate ensures values assigned to Min, Cap and Max are within valid thresholds.
+func (m *Memory) Validate(memoryLimitPages uint32) error {
+ min, capacity, max := m.Min, m.Cap, m.Max
+
+ if max > memoryLimitPages {
+ return fmt.Errorf("max %d pages (%s) over limit of %d pages (%s)",
+ max, PagesToUnitOfBytes(max), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages))
+ } else if min > memoryLimitPages {
+ return fmt.Errorf("min %d pages (%s) over limit of %d pages (%s)",
+ min, PagesToUnitOfBytes(min), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages))
+ } else if min > max {
+ return fmt.Errorf("min %d pages (%s) > max %d pages (%s)",
+ min, PagesToUnitOfBytes(min), max, PagesToUnitOfBytes(max))
+ } else if capacity < min {
+ return fmt.Errorf("capacity %d pages (%s) less than minimum %d pages (%s)",
+ capacity, PagesToUnitOfBytes(capacity), min, PagesToUnitOfBytes(min))
+ } else if capacity > memoryLimitPages {
+ return fmt.Errorf("capacity %d pages (%s) over limit of %d pages (%s)",
+ capacity, PagesToUnitOfBytes(capacity), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages))
+ }
+ return nil
+}
+
+type GlobalType struct {
+ ValType ValueType
+ Mutable bool
+}
+
+type Global struct {
+ Type GlobalType
+ Init ConstantExpression
+}
+
+type ConstantExpression struct {
+ Opcode Opcode
+ Data []byte
+}
+
+// Export is the binary representation of an export indicated by Type
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-export
+type Export struct {
+ Type ExternType
+
+ // Name is what the host refers to this definition as.
+ Name string
+
+ // Index is the index of the definition to export, the index is by Type
+ // e.g. If ExternTypeFunc, this is a position in the function index.
+ Index Index
+}
+
+// Code is an entry in the Module.CodeSection containing the locals and body of the function.
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-code
+type Code struct {
+ // LocalTypes are any function-scoped variables in insertion order.
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-local
+ LocalTypes []ValueType
+
+ // Body is a sequence of expressions ending in OpcodeEnd
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-expr
+ Body []byte
+
+ // GoFunc is non-nil when IsHostFunction and defined in go, either
+ // api.GoFunction or api.GoModuleFunction. When present, LocalTypes and Body must
+ // be nil.
+ //
+ // Note: This has no serialization format, so is not encodable.
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#host-functions%E2%91%A2
+ GoFunc interface{}
+
+ // BodyOffsetInCodeSection is the offset of the beginning of the body in the code section.
+ // This is used for DWARF based stack trace where a program counter represents an offset in code section.
+ BodyOffsetInCodeSection uint64
+}
+
+type DataSegment struct {
+ OffsetExpression ConstantExpression
+ Init []byte
+ Passive bool
+}
+
+// IsPassive returns true if this data segment is "passive" in the sense that memory offset and
+// index is determined at runtime and used by OpcodeMemoryInitName instruction in the bulk memory
+// operations proposal.
+//
+// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
+func (d *DataSegment) IsPassive() bool {
+ return d.Passive
+}
+
+// NameSection represent the known custom name subsections defined in the WebAssembly Binary Format
+//
+// Note: This can be nil if no names were decoded for any reason including configuration.
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
+type NameSection struct {
+ // ModuleName is the symbolic identifier for a module. e.g. math
+ //
+ // Note: This can be empty for any reason including configuration.
+ ModuleName string
+
+ // FunctionNames is an association of a function index to its symbolic identifier. e.g. add
+ //
+ // * the key (idx) is in the function index, where module defined functions are preceded by imported ones.
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#functions%E2%91%A7
+ //
+ // For example, assuming the below text format is the second import, you would expect FunctionNames[1] = "mul"
+ // (import "Math" "Mul" (func $mul (param $x f32) (param $y f32) (result f32)))
+ //
+ // Note: FunctionNames are only used for debugging. At runtime, functions are called based on raw numeric index.
+ // Note: This can be nil for any reason including configuration.
+ FunctionNames NameMap
+
+ // LocalNames contains symbolic names for function parameters or locals that have one.
+ //
+ // Note: In the Text Format, function local names can inherit parameter
+ // names from their type. Here are some examples:
+ // * (module (import (func (param $x i32) (param i32))) (func (type 0))) = [{0, {x,0}}]
+ // * (module (import (func (param i32) (param $y i32))) (func (type 0) (local $z i32))) = [0, [{y,1},{z,2}]]
+ // * (module (func (param $x i32) (local $y i32) (local $z i32))) = [{x,0},{y,1},{z,2}]
+ //
+ // Note: LocalNames are only used for debugging. At runtime, locals are called based on raw numeric index.
+ // Note: This can be nil for any reason including configuration.
+ LocalNames IndirectNameMap
+
+ // ResultNames is a wazero-specific mechanism to store result names.
+ ResultNames IndirectNameMap
+}
+
+// CustomSection contains the name and raw data of a custom section.
+type CustomSection struct {
+ Name string
+ Data []byte
+}
+
+// NameMap associates an index with any associated names.
+//
+// Note: Often the index bridges multiple sections. For example, the function index starts with any
+// ExternTypeFunc in the Module.ImportSection followed by the Module.FunctionSection
+//
+// Note: NameMap is unique by NameAssoc.Index, but NameAssoc.Name needn't be unique.
+// Note: When encoding in the Binary format, this must be ordered by NameAssoc.Index
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-namemap
+type NameMap []NameAssoc
+
+type NameAssoc struct {
+ Index Index
+ Name string
+}
+
+// IndirectNameMap associates an index with an association of names.
+//
+// Note: IndirectNameMap is unique by NameMapAssoc.Index, but NameMapAssoc.NameMap needn't be unique.
+// Note: When encoding in the Binary format, this must be ordered by NameMapAssoc.Index
+// https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-indirectnamemap
+type IndirectNameMap []NameMapAssoc
+
+type NameMapAssoc struct {
+ Index Index
+ NameMap NameMap
+}
+
+// AllDeclarations returns all declarations for functions, globals, memories and tables in a module including imported ones.
+func (m *Module) AllDeclarations() (functions []Index, globals []GlobalType, memory *Memory, tables []Table, err error) {
+ for i := range m.ImportSection {
+ imp := &m.ImportSection[i]
+ switch imp.Type {
+ case ExternTypeFunc:
+ functions = append(functions, imp.DescFunc)
+ case ExternTypeGlobal:
+ globals = append(globals, imp.DescGlobal)
+ case ExternTypeMemory:
+ memory = imp.DescMem
+ case ExternTypeTable:
+ tables = append(tables, imp.DescTable)
+ }
+ }
+
+ functions = append(functions, m.FunctionSection...)
+ for i := range m.GlobalSection {
+ g := &m.GlobalSection[i]
+ globals = append(globals, g.Type)
+ }
+ if m.MemorySection != nil {
+ if memory != nil { // shouldn't be possible due to Validate
+ err = errors.New("at most one table allowed in module")
+ return
+ }
+ memory = m.MemorySection
+ }
+ if m.TableSection != nil {
+ tables = append(tables, m.TableSection...)
+ }
+ return
+}
+
+// SectionID identifies the sections of a Module in the WebAssembly 1.0 (20191205) Binary Format.
+//
+// Note: these are defined in the wasm package, instead of the binary package, as a key per section is needed regardless
+// of format, and deferring to the binary type avoids confusion.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
+type SectionID = byte
+
+const (
+ // SectionIDCustom includes the standard defined NameSection and possibly others not defined in the standard.
+ SectionIDCustom SectionID = iota // don't add anything not in https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
+ SectionIDType
+ SectionIDImport
+ SectionIDFunction
+ SectionIDTable
+ SectionIDMemory
+ SectionIDGlobal
+ SectionIDExport
+ SectionIDStart
+ SectionIDElement
+ SectionIDCode
+ SectionIDData
+
+ // SectionIDDataCount may exist in WebAssembly 2.0 or WebAssembly 1.0 with CoreFeatureBulkMemoryOperations enabled.
+ //
+ // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section
+ // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
+ SectionIDDataCount
+)
+
+// SectionIDName returns the canonical name of a module section.
+// https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
+func SectionIDName(sectionID SectionID) string {
+ switch sectionID {
+ case SectionIDCustom:
+ return "custom"
+ case SectionIDType:
+ return "type"
+ case SectionIDImport:
+ return "import"
+ case SectionIDFunction:
+ return "function"
+ case SectionIDTable:
+ return "table"
+ case SectionIDMemory:
+ return "memory"
+ case SectionIDGlobal:
+ return "global"
+ case SectionIDExport:
+ return "export"
+ case SectionIDStart:
+ return "start"
+ case SectionIDElement:
+ return "element"
+ case SectionIDCode:
+ return "code"
+ case SectionIDData:
+ return "data"
+ case SectionIDDataCount:
+ return "data_count"
+ }
+ return "unknown"
+}
+
+// ValueType is an alias of api.ValueType defined to simplify imports.
+type ValueType = api.ValueType
+
+const (
+ ValueTypeI32 = api.ValueTypeI32
+ ValueTypeI64 = api.ValueTypeI64
+ ValueTypeF32 = api.ValueTypeF32
+ ValueTypeF64 = api.ValueTypeF64
+ // TODO: ValueTypeV128 is not exposed in the api pkg yet.
+ ValueTypeV128 ValueType = 0x7b
+ // TODO: ValueTypeFuncref is not exposed in the api pkg yet.
+ ValueTypeFuncref ValueType = 0x70
+ ValueTypeExternref = api.ValueTypeExternref
+)
+
+// ValueTypeName is an alias of api.ValueTypeName defined to simplify imports.
+func ValueTypeName(t ValueType) string {
+ if t == ValueTypeFuncref {
+ return "funcref"
+ } else if t == ValueTypeV128 {
+ return "v128"
+ }
+ return api.ValueTypeName(t)
+}
+
+func isReferenceValueType(vt ValueType) bool {
+ return vt == ValueTypeExternref || vt == ValueTypeFuncref
+}
+
+// ExternType is an alias of api.ExternType defined to simplify imports.
+type ExternType = api.ExternType
+
+const (
+ ExternTypeFunc = api.ExternTypeFunc
+ ExternTypeFuncName = api.ExternTypeFuncName
+ ExternTypeTable = api.ExternTypeTable
+ ExternTypeTableName = api.ExternTypeTableName
+ ExternTypeMemory = api.ExternTypeMemory
+ ExternTypeMemoryName = api.ExternTypeMemoryName
+ ExternTypeGlobal = api.ExternTypeGlobal
+ ExternTypeGlobalName = api.ExternTypeGlobalName
+)
+
+// ExternTypeName is an alias of api.ExternTypeName defined to simplify imports.
+func ExternTypeName(t ValueType) string {
+ return api.ExternTypeName(t)
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance.go
new file mode 100644
index 000000000..20c733e6f
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance.go
@@ -0,0 +1,251 @@
+package wasm
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/sys"
+)
+
+// FailIfClosed returns a sys.ExitError if CloseWithExitCode was called.
+func (m *ModuleInstance) FailIfClosed() (err error) {
+ if closed := m.Closed.Load(); closed != 0 {
+ switch closed & exitCodeFlagMask {
+ case exitCodeFlagResourceClosed:
+ case exitCodeFlagResourceNotClosed:
+ // This happens when this module is closed asynchronously in CloseModuleOnCanceledOrTimeout,
+ // and the closure of resources have been deferred here.
+ _ = m.ensureResourcesClosed(context.Background())
+ }
+ return sys.NewExitError(uint32(closed >> 32)) // Unpack the high order bits as the exit code.
+ }
+ return nil
+}
+
+// CloseModuleOnCanceledOrTimeout take a context `ctx`, which might be a Cancel or Timeout context,
+// and spawns the Goroutine to check the context is canceled ot deadline exceeded. If it reaches
+// one of the conditions, it sets the appropriate exit code.
+//
+// Callers of this function must invoke the returned context.CancelFunc to release the spawned Goroutine.
+func (m *ModuleInstance) CloseModuleOnCanceledOrTimeout(ctx context.Context) context.CancelFunc {
+ // Creating an empty channel in this case is a bit more efficient than
+ // creating a context.Context and canceling it with the same effect. We
+ // really just need to be notified when to stop listening to the users
+ // context. Closing the channel will unblock the select in the goroutine
+ // causing it to return an stop listening to ctx.Done().
+ cancelChan := make(chan struct{})
+ go m.closeModuleOnCanceledOrTimeout(ctx, cancelChan)
+ return func() { close(cancelChan) }
+}
+
+// closeModuleOnCanceledOrTimeout is extracted from CloseModuleOnCanceledOrTimeout for testing.
+func (m *ModuleInstance) closeModuleOnCanceledOrTimeout(ctx context.Context, cancelChan <-chan struct{}) {
+ select {
+ case <-ctx.Done():
+ select {
+ case <-cancelChan:
+ // In some cases by the time this goroutine is scheduled, the caller
+ // has already closed both the context and the cancelChan. In this
+ // case go will randomize which branch of the outer select to enter
+ // and we don't want to close the module.
+ default:
+ // This is the same logic as CloseWithCtxErr except this calls closeWithExitCodeWithoutClosingResource
+ // so that we can defer the resource closure in FailIfClosed.
+ switch {
+ case errors.Is(ctx.Err(), context.Canceled):
+ // TODO: figure out how to report error here.
+ _ = m.closeWithExitCodeWithoutClosingResource(sys.ExitCodeContextCanceled)
+ case errors.Is(ctx.Err(), context.DeadlineExceeded):
+ // TODO: figure out how to report error here.
+ _ = m.closeWithExitCodeWithoutClosingResource(sys.ExitCodeDeadlineExceeded)
+ }
+ }
+ case <-cancelChan:
+ }
+}
+
+// CloseWithCtxErr closes the module with an exit code based on the type of
+// error reported by the context.
+//
+// If the context's error is unknown or nil, the module does not close.
+func (m *ModuleInstance) CloseWithCtxErr(ctx context.Context) {
+ switch {
+ case errors.Is(ctx.Err(), context.Canceled):
+ // TODO: figure out how to report error here.
+ _ = m.CloseWithExitCode(ctx, sys.ExitCodeContextCanceled)
+ case errors.Is(ctx.Err(), context.DeadlineExceeded):
+ // TODO: figure out how to report error here.
+ _ = m.CloseWithExitCode(ctx, sys.ExitCodeDeadlineExceeded)
+ }
+}
+
+// Name implements the same method as documented on api.Module
+func (m *ModuleInstance) Name() string {
+ return m.ModuleName
+}
+
+// String implements the same method as documented on api.Module
+func (m *ModuleInstance) String() string {
+ return fmt.Sprintf("Module[%s]", m.Name())
+}
+
+// Close implements the same method as documented on api.Module.
+func (m *ModuleInstance) Close(ctx context.Context) (err error) {
+ return m.CloseWithExitCode(ctx, 0)
+}
+
+// CloseWithExitCode implements the same method as documented on api.Module.
+func (m *ModuleInstance) CloseWithExitCode(ctx context.Context, exitCode uint32) (err error) {
+ if !m.setExitCode(exitCode, exitCodeFlagResourceClosed) {
+ return nil // not an error to have already closed
+ }
+ _ = m.s.deleteModule(m)
+ return m.ensureResourcesClosed(ctx)
+}
+
+// IsClosed implements the same method as documented on api.Module.
+func (m *ModuleInstance) IsClosed() bool {
+ return m.Closed.Load() != 0
+}
+
+func (m *ModuleInstance) closeWithExitCodeWithoutClosingResource(exitCode uint32) (err error) {
+ if !m.setExitCode(exitCode, exitCodeFlagResourceNotClosed) {
+ return nil // not an error to have already closed
+ }
+ _ = m.s.deleteModule(m)
+ return nil
+}
+
+// closeWithExitCode is the same as CloseWithExitCode besides this doesn't delete it from Store.moduleList.
+func (m *ModuleInstance) closeWithExitCode(ctx context.Context, exitCode uint32) (err error) {
+ if !m.setExitCode(exitCode, exitCodeFlagResourceClosed) {
+ return nil // not an error to have already closed
+ }
+ return m.ensureResourcesClosed(ctx)
+}
+
+type exitCodeFlag = uint64
+
+const exitCodeFlagMask = 0xff
+
+const (
+ // exitCodeFlagResourceClosed indicates that the module was closed and resources were already closed.
+ exitCodeFlagResourceClosed = 1 << iota
+ // exitCodeFlagResourceNotClosed indicates that the module was closed while resources are not closed yet.
+ exitCodeFlagResourceNotClosed
+)
+
+func (m *ModuleInstance) setExitCode(exitCode uint32, flag exitCodeFlag) bool {
+ closed := flag | uint64(exitCode)<<32 // Store exitCode as high-order bits.
+ return m.Closed.CompareAndSwap(0, closed)
+}
+
+// ensureResourcesClosed ensures that resources assigned to ModuleInstance is released.
+// Only one call will happen per module, due to external atomic guards on Closed.
+func (m *ModuleInstance) ensureResourcesClosed(ctx context.Context) (err error) {
+ if closeNotifier := m.CloseNotifier; closeNotifier != nil { // experimental
+ closeNotifier.CloseNotify(ctx, uint32(m.Closed.Load()>>32))
+ m.CloseNotifier = nil
+ }
+
+ if sysCtx := m.Sys; sysCtx != nil { // nil if from HostModuleBuilder
+ err = sysCtx.FS().Close()
+ m.Sys = nil
+ }
+
+ if mem := m.MemoryInstance; mem != nil {
+ if mem.expBuffer != nil {
+ mem.expBuffer.Free()
+ mem.expBuffer = nil
+ }
+ }
+
+ if m.CodeCloser != nil {
+ if e := m.CodeCloser.Close(ctx); err == nil {
+ err = e
+ }
+ m.CodeCloser = nil
+ }
+ return err
+}
+
+// Memory implements the same method as documented on api.Module.
+func (m *ModuleInstance) Memory() api.Memory {
+ return m.MemoryInstance
+}
+
+// ExportedMemory implements the same method as documented on api.Module.
+func (m *ModuleInstance) ExportedMemory(name string) api.Memory {
+ _, err := m.getExport(name, ExternTypeMemory)
+ if err != nil {
+ return nil
+ }
+ // We Assume that we have at most one memory.
+ return m.MemoryInstance
+}
+
+// ExportedMemoryDefinitions implements the same method as documented on
+// api.Module.
+func (m *ModuleInstance) ExportedMemoryDefinitions() map[string]api.MemoryDefinition {
+ // Special case as we currently only support one memory.
+ if mem := m.MemoryInstance; mem != nil {
+ // Now, find out if it is exported
+ for name, exp := range m.Exports {
+ if exp.Type == ExternTypeMemory {
+ return map[string]api.MemoryDefinition{name: mem.definition}
+ }
+ }
+ }
+ return map[string]api.MemoryDefinition{}
+}
+
+// ExportedFunction implements the same method as documented on api.Module.
+func (m *ModuleInstance) ExportedFunction(name string) api.Function {
+ exp, err := m.getExport(name, ExternTypeFunc)
+ if err != nil {
+ return nil
+ }
+ return m.Engine.NewFunction(exp.Index)
+}
+
+// ExportedFunctionDefinitions implements the same method as documented on
+// api.Module.
+func (m *ModuleInstance) ExportedFunctionDefinitions() map[string]api.FunctionDefinition {
+ result := map[string]api.FunctionDefinition{}
+ for name, exp := range m.Exports {
+ if exp.Type == ExternTypeFunc {
+ result[name] = m.Source.FunctionDefinition(exp.Index)
+ }
+ }
+ return result
+}
+
+// GlobalVal is an internal hack to get the lower 64 bits of a global.
+func (m *ModuleInstance) GlobalVal(idx Index) uint64 {
+ return m.Globals[idx].Val
+}
+
+// ExportedGlobal implements the same method as documented on api.Module.
+func (m *ModuleInstance) ExportedGlobal(name string) api.Global {
+ exp, err := m.getExport(name, ExternTypeGlobal)
+ if err != nil {
+ return nil
+ }
+ g := m.Globals[exp.Index]
+ if g.Type.Mutable {
+ return mutableGlobal{g: g}
+ }
+ return constantGlobal{g: g}
+}
+
+// NumGlobal implements experimental.InternalModule.
+func (m *ModuleInstance) NumGlobal() int {
+ return len(m.Globals)
+}
+
+// Global implements experimental.InternalModule.
+func (m *ModuleInstance) Global(idx int) api.Global {
+ return constantGlobal{g: m.Globals[idx]}
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go
new file mode 100644
index 000000000..442d26a22
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go
@@ -0,0 +1,73 @@
+package wasm
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/internalapi"
+)
+
+// LookupFunction looks up the table by the given index, and returns the api.Function implementation if found,
+// otherwise this panics according to the same semantics as call_indirect instruction.
+// Currently, this is only used by emscripten which needs to do call_indirect-like operation in the host function.
+func (m *ModuleInstance) LookupFunction(t *TableInstance, typeId FunctionTypeID, tableOffset Index) api.Function {
+ fm, index := m.Engine.LookupFunction(t, typeId, tableOffset)
+ if source := fm.Source; source.IsHostModule {
+ // This case, the found function is a host function stored in the table. Generally, Engine.NewFunction are only
+ // responsible for calling Wasm-defined functions (not designed for calling Go functions!). Hence we need to wrap
+ // the host function as a special case.
+ def := &source.FunctionDefinitionSection[index]
+ goF := source.CodeSection[index].GoFunc
+ switch typed := goF.(type) {
+ case api.GoFunction:
+ // GoFunction doesn't need looked up module.
+ return &lookedUpGoFunction{def: def, g: goFunctionAsGoModuleFunction(typed)}
+ case api.GoModuleFunction:
+ return &lookedUpGoFunction{def: def, lookedUpModule: m, g: typed}
+ default:
+ panic(fmt.Sprintf("unexpected GoFunc type: %T", goF))
+ }
+ } else {
+ return fm.Engine.NewFunction(index)
+ }
+}
+
+// lookedUpGoFunction implements lookedUpGoModuleFunction.
+type lookedUpGoFunction struct {
+ internalapi.WazeroOnly
+ def *FunctionDefinition
+ // lookedUpModule is the *ModuleInstance from which this Go function is looked up, i.e. owner of the table.
+ lookedUpModule *ModuleInstance
+ g api.GoModuleFunction
+}
+
+// goFunctionAsGoModuleFunction converts api.GoFunction to api.GoModuleFunction which ignores the api.Module argument.
+func goFunctionAsGoModuleFunction(g api.GoFunction) api.GoModuleFunction {
+ return api.GoModuleFunc(func(ctx context.Context, _ api.Module, stack []uint64) {
+ g.Call(ctx, stack)
+ })
+}
+
+// Definition implements api.Function.
+func (l *lookedUpGoFunction) Definition() api.FunctionDefinition { return l.def }
+
+// Call implements api.Function.
+func (l *lookedUpGoFunction) Call(ctx context.Context, params ...uint64) ([]uint64, error) {
+ typ := l.def.Functype
+ stackSize := typ.ParamNumInUint64
+ rn := typ.ResultNumInUint64
+ if rn > stackSize {
+ stackSize = rn
+ }
+ stack := make([]uint64, stackSize)
+ copy(stack, params)
+ return stack[:rn], l.CallWithStack(ctx, stack)
+}
+
+// CallWithStack implements api.Function.
+func (l *lookedUpGoFunction) CallWithStack(ctx context.Context, stack []uint64) error {
+ // The Go host function always needs to access caller's module, in this case the one holding the table.
+ l.g.Call(ctx, l.lookedUpModule, stack)
+ return nil
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/store.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/store.go
new file mode 100644
index 000000000..1db661e85
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/store.go
@@ -0,0 +1,668 @@
+package wasm
+
+import (
+ "context"
+ "encoding/binary"
+ "fmt"
+ "sync"
+ "sync/atomic"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/experimental"
+ "github.com/tetratelabs/wazero/internal/expctxkeys"
+ "github.com/tetratelabs/wazero/internal/internalapi"
+ "github.com/tetratelabs/wazero/internal/leb128"
+ internalsys "github.com/tetratelabs/wazero/internal/sys"
+ "github.com/tetratelabs/wazero/sys"
+)
+
+// nameToModuleShrinkThreshold is the size the nameToModule map can grow to
+// before it starts to be monitored for shrinking.
+// The capacity will never be smaller than this once the threshold is met.
+const nameToModuleShrinkThreshold = 100
+
+type (
+ // Store is the runtime representation of "instantiated" Wasm module and objects.
+ // Multiple modules can be instantiated within a single store, and each instance,
+ // (e.g. function instance) can be referenced by other module instances in a Store via Module.ImportSection.
+ //
+ // Every type whose name ends with "Instance" suffix belongs to exactly one store.
+ //
+ // Note that store is not thread (concurrency) safe, meaning that using single Store
+ // via multiple goroutines might result in race conditions. In that case, the invocation
+ // and access to any methods and field of Store must be guarded by mutex.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#store%E2%91%A0
+ Store struct {
+ // moduleList ensures modules are closed in reverse initialization order.
+ moduleList *ModuleInstance // guarded by mux
+
+ // nameToModule holds the instantiated Wasm modules by module name from Instantiate.
+ // It ensures no race conditions instantiating two modules of the same name.
+ nameToModule map[string]*ModuleInstance // guarded by mux
+
+ // nameToModuleCap tracks the growth of the nameToModule map in order to
+ // track when to shrink it.
+ nameToModuleCap int // guarded by mux
+
+ // EnabledFeatures are read-only to allow optimizations.
+ EnabledFeatures api.CoreFeatures
+
+ // Engine is a global context for a Store which is in responsible for compilation and execution of Wasm modules.
+ Engine Engine
+
+ // typeIDs maps each FunctionType.String() to a unique FunctionTypeID. This is used at runtime to
+ // do type-checks on indirect function calls.
+ typeIDs map[string]FunctionTypeID
+
+ // functionMaxTypes represents the limit on the number of function types in a store.
+ // Note: this is fixed to 2^27 but have this a field for testability.
+ functionMaxTypes uint32
+
+ // mux is used to guard the fields from concurrent access.
+ mux sync.RWMutex
+ }
+
+ // ModuleInstance represents instantiated wasm module.
+ // The difference from the spec is that in wazero, a ModuleInstance holds pointers
+ // to the instances, rather than "addresses" (i.e. index to Store.Functions, Globals, etc) for convenience.
+ //
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-moduleinst
+ //
+ // This implements api.Module.
+ ModuleInstance struct {
+ internalapi.WazeroOnlyType
+
+ ModuleName string
+ Exports map[string]*Export
+ Globals []*GlobalInstance
+ MemoryInstance *MemoryInstance
+ Tables []*TableInstance
+
+ // Engine implements function calls for this module.
+ Engine ModuleEngine
+
+ // TypeIDs is index-correlated with types and holds typeIDs which is uniquely assigned to a type by store.
+ // This is necessary to achieve fast runtime type checking for indirect function calls at runtime.
+ TypeIDs []FunctionTypeID
+
+ // DataInstances holds data segments bytes of the module.
+ // This is only used by bulk memory operations.
+ //
+ // https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/exec/runtime.html#data-instances
+ DataInstances []DataInstance
+
+ // ElementInstances holds the element instance, and each holds the references to either functions
+ // or external objects (unimplemented).
+ ElementInstances []ElementInstance
+
+ // Sys is exposed for use in special imports such as WASI, assemblyscript.
+ //
+ // # Notes
+ //
+ // - This is a part of ModuleInstance so that scope and Close is coherent.
+ // - This is not exposed outside this repository (as a host function
+ // parameter) because we haven't thought through capabilities based
+ // security implications.
+ Sys *internalsys.Context
+
+ // Closed is used both to guard moduleEngine.CloseWithExitCode and to store the exit code.
+ //
+ // The update value is closedType + exitCode << 32. This ensures an exit code of zero isn't mistaken for never closed.
+ //
+ // Note: Exclusively reading and updating this with atomics guarantees cross-goroutine observations.
+ // See /RATIONALE.md
+ Closed atomic.Uint64
+
+ // CodeCloser is non-nil when the code should be closed after this module.
+ CodeCloser api.Closer
+
+ // s is the Store on which this module is instantiated.
+ s *Store
+ // prev and next hold the nodes in the linked list of ModuleInstance held by Store.
+ prev, next *ModuleInstance
+ // Source is a pointer to the Module from which this ModuleInstance derives.
+ Source *Module
+
+ // CloseNotifier is an experimental hook called once on close.
+ CloseNotifier experimental.CloseNotifier
+ }
+
+ // DataInstance holds bytes corresponding to the data segment in a module.
+ //
+ // https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/exec/runtime.html#data-instances
+ DataInstance = []byte
+
+ // GlobalInstance represents a global instance in a store.
+ // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-instances%E2%91%A0
+ GlobalInstance struct {
+ Type GlobalType
+ // Val holds a 64-bit representation of the actual value.
+ // If me is non-nil, the value will not be updated and the current value is stored in the module engine.
+ Val uint64
+ // ValHi is only used for vector type globals, and holds the higher bits of the vector.
+ // If me is non-nil, the value will not be updated and the current value is stored in the module engine.
+ ValHi uint64
+ // Me is the module engine that owns this global instance.
+ // The .Val and .ValHi fields are only valid when me is nil.
+ // If me is non-nil, the value is stored in the module engine.
+ Me ModuleEngine
+ Index Index
+ }
+
+ // FunctionTypeID is a uniquely assigned integer for a function type.
+ // This is wazero specific runtime object and specific to a store,
+ // and used at runtime to do type-checks on indirect function calls.
+ FunctionTypeID uint32
+)
+
+// The wazero specific limitations described at RATIONALE.md.
+const maximumFunctionTypes = 1 << 27
+
+// GetFunctionTypeID is used by emscripten.
+func (m *ModuleInstance) GetFunctionTypeID(t *FunctionType) FunctionTypeID {
+ id, err := m.s.GetFunctionTypeID(t)
+ if err != nil {
+ // This is not recoverable in practice since the only error GetFunctionTypeID returns is
+ // when there's too many function types in the store.
+ panic(err)
+ }
+ return id
+}
+
+func (m *ModuleInstance) buildElementInstances(elements []ElementSegment) {
+ m.ElementInstances = make([][]Reference, len(elements))
+ for i, elm := range elements {
+ if elm.Type == RefTypeFuncref && elm.Mode == ElementModePassive {
+ // Only passive elements can be access as element instances.
+ // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/syntax/modules.html#element-segments
+ inits := elm.Init
+ inst := make([]Reference, len(inits))
+ m.ElementInstances[i] = inst
+ for j, idx := range inits {
+ if index, ok := unwrapElementInitGlobalReference(idx); ok {
+ global := m.Globals[index]
+ inst[j] = Reference(global.Val)
+ } else {
+ if idx != ElementInitNullReference {
+ inst[j] = m.Engine.FunctionInstanceReference(idx)
+ }
+ }
+ }
+ }
+ }
+}
+
+func (m *ModuleInstance) applyElements(elems []ElementSegment) {
+ for elemI := range elems {
+ elem := &elems[elemI]
+ if !elem.IsActive() ||
+ // Per https://github.com/WebAssembly/spec/issues/1427 init can be no-op.
+ len(elem.Init) == 0 {
+ continue
+ }
+ var offset uint32
+ if elem.OffsetExpr.Opcode == OpcodeGlobalGet {
+ // Ignore error as it's already validated.
+ globalIdx, _, _ := leb128.LoadUint32(elem.OffsetExpr.Data)
+ global := m.Globals[globalIdx]
+ offset = uint32(global.Val)
+ } else {
+ // Ignore error as it's already validated.
+ o, _, _ := leb128.LoadInt32(elem.OffsetExpr.Data)
+ offset = uint32(o)
+ }
+
+ table := m.Tables[elem.TableIndex]
+ references := table.References
+ if int(offset)+len(elem.Init) > len(references) {
+ // ErrElementOffsetOutOfBounds is the error raised when the active element offset exceeds the table length.
+ // Before CoreFeatureReferenceTypes, this was checked statically before instantiation, after the proposal,
+ // this must be raised as runtime error (as in assert_trap in spectest), not even an instantiation error.
+ // https://github.com/WebAssembly/spec/blob/d39195773112a22b245ffbe864bab6d1182ccb06/test/core/linking.wast#L264-L274
+ //
+ // In wazero, we ignore it since in any way, the instantiated module and engines are fine and can be used
+ // for function invocations.
+ return
+ }
+
+ if table.Type == RefTypeExternref {
+ for i := 0; i < len(elem.Init); i++ {
+ references[offset+uint32(i)] = Reference(0)
+ }
+ } else {
+ for i, init := range elem.Init {
+ if init == ElementInitNullReference {
+ continue
+ }
+
+ var ref Reference
+ if index, ok := unwrapElementInitGlobalReference(init); ok {
+ global := m.Globals[index]
+ ref = Reference(global.Val)
+ } else {
+ ref = m.Engine.FunctionInstanceReference(index)
+ }
+ references[offset+uint32(i)] = ref
+ }
+ }
+ }
+}
+
+// validateData ensures that data segments are valid in terms of memory boundary.
+// Note: this is used only when bulk-memory/reference type feature is disabled.
+func (m *ModuleInstance) validateData(data []DataSegment) (err error) {
+ for i := range data {
+ d := &data[i]
+ if !d.IsPassive() {
+ offset := int(executeConstExpressionI32(m.Globals, &d.OffsetExpression))
+ ceil := offset + len(d.Init)
+ if offset < 0 || ceil > len(m.MemoryInstance.Buffer) {
+ return fmt.Errorf("%s[%d]: out of bounds memory access", SectionIDName(SectionIDData), i)
+ }
+ }
+ }
+ return
+}
+
+// applyData uses the given data segments and mutate the memory according to the initial contents on it
+// and populate the `DataInstances`. This is called after all the validation phase passes and out of
+// bounds memory access error here is not a validation error, but rather a runtime error.
+func (m *ModuleInstance) applyData(data []DataSegment) error {
+ m.DataInstances = make([][]byte, len(data))
+ for i := range data {
+ d := &data[i]
+ m.DataInstances[i] = d.Init
+ if !d.IsPassive() {
+ offset := executeConstExpressionI32(m.Globals, &d.OffsetExpression)
+ if offset < 0 || int(offset)+len(d.Init) > len(m.MemoryInstance.Buffer) {
+ return fmt.Errorf("%s[%d]: out of bounds memory access", SectionIDName(SectionIDData), i)
+ }
+ copy(m.MemoryInstance.Buffer[offset:], d.Init)
+ }
+ }
+ return nil
+}
+
+// GetExport returns an export of the given name and type or errs if not exported or the wrong type.
+func (m *ModuleInstance) getExport(name string, et ExternType) (*Export, error) {
+ exp, ok := m.Exports[name]
+ if !ok {
+ return nil, fmt.Errorf("%q is not exported in module %q", name, m.ModuleName)
+ }
+ if exp.Type != et {
+ return nil, fmt.Errorf("export %q in module %q is a %s, not a %s", name, m.ModuleName, ExternTypeName(exp.Type), ExternTypeName(et))
+ }
+ return exp, nil
+}
+
+func NewStore(enabledFeatures api.CoreFeatures, engine Engine) *Store {
+ return &Store{
+ nameToModule: map[string]*ModuleInstance{},
+ nameToModuleCap: nameToModuleShrinkThreshold,
+ EnabledFeatures: enabledFeatures,
+ Engine: engine,
+ typeIDs: map[string]FunctionTypeID{},
+ functionMaxTypes: maximumFunctionTypes,
+ }
+}
+
+// Instantiate uses name instead of the Module.NameSection ModuleName as it allows instantiating the same module under
+// different names safely and concurrently.
+//
+// * ctx: the default context used for function calls.
+// * name: the name of the module.
+// * sys: the system context, which will be closed (SysContext.Close) on ModuleInstance.Close.
+//
+// Note: Module.Validate must be called prior to instantiation.
+func (s *Store) Instantiate(
+ ctx context.Context,
+ module *Module,
+ name string,
+ sys *internalsys.Context,
+ typeIDs []FunctionTypeID,
+) (*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)
+ if err != nil {
+ return nil, err
+ }
+
+ // Now that the instantiation is complete without error, add it.
+ if err = s.registerModule(m); err != nil {
+ _ = m.Close(ctx)
+ return nil, err
+ }
+ return m, nil
+}
+
+func (s *Store) instantiate(
+ ctx context.Context,
+ module *Module,
+ name string,
+ sysCtx *internalsys.Context,
+ typeIDs []FunctionTypeID,
+) (m *ModuleInstance, err error) {
+ m = &ModuleInstance{ModuleName: name, TypeIDs: typeIDs, Sys: sysCtx, s: s, Source: module}
+
+ m.Tables = make([]*TableInstance, int(module.ImportTableCount)+len(module.TableSection))
+ m.Globals = make([]*GlobalInstance, int(module.ImportGlobalCount)+len(module.GlobalSection))
+ m.Engine, err = s.Engine.NewModuleEngine(module, m)
+ if err != nil {
+ return nil, err
+ }
+
+ if err = m.resolveImports(module); err != nil {
+ return nil, err
+ }
+
+ err = m.buildTables(module,
+ // As of reference-types proposal, boundary check must be done after instantiation.
+ s.EnabledFeatures.IsEnabled(api.CoreFeatureReferenceTypes))
+ if err != nil {
+ return nil, err
+ }
+
+ allocator, _ := ctx.Value(expctxkeys.MemoryAllocatorKey{}).(experimental.MemoryAllocator)
+
+ m.buildGlobals(module, m.Engine.FunctionInstanceReference)
+ m.buildMemory(module, allocator)
+ m.Exports = module.Exports
+ for _, exp := range m.Exports {
+ if exp.Type == ExternTypeTable {
+ t := m.Tables[exp.Index]
+ t.involvingModuleInstances = append(t.involvingModuleInstances, m)
+ }
+ }
+
+ // As of reference types proposal, data segment validation must happen after instantiation,
+ // and the side effect must persist even if there's out of bounds error after instantiation.
+ // https://github.com/WebAssembly/spec/blob/d39195773112a22b245ffbe864bab6d1182ccb06/test/core/linking.wast#L395-L405
+ if !s.EnabledFeatures.IsEnabled(api.CoreFeatureReferenceTypes) {
+ if err = m.validateData(module.DataSection); err != nil {
+ return nil, err
+ }
+ }
+
+ // After engine creation, we can create the funcref element instances and initialize funcref type globals.
+ m.buildElementInstances(module.ElementSection)
+
+ // Now all the validation passes, we are safe to mutate memory instances (possibly imported ones).
+ if err = m.applyData(module.DataSection); err != nil {
+ return nil, err
+ }
+
+ m.applyElements(module.ElementSection)
+
+ m.Engine.DoneInstantiation()
+
+ // Execute the start function.
+ if module.StartSection != nil {
+ funcIdx := *module.StartSection
+ ce := m.Engine.NewFunction(funcIdx)
+ _, err = ce.Call(ctx)
+ if exitErr, ok := err.(*sys.ExitError); ok { // Don't wrap an exit error!
+ return nil, exitErr
+ } else if err != nil {
+ return nil, fmt.Errorf("start %s failed: %w", module.funcDesc(SectionIDFunction, funcIdx), err)
+ }
+ }
+ return
+}
+
+func (m *ModuleInstance) resolveImports(module *Module) (err error) {
+ for moduleName, imports := range module.ImportPerModule {
+ var importedModule *ModuleInstance
+ importedModule, err = m.s.module(moduleName)
+ if err != nil {
+ return err
+ }
+
+ for _, i := range imports {
+ var imported *Export
+ imported, err = importedModule.getExport(i.Name, i.Type)
+ if err != nil {
+ return
+ }
+
+ switch i.Type {
+ case ExternTypeFunc:
+ expectedType := &module.TypeSection[i.DescFunc]
+ src := importedModule.Source
+ actual := src.typeOfFunction(imported.Index)
+ if !actual.EqualsSignature(expectedType.Params, expectedType.Results) {
+ err = errorInvalidImport(i, fmt.Errorf("signature mismatch: %s != %s", expectedType, actual))
+ return
+ }
+
+ m.Engine.ResolveImportedFunction(i.IndexPerType, imported.Index, importedModule.Engine)
+ case ExternTypeTable:
+ expected := i.DescTable
+ importedTable := importedModule.Tables[imported.Index]
+ if expected.Type != importedTable.Type {
+ err = errorInvalidImport(i, fmt.Errorf("table type mismatch: %s != %s",
+ RefTypeName(expected.Type), RefTypeName(importedTable.Type)))
+ return
+ }
+
+ if expected.Min > importedTable.Min {
+ err = errorMinSizeMismatch(i, expected.Min, importedTable.Min)
+ return
+ }
+
+ if expected.Max != nil {
+ expectedMax := *expected.Max
+ if importedTable.Max == nil {
+ err = errorNoMax(i, expectedMax)
+ return
+ } else if expectedMax < *importedTable.Max {
+ err = errorMaxSizeMismatch(i, expectedMax, *importedTable.Max)
+ return
+ }
+ }
+ m.Tables[i.IndexPerType] = importedTable
+ importedTable.involvingModuleInstancesMutex.Lock()
+ if len(importedTable.involvingModuleInstances) == 0 {
+ panic("BUG: involvingModuleInstances must not be nil when it's imported")
+ }
+ importedTable.involvingModuleInstances = append(importedTable.involvingModuleInstances, m)
+ importedTable.involvingModuleInstancesMutex.Unlock()
+ case ExternTypeMemory:
+ expected := i.DescMem
+ importedMemory := importedModule.MemoryInstance
+
+ if expected.Min > memoryBytesNumToPages(uint64(len(importedMemory.Buffer))) {
+ err = errorMinSizeMismatch(i, expected.Min, importedMemory.Min)
+ return
+ }
+
+ if expected.Max < importedMemory.Max {
+ err = errorMaxSizeMismatch(i, expected.Max, importedMemory.Max)
+ return
+ }
+ m.MemoryInstance = importedMemory
+ m.Engine.ResolveImportedMemory(importedModule.Engine)
+ case ExternTypeGlobal:
+ expected := i.DescGlobal
+ importedGlobal := importedModule.Globals[imported.Index]
+
+ if expected.Mutable != importedGlobal.Type.Mutable {
+ err = errorInvalidImport(i, fmt.Errorf("mutability mismatch: %t != %t",
+ expected.Mutable, importedGlobal.Type.Mutable))
+ return
+ }
+
+ if expected.ValType != importedGlobal.Type.ValType {
+ err = errorInvalidImport(i, fmt.Errorf("value type mismatch: %s != %s",
+ ValueTypeName(expected.ValType), ValueTypeName(importedGlobal.Type.ValType)))
+ return
+ }
+ m.Globals[i.IndexPerType] = importedGlobal
+ }
+ }
+ }
+ return
+}
+
+func errorMinSizeMismatch(i *Import, expected, actual uint32) error {
+ return errorInvalidImport(i, fmt.Errorf("minimum size mismatch: %d > %d", expected, actual))
+}
+
+func errorNoMax(i *Import, expected uint32) error {
+ return errorInvalidImport(i, fmt.Errorf("maximum size mismatch: %d, but actual has no max", expected))
+}
+
+func errorMaxSizeMismatch(i *Import, expected, actual uint32) error {
+ return errorInvalidImport(i, fmt.Errorf("maximum size mismatch: %d < %d", expected, actual))
+}
+
+func errorInvalidImport(i *Import, err error) error {
+ return fmt.Errorf("import %s[%s.%s]: %w", ExternTypeName(i.Type), i.Module, i.Name, err)
+}
+
+// executeConstExpressionI32 executes the ConstantExpression which returns ValueTypeI32.
+// The validity of the expression is ensured when calling this function as this is only called
+// during instantiation phrase, and the validation happens in compilation (validateConstExpression).
+func executeConstExpressionI32(importedGlobals []*GlobalInstance, expr *ConstantExpression) (ret int32) {
+ switch expr.Opcode {
+ case OpcodeI32Const:
+ ret, _, _ = leb128.LoadInt32(expr.Data)
+ case OpcodeGlobalGet:
+ id, _, _ := leb128.LoadUint32(expr.Data)
+ g := importedGlobals[id]
+ ret = int32(g.Val)
+ }
+ return
+}
+
+// initialize initializes the value of this global instance given the const expr and imported globals.
+// funcRefResolver is called to get the actual funcref (engine specific) from the OpcodeRefFunc const expr.
+//
+// Global initialization constant expression can only reference the imported globals.
+// See the note on https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#constant-expressions%E2%91%A0
+func (g *GlobalInstance) initialize(importedGlobals []*GlobalInstance, expr *ConstantExpression, funcRefResolver func(funcIndex Index) Reference) {
+ switch expr.Opcode {
+ case OpcodeI32Const:
+ // Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
+ v, _, _ := leb128.LoadInt32(expr.Data)
+ g.Val = uint64(uint32(v))
+ case OpcodeI64Const:
+ // Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
+ v, _, _ := leb128.LoadInt64(expr.Data)
+ g.Val = uint64(v)
+ case OpcodeF32Const:
+ g.Val = uint64(binary.LittleEndian.Uint32(expr.Data))
+ case OpcodeF64Const:
+ g.Val = binary.LittleEndian.Uint64(expr.Data)
+ case OpcodeGlobalGet:
+ id, _, _ := leb128.LoadUint32(expr.Data)
+ importedG := importedGlobals[id]
+ switch importedG.Type.ValType {
+ case ValueTypeI32:
+ g.Val = uint64(uint32(importedG.Val))
+ case ValueTypeI64:
+ g.Val = importedG.Val
+ case ValueTypeF32:
+ g.Val = importedG.Val
+ case ValueTypeF64:
+ g.Val = importedG.Val
+ case ValueTypeV128:
+ g.Val, g.ValHi = importedG.Val, importedG.ValHi
+ case ValueTypeFuncref, ValueTypeExternref:
+ g.Val = importedG.Val
+ }
+ case OpcodeRefNull:
+ switch expr.Data[0] {
+ case ValueTypeExternref, ValueTypeFuncref:
+ g.Val = 0 // Reference types are opaque 64bit pointer at runtime.
+ }
+ case OpcodeRefFunc:
+ v, _, _ := leb128.LoadUint32(expr.Data)
+ g.Val = uint64(funcRefResolver(v))
+ case OpcodeVecV128Const:
+ g.Val, g.ValHi = binary.LittleEndian.Uint64(expr.Data[0:8]), binary.LittleEndian.Uint64(expr.Data[8:16])
+ }
+}
+
+// String implements api.Global.
+func (g *GlobalInstance) String() string {
+ switch g.Type.ValType {
+ case ValueTypeI32, ValueTypeI64:
+ return fmt.Sprintf("global(%d)", g.Val)
+ case ValueTypeF32:
+ return fmt.Sprintf("global(%f)", api.DecodeF32(g.Val))
+ case ValueTypeF64:
+ return fmt.Sprintf("global(%f)", api.DecodeF64(g.Val))
+ default:
+ panic(fmt.Errorf("BUG: unknown value type %X", g.Type.ValType))
+ }
+}
+
+func (g *GlobalInstance) Value() (uint64, uint64) {
+ if g.Me != nil {
+ return g.Me.GetGlobalValue(g.Index)
+ }
+ return g.Val, g.ValHi
+}
+
+func (g *GlobalInstance) SetValue(lo, hi uint64) {
+ if g.Me != nil {
+ g.Me.SetGlobalValue(g.Index, lo, hi)
+ } else {
+ g.Val, g.ValHi = lo, hi
+ }
+}
+
+func (s *Store) GetFunctionTypeIDs(ts []FunctionType) ([]FunctionTypeID, error) {
+ ret := make([]FunctionTypeID, len(ts))
+ for i := range ts {
+ t := &ts[i]
+ inst, err := s.GetFunctionTypeID(t)
+ if err != nil {
+ return nil, err
+ }
+ ret[i] = inst
+ }
+ return ret, nil
+}
+
+func (s *Store) GetFunctionTypeID(t *FunctionType) (FunctionTypeID, error) {
+ s.mux.RLock()
+ key := t.key()
+ id, ok := s.typeIDs[key]
+ s.mux.RUnlock()
+ if !ok {
+ s.mux.Lock()
+ defer s.mux.Unlock()
+ // Check again in case another goroutine has already added the type.
+ if id, ok = s.typeIDs[key]; ok {
+ return id, nil
+ }
+ l := len(s.typeIDs)
+ if uint32(l) >= s.functionMaxTypes {
+ return 0, fmt.Errorf("too many function types in a store")
+ }
+ id = FunctionTypeID(l)
+ s.typeIDs[key] = id
+ }
+ return id, nil
+}
+
+// CloseWithExitCode implements the same method as documented on wazero.Runtime.
+func (s *Store) CloseWithExitCode(ctx context.Context, exitCode uint32) (err error) {
+ s.mux.Lock()
+ defer s.mux.Unlock()
+ // Close modules in reverse initialization order.
+ for m := s.moduleList; m != nil; m = m.next {
+ // If closing this module errs, proceed anyway to close the others.
+ if e := m.closeWithExitCode(ctx, exitCode); e != nil && err == nil {
+ // TODO: use multiple errors handling in Go 1.20.
+ err = e // first error
+ }
+ }
+ s.moduleList = nil
+ s.nameToModule = nil
+ s.nameToModuleCap = 0
+ s.typeIDs = nil
+ return
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/store_module_list.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/store_module_list.go
new file mode 100644
index 000000000..17c63e38e
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/store_module_list.go
@@ -0,0 +1,97 @@
+package wasm
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/tetratelabs/wazero/api"
+)
+
+// deleteModule makes the moduleName available for instantiation again.
+func (s *Store) deleteModule(m *ModuleInstance) error {
+ s.mux.Lock()
+ defer s.mux.Unlock()
+
+ // Remove this module name.
+ if m.prev != nil {
+ m.prev.next = m.next
+ }
+ if m.next != nil {
+ m.next.prev = m.prev
+ }
+ if s.moduleList == m {
+ s.moduleList = m.next
+ }
+ // Clear the m state so it does not enter any other branch
+ // on subsequent calls to deleteModule.
+ m.prev = nil
+ m.next = nil
+
+ if m.ModuleName != "" {
+ delete(s.nameToModule, m.ModuleName)
+
+ // Shrink the map if it's allocated more than twice the size of the list
+ newCap := len(s.nameToModule)
+ if newCap < nameToModuleShrinkThreshold {
+ newCap = nameToModuleShrinkThreshold
+ }
+ if newCap*2 <= s.nameToModuleCap {
+ nameToModule := make(map[string]*ModuleInstance, newCap)
+ for k, v := range s.nameToModule {
+ nameToModule[k] = v
+ }
+ s.nameToModule = nameToModule
+ s.nameToModuleCap = newCap
+ }
+ }
+ return nil
+}
+
+// module returns the module of the given name or error if not in this store
+func (s *Store) module(moduleName string) (*ModuleInstance, error) {
+ s.mux.RLock()
+ defer s.mux.RUnlock()
+ m, ok := s.nameToModule[moduleName]
+ if !ok {
+ return nil, fmt.Errorf("module[%s] not instantiated", moduleName)
+ }
+ return m, nil
+}
+
+// registerModule registers a ModuleInstance into the store.
+// This makes the ModuleInstance visible for import if it's not anonymous, and ensures it is closed when the store is.
+func (s *Store) registerModule(m *ModuleInstance) error {
+ s.mux.Lock()
+ defer s.mux.Unlock()
+
+ if s.nameToModule == nil {
+ return errors.New("already closed")
+ }
+
+ if m.ModuleName != "" {
+ if _, ok := s.nameToModule[m.ModuleName]; ok {
+ return fmt.Errorf("module[%s] has already been instantiated", m.ModuleName)
+ }
+ s.nameToModule[m.ModuleName] = m
+ if len(s.nameToModule) > s.nameToModuleCap {
+ s.nameToModuleCap = len(s.nameToModule)
+ }
+ }
+
+ // Add the newest node to the moduleNamesList as the head.
+ m.next = s.moduleList
+ if m.next != nil {
+ m.next.prev = m
+ }
+ s.moduleList = m
+ return nil
+}
+
+// Module implements wazero.Runtime Module
+func (s *Store) Module(moduleName string) api.Module {
+ m, err := s.module(moduleName)
+ if err != nil {
+ return nil
+ }
+ return m
+}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/table.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/table.go
new file mode 100644
index 000000000..2123693c6
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/wasm/table.go
@@ -0,0 +1,339 @@
+package wasm
+
+import (
+ "fmt"
+ "math"
+ "sync"
+
+ "github.com/tetratelabs/wazero/api"
+ "github.com/tetratelabs/wazero/internal/leb128"
+)
+
+// Table describes the limits of elements and its type in a table.
+type Table struct {
+ Min uint32
+ Max *uint32
+ Type RefType
+}
+
+// RefType is either RefTypeFuncref or RefTypeExternref as of WebAssembly core 2.0.
+type RefType = byte
+
+const (
+ // RefTypeFuncref represents a reference to a function.
+ RefTypeFuncref = ValueTypeFuncref
+ // RefTypeExternref represents a reference to a host object, which is not currently supported in wazero.
+ RefTypeExternref = ValueTypeExternref
+)
+
+func RefTypeName(t RefType) (ret string) {
+ switch t {
+ case RefTypeFuncref:
+ ret = "funcref"
+ case RefTypeExternref:
+ ret = "externref"
+ default:
+ ret = fmt.Sprintf("unknown(0x%x)", t)
+ }
+ return
+}
+
+// ElementMode represents a mode of element segment which is either active, passive or declarative.
+//
+// https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/syntax/modules.html#element-segments
+type ElementMode = byte
+
+const (
+ // ElementModeActive is the mode which requires the runtime to initialize table with the contents in .Init field combined with OffsetExpr.
+ ElementModeActive ElementMode = iota
+ // ElementModePassive is the mode which doesn't require the runtime to initialize table, and only used with OpcodeTableInitName.
+ ElementModePassive
+ // ElementModeDeclarative is introduced in reference-types proposal which can be used to declare function indexes used by OpcodeRefFunc.
+ ElementModeDeclarative
+)
+
+// ElementSegment are initialization instructions for a TableInstance
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-elem
+type ElementSegment struct {
+ // OffsetExpr returns the table element offset to apply to Init indices.
+ // Note: This can be validated prior to instantiation unless it includes OpcodeGlobalGet (an imported global).
+ OffsetExpr ConstantExpression
+
+ // TableIndex is the table's index to which this element segment is applied.
+ // Note: This is used if and only if the Mode is active.
+ TableIndex Index
+
+ // Followings are set/used regardless of the Mode.
+
+ // Init indices are (nullable) table elements where each index is the function index by which the module initialize the table.
+ Init []Index
+
+ // Type holds the type of this element segment, which is the RefType in WebAssembly 2.0.
+ Type RefType
+
+ // Mode is the mode of this element segment.
+ Mode ElementMode
+}
+
+const (
+ // ElementInitNullReference represents the null reference in ElementSegment's Init.
+ // In Wasm spec, an init item represents either Function's Index or null reference,
+ // and in wazero, we limit the maximum number of functions available in a module to
+ // MaximumFunctionIndex. Therefore, it is safe to use 1 << 31 to represent the null
+ // reference in Element segments.
+ ElementInitNullReference Index = 1 << 31
+ // elementInitImportedGlobalReferenceType represents an init item which is resolved via an imported global constexpr.
+ // The actual function reference stored at Global is only known at instantiation-time, so we set this flag
+ // to items of ElementSegment.Init at binary decoding, and unwrap this flag at instantiation to resolve the value.
+ //
+ // This might collide the init element resolved via ref.func instruction which is resolved with the func index at decoding,
+ // but in practice, that is not allowed in wazero thanks to our limit MaximumFunctionIndex. Thus, it is safe to set this flag
+ // in init element to indicate as such.
+ elementInitImportedGlobalReferenceType Index = 1 << 30
+)
+
+// unwrapElementInitGlobalReference takes an item of the init vector of an ElementSegment,
+// and returns the Global index if it is supposed to get generated from a global.
+// ok is true if the given init item is as such.
+func unwrapElementInitGlobalReference(init Index) (_ Index, ok bool) {
+ if init&elementInitImportedGlobalReferenceType == elementInitImportedGlobalReferenceType {
+ return init &^ elementInitImportedGlobalReferenceType, true
+ }
+ return init, false
+}
+
+// WrapGlobalIndexAsElementInit wraps the given index as an init item which is resolved via an imported global value.
+// See the comments on elementInitImportedGlobalReferenceType for more details.
+func WrapGlobalIndexAsElementInit(init Index) Index {
+ return init | elementInitImportedGlobalReferenceType
+}
+
+// IsActive returns true if the element segment is "active" mode which requires the runtime to initialize table
+// with the contents in .Init field.
+func (e *ElementSegment) IsActive() bool {
+ return e.Mode == ElementModeActive
+}
+
+// TableInstance represents a table of (RefTypeFuncref) elements in a module.
+//
+// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-instances%E2%91%A0
+type TableInstance struct {
+ // References holds references whose type is either RefTypeFuncref or RefTypeExternref (unsupported).
+ //
+ // Currently, only function references are supported.
+ References []Reference
+
+ // Min is the minimum (function) elements in this table and cannot grow to accommodate ElementSegment.
+ Min uint32
+
+ // Max if present is the maximum (function) elements in this table, or nil if unbounded.
+ Max *uint32
+
+ // Type is either RefTypeFuncref or RefTypeExternRef.
+ Type RefType
+
+ // The following is only used when the table is exported.
+
+ // involvingModuleInstances is a set of module instances which are involved in the table instance.
+ // This is critical for safety purpose because once a table is imported, it can hold any reference to
+ // any function in the owner and importing module instances. Therefore, these module instance,
+ // transitively the compiled modules, must be alive as long as the table instance is alive.
+ involvingModuleInstances []*ModuleInstance
+ // involvingModuleInstancesMutex is a mutex to protect involvingModuleInstances.
+ involvingModuleInstancesMutex sync.RWMutex
+}
+
+// ElementInstance represents an element instance in a module.
+//
+// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/exec/runtime.html#element-instances
+type ElementInstance = []Reference
+
+// Reference is the runtime representation of RefType which is either RefTypeFuncref or RefTypeExternref.
+type Reference = uintptr
+
+// validateTable ensures any ElementSegment is valid. This caches results via Module.validatedActiveElementSegments.
+// Note: limitsType are validated by decoders, so not re-validated here.
+func (m *Module) validateTable(enabledFeatures api.CoreFeatures, tables []Table, maximumTableIndex uint32) error {
+ if len(tables) > int(maximumTableIndex) {
+ return fmt.Errorf("too many tables in a module: %d given with limit %d", len(tables), maximumTableIndex)
+ }
+
+ importedTableCount := m.ImportTableCount
+
+ // Create bounds checks as these can err prior to instantiation
+ funcCount := m.ImportFunctionCount + m.SectionElementCount(SectionIDFunction)
+ globalsCount := m.ImportGlobalCount + m.SectionElementCount(SectionIDGlobal)
+
+ // Now, we have to figure out which table elements can be resolved before instantiation and also fail early if there
+ // are any imported globals that are known to be invalid by their declarations.
+ for i := range m.ElementSection {
+ elem := &m.ElementSection[i]
+ idx := Index(i)
+ initCount := uint32(len(elem.Init))
+
+ // Any offset applied is to the element, not the function index: validate here if the funcidx is sound.
+ for ei, init := range elem.Init {
+ if init == ElementInitNullReference {
+ continue
+ }
+ index, ok := unwrapElementInitGlobalReference(init)
+ if ok {
+ if index >= globalsCount {
+ return fmt.Errorf("%s[%d].init[%d] global index %d out of range", SectionIDName(SectionIDElement), idx, ei, index)
+ }
+ } else {
+ if elem.Type == RefTypeExternref {
+ return fmt.Errorf("%s[%d].init[%d] must be ref.null but was %d", SectionIDName(SectionIDElement), idx, ei, init)
+ }
+ if index >= funcCount {
+ return fmt.Errorf("%s[%d].init[%d] func index %d out of range", SectionIDName(SectionIDElement), idx, ei, index)
+ }
+ }
+ }
+
+ if elem.IsActive() {
+ if len(tables) <= int(elem.TableIndex) {
+ return fmt.Errorf("unknown table %d as active element target", elem.TableIndex)
+ }
+
+ t := tables[elem.TableIndex]
+ if t.Type != elem.Type {
+ return fmt.Errorf("element type mismatch: table has %s but element has %s",
+ RefTypeName(t.Type), RefTypeName(elem.Type),
+ )
+ }
+
+ // global.get needs to be discovered during initialization
+ oc := elem.OffsetExpr.Opcode
+ if oc == OpcodeGlobalGet {
+ globalIdx, _, err := leb128.LoadUint32(elem.OffsetExpr.Data)
+ if err != nil {
+ return fmt.Errorf("%s[%d] couldn't read global.get parameter: %w", SectionIDName(SectionIDElement), idx, err)
+ } else if err = m.verifyImportGlobalI32(SectionIDElement, idx, globalIdx); err != nil {
+ return err
+ }
+ } else if oc == OpcodeI32Const {
+ // Per https://github.com/WebAssembly/spec/blob/wg-1.0/test/core/elem.wast#L117 we must pass if imported
+ // table has set its min=0. Per https://github.com/WebAssembly/spec/blob/wg-1.0/test/core/elem.wast#L142, we
+ // have to do fail if module-defined min=0.
+ if !enabledFeatures.IsEnabled(api.CoreFeatureReferenceTypes) && elem.TableIndex >= importedTableCount {
+ // Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
+ o, _, err := leb128.LoadInt32(elem.OffsetExpr.Data)
+ if err != nil {
+ return fmt.Errorf("%s[%d] couldn't read i32.const parameter: %w", SectionIDName(SectionIDElement), idx, err)
+ }
+ offset := Index(o)
+ if err = checkSegmentBounds(t.Min, uint64(initCount)+uint64(offset), idx); err != nil {
+ return err
+ }
+ }
+ } else {
+ return fmt.Errorf("%s[%d] has an invalid const expression: %s", SectionIDName(SectionIDElement), idx, InstructionName(oc))
+ }
+ }
+ }
+ return nil
+}
+
+// buildTable returns TableInstances if the module defines or imports a table.
+// - importedTables: returned as `tables` unmodified.
+// - importedGlobals: include all instantiated, imported globals.
+//
+// If the result `init` is non-nil, it is the `tableInit` parameter of Engine.NewModuleEngine.
+//
+// Note: An error is only possible when an ElementSegment.OffsetExpr is out of range of the TableInstance.Min.
+func (m *ModuleInstance) buildTables(module *Module, skipBoundCheck bool) (err error) {
+ idx := module.ImportTableCount
+ for i := range module.TableSection {
+ tsec := &module.TableSection[i]
+ // The module defining the table is the one that sets its Min/Max etc.
+ m.Tables[idx] = &TableInstance{
+ References: make([]Reference, tsec.Min), Min: tsec.Min, Max: tsec.Max,
+ Type: tsec.Type,
+ }
+ idx++
+ }
+
+ if !skipBoundCheck {
+ for elemI := range module.ElementSection { // Do not loop over the value since elementSegments is a slice of value.
+ elem := &module.ElementSection[elemI]
+ table := m.Tables[elem.TableIndex]
+ var offset uint32
+ if elem.OffsetExpr.Opcode == OpcodeGlobalGet {
+ // Ignore error as it's already validated.
+ globalIdx, _, _ := leb128.LoadUint32(elem.OffsetExpr.Data)
+ global := m.Globals[globalIdx]
+ offset = uint32(global.Val)
+ } else { // i32.const
+ // Ignore error as it's already validated.
+ o, _, _ := leb128.LoadInt32(elem.OffsetExpr.Data)
+ offset = uint32(o)
+ }
+
+ // Check to see if we are out-of-bounds
+ initCount := uint64(len(elem.Init))
+ if err = checkSegmentBounds(table.Min, uint64(offset)+initCount, Index(elemI)); err != nil {
+ return
+ }
+ }
+ }
+ return
+}
+
+// checkSegmentBounds fails if the capacity needed for an ElementSegment.Init is larger than limitsType.Min
+//
+// WebAssembly 1.0 (20191205) doesn't forbid growing to accommodate element segments, and spectests are inconsistent.
+// For example, the spectests enforce elements within Table limitsType.Min, but ignore Import.DescTable min. What this
+// means is we have to delay offset checks on imported tables until we link to them.
+// e.g. https://github.com/WebAssembly/spec/blob/wg-1.0/test/core/elem.wast#L117 wants pass on min=0 for import
+// e.g. https://github.com/WebAssembly/spec/blob/wg-1.0/test/core/elem.wast#L142 wants fail on min=0 module-defined
+func checkSegmentBounds(min uint32, requireMin uint64, idx Index) error { // uint64 in case offset was set to -1
+ if requireMin > uint64(min) {
+ return fmt.Errorf("%s[%d].init exceeds min table size", SectionIDName(SectionIDElement), idx)
+ }
+ return nil
+}
+
+func (m *Module) verifyImportGlobalI32(sectionID SectionID, sectionIdx Index, idx uint32) error {
+ ig := uint32(math.MaxUint32) // +1 == 0
+ for i := range m.ImportSection {
+ imp := &m.ImportSection[i]
+ if imp.Type == ExternTypeGlobal {
+ ig++
+ if ig == idx {
+ if imp.DescGlobal.ValType != ValueTypeI32 {
+ return fmt.Errorf("%s[%d] (global.get %d): import[%d].global.ValType != i32", SectionIDName(sectionID), sectionIdx, idx, i)
+ }
+ return nil
+ }
+ }
+ }
+ return fmt.Errorf("%s[%d] (global.get %d): out of range of imported globals", SectionIDName(sectionID), sectionIdx, idx)
+}
+
+// Grow appends the `initialRef` by `delta` times into the References slice.
+// Returns -1 if the operation is not valid, otherwise the old length of the table.
+//
+// https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/exec/instructions.html#xref-syntax-instructions-syntax-instr-table-mathsf-table-grow-x
+func (t *TableInstance) Grow(delta uint32, initialRef Reference) (currentLen uint32) {
+ currentLen = uint32(len(t.References))
+ if delta == 0 {
+ return
+ }
+
+ if newLen := int64(currentLen) + int64(delta); // adding as 64bit ints to avoid overflow.
+ newLen >= math.MaxUint32 || (t.Max != nil && newLen > int64(*t.Max)) {
+ return 0xffffffff // = -1 in signed 32-bit integer.
+ }
+ t.References = append(t.References, make([]uintptr, delta)...)
+
+ // Uses the copy trick for faster filling the new region with the initial value.
+ // https://gist.github.com/taylorza/df2f89d5f9ab3ffd06865062a4cf015d
+ newRegion := t.References[currentLen:]
+ newRegion[0] = initialRef
+ for i := 1; i < len(newRegion); i *= 2 {
+ copy(newRegion[i:], newRegion[:i])
+ }
+ return
+}