While compilers should be conservative when targeting WebAssembly Core features, runtimes should be lenient as otherwise people need to constantly turn on all features. Currently, most examples have to turn on 2.0 features because compilers such as AssemblyScript and TinyGo use them by default. This matches the policy with the reality, and should make first time use easier. This top-levels an internal type as `api.CoreFeatures` and defaults to 2.0 as opposed to 1.0, our previous default. This is less cluttered than the excess of `WithXXX` methods we had prior to implementing all planned WebAssembly Core Specification 1.0 features. Finally, this backfills rationale as flat config types were a distinct decision even if feature set selection muddied the topic. Signed-off-by: Adrian Cole <adrian@tetrate.io>
190 lines
4.0 KiB
Go
190 lines
4.0 KiB
Go
package binary
|
|
|
|
import (
|
|
"bytes"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/tetratelabs/wazero/api"
|
|
"github.com/tetratelabs/wazero/internal/testing/require"
|
|
"github.com/tetratelabs/wazero/internal/wasm"
|
|
)
|
|
|
|
func TestDecodeConstantExpression(t *testing.T) {
|
|
tests := []struct {
|
|
in []byte
|
|
exp *wasm.ConstantExpression
|
|
}{
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeRefFunc,
|
|
0x80, 0, // Multi byte zero.
|
|
wasm.OpcodeEnd,
|
|
},
|
|
exp: &wasm.ConstantExpression{
|
|
Opcode: wasm.OpcodeRefFunc,
|
|
Data: []byte{0x80, 0},
|
|
},
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeRefFunc,
|
|
0x80, 0x80, 0x80, 0x4f, // 165675008 in varint encoding.
|
|
wasm.OpcodeEnd,
|
|
},
|
|
exp: &wasm.ConstantExpression{
|
|
Opcode: wasm.OpcodeRefFunc,
|
|
Data: []byte{0x80, 0x80, 0x80, 0x4f},
|
|
},
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeRefNull,
|
|
wasm.RefTypeFuncref,
|
|
wasm.OpcodeEnd,
|
|
},
|
|
exp: &wasm.ConstantExpression{
|
|
Opcode: wasm.OpcodeRefNull,
|
|
Data: []byte{
|
|
wasm.RefTypeFuncref,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeRefNull,
|
|
wasm.RefTypeExternref,
|
|
wasm.OpcodeEnd,
|
|
},
|
|
exp: &wasm.ConstantExpression{
|
|
Opcode: wasm.OpcodeRefNull,
|
|
Data: []byte{
|
|
wasm.RefTypeExternref,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeVecPrefix,
|
|
wasm.OpcodeVecV128Const,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
wasm.OpcodeEnd,
|
|
},
|
|
exp: &wasm.ConstantExpression{
|
|
Opcode: wasm.OpcodeVecV128Const,
|
|
Data: []byte{
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
tc := tt
|
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
|
actual, err := decodeConstantExpression(bytes.NewReader(tc.in),
|
|
api.CoreFeatureBulkMemoryOperations|api.CoreFeatureSIMD)
|
|
require.NoError(t, err)
|
|
require.Equal(t, tc.exp, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeConstantExpression_errors(t *testing.T) {
|
|
tests := []struct {
|
|
in []byte
|
|
expectedErr string
|
|
features api.CoreFeatures
|
|
}{
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeRefFunc,
|
|
0,
|
|
},
|
|
expectedErr: "look for end opcode: EOF",
|
|
features: api.CoreFeatureBulkMemoryOperations,
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeRefNull,
|
|
},
|
|
expectedErr: "read reference type for ref.null: EOF",
|
|
features: api.CoreFeatureBulkMemoryOperations,
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeRefNull,
|
|
0xff,
|
|
wasm.OpcodeEnd,
|
|
},
|
|
expectedErr: "invalid type for ref.null: 0xff",
|
|
features: api.CoreFeatureBulkMemoryOperations,
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeRefNull,
|
|
wasm.RefTypeExternref,
|
|
wasm.OpcodeEnd,
|
|
},
|
|
expectedErr: "ref.null is not supported as feature \"bulk-memory-operations\" is disabled",
|
|
features: api.CoreFeaturesV1,
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeRefFunc,
|
|
0x80, 0,
|
|
wasm.OpcodeEnd,
|
|
},
|
|
expectedErr: "ref.func is not supported as feature \"bulk-memory-operations\" is disabled",
|
|
features: api.CoreFeaturesV1,
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeVecPrefix,
|
|
wasm.OpcodeVecV128Const,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
wasm.OpcodeEnd,
|
|
},
|
|
expectedErr: "vector instructions are not supported as feature \"simd\" is disabled",
|
|
features: api.CoreFeaturesV1,
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeVecPrefix,
|
|
},
|
|
expectedErr: "read vector instruction opcode suffix: EOF",
|
|
features: api.CoreFeatureSIMD,
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeVecPrefix,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
wasm.OpcodeEnd,
|
|
},
|
|
expectedErr: "invalid vector opcode for const expression: 0x1",
|
|
features: api.CoreFeatureSIMD,
|
|
},
|
|
{
|
|
in: []byte{
|
|
wasm.OpcodeVecPrefix,
|
|
wasm.OpcodeVecV128Const,
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
},
|
|
expectedErr: "read vector const instruction immediates: needs 16 bytes but was 8 bytes",
|
|
features: api.CoreFeatureSIMD,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tc := tt
|
|
t.Run(tc.expectedErr, func(t *testing.T) {
|
|
_, err := decodeConstantExpression(bytes.NewReader(tc.in), tc.features)
|
|
require.EqualError(t, err, tc.expectedErr)
|
|
})
|
|
}
|
|
}
|