From 1bfc701e5a7782fadc6e4f0f89342b65581745fd Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 6 Nov 2020 13:41:51 +0000 Subject: [PATCH 1/8] test: refactor test_cases loops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Bylica --- test/unittests/execute_test.cpp | 46 +++++++++++++++--------------- test/unittests/validation_test.cpp | 7 ++--- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/test/unittests/execute_test.cpp b/test/unittests/execute_test.cpp index 8611afe4a..d420e0ed5 100644 --- a/test/unittests/execute_test.cpp +++ b/test/unittests/execute_test.cpp @@ -394,12 +394,12 @@ TEST(execute, i32_load_all_variants) {Instr::i32_load, 0xb3b2b1b0}, }; - for (const auto& test_case : test_cases) + for (const auto& [instr, expected] : test_cases) { - load_instr = static_cast(std::get<0>(test_case)); + load_instr = static_cast(instr); auto instance = instantiate(*module); std::copy(std::begin(memory_fill), std::end(memory_fill), std::begin(*instance->memory)); - EXPECT_THAT(execute(*instance, 0, {1}), Result(std::get<1>(test_case))); + EXPECT_THAT(execute(*instance, 0, {1}), Result(expected)); EXPECT_THAT(execute(*instance, 0, {65537}), Traps()); } @@ -434,12 +434,12 @@ TEST(execute, i64_load_all_variants) {Instr::i64_load, 0xb7b6b5b4b3b2b1b0}, }; - for (const auto& test_case : test_cases) + for (const auto& [instr, expected] : test_cases) { - load_instr = static_cast(std::get<0>(test_case)); + load_instr = static_cast(instr); auto instance = instantiate(*module); std::copy(std::begin(memory_fill), std::end(memory_fill), std::begin(*instance->memory)); - EXPECT_THAT(execute(*instance, 0, {1}), Result(std::get<1>(test_case))); + EXPECT_THAT(execute(*instance, 0, {1}), Result(expected)); EXPECT_THAT(execute(*instance, 0, {65537}), Traps()); } @@ -539,13 +539,13 @@ TEST(execute, i32_store_all_variants) {Instr::i32_store, "ccb0b1b2b3cc"_bytes}, }; - for (const auto& test_case : test_cases) + for (const auto& [instr, expected] : test_cases) { - store_instr = static_cast(std::get<0>(test_case)); + store_instr = static_cast(instr); auto instance = instantiate(*module); std::fill_n(instance->memory->begin(), 6, uint8_t{0xcc}); EXPECT_THAT(execute(*instance, 0, {0xb3b2b1b0, 1}), Result()); - EXPECT_EQ(instance->memory->substr(0, 6), std::get<1>(test_case)); + EXPECT_EQ(instance->memory->substr(0, 6), expected); EXPECT_THAT(execute(*instance, 0, {0xb3b2b1b0, 65537}), Traps()); } @@ -576,13 +576,13 @@ TEST(execute, i64_store_all_variants) {Instr::i64_store, "ccb0b1b2b3b4b5b6b7cc"_bytes}, }; - for (const auto& test_case : test_cases) + for (const auto& [instr, expected] : test_cases) { - store_instr = static_cast(std::get<0>(test_case)); + store_instr = static_cast(instr); auto instance = instantiate(*module); std::fill_n(instance->memory->begin(), 10, uint8_t{0xcc}); EXPECT_THAT(execute(*instance, 0, {0xb7b6b5b4b3b2b1b0, 1}), Result()); - EXPECT_EQ(instance->memory->substr(0, 10), std::get<1>(test_case)); + EXPECT_EQ(instance->memory->substr(0, 10), expected); EXPECT_THAT(execute(*instance, 0, {0xb7b6b5b4b3b2b1b0, 65537}), Traps()); } @@ -651,10 +651,10 @@ TEST(execute, memory_grow_custom_hard_limit) from_hex("0061736d0100000001060160017f017f0302010005030100010a08010600200040000b"); const auto module = parse(wasm); - for (const auto& test_case : test_cases) + for (const auto& [input, expected] : test_cases) { const auto instance = instantiate(*module, {}, {}, {}, {}, 16); - EXPECT_THAT(execute(*instance, 0, {test_case.first}), Result(test_case.second)); + EXPECT_THAT(execute(*instance, 0, {input}), Result(expected)); } /* wat2wasm @@ -668,10 +668,10 @@ TEST(execute, memory_grow_custom_hard_limit) from_hex("0061736d0100000001060160017f017f030201000504010101100a08010600200040000b"); const auto module_max_limit = parse(wasm_max_limit); - for (const auto& test_case : test_cases) + for (const auto& [input, expected] : test_cases) { const auto instance = instantiate(*module_max_limit, {}, {}, {}, {}, 32); - EXPECT_THAT(execute(*instance, 0, {test_case.first}), Result(test_case.second)); + EXPECT_THAT(execute(*instance, 0, {input}), Result(expected)); } /* wat2wasm @@ -685,17 +685,17 @@ TEST(execute, memory_grow_custom_hard_limit) "0061736d0100000001060160017f017f020c01036d6f64036d656d020001030201000a08010600200040000b"); const auto module_imported = parse(wasm_imported); - for (const auto& test_case : test_cases) + for (const auto& [input, expected] : test_cases) { bytes memory(PageSize, 0); const auto instance = instantiate(*module_imported, {}, {}, {{&memory, {1, std::nullopt}}}, {}, 16); - EXPECT_THAT(execute(*instance, 0, {test_case.first}), Result(test_case.second)); + EXPECT_THAT(execute(*instance, 0, {input}), Result(expected)); bytes memory_max_limit(PageSize, 0); const auto instance_max_limit = instantiate(*module_imported, {}, {}, {{&memory_max_limit, {1, 16}}}, {}, 32); - EXPECT_THAT(execute(*instance_max_limit, 0, {test_case.first}), Result(test_case.second)); + EXPECT_THAT(execute(*instance_max_limit, 0, {input}), Result(expected)); } /* wat2wasm @@ -710,12 +710,12 @@ TEST(execute, memory_grow_custom_hard_limit) "b"); const auto module_imported_max_limit = parse(wasm_imported_max_limit); - for (const auto& test_case : test_cases) + for (const auto& [input, expected] : test_cases) { bytes memory(PageSize, 0); const auto instance = instantiate(*module_imported_max_limit, {}, {}, {{&memory, {1, 16}}}, {}, 32); - EXPECT_THAT(execute(*instance, 0, {test_case.first}), Result(test_case.second)); + EXPECT_THAT(execute(*instance, 0, {input}), Result(expected)); } /* wat2wasm @@ -730,12 +730,12 @@ TEST(execute, memory_grow_custom_hard_limit) "b"); const auto module_imported_max_limit_narrowing = parse(wasm_imported_max_limit_narrowing); - for (const auto& test_case : test_cases) + for (const auto& [input, expected] : test_cases) { bytes memory(PageSize, 0); const auto instance = instantiate(*module_imported_max_limit_narrowing, {}, {}, {{&memory, {1, 16}}}, {}, 32); - EXPECT_THAT(execute(*instance, 0, {test_case.first}), Result(test_case.second)); + EXPECT_THAT(execute(*instance, 0, {input}), Result(expected)); } } diff --git a/test/unittests/validation_test.cpp b/test/unittests/validation_test.cpp index 4401ef47c..5537b2e0f 100644 --- a/test/unittests/validation_test.cpp +++ b/test/unittests/validation_test.cpp @@ -344,9 +344,8 @@ TEST(validation, store_alignment) {Instr::i64_store32, 2, Instr::i64_const}, {Instr::i64_store, 3, Instr::i64_const}, {Instr::f32_store, 2, Instr::f32_const}, {Instr::f64_store, 3, Instr::f64_const}}; - for (const auto& test_case : test_cases) + for (const auto& [instr, max_align, push_address_instr] : test_cases) { - const auto [instr, max_align, push_address_instr] = test_case; // TODO: consider using leb128_encode and test 2^32-1 for (auto align : {0, 1, 2, 3, 4, 0x7f}) { @@ -406,10 +405,8 @@ TEST(validation, load_alignment) {Instr::f64_load, 3}, }; - for (const auto& test_case : test_cases) + for (const auto& [instr, max_align] : test_cases) { - const auto instr = test_case.first; - const auto max_align = test_case.second; // TODO: consider using leb128_encode and test 2^32-1 for (auto align : {0, 1, 2, 3, 4, 0x7f}) { From e8823b9f2874d9f6edabb8bf24940e9146ba11d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Oct 2020 19:38:52 +0200 Subject: [PATCH 2/8] Move constants' immediate values to the instructions array --- lib/fizzy/execute.cpp | 4 +- lib/fizzy/parser_expr.cpp | 28 +++-- lib/fizzy/types.hpp | 4 +- test/unittests/module_test.cpp | 2 +- test/unittests/parser_expr_test.cpp | 160 ++++++++++++++-------------- test/unittests/parser_test.cpp | 11 +- 6 files changed, 108 insertions(+), 101 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index afce983de..d2b389d0a 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -861,14 +861,14 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, case Instr::i32_const: case Instr::f32_const: { - const auto value = read(immediates); + const auto value = read(pc); stack.push(value); break; } case Instr::i64_const: case Instr::f64_const: { - const auto value = read(immediates); + const auto value = read(pc); stack.push(value); break; } diff --git a/lib/fizzy/parser_expr.cpp b/lib/fizzy/parser_expr.cpp index f0ced862d..ef0b1411e 100644 --- a/lib/fizzy/parser_expr.cpp +++ b/lib/fizzy/parser_expr.cpp @@ -27,6 +27,14 @@ inline void push(bytes& b, T value) b.append(storage, sizeof(storage)); } +template +inline void push(std::vector& b, T value) +{ + uint8_t storage[sizeof(T)]; + store(storage, value); + b.insert(b.end(), std::begin(storage), std::end(storage)); +} + /// The control frame to keep information about labels and blocks as defined in /// Wasm Validation Algorithm https://webassembly.github.io/spec/core/appendix/algorithm.html. struct ControlFrame @@ -788,32 +796,36 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f { int32_t value; std::tie(value, pos) = leb128s_decode(pos, end); - push(code.immediates, static_cast(value)); - break; + code.instructions.push_back(opcode); + push(code.instructions, static_cast(value)); + continue; } case Instr::i64_const: { int64_t value; std::tie(value, pos) = leb128s_decode(pos, end); - push(code.immediates, static_cast(value)); - break; + code.instructions.push_back(opcode); + push(code.instructions, static_cast(value)); + continue; } case Instr::f32_const: { uint32_t value; std::tie(value, pos) = parse_value(pos, end); - push(code.immediates, value); - break; + code.instructions.push_back(opcode); + push(code.instructions, value); + continue; } case Instr::f64_const: { uint64_t value; std::tie(value, pos) = parse_value(pos, end); - push(code.immediates, value); - break; + code.instructions.push_back(opcode); + push(code.instructions, value); + continue; } case Instr::i32_load: diff --git a/lib/fizzy/types.hpp b/lib/fizzy/types.hpp index 06fbbd239..b477ee1a2 100644 --- a/lib/fizzy/types.hpp +++ b/lib/fizzy/types.hpp @@ -360,8 +360,8 @@ struct Code uint32_t local_count = 0; - // The instructions bytecode without immediate values. - // https://webassembly.github.io/spec/core/binary/instructions.html + /// The instructions bytecode interleaved with decoded immediate values. + /// https://webassembly.github.io/spec/core/binary/instructions.html std::vector instructions; // The decoded instructions' immediate values. diff --git a/test/unittests/module_test.cpp b/test/unittests/module_test.cpp index 276a02f32..e9309af8e 100644 --- a/test/unittests/module_test.cpp +++ b/test/unittests/module_test.cpp @@ -34,7 +34,7 @@ TEST(module, functions) EXPECT_EQ(module->get_code(1).local_count, 0); EXPECT_EQ(module->get_code(2).instructions.size(), 1); EXPECT_EQ(module->get_code(2).local_count, 1); - EXPECT_EQ(module->get_code(3).instructions.size(), 2); + EXPECT_EQ(module->get_code(3).instructions.size(), 6); EXPECT_EQ(module->get_code(3).local_count, 0); } diff --git a/test/unittests/parser_expr_test.cpp b/test/unittests/parser_expr_test.cpp index 661de5144..6c38e082d 100644 --- a/test/unittests/parser_expr_test.cpp +++ b/test/unittests/parser_expr_test.cpp @@ -34,23 +34,23 @@ TEST(parser_expr, instr_loop) const auto loop_i32 = "037f41000b1a0b"_bytes; const auto [code2, pos2] = parse_expr(loop_i32); - EXPECT_THAT(code2.instructions, - ElementsAre(Instr::loop, Instr::i32_const, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code2.immediates.size(), 4); + EXPECT_THAT(code2.instructions, ElementsAre(Instr::loop, Instr::i32_const, 0, 0, 0, 0, + Instr::end, Instr::drop, Instr::end)); + EXPECT_EQ(code2.immediates.size(), 0); EXPECT_EQ(code2.max_stack_height, 1); const auto loop_f32 = "037d43000000000b1a0b"_bytes; const auto [code3, pos3] = parse_expr(loop_f32); - EXPECT_THAT(code3.instructions, - ElementsAre(Instr::loop, Instr::f32_const, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code3.immediates.size(), 4); + EXPECT_THAT(code3.instructions, ElementsAre(Instr::loop, Instr::f32_const, 0, 0, 0, 0, + Instr::end, Instr::drop, Instr::end)); + EXPECT_EQ(code3.immediates.size(), 0); EXPECT_EQ(code3.max_stack_height, 1); const auto loop_f64 = "037c4400000000000000000b1a0b"_bytes; const auto [code4, pos4] = parse_expr(loop_f64); - EXPECT_THAT(code4.instructions, - ElementsAre(Instr::loop, Instr::f64_const, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code4.immediates.size(), 8); + EXPECT_THAT(code4.instructions, ElementsAre(Instr::loop, Instr::f64_const, 0, 0, 0, 0, 0, 0, 0, + 0, Instr::end, Instr::drop, Instr::end)); + EXPECT_EQ(code4.immediates.size(), 0); EXPECT_EQ(code4.max_stack_height, 1); } @@ -74,15 +74,15 @@ TEST(parser_expr, instr_block) const auto block_i64 = "027e42000b1a0b"_bytes; const auto [code2, pos2] = parse_expr(block_i64); - EXPECT_THAT(code2.instructions, - ElementsAre(Instr::block, Instr::i64_const, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code2.immediates, "0000000000000000"_bytes); + EXPECT_THAT(code2.instructions, ElementsAre(Instr::block, Instr::i64_const, 0, 0, 0, 0, 0, 0, 0, + 0, Instr::end, Instr::drop, Instr::end)); + EXPECT_EQ(code2.immediates.size(), 0); const auto block_f64 = "027c4400000000000000000b1a0b"_bytes; const auto [code3, pos3] = parse_expr(block_f64); - EXPECT_THAT(code3.instructions, - ElementsAre(Instr::block, Instr::f64_const, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code2.immediates, "0000000000000000"_bytes); + EXPECT_THAT(code3.instructions, ElementsAre(Instr::block, Instr::f64_const, 0, 0, 0, 0, 0, 0, 0, + 0, Instr::end, Instr::drop, Instr::end)); + EXPECT_EQ(code2.immediates.size(), 0); } TEST(parser_expr, instr_block_input_buffer_overflow) @@ -120,12 +120,12 @@ TEST(parser_expr, loop_br) const auto module_parent_stack = parse(wasm_parent_stack); EXPECT_THAT(module_parent_stack->codesec[0].instructions, - ElementsAre(Instr::i32_const, Instr::loop, Instr::br, Instr::end, Instr::drop, Instr::end)); + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::loop, Instr::br, Instr::end, Instr::drop, + Instr::end)); EXPECT_EQ(module_parent_stack->codesec[0].immediates, - "00000000" // i32.const "00000000" // arity - "01000000" // code_offset - "04000000" // imm_offset + "05000000" // code_offset + "00000000" // imm_offset "00000000"_bytes); // stack_drop /* wat2wasm @@ -142,9 +142,9 @@ TEST(parser_expr, loop_br) const auto module_arity = parse(wasm_arity); EXPECT_THAT(module_arity->codesec[0].instructions, - ElementsAre(Instr::loop, Instr::i32_const, Instr::br, Instr::end, Instr::drop, Instr::end)); + ElementsAre(Instr::loop, Instr::i32_const, 0, 0, 0, 0, Instr::br, Instr::end, Instr::drop, + Instr::end)); EXPECT_EQ(module_arity->codesec[0].immediates, - "00000000" // i32.const "00000000" // arity - always 0 for loop "00000000" // code_offset "00000000" // imm_offset @@ -184,18 +184,16 @@ TEST(parser_expr, block_br) const auto code_bin = "010240410a21010c00410b21010b20011a0b"_bytes; const auto [code, pos] = parse_expr(code_bin, 0, {{2, ValType::i32}}); - EXPECT_THAT( - code.instructions, ElementsAre(Instr::nop, Instr::block, Instr::i32_const, Instr::local_set, - Instr::br, Instr::i32_const, Instr::local_set, Instr::end, - Instr::local_get, Instr::drop, Instr::end)); + EXPECT_THAT(code.instructions, + ElementsAre(Instr::nop, Instr::block, Instr::i32_const, 0x0a, 0, 0, 0, Instr::local_set, + Instr::br, Instr::i32_const, 0x0b, 0, 0, 0, Instr::local_set, Instr::end, + Instr::local_get, Instr::drop, Instr::end)); EXPECT_EQ(code.immediates, - "0a000000" "01000000" "00000000" // arity - "08000000" // code_offset - "20000000" // imm_offset + "10000000" // code_offset + "18000000" // imm_offset "00000000" // stack_drop - "0b000000" "01000000" "01000000"_bytes); EXPECT_EQ(code.max_stack_height, 1); @@ -212,13 +210,12 @@ TEST(parser_expr, block_br) const auto module_parent_stack = parse(wasm_parent_stack); EXPECT_THAT(module_parent_stack->codesec[0].instructions, - ElementsAre( - Instr::i32_const, Instr::block, Instr::br, Instr::end, Instr::drop, Instr::end)); + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::block, Instr::br, Instr::end, Instr::drop, + Instr::end)); EXPECT_EQ(module_parent_stack->codesec[0].immediates, - "00000000" // i32.const "00000000" // arity - "04000000" // code_offset - "14000000" // imm_offset + "08000000" // code_offset + "10000000" // imm_offset "00000000"_bytes); // stack_drop /* wat2wasm @@ -234,14 +231,13 @@ TEST(parser_expr, block_br) from_hex("0061736d01000000010401600000030201000a0c010a00027f41000c000b1a0b"); const auto module_arity = parse(wasm_arity); - EXPECT_THAT( - module_arity->codesec[0].instructions, ElementsAre(Instr::block, Instr::i32_const, - Instr::br, Instr::end, Instr::drop, Instr::end)); + EXPECT_THAT(module_arity->codesec[0].instructions, + ElementsAre(Instr::block, Instr::i32_const, 0, 0, 0, 0, Instr::br, Instr::end, Instr::drop, + Instr::end)); EXPECT_EQ(module_arity->codesec[0].immediates, - "00000000" // i32.const "01000000" // arity - "04000000" // code_offset - "14000000" // imm_offset + "08000000" // code_offset + "10000000" // imm_offset "00000000"_bytes); // stack_drop } @@ -274,14 +270,13 @@ TEST(parser_expr, if_br) const auto module = parse(wasm); EXPECT_THAT(module->codesec[0].instructions, - ElementsAre(Instr::i32_const, Instr::if_, Instr::br, Instr::end, Instr::end)); + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::if_, Instr::br, Instr::end, Instr::end)); EXPECT_EQ(module->codesec[0].immediates, - "00000000" // i32.const - "04000000" // else code offset - "1c000000" // else imm offset + "08000000" // else code offset + "18000000" // else imm offset "00000000" // arity - "04000000" // code_offset - "1c000000" // imm_offset + "08000000" // code_offset + "18000000" // imm_offset "00000000"_bytes); // stack_drop /* wat2wasm @@ -297,16 +292,14 @@ TEST(parser_expr, if_br) const auto module_parent_stack = parse(wasm_parent_stack); EXPECT_THAT(module_parent_stack->codesec[0].instructions, - ElementsAre(Instr::i32_const, Instr::i32_const, Instr::if_, Instr::br, Instr::end, - Instr::drop, Instr::end)); + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::i32_const, 0, 0, 0, 0, Instr::if_, + Instr::br, Instr::end, Instr::drop, Instr::end)); EXPECT_EQ(module_parent_stack->codesec[0].immediates, - "00000000" // i32.const - "00000000" // i32.const - "05000000" // else code offset - "20000000" // else imm offset + "0d000000" // else code offset + "18000000" // else imm offset "00000000" // arity - "05000000" // code_offset - "20000000" // imm_offset + "0d000000" // code_offset + "18000000" // imm_offset "00000000"_bytes); // stack_drop } @@ -320,22 +313,22 @@ TEST(parser_expr, instr_br_table) (block (block (br_table 3 2 1 0 4 (get_local 0)) - (return (i32.const 99)) + (return (i32.const 0x41)) ) - (return (i32.const 100)) + (return (i32.const 0x42)) ) - (return (i32.const 101)) + (return (i32.const 0x43)) ) - (return (i32.const 102)) + (return (i32.const 0x44)) ) - (return (i32.const 103)) + (return (i32.const 0x45)) ) - (i32.const 104) + (i32.const 0x46) ) */ const auto wasm = from_hex( "0061736d0100000001060160017f017f030201000a330131000240024002400240024020000e04030201000441" - "e3000f0b41e4000f0b41e5000f0b41e6000f0b41e7000f0b41e8000b"); + "c1000f0b41c2000f0b41c3000f0b41c4000f0b41c5000f0b41c6000b"); const auto module = parse(wasm); ASSERT_EQ(module->codesec.size(), 1); @@ -343,10 +336,11 @@ TEST(parser_expr, instr_br_table) EXPECT_THAT(code.instructions, ElementsAre(Instr::block, Instr::block, Instr::block, Instr::block, Instr::block, - Instr::local_get, Instr::br_table, Instr::i32_const, Instr::return_, Instr::end, - Instr::i32_const, Instr::return_, Instr::end, Instr::i32_const, Instr::return_, - Instr::end, Instr::i32_const, Instr::return_, Instr::end, Instr::i32_const, - Instr::return_, Instr::end, Instr::i32_const, Instr::end)); + Instr::local_get, Instr::br_table, Instr::i32_const, 0x41, 0, 0, 0, Instr::return_, + Instr::end, Instr::i32_const, 0x42, 0, 0, 0, Instr::return_, Instr::end, + Instr::i32_const, 0x43, 0, 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x44, 0, + 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x45, 0, 0, 0, Instr::return_, + Instr::end, Instr::i32_const, 0x46, 0, 0, 0, Instr::end)); // 1 local_get before br_table const auto br_table_imm_offset = 4; @@ -361,24 +355,24 @@ TEST(parser_expr, instr_br_table) "04000000" // label_count "00000000" // arity - "13000000" // code_offset - "98000000" // imm_offset + "23000000" // code_offset + "88000000" // imm_offset "00000000" // stack_drop - "10000000" // code_offset - "84000000" // imm_offset + "1c000000" // code_offset + "78000000" // imm_offset "00000000" // stack_drop - "0d000000" // code_offset - "70000000" // imm_offset + "15000000" // code_offset + "68000000" // imm_offset "00000000" // stack_drop - "0a000000" // code_offset - "5c000000" // imm_offset + "0e000000" // code_offset + "58000000" // imm_offset "00000000" // stack_drop - "16000000" // code_offset - "ac000000" // imm_offset + "2a000000" // code_offset + "98000000" // imm_offset "00000000"_bytes; // stack_drop EXPECT_EQ(code.immediates.substr(br_table_imm_offset, expected_br_imm.size()), expected_br_imm); @@ -404,16 +398,16 @@ TEST(parser_expr, instr_br_table_empty_vector) const auto& code = module->codesec[0]; EXPECT_THAT(code.instructions, - ElementsAre(Instr::block, Instr::local_get, Instr::br_table, Instr::i32_const, - Instr::return_, Instr::end, Instr::i32_const, Instr::end)); + ElementsAre(Instr::block, Instr::local_get, Instr::br_table, Instr::i32_const, 0x63, 0, 0, + 0, Instr::return_, Instr::end, Instr::i32_const, 0x64, 0, 0, 0, Instr::end)); // local_get before br_table const auto br_table_imm_offset = 4; const auto expected_br_imm = "00000000" // label_count "00000000" // arity - "06000000" // code_offset - "2c000000" // imm_offset + "0a000000" // code_offset + "28000000" // imm_offset "00000000"_bytes; // stack_drop EXPECT_EQ(code.immediates.substr(br_table_imm_offset, expected_br_imm.size()), expected_br_imm); EXPECT_EQ(code.max_stack_height, 1); @@ -426,9 +420,10 @@ TEST(parser_expr, instr_br_table_as_return) br_table 0 */ - const auto code_bin = "41000e00000b"_bytes; + const auto code_bin = i32_const(0) + "0e00000b"_bytes; const auto [code, _] = parse_expr(code_bin); - EXPECT_THAT(code.instructions, ElementsAre(Instr::i32_const, Instr::br_table, Instr::end)); + EXPECT_THAT( + code.instructions, ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::br_table, Instr::end)); EXPECT_EQ(code.max_stack_height, 1); } @@ -464,7 +459,8 @@ TEST(parser_expr, call_indirect_table_index) const auto code1_bin = i32_const(0) + "1100000b"_bytes; const auto [code, pos] = parse_expr(code1_bin, 0, {}, module); - EXPECT_THAT(code.instructions, ElementsAre(Instr::i32_const, Instr::call_indirect, Instr::end)); + EXPECT_THAT(code.instructions, + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::call_indirect, Instr::end)); const auto code2_bin = i32_const(0) + "1100010b"_bytes; EXPECT_THROW_MESSAGE(parse_expr(code2_bin, 0, {}, module), parser_error, diff --git a/test/unittests/parser_test.cpp b/test/unittests/parser_test.cpp index c60c6ec12..620fcc7e7 100644 --- a/test/unittests/parser_test.cpp +++ b/test/unittests/parser_test.cpp @@ -1088,11 +1088,10 @@ TEST(parser, code_section_with_basic_instructions) EXPECT_EQ(module->typesec[0].outputs.size(), 0); ASSERT_EQ(module->codesec.size(), 1); EXPECT_EQ(module->codesec[0].local_count, 4); - EXPECT_THAT(module->codesec[0].instructions, - ElementsAre(Instr::local_get, Instr::i32_const, Instr::i32_add, Instr::local_set, - Instr::nop, Instr::unreachable, Instr::end)); - EXPECT_EQ(module->codesec[0].immediates, "010000000200000003000000"_bytes); + ElementsAre(Instr::local_get, Instr::i32_const, 2, 0, 0, 0, Instr::i32_add, + Instr::local_set, Instr::nop, Instr::unreachable, Instr::end)); + EXPECT_EQ(module->codesec[0].immediates, "0100000003000000"_bytes); } TEST(parser, code_section_with_memory_size) @@ -1137,8 +1136,8 @@ TEST(parser, code_section_with_memory_grow) ASSERT_EQ(module->codesec.size(), 1); EXPECT_EQ(module->codesec[0].local_count, 0); EXPECT_THAT(module->codesec[0].instructions, - ElementsAre(Instr::i32_const, Instr::memory_grow, Instr::drop, Instr::end)); - EXPECT_EQ(module->codesec[0].immediates, "00000000"_bytes); + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::memory_grow, Instr::drop, Instr::end)); + EXPECT_EQ(module->codesec[0].immediates.size(), 0); const auto func_bin_invalid = "00"_bytes + // vec(locals) i32_const(0) + "40011a0b"_bytes; From 712332ea72ded2dea3e996dafc0b7d77dde8dd28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Oct 2020 19:48:16 +0200 Subject: [PATCH 3/8] Move load/store offset immediate values to the instructions array --- lib/fizzy/execute.cpp | 42 ++++++++++++++++----------------- lib/fizzy/parser_expr.cpp | 5 ++-- test/unittests/execute_test.cpp | 32 ++++++++++++------------- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index d2b389d0a..80ca567f7 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -706,129 +706,129 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, } case Instr::i32_load: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i64_load: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::f32_load: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::f64_load: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i32_load8_s: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i32_load8_u: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i32_load16_s: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i32_load16_u: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i64_load8_s: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i64_load8_u: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i64_load16_s: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i64_load16_u: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i64_load32_s: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i64_load32_u: { - if (!load_from_memory(*memory, stack, immediates)) + if (!load_from_memory(*memory, stack, pc)) goto trap; break; } case Instr::i32_store: { - if (!store_into_memory(*memory, stack, immediates)) + if (!store_into_memory(*memory, stack, pc)) goto trap; break; } case Instr::i64_store: { - if (!store_into_memory(*memory, stack, immediates)) + if (!store_into_memory(*memory, stack, pc)) goto trap; break; } case Instr::f32_store: { - if (!store_into_memory(*memory, stack, immediates)) + if (!store_into_memory(*memory, stack, pc)) goto trap; break; } case Instr::f64_store: { - if (!store_into_memory(*memory, stack, immediates)) + if (!store_into_memory(*memory, stack, pc)) goto trap; break; } case Instr::i32_store8: case Instr::i64_store8: { - if (!store_into_memory(*memory, stack, immediates)) + if (!store_into_memory(*memory, stack, pc)) goto trap; break; } case Instr::i32_store16: case Instr::i64_store16: { - if (!store_into_memory(*memory, stack, immediates)) + if (!store_into_memory(*memory, stack, pc)) goto trap; break; } case Instr::i64_store32: { - if (!store_into_memory(*memory, stack, immediates)) + if (!store_into_memory(*memory, stack, pc)) goto trap; break; } diff --git a/lib/fizzy/parser_expr.cpp b/lib/fizzy/parser_expr.cpp index ef0b1411e..e391bc193 100644 --- a/lib/fizzy/parser_expr.cpp +++ b/lib/fizzy/parser_expr.cpp @@ -861,11 +861,12 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f uint32_t offset; std::tie(offset, pos) = leb128u_decode(pos, end); - push(code.immediates, offset); + code.instructions.push_back(opcode); + push(code.instructions, offset); if (!module.has_memory()) throw validation_error{"memory instructions require imported or defined memory"}; - break; + continue; } case Instr::memory_size: diff --git a/test/unittests/execute_test.cpp b/test/unittests/execute_test.cpp index d420e0ed5..84b6e9461 100644 --- a/test/unittests/execute_test.cpp +++ b/test/unittests/execute_test.cpp @@ -380,9 +380,9 @@ TEST(execute, i32_load_all_variants) from_hex("0061736d0100000001060160017f017f030201000504010101010a0901070020002802000b"); const auto module = parse(wasm); - auto& load_instr = const_cast(module->codesec[0].instructions[1]); - ASSERT_EQ(load_instr, Instr::i32_load); - ASSERT_EQ(module->codesec[0].immediates.substr(4), "00000000"_bytes); // load offset. + auto* const load_instr = const_cast(&module->codesec[0].instructions[1]); + ASSERT_EQ(*load_instr, Instr::i32_load); + ASSERT_EQ(bytes_view(load_instr + 1, 4), "00000000"_bytes); // load offset. const auto memory_fill = "deb0b1b2b3ed"_bytes; @@ -396,7 +396,7 @@ TEST(execute, i32_load_all_variants) for (const auto& [instr, expected] : test_cases) { - load_instr = static_cast(instr); + *load_instr = static_cast(instr); auto instance = instantiate(*module); std::copy(std::begin(memory_fill), std::end(memory_fill), std::begin(*instance->memory)); EXPECT_THAT(execute(*instance, 0, {1}), Result(expected)); @@ -418,9 +418,9 @@ TEST(execute, i64_load_all_variants) from_hex("0061736d0100000001060160017f017e030201000504010101010a0901070020002903000b"); const auto module = parse(wasm); - auto& load_instr = const_cast(module->codesec[0].instructions[1]); - ASSERT_EQ(load_instr, Instr::i64_load); - ASSERT_EQ(module->codesec[0].immediates.substr(4), "00000000"_bytes); // load offset. + auto* const load_instr = const_cast(&module->codesec[0].instructions[1]); + ASSERT_EQ(*load_instr, Instr::i64_load); + ASSERT_EQ(bytes_view(load_instr + 1, 4), "00000000"_bytes); // load offset. const auto memory_fill = "deb0b1b2b3b4b5b6b7ed"_bytes; @@ -436,7 +436,7 @@ TEST(execute, i64_load_all_variants) for (const auto& [instr, expected] : test_cases) { - load_instr = static_cast(instr); + *load_instr = static_cast(instr); auto instance = instantiate(*module); std::copy(std::begin(memory_fill), std::end(memory_fill), std::begin(*instance->memory)); EXPECT_THAT(execute(*instance, 0, {1}), Result(expected)); @@ -529,9 +529,9 @@ TEST(execute, i32_store_all_variants) from_hex("0061736d0100000001060160027f7f00030201000504010101010a0b010900200120003602000b"); const auto module = parse(wasm); - auto& store_instr = const_cast(module->codesec[0].instructions[2]); - ASSERT_EQ(store_instr, Instr::i32_store); - ASSERT_EQ(module->codesec[0].immediates.substr(8), "00000000"_bytes); // store offset + auto* const store_instr = const_cast(&module->codesec[0].instructions[2]); + ASSERT_EQ(*store_instr, Instr::i32_store); + ASSERT_EQ(bytes_view(store_instr + 1, 4), "00000000"_bytes); // store offset const std::tuple test_cases[]{ {Instr::i32_store8, "ccb0cccccccc"_bytes}, @@ -541,7 +541,7 @@ TEST(execute, i32_store_all_variants) for (const auto& [instr, expected] : test_cases) { - store_instr = static_cast(instr); + *store_instr = static_cast(instr); auto instance = instantiate(*module); std::fill_n(instance->memory->begin(), 6, uint8_t{0xcc}); EXPECT_THAT(execute(*instance, 0, {0xb3b2b1b0, 1}), Result()); @@ -565,9 +565,9 @@ TEST(execute, i64_store_all_variants) from_hex("0061736d0100000001060160027e7f00030201000504010101010a0b010900200120003703000b"); const auto module = parse(wasm); - auto& store_instr = const_cast(module->codesec[0].instructions[2]); - ASSERT_EQ(store_instr, Instr::i64_store); - ASSERT_EQ(module->codesec[0].immediates.substr(8), "00000000"_bytes); // store offset + auto* const store_instr = const_cast(&module->codesec[0].instructions[2]); + ASSERT_EQ(*store_instr, Instr::i64_store); + ASSERT_EQ(bytes_view(store_instr + 1, 4), "00000000"_bytes); // store offset const std::tuple test_cases[]{ {Instr::i64_store8, "ccb0cccccccccccccccc"_bytes}, @@ -578,7 +578,7 @@ TEST(execute, i64_store_all_variants) for (const auto& [instr, expected] : test_cases) { - store_instr = static_cast(instr); + *store_instr = static_cast(instr); auto instance = instantiate(*module); std::fill_n(instance->memory->begin(), 10, uint8_t{0xcc}); EXPECT_THAT(execute(*instance, 0, {0xb7b6b5b4b3b2b1b0, 1}), Result()); From 90c63c5fa5fcee6141fe4ae39c78369a9ce1f256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Oct 2020 19:58:37 +0200 Subject: [PATCH 4/8] Move locals immediate values to the instructions array --- lib/fizzy/execute.cpp | 10 ++-- lib/fizzy/parser_expr.cpp | 25 ++++++---- test/unittests/execute_numeric_test.cpp | 10 ++-- test/unittests/execute_test.cpp | 8 ++-- test/unittests/parser_expr_test.cpp | 61 ++++++++++++------------- test/unittests/parser_test.cpp | 18 +++----- 6 files changed, 64 insertions(+), 68 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index 80ca567f7..ac0cd2a89 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -655,25 +655,25 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, } case Instr::local_get: { - const auto idx = read(immediates); + const auto idx = read(pc); stack.push(stack.local(idx)); break; } case Instr::local_set: { - const auto idx = read(immediates); + const auto idx = read(pc); stack.local(idx) = stack.pop(); break; } case Instr::local_tee: { - const auto idx = read(immediates); + const auto idx = read(pc); stack.local(idx) = stack.top(); break; } case Instr::global_get: { - const auto idx = read(immediates); + const auto idx = read(pc); assert(idx < instance.imported_globals.size() + instance.globals.size()); if (idx < instance.imported_globals.size()) { @@ -689,7 +689,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, } case Instr::global_set: { - const auto idx = read(immediates); + const auto idx = read(pc); if (idx < instance.imported_globals.size()) { assert(instance.imported_globals[idx].type.is_mutable); diff --git a/lib/fizzy/parser_expr.cpp b/lib/fizzy/parser_expr.cpp index e391bc193..851eaf73b 100644 --- a/lib/fizzy/parser_expr.cpp +++ b/lib/fizzy/parser_expr.cpp @@ -733,8 +733,9 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f push_operand(operand_stack, find_local_type(func_inputs, locals, local_idx)); - push(code.immediates, local_idx); - break; + code.instructions.push_back(opcode); + push(code.instructions, local_idx); + continue; } case Instr::local_set: @@ -744,8 +745,9 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f drop_operand(frame, operand_stack, find_local_type(func_inputs, locals, local_idx)); - push(code.immediates, local_idx); - break; + code.instructions.push_back(opcode); + push(code.instructions, local_idx); + continue; } case Instr::local_tee: @@ -757,8 +759,9 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f drop_operand(frame, operand_stack, local_type); push_operand(operand_stack, local_type); - push(code.immediates, local_idx); - break; + code.instructions.push_back(opcode); + push(code.instructions, local_idx); + continue; } case Instr::global_get: @@ -771,8 +774,9 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f push_operand(operand_stack, module.get_global_type(global_idx).value_type); - push(code.immediates, global_idx); - break; + code.instructions.push_back(opcode); + push(code.instructions, global_idx); + continue; } case Instr::global_set: @@ -788,8 +792,9 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f drop_operand(frame, operand_stack, module.get_global_type(global_idx).value_type); - push(code.immediates, global_idx); - break; + code.instructions.push_back(opcode); + push(code.instructions, global_idx); + continue; } case Instr::i32_const: diff --git a/test/unittests/execute_numeric_test.cpp b/test/unittests/execute_numeric_test.cpp index 4662d2dc1..a054c6a76 100644 --- a/test/unittests/execute_numeric_test.cpp +++ b/test/unittests/execute_numeric_test.cpp @@ -21,9 +21,9 @@ ExecutionResult execute_unary_operation(Instr instr, uint64_t arg) module->typesec.emplace_back(FuncType{{ValType::i32}, {ValType::i32}}); module->funcsec.emplace_back(TypeIdx{0}); module->codesec.emplace_back(Code{1, 0, - {static_cast(Instr::local_get), static_cast(instr), + {static_cast(Instr::local_get), 0, 0, 0, 0, static_cast(instr), static_cast(Instr::end)}, - {0, 0, 0, 0}}); + {}}); return execute(*instantiate(std::move(module)), 0, {arg}); } @@ -35,9 +35,9 @@ ExecutionResult execute_binary_operation(Instr instr, uint64_t lhs, uint64_t rhs module->typesec.emplace_back(FuncType{{ValType::i32, ValType::i32}, {ValType::i32}}); module->funcsec.emplace_back(TypeIdx{0}); module->codesec.emplace_back(Code{2, 0, - {static_cast(Instr::local_get), static_cast(Instr::local_get), - static_cast(instr), static_cast(Instr::end)}, - {0, 0, 0, 0, 1, 0, 0, 0}}); + {static_cast(Instr::local_get), 0, 0, 0, 0, static_cast(Instr::local_get), + 1, 0, 0, 0, static_cast(instr), static_cast(Instr::end)}, + {}}); return execute(*instantiate(std::move(module)), 0, {lhs, rhs}); } diff --git a/test/unittests/execute_test.cpp b/test/unittests/execute_test.cpp index 84b6e9461..f84a501de 100644 --- a/test/unittests/execute_test.cpp +++ b/test/unittests/execute_test.cpp @@ -380,7 +380,7 @@ TEST(execute, i32_load_all_variants) from_hex("0061736d0100000001060160017f017f030201000504010101010a0901070020002802000b"); const auto module = parse(wasm); - auto* const load_instr = const_cast(&module->codesec[0].instructions[1]); + auto* const load_instr = const_cast(&module->codesec[0].instructions[5]); ASSERT_EQ(*load_instr, Instr::i32_load); ASSERT_EQ(bytes_view(load_instr + 1, 4), "00000000"_bytes); // load offset. @@ -418,7 +418,7 @@ TEST(execute, i64_load_all_variants) from_hex("0061736d0100000001060160017f017e030201000504010101010a0901070020002903000b"); const auto module = parse(wasm); - auto* const load_instr = const_cast(&module->codesec[0].instructions[1]); + auto* const load_instr = const_cast(&module->codesec[0].instructions[5]); ASSERT_EQ(*load_instr, Instr::i64_load); ASSERT_EQ(bytes_view(load_instr + 1, 4), "00000000"_bytes); // load offset. @@ -529,7 +529,7 @@ TEST(execute, i32_store_all_variants) from_hex("0061736d0100000001060160027f7f00030201000504010101010a0b010900200120003602000b"); const auto module = parse(wasm); - auto* const store_instr = const_cast(&module->codesec[0].instructions[2]); + auto* const store_instr = const_cast(&module->codesec[0].instructions[10]); ASSERT_EQ(*store_instr, Instr::i32_store); ASSERT_EQ(bytes_view(store_instr + 1, 4), "00000000"_bytes); // store offset @@ -565,7 +565,7 @@ TEST(execute, i64_store_all_variants) from_hex("0061736d0100000001060160027e7f00030201000504010101010a0b010900200120003703000b"); const auto module = parse(wasm); - auto* const store_instr = const_cast(&module->codesec[0].instructions[2]); + auto* const store_instr = const_cast(&module->codesec[0].instructions[10]); ASSERT_EQ(*store_instr, Instr::i64_store); ASSERT_EQ(bytes_view(store_instr + 1, 4), "00000000"_bytes); // store offset diff --git a/test/unittests/parser_expr_test.cpp b/test/unittests/parser_expr_test.cpp index 6c38e082d..2c64b78e7 100644 --- a/test/unittests/parser_expr_test.cpp +++ b/test/unittests/parser_expr_test.cpp @@ -185,17 +185,15 @@ TEST(parser_expr, block_br) const auto code_bin = "010240410a21010c00410b21010b20011a0b"_bytes; const auto [code, pos] = parse_expr(code_bin, 0, {{2, ValType::i32}}); EXPECT_THAT(code.instructions, - ElementsAre(Instr::nop, Instr::block, Instr::i32_const, 0x0a, 0, 0, 0, Instr::local_set, - Instr::br, Instr::i32_const, 0x0b, 0, 0, 0, Instr::local_set, Instr::end, - Instr::local_get, Instr::drop, Instr::end)); + ElementsAre(Instr::nop, Instr::block, Instr::i32_const, 0x0a, 0, 0, 0, Instr::local_set, 1, + 0, 0, 0, Instr::br, Instr::i32_const, 0x0b, 0, 0, 0, Instr::local_set, 1, 0, 0, 0, + Instr::end, Instr::local_get, 1, 0, 0, 0, Instr::drop, Instr::end)); EXPECT_EQ(code.immediates, - "01000000" - "00000000" // arity - "10000000" // code_offset - "18000000" // imm_offset - "00000000" // stack_drop - "01000000" - "01000000"_bytes); + "00000000" // arity + "18000000" // code_offset + "10000000" // imm_offset + "00000000"_bytes // stack_drop + ); EXPECT_EQ(code.max_stack_height, 1); /* wat2wasm @@ -336,14 +334,12 @@ TEST(parser_expr, instr_br_table) EXPECT_THAT(code.instructions, ElementsAre(Instr::block, Instr::block, Instr::block, Instr::block, Instr::block, - Instr::local_get, Instr::br_table, Instr::i32_const, 0x41, 0, 0, 0, Instr::return_, - Instr::end, Instr::i32_const, 0x42, 0, 0, 0, Instr::return_, Instr::end, + Instr::local_get, 0, 0, 0, 0, Instr::br_table, Instr::i32_const, 0x41, 0, 0, 0, + Instr::return_, Instr::end, Instr::i32_const, 0x42, 0, 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x43, 0, 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x44, 0, 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x45, 0, 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x46, 0, 0, 0, Instr::end)); - // 1 local_get before br_table - const auto br_table_imm_offset = 4; // br_imm_size = 12 // return_imm_size = br_imm_size + arity_size = 16 // br_0_offset = br_table_imm_offset + 4 + 4 + br_imm_size * 5 + 4 + return_imm_size = 92 = 0x5c @@ -355,27 +351,27 @@ TEST(parser_expr, instr_br_table) "04000000" // label_count "00000000" // arity - "23000000" // code_offset - "88000000" // imm_offset + "27000000" // code_offset + "84000000" // imm_offset "00000000" // stack_drop - "1c000000" // code_offset - "78000000" // imm_offset + "20000000" // code_offset + "74000000" // imm_offset "00000000" // stack_drop - "15000000" // code_offset - "68000000" // imm_offset + "19000000" // code_offset + "64000000" // imm_offset "00000000" // stack_drop - "0e000000" // code_offset - "58000000" // imm_offset + "12000000" // code_offset + "54000000" // imm_offset "00000000" // stack_drop - "2a000000" // code_offset - "98000000" // imm_offset + "2e000000" // code_offset + "94000000" // imm_offset "00000000"_bytes; // stack_drop - EXPECT_EQ(code.immediates.substr(br_table_imm_offset, expected_br_imm.size()), expected_br_imm); + EXPECT_EQ(code.immediates.substr(0, expected_br_imm.size()), expected_br_imm); EXPECT_EQ(code.max_stack_height, 1); } @@ -397,19 +393,18 @@ TEST(parser_expr, instr_br_table_empty_vector) ASSERT_EQ(module->codesec.size(), 1); const auto& code = module->codesec[0]; - EXPECT_THAT(code.instructions, - ElementsAre(Instr::block, Instr::local_get, Instr::br_table, Instr::i32_const, 0x63, 0, 0, - 0, Instr::return_, Instr::end, Instr::i32_const, 0x64, 0, 0, 0, Instr::end)); + EXPECT_THAT( + code.instructions, ElementsAre(Instr::block, Instr::local_get, 0, 0, 0, 0, Instr::br_table, + Instr::i32_const, 0x63, 0, 0, 0, Instr::return_, Instr::end, + Instr::i32_const, 0x64, 0, 0, 0, Instr::end)); - // local_get before br_table - const auto br_table_imm_offset = 4; const auto expected_br_imm = "00000000" // label_count "00000000" // arity - "0a000000" // code_offset - "28000000" // imm_offset + "0e000000" // code_offset + "24000000" // imm_offset "00000000"_bytes; // stack_drop - EXPECT_EQ(code.immediates.substr(br_table_imm_offset, expected_br_imm.size()), expected_br_imm); + EXPECT_EQ(code.immediates.substr(0, expected_br_imm.size()), expected_br_imm); EXPECT_EQ(code.max_stack_height, 1); } diff --git a/test/unittests/parser_test.cpp b/test/unittests/parser_test.cpp index 620fcc7e7..71514c017 100644 --- a/test/unittests/parser_test.cpp +++ b/test/unittests/parser_test.cpp @@ -1089,9 +1089,9 @@ TEST(parser, code_section_with_basic_instructions) ASSERT_EQ(module->codesec.size(), 1); EXPECT_EQ(module->codesec[0].local_count, 4); EXPECT_THAT(module->codesec[0].instructions, - ElementsAre(Instr::local_get, Instr::i32_const, 2, 0, 0, 0, Instr::i32_add, - Instr::local_set, Instr::nop, Instr::unreachable, Instr::end)); - EXPECT_EQ(module->codesec[0].immediates, "0100000003000000"_bytes); + ElementsAre(Instr::local_get, 1, 0, 0, 0, Instr::i32_const, 2, 0, 0, 0, Instr::i32_add, + Instr::local_set, 3, 0, 0, 0, Instr::nop, Instr::unreachable, Instr::end)); + EXPECT_EQ(module->codesec[0].immediates.size(), 0); } TEST(parser, code_section_with_memory_size) @@ -1458,12 +1458,8 @@ TEST(parser, milestone1) const auto& c = m->codesec[0]; EXPECT_EQ(c.local_count, 1); EXPECT_THAT(c.instructions, - ElementsAre(Instr::local_get, Instr::local_get, Instr::i32_add, Instr::local_get, - Instr::i32_add, Instr::local_tee, Instr::local_get, Instr::i32_add, Instr::end)); - EXPECT_EQ(c.immediates, - "00000000" - "01000000" - "02000000" - "02000000" - "00000000"_bytes); + ElementsAre(Instr::local_get, 0, 0, 0, 0, Instr::local_get, 1, 0, 0, 0, Instr::i32_add, + Instr::local_get, 2, 0, 0, 0, Instr::i32_add, Instr::local_tee, 2, 0, 0, 0, + Instr::local_get, 0, 0, 0, 0, Instr::i32_add, Instr::end)); + EXPECT_EQ(c.immediates.size(), 0); } From 908b2a48836d6d6a624765428e14b3ed7ac2eb58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 22 Oct 2020 18:08:00 +0200 Subject: [PATCH 5/8] Move call immediate values to the instructions array --- lib/fizzy/execute.cpp | 4 ++-- lib/fizzy/parser_expr.cpp | 12 +++++++----- test/unittests/parser_expr_test.cpp | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index ac0cd2a89..39d10cc6d 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -602,7 +602,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, } case Instr::call: { - const auto called_func_idx = read(immediates); + const auto called_func_idx = read(pc); const auto& called_func_type = instance.module->get_function_type(called_func_idx); if (!invoke_function(called_func_type, called_func_idx, instance, stack, depth)) @@ -613,7 +613,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, { assert(instance.table != nullptr); - const auto expected_type_idx = read(immediates); + const auto expected_type_idx = read(pc); assert(expected_type_idx < instance.module->typesec.size()); const auto elem_idx = stack.pop().as(); diff --git a/lib/fizzy/parser_expr.cpp b/lib/fizzy/parser_expr.cpp index 851eaf73b..62dab3542 100644 --- a/lib/fizzy/parser_expr.cpp +++ b/lib/fizzy/parser_expr.cpp @@ -698,8 +698,9 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f update_operand_stack( frame, operand_stack, callee_func_type.inputs, callee_func_type.outputs); - push(code.immediates, callee_func_idx); - break; + code.instructions.push_back(opcode); + push(code.instructions, callee_func_idx); + continue; } case Instr::call_indirect: @@ -717,13 +718,14 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f update_operand_stack( frame, operand_stack, callee_func_type.inputs, callee_func_type.outputs); - push(code.immediates, callee_type_idx); - uint8_t table_idx; std::tie(table_idx, pos) = parse_byte(pos, end); if (table_idx != 0) throw parser_error{"invalid tableidx encountered with call_indirect"}; - break; + + code.instructions.push_back(opcode); + push(code.instructions, callee_type_idx); + continue; } case Instr::local_get: diff --git a/test/unittests/parser_expr_test.cpp b/test/unittests/parser_expr_test.cpp index 2c64b78e7..f26a45ef1 100644 --- a/test/unittests/parser_expr_test.cpp +++ b/test/unittests/parser_expr_test.cpp @@ -455,7 +455,7 @@ TEST(parser_expr, call_indirect_table_index) const auto code1_bin = i32_const(0) + "1100000b"_bytes; const auto [code, pos] = parse_expr(code1_bin, 0, {}, module); EXPECT_THAT(code.instructions, - ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::call_indirect, Instr::end)); + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::call_indirect, 0, 0, 0, 0, Instr::end)); const auto code2_bin = i32_const(0) + "1100010b"_bytes; EXPECT_THROW_MESSAGE(parse_expr(code2_bin, 0, {}, module), parser_error, From 9b3d4b5a4f7304777793dce8343ca621822ded17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 22 Oct 2020 18:21:29 +0200 Subject: [PATCH 6/8] Move br_table immediate values to the instructions array --- lib/fizzy/execute.cpp | 4 +-- lib/fizzy/parser_expr.cpp | 7 ++-- test/unittests/parser_expr_test.cpp | 53 ++++++++++++++--------------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index 39d10cc6d..60eb24583 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -587,8 +587,8 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, } case Instr::br_table: { - const auto br_table_size = read(immediates); - const auto arity = read(immediates); + const auto br_table_size = read(pc); + const auto arity = read(pc); const auto br_table_idx = stack.pop().as(); diff --git a/lib/fizzy/parser_expr.cpp b/lib/fizzy/parser_expr.cpp index 62dab3542..052987c1e 100644 --- a/lib/fizzy/parser_expr.cpp +++ b/lib/fizzy/parser_expr.cpp @@ -634,7 +634,8 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f if (default_label_idx >= control_stack.size()) throw validation_error{"invalid label index"}; - push(code.immediates, static_cast(label_indices.size())); + code.instructions.push_back(opcode); + push(code.instructions, static_cast(label_indices.size())); auto& default_branch_frame = control_stack[default_label_idx]; const auto default_branch_type = get_branch_frame_type(default_branch_frame); @@ -642,7 +643,7 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f update_branch_stack(frame, default_branch_frame, operand_stack); // arity is the same for all indices, so we push it once - push(code.immediates, get_branch_arity(default_branch_frame)); + push(code.instructions, get_branch_arity(default_branch_frame)); // Remember immediates offset for all br items to fill them at end instruction. for (const auto idx : label_indices) @@ -662,7 +663,7 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f mark_frame_unreachable(frame, operand_stack); - break; + continue; } case Instr::return_: diff --git a/test/unittests/parser_expr_test.cpp b/test/unittests/parser_expr_test.cpp index f26a45ef1..02e74b181 100644 --- a/test/unittests/parser_expr_test.cpp +++ b/test/unittests/parser_expr_test.cpp @@ -334,11 +334,12 @@ TEST(parser_expr, instr_br_table) EXPECT_THAT(code.instructions, ElementsAre(Instr::block, Instr::block, Instr::block, Instr::block, Instr::block, - Instr::local_get, 0, 0, 0, 0, Instr::br_table, Instr::i32_const, 0x41, 0, 0, 0, - Instr::return_, Instr::end, Instr::i32_const, 0x42, 0, 0, 0, Instr::return_, Instr::end, - Instr::i32_const, 0x43, 0, 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x44, 0, - 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x45, 0, 0, 0, Instr::return_, - Instr::end, Instr::i32_const, 0x46, 0, 0, 0, Instr::end)); + Instr::local_get, 0, 0, 0, 0, Instr::br_table, /*label_count:*/ 4, 0, 0, 0, + /*arity:*/ 0, 0, 0, 0, Instr::i32_const, 0x41, 0, 0, 0, Instr::return_, Instr::end, + Instr::i32_const, 0x42, 0, 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x43, 0, + 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x44, 0, 0, 0, Instr::return_, + Instr::end, Instr::i32_const, 0x45, 0, 0, 0, Instr::return_, Instr::end, + Instr::i32_const, 0x46, 0, 0, 0, Instr::end)); // br_imm_size = 12 // return_imm_size = br_imm_size + arity_size = 16 @@ -348,27 +349,24 @@ TEST(parser_expr, instr_br_table) // br_3_offset = br_2_offset + 4 + return_imm_size = 0x98 // br_4_offset = br_3_offset + 4 + return_imm_size = 0xac const auto expected_br_imm = - "04000000" // label_count - "00000000" // arity - - "27000000" // code_offset - "84000000" // imm_offset + "2f000000" // code_offset + "7c000000" // imm_offset "00000000" // stack_drop - "20000000" // code_offset - "74000000" // imm_offset + "28000000" // code_offset + "6c000000" // imm_offset "00000000" // stack_drop - "19000000" // code_offset - "64000000" // imm_offset + "21000000" // code_offset + "5c000000" // imm_offset "00000000" // stack_drop - "12000000" // code_offset - "54000000" // imm_offset + "1a000000" // code_offset + "4c000000" // imm_offset "00000000" // stack_drop - "2e000000" // code_offset - "94000000" // imm_offset + "36000000" // code_offset + "8c000000" // imm_offset "00000000"_bytes; // stack_drop EXPECT_EQ(code.immediates.substr(0, expected_br_imm.size()), expected_br_imm); @@ -393,16 +391,14 @@ TEST(parser_expr, instr_br_table_empty_vector) ASSERT_EQ(module->codesec.size(), 1); const auto& code = module->codesec[0]; - EXPECT_THAT( - code.instructions, ElementsAre(Instr::block, Instr::local_get, 0, 0, 0, 0, Instr::br_table, - Instr::i32_const, 0x63, 0, 0, 0, Instr::return_, Instr::end, - Instr::i32_const, 0x64, 0, 0, 0, Instr::end)); + EXPECT_THAT(code.instructions, + ElementsAre(Instr::block, Instr::local_get, 0, 0, 0, 0, Instr::br_table, + /*label_count:*/ 0, 0, 0, 0, /*arity:*/ 0, 0, 0, 0, Instr::i32_const, 0x63, 0, 0, 0, + Instr::return_, Instr::end, Instr::i32_const, 0x64, 0, 0, 0, Instr::end)); const auto expected_br_imm = - "00000000" // label_count - "00000000" // arity - "0e000000" // code_offset - "24000000" // imm_offset + "16000000" // code_offset + "1c000000" // imm_offset "00000000"_bytes; // stack_drop EXPECT_EQ(code.immediates.substr(0, expected_br_imm.size()), expected_br_imm); EXPECT_EQ(code.max_stack_height, 1); @@ -417,8 +413,9 @@ TEST(parser_expr, instr_br_table_as_return) const auto code_bin = i32_const(0) + "0e00000b"_bytes; const auto [code, _] = parse_expr(code_bin); - EXPECT_THAT( - code.instructions, ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::br_table, Instr::end)); + EXPECT_THAT(code.instructions, + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::br_table, /*label_count:*/ 0, 0, 0, 0, + /*arity:*/ 0, 0, 0, 0, Instr::end)); EXPECT_EQ(code.max_stack_height, 1); } From bbcf33a7e9beb631d0a5fea1993d8c4f23fe6e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 21 Oct 2020 20:52:29 +0200 Subject: [PATCH 7/8] Move branch immediate values to the instructions array This also drop the immediates array as no longer needed. --- lib/fizzy/execute.cpp | 37 ++--- lib/fizzy/parser_expr.cpp | 95 ++++++------- lib/fizzy/types.hpp | 4 - test/unittests/execute_numeric_test.cpp | 6 +- test/unittests/parser_expr_test.cpp | 178 ++++++++---------------- test/unittests/parser_test.cpp | 6 - 6 files changed, 111 insertions(+), 215 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index 60eb24583..5b35a7e89 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -18,8 +18,8 @@ namespace fizzy { namespace { -// code_offset + imm_offset + stack_height -constexpr auto BranchImmediateSize = 3 * sizeof(uint32_t); +// code_offset + stack_drop +constexpr auto BranchImmediateSize = 2 * sizeof(uint32_t); constexpr uint32_t F32AbsMask = 0x7fffffff; constexpr uint32_t F32SignMask = ~F32AbsMask; @@ -453,15 +453,12 @@ __attribute__((no_sanitize("float-cast-overflow"))) inline constexpr float demot return static_cast(value); } -void branch(const Code& code, OperandStack& stack, const uint8_t*& pc, const uint8_t*& immediates, - uint32_t arity) noexcept +void branch(const Code& code, OperandStack& stack, const uint8_t*& pc, uint32_t arity) noexcept { - const auto code_offset = read(immediates); - const auto imm_offset = read(immediates); - const auto stack_drop = read(immediates); + const auto code_offset = read(pc); + const auto stack_drop = read(pc); pc = code.instructions.data() + code_offset; - immediates = code.immediates.data() + imm_offset; // When branch is taken, additional stack items must be dropped. assert(static_cast(stack_drop) >= 0); @@ -523,7 +520,6 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, static_cast(code.max_stack_height)); const uint8_t* pc = code.instructions.data(); - const uint8_t* immediates = code.immediates.data(); while (true) { @@ -539,14 +535,11 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, case Instr::if_: { if (stack.pop().as() != 0) - immediates += 2 * sizeof(uint32_t); // Skip the immediates for else instruction. + pc += sizeof(uint32_t); // Skip the immediate for else instruction. else { - const auto target_pc = read(immediates); - const auto target_imm = read(immediates); - + const auto target_pc = read(pc); pc = code.instructions.data() + target_pc; - immediates = code.immediates.data() + target_imm; } break; } @@ -554,12 +547,8 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, { // We reach else only after executing if block ("then" part), // so we need to skip else block now. - const auto target_pc = read(immediates); - const auto target_imm = read(immediates); - + const auto target_pc = read(pc); pc = code.instructions.data() + target_pc; - immediates = code.immediates.data() + target_imm; - break; } case Instr::end: @@ -573,16 +562,16 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, case Instr::br_if: case Instr::return_: { - const auto arity = read(immediates); + const auto arity = read(pc); // Check condition for br_if. if (instruction == Instr::br_if && stack.pop().as() == 0) { - immediates += BranchImmediateSize; + pc += BranchImmediateSize; break; } - branch(code, stack, pc, immediates, arity); + branch(code, stack, pc, arity); break; } case Instr::br_table: @@ -595,9 +584,9 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, const Value* args, const auto label_idx_offset = br_table_idx < br_table_size ? br_table_idx * BranchImmediateSize : br_table_size * BranchImmediateSize; - immediates += label_idx_offset; + pc += label_idx_offset; - branch(code, stack, pc, immediates, arity); + branch(code, stack, pc, arity); break; } case Instr::call: diff --git a/lib/fizzy/parser_expr.cpp b/lib/fizzy/parser_expr.cpp index 052987c1e..f75f2b4e9 100644 --- a/lib/fizzy/parser_expr.cpp +++ b/lib/fizzy/parser_expr.cpp @@ -19,14 +19,6 @@ inline void store(uint8_t* dst, T value) noexcept __builtin_memcpy(dst, &value, sizeof(value)); } -template -inline void push(bytes& b, T value) -{ - uint8_t storage[sizeof(T)]; - store(storage, value); - b.append(storage, sizeof(storage)); -} - template inline void push(std::vector& b, T value) { @@ -48,9 +40,6 @@ struct ControlFrame /// The target instruction code offset. const size_t code_offset{0}; - /// The immediates offset for block instructions. - const size_t immediates_offset{0}; - /// The frame stack height of the parent frame. const int parent_stack_height{0}; @@ -62,11 +51,10 @@ struct ControlFrame std::vector br_immediate_offsets{}; ControlFrame(Instr _instruction, std::optional _type, int _parent_stack_height, - size_t _code_offset = 0, size_t _immediates_offset = 0) noexcept + size_t _code_offset = 0) noexcept : instruction{_instruction}, type{_type}, code_offset{_code_offset}, - immediates_offset{_immediates_offset}, parent_stack_height{_parent_stack_height} {} }; @@ -210,16 +198,16 @@ inline void update_branch_stack(const ControlFrame& current_frame, const Control drop_operand(current_frame, operand_stack, from_valtype(*branch_frame_type)); } -void push_branch_immediates(const ControlFrame& branch_frame, int stack_height, bytes& immediates) +void push_branch_immediates( + const ControlFrame& branch_frame, int stack_height, std::vector& instructions) { // How many stack items to drop when taking the branch. const auto stack_drop = stack_height - branch_frame.parent_stack_height; // Push frame start location as br immediates - these are final if frame is loop, // but for block/if/else these are just placeholders, to be filled at end instruction. - push(immediates, static_cast(branch_frame.code_offset)); - push(immediates, static_cast(branch_frame.immediates_offset)); - push(immediates, static_cast(stack_drop)); + push(instructions, static_cast(branch_frame.code_offset)); + push(instructions, static_cast(stack_drop)); } inline void mark_frame_unreachable( @@ -473,7 +461,7 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f // Push label with immediates offset after arity. control_stack.emplace(Instr::block, block_type, static_cast(operand_stack.size()), - code.instructions.size(), code.immediates.size()); + code.instructions.size()); break; } @@ -483,7 +471,7 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f std::tie(loop_type, pos) = parse_blocktype(pos, end); control_stack.emplace(Instr::loop, loop_type, static_cast(operand_stack.size()), - code.instructions.size(), code.immediates.size()); + code.instructions.size()); break; } @@ -493,12 +481,12 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f std::tie(if_type, pos) = parse_blocktype(pos, end); control_stack.emplace(Instr::if_, if_type, static_cast(operand_stack.size()), - code.instructions.size(), code.immediates.size()); + code.instructions.size()); // Placeholders for immediate values, filled at the matching end or else instructions. - push(code.immediates, uint32_t{0}); // Diff to the else instruction - push(code.immediates, uint32_t{0}); // Diff for the immediates. - break; + code.instructions.push_back(opcode); + push(code.instructions, uint32_t{0}); // Diff to the else instruction + continue; } case Instr::else_: @@ -508,30 +496,28 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f update_result_stack(frame, operand_stack); // else is the end of if. - const auto if_imm_offset = frame.immediates_offset; + const auto if_imm_offset = frame.code_offset + 1; const auto frame_type = frame.type; auto frame_br_immediate_offsets = std::move(frame.br_immediate_offsets); control_stack.pop(); control_stack.emplace(Instr::else_, frame_type, static_cast(operand_stack.size()), - code.instructions.size(), code.immediates.size()); + code.instructions.size()); // br immediates from `then` branch will need to be filled at the end of `else` control_stack.top().br_immediate_offsets = std::move(frame_br_immediate_offsets); - // Placeholders for immediate values, filled at the matching end instructions. - push(code.immediates, uint32_t{0}); // Diff to the end instruction. - push(code.immediates, uint32_t{0}); // Diff for the immediates + code.instructions.push_back(opcode); + + // Placeholder for the immediate value, filled at the matching end instructions. + push(code.instructions, uint32_t{0}); // Diff to the end instruction. - // Fill in if's immediates with offsets of first instruction in else block. - const auto target_pc = static_cast(code.instructions.size() + 1); - const auto target_imm = static_cast(code.immediates.size()); + // Fill in if's immediate with the offset of first instruction in else block. + const auto target_pc = static_cast(code.instructions.size()); - // Set the imm values for else instruction. - auto* if_imm = code.immediates.data() + if_imm_offset; + // Set the imm values for if instruction. + auto* if_imm = code.instructions.data() + if_imm_offset; store(if_imm, target_pc); - if_imm += sizeof(target_pc); - store(if_imm, target_imm); - break; + continue; } case Instr::end: @@ -549,26 +535,21 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f const auto target_pc = control_stack.size() == 1 ? static_cast(code.instructions.size()) : static_cast(code.instructions.size() + 1); - const auto target_imm = static_cast(code.immediates.size()); if (frame.instruction == Instr::if_ || frame.instruction == Instr::else_) { // We're at the end instruction of the if block without else or at the end of - // else block. Fill in if/else's immediates with offsets of first instruction + // else block. Fill in if/else's immediate with the offset of first instruction // after if/else block. - auto* if_imm = code.immediates.data() + frame.immediates_offset; + auto* if_imm = code.instructions.data() + frame.code_offset + 1; store(if_imm, target_pc); - if_imm += sizeof(target_pc); - store(if_imm, target_imm); } // Fill in immediates all br/br_table instructions jumping out of this block. for (const auto br_imm_offset : frame.br_immediate_offsets) { - auto* br_imm = code.immediates.data() + br_imm_offset; + auto* br_imm = code.instructions.data() + br_imm_offset; store(br_imm, static_cast(target_pc)); - br_imm += sizeof(uint32_t); - store(br_imm, static_cast(target_imm)); // stack drop and arity were already stored in br handler } } @@ -596,13 +577,14 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f update_branch_stack(frame, branch_frame, operand_stack); - push(code.immediates, get_branch_arity(branch_frame)); + code.instructions.push_back(opcode); + push(code.instructions, get_branch_arity(branch_frame)); // Remember this br immediates offset to fill it at end instruction. - branch_frame.br_immediate_offsets.push_back(code.immediates.size()); + branch_frame.br_immediate_offsets.push_back(code.instructions.size()); push_branch_immediates( - branch_frame, static_cast(operand_stack.size()), code.immediates); + branch_frame, static_cast(operand_stack.size()), code.instructions); if (instr == Instr::br) mark_frame_unreachable(frame, operand_stack); @@ -615,7 +597,7 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f push_operand(operand_stack, *branch_frame.type); } - break; + continue; } case Instr::br_table: @@ -653,13 +635,13 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f if (get_branch_frame_type(branch_frame) != default_branch_type) throw validation_error{"br_table labels have inconsistent types"}; - branch_frame.br_immediate_offsets.push_back(code.immediates.size()); + branch_frame.br_immediate_offsets.push_back(code.instructions.size()); push_branch_immediates( - branch_frame, static_cast(operand_stack.size()), code.immediates); + branch_frame, static_cast(operand_stack.size()), code.instructions); } - default_branch_frame.br_immediate_offsets.push_back(code.immediates.size()); + default_branch_frame.br_immediate_offsets.push_back(code.instructions.size()); push_branch_immediates( - default_branch_frame, static_cast(operand_stack.size()), code.immediates); + default_branch_frame, static_cast(operand_stack.size()), code.instructions); mark_frame_unreachable(frame, operand_stack); @@ -676,15 +658,16 @@ parser_result parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f update_branch_stack(frame, branch_frame, operand_stack); - push(code.immediates, get_branch_arity(branch_frame)); + code.instructions.push_back(opcode); + push(code.instructions, get_branch_arity(branch_frame)); - branch_frame.br_immediate_offsets.push_back(code.immediates.size()); + branch_frame.br_immediate_offsets.push_back(code.instructions.size()); push_branch_immediates( - branch_frame, static_cast(operand_stack.size()), code.immediates); + branch_frame, static_cast(operand_stack.size()), code.instructions); mark_frame_unreachable(frame, operand_stack); - break; + continue; } case Instr::call: diff --git a/lib/fizzy/types.hpp b/lib/fizzy/types.hpp index b477ee1a2..82b0dd080 100644 --- a/lib/fizzy/types.hpp +++ b/lib/fizzy/types.hpp @@ -363,10 +363,6 @@ struct Code /// The instructions bytecode interleaved with decoded immediate values. /// https://webassembly.github.io/spec/core/binary/instructions.html std::vector instructions; - - // The decoded instructions' immediate values. - // These are instruction-type dependent fixed size value in the order of instructions. - bytes immediates; }; /// The reference to the `code` in the wasm binary. diff --git a/test/unittests/execute_numeric_test.cpp b/test/unittests/execute_numeric_test.cpp index a054c6a76..c76cd68d1 100644 --- a/test/unittests/execute_numeric_test.cpp +++ b/test/unittests/execute_numeric_test.cpp @@ -22,8 +22,7 @@ ExecutionResult execute_unary_operation(Instr instr, uint64_t arg) module->funcsec.emplace_back(TypeIdx{0}); module->codesec.emplace_back(Code{1, 0, {static_cast(Instr::local_get), 0, 0, 0, 0, static_cast(instr), - static_cast(Instr::end)}, - {}}); + static_cast(Instr::end)}}); return execute(*instantiate(std::move(module)), 0, {arg}); } @@ -36,8 +35,7 @@ ExecutionResult execute_binary_operation(Instr instr, uint64_t lhs, uint64_t rhs module->funcsec.emplace_back(TypeIdx{0}); module->codesec.emplace_back(Code{2, 0, {static_cast(Instr::local_get), 0, 0, 0, 0, static_cast(Instr::local_get), - 1, 0, 0, 0, static_cast(instr), static_cast(Instr::end)}, - {}}); + 1, 0, 0, 0, static_cast(instr), static_cast(Instr::end)}}); return execute(*instantiate(std::move(module)), 0, {lhs, rhs}); } diff --git a/test/unittests/parser_expr_test.cpp b/test/unittests/parser_expr_test.cpp index 02e74b181..0c235215e 100644 --- a/test/unittests/parser_expr_test.cpp +++ b/test/unittests/parser_expr_test.cpp @@ -29,28 +29,24 @@ TEST(parser_expr, instr_loop) const auto loop_void = "03400b0b"_bytes; const auto [code1, pos1] = parse_expr(loop_void); EXPECT_THAT(code1.instructions, ElementsAre(Instr::loop, Instr::end, Instr::end)); - EXPECT_EQ(code1.immediates.size(), 0); EXPECT_EQ(code1.max_stack_height, 0); const auto loop_i32 = "037f41000b1a0b"_bytes; const auto [code2, pos2] = parse_expr(loop_i32); EXPECT_THAT(code2.instructions, ElementsAre(Instr::loop, Instr::i32_const, 0, 0, 0, 0, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code2.immediates.size(), 0); EXPECT_EQ(code2.max_stack_height, 1); const auto loop_f32 = "037d43000000000b1a0b"_bytes; const auto [code3, pos3] = parse_expr(loop_f32); EXPECT_THAT(code3.instructions, ElementsAre(Instr::loop, Instr::f32_const, 0, 0, 0, 0, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code3.immediates.size(), 0); EXPECT_EQ(code3.max_stack_height, 1); const auto loop_f64 = "037c4400000000000000000b1a0b"_bytes; const auto [code4, pos4] = parse_expr(loop_f64); EXPECT_THAT(code4.instructions, ElementsAre(Instr::loop, Instr::f64_const, 0, 0, 0, 0, 0, 0, 0, 0, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code4.immediates.size(), 0); EXPECT_EQ(code4.max_stack_height, 1); } @@ -70,19 +66,16 @@ TEST(parser_expr, instr_block) const auto [code1, pos1] = parse_expr(empty); EXPECT_THAT(code1.instructions, ElementsAre(Instr::nop, Instr::nop, Instr::block, Instr::end, Instr::end)); - EXPECT_TRUE(code1.immediates.empty()); const auto block_i64 = "027e42000b1a0b"_bytes; const auto [code2, pos2] = parse_expr(block_i64); EXPECT_THAT(code2.instructions, ElementsAre(Instr::block, Instr::i64_const, 0, 0, 0, 0, 0, 0, 0, 0, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code2.immediates.size(), 0); const auto block_f64 = "027c4400000000000000000b1a0b"_bytes; const auto [code3, pos3] = parse_expr(block_f64); EXPECT_THAT(code3.instructions, ElementsAre(Instr::block, Instr::f64_const, 0, 0, 0, 0, 0, 0, 0, 0, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(code2.immediates.size(), 0); } TEST(parser_expr, instr_block_input_buffer_overflow) @@ -101,12 +94,8 @@ TEST(parser_expr, loop_br) const auto module = parse(wasm); EXPECT_THAT(module->codesec[0].instructions, - ElementsAre(Instr::loop, Instr::br, Instr::end, Instr::end)); - EXPECT_EQ(module->codesec[0].immediates, - "00000000" // code_offset - "00000000" // imm_offset - "00000000" // stack_drop - "00000000"_bytes); // arity + ElementsAre(Instr::loop, Instr::br, /*arity:*/ 0, 0, 0, 0, /*code_offset:*/ 0, 0, 0, 0, + /*stack_drop:*/ 0, 0, 0, 0, Instr::end, Instr::end)); /* wat2wasm (func @@ -120,13 +109,9 @@ TEST(parser_expr, loop_br) const auto module_parent_stack = parse(wasm_parent_stack); EXPECT_THAT(module_parent_stack->codesec[0].instructions, - ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::loop, Instr::br, Instr::end, Instr::drop, + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::loop, Instr::br, /*arity:*/ 0, 0, 0, 0, + /*code_offset:*/ 5, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(module_parent_stack->codesec[0].immediates, - "00000000" // arity - "05000000" // code_offset - "00000000" // imm_offset - "00000000"_bytes); // stack_drop /* wat2wasm (func @@ -142,13 +127,9 @@ TEST(parser_expr, loop_br) const auto module_arity = parse(wasm_arity); EXPECT_THAT(module_arity->codesec[0].instructions, - ElementsAre(Instr::loop, Instr::i32_const, 0, 0, 0, 0, Instr::br, Instr::end, Instr::drop, + ElementsAre(Instr::loop, Instr::i32_const, 0, 0, 0, 0, Instr::br, /*arity:*/ 0, 0, 0, 0, + /*code_offset:*/ 0, 0, 0, 0, /*stack_drop:*/ 1, 0, 0, 0, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(module_arity->codesec[0].immediates, - "00000000" // arity - always 0 for loop - "00000000" // code_offset - "00000000" // imm_offset - "01000000"_bytes); // stack_drop } TEST(parser_expr, loop_return) @@ -159,13 +140,10 @@ TEST(parser_expr, loop_return) const auto wasm = from_hex("0061736d01000000010401600000030201000a0801060003400f0b0b"); const auto module = parse(wasm); - EXPECT_THAT(module->codesec[0].instructions, - ElementsAre(Instr::loop, Instr::return_, Instr::end, Instr::end)); - EXPECT_EQ(module->codesec[0].immediates, - "00000000" // arity - "03000000" // code_offset - "10000000" // imm_offset - "00000000"_bytes); // stack_drop + EXPECT_THAT( + module->codesec[0].instructions, ElementsAre(Instr::loop, Instr::return_, + /*arity:*/ 0, 0, 0, 0, /*code_offset:*/ 15, 0, 0, 0, + /*stack_drop:*/ 0, 0, 0, 0, Instr::end, Instr::end)); } TEST(parser_expr, block_br) @@ -184,16 +162,12 @@ TEST(parser_expr, block_br) const auto code_bin = "010240410a21010c00410b21010b20011a0b"_bytes; const auto [code, pos] = parse_expr(code_bin, 0, {{2, ValType::i32}}); - EXPECT_THAT(code.instructions, - ElementsAre(Instr::nop, Instr::block, Instr::i32_const, 0x0a, 0, 0, 0, Instr::local_set, 1, - 0, 0, 0, Instr::br, Instr::i32_const, 0x0b, 0, 0, 0, Instr::local_set, 1, 0, 0, 0, - Instr::end, Instr::local_get, 1, 0, 0, 0, Instr::drop, Instr::end)); - EXPECT_EQ(code.immediates, - "00000000" // arity - "18000000" // code_offset - "10000000" // imm_offset - "00000000"_bytes // stack_drop - ); + EXPECT_THAT( + code.instructions, ElementsAre(Instr::nop, Instr::block, Instr::i32_const, 0x0a, 0, 0, 0, + Instr::local_set, 1, 0, 0, 0, Instr::br, /*arity:*/ 0, 0, 0, 0, + /*code_offset:*/ 36, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, + Instr::i32_const, 0x0b, 0, 0, 0, Instr::local_set, 1, 0, 0, 0, + Instr::end, Instr::local_get, 1, 0, 0, 0, Instr::drop, Instr::end)); EXPECT_EQ(code.max_stack_height, 1); /* wat2wasm @@ -208,13 +182,9 @@ TEST(parser_expr, block_br) const auto module_parent_stack = parse(wasm_parent_stack); EXPECT_THAT(module_parent_stack->codesec[0].instructions, - ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::block, Instr::br, Instr::end, Instr::drop, + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::block, Instr::br, /*arity:*/ 0, 0, 0, 0, + /*code_offset:*/ 20, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(module_parent_stack->codesec[0].immediates, - "00000000" // arity - "08000000" // code_offset - "10000000" // imm_offset - "00000000"_bytes); // stack_drop /* wat2wasm (func @@ -230,13 +200,9 @@ TEST(parser_expr, block_br) const auto module_arity = parse(wasm_arity); EXPECT_THAT(module_arity->codesec[0].instructions, - ElementsAre(Instr::block, Instr::i32_const, 0, 0, 0, 0, Instr::br, Instr::end, Instr::drop, + ElementsAre(Instr::block, Instr::i32_const, 0, 0, 0, 0, Instr::br, /*arity:*/ 1, 0, 0, 0, + /*code_offset:*/ 20, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(module_arity->codesec[0].immediates, - "01000000" // arity - "08000000" // code_offset - "10000000" // imm_offset - "00000000"_bytes); // stack_drop } TEST(parser_expr, block_return) @@ -248,12 +214,8 @@ TEST(parser_expr, block_return) const auto module = parse(wasm); EXPECT_THAT(module->codesec[0].instructions, - ElementsAre(Instr::block, Instr::return_, Instr::end, Instr::end)); - EXPECT_EQ(module->codesec[0].immediates, - "00000000" // arity - "03000000" // code_offset - "10000000" // imm_offset - "00000000"_bytes); // stack_drop + ElementsAre(Instr::block, Instr::return_, /*arity:*/ 0, 0, 0, 0, + /*code_offset:*/ 15, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, Instr::end)); } TEST(parser_expr, if_br) @@ -268,14 +230,10 @@ TEST(parser_expr, if_br) const auto module = parse(wasm); EXPECT_THAT(module->codesec[0].instructions, - ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::if_, Instr::br, Instr::end, Instr::end)); - EXPECT_EQ(module->codesec[0].immediates, - "08000000" // else code offset - "18000000" // else imm offset - "00000000" // arity - "08000000" // code_offset - "18000000" // imm_offset - "00000000"_bytes); // stack_drop + ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::if_, /*else_offset:*/ 24, 0, 0, 0, + Instr::br, /*arity:*/ 0, 0, 0, 0, + /*code_offset:*/ 24, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, + /*24:*/ Instr::end)); /* wat2wasm (func @@ -291,14 +249,9 @@ TEST(parser_expr, if_br) EXPECT_THAT(module_parent_stack->codesec[0].instructions, ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::i32_const, 0, 0, 0, 0, Instr::if_, - Instr::br, Instr::end, Instr::drop, Instr::end)); - EXPECT_EQ(module_parent_stack->codesec[0].immediates, - "0d000000" // else code offset - "18000000" // else imm offset - "00000000" // arity - "0d000000" // code_offset - "18000000" // imm_offset - "00000000"_bytes); // stack_drop + /*else_offset:*/ 29, 0, 0, 0, Instr::br, /*arity:*/ 0, 0, 0, 0, + /*code_offset:*/ 29, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, + /*29:*/ Instr::end, Instr::drop, Instr::end)); } TEST(parser_expr, instr_br_table) @@ -334,42 +287,27 @@ TEST(parser_expr, instr_br_table) EXPECT_THAT(code.instructions, ElementsAre(Instr::block, Instr::block, Instr::block, Instr::block, Instr::block, - Instr::local_get, 0, 0, 0, 0, Instr::br_table, /*label_count:*/ 4, 0, 0, 0, - /*arity:*/ 0, 0, 0, 0, Instr::i32_const, 0x41, 0, 0, 0, Instr::return_, Instr::end, - Instr::i32_const, 0x42, 0, 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x43, 0, - 0, 0, Instr::return_, Instr::end, Instr::i32_const, 0x44, 0, 0, 0, Instr::return_, - Instr::end, Instr::i32_const, 0x45, 0, 0, 0, Instr::return_, Instr::end, - Instr::i32_const, 0x46, 0, 0, 0, Instr::end)); - - // br_imm_size = 12 - // return_imm_size = br_imm_size + arity_size = 16 - // br_0_offset = br_table_imm_offset + 4 + 4 + br_imm_size * 5 + 4 + return_imm_size = 92 = 0x5c - // br_1_offset = br_0_offset + 4 + return_imm_size = 0x70 - // br_2_offset = br_1_offset + 4 + return_imm_size = 0x84 - // br_3_offset = br_2_offset + 4 + return_imm_size = 0x98 - // br_4_offset = br_3_offset + 4 + return_imm_size = 0xac - const auto expected_br_imm = - "2f000000" // code_offset - "7c000000" // imm_offset - "00000000" // stack_drop - - "28000000" // code_offset - "6c000000" // imm_offset - "00000000" // stack_drop - - "21000000" // code_offset - "5c000000" // imm_offset - "00000000" // stack_drop - - "1a000000" // code_offset - "4c000000" // imm_offset - "00000000" // stack_drop - - "36000000" // code_offset - "8c000000" // imm_offset - "00000000"_bytes; // stack_drop - - EXPECT_EQ(code.immediates.substr(0, expected_br_imm.size()), expected_br_imm); + Instr::local_get, 0, 0, 0, 0, Instr::br_table, + /*label_count:*/ 4, 0, 0, 0, /*arity:*/ 0, 0, 0, 0, + /*code_offset:*/ 135, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, + /*code_offset:*/ 116, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, + /*code_offset:*/ 97, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, + /*code_offset:*/ 78, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, + /*code_offset:*/ 154, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, + + /*59:*/ Instr::i32_const, 0x41, 0, 0, 0, Instr::return_, /*arity:*/ 1, 0, 0, 0, + /*code_offset:*/ 159, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, + /*78:*/ Instr::i32_const, 0x42, 0, 0, 0, Instr::return_, /*arity:*/ 1, 0, 0, 0, + /*code_offset:*/ 159, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, + /*97:*/ Instr::i32_const, 0x43, 0, 0, 0, Instr::return_, /*arity:*/ 1, 0, 0, 0, + /*code_offset:*/ 159, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, + /*116:*/ Instr::i32_const, 0x44, 0, 0, 0, Instr::return_, /*arity:*/ 1, 0, 0, 0, + /*code_offset:*/ 159, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, + /*135:*/ Instr::i32_const, 0x45, 0, 0, 0, Instr::return_, /*arity:*/ 1, 0, 0, 0, + /*code_offset:*/ 159, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, Instr::end, + /*154:*/ Instr::i32_const, 0x46, 0, 0, 0, + /*159:*/ Instr::end)); + EXPECT_EQ(code.max_stack_height, 1); } @@ -393,14 +331,11 @@ TEST(parser_expr, instr_br_table_empty_vector) EXPECT_THAT(code.instructions, ElementsAre(Instr::block, Instr::local_get, 0, 0, 0, 0, Instr::br_table, - /*label_count:*/ 0, 0, 0, 0, /*arity:*/ 0, 0, 0, 0, Instr::i32_const, 0x63, 0, 0, 0, - Instr::return_, Instr::end, Instr::i32_const, 0x64, 0, 0, 0, Instr::end)); - - const auto expected_br_imm = - "16000000" // code_offset - "1c000000" // imm_offset - "00000000"_bytes; // stack_drop - EXPECT_EQ(code.immediates.substr(0, expected_br_imm.size()), expected_br_imm); + /*label_count:*/ 0, 0, 0, 0, /*arity:*/ 0, 0, 0, 0, /*code_offset:*/ 42, 0, 0, 0, + /*stack_drop:*/ 0, 0, 0, 0, Instr::i32_const, 0x63, 0, 0, 0, Instr::return_, + /*arity:*/ 1, 0, 0, 0, /*code_offset:*/ 47, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, + Instr::end, Instr::i32_const, 0x64, 0, 0, 0, Instr::end)); + EXPECT_EQ(code.max_stack_height, 1); } @@ -415,7 +350,8 @@ TEST(parser_expr, instr_br_table_as_return) const auto [code, _] = parse_expr(code_bin); EXPECT_THAT(code.instructions, ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::br_table, /*label_count:*/ 0, 0, 0, 0, - /*arity:*/ 0, 0, 0, 0, Instr::end)); + /*arity:*/ 0, 0, 0, 0, /*code_offset:*/ 22, 0, 0, 0, /*stack_drop:*/ 0, 0, 0, 0, + Instr::end)); EXPECT_EQ(code.max_stack_height, 1); } diff --git a/test/unittests/parser_test.cpp b/test/unittests/parser_test.cpp index 71514c017..9cdc97d28 100644 --- a/test/unittests/parser_test.cpp +++ b/test/unittests/parser_test.cpp @@ -1028,7 +1028,6 @@ TEST(parser, code_with_empty_expr_2_locals) const auto& code_obj = module->codesec[0]; EXPECT_EQ(code_obj.local_count, 2); EXPECT_THAT(code_obj.instructions, ElementsAre(Instr::end)); - EXPECT_EQ(code_obj.immediates.size(), 0); } TEST(parser, code_with_empty_expr_5_locals) @@ -1044,7 +1043,6 @@ TEST(parser, code_with_empty_expr_5_locals) const auto& code_obj = module->codesec[0]; EXPECT_EQ(code_obj.local_count, 5); EXPECT_THAT(code_obj.instructions, ElementsAre(Instr::end)); - EXPECT_EQ(code_obj.immediates.size(), 0); } TEST(parser, code_section_with_2_trivial_codes) @@ -1091,7 +1089,6 @@ TEST(parser, code_section_with_basic_instructions) EXPECT_THAT(module->codesec[0].instructions, ElementsAre(Instr::local_get, 1, 0, 0, 0, Instr::i32_const, 2, 0, 0, 0, Instr::i32_add, Instr::local_set, 3, 0, 0, 0, Instr::nop, Instr::unreachable, Instr::end)); - EXPECT_EQ(module->codesec[0].immediates.size(), 0); } TEST(parser, code_section_with_memory_size) @@ -1108,7 +1105,6 @@ TEST(parser, code_section_with_memory_size) ASSERT_EQ(module->codesec.size(), 1); EXPECT_EQ(module->codesec[0].local_count, 0); EXPECT_THAT(module->codesec[0].instructions, ElementsAre(Instr::memory_size, Instr::end)); - EXPECT_TRUE(module->codesec[0].immediates.empty()); const auto func_bin_invalid = "00" // vec(locals) @@ -1137,7 +1133,6 @@ TEST(parser, code_section_with_memory_grow) EXPECT_EQ(module->codesec[0].local_count, 0); EXPECT_THAT(module->codesec[0].instructions, ElementsAre(Instr::i32_const, 0, 0, 0, 0, Instr::memory_grow, Instr::drop, Instr::end)); - EXPECT_EQ(module->codesec[0].immediates.size(), 0); const auto func_bin_invalid = "00"_bytes + // vec(locals) i32_const(0) + "40011a0b"_bytes; @@ -1461,5 +1456,4 @@ TEST(parser, milestone1) ElementsAre(Instr::local_get, 0, 0, 0, 0, Instr::local_get, 1, 0, 0, 0, Instr::i32_add, Instr::local_get, 2, 0, 0, 0, Instr::i32_add, Instr::local_tee, 2, 0, 0, 0, Instr::local_get, 0, 0, 0, 0, Instr::i32_add, Instr::end)); - EXPECT_EQ(c.immediates.size(), 0); } From 1bb954b3071583ee2b0767ac328893a938f39375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 22 Oct 2020 20:27:51 +0200 Subject: [PATCH 8/8] ci: Lower the number or parallel compilations --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 6ab205f79..e7a64f762 100644 --- a/circle.yml +++ b/circle.yml @@ -390,7 +390,7 @@ jobs: sanitizers-gcc: executor: linux-gcc-latest environment: - CMAKE_BUILD_PARALLEL_LEVEL: 6 + CMAKE_BUILD_PARALLEL_LEVEL: 2 # TODO: Enable detect_stack_use_after_return=1 when https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97414 is fixed. ASAN_OPTIONS: detect_invalid_pointer_pairs=2:check_initialization_order=1 UBSAN_OPTIONS: halt_on_error=1