From 5de5588f0c0fbc088297d0959d121e97afdd67fb Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Fri, 28 May 2021 19:36:26 +0200 Subject: [PATCH] Support EOF execution in advanced --- lib/evmone/analysis.cpp | 8 +++++--- lib/evmone/analysis.hpp | 3 ++- lib/evmone/execution.cpp | 6 +++++- test/bench/helpers.hpp | 2 +- test/unittests/analysis_test.cpp | 21 +++++++++++---------- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/evmone/analysis.cpp b/lib/evmone/analysis.cpp index bf7750564e..47d15e1edb 100644 --- a/lib/evmone/analysis.cpp +++ b/lib/evmone/analysis.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "analysis.hpp" +#include "eof.hpp" #include "opcodes_helpers.h" #include @@ -39,7 +40,8 @@ struct block_analysis } }; -AdvancedCodeAnalysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) noexcept +AdvancedCodeAnalysis analyze( + evmc_revision rev, const uint8_t* code, size_t code_size, const EOF1Header& header) noexcept { const auto& op_tbl = get_op_table(rev); const auto opx_beginblock_fn = op_tbl[OPX_BEGINBLOCK].fn; @@ -57,8 +59,8 @@ AdvancedCodeAnalysis analyze(evmc_revision rev, const uint8_t* code, size_t code analysis.instrs.emplace_back(opx_beginblock_fn); auto block = block_analysis{0}; - const auto code_end = code + code_size; - auto code_pos = code; + const auto code_end = header.code_end(code, code_size); + auto code_pos = header.code_begin(code); while (code_pos != code_end) { diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index c80069b7f6..5e8a553dc6 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -15,6 +15,7 @@ namespace evmone { +struct EOF1Header; struct instruction; /// Compressed information about instruction basic block. @@ -149,7 +150,7 @@ inline int find_jumpdest(const AdvancedCodeAnalysis& analysis, int offset) noexc } EVMC_EXPORT AdvancedCodeAnalysis analyze( - evmc_revision rev, const uint8_t* code, size_t code_size) noexcept; + evmc_revision rev, const uint8_t* code, size_t code_size, const EOF1Header& header) noexcept; EVMC_EXPORT const op_table& get_op_table(evmc_revision rev) noexcept; diff --git a/lib/evmone/execution.cpp b/lib/evmone/execution.cpp index 266adbcb4a..74a46a2f24 100644 --- a/lib/evmone/execution.cpp +++ b/lib/evmone/execution.cpp @@ -4,6 +4,7 @@ #include "execution.hpp" #include "analysis.hpp" +#include "eof.hpp" #include namespace evmone @@ -26,7 +27,10 @@ evmc_result execute(AdvancedExecutionState& state, const AdvancedCodeAnalysis& a evmc_result execute(evmc_vm* /*unused*/, const evmc_host_interface* host, evmc_host_context* ctx, evmc_revision rev, const evmc_message* msg, const uint8_t* code, size_t code_size) noexcept { - const auto analysis = analyze(rev, code, code_size); + EOF1Header eof1_header; + if (is_eof_code(code, code_size)) + eof1_header = read_valid_eof1_header(code); + const auto analysis = analyze(rev, code, code_size, eof1_header); auto state = std::make_unique(*msg, rev, *host, ctx, code, code_size); return execute(*state, analysis); } diff --git a/test/bench/helpers.hpp b/test/bench/helpers.hpp index 804260a74f..c75e80defc 100644 --- a/test/bench/helpers.hpp +++ b/test/bench/helpers.hpp @@ -23,7 +23,7 @@ inline void analyse(benchmark::State& state, evmc_revision rev, bytes_view code) auto bytes_analysed = uint64_t{0}; for (auto _ : state) { - auto r = evmone::analyze(rev, code.data(), code.size()); + auto r = evmone::analyze(rev, code.data(), code.size(), {}); benchmark::DoNotOptimize(r); bytes_analysed += code.size(); } diff --git a/test/unittests/analysis_test.cpp b/test/unittests/analysis_test.cpp index 5850796a78..89bc0f0882 100644 --- a/test/unittests/analysis_test.cpp +++ b/test/unittests/analysis_test.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -16,7 +17,7 @@ const auto& op_tbl = get_op_table(rev); TEST(analysis, example1) { const auto code = push(0x2a) + push(0x1e) + OP_MSTORE8 + OP_MSIZE + push(0) + OP_SSTORE; - const auto analysis = analyze(rev, &code[0], code.size()); + const auto analysis = analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.instrs.size(), 8); @@ -38,7 +39,7 @@ TEST(analysis, example1) TEST(analysis, stack_up_and_down) { const auto code = OP_DUP2 + 6 * OP_DUP1 + 10 * OP_POP + push(0); - const auto analysis = analyze(rev, &code[0], code.size()); + const auto analysis = analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.instrs.size(), 20); EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); @@ -57,7 +58,7 @@ TEST(analysis, push) { constexpr auto push_value = 0x8807060504030201; const auto code = push(push_value) + "7f00ee"; - const auto analysis = analyze(rev, &code[0], code.size()); + const auto analysis = analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.instrs.size(), 4); ASSERT_EQ(analysis.push_values.size(), 1); @@ -73,7 +74,7 @@ TEST(analysis, jumpdest_skip) // and no new block should be created in this place. const auto code = bytecode{} + OP_STOP + OP_JUMPDEST; - auto analysis = evmone::analyze(rev, &code[0], code.size()); + auto analysis = evmone::analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.instrs.size(), 4); EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); @@ -85,7 +86,7 @@ TEST(analysis, jumpdest_skip) TEST(analysis, jump1) { const auto code = jump(add(4, 2)) + OP_JUMPDEST + mstore(0, 3) + ret(0, 0x20) + jump(6); - const auto analysis = analyze(rev, &code[0], code.size()); + const auto analysis = analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.jumpdest_offsets.size(), 1); ASSERT_EQ(analysis.jumpdest_targets.size(), 1); @@ -99,7 +100,7 @@ TEST(analysis, jump1) TEST(analysis, empty) { bytes code; - auto analysis = evmone::analyze(rev, &code[0], code.size()); + auto analysis = evmone::analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.instrs.size(), 2); EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); @@ -109,7 +110,7 @@ TEST(analysis, empty) TEST(analysis, only_jumpdest) { const auto code = bytecode{OP_JUMPDEST}; - auto analysis = evmone::analyze(rev, &code[0], code.size()); + auto analysis = evmone::analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.jumpdest_offsets.size(), 1); ASSERT_EQ(analysis.jumpdest_targets.size(), 1); @@ -120,7 +121,7 @@ TEST(analysis, only_jumpdest) TEST(analysis, jumpi_at_the_end) { const auto code = bytecode{OP_JUMPI}; - auto analysis = evmone::analyze(rev, &code[0], code.size()); + auto analysis = evmone::analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.instrs.size(), 4); EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); @@ -134,7 +135,7 @@ TEST(analysis, terminated_last_block) // TODO: Even if the last basic block is properly terminated an additional artificial block // is going to be created with only STOP instruction. const auto code = ret(0, 0); - auto analysis = evmone::analyze(rev, &code[0], code.size()); + auto analysis = evmone::analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.instrs.size(), 6); EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); @@ -146,7 +147,7 @@ TEST(analysis, terminated_last_block) TEST(analysis, jumpdests_groups) { const auto code = 3 * OP_JUMPDEST + push(1) + 3 * OP_JUMPDEST + push(2) + OP_JUMPI; - auto analysis = evmone::analyze(rev, &code[0], code.size()); + auto analysis = evmone::analyze(rev, &code[0], code.size(), {}); ASSERT_EQ(analysis.instrs.size(), 11); EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OP_JUMPDEST].fn);