From 02d6365d5d41a7f68900e54ecc476e1551e4d94e Mon Sep 17 00:00:00 2001 From: Crypt Keeper <64215+codefromthecrypt@users.noreply.github.com> Date: Tue, 5 Apr 2022 10:04:53 +0800 Subject: [PATCH] wat: syncs spectest with latest text decoder (#439) Signed-off-by: Adrian Cole --- api/wasm.go | 4 +- internal/wasm/text/func_parser.go | 15 +-- internal/wasm/text/func_parser_test.go | 5 + tests/spectest/spec_test.go | 143 ++++++++++++------------- 4 files changed, 87 insertions(+), 80 deletions(-) diff --git a/api/wasm.go b/api/wasm.go index 9a6e25fa..408d4d09 100644 --- a/api/wasm.go +++ b/api/wasm.go @@ -11,8 +11,8 @@ import ( // only definable as a value type. // // The following describes how to convert between Wasm and Golang types: -// * ValueTypeI32 - uint64(uint32,int32,int64) -// * ValueTypeI64 - uint64 +// * ValueTypeI32 - uint64(uint32,int32) +// * ValueTypeI64 - uint64(int64) // * ValueTypeF32 - EncodeF32 DecodeF32 from float32 // * ValueTypeF64 - EncodeF64 DecodeF64 from float64 // diff --git a/internal/wasm/text/func_parser.go b/internal/wasm/text/func_parser.go index 5503a3ff..e24f0068 100644 --- a/internal/wasm/text/func_parser.go +++ b/internal/wasm/text/func_parser.go @@ -145,15 +145,15 @@ func (p *funcParser) beginFieldOrInstruction(tok tokenType, tokenBytes []byte, _ func (p *funcParser) beginInstruction(tokenBytes []byte) (next tokenParser, err error) { var opCode wasm.Opcode switch string(tokenBytes) { - case "local.get": // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#-hrefsyntax-instr-variablemathsflocalgetx%E2%91%A0 - opCode = wasm.OpcodeLocalGet - next = p.parseLocalIndex - case "i32.add": // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-instr-numeric - opCode = wasm.OpcodeI32Add - next = p.beginFieldOrInstruction case "call": // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#-hrefsyntax-instr-controlmathsfcallx opCode = wasm.OpcodeCall next = p.parseFuncIndex + case "drop": // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#-hrefsyntax-instr-parametricmathsfdrop + opCode = wasm.OpcodeDrop + next = p.beginFieldOrInstruction + case "i32.add": // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-instr-numeric + opCode = wasm.OpcodeI32Add + next = p.beginFieldOrInstruction case "i32.extend8_s": // See https://github.com/WebAssembly/spec/blob/main/proposals/sign-extension-ops/Overview.md opCode = wasm.OpcodeI32Extend8S next = p.beginFieldOrInstruction @@ -169,6 +169,9 @@ func (p *funcParser) beginInstruction(tokenBytes []byte) (next tokenParser, err case "i64.extend32_s": // See https://github.com/WebAssembly/spec/blob/main/proposals/sign-extension-ops/Overview.md opCode = wasm.OpcodeI64Extend32S next = p.beginFieldOrInstruction + case "local.get": // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#-hrefsyntax-instr-variablemathsflocalgetx%E2%91%A0 + opCode = wasm.OpcodeLocalGet + next = p.parseLocalIndex default: return nil, fmt.Errorf("unsupported instruction: %s", tokenBytes) } diff --git a/internal/wasm/text/func_parser_test.go b/internal/wasm/text/func_parser_test.go index 007b8883..1b7241ed 100644 --- a/internal/wasm/text/func_parser_test.go +++ b/internal/wasm/text/func_parser_test.go @@ -25,6 +25,11 @@ func TestFuncParser(t *testing.T) { source: "(func local.get 0)", expected: &wasm.Code{Body: []byte{wasm.OpcodeLocalGet, 0x00, wasm.OpcodeEnd}}, }, + { + name: "local.get, drop", + source: "(func local.get 0 drop)", + expected: &wasm.Code{Body: []byte{wasm.OpcodeLocalGet, 0x00, wasm.OpcodeDrop, wasm.OpcodeEnd}}, + }, { name: "local.get twice", source: "(func local.get 0 local.get 1)", diff --git a/tests/spectest/spec_test.go b/tests/spectest/spec_test.go index ece5d5a9..689f0ef9 100644 --- a/tests/spectest/spec_test.go +++ b/tests/spectest/spec_test.go @@ -13,10 +13,13 @@ import ( "github.com/stretchr/testify/require" + "github.com/tetratelabs/wazero/api" + "github.com/tetratelabs/wazero/internal/leb128" "github.com/tetratelabs/wazero/internal/wasm" "github.com/tetratelabs/wazero/internal/wasm/binary" "github.com/tetratelabs/wazero/internal/wasm/interpreter" "github.com/tetratelabs/wazero/internal/wasm/jit" + "github.com/tetratelabs/wazero/internal/wasm/text" "github.com/tetratelabs/wazero/internal/wasmruntime" ) @@ -195,80 +198,76 @@ func (c command) expectedError() (err error) { return } +// addSpectestModule adds a module that drops inputs and returns globals as 666 per the default test harness. +// +// See https://github.com/WebAssembly/spec/blob/wg-1.0/test/core/imports.wast +// See https://github.com/WebAssembly/spec/blob/wg-1.0/interpreter/script/js.ml#L13-L25 func addSpectestModule(t *testing.T, store *wasm.Store) { - memoryLimitMax := uint32(2) - tableLimitMax := uint32(20) + mod, err := text.DecodeModule([]byte(`(module $spectest +(; TODO + (global (export "global_i32") i32) + (global (export "global_f32") f32) + (global (export "global_f64") f64) - mod := &wasm.Module{ - FunctionSection: []uint32{ - 0, // print - 1, // print_i32 - 2, // print_i64 - 3, // print_f32 - 4, // print_f64 - 5, // print_f64 - 6, // print_f64 - }, - TypeSection: []*wasm.FunctionType{ - {}, // print - {Params: []byte{wasm.ValueTypeI32}}, // print_i32 - {Params: []byte{wasm.ValueTypeI64}}, // print_i64 - {Params: []byte{wasm.ValueTypeF32}}, // print_f32 - {Params: []byte{wasm.ValueTypeF64}}, // print_f64 - {Params: []byte{wasm.ValueTypeI32, wasm.ValueTypeF32}}, // print_i32_f32 - {Params: []byte{wasm.ValueTypeF64, wasm.ValueTypeF64}}, // print_f64_f64 - }, - CodeSection: []*wasm.Code{ - {Body: []byte{wasm.OpcodeEnd}}, // print - {Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeDrop, wasm.OpcodeEnd}}, // print_i32 - {Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeDrop, wasm.OpcodeEnd}}, // print_i64 - {Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeDrop, wasm.OpcodeEnd}}, // print_f32 - {Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeDrop, wasm.OpcodeEnd}}, // print_f64 - {Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeDrop, wasm.OpcodeLocalGet, 1, wasm.OpcodeDrop, wasm.OpcodeEnd}}, // print_i32_f32 - {Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeDrop, wasm.OpcodeLocalGet, 1, wasm.OpcodeDrop, wasm.OpcodeEnd}}, // print_f64_f64 - }, - GlobalSection: []*wasm.Global{ - { // global_i32 - Type: &wasm.GlobalType{ValType: wasm.ValueTypeI32}, - Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: []byte{0x9a, 0x5} /* = 666 */}, - }, - { // global_i64 - Type: &wasm.GlobalType{ValType: wasm.ValueTypeI64}, - Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI64Const, Data: []byte{0x9a, 0x5} /* = 666 */}, - }, - { // global_f32 - Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32}, - Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: []byte{0x44, 0x26, 0x80, 0x00}}, - }, - { // global_f64 - Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64}, - Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: []byte{0x40, 0x84, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00}}, - }, - }, - MemorySection: &wasm.Memory{ - Min: 1, Max: memoryLimitMax, - }, - TableSection: &wasm.Table{ - Min: 10, Max: &tableLimitMax, - }, - ExportSection: map[string]*wasm.Export{ - "print": {Name: "print", Index: 0, Type: wasm.ExternTypeFunc}, - "print_i32": {Name: "print_i32", Index: 1, Type: wasm.ExternTypeFunc}, - "print_i64": {Name: "print_i64", Index: 2, Type: wasm.ExternTypeFunc}, - "print_f32": {Name: "print_f32", Index: 3, Type: wasm.ExternTypeFunc}, - "print_f64": {Name: "print_f64", Index: 4, Type: wasm.ExternTypeFunc}, - "print_i32_f32": {Name: "print_i32_f32", Index: 5, Type: wasm.ExternTypeFunc}, - "print_f64_f64": {Name: "print_f64_f64", Index: 6, Type: wasm.ExternTypeFunc}, - "global_i32": {Name: "global_i32", Index: 0, Type: wasm.ExternTypeGlobal}, - "global_i64": {Name: "global_i64", Index: 1, Type: wasm.ExternTypeGlobal}, - "global_f32": {Name: "global_f32", Index: 2, Type: wasm.ExternTypeGlobal}, - "global_f64": {Name: "global_f64", Index: 3, Type: wasm.ExternTypeGlobal}, - "table": {Name: "table", Index: 0, Type: wasm.ExternTypeTable}, - "memory": {Name: "memory", Index: 0, Type: wasm.ExternTypeMemory}, - }, - } - require.NoError(t, mod.Validate(wasm.Features20191205)) - _, err := store.Instantiate(context.Background(), mod, "spectest", nil) + (table (export "table") 10 20 funcref) +;) + +;; TODO: revisit inlining after #215 + + (memory 1 2) + (export "memory" (memory 0)) + +;; Note: the following aren't host functions that print to console as it would clutter it. These only drop the inputs. + (func) + (export "print" (func 0)) + + (func (param i32) local.get 0 drop) + (export "print_i32" (func 1)) + + (func (param i64) local.get 0 drop) + (export "print_i64" (func 2)) + + (func (param f32) local.get 0 drop) + (export "print_f32" (func 3)) + + (func (param f64) local.get 0 drop) + (export "print_f64" (func 4)) + + (func (param i32 f32) local.get 0 drop local.get 1 drop) + (export "print_i32_f32" (func 5)) + + (func (param f64 f64) local.get 0 drop local.get 1 drop) + (export "print_f64_f64" (func 6)) +)`), wasm.Features20191205, wasm.MemoryMaxPages) + require.NoError(t, err) + + // (global (export "global_i32") i32 (i32.const 666)) + mod.GlobalSection = append(mod.GlobalSection, &wasm.Global{ + Type: &wasm.GlobalType{ValType: wasm.ValueTypeI32}, + Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeUint32(666)}, + }) + mod.ExportSection["global_i32"] = &wasm.Export{Name: "global_i32", Index: 0, Type: wasm.ExternTypeGlobal} + + // (global (export "global_f32") f32 (f32.const 666)) + mod.GlobalSection = append(mod.GlobalSection, &wasm.Global{ + Type: &wasm.GlobalType{ValType: wasm.ValueTypeF32}, + Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF32Const, Data: leb128.EncodeUint64(api.EncodeF32(666))}, + }) + mod.ExportSection["global_f32"] = &wasm.Export{Name: "global_f32", Index: 1, Type: wasm.ExternTypeGlobal} + + // (global (export "global_f64") f64 (f64.const 666)) + mod.GlobalSection = append(mod.GlobalSection, &wasm.Global{ + Type: &wasm.GlobalType{ValType: wasm.ValueTypeF64}, + Init: &wasm.ConstantExpression{Opcode: wasm.OpcodeF64Const, Data: leb128.EncodeUint64(api.EncodeF64(666))}, + }) + mod.ExportSection["global_f64"] = &wasm.Export{Name: "global_f64", Index: 2, Type: wasm.ExternTypeGlobal} + + // (table (export "table") 10 20 funcref) + tableLimitMax := uint32(20) + mod.TableSection = &wasm.Table{Min: 10, Max: &tableLimitMax} + mod.ExportSection["table"] = &wasm.Export{Name: "table", Index: 0, Type: wasm.ExternTypeTable} + + _, err = store.Instantiate(context.Background(), mod, mod.NameSection.ModuleName, wasm.DefaultSysContext()) require.NoError(t, err) }