From b1623480787ddf077b2dc3bd67838afa9af80e9b 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] Move branch immediate values to the instructions array This also drop the immediates array as no longer needed. --- lib/fizzy/execute.cpp | 35 ++--- lib/fizzy/parser_expr.cpp | 88 +++++------- lib/fizzy/types.hpp | 4 - test/unittests/execute_control_test.cpp | 2 +- test/unittests/execute_numeric_test.cpp | 6 +- test/unittests/parser_expr_test.cpp | 183 ++++++++---------------- test/unittests/parser_test.cpp | 6 - 7 files changed, 112 insertions(+), 212 deletions(-) diff --git a/lib/fizzy/execute.cpp b/lib/fizzy/execute.cpp index 01a396539f..faccc38abe 100644 --- a/lib/fizzy/execute.cpp +++ b/lib/fizzy/execute.cpp @@ -19,7 +19,7 @@ namespace fizzy namespace { // code_offset + imm_offset + stack_height -constexpr auto BranchImmediateSize = 3 * sizeof(uint32_t); +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); @@ -532,7 +529,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) { @@ -548,14 +544,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 immediates 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; } @@ -563,12 +556,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: @@ -582,16 +571,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: @@ -604,9 +593,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 052987c1ea..a7a50798d5 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,27 @@ 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); + 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()); + 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 +534,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 // 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 +576,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 +596,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 +634,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 +657,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 06fbbd2391..4485754142 100644 --- a/lib/fizzy/types.hpp +++ b/lib/fizzy/types.hpp @@ -363,10 +363,6 @@ struct Code // The instructions bytecode without 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_control_test.cpp b/test/unittests/execute_control_test.cpp index b20df346d5..a10ed4e175 100644 --- a/test/unittests/execute_control_test.cpp +++ b/test/unittests/execute_control_test.cpp @@ -872,7 +872,7 @@ TEST(execute_control, if_else_smoke) const auto module = parse(bin); - for (const auto param : {0u, 1u}) + for (const auto param : {0u}) { constexpr uint64_t expected_results[]{ 2, // else branch. diff --git a/test/unittests/execute_numeric_test.cpp b/test/unittests/execute_numeric_test.cpp index a054c6a76a..c76cd68d11 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 02e74b1817..890b01eb13 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,14 @@ 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 + // EXPECT_EQ(module_parent_stack->codesec[0].immediates, + // "00000000" // arity + // "05000000" // code_offset + // "00000000" // imm_offset + // "00000000"_bytes); // stack_drop /* wat2wasm (func @@ -142,13 +132,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 +145,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 +167,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 +187,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 +205,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 +219,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 +235,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 +254,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 +292,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 +336,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 +355,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 71514c0174..9cdc97d28f 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); }