add ieee754 and leb128 byte slice funcs (#837)
Signed-off-by: Clifton Kaznocha <ckaznocha@users.noreply.github.com>
This commit is contained in:
@@ -8,24 +8,22 @@ import (
|
|||||||
|
|
||||||
// DecodeFloat32 decodes a float32 in IEEE 754 binary representation.
|
// DecodeFloat32 decodes a float32 in IEEE 754 binary representation.
|
||||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#floating-point%E2%91%A2
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#floating-point%E2%91%A2
|
||||||
func DecodeFloat32(r io.Reader) (float32, error) {
|
func DecodeFloat32(buf []byte) (float32, error) {
|
||||||
buf := make([]byte, 4)
|
if len(buf) < 4 {
|
||||||
_, err := io.ReadFull(r, buf)
|
return 0, io.ErrUnexpectedEOF
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
raw := binary.LittleEndian.Uint32(buf)
|
|
||||||
|
raw := binary.LittleEndian.Uint32(buf[:4])
|
||||||
return math.Float32frombits(raw), nil
|
return math.Float32frombits(raw), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeFloat64 decodes a float64 in IEEE 754 binary representation.
|
// DecodeFloat64 decodes a float64 in IEEE 754 binary representation.
|
||||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#floating-point%E2%91%A2
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#floating-point%E2%91%A2
|
||||||
func DecodeFloat64(r io.Reader) (float64, error) {
|
func DecodeFloat64(buf []byte) (float64, error) {
|
||||||
buf := make([]byte, 8)
|
if len(buf) < 8 {
|
||||||
_, err := io.ReadFull(r, buf)
|
return 0, io.ErrUnexpectedEOF
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
raw := binary.LittleEndian.Uint64(buf)
|
raw := binary.LittleEndian.Uint64(buf)
|
||||||
return math.Float64frombits(raw), nil
|
return math.Float64frombits(raw), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,25 @@
|
|||||||
package leb128
|
package leb128
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
maxVarintLen32 = 5
|
maxVarintLen32 = 5
|
||||||
|
maxVarintLen33 = maxVarintLen32
|
||||||
maxVarintLen64 = 10
|
maxVarintLen64 = 10
|
||||||
|
|
||||||
|
int33Mask int64 = 1 << 7
|
||||||
|
int33Mask2 = ^int33Mask
|
||||||
|
int33Mask3 = 1 << 6
|
||||||
|
int33Mask4 = 8589934591 // 2^33-1
|
||||||
|
int33Mask5 = 1 << 32
|
||||||
|
int33Mask6 = int33Mask4 + 1 // 2^33
|
||||||
|
|
||||||
|
int64Mask3 = 1 << 6
|
||||||
|
int64Mask4 = ^0
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -98,12 +109,37 @@ func EncodeUint64(value uint64) (buf []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeUint32(r *bytes.Reader) (ret uint32, bytesRead uint64, err error) {
|
type nextByte interface {
|
||||||
|
next(i int) (byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type byteSliceNext []byte
|
||||||
|
|
||||||
|
func (n byteSliceNext) next(i int) (byte, error) {
|
||||||
|
if i >= len(n) {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
return n[i], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type byteReaderNext struct{ io.ByteReader }
|
||||||
|
|
||||||
|
func (n byteReaderNext) next(_ int) (byte, error) { return n.ReadByte() }
|
||||||
|
|
||||||
|
func DecodeUint32(r io.ByteReader) (ret uint32, bytesRead uint64, err error) {
|
||||||
|
return decodeUint32(byteReaderNext{r})
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadUint32(buf []byte) (ret uint32, bytesRead uint64, err error) {
|
||||||
|
return decodeUint32(byteSliceNext(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeUint32(buf nextByte) (ret uint32, bytesRead uint64, err error) {
|
||||||
// Derived from https://github.com/golang/go/blob/aafad20b617ee63d58fcd4f6e0d98fe27760678c/src/encoding/binary/varint.go
|
// Derived from https://github.com/golang/go/blob/aafad20b617ee63d58fcd4f6e0d98fe27760678c/src/encoding/binary/varint.go
|
||||||
// with the modification on the overflow handling tailored for 32-bits.
|
// with the modification on the overflow handling tailored for 32-bits.
|
||||||
var s uint32
|
var s uint32
|
||||||
for i := 0; i < maxVarintLen32; i++ {
|
for i := 0; i < maxVarintLen32; i++ {
|
||||||
b, err := r.ReadByte()
|
b, err := buf.next(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
@@ -120,14 +156,19 @@ func DecodeUint32(r *bytes.Reader) (ret uint32, bytesRead uint64, err error) {
|
|||||||
return 0, 0, errOverflow32
|
return 0, 0, errOverflow32
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeUint64(r *bytes.Reader) (ret uint64, bytesRead uint64, err error) {
|
func LoadUint64(buf []byte) (ret uint64, bytesRead uint64, err error) {
|
||||||
|
bufLen := len(buf)
|
||||||
|
if bufLen == 0 {
|
||||||
|
return 0, 0, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
// Derived from https://github.com/golang/go/blob/aafad20b617ee63d58fcd4f6e0d98fe27760678c/src/encoding/binary/varint.go
|
// Derived from https://github.com/golang/go/blob/aafad20b617ee63d58fcd4f6e0d98fe27760678c/src/encoding/binary/varint.go
|
||||||
var s uint64
|
var s uint64
|
||||||
for i := 0; i < maxVarintLen64; i++ {
|
for i := 0; i < maxVarintLen64; i++ {
|
||||||
b, err := r.ReadByte()
|
if i >= bufLen {
|
||||||
if err != nil {
|
return 0, 0, io.EOF
|
||||||
return 0, 0, err
|
|
||||||
}
|
}
|
||||||
|
b := buf[i]
|
||||||
if b < 0x80 {
|
if b < 0x80 {
|
||||||
// Unused bits (non first bit) must all be zero.
|
// Unused bits (non first bit) must all be zero.
|
||||||
if i == maxVarintLen64-1 && b > 1 {
|
if i == maxVarintLen64-1 && b > 1 {
|
||||||
@@ -141,11 +182,19 @@ func DecodeUint64(r *bytes.Reader) (ret uint64, bytesRead uint64, err error) {
|
|||||||
return 0, 0, errOverflow64
|
return 0, 0, errOverflow64
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeInt32(r *bytes.Reader) (ret int32, bytesRead uint64, err error) {
|
func DecodeInt32(r io.ByteReader) (ret int32, bytesRead uint64, err error) {
|
||||||
|
return decodeInt32(byteReaderNext{r})
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadInt32(buf []byte) (ret int32, bytesRead uint64, err error) {
|
||||||
|
return decodeInt32(byteSliceNext(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeInt32(buf nextByte) (ret int32, bytesRead uint64, err error) {
|
||||||
var shift int
|
var shift int
|
||||||
var b byte
|
var b byte
|
||||||
for {
|
for {
|
||||||
b, err = r.ReadByte()
|
b, err = buf.next(int(bytesRead))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, fmt.Errorf("readByte failed: %w", err)
|
return 0, 0, fmt.Errorf("readByte failed: %w", err)
|
||||||
}
|
}
|
||||||
@@ -158,11 +207,11 @@ func DecodeInt32(r *bytes.Reader) (ret int32, bytesRead uint64, err error) {
|
|||||||
}
|
}
|
||||||
// Over flow checks.
|
// Over flow checks.
|
||||||
// fixme: can be optimized.
|
// fixme: can be optimized.
|
||||||
if bytesRead > 5 {
|
if bytesRead > maxVarintLen32 {
|
||||||
return 0, 0, errOverflow32
|
return 0, 0, errOverflow32
|
||||||
} else if unused := b & 0b00110000; bytesRead == 5 && ret < 0 && unused != 0b00110000 {
|
} else if unused := b & 0b00110000; bytesRead == maxVarintLen32 && ret < 0 && unused != 0b00110000 {
|
||||||
return 0, 0, errOverflow32
|
return 0, 0, errOverflow32
|
||||||
} else if bytesRead == 5 && ret >= 0 && unused != 0x00 {
|
} else if bytesRead == maxVarintLen32 && ret >= 0 && unused != 0x00 {
|
||||||
return 0, 0, errOverflow32
|
return 0, 0, errOverflow32
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -174,15 +223,7 @@ func DecodeInt32(r *bytes.Reader) (ret int32, bytesRead uint64, err error) {
|
|||||||
// still needs to fit the 32-bit range of allowed indices. Hence, this is 33, not 32-bit!
|
// still needs to fit the 32-bit range of allowed indices. Hence, this is 33, not 32-bit!
|
||||||
//
|
//
|
||||||
// See https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions
|
// See https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions
|
||||||
func DecodeInt33AsInt64(r *bytes.Reader) (ret int64, bytesRead uint64, err error) {
|
func DecodeInt33AsInt64(r io.ByteReader) (ret int64, bytesRead uint64, err error) {
|
||||||
const (
|
|
||||||
int33Mask int64 = 1 << 7
|
|
||||||
int33Mask2 = ^int33Mask
|
|
||||||
int33Mask3 = 1 << 6
|
|
||||||
int33Mask4 = 8589934591 // 2^33-1
|
|
||||||
int33Mask5 = 1 << 32
|
|
||||||
int33Mask6 = int33Mask4 + 1 // 2^33
|
|
||||||
)
|
|
||||||
var shift int
|
var shift int
|
||||||
var b int64
|
var b int64
|
||||||
var rb byte
|
var rb byte
|
||||||
@@ -212,25 +253,29 @@ func DecodeInt33AsInt64(r *bytes.Reader) (ret int64, bytesRead uint64, err error
|
|||||||
}
|
}
|
||||||
// Over flow checks.
|
// Over flow checks.
|
||||||
// fixme: can be optimized.
|
// fixme: can be optimized.
|
||||||
if bytesRead > 5 {
|
if bytesRead > maxVarintLen33 {
|
||||||
return 0, 0, errOverflow33
|
return 0, 0, errOverflow33
|
||||||
} else if unused := b & 0b00100000; bytesRead == 5 && ret < 0 && unused != 0b00100000 {
|
} else if unused := b & 0b00100000; bytesRead == maxVarintLen33 && ret < 0 && unused != 0b00100000 {
|
||||||
return 0, 0, errOverflow33
|
return 0, 0, errOverflow33
|
||||||
} else if bytesRead == 5 && ret >= 0 && unused != 0x00 {
|
} else if bytesRead == maxVarintLen33 && ret >= 0 && unused != 0x00 {
|
||||||
return 0, 0, errOverflow33
|
return 0, 0, errOverflow33
|
||||||
}
|
}
|
||||||
return ret, bytesRead, nil
|
return ret, bytesRead, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeInt64(r *bytes.Reader) (ret int64, bytesRead uint64, err error) {
|
func DecodeInt64(r io.ByteReader) (ret int64, bytesRead uint64, err error) {
|
||||||
const (
|
return decodeInt64(byteReaderNext{r})
|
||||||
int64Mask3 = 1 << 6
|
}
|
||||||
int64Mask4 = ^0
|
|
||||||
)
|
func LoadInt64(buf []byte) (ret int64, bytesRead uint64, err error) {
|
||||||
|
return decodeInt64(byteSliceNext(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeInt64(buf nextByte) (ret int64, bytesRead uint64, err error) {
|
||||||
var shift int
|
var shift int
|
||||||
var b byte
|
var b byte
|
||||||
for {
|
for {
|
||||||
b, err = r.ReadByte()
|
b, err = buf.next(int(bytesRead))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, fmt.Errorf("readByte failed: %w", err)
|
return 0, 0, fmt.Errorf("readByte failed: %w", err)
|
||||||
}
|
}
|
||||||
@@ -243,11 +288,11 @@ func DecodeInt64(r *bytes.Reader) (ret int64, bytesRead uint64, err error) {
|
|||||||
}
|
}
|
||||||
// Over flow checks.
|
// Over flow checks.
|
||||||
// fixme: can be optimized.
|
// fixme: can be optimized.
|
||||||
if bytesRead > 10 {
|
if bytesRead > maxVarintLen64 {
|
||||||
return 0, 0, errOverflow64
|
return 0, 0, errOverflow64
|
||||||
} else if unused := b & 0b00111110; bytesRead == 10 && ret < 0 && unused != 0b00111110 {
|
} else if unused := b & 0b00111110; bytesRead == maxVarintLen64 && ret < 0 && unused != 0b00111110 {
|
||||||
return 0, 0, errOverflow64
|
return 0, 0, errOverflow64
|
||||||
} else if bytesRead == 10 && ret >= 0 && unused != 0x00 {
|
} else if bytesRead == maxVarintLen64 && ret >= 0 && unused != 0x00 {
|
||||||
return 0, 0, errOverflow64
|
return 0, 0, errOverflow64
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func TestEncode_DecodeInt32(t *testing.T) {
|
|||||||
{input: int32(math.MaxInt32), expected: []byte{0xff, 0xff, 0xff, 0xff, 0x7}},
|
{input: int32(math.MaxInt32), expected: []byte{0xff, 0xff, 0xff, 0xff, 0x7}},
|
||||||
} {
|
} {
|
||||||
require.Equal(t, c.expected, EncodeInt32(c.input))
|
require.Equal(t, c.expected, EncodeInt32(c.input))
|
||||||
decoded, _, err := DecodeInt32(bytes.NewReader(c.expected))
|
decoded, _, err := LoadInt32(c.expected)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, c.input, decoded)
|
require.Equal(t, c.input, decoded)
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ func TestEncode_DecodeInt64(t *testing.T) {
|
|||||||
{input: math.MaxInt64, expected: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0}},
|
{input: math.MaxInt64, expected: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0}},
|
||||||
} {
|
} {
|
||||||
require.Equal(t, c.expected, EncodeInt64(c.input))
|
require.Equal(t, c.expected, EncodeInt64(c.input))
|
||||||
decoded, _, err := DecodeInt64(bytes.NewReader(c.expected))
|
decoded, _, err := LoadInt64(c.expected)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, c.input, decoded)
|
require.Equal(t, c.input, decoded)
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ func TestDecodeUint32(t *testing.T) {
|
|||||||
{bytes: []byte{0x82, 0x80, 0x80, 0x80, 0x70}, expErr: true},
|
{bytes: []byte{0x82, 0x80, 0x80, 0x80, 0x70}, expErr: true},
|
||||||
{bytes: []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, expErr: true},
|
{bytes: []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, expErr: true},
|
||||||
} {
|
} {
|
||||||
actual, num, err := DecodeUint32(bytes.NewReader(c.bytes))
|
actual, num, err := LoadUint32(c.bytes)
|
||||||
if c.expErr {
|
if c.expErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
} else {
|
} else {
|
||||||
@@ -140,7 +140,7 @@ func TestDecodeUint64(t *testing.T) {
|
|||||||
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1}, exp: math.MaxUint64},
|
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1}, exp: math.MaxUint64},
|
||||||
{bytes: []byte{0x89, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x71}, expErr: true},
|
{bytes: []byte{0x89, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x71}, expErr: true},
|
||||||
} {
|
} {
|
||||||
actual, num, err := DecodeUint64(bytes.NewReader(c.bytes))
|
actual, num, err := LoadUint64(c.bytes)
|
||||||
if c.expErr {
|
if c.expErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
} else {
|
} else {
|
||||||
@@ -169,7 +169,7 @@ func TestDecodeInt32(t *testing.T) {
|
|||||||
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0x4f}, expErr: true},
|
{bytes: []byte{0xff, 0xff, 0xff, 0xff, 0x4f}, expErr: true},
|
||||||
{bytes: []byte{0x80, 0x80, 0x80, 0x80, 0x70}, expErr: true},
|
{bytes: []byte{0x80, 0x80, 0x80, 0x80, 0x70}, expErr: true},
|
||||||
} {
|
} {
|
||||||
actual, num, err := DecodeInt32(bytes.NewReader(c.bytes))
|
actual, num, err := LoadInt32(c.bytes)
|
||||||
if c.expErr {
|
if c.expErr {
|
||||||
require.Error(t, err, fmt.Sprintf("%d-th got value %d", i, actual))
|
require.Error(t, err, fmt.Sprintf("%d-th got value %d", i, actual))
|
||||||
} else {
|
} else {
|
||||||
@@ -220,7 +220,7 @@ func TestDecodeInt64(t *testing.T) {
|
|||||||
{bytes: []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f},
|
{bytes: []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f},
|
||||||
exp: -9223372036854775808},
|
exp: -9223372036854775808},
|
||||||
} {
|
} {
|
||||||
actual, num, err := DecodeInt64(bytes.NewReader(c.bytes))
|
actual, num, err := LoadInt64(c.bytes)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, c.exp, actual)
|
require.Equal(t, c.exp, actual)
|
||||||
require.Equal(t, uint64(len(c.bytes)), num)
|
require.Equal(t, uint64(len(c.bytes)), num)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package binary
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/tetratelabs/wazero/api"
|
"github.com/tetratelabs/wazero/api"
|
||||||
"github.com/tetratelabs/wazero/internal/ieee754"
|
"github.com/tetratelabs/wazero/internal/ieee754"
|
||||||
@@ -28,9 +29,17 @@ func decodeConstantExpression(r *bytes.Reader, enabledFeatures api.CoreFeatures)
|
|||||||
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
||||||
_, _, err = leb128.DecodeInt64(r)
|
_, _, err = leb128.DecodeInt64(r)
|
||||||
case wasm.OpcodeF32Const:
|
case wasm.OpcodeF32Const:
|
||||||
_, err = ieee754.DecodeFloat32(r)
|
buf := make([]byte, 4)
|
||||||
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||||||
|
return nil, fmt.Errorf("read f32 constant: %v", err)
|
||||||
|
}
|
||||||
|
_, err = ieee754.DecodeFloat32(buf)
|
||||||
case wasm.OpcodeF64Const:
|
case wasm.OpcodeF64Const:
|
||||||
_, err = ieee754.DecodeFloat64(r)
|
buf := make([]byte, 8)
|
||||||
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||||||
|
return nil, fmt.Errorf("read f64 constant: %v", err)
|
||||||
|
}
|
||||||
|
_, err = ieee754.DecodeFloat64(buf)
|
||||||
case wasm.OpcodeGlobalGet:
|
case wasm.OpcodeGlobalGet:
|
||||||
_, _, err = leb128.DecodeUint32(r)
|
_, _, err = leb128.DecodeUint32(r)
|
||||||
case wasm.OpcodeRefNull:
|
case wasm.OpcodeRefNull:
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func decodeElementConstExprVector(r *bytes.Reader, elemType wasm.RefType, enable
|
|||||||
if elemType != wasm.RefTypeFuncref {
|
if elemType != wasm.RefTypeFuncref {
|
||||||
return nil, fmt.Errorf("element type mismatch: want %s, but constexpr has funcref", wasm.RefTypeName(elemType))
|
return nil, fmt.Errorf("element type mismatch: want %s, but constexpr has funcref", wasm.RefTypeName(elemType))
|
||||||
}
|
}
|
||||||
v, _, _ := leb128.DecodeUint32(bytes.NewReader(expr.Data))
|
v, _, _ := leb128.LoadUint32(expr.Data)
|
||||||
vec[i] = &v
|
vec[i] = &v
|
||||||
case wasm.OpcodeRefNull:
|
case wasm.OpcodeRefNull:
|
||||||
if elemType != expr.Data[0] {
|
if elemType != expr.Data[0] {
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ func (m *Module) validateFunction(enabledFeatures api.CoreFeatures, idx Index, f
|
|||||||
}
|
}
|
||||||
|
|
||||||
func readMemArg(pc uint64, body []byte) (align, offset uint32, read uint64, err error) {
|
func readMemArg(pc uint64, body []byte) (align, offset uint32, read uint64, err error) {
|
||||||
align, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
align, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("read memory align: %v", err)
|
err = fmt.Errorf("read memory align: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
read += num
|
read += num
|
||||||
|
|
||||||
offset, num, err = leb128.DecodeUint32(bytes.NewReader(body[pc+num:]))
|
offset, num, err = leb128.LoadUint32(body[pc+num:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("read memory offset: %v", err)
|
err = fmt.Errorf("read memory offset: %v", err)
|
||||||
return
|
return
|
||||||
@@ -276,7 +276,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
return fmt.Errorf("memory must exist for %s", InstructionName(op))
|
return fmt.Errorf("memory must exist for %s", InstructionName(op))
|
||||||
}
|
}
|
||||||
pc++
|
pc++
|
||||||
val, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
val, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read immediate: %v", err)
|
return fmt.Errorf("read immediate: %v", err)
|
||||||
}
|
}
|
||||||
@@ -297,14 +297,14 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
pc++
|
pc++
|
||||||
switch Opcode(op) {
|
switch Opcode(op) {
|
||||||
case OpcodeI32Const:
|
case OpcodeI32Const:
|
||||||
_, num, err := leb128.DecodeInt32(bytes.NewReader(body[pc:]))
|
_, num, err := leb128.LoadInt32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read i32 immediate: %s", err)
|
return fmt.Errorf("read i32 immediate: %s", err)
|
||||||
}
|
}
|
||||||
pc += num - 1
|
pc += num - 1
|
||||||
valueTypeStack.push(ValueTypeI32)
|
valueTypeStack.push(ValueTypeI32)
|
||||||
case OpcodeI64Const:
|
case OpcodeI64Const:
|
||||||
_, num, err := leb128.DecodeInt64(bytes.NewReader(body[pc:]))
|
_, num, err := leb128.LoadInt64(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read i64 immediate: %v", err)
|
return fmt.Errorf("read i64 immediate: %v", err)
|
||||||
}
|
}
|
||||||
@@ -319,7 +319,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
}
|
}
|
||||||
} else if OpcodeLocalGet <= op && op <= OpcodeGlobalSet {
|
} else if OpcodeLocalGet <= op && op <= OpcodeGlobalSet {
|
||||||
pc++
|
pc++
|
||||||
index, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
index, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read immediate: %v", err)
|
return fmt.Errorf("read immediate: %v", err)
|
||||||
}
|
}
|
||||||
@@ -384,7 +384,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
}
|
}
|
||||||
} else if op == OpcodeBr {
|
} else if op == OpcodeBr {
|
||||||
pc++
|
pc++
|
||||||
index, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
index, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read immediate: %v", err)
|
return fmt.Errorf("read immediate: %v", err)
|
||||||
} else if int(index) >= len(controlBlockStack) {
|
} else if int(index) >= len(controlBlockStack) {
|
||||||
@@ -406,7 +406,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
valueTypeStack.unreachable()
|
valueTypeStack.unreachable()
|
||||||
} else if op == OpcodeBrIf {
|
} else if op == OpcodeBrIf {
|
||||||
pc++
|
pc++
|
||||||
index, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
index, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read immediate: %v", err)
|
return fmt.Errorf("read immediate: %v", err)
|
||||||
} else if int(index) >= len(controlBlockStack) {
|
} else if int(index) >= len(controlBlockStack) {
|
||||||
@@ -526,7 +526,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
valueTypeStack.unreachable()
|
valueTypeStack.unreachable()
|
||||||
} else if op == OpcodeCall {
|
} else if op == OpcodeCall {
|
||||||
pc++
|
pc++
|
||||||
index, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
index, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read immediate: %v", err)
|
return fmt.Errorf("read immediate: %v", err)
|
||||||
}
|
}
|
||||||
@@ -545,7 +545,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
}
|
}
|
||||||
} else if op == OpcodeCallIndirect {
|
} else if op == OpcodeCallIndirect {
|
||||||
pc++
|
pc++
|
||||||
typeIndex, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
typeIndex, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read immediate: %v", err)
|
return fmt.Errorf("read immediate: %v", err)
|
||||||
}
|
}
|
||||||
@@ -555,7 +555,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
return fmt.Errorf("invalid type index at %s: %d", OpcodeCallIndirectName, typeIndex)
|
return fmt.Errorf("invalid type index at %s: %d", OpcodeCallIndirectName, typeIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
tableIndex, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read table index: %v", err)
|
return fmt.Errorf("read table index: %v", err)
|
||||||
}
|
}
|
||||||
@@ -827,7 +827,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
valueTypeStack.push(ValueTypeI32)
|
valueTypeStack.push(ValueTypeI32)
|
||||||
case OpcodeRefFunc:
|
case OpcodeRefFunc:
|
||||||
pc++
|
pc++
|
||||||
index, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
index, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read function index for ref.func: %v", err)
|
return fmt.Errorf("failed to read function index for ref.func: %v", err)
|
||||||
}
|
}
|
||||||
@@ -842,7 +842,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
return fmt.Errorf("%s is invalid as %v", InstructionName(op), err)
|
return fmt.Errorf("%s is invalid as %v", InstructionName(op), err)
|
||||||
}
|
}
|
||||||
pc++
|
pc++
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
tableIndex, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read immediate: %v", err)
|
return fmt.Errorf("read immediate: %v", err)
|
||||||
}
|
}
|
||||||
@@ -903,7 +903,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
|
|
||||||
// We need to read the index to the data section.
|
// We need to read the index to the data section.
|
||||||
pc++
|
pc++
|
||||||
index, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
index, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
}
|
}
|
||||||
@@ -924,7 +924,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
|
|
||||||
// We need to read the index to the data section.
|
// We need to read the index to the data section.
|
||||||
pc++
|
pc++
|
||||||
index, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
index, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
}
|
}
|
||||||
@@ -935,7 +935,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pc++
|
pc++
|
||||||
val, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
val, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
}
|
}
|
||||||
@@ -945,7 +945,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
if miscOpcode == OpcodeMiscMemoryCopy {
|
if miscOpcode == OpcodeMiscMemoryCopy {
|
||||||
pc++
|
pc++
|
||||||
// memory.copy needs two memory index which are reserved as zero.
|
// memory.copy needs two memory index which are reserved as zero.
|
||||||
val, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
val, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
}
|
}
|
||||||
@@ -957,7 +957,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
case OpcodeMiscTableInit:
|
case OpcodeMiscTableInit:
|
||||||
params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
|
params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
|
||||||
pc++
|
pc++
|
||||||
elementIndex, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
elementIndex, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
}
|
}
|
||||||
@@ -966,7 +966,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
}
|
}
|
||||||
pc += num
|
pc += num
|
||||||
|
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
tableIndex, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
}
|
}
|
||||||
@@ -988,7 +988,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
pc += num - 1
|
pc += num - 1
|
||||||
case OpcodeMiscElemDrop:
|
case OpcodeMiscElemDrop:
|
||||||
pc++
|
pc++
|
||||||
elementIndex, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
elementIndex, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
} else if int(elementIndex) >= len(m.ElementSection) {
|
} else if int(elementIndex) >= len(m.ElementSection) {
|
||||||
@@ -999,7 +999,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
|
params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
|
||||||
pc++
|
pc++
|
||||||
|
|
||||||
dstTableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
dstTableIndex, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read destination table index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read destination table index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
}
|
}
|
||||||
@@ -1013,7 +1013,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
}
|
}
|
||||||
pc += num
|
pc += num
|
||||||
|
|
||||||
srcTableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
srcTableIndex, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
}
|
}
|
||||||
@@ -1044,7 +1044,7 @@ func (m *Module) validateFunctionWithMaxStackValues(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pc++
|
pc++
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(body[pc:]))
|
tableIndex, num, err := leb128.LoadUint32(body[pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read table index for %s: %v", MiscInstructionName(miscOpcode), err)
|
return fmt.Errorf("failed to read table index for %s: %v", MiscInstructionName(miscOpcode), err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -372,7 +373,7 @@ func (m *Module) declaredFunctionIndexes() (ret map[Index]struct{}, err error) {
|
|||||||
for i, g := range m.GlobalSection {
|
for i, g := range m.GlobalSection {
|
||||||
if g.Init.Opcode == OpcodeRefFunc {
|
if g.Init.Opcode == OpcodeRefFunc {
|
||||||
var index uint32
|
var index uint32
|
||||||
index, _, err = leb128.DecodeUint32(bytes.NewReader(g.Init.Data))
|
index, _, err = leb128.LoadUint32(g.Init.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("%s[%d] failed to initialize: %w", SectionIDName(SectionIDGlobal), i, err)
|
err = fmt.Errorf("%s[%d] failed to initialize: %w", SectionIDName(SectionIDGlobal), i, err)
|
||||||
return
|
return
|
||||||
@@ -480,36 +481,35 @@ func (m *Module) validateExports(enabledFeatures api.CoreFeatures, functions []I
|
|||||||
|
|
||||||
func validateConstExpression(globals []*GlobalType, numFuncs uint32, expr *ConstantExpression, expectedType ValueType) (err error) {
|
func validateConstExpression(globals []*GlobalType, numFuncs uint32, expr *ConstantExpression, expectedType ValueType) (err error) {
|
||||||
var actualType ValueType
|
var actualType ValueType
|
||||||
r := bytes.NewReader(expr.Data)
|
|
||||||
switch expr.Opcode {
|
switch expr.Opcode {
|
||||||
case OpcodeI32Const:
|
case OpcodeI32Const:
|
||||||
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
||||||
_, _, err = leb128.DecodeInt32(r)
|
_, _, err = leb128.LoadInt32(expr.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read i32: %w", err)
|
return fmt.Errorf("read i32: %w", err)
|
||||||
}
|
}
|
||||||
actualType = ValueTypeI32
|
actualType = ValueTypeI32
|
||||||
case OpcodeI64Const:
|
case OpcodeI64Const:
|
||||||
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
||||||
_, _, err = leb128.DecodeInt64(r)
|
_, _, err = leb128.LoadInt64(expr.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read i64: %w", err)
|
return fmt.Errorf("read i64: %w", err)
|
||||||
}
|
}
|
||||||
actualType = ValueTypeI64
|
actualType = ValueTypeI64
|
||||||
case OpcodeF32Const:
|
case OpcodeF32Const:
|
||||||
_, err = ieee754.DecodeFloat32(r)
|
_, err = ieee754.DecodeFloat32(expr.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read f32: %w", err)
|
return fmt.Errorf("read f32: %w", err)
|
||||||
}
|
}
|
||||||
actualType = ValueTypeF32
|
actualType = ValueTypeF32
|
||||||
case OpcodeF64Const:
|
case OpcodeF64Const:
|
||||||
_, err = ieee754.DecodeFloat64(r)
|
_, err = ieee754.DecodeFloat64(expr.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read f64: %w", err)
|
return fmt.Errorf("read f64: %w", err)
|
||||||
}
|
}
|
||||||
actualType = ValueTypeF64
|
actualType = ValueTypeF64
|
||||||
case OpcodeGlobalGet:
|
case OpcodeGlobalGet:
|
||||||
id, _, err := leb128.DecodeUint32(r)
|
id, _, err := leb128.LoadUint32(expr.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read index of global: %w", err)
|
return fmt.Errorf("read index of global: %w", err)
|
||||||
}
|
}
|
||||||
@@ -518,15 +518,16 @@ func validateConstExpression(globals []*GlobalType, numFuncs uint32, expr *Const
|
|||||||
}
|
}
|
||||||
actualType = globals[id].ValType
|
actualType = globals[id].ValType
|
||||||
case OpcodeRefNull:
|
case OpcodeRefNull:
|
||||||
reftype, err := r.ReadByte()
|
if len(expr.Data) == 0 {
|
||||||
if err != nil {
|
return fmt.Errorf("read reference type for ref.null: %w", io.ErrShortBuffer)
|
||||||
return fmt.Errorf("read reference type for ref.null: %w", err)
|
}
|
||||||
} else if reftype != RefTypeFuncref && reftype != RefTypeExternref {
|
reftype := expr.Data[0]
|
||||||
|
if reftype != RefTypeFuncref && reftype != RefTypeExternref {
|
||||||
return fmt.Errorf("invalid type for ref.null: 0x%x", reftype)
|
return fmt.Errorf("invalid type for ref.null: 0x%x", reftype)
|
||||||
}
|
}
|
||||||
actualType = reftype
|
actualType = reftype
|
||||||
case OpcodeRefFunc:
|
case OpcodeRefFunc:
|
||||||
index, _, err := leb128.DecodeUint32(r)
|
index, _, err := leb128.LoadUint32(expr.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read i32: %w", err)
|
return fmt.Errorf("read i32: %w", err)
|
||||||
} else if index >= numFuncs {
|
} else if index >= numFuncs {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package wasm
|
package wasm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -533,20 +532,19 @@ func errorInvalidImport(i *Import, idx int, err error) error {
|
|||||||
// Global initialization constant expression can only reference the imported globals.
|
// 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
|
// See the note on https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#constant-expressions%E2%91%A0
|
||||||
func executeConstExpression(importedGlobals []*GlobalInstance, expr *ConstantExpression) (v interface{}) {
|
func executeConstExpression(importedGlobals []*GlobalInstance, expr *ConstantExpression) (v interface{}) {
|
||||||
r := bytes.NewReader(expr.Data)
|
|
||||||
switch expr.Opcode {
|
switch expr.Opcode {
|
||||||
case OpcodeI32Const:
|
case OpcodeI32Const:
|
||||||
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
||||||
v, _, _ = leb128.DecodeInt32(r)
|
v, _, _ = leb128.LoadInt32(expr.Data)
|
||||||
case OpcodeI64Const:
|
case OpcodeI64Const:
|
||||||
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
||||||
v, _, _ = leb128.DecodeInt64(r)
|
v, _, _ = leb128.LoadInt64(expr.Data)
|
||||||
case OpcodeF32Const:
|
case OpcodeF32Const:
|
||||||
v, _ = ieee754.DecodeFloat32(r)
|
v, _ = ieee754.DecodeFloat32(expr.Data)
|
||||||
case OpcodeF64Const:
|
case OpcodeF64Const:
|
||||||
v, _ = ieee754.DecodeFloat64(r)
|
v, _ = ieee754.DecodeFloat64(expr.Data)
|
||||||
case OpcodeGlobalGet:
|
case OpcodeGlobalGet:
|
||||||
id, _, _ := leb128.DecodeUint32(r)
|
id, _, _ := leb128.LoadUint32(expr.Data)
|
||||||
g := importedGlobals[id]
|
g := importedGlobals[id]
|
||||||
switch g.Type.ValType {
|
switch g.Type.ValType {
|
||||||
case ValueTypeI32:
|
case ValueTypeI32:
|
||||||
@@ -573,7 +571,7 @@ func executeConstExpression(importedGlobals []*GlobalInstance, expr *ConstantExp
|
|||||||
// For ref.func const expression, we temporarily store the index as value,
|
// For ref.func const expression, we temporarily store the index as value,
|
||||||
// and if this is the const expr for global, the value will be further downed to
|
// and if this is the const expr for global, the value will be further downed to
|
||||||
// opaque pointer of the engine-specific compiled function.
|
// opaque pointer of the engine-specific compiled function.
|
||||||
v, _, _ = leb128.DecodeUint32(r)
|
v, _, _ = leb128.LoadUint32(expr.Data)
|
||||||
case OpcodeVecV128Const:
|
case OpcodeVecV128Const:
|
||||||
v = [2]uint64{binary.LittleEndian.Uint64(expr.Data[0:8]), binary.LittleEndian.Uint64(expr.Data[8:16])}
|
v = [2]uint64{binary.LittleEndian.Uint64(expr.Data[0:8]), binary.LittleEndian.Uint64(expr.Data[8:16])}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package wasm
|
package wasm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
@@ -185,7 +184,7 @@ func (m *Module) validateTable(enabledFeatures api.CoreFeatures, tables []*Table
|
|||||||
// global.get needs to be discovered during initialization
|
// global.get needs to be discovered during initialization
|
||||||
oc := elem.OffsetExpr.Opcode
|
oc := elem.OffsetExpr.Opcode
|
||||||
if oc == OpcodeGlobalGet {
|
if oc == OpcodeGlobalGet {
|
||||||
globalIdx, _, err := leb128.DecodeUint32(bytes.NewReader(elem.OffsetExpr.Data))
|
globalIdx, _, err := leb128.LoadUint32(elem.OffsetExpr.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s[%d] couldn't read global.get parameter: %w", SectionIDName(SectionIDElement), idx, err)
|
return nil, 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 {
|
} else if err = m.verifyImportGlobalI32(SectionIDElement, idx, globalIdx); err != nil {
|
||||||
@@ -199,7 +198,7 @@ func (m *Module) validateTable(enabledFeatures api.CoreFeatures, tables []*Table
|
|||||||
ret = append(ret, &validatedActiveElementSegment{opcode: oc, arg: globalIdx, init: elem.Init, tableIndex: elem.TableIndex})
|
ret = append(ret, &validatedActiveElementSegment{opcode: oc, arg: globalIdx, init: elem.Init, tableIndex: elem.TableIndex})
|
||||||
} else if oc == OpcodeI32Const {
|
} else if oc == OpcodeI32Const {
|
||||||
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
|
||||||
o, _, err := leb128.DecodeInt32(bytes.NewReader(elem.OffsetExpr.Data))
|
o, _, err := leb128.LoadInt32(elem.OffsetExpr.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s[%d] couldn't read i32.const parameter: %w", SectionIDName(SectionIDElement), idx, err)
|
return nil, fmt.Errorf("%s[%d] couldn't read i32.const parameter: %w", SectionIDName(SectionIDElement), idx, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -649,7 +649,7 @@ operatorSwitch:
|
|||||||
}
|
}
|
||||||
|
|
||||||
case wasm.OpcodeBr:
|
case wasm.OpcodeBr:
|
||||||
targetIndex, n, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
targetIndex, n, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read the target for br_if: %w", err)
|
return fmt.Errorf("read the target for br_if: %w", err)
|
||||||
}
|
}
|
||||||
@@ -674,7 +674,7 @@ operatorSwitch:
|
|||||||
// and can be safely removed.
|
// and can be safely removed.
|
||||||
c.markUnreachable()
|
c.markUnreachable()
|
||||||
case wasm.OpcodeBrIf:
|
case wasm.OpcodeBrIf:
|
||||||
targetIndex, n, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
targetIndex, n, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read the target for br_if: %w", err)
|
return fmt.Errorf("read the target for br_if: %w", err)
|
||||||
}
|
}
|
||||||
@@ -790,7 +790,7 @@ operatorSwitch:
|
|||||||
if index == nil {
|
if index == nil {
|
||||||
return fmt.Errorf("index does not exist for indirect function call")
|
return fmt.Errorf("index does not exist for indirect function call")
|
||||||
}
|
}
|
||||||
tableIndex, n, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
tableIndex, n, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read target for br_table: %w", err)
|
return fmt.Errorf("read target for br_table: %w", err)
|
||||||
}
|
}
|
||||||
@@ -1096,7 +1096,7 @@ operatorSwitch:
|
|||||||
&OperationMemoryGrow{},
|
&OperationMemoryGrow{},
|
||||||
)
|
)
|
||||||
case wasm.OpcodeI32Const:
|
case wasm.OpcodeI32Const:
|
||||||
val, num, err := leb128.DecodeInt32(bytes.NewReader(c.body[c.pc+1:]))
|
val, num, err := leb128.LoadInt32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1105,7 +1105,7 @@ operatorSwitch:
|
|||||||
&OperationConstI32{Value: uint32(val)},
|
&OperationConstI32{Value: uint32(val)},
|
||||||
)
|
)
|
||||||
case wasm.OpcodeI64Const:
|
case wasm.OpcodeI64Const:
|
||||||
val, num, err := leb128.DecodeInt64(bytes.NewReader(c.body[c.pc+1:]))
|
val, num, err := leb128.LoadInt64(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i64.const value: %v", err)
|
return fmt.Errorf("reading i64.const value: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1639,7 +1639,7 @@ operatorSwitch:
|
|||||||
)
|
)
|
||||||
case wasm.OpcodeRefFunc:
|
case wasm.OpcodeRefFunc:
|
||||||
c.pc++
|
c.pc++
|
||||||
index, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc:]))
|
index, num, err := leb128.LoadUint32(c.body[c.pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read function index for ref.func: %v", err)
|
return fmt.Errorf("failed to read function index for ref.func: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1659,7 +1659,7 @@ operatorSwitch:
|
|||||||
)
|
)
|
||||||
case wasm.OpcodeTableGet:
|
case wasm.OpcodeTableGet:
|
||||||
c.pc++
|
c.pc++
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc:]))
|
tableIndex, num, err := leb128.LoadUint32(c.body[c.pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read function index for table.get: %v", err)
|
return fmt.Errorf("failed to read function index for table.get: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1669,7 +1669,7 @@ operatorSwitch:
|
|||||||
)
|
)
|
||||||
case wasm.OpcodeTableSet:
|
case wasm.OpcodeTableSet:
|
||||||
c.pc++
|
c.pc++
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc:]))
|
tableIndex, num, err := leb128.LoadUint32(c.body[c.pc:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read function index for table.set: %v", err)
|
return fmt.Errorf("failed to read function index for table.set: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1714,7 +1714,7 @@ operatorSwitch:
|
|||||||
)
|
)
|
||||||
case wasm.OpcodeMiscMemoryInit:
|
case wasm.OpcodeMiscMemoryInit:
|
||||||
c.result.UsesMemory = true
|
c.result.UsesMemory = true
|
||||||
dataIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
dataIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1723,7 +1723,7 @@ operatorSwitch:
|
|||||||
&OperationMemoryInit{DataIndex: dataIndex},
|
&OperationMemoryInit{DataIndex: dataIndex},
|
||||||
)
|
)
|
||||||
case wasm.OpcodeMiscDataDrop:
|
case wasm.OpcodeMiscDataDrop:
|
||||||
dataIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
dataIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1744,13 +1744,13 @@ operatorSwitch:
|
|||||||
&OperationMemoryFill{},
|
&OperationMemoryFill{},
|
||||||
)
|
)
|
||||||
case wasm.OpcodeMiscTableInit:
|
case wasm.OpcodeMiscTableInit:
|
||||||
elemIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
elemIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
c.pc += num
|
c.pc += num
|
||||||
// Read table index which is fixed to zero currently.
|
// Read table index which is fixed to zero currently.
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
tableIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1759,7 +1759,7 @@ operatorSwitch:
|
|||||||
&OperationTableInit{ElemIndex: elemIndex, TableIndex: tableIndex},
|
&OperationTableInit{ElemIndex: elemIndex, TableIndex: tableIndex},
|
||||||
)
|
)
|
||||||
case wasm.OpcodeMiscElemDrop:
|
case wasm.OpcodeMiscElemDrop:
|
||||||
elemIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
elemIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1769,13 +1769,13 @@ operatorSwitch:
|
|||||||
)
|
)
|
||||||
case wasm.OpcodeMiscTableCopy:
|
case wasm.OpcodeMiscTableCopy:
|
||||||
// Read the source table inde.g.
|
// Read the source table inde.g.
|
||||||
dst, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
dst, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
c.pc += num
|
c.pc += num
|
||||||
// Read the destination table inde.g.
|
// Read the destination table inde.g.
|
||||||
src, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
src, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
@@ -1786,7 +1786,7 @@ operatorSwitch:
|
|||||||
)
|
)
|
||||||
case wasm.OpcodeMiscTableGrow:
|
case wasm.OpcodeMiscTableGrow:
|
||||||
// Read the source table inde.g.
|
// Read the source table inde.g.
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
tableIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1796,7 +1796,7 @@ operatorSwitch:
|
|||||||
)
|
)
|
||||||
case wasm.OpcodeMiscTableSize:
|
case wasm.OpcodeMiscTableSize:
|
||||||
// Read the source table inde.g.
|
// Read the source table inde.g.
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
tableIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1806,7 +1806,7 @@ operatorSwitch:
|
|||||||
)
|
)
|
||||||
case wasm.OpcodeMiscTableFill:
|
case wasm.OpcodeMiscTableFill:
|
||||||
// Read the source table index.
|
// Read the source table index.
|
||||||
tableIndex, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
tableIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading i32.const value: %v", err)
|
return fmt.Errorf("reading i32.const value: %v", err)
|
||||||
}
|
}
|
||||||
@@ -2936,7 +2936,7 @@ func (c *compiler) applyToStack(opcode wasm.Opcode) (*uint32, error) {
|
|||||||
wasm.OpcodeGlobalGet,
|
wasm.OpcodeGlobalGet,
|
||||||
wasm.OpcodeGlobalSet:
|
wasm.OpcodeGlobalSet:
|
||||||
// Assumes that we are at the opcode now so skip it before read immediates.
|
// Assumes that we are at the opcode now so skip it before read immediates.
|
||||||
v, num, err := leb128.DecodeUint32(bytes.NewReader(c.body[c.pc+1:]))
|
v, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("reading immediates: %w", err)
|
return nil, fmt.Errorf("reading immediates: %w", err)
|
||||||
}
|
}
|
||||||
@@ -3117,13 +3117,12 @@ func (c *compiler) stackLenInUint64(ceil int) (ret int) {
|
|||||||
|
|
||||||
func (c *compiler) readMemoryArg(tag string) (*MemoryArg, error) {
|
func (c *compiler) readMemoryArg(tag string) (*MemoryArg, error) {
|
||||||
c.result.UsesMemory = true
|
c.result.UsesMemory = true
|
||||||
r := bytes.NewReader(c.body[c.pc+1:])
|
alignment, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
alignment, num, err := leb128.DecodeUint32(r)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("reading alignment for %s: %w", tag, err)
|
return nil, fmt.Errorf("reading alignment for %s: %w", tag, err)
|
||||||
}
|
}
|
||||||
c.pc += num
|
c.pc += num
|
||||||
offset, num, err := leb128.DecodeUint32(r)
|
offset, num, err := leb128.LoadUint32(c.body[c.pc+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("reading offset for %s: %w", tag, err)
|
return nil, fmt.Errorf("reading offset for %s: %w", tag, err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user