Polishes in preparation of first post 1.0 feature (#340)
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -31,6 +31,7 @@ func validateFunction(
|
||||
tables []*TableType,
|
||||
types []*FunctionType,
|
||||
maxStackValues int,
|
||||
features Features,
|
||||
) error {
|
||||
// Note: In WebAssembly 1.0 (20191205), multiple memories are not allowed.
|
||||
hasMemory := len(memories) > 0
|
||||
@@ -503,8 +504,8 @@ func validateFunction(
|
||||
for _, exp := range funcType.Results {
|
||||
valueTypeStack.push(exp)
|
||||
}
|
||||
} else if OpcodeI32Eqz <= op && op <= OpcodeF64ReinterpretI64 {
|
||||
switch Opcode(op) {
|
||||
} else if OpcodeI32Eqz <= op && op <= LastOpcode {
|
||||
switch op {
|
||||
case OpcodeI32Eqz:
|
||||
if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
|
||||
return fmt.Errorf("cannot pop the operand for i32.eqz: %v", err)
|
||||
@@ -697,6 +698,8 @@ func validateFunction(
|
||||
return fmt.Errorf("cannot pop the operand for f64.reinterpret_i64: %v", err)
|
||||
}
|
||||
valueTypeStack.push(ValueTypeF64)
|
||||
case OpcodeI32Extend8S, OpcodeI32Extend16S, OpcodeI64Extend8S, OpcodeI64Extend16S, OpcodeI64Extend32S:
|
||||
return fmt.Errorf("%s invalid as %s is not yet supported. See #66", InstructionName(op), FeatureSignExtensionOps)
|
||||
default:
|
||||
return fmt.Errorf("invalid numeric instruction 0x%x", op)
|
||||
}
|
||||
@@ -814,8 +817,6 @@ func validateFunction(
|
||||
// unreachable instruction is stack-polymorphic.
|
||||
valueTypeStack.unreachable()
|
||||
} else if op == OpcodeNop {
|
||||
} else if OpcodeI32Extend8S <= op && op <= OpcodeI64Extend32S {
|
||||
return fmt.Errorf("%s invalid as %s is not yet supported. See #66", InstructionName(op), FeatureSignExtensionOps)
|
||||
} else {
|
||||
return fmt.Errorf("invalid instruction 0x%x", op)
|
||||
}
|
||||
|
||||
@@ -26,18 +26,18 @@ func TestValidateFunction_valueStackLimit(t *testing.T) {
|
||||
body = append(body, OpcodeEnd)
|
||||
|
||||
t.Run("not exceed", func(t *testing.T) {
|
||||
err := validateFunction(&FunctionType{}, body, nil, nil, nil, nil, nil, nil, max+1)
|
||||
err := validateFunction(&FunctionType{}, body, nil, nil, nil, nil, nil, nil, max+1, Features(0))
|
||||
require.NoError(t, err)
|
||||
})
|
||||
t.Run("exceed", func(t *testing.T) {
|
||||
err := validateFunction(&FunctionType{}, body, nil, nil, nil, nil, nil, nil, max)
|
||||
err := validateFunction(&FunctionType{}, body, nil, nil, nil, nil, nil, nil, max, Features(0))
|
||||
require.Error(t, err)
|
||||
expMsg := fmt.Sprintf("function may have %d stack values, which exceeds limit %d", valuesNum, max)
|
||||
require.Equal(t, expMsg, err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestValidateFunction_FeatureSignExtensionOps(t *testing.T) {
|
||||
func TestValidateFunction_SignExtensionOps(t *testing.T) {
|
||||
// TODO: actually support, guarded by FeatureSignExtensionOps flag which defaults to false #66
|
||||
tests := []struct {
|
||||
input Opcode
|
||||
@@ -69,7 +69,7 @@ func TestValidateFunction_FeatureSignExtensionOps(t *testing.T) {
|
||||
tc := tt
|
||||
|
||||
t.Run(InstructionName(tc.input), func(t *testing.T) {
|
||||
err := validateFunction(&FunctionType{}, []byte{tc.input}, nil, nil, nil, nil, nil, nil, 0)
|
||||
err := validateFunction(&FunctionType{}, []byte{tc.input}, nil, nil, nil, nil, nil, nil, 0, Features(0))
|
||||
require.EqualError(t, err, tc.expectedErr)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -217,11 +217,13 @@ const (
|
||||
|
||||
// Below are toggled with FeatureSignExtensionOps
|
||||
|
||||
OpcodeI32Extend8S Opcode = 0xC0
|
||||
OpcodeI32Extend16S Opcode = 0xC1
|
||||
OpcodeI64Extend8S Opcode = 0xC2
|
||||
OpcodeI64Extend16S Opcode = 0xC3
|
||||
OpcodeI64Extend32S Opcode = 0xC4
|
||||
OpcodeI32Extend8S Opcode = 0xc0
|
||||
OpcodeI32Extend16S Opcode = 0xc1
|
||||
OpcodeI64Extend8S Opcode = 0xc2
|
||||
OpcodeI64Extend16S Opcode = 0xc3
|
||||
OpcodeI64Extend32S Opcode = 0xc4
|
||||
|
||||
LastOpcode = OpcodeI64Extend32S
|
||||
)
|
||||
|
||||
var instructionNames = [256]string{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3441,17 +3441,23 @@ func (c *amd64Compiler) compileF64ReinterpretFromI64() error {
|
||||
|
||||
// compileExtend implements compiler.compileExtend for the amd64 architecture.
|
||||
func (c *amd64Compiler) compileExtend(o *wazeroir.OperationExtend) error {
|
||||
var inst obj.As
|
||||
if o.Signed {
|
||||
inst = x86.AMOVLQSX // = MOVSXD https://www.felixcloutier.com/x86/movsx:movsxd
|
||||
} else {
|
||||
inst = x86.AMOVQ
|
||||
}
|
||||
return c.compileExtendImpl(inst)
|
||||
}
|
||||
|
||||
func (c *amd64Compiler) compileExtendImpl(inst obj.As) error {
|
||||
target := c.locationStack.peek() // Note this is peek!
|
||||
if err := c.ensureOnGeneralPurposeRegister(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
extend := c.newProg()
|
||||
if o.Signed {
|
||||
extend.As = x86.AMOVLQSX // = MOVSXD https://www.felixcloutier.com/x86/movsx:movsxd
|
||||
} else {
|
||||
extend.As = x86.AMOVQ
|
||||
}
|
||||
extend.As = inst
|
||||
extend.From.Type = obj.TYPE_REG
|
||||
extend.From.Reg = target.register
|
||||
extend.To.Type = obj.TYPE_REG
|
||||
|
||||
@@ -173,7 +173,7 @@ func (m *Module) TypeOfFunction(funcIdx Index) *FunctionType {
|
||||
return m.TypeSection[typeIdx]
|
||||
}
|
||||
|
||||
func (m *Module) Validate() error {
|
||||
func (m *Module) Validate(features Features) error {
|
||||
if err := m.validateStartSection(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -194,7 +194,7 @@ func (m *Module) Validate() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.validateFunctions(functions, globals, memories, tables); err != nil {
|
||||
if err := m.validateFunctions(functions, globals, memories, tables, features); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ func (m *Module) validateGlobals(globals []*GlobalType, maxGlobals int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Module) validateFunctions(functions []Index, globals []*GlobalType, memories []*MemoryType, tables []*TableType) error {
|
||||
func (m *Module) validateFunctions(functions []Index, globals []*GlobalType, memories []*MemoryType, tables []*TableType, features Features) error {
|
||||
// The wazero specific limitation described at RATIONALE.md.
|
||||
const maximumValuesOnStack = 1 << 27
|
||||
|
||||
@@ -252,7 +252,7 @@ func (m *Module) validateFunctions(functions []Index, globals []*GlobalType, mem
|
||||
m.TypeSection[typeIndex],
|
||||
m.CodeSection[codeIndex].Body,
|
||||
m.CodeSection[codeIndex].LocalTypes,
|
||||
functions, globals, memories, tables, m.TypeSection, maximumValuesOnStack); err != nil {
|
||||
functions, globals, memories, tables, m.TypeSection, maximumValuesOnStack, features); err != nil {
|
||||
idx := m.SectionElementCount(SectionIDFunction) - 1
|
||||
return fmt.Errorf("invalid function (%d/%d): %v", codeIndex, idx, err)
|
||||
}
|
||||
|
||||
@@ -465,7 +465,7 @@ func TestModule_validateGlobals(t *testing.T) {
|
||||
func TestModule_validateFunctions(t *testing.T) {
|
||||
t.Run("type index out of range", func(t *testing.T) {
|
||||
m := Module{FunctionSection: []uint32{1000 /* arbitrary large */}}
|
||||
err := m.validateFunctions(nil, nil, nil, nil)
|
||||
err := m.validateFunctions(nil, nil, nil, nil, Features(0))
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "function type index out of range")
|
||||
})
|
||||
@@ -475,7 +475,7 @@ func TestModule_validateFunctions(t *testing.T) {
|
||||
TypeSection: []*FunctionType{{}},
|
||||
// Code section not exists.
|
||||
}
|
||||
err := m.validateFunctions(nil, nil, nil, nil)
|
||||
err := m.validateFunctions(nil, nil, nil, nil, Features(0))
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "code index out of range")
|
||||
})
|
||||
@@ -487,7 +487,7 @@ func TestModule_validateFunctions(t *testing.T) {
|
||||
{Body: []byte{OpcodeF32Abs}},
|
||||
},
|
||||
}
|
||||
err := m.validateFunctions(nil, nil, nil, nil)
|
||||
err := m.validateFunctions(nil, nil, nil, nil, Features(0))
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "invalid function (0/0): cannot pop the 1st f32 operand")
|
||||
})
|
||||
@@ -499,7 +499,7 @@ func TestModule_validateFunctions(t *testing.T) {
|
||||
{Body: []byte{OpcodeI32Const, 0, OpcodeDrop, OpcodeEnd}},
|
||||
},
|
||||
}
|
||||
err := m.validateFunctions(nil, nil, nil, nil)
|
||||
err := m.validateFunctions(nil, nil, nil, nil, Features(0))
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
This directory contains tests which use multiple packages. For example:
|
||||
|
||||
* `bench` contains benchmark tests.
|
||||
* `engine` contains variety of e2e tests, mainly to ensure the consistency in the behavior between engines.
|
||||
* `engine` contains variety of end-to-end tests, mainly to ensure the consistency in the behavior between engines.
|
||||
* `post1_0` contains end-to-end tests for features [finished](https://github.com/WebAssembly/proposals/blob/main/finished-proposals.md) after WebAssembly 1.0 (20191205).
|
||||
* `spectest` contains end-to-end tests with the [WebAssembly specification tests](https://github.com/WebAssembly/spec/tree/wg-1.0/test/core).
|
||||
|
||||
*Note*: this doesn't contain WASI tests, as there's not yet an [official testsuite](https://github.com/WebAssembly/WASI/issues/9).
|
||||
*Note*: This doesn't contain WASI tests, as there's not yet an [official testsuite](https://github.com/WebAssembly/WASI/issues/9).
|
||||
Meanwhile, WASI functions are unit tested including via Text Format imports [here](../wasi/wasi_test.go)
|
||||
|
||||
27
tests/post1_0/post1_0_test.go
Normal file
27
tests/post1_0/post1_0_test.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package post1_0
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
)
|
||||
|
||||
func TestJIT(t *testing.T) {
|
||||
if !wazero.JITSupported {
|
||||
t.Skip()
|
||||
}
|
||||
runOptionalFeatureTests(t, wazero.NewRuntimeConfigJIT)
|
||||
}
|
||||
|
||||
func TestInterpreter(t *testing.T) {
|
||||
runOptionalFeatureTests(t, wazero.NewRuntimeConfigInterpreter)
|
||||
}
|
||||
|
||||
// runOptionalFeatureTests tests features enabled by feature flags (internalwasm.Features) as they were unfinished when
|
||||
// WebAssembly 1.0 (20191205) was released.
|
||||
//
|
||||
// See https://github.com/WebAssembly/proposals/blob/main/finished-proposals.md
|
||||
func runOptionalFeatureTests(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
||||
// TODO:
|
||||
}
|
||||
@@ -452,7 +452,7 @@ func requireInstantiationError(t *testing.T, store *wasm.Store, buf []byte, msg
|
||||
return
|
||||
}
|
||||
|
||||
err = mod.Validate()
|
||||
err = mod.Validate(store.EnabledFeatures)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
2
wasm.go
2
wasm.go
@@ -111,7 +111,7 @@ func (r *runtime) DecodeModule(source []byte) (*DecodedModule, error) {
|
||||
internal, err := decoder(source, r.enabledFeatures)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if err = internal.Validate(); err != nil {
|
||||
} else if err = internal.Validate(r.enabledFeatures); err != nil {
|
||||
// TODO: decoders should validate before returning, as that allows
|
||||
// them to err with the correct source position.
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user