diff options
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/wasm')
34 files changed, 0 insertions, 9695 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 deleted file mode 100644 index 2fac9196c..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/code.go +++ /dev/null @@ -1,100 +0,0 @@ -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 deleted file mode 100644 index edfc0a086..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/const_expr.go +++ /dev/null @@ -1,105 +0,0 @@ -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 deleted file mode 100644 index 771f8c327..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/custom.go +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 054ccb3c6..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/data.go +++ /dev/null @@ -1,79 +0,0 @@ -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 deleted file mode 100644 index c4191dae9..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/decoder.go +++ /dev/null @@ -1,193 +0,0 @@ -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 deleted file mode 100644 index 7ab4b48eb..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/element.go +++ /dev/null @@ -1,269 +0,0 @@ -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 deleted file mode 100644 index b9125b038..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/errors.go +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 925e9c499..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/export.go +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index bb9e2b649..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/function.go +++ /dev/null @@ -1,56 +0,0 @@ -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 deleted file mode 100644 index 4e1c16fda..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/global.go +++ /dev/null @@ -1,50 +0,0 @@ -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 deleted file mode 100644 index 29ba1b599..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/header.go +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index 39d310c55..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/import.go +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index ff2d73b5f..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/limits.go +++ /dev/null @@ -1,47 +0,0 @@ -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 deleted file mode 100644 index e1b175123..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/memory.go +++ /dev/null @@ -1,42 +0,0 @@ -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 deleted file mode 100644 index 56fb96dc8..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/names.go +++ /dev/null @@ -1,151 +0,0 @@ -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 deleted file mode 100644 index 622ee5923..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/section.go +++ /dev/null @@ -1,226 +0,0 @@ -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 deleted file mode 100644 index 353ec7566..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/table.go +++ /dev/null @@ -1,43 +0,0 @@ -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 deleted file mode 100644 index dfc4417ed..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/binary/value.go +++ /dev/null @@ -1,59 +0,0 @@ -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...)) - } - - ret := unsafe.String(&buf[0], int(size)) - 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 deleted file mode 100644 index 685a40941..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/counts.go +++ /dev/null @@ -1,51 +0,0 @@ -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 deleted file mode 100644 index 8c387e9e1..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/engine.go +++ /dev/null @@ -1,76 +0,0 @@ -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. - // - `descFunc` is the type Index in Module.TypeSection of this imported function. It corresponds to Import.DescFunc. - // - `indexInImportedModule` is the function Index of the imported function in the imported module. - // - `importedModuleEngine` is the ModuleEngine for the imported ModuleInstance. - ResolveImportedFunction(index, descFunc, 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 - - // MemoryGrown notifies the engine that the memory has grown. - MemoryGrown() -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/func_validation.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/func_validation.go deleted file mode 100644 index 604489228..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/func_validation.go +++ /dev/null @@ -1,2336 +0,0 @@ -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 { - 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) - } - 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) - } - 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) - } - - sts.ls = sts.ls[:0] - 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 - sts.ls = append(sts.ls, 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 sts.ls { - 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 - // ls is the label slice that is reused for each br_table instruction. - ls []uint32 -} - -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}) - sts.ls = sts.ls[:0] -} - -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 deleted file mode 100644 index c5f6e9121..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/function_definition.go +++ /dev/null @@ -1,188 +0,0 @@ -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 deleted file mode 100644 index abaa2d1f9..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/global.go +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index 9510c2588..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go +++ /dev/null @@ -1,279 +0,0 @@ -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 deleted file mode 100644 index bca686d1d..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/host.go +++ /dev/null @@ -1,179 +0,0 @@ -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 deleted file mode 100644 index 67f196b8b..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/instruction.go +++ /dev/null @@ -1,1866 +0,0 @@ -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 deleted file mode 100644 index 9a1f0c6d1..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/memory.go +++ /dev/null @@ -1,476 +0,0 @@ -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, and in compiler mode to make memory modifications - // within Grow non-racy for the Go race detector. - 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 - - // ownerModuleEngine is the module engine that owns this memory instance. - ownerModuleEngine ModuleEngine - - expBuffer experimental.LinearMemory -} - -// NewMemoryInstance creates a new instance based on the parameters in the SectionIDMemory. -func NewMemoryInstance(memSec *Memory, allocator experimental.MemoryAllocator, moduleEngine ModuleEngine) *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) - _ = buffer[:minBytes] // Bounds check that the minimum was allocated. - } 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, - ownerModuleEngine: moduleEngine, - } -} - -// 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) { - if m.Shared { - m.Mux.Lock() - defer m.Mux.Unlock() - } - - currentPages := m.Pages() - if delta == 0 { - return currentPages, true - } - - 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 buffer == nil { - // Allocator failed to grow. - return 0, false - } - 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 - } - } 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 - } 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)] - } - } - m.ownerModuleEngine.MemoryGrown() - 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) { - //nolint:staticcheck - 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) { - //nolint:staticcheck - 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 deleted file mode 100644 index 03d6fd303..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/memory_definition.go +++ /dev/null @@ -1,128 +0,0 @@ -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 deleted file mode 100644 index 8369ad9ed..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/module.go +++ /dev/null @@ -1,1078 +0,0 @@ -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 -} - -// 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{} - 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.Engine) - 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 deleted file mode 100644 index 20c733e6f..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance.go +++ /dev/null @@ -1,251 +0,0 @@ -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 deleted file mode 100644 index 442d26a22..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/module_instance_lookup.go +++ /dev/null @@ -1,73 +0,0 @@ -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 deleted file mode 100644 index c7909c67c..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/store.go +++ /dev/null @@ -1,679 +0,0 @@ -package wasm - -import ( - "context" - "encoding/binary" - "errors" - "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(ctx, 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(ctx context.Context, module *Module) (err error) { - // Check if ctx contains an ImportResolver. - resolveImport, _ := ctx.Value(expctxkeys.ImportResolverKey{}).(experimental.ImportResolver) - - for moduleName, imports := range module.ImportPerModule { - var importedModule *ModuleInstance - if resolveImport != nil { - if v := resolveImport(moduleName); v != nil { - importedModule = v.(*ModuleInstance) - } - } - if importedModule == nil { - 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, i.DescFunc, 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) error { - s.mux.Lock() - defer s.mux.Unlock() - // Close modules in reverse initialization order. - var errs []error - for m := s.moduleList; m != nil; m = m.next { - // If closing this module errs, proceed anyway to close the others. - if err := m.closeWithExitCode(ctx, exitCode); err != nil { - errs = append(errs, err) - } - } - s.moduleList = nil - s.nameToModule = nil - s.nameToModuleCap = 0 - s.typeIDs = nil - return errors.Join(errs...) -} 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 deleted file mode 100644 index ede3047de..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/store_module_list.go +++ /dev/null @@ -1,95 +0,0 @@ -package wasm - -import ( - "errors" - "fmt" -) - -// 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) *ModuleInstance { - 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 deleted file mode 100644 index 2123693c6..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/table.go +++ /dev/null @@ -1,339 +0,0 @@ -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 -} |