updated vendor
This commit is contained in:
+28
-4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user