summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/wasm/binary
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2024-05-27 15:46:15 +0000
committerLibravatar GitHub <noreply@github.com>2024-05-27 17:46:15 +0200
commit1e7b32490dfdccddd04f46d4b0416b48d749d51b (patch)
tree62a11365933a5a11e0800af64cbdf9172e5e6e7a /vendor/github.com/tetratelabs/wazero/internal/wasm/binary
parent[chore] Small styling + link issues (#2933) (diff)
downloadgotosocial-1e7b32490dfdccddd04f46d4b0416b48d749d51b.tar.xz
[experiment] add alternative wasm sqlite3 implementation available via build-tag (#2863)
This allows for building GoToSocial with [SQLite transpiled to WASM](https://github.com/ncruces/go-sqlite3) and accessed through [Wazero](https://wazero.io/).
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/wasm/binary')
-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
18 files changed, 1547 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
+}