updated vendor

This commit is contained in:
2026-06-16 08:02:19 +02:00
parent 2f7f99d3f0
commit 77299d0c64
1283 changed files with 67302 additions and 208958 deletions
+28 -4
View File
@@ -45,11 +45,22 @@ func decodeCode(r *bytes.Reader, codeSectionStart uint64, ret *wasm.Code) (err e
}
bytesRead += n + 1
switch vt := b; vt {
switch vt := b; wasm.ValueType(vt) {
case wasm.ValueTypeI32, wasm.ValueTypeF32, wasm.ValueTypeI64, wasm.ValueTypeF64,
wasm.ValueTypeFuncref, wasm.ValueTypeExternref, wasm.ValueTypeV128:
wasm.ValueTypeFuncref, wasm.ValueTypeExternref, wasm.ValueTypeV128,
wasm.ValueTypeExnref:
default:
return fmt.Errorf("invalid local type: 0x%x", vt)
switch vt {
case wasm.RefPrefixNullable, wasm.RefPrefixNonNullable:
// Read and skip the heap type.
_, htNum, err := leb128.DecodeInt33AsInt64(r)
if err != nil {
return fmt.Errorf("read local ref heap type: %v", err)
}
bytesRead += htNum
default:
return fmt.Errorf("invalid local type: 0x%x", vt)
}
}
}
@@ -78,8 +89,21 @@ func decodeCode(r *bytes.Reader, codeSectionStart uint64, ret *wasm.Code) (err e
return fmt.Errorf("read type of local: %v", err)
}
var vt wasm.ValueType
switch b {
case wasm.RefPrefixNullable, wasm.RefPrefixNonNullable:
before := r.Len()
vt, err = decodeRefType(r, b == wasm.RefPrefixNullable)
if err != nil {
return err
}
remaining -= int64(before - r.Len())
default:
vt = wasm.ValueType(b)
}
for j := uint32(0); j < num; j++ {
localTypes = append(localTypes, b)
localTypes = append(localTypes, vt)
}
}
+95 -84
View File
@@ -6,100 +6,111 @@ import (
"io"
"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/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()
lenAtStart := r.Len()
startPos := r.Size() - int64(lenAtStart)
for {
opcode, 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)
return fmt.Errorf("read const expression opcode: %v", err)
}
case wasm.OpcodeRefFunc:
if err := enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
return fmt.Errorf("ref.func is not supported as %w", err)
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.OpcodeI32Add, wasm.OpcodeI32Sub, wasm.OpcodeI32Mul:
// No immediate to read.
if !enabledFeatures.IsEnabled(experimental.CoreFeaturesExtendedConst) {
return fmt.Errorf("%v is not supported in a constant expression as feature \"extended-const\" is disabled", wasm.InstructionName(opcode))
}
case wasm.OpcodeI64Const:
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
_, _, err = leb128.DecodeInt64(r)
case wasm.OpcodeI64Add, wasm.OpcodeI64Sub, wasm.OpcodeI64Mul:
// No immediate to read.
if !enabledFeatures.IsEnabled(experimental.CoreFeaturesExtendedConst) {
return fmt.Errorf("%v is not supported in a constant expression as feature \"extended-const\" is disabled", wasm.InstructionName(opcode))
}
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)
}
b, err := r.ReadByte()
reftype := wasm.ValueType(b)
if err != nil {
return fmt.Errorf("read reference type for ref.null: %w", err)
}
switch reftype {
case wasm.RefTypeFuncref, wasm.RefTypeExternref, wasm.ValueTypeExnref:
// Valid abstract heap type.
default:
// Could be a concrete type index; unread the byte and try reading as LEB128.
if err := r.UnreadByte(); err != nil {
return fmt.Errorf("unread byte for ref.null: %w", err)
}
_, _, err = leb128.DecodeUint32(r)
if err != nil {
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)
}
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)
}
case wasm.OpcodeEnd:
data := make([]byte, lenAtStart-(r.Len()))
if _, err := r.ReadAt(data, startPos); err != nil {
return fmt.Errorf("error re-buffering ConstantExpression.Data: %w", err)
}
ret.Data = data
return nil
default:
return fmt.Errorf("%v for const expression op code: %#x", ErrInvalidByte, opcode)
}
// 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)
return fmt.Errorf("read value: %v", 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
}
+16 -6
View File
@@ -8,6 +8,7 @@ import (
"io"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/wasm"
"github.com/tetratelabs/wazero/internal/wasmdebug"
@@ -113,7 +114,7 @@ func DecodeModule(
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)
m.ImportSection, m.ImportPerModule, m.ImportFunctionCount, m.ImportGlobalCount, m.ImportMemoryCount, m.ImportTableCount, m.ImportTagCount, err = decodeImportSection(r, memSizer, memoryLimitPages, enabledFeatures)
if err != nil {
return nil, err // avoid re-wrapping the error.
}
@@ -123,6 +124,11 @@ func DecodeModule(
m.TableSection, err = decodeTableSection(r, enabledFeatures)
case wasm.SectionIDMemory:
m.MemorySection, err = decodeMemorySection(r, enabledFeatures, memSizer, memoryLimitPages)
case wasm.SectionIDTag:
if err := enabledFeatures.RequireEnabled(experimental.CoreFeaturesExceptionHandling); err != nil {
return nil, fmt.Errorf("tag section not supported as %v", err)
}
m.TagSection, err = decodeTagSection(r)
case wasm.SectionIDGlobal:
if m.GlobalSection, err = decodeGlobalSection(r, enabledFeatures); err != nil {
return nil, err // avoid re-wrapping the error.
@@ -176,8 +182,15 @@ func checkSectionOrder(current, previous wasm.SectionID) (byte, bool) {
return previous, true
}
// DataCount was introduced in Wasm 2.0,
// and it's the maximum we support so far.
// Tag section (ID 13) must come after Memory (5) and before Global (6).
if current == wasm.SectionIDTag {
return current, previous <= wasm.SectionIDMemory
}
if previous == wasm.SectionIDTag {
return current, current >= wasm.SectionIDGlobal
}
// DataCount was introduced in Wasm 2.0.
// It must come after Element and before Code.
if current > wasm.SectionIDDataCount {
return current, false
@@ -189,9 +202,6 @@ func checkSectionOrder(current, previous wasm.SectionID) (byte, bool) {
return current, current >= wasm.SectionIDCode
}
// Tag will be introduced in Wasm 3.0.
// It must come after Memory and before Global.
// Otherwise, strictly increasing order.
return current, current > previous
}
+24 -43
View File
@@ -2,7 +2,6 @@ package binary
import (
"bytes"
"errors"
"fmt"
"github.com/tetratelabs/wazero/api"
@@ -21,13 +20,13 @@ func ensureElementKindFuncRef(r *bytes.Reader) error {
return nil
}
func decodeElementInitValueVector(r *bytes.Reader) ([]wasm.Index, error) {
func decodeElementInitValueVector(r *bytes.Reader) ([]wasm.ConstantExpression, error) {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return nil, fmt.Errorf("get size of vector: %w", err)
}
vec := make([]wasm.Index, vs)
vec := make([]wasm.ConstantExpression, vs)
for i := range vec {
u32, _, err := leb128.DecodeUint32(r)
if err != nil {
@@ -37,61 +36,43 @@ func decodeElementInitValueVector(r *bytes.Reader) ([]wasm.Index, error) {
if u32 >= wasm.MaximumFunctionIndex {
return nil, fmt.Errorf("too large function index in Element init: %d", u32)
}
vec[i] = u32
vec[i] = wasm.NewConstantExpressionFromOpcode(wasm.OpcodeRefFunc, leb128.EncodeUint32(u32))
}
return vec, nil
}
func decodeElementConstExprVector(r *bytes.Reader, elemType wasm.RefType, enabledFeatures api.CoreFeatures) ([]wasm.Index, error) {
func decodeElementConstExprVector(r *bytes.Reader, elemType wasm.RefType, enabledFeatures api.CoreFeatures) ([]wasm.ConstantExpression, 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)
vec := make([]wasm.ConstantExpression, vs)
for i := range vec {
var expr wasm.ConstantExpression
err := decodeConstantExpression(r, enabledFeatures, &expr)
err := decodeConstantExpression(r, enabledFeatures, &vec[i])
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))
}
// Expression will be validated later since we don't yet have globals to resolve the types yet.
}
return vec, nil
}
func decodeElementRefType(r *bytes.Reader) (ret wasm.RefType, err error) {
ret, err = r.ReadByte()
func decodeElementRefType(r *bytes.Reader) (wasm.RefType, error) {
b, err := r.ReadByte()
if err != nil {
err = fmt.Errorf("read element ref type: %w", err)
return
return 0, fmt.Errorf("read element ref type: %w", err)
}
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")
switch b {
case wasm.RefPrefixNullable, wasm.RefPrefixNonNullable:
return decodeRefType(r, b == wasm.RefPrefixNullable)
default:
ret := wasm.ValueType(b)
if ret != wasm.RefTypeFuncref && ret != wasm.RefTypeExternref {
return 0, fmt.Errorf("invalid ref type for element: 0x%x", b)
}
return ret, nil
}
return
}
const (
@@ -142,7 +123,7 @@ func decodeElementSegment(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret
}
ret.Mode = wasm.ElementModeActive
ret.Type = wasm.RefTypeFuncref
ret.Type = wasm.RefTypeFuncref.AsNonNullable()
return nil
case elementSegmentPrefixPassiveFuncrefValueVector:
// Prefix 1 requires funcref.
@@ -155,7 +136,7 @@ func decodeElementSegment(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret
return err
}
ret.Mode = wasm.ElementModePassive
ret.Type = wasm.RefTypeFuncref
ret.Type = wasm.RefTypeFuncref.AsNonNullable()
return nil
case elementSegmentPrefixActiveFuncrefValueVectorWithTableIndex:
ret.TableIndex, _, err = leb128.DecodeUint32(r)
@@ -185,7 +166,7 @@ func decodeElementSegment(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret
}
ret.Mode = wasm.ElementModeActive
ret.Type = wasm.RefTypeFuncref
ret.Type = wasm.RefTypeFuncref.AsNonNullable()
return nil
case elementSegmentPrefixDeclarativeFuncrefValueVector:
// Prefix 3 requires funcref.
@@ -196,7 +177,7 @@ func decodeElementSegment(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret
if err != nil {
return err
}
ret.Type = wasm.RefTypeFuncref
ret.Type = wasm.RefTypeFuncref.AsNonNullable()
ret.Mode = wasm.ElementModeDeclarative
return nil
case elementSegmentPrefixActiveFuncrefConstExprVector:
+1 -1
View File
@@ -21,7 +21,7 @@ func decodeExport(r *bytes.Reader, ret *wasm.Export) (err error) {
ret.Type = b
switch ret.Type {
case wasm.ExternTypeFunc, wasm.ExternTypeTable, wasm.ExternTypeMemory, wasm.ExternTypeGlobal:
case wasm.ExternTypeFunc, wasm.ExternTypeTable, wasm.ExternTypeMemory, wasm.ExternTypeGlobal, wasm.ExternTypeTag:
if ret.Index, _, err = leb128.DecodeUint32(r); err != nil {
err = fmt.Errorf("error decoding export index: %w", err)
}
+16
View File
@@ -42,6 +42,22 @@ func decodeImport(
ret.DescMem, err = decodeMemory(r, enabledFeatures, memorySizer, memoryLimitPages)
case wasm.ExternTypeGlobal:
ret.DescGlobal, err = decodeGlobalType(r)
case wasm.ExternTypeTag:
if err = enabledFeatures.RequireEnabled(api.CoreFeatureSIMD << 4); err != nil { // CoreFeaturesExceptionHandling
err = fmt.Errorf("tag imports require exception handling feature: %w", err)
break
}
// Tag import: read attribute byte (must be 0x00) then type index.
var attr byte
attr, err = r.ReadByte()
if err != nil {
break
}
if attr != 0x00 {
err = fmt.Errorf("invalid tag attribute: %#x", attr)
break
}
ret.DescTag, _, err = leb128.DecodeUint32(r)
default:
err = fmt.Errorf("%w: invalid byte for importdesc: %#x", ErrInvalidByte, b)
}
+86 -3
View File
@@ -16,15 +16,70 @@ func decodeTypeSection(enabledFeatures api.CoreFeatures, r *bytes.Reader) ([]was
return nil, fmt.Errorf("get size of vector: %w", err)
}
result := make([]wasm.FunctionType, vs)
var result []wasm.FunctionType
for i := uint32(0); i < vs; i++ {
if err = decodeFunctionType(enabledFeatures, r, &result[i]); err != nil {
// Peek at the leading byte to check for rec group (0x4e, GC proposal).
b, err := r.ReadByte()
if err != nil {
return nil, fmt.Errorf("read %d-th type: %v", i, err)
}
if b == 0x4e {
// Rec group: contains multiple types.
recCount, _, err := leb128.DecodeUint32(r)
if err != nil {
return nil, fmt.Errorf("read rec group count: %v", err)
}
startIdx := uint32(len(result))
for j := uint32(0); j < recCount; j++ {
var ft wasm.FunctionType
if err = decodeFunctionType(enabledFeatures, r, &ft); err != nil {
return nil, fmt.Errorf("read %d-th type in rec group: %v", j, err)
}
ft.RecGroupSize = int(recCount)
ft.RecGroupPosition = int(j)
result = append(result, ft)
}
for j := uint32(0); j < recCount; j++ {
if err := validateTypeForwardRefs(&result[startIdx+j], startIdx+recCount); err != nil {
return nil, err
}
}
} else {
// Put back the byte and decode as a regular function type.
if err := r.UnreadByte(); err != nil {
return nil, err
}
var ft wasm.FunctionType
if err = decodeFunctionType(enabledFeatures, r, &ft); err != nil {
return nil, fmt.Errorf("read %d-th type: %v", i, err)
}
if err := validateTypeForwardRefs(&ft, uint32(len(result))); err != nil {
return nil, err
}
result = append(result, ft)
}
}
return result, nil
}
// validateTypeForwardRefs rejects concrete reference types (ref $t) whose type
// index is not yet defined. For standalone types, maxTypeIndex is the count of
// types decoded so far; for rec groups, it is the index after the last member,
// allowing mutual references within the group.
func validateTypeForwardRefs(ft *wasm.FunctionType, maxTypeIndex uint32) error {
for i, vt := range ft.Params {
if vt.IsConcreteRef() && vt.TypeIndex() >= maxTypeIndex {
return fmt.Errorf("unknown type index %d in param[%d]", vt.TypeIndex(), i)
}
}
for i, vt := range ft.Results {
if vt.IsConcreteRef() && vt.TypeIndex() >= maxTypeIndex {
return fmt.Errorf("unknown type index %d in result[%d]", vt.TypeIndex(), i)
}
}
return nil
}
// decodeImportSection decodes the decoded import segments plus the count per wasm.ExternType.
func decodeImportSection(
r *bytes.Reader,
@@ -33,7 +88,7 @@ func decodeImportSection(
enabledFeatures api.CoreFeatures,
) (result []wasm.Import,
perModule map[string][]*wasm.Import,
funcCount, globalCount, memoryCount, tableCount wasm.Index, err error,
funcCount, globalCount, memoryCount, tableCount, tagCount wasm.Index, err error,
) {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
@@ -61,6 +116,9 @@ func decodeImportSection(
case wasm.ExternTypeTable:
imp.IndexPerType = tableCount
tableCount++
case wasm.ExternTypeTag:
imp.IndexPerType = tagCount
tagCount++
}
perModule[imp.Module] = append(perModule[imp.Module], imp)
}
@@ -216,6 +274,31 @@ func decodeDataSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]was
return result, nil
}
func decodeTagSection(r *bytes.Reader) ([]wasm.Tag, error) {
vs, _, err := leb128.DecodeUint32(r)
if err != nil {
return nil, fmt.Errorf("get size of vector: %w", err)
}
result := make([]wasm.Tag, vs)
for i := uint32(0); i < vs; i++ {
// Read attribute byte (must be 0x00 per spec).
attr, err := r.ReadByte()
if err != nil {
return nil, fmt.Errorf("read tag[%d] attribute: %w", i, err)
}
if attr != 0x00 {
return nil, fmt.Errorf("tag[%d] has invalid attribute: %#x", i, attr)
}
// Read type index.
result[i].Type, _, err = leb128.DecodeUint32(r)
if err != nil {
return nil, fmt.Errorf("read tag[%d] type index: %w", i, err)
}
}
return result, nil
}
func decodeDataCountSection(r *bytes.Reader) (count *uint32, err error) {
v, _, err := leb128.DecodeUint32(r)
if err != nil && err != io.EOF {
+37 -1
View File
@@ -12,11 +12,39 @@ import (
//
// 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()
b, err := r.ReadByte()
if err != nil {
return fmt.Errorf("read leading byte: %v", err)
}
hasInitExpr := false
if b == 0x40 {
// Table with initializer expression: 0x40 0x00 tabletype expr
reserved, err := r.ReadByte()
if err != nil {
return fmt.Errorf("read reserved byte after 0x40: %v", err)
}
if reserved != 0x00 {
return fmt.Errorf("expected 0x00 after 0x40 table prefix, got 0x%02x", reserved)
}
hasInitExpr = true
b, err = r.ReadByte()
if err != nil {
return fmt.Errorf("read table ref type: %v", err)
}
}
switch b {
case wasm.RefPrefixNullable, wasm.RefPrefixNonNullable:
vt, err := decodeRefType(r, b == wasm.RefPrefixNullable)
if err != nil {
return err
}
ret.Type = vt
default:
ret.Type = wasm.ValueType(b)
}
if ret.Type != wasm.RefTypeFuncref {
if err = enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
return fmt.Errorf("table type funcref is invalid: %w", err)
@@ -39,5 +67,13 @@ func decodeTable(r *bytes.Reader, enabledFeatures api.CoreFeatures, ret *wasm.Ta
if shared {
return fmt.Errorf("tables cannot be marked as shared")
}
if hasInitExpr {
var initExpr wasm.ConstantExpression
if err := decodeConstantExpression(r, enabledFeatures, &initExpr); err != nil {
return fmt.Errorf("read table init expr: %v", err)
}
ret.InitExpr = &initExpr
}
return
}
+49 -11
View File
@@ -16,23 +16,61 @@ func decodeValueTypes(r *bytes.Reader, num uint32) ([]wasm.ValueType, error) {
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:
ret := make([]wasm.ValueType, 0, num)
for i := uint32(0); i < num; i++ {
b, err := r.ReadByte()
if err != nil {
return nil, err
}
switch b {
case wasm.ValueTypeI32.Kind(), wasm.ValueTypeF32.Kind(), wasm.ValueTypeI64.Kind(), wasm.ValueTypeF64.Kind(),
wasm.ValueTypeExternref.Kind(), wasm.ValueTypeFuncref.Kind(), wasm.ValueTypeV128.Kind(),
wasm.ValueTypeExnref.Kind():
ret = append(ret, wasm.ValueType(b))
case wasm.RefPrefixNullable, wasm.RefPrefixNonNullable:
vt, err := decodeRefType(r, b == wasm.RefPrefixNullable)
if err != nil {
return nil, err
}
ret = append(ret, vt)
default:
return nil, fmt.Errorf("invalid value type: %d", v)
return nil, fmt.Errorf("invalid value type: %d", b)
}
}
return ret, nil
}
// decodeRefType decodes a heap type from r and returns the corresponding
// ValueType with the given nullability. Abstract nullable refs are desugared
// to their short forms:
// - (ref null func) -> funcref
// - (ref null extern) -> externref
// - (ref null exn) -> exnref
func decodeRefType(r *bytes.Reader, nullable bool) (wasm.ValueType, error) {
ht, _, err := leb128.DecodeInt33AsInt64(r)
if err != nil {
return 0, fmt.Errorf("read ref heap type: %w", err)
}
var vt wasm.ValueType
switch ht {
case wasm.HeapTypeFunc:
vt = wasm.ValueTypeFuncref
case wasm.HeapTypeExtern:
vt = wasm.ValueTypeExternref
case wasm.HeapTypeExn:
vt = wasm.ValueTypeExnref
default:
if ht < 0 {
return 0, fmt.Errorf("unknown abstract heap type: %d", ht)
}
vt = wasm.ValueTypeConcreteRef(uint32(ht), nullable)
}
if !nullable {
vt = vt.AsNonNullable()
}
return vt, 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) {