This commit implements the v128.const, i32x4.add and i64x2.add in interpreter mode and this adds support for the vector value types in the locals and globals. Notably, the vector type values can be passed and returned by exported functions as well as host functions via two-uint64 encodings as described in #484 (comment). Note: implementation of these instructions on JIT will be done in subsequent PR. part of #484 Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
183 lines
5.1 KiB
Go
183 lines
5.1 KiB
Go
package binary
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/tetratelabs/wazero/internal/testing/require"
|
|
"github.com/tetratelabs/wazero/internal/wasm"
|
|
)
|
|
|
|
// TestDecodeModule relies on unit tests for Module.Encode, specifically that the encoding is both known and correct.
|
|
// This avoids having to copy/paste or share variables to assert against byte arrays.
|
|
func TestDecodeModule(t *testing.T) {
|
|
i32, f32 := wasm.ValueTypeI32, wasm.ValueTypeF32
|
|
zero := uint32(0)
|
|
|
|
tests := []struct {
|
|
name string
|
|
input *wasm.Module // round trip test!
|
|
}{
|
|
{
|
|
name: "empty",
|
|
input: &wasm.Module{},
|
|
},
|
|
{
|
|
name: "only name section",
|
|
input: &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "simple"}},
|
|
},
|
|
{
|
|
name: "type section",
|
|
input: &wasm.Module{
|
|
TypeSection: []*wasm.FunctionType{
|
|
{},
|
|
{Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32},
|
|
ParamNumInUint64: 2,
|
|
ResultNumInUint64: 1,
|
|
},
|
|
{Params: []wasm.ValueType{i32, i32, i32, i32}, Results: []wasm.ValueType{i32},
|
|
ParamNumInUint64: 4,
|
|
ResultNumInUint64: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "type and import section",
|
|
input: &wasm.Module{
|
|
TypeSection: []*wasm.FunctionType{
|
|
{Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32},
|
|
ParamNumInUint64: 2,
|
|
ResultNumInUint64: 1,
|
|
},
|
|
{Params: []wasm.ValueType{f32, f32}, Results: []wasm.ValueType{f32},
|
|
ParamNumInUint64: 2,
|
|
ResultNumInUint64: 1,
|
|
},
|
|
},
|
|
ImportSection: []*wasm.Import{
|
|
{
|
|
Module: "Math", Name: "Mul",
|
|
Type: wasm.ExternTypeFunc,
|
|
DescFunc: 1,
|
|
}, {
|
|
Module: "Math", Name: "Add",
|
|
Type: wasm.ExternTypeFunc,
|
|
DescFunc: 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "table and memory section",
|
|
input: &wasm.Module{
|
|
TableSection: []*wasm.Table{{Min: 3, Type: wasm.RefTypeFuncref}},
|
|
MemorySection: &wasm.Memory{Min: 1, Cap: 1, Max: 1, IsMaxEncoded: true},
|
|
},
|
|
},
|
|
{
|
|
name: "type function and start section",
|
|
input: &wasm.Module{
|
|
TypeSection: []*wasm.FunctionType{{}},
|
|
ImportSection: []*wasm.Import{{
|
|
Module: "", Name: "hello",
|
|
Type: wasm.ExternTypeFunc,
|
|
DescFunc: 0,
|
|
}},
|
|
StartSection: &zero,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
m, e := DecodeModule(EncodeModule(tc.input), wasm.Features20191205, wasm.MemorySizer)
|
|
require.NoError(t, e)
|
|
require.Equal(t, tc.input, m)
|
|
})
|
|
}
|
|
|
|
t.Run("skips custom section", func(t *testing.T) {
|
|
input := append(append(Magic, version...),
|
|
wasm.SectionIDCustom, 0xf, // 15 bytes in this section
|
|
0x04, 'm', 'e', 'm', 'e',
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
|
|
m, e := DecodeModule(input, wasm.Features20191205, wasm.MemorySizer)
|
|
require.NoError(t, e)
|
|
require.Equal(t, &wasm.Module{}, m)
|
|
})
|
|
|
|
t.Run("skips custom section, but not name", func(t *testing.T) {
|
|
input := append(append(Magic, version...),
|
|
wasm.SectionIDCustom, 0xf, // 15 bytes in this section
|
|
0x04, 'm', 'e', 'm', 'e',
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
|
|
wasm.SectionIDCustom, 0x0e, // 14 bytes in this section
|
|
0x04, 'n', 'a', 'm', 'e',
|
|
subsectionIDModuleName, 0x07, // 7 bytes in this subsection
|
|
0x06, // the Module name simple is 6 bytes long
|
|
's', 'i', 'm', 'p', 'l', 'e')
|
|
m, e := DecodeModule(input, wasm.Features20191205, wasm.MemorySizer)
|
|
require.NoError(t, e)
|
|
require.Equal(t, &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "simple"}}, m)
|
|
})
|
|
t.Run("data count section disabled", func(t *testing.T) {
|
|
input := append(append(Magic, version...),
|
|
wasm.SectionIDDataCount, 1, 0)
|
|
_, e := DecodeModule(input, wasm.Features20191205, wasm.MemorySizer)
|
|
require.EqualError(t, e, `data count section not supported as feature "bulk-memory-operations" is disabled`)
|
|
})
|
|
}
|
|
|
|
func TestDecodeModule_Errors(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input []byte
|
|
expectedErr string
|
|
}{
|
|
{
|
|
name: "wrong magic",
|
|
input: []byte("wasm\x01\x00\x00\x00"),
|
|
expectedErr: "invalid magic number",
|
|
},
|
|
{
|
|
name: "wrong version",
|
|
input: []byte("\x00asm\x01\x00\x00\x01"),
|
|
expectedErr: "invalid version header",
|
|
},
|
|
{
|
|
name: "multiple start sections",
|
|
input: append(append(Magic, version...),
|
|
wasm.SectionIDType, 4, 1, 0x60, 0, 0,
|
|
wasm.SectionIDFunction, 2, 1, 0,
|
|
wasm.SectionIDCode, 4, 1,
|
|
2, 0, wasm.OpcodeEnd,
|
|
wasm.SectionIDStart, 1, 0,
|
|
wasm.SectionIDStart, 1, 0,
|
|
),
|
|
expectedErr: `multiple start sections are invalid`,
|
|
},
|
|
{
|
|
name: "redundant name section",
|
|
input: append(append(Magic, version...),
|
|
wasm.SectionIDCustom, 0x09, // 9 bytes in this section
|
|
0x04, 'n', 'a', 'm', 'e',
|
|
subsectionIDModuleName, 0x02, 0x01, 'x',
|
|
wasm.SectionIDCustom, 0x09, // 9 bytes in this section
|
|
0x04, 'n', 'a', 'm', 'e',
|
|
subsectionIDModuleName, 0x02, 0x01, 'x'),
|
|
expectedErr: "section custom: redundant custom section name",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, e := DecodeModule(tc.input, wasm.Features20191205, wasm.MemorySizer)
|
|
require.EqualError(t, e, tc.expectedErr)
|
|
})
|
|
}
|
|
}
|