Polishes in preparation of first post 1.0 feature (#340)

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2022-03-07 12:54:50 +08:00
committed by GitHub
parent 2b897ccce4
commit 0596fd32a7
11 changed files with 352 additions and 315 deletions

View File

@@ -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)
}

View File

@@ -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)
})
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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)
})
}

View File

@@ -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)

View 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:
}

View File

@@ -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
}

View File

@@ -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