From 4ea2270d4b397026300853fe531b5a1437416d44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Sep 2019 17:00:26 +0200 Subject: [PATCH 1/6] Rename exec_fn_table to op_table --- lib/evmone/analysis.hpp | 4 +- lib/evmone/instructions.cpp | 16 +++---- test/unittests/analysis_test.cpp | 80 ++++++++++++++++---------------- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index 0c8900981a..646f078ecf 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -170,7 +170,7 @@ enum intrinsic_opcodes OPX_BEGINBLOCK = OP_JUMPDEST }; -using exec_fn_table = std::array; +using op_table = std::array; struct instr_info { @@ -213,6 +213,6 @@ inline int find_jumpdest(const code_analysis& analysis, int offset) noexcept EVMC_EXPORT code_analysis analyze( evmc_revision rev, const uint8_t* code, size_t code_size) noexcept; -EVMC_EXPORT const exec_fn_table& get_op_table(evmc_revision rev) noexcept; +EVMC_EXPORT const op_table& get_op_table(evmc_revision rev) noexcept; } // namespace evmone diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index c8118cb18a..1e8a350e43 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -1217,9 +1217,9 @@ const instr_info* opx_beginblock(const instr_info* instr, execution_state& state return ++instr; } -constexpr exec_fn_table create_op_table_frontier() noexcept +constexpr op_table create_op_table_frontier() noexcept { - auto table = exec_fn_table{}; + auto table = op_table{}; // First, mark all opcodes as undefined. for (auto& t : table) @@ -1334,14 +1334,14 @@ constexpr exec_fn_table create_op_table_frontier() noexcept return table; } -constexpr exec_fn_table create_op_table_homestead() noexcept +constexpr op_table create_op_table_homestead() noexcept { auto table = create_op_table_frontier(); table[OP_DELEGATECALL] = op_delegatecall; return table; } -constexpr exec_fn_table create_op_table_byzantium() noexcept +constexpr op_table create_op_table_byzantium() noexcept { auto table = create_op_table_homestead(); table[OP_RETURNDATASIZE] = op_returndatasize; @@ -1351,7 +1351,7 @@ constexpr exec_fn_table create_op_table_byzantium() noexcept return table; } -constexpr exec_fn_table create_op_table_constantinople() noexcept +constexpr op_table create_op_table_constantinople() noexcept { auto table = create_op_table_byzantium(); table[OP_SHL] = op_shl; @@ -1362,13 +1362,13 @@ constexpr exec_fn_table create_op_table_constantinople() noexcept return table; } -constexpr exec_fn_table create_op_table_istanbul() noexcept +constexpr op_table create_op_table_istanbul() noexcept { auto table = create_op_table_constantinople(); return table; } -constexpr exec_fn_table op_tables[] = { +constexpr op_table op_tables[] = { create_op_table_frontier(), // Frontier create_op_table_homestead(), // Homestead create_op_table_homestead(), // Tangerine Whistle @@ -1382,7 +1382,7 @@ static_assert(sizeof(op_tables) / sizeof(op_tables[0]) > EVMC_MAX_REVISION, "op table entry missing for an EVMC revision"); } // namespace -EVMC_EXPORT const exec_fn_table& get_op_table(evmc_revision rev) noexcept +EVMC_EXPORT const op_table& get_op_table(evmc_revision rev) noexcept { return op_tables[rev]; } diff --git a/test/unittests/analysis_test.cpp b/test/unittests/analysis_test.cpp index ec06369fd7..297ce8c9f3 100644 --- a/test/unittests/analysis_test.cpp +++ b/test/unittests/analysis_test.cpp @@ -11,7 +11,7 @@ using namespace evmone; constexpr auto rev = EVMC_BYZANTIUM; -const auto& op_table = get_op_table(rev); +const auto& op_tbl = get_op_table(rev); TEST(analysis, example1) { @@ -20,14 +20,14 @@ TEST(analysis, example1) ASSERT_EQ(analysis.instrs.size(), 8); - EXPECT_EQ(analysis.instrs[0].fn, op_table[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[1].fn, op_table[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[2].fn, op_table[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[3].fn, op_table[OP_MSTORE8]); - EXPECT_EQ(analysis.instrs[4].fn, op_table[OP_MSIZE]); - EXPECT_EQ(analysis.instrs[5].fn, op_table[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[6].fn, op_table[OP_SSTORE]); - EXPECT_EQ(analysis.instrs[7].fn, op_table[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_PUSH1]); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_PUSH1]); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_MSTORE8]); + EXPECT_EQ(analysis.instrs[4].fn, op_tbl[OP_MSIZE]); + EXPECT_EQ(analysis.instrs[5].fn, op_tbl[OP_PUSH1]); + EXPECT_EQ(analysis.instrs[6].fn, op_tbl[OP_SSTORE]); + EXPECT_EQ(analysis.instrs[7].fn, op_tbl[OP_STOP]); const auto& block = analysis.instrs[0].arg.block; EXPECT_EQ(block.gas_cost, 14); @@ -41,11 +41,11 @@ TEST(analysis, stack_up_and_down) const auto analysis = analyze(rev, &code[0], code.size()); ASSERT_EQ(analysis.instrs.size(), 20); - EXPECT_EQ(analysis.instrs[0].fn, op_table[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[1].fn, op_table[OP_DUP2]); - EXPECT_EQ(analysis.instrs[2].fn, op_table[OP_DUP1]); - EXPECT_EQ(analysis.instrs[8].fn, op_table[OP_POP]); - EXPECT_EQ(analysis.instrs[18].fn, op_table[OP_PUSH1]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_DUP2]); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_DUP1]); + EXPECT_EQ(analysis.instrs[8].fn, op_tbl[OP_POP]); + EXPECT_EQ(analysis.instrs[18].fn, op_tbl[OP_PUSH1]); const auto& block = analysis.instrs[0].arg.block; EXPECT_EQ(block.gas_cost, 7 * 3 + 10 * 2 + 3); @@ -61,7 +61,7 @@ TEST(analysis, push) ASSERT_EQ(analysis.instrs.size(), 4); ASSERT_EQ(analysis.push_values.size(), 1); - EXPECT_EQ(analysis.instrs[0].fn, op_table[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK]); EXPECT_EQ(analysis.instrs[1].arg.small_push_value, push_value); EXPECT_EQ(analysis.instrs[2].arg.push_value, &analysis.push_values[0]); EXPECT_EQ(analysis.push_values[0], intx::uint256{0xee} << 240); @@ -76,10 +76,10 @@ TEST(analysis, jumpdest_skip) auto analysis = evmone::analyze(rev, &code[0], code.size()); ASSERT_EQ(analysis.instrs.size(), 4); - EXPECT_EQ(analysis.instrs[0].fn, op_table[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[1].fn, op_table[OP_STOP]); - EXPECT_EQ(analysis.instrs[2].fn, op_table[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[3].fn, op_table[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_STOP]); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_JUMPDEST]); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_STOP]); } TEST(analysis, jump1) @@ -102,8 +102,8 @@ TEST(analysis, empty) auto analysis = evmone::analyze(rev, &code[0], code.size()); ASSERT_EQ(analysis.instrs.size(), 2); - EXPECT_EQ(analysis.instrs[0].fn, op_table[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[1].fn, op_table[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_STOP]); } TEST(analysis, only_jumpdest) @@ -123,10 +123,10 @@ TEST(analysis, jumpi_at_the_end) auto analysis = evmone::analyze(rev, &code[0], code.size()); ASSERT_EQ(analysis.instrs.size(), 4); - EXPECT_EQ(analysis.instrs[0].fn, op_table[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[1].fn, op_table[OP_JUMPI]); - EXPECT_EQ(analysis.instrs[2].fn, op_table[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[3].fn, op_table[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_JUMPI]); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_STOP]); } TEST(analysis, terminated_last_block) @@ -137,10 +137,10 @@ TEST(analysis, terminated_last_block) auto analysis = evmone::analyze(rev, &code[0], code.size()); ASSERT_EQ(analysis.instrs.size(), 6); - EXPECT_EQ(analysis.instrs[0].fn, op_table[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[3].fn, op_table[OP_RETURN]); - EXPECT_EQ(analysis.instrs[4].fn, op_table[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[5].fn, op_table[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_RETURN]); + EXPECT_EQ(analysis.instrs[4].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[5].fn, op_tbl[OP_STOP]); } TEST(analysis, jumpdests_groups) @@ -149,17 +149,17 @@ TEST(analysis, jumpdests_groups) auto analysis = evmone::analyze(rev, &code[0], code.size()); ASSERT_EQ(analysis.instrs.size(), 11); - EXPECT_EQ(analysis.instrs[0].fn, op_table[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[1].fn, op_table[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[2].fn, op_table[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[3].fn, op_table[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[4].fn, op_table[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[5].fn, op_table[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[6].fn, op_table[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[7].fn, op_table[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[8].fn, op_table[OP_JUMPI]); - EXPECT_EQ(analysis.instrs[9].fn, op_table[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[10].fn, op_table[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OP_JUMPDEST]); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_JUMPDEST]); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_JUMPDEST]); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_PUSH1]); + EXPECT_EQ(analysis.instrs[4].fn, op_tbl[OP_JUMPDEST]); + EXPECT_EQ(analysis.instrs[5].fn, op_tbl[OP_JUMPDEST]); + EXPECT_EQ(analysis.instrs[6].fn, op_tbl[OP_JUMPDEST]); + EXPECT_EQ(analysis.instrs[7].fn, op_tbl[OP_PUSH1]); + EXPECT_EQ(analysis.instrs[8].fn, op_tbl[OP_JUMPI]); + EXPECT_EQ(analysis.instrs[9].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[10].fn, op_tbl[OP_STOP]); ASSERT_EQ(analysis.jumpdest_offsets.size(), 6); From dd3aafb6031efeedd61c6592f28eb1b820f64b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Sep 2019 20:45:29 +0200 Subject: [PATCH 2/6] Rename local variable fns -> op_tbl --- lib/evmone/analysis.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/evmone/analysis.cpp b/lib/evmone/analysis.cpp index 123b729ae8..19b6e7b133 100644 --- a/lib/evmone/analysis.cpp +++ b/lib/evmone/analysis.cpp @@ -32,8 +32,8 @@ inline constexpr uint64_t load64be(const unsigned char* data) noexcept code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) noexcept { - const auto& fns = get_op_table(rev); - const auto opx_beginblock_fn = fns[OPX_BEGINBLOCK]; + const auto& op_tbl = get_op_table(rev); + const auto opx_beginblock_fn = op_tbl[OPX_BEGINBLOCK]; code_analysis analysis; @@ -77,7 +77,7 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) static_cast(analysis.instrs.size() - 1)); } else - analysis.instrs.emplace_back(fns[opcode]); + analysis.instrs.emplace_back(op_tbl[opcode]); auto& instr = analysis.instrs.back(); @@ -177,7 +177,7 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) // Make sure the last block is terminated. // TODO: This is not needed if the last instruction is a terminating one. - analysis.instrs.emplace_back(fns[OP_STOP]); + analysis.instrs.emplace_back(op_tbl[OP_STOP]); // FIXME: assert(analysis.instrs.size() <= max_instrs_size); From aae695cda6152921550c747db4034c5226d1aa53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Sep 2019 17:22:10 +0200 Subject: [PATCH 3/6] Convert the op_table entry into a struct --- lib/evmone/analysis.cpp | 6 +- lib/evmone/analysis.hpp | 7 +- lib/evmone/instructions.cpp | 232 +++++++++++++++---------------- test/unittests/analysis_test.cpp | 78 +++++------ 4 files changed, 164 insertions(+), 159 deletions(-) diff --git a/lib/evmone/analysis.cpp b/lib/evmone/analysis.cpp index 19b6e7b133..0df6ad5ea0 100644 --- a/lib/evmone/analysis.cpp +++ b/lib/evmone/analysis.cpp @@ -33,7 +33,7 @@ inline constexpr uint64_t load64be(const unsigned char* data) noexcept code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) noexcept { const auto& op_tbl = get_op_table(rev); - const auto opx_beginblock_fn = op_tbl[OPX_BEGINBLOCK]; + const auto opx_beginblock_fn = op_tbl[OPX_BEGINBLOCK].fn; code_analysis analysis; @@ -77,7 +77,7 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) static_cast(analysis.instrs.size() - 1)); } else - analysis.instrs.emplace_back(op_tbl[opcode]); + analysis.instrs.emplace_back(op_tbl[opcode].fn); auto& instr = analysis.instrs.back(); @@ -177,7 +177,7 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) // Make sure the last block is terminated. // TODO: This is not needed if the last instruction is a terminating one. - analysis.instrs.emplace_back(op_tbl[OP_STOP]); + analysis.instrs.emplace_back(op_tbl[OP_STOP].fn); // FIXME: assert(analysis.instrs.size() <= max_instrs_size); diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index 646f078ecf..a3c6208fb3 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -170,7 +170,12 @@ enum intrinsic_opcodes OPX_BEGINBLOCK = OP_JUMPDEST }; -using op_table = std::array; +struct op_table_entry +{ + exec_fn fn; +}; + +using op_table = std::array; struct instr_info { diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index 1e8a350e43..cf1b09d702 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -1223,142 +1223,142 @@ constexpr op_table create_op_table_frontier() noexcept // First, mark all opcodes as undefined. for (auto& t : table) - t = op_undefined; - - table[OP_STOP] = op_stop; - table[OP_ADD] = op_add; - table[OP_MUL] = op_mul; - table[OP_SUB] = op_sub; - table[OP_DIV] = op_div; - table[OP_SDIV] = op_sdiv; - table[OP_MOD] = op_mod; - table[OP_SMOD] = op_smod; - table[OP_ADDMOD] = op_addmod; - table[OP_MULMOD] = op_mulmod; - table[OP_EXP] = op_exp; - table[OP_SIGNEXTEND] = op_signextend; - table[OP_LT] = op_lt; - table[OP_GT] = op_gt; - table[OP_SLT] = op_slt; - table[OP_SGT] = op_sgt; - table[OP_EQ] = op_eq; - table[OP_ISZERO] = op_iszero; - table[OP_AND] = op_and; - table[OP_OR] = op_or; - table[OP_XOR] = op_xor; - table[OP_NOT] = op_not; - table[OP_BYTE] = op_byte; - table[OP_SHA3] = op_sha3; - table[OP_ADDRESS] = op_address; - table[OP_BALANCE] = op_balance; - table[OP_ORIGIN] = op_origin; - table[OP_CALLER] = op_caller; - table[OP_CALLVALUE] = op_callvalue; - table[OP_CALLDATALOAD] = op_calldataload; - table[OP_CALLDATASIZE] = op_calldatasize; - table[OP_CALLDATACOPY] = op_calldatacopy; - table[OP_CODESIZE] = op_codesize; - table[OP_CODECOPY] = op_codecopy; - table[OP_EXTCODESIZE] = op_extcodesize; - table[OP_EXTCODECOPY] = op_extcodecopy; - table[OP_GASPRICE] = op_gasprice; - table[OP_BLOCKHASH] = op_blockhash; - table[OP_COINBASE] = op_coinbase; - table[OP_TIMESTAMP] = op_timestamp; - table[OP_NUMBER] = op_number; - table[OP_DIFFICULTY] = op_difficulty; - table[OP_GASLIMIT] = op_gaslimit; - table[OP_POP] = op_pop; - table[OP_MLOAD] = op_mload; - table[OP_MSTORE] = op_mstore; - table[OP_MSTORE8] = op_mstore8; - table[OP_SLOAD] = op_sload; - table[OP_SSTORE] = op_sstore; - table[OP_JUMP] = op_jump; - table[OP_JUMPI] = op_jumpi; - table[OP_PC] = op_pc; - table[OP_MSIZE] = op_msize; - table[OP_GAS] = op_gas; - table[OPX_BEGINBLOCK] = opx_beginblock; // Replaces JUMPDEST. + t = {op_undefined}; + + table[OP_STOP] = {op_stop}; + table[OP_ADD] = {op_add}; + table[OP_MUL] = {op_mul}; + table[OP_SUB] = {op_sub}; + table[OP_DIV] = {op_div}; + table[OP_SDIV] = {op_sdiv}; + table[OP_MOD] = {op_mod}; + table[OP_SMOD] = {op_smod}; + table[OP_ADDMOD] = {op_addmod}; + table[OP_MULMOD] = {op_mulmod}; + table[OP_EXP] = {op_exp}; + table[OP_SIGNEXTEND] = {op_signextend}; + table[OP_LT] = {op_lt}; + table[OP_GT] = {op_gt}; + table[OP_SLT] = {op_slt}; + table[OP_SGT] = {op_sgt}; + table[OP_EQ] = {op_eq}; + table[OP_ISZERO] = {op_iszero}; + table[OP_AND] = {op_and}; + table[OP_OR] = {op_or}; + table[OP_XOR] = {op_xor}; + table[OP_NOT] = {op_not}; + table[OP_BYTE] = {op_byte}; + table[OP_SHA3] = {op_sha3}; + table[OP_ADDRESS] = {op_address}; + table[OP_BALANCE] = {op_balance}; + table[OP_ORIGIN] = {op_origin}; + table[OP_CALLER] = {op_caller}; + table[OP_CALLVALUE] = {op_callvalue}; + table[OP_CALLDATALOAD] = {op_calldataload}; + table[OP_CALLDATASIZE] = {op_calldatasize}; + table[OP_CALLDATACOPY] = {op_calldatacopy}; + table[OP_CODESIZE] = {op_codesize}; + table[OP_CODECOPY] = {op_codecopy}; + table[OP_EXTCODESIZE] = {op_extcodesize}; + table[OP_EXTCODECOPY] = {op_extcodecopy}; + table[OP_GASPRICE] = {op_gasprice}; + table[OP_BLOCKHASH] = {op_blockhash}; + table[OP_COINBASE] = {op_coinbase}; + table[OP_TIMESTAMP] = {op_timestamp}; + table[OP_NUMBER] = {op_number}; + table[OP_DIFFICULTY] = {op_difficulty}; + table[OP_GASLIMIT] = {op_gaslimit}; + table[OP_POP] = {op_pop}; + table[OP_MLOAD] = {op_mload}; + table[OP_MSTORE] = {op_mstore}; + table[OP_MSTORE8] = {op_mstore8}; + table[OP_SLOAD] = {op_sload}; + table[OP_SSTORE] = {op_sstore}; + table[OP_JUMP] = {op_jump}; + table[OP_JUMPI] = {op_jumpi}; + table[OP_PC] = {op_pc}; + table[OP_MSIZE] = {op_msize}; + table[OP_GAS] = {op_gas}; + table[OPX_BEGINBLOCK] = {opx_beginblock}; // Replaces JUMPDEST. for (auto op = size_t{OP_PUSH1}; op <= OP_PUSH8; ++op) - table[op] = op_push_small; + table[op] = {op_push_small}; for (auto op = size_t{OP_PUSH9}; op <= OP_PUSH32; ++op) - table[op] = op_push_full; - - table[OP_DUP1] = op_dup; - table[OP_DUP2] = op_dup; - table[OP_DUP3] = op_dup; - table[OP_DUP4] = op_dup; - table[OP_DUP5] = op_dup; - table[OP_DUP6] = op_dup; - table[OP_DUP7] = op_dup; - table[OP_DUP8] = op_dup; - table[OP_DUP9] = op_dup; - table[OP_DUP10] = op_dup; - table[OP_DUP11] = op_dup; - table[OP_DUP12] = op_dup; - table[OP_DUP13] = op_dup; - table[OP_DUP14] = op_dup; - table[OP_DUP15] = op_dup; - table[OP_DUP16] = op_dup; - - table[OP_SWAP1] = op_swap; - table[OP_SWAP2] = op_swap; - table[OP_SWAP3] = op_swap; - table[OP_SWAP4] = op_swap; - table[OP_SWAP5] = op_swap; - table[OP_SWAP6] = op_swap; - table[OP_SWAP7] = op_swap; - table[OP_SWAP8] = op_swap; - table[OP_SWAP9] = op_swap; - table[OP_SWAP10] = op_swap; - table[OP_SWAP11] = op_swap; - table[OP_SWAP12] = op_swap; - table[OP_SWAP13] = op_swap; - table[OP_SWAP14] = op_swap; - table[OP_SWAP15] = op_swap; - table[OP_SWAP16] = op_swap; - - table[OP_LOG0] = op_log; - table[OP_LOG1] = op_log; - table[OP_LOG2] = op_log; - table[OP_LOG3] = op_log; - table[OP_LOG4] = op_log; - - table[OP_CREATE] = op_create; - table[OP_CALL] = op_call; - table[OP_CALLCODE] = op_call; - table[OP_RETURN] = op_return; - table[OP_INVALID] = op_invalid; - table[OP_SELFDESTRUCT] = op_selfdestruct; + table[op] = {op_push_full}; + + table[OP_DUP1] = {op_dup}; + table[OP_DUP2] = {op_dup}; + table[OP_DUP3] = {op_dup}; + table[OP_DUP4] = {op_dup}; + table[OP_DUP5] = {op_dup}; + table[OP_DUP6] = {op_dup}; + table[OP_DUP7] = {op_dup}; + table[OP_DUP8] = {op_dup}; + table[OP_DUP9] = {op_dup}; + table[OP_DUP10] = {op_dup}; + table[OP_DUP11] = {op_dup}; + table[OP_DUP12] = {op_dup}; + table[OP_DUP13] = {op_dup}; + table[OP_DUP14] = {op_dup}; + table[OP_DUP15] = {op_dup}; + table[OP_DUP16] = {op_dup}; + + table[OP_SWAP1] = {op_swap}; + table[OP_SWAP2] = {op_swap}; + table[OP_SWAP3] = {op_swap}; + table[OP_SWAP4] = {op_swap}; + table[OP_SWAP5] = {op_swap}; + table[OP_SWAP6] = {op_swap}; + table[OP_SWAP7] = {op_swap}; + table[OP_SWAP8] = {op_swap}; + table[OP_SWAP9] = {op_swap}; + table[OP_SWAP10] = {op_swap}; + table[OP_SWAP11] = {op_swap}; + table[OP_SWAP12] = {op_swap}; + table[OP_SWAP13] = {op_swap}; + table[OP_SWAP14] = {op_swap}; + table[OP_SWAP15] = {op_swap}; + table[OP_SWAP16] = {op_swap}; + + table[OP_LOG0] = {op_log}; + table[OP_LOG1] = {op_log}; + table[OP_LOG2] = {op_log}; + table[OP_LOG3] = {op_log}; + table[OP_LOG4] = {op_log}; + + table[OP_CREATE] = {op_create}; + table[OP_CALL] = {op_call}; + table[OP_CALLCODE] = {op_call}; + table[OP_RETURN] = {op_return}; + table[OP_INVALID] = {op_invalid}; + table[OP_SELFDESTRUCT] = {op_selfdestruct}; return table; } constexpr op_table create_op_table_homestead() noexcept { auto table = create_op_table_frontier(); - table[OP_DELEGATECALL] = op_delegatecall; + table[OP_DELEGATECALL] = {op_delegatecall}; return table; } constexpr op_table create_op_table_byzantium() noexcept { auto table = create_op_table_homestead(); - table[OP_RETURNDATASIZE] = op_returndatasize; - table[OP_RETURNDATACOPY] = op_returndatacopy; - table[OP_STATICCALL] = op_staticcall; - table[OP_REVERT] = op_revert; + table[OP_RETURNDATASIZE] = {op_returndatasize}; + table[OP_RETURNDATACOPY] = {op_returndatacopy}; + table[OP_STATICCALL] = {op_staticcall}; + table[OP_REVERT] = {op_revert}; return table; } constexpr op_table create_op_table_constantinople() noexcept { auto table = create_op_table_byzantium(); - table[OP_SHL] = op_shl; - table[OP_SHR] = op_shr; - table[OP_SAR] = op_sar; - table[OP_EXTCODEHASH] = op_extcodehash; - table[OP_CREATE2] = op_create2; + table[OP_SHL] = {op_shl}; + table[OP_SHR] = {op_shr}; + table[OP_SAR] = {op_sar}; + table[OP_EXTCODEHASH] = {op_extcodehash}; + table[OP_CREATE2] = {op_create2}; return table; } diff --git a/test/unittests/analysis_test.cpp b/test/unittests/analysis_test.cpp index 297ce8c9f3..a3311f75b8 100644 --- a/test/unittests/analysis_test.cpp +++ b/test/unittests/analysis_test.cpp @@ -20,14 +20,14 @@ TEST(analysis, example1) ASSERT_EQ(analysis.instrs.size(), 8); - EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_MSTORE8]); - EXPECT_EQ(analysis.instrs[4].fn, op_tbl[OP_MSIZE]); - EXPECT_EQ(analysis.instrs[5].fn, op_tbl[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[6].fn, op_tbl[OP_SSTORE]); - EXPECT_EQ(analysis.instrs[7].fn, op_tbl[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_PUSH1].fn); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_PUSH1].fn); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_MSTORE8].fn); + EXPECT_EQ(analysis.instrs[4].fn, op_tbl[OP_MSIZE].fn); + EXPECT_EQ(analysis.instrs[5].fn, op_tbl[OP_PUSH1].fn); + EXPECT_EQ(analysis.instrs[6].fn, op_tbl[OP_SSTORE].fn); + EXPECT_EQ(analysis.instrs[7].fn, op_tbl[OP_STOP].fn); const auto& block = analysis.instrs[0].arg.block; EXPECT_EQ(block.gas_cost, 14); @@ -41,11 +41,11 @@ TEST(analysis, stack_up_and_down) 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]); - EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_DUP2]); - EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_DUP1]); - EXPECT_EQ(analysis.instrs[8].fn, op_tbl[OP_POP]); - EXPECT_EQ(analysis.instrs[18].fn, op_tbl[OP_PUSH1]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_DUP2].fn); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_DUP1].fn); + EXPECT_EQ(analysis.instrs[8].fn, op_tbl[OP_POP].fn); + EXPECT_EQ(analysis.instrs[18].fn, op_tbl[OP_PUSH1].fn); const auto& block = analysis.instrs[0].arg.block; EXPECT_EQ(block.gas_cost, 7 * 3 + 10 * 2 + 3); @@ -61,7 +61,7 @@ TEST(analysis, push) ASSERT_EQ(analysis.instrs.size(), 4); ASSERT_EQ(analysis.push_values.size(), 1); - EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); EXPECT_EQ(analysis.instrs[1].arg.small_push_value, push_value); EXPECT_EQ(analysis.instrs[2].arg.push_value, &analysis.push_values[0]); EXPECT_EQ(analysis.push_values[0], intx::uint256{0xee} << 240); @@ -76,10 +76,10 @@ TEST(analysis, jumpdest_skip) 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]); - EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_STOP]); - EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_STOP].fn); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_JUMPDEST].fn); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_STOP].fn); } TEST(analysis, jump1) @@ -102,8 +102,8 @@ TEST(analysis, empty) 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]); - EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_STOP].fn); } TEST(analysis, only_jumpdest) @@ -123,10 +123,10 @@ TEST(analysis, jumpi_at_the_end) 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]); - EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_JUMPI]); - EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_JUMPI].fn); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OPX_BEGINBLOCK].fn); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_STOP].fn); } TEST(analysis, terminated_last_block) @@ -137,10 +137,10 @@ TEST(analysis, terminated_last_block) 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]); - EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_RETURN]); - EXPECT_EQ(analysis.instrs[4].fn, op_tbl[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[5].fn, op_tbl[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OPX_BEGINBLOCK].fn); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_RETURN].fn); + EXPECT_EQ(analysis.instrs[4].fn, op_tbl[OPX_BEGINBLOCK].fn); + EXPECT_EQ(analysis.instrs[5].fn, op_tbl[OP_STOP].fn); } TEST(analysis, jumpdests_groups) @@ -149,17 +149,17 @@ TEST(analysis, jumpdests_groups) 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]); - EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[4].fn, op_tbl[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[5].fn, op_tbl[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[6].fn, op_tbl[OP_JUMPDEST]); - EXPECT_EQ(analysis.instrs[7].fn, op_tbl[OP_PUSH1]); - EXPECT_EQ(analysis.instrs[8].fn, op_tbl[OP_JUMPI]); - EXPECT_EQ(analysis.instrs[9].fn, op_tbl[OPX_BEGINBLOCK]); - EXPECT_EQ(analysis.instrs[10].fn, op_tbl[OP_STOP]); + EXPECT_EQ(analysis.instrs[0].fn, op_tbl[OP_JUMPDEST].fn); + EXPECT_EQ(analysis.instrs[1].fn, op_tbl[OP_JUMPDEST].fn); + EXPECT_EQ(analysis.instrs[2].fn, op_tbl[OP_JUMPDEST].fn); + EXPECT_EQ(analysis.instrs[3].fn, op_tbl[OP_PUSH1].fn); + EXPECT_EQ(analysis.instrs[4].fn, op_tbl[OP_JUMPDEST].fn); + EXPECT_EQ(analysis.instrs[5].fn, op_tbl[OP_JUMPDEST].fn); + EXPECT_EQ(analysis.instrs[6].fn, op_tbl[OP_JUMPDEST].fn); + EXPECT_EQ(analysis.instrs[7].fn, op_tbl[OP_PUSH1].fn); + EXPECT_EQ(analysis.instrs[8].fn, op_tbl[OP_JUMPI].fn); + EXPECT_EQ(analysis.instrs[9].fn, op_tbl[OPX_BEGINBLOCK].fn); + EXPECT_EQ(analysis.instrs[10].fn, op_tbl[OP_STOP].fn); ASSERT_EQ(analysis.jumpdest_offsets.size(), 6); From 48696fcca7ab64420f4e6373c096e75694a4c243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Sep 2019 17:41:10 +0200 Subject: [PATCH 4/6] Add gas cost and stack requirements to op tables --- lib/evmone/analysis.hpp | 3 + lib/evmone/instructions.cpp | 265 +++++++++++++++++++----------------- 2 files changed, 143 insertions(+), 125 deletions(-) diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index a3c6208fb3..04a0c1101f 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -173,6 +173,9 @@ enum intrinsic_opcodes struct op_table_entry { exec_fn fn; + int16_t gas_cost; + int8_t stack_req; + int8_t stack_change; }; using op_table = std::array; diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index cf1b09d702..2543b78bbb 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -1223,142 +1223,157 @@ constexpr op_table create_op_table_frontier() noexcept // First, mark all opcodes as undefined. for (auto& t : table) - t = {op_undefined}; - - table[OP_STOP] = {op_stop}; - table[OP_ADD] = {op_add}; - table[OP_MUL] = {op_mul}; - table[OP_SUB] = {op_sub}; - table[OP_DIV] = {op_div}; - table[OP_SDIV] = {op_sdiv}; - table[OP_MOD] = {op_mod}; - table[OP_SMOD] = {op_smod}; - table[OP_ADDMOD] = {op_addmod}; - table[OP_MULMOD] = {op_mulmod}; - table[OP_EXP] = {op_exp}; - table[OP_SIGNEXTEND] = {op_signextend}; - table[OP_LT] = {op_lt}; - table[OP_GT] = {op_gt}; - table[OP_SLT] = {op_slt}; - table[OP_SGT] = {op_sgt}; - table[OP_EQ] = {op_eq}; - table[OP_ISZERO] = {op_iszero}; - table[OP_AND] = {op_and}; - table[OP_OR] = {op_or}; - table[OP_XOR] = {op_xor}; - table[OP_NOT] = {op_not}; - table[OP_BYTE] = {op_byte}; - table[OP_SHA3] = {op_sha3}; - table[OP_ADDRESS] = {op_address}; - table[OP_BALANCE] = {op_balance}; - table[OP_ORIGIN] = {op_origin}; - table[OP_CALLER] = {op_caller}; - table[OP_CALLVALUE] = {op_callvalue}; - table[OP_CALLDATALOAD] = {op_calldataload}; - table[OP_CALLDATASIZE] = {op_calldatasize}; - table[OP_CALLDATACOPY] = {op_calldatacopy}; - table[OP_CODESIZE] = {op_codesize}; - table[OP_CODECOPY] = {op_codecopy}; - table[OP_EXTCODESIZE] = {op_extcodesize}; - table[OP_EXTCODECOPY] = {op_extcodecopy}; - table[OP_GASPRICE] = {op_gasprice}; - table[OP_BLOCKHASH] = {op_blockhash}; - table[OP_COINBASE] = {op_coinbase}; - table[OP_TIMESTAMP] = {op_timestamp}; - table[OP_NUMBER] = {op_number}; - table[OP_DIFFICULTY] = {op_difficulty}; - table[OP_GASLIMIT] = {op_gaslimit}; - table[OP_POP] = {op_pop}; - table[OP_MLOAD] = {op_mload}; - table[OP_MSTORE] = {op_mstore}; - table[OP_MSTORE8] = {op_mstore8}; - table[OP_SLOAD] = {op_sload}; - table[OP_SSTORE] = {op_sstore}; - table[OP_JUMP] = {op_jump}; - table[OP_JUMPI] = {op_jumpi}; - table[OP_PC] = {op_pc}; - table[OP_MSIZE] = {op_msize}; - table[OP_GAS] = {op_gas}; - table[OPX_BEGINBLOCK] = {opx_beginblock}; // Replaces JUMPDEST. + t = {op_undefined, 0, 0, 0}; + + table[OP_STOP] = {op_stop, 0, 0, 0}; + table[OP_ADD] = {op_add, 3, 2, -1}; + table[OP_MUL] = {op_mul, 5, 2, -1}; + table[OP_SUB] = {op_sub, 3, 2, -1}; + table[OP_DIV] = {op_div, 5, 2, -1}; + table[OP_SDIV] = {op_sdiv, 5, 2, -1}; + table[OP_MOD] = {op_mod, 5, 2, -1}; + table[OP_SMOD] = {op_smod, 5, 2, -1}; + table[OP_ADDMOD] = {op_addmod, 8, 3, -2}; + table[OP_MULMOD] = {op_mulmod, 8, 3, -2}; + table[OP_EXP] = {op_exp, 10, 2, -1}; + table[OP_SIGNEXTEND] = {op_signextend, 5, 2, -1}; + table[OP_LT] = {op_lt, 3, 2, -1}; + table[OP_GT] = {op_gt, 3, 2, -1}; + table[OP_SLT] = {op_slt, 3, 2, -1}; + table[OP_SGT] = {op_sgt, 3, 2, -1}; + table[OP_EQ] = {op_eq, 3, 2, -1}; + table[OP_ISZERO] = {op_iszero, 3, 1, 0}; + table[OP_AND] = {op_and, 3, 2, -1}; + table[OP_OR] = {op_or, 3, 2, -1}; + table[OP_XOR] = {op_xor, 3, 2, -1}; + table[OP_NOT] = {op_not, 3, 1, 0}; + table[OP_BYTE] = {op_byte, 3, 2, -1}; + table[OP_SHA3] = {op_sha3, 30, 2, -1}; + table[OP_ADDRESS] = {op_address, 2, 0, 1}; + table[OP_BALANCE] = {op_balance, 20, 1, 0}; + table[OP_ORIGIN] = {op_origin, 2, 0, 1}; + table[OP_CALLER] = {op_caller, 2, 0, 1}; + table[OP_CALLVALUE] = {op_callvalue, 2, 0, 1}; + table[OP_CALLDATALOAD] = {op_calldataload, 3, 1, 0}; + table[OP_CALLDATASIZE] = {op_calldatasize, 2, 0, 1}; + table[OP_CALLDATACOPY] = {op_calldatacopy, 3, 3, -3}; + table[OP_CODESIZE] = {op_codesize, 2, 0, 1}; + table[OP_CODECOPY] = {op_codecopy, 3, 3, -3}; + table[OP_GASPRICE] = {op_gasprice, 2, 0, 1}; + table[OP_EXTCODESIZE] = {op_extcodesize, 20, 1, 0}; + table[OP_EXTCODECOPY] = {op_extcodecopy, 20, 4, -4}; + table[OP_BLOCKHASH] = {op_blockhash, 20, 1, 0}; + table[OP_COINBASE] = {op_coinbase, 2, 0, 1}; + table[OP_TIMESTAMP] = {op_timestamp, 2, 0, 1}; + table[OP_NUMBER] = {op_number, 2, 0, 1}; + table[OP_DIFFICULTY] = {op_difficulty, 2, 0, 1}; + table[OP_GASLIMIT] = {op_gaslimit, 2, 0, 1}; + table[OP_POP] = {op_pop, 2, 1, -1}; + table[OP_MLOAD] = {op_mload, 3, 1, 0}; + table[OP_MSTORE] = {op_mstore, 3, 2, -2}; + table[OP_MSTORE8] = {op_mstore8, 3, 2, -2}; + table[OP_SLOAD] = {op_sload, 50, 1, 0}; + table[OP_SSTORE] = {op_sstore, 0, 2, -2}; + table[OP_JUMP] = {op_jump, 8, 1, -1}; + table[OP_JUMPI] = {op_jumpi, 10, 2, -2}; + table[OP_PC] = {op_pc, 2, 0, 1}; + table[OP_MSIZE] = {op_msize, 2, 0, 1}; + table[OP_GAS] = {op_gas, 2, 0, 1}; + table[OPX_BEGINBLOCK] = {opx_beginblock, 1, 0, 0}; // Replaces JUMPDEST. + for (auto op = size_t{OP_PUSH1}; op <= OP_PUSH8; ++op) - table[op] = {op_push_small}; + table[op] = {op_push_small, 3, 0, 1}; for (auto op = size_t{OP_PUSH9}; op <= OP_PUSH32; ++op) - table[op] = {op_push_full}; - - table[OP_DUP1] = {op_dup}; - table[OP_DUP2] = {op_dup}; - table[OP_DUP3] = {op_dup}; - table[OP_DUP4] = {op_dup}; - table[OP_DUP5] = {op_dup}; - table[OP_DUP6] = {op_dup}; - table[OP_DUP7] = {op_dup}; - table[OP_DUP8] = {op_dup}; - table[OP_DUP9] = {op_dup}; - table[OP_DUP10] = {op_dup}; - table[OP_DUP11] = {op_dup}; - table[OP_DUP12] = {op_dup}; - table[OP_DUP13] = {op_dup}; - table[OP_DUP14] = {op_dup}; - table[OP_DUP15] = {op_dup}; - table[OP_DUP16] = {op_dup}; - - table[OP_SWAP1] = {op_swap}; - table[OP_SWAP2] = {op_swap}; - table[OP_SWAP3] = {op_swap}; - table[OP_SWAP4] = {op_swap}; - table[OP_SWAP5] = {op_swap}; - table[OP_SWAP6] = {op_swap}; - table[OP_SWAP7] = {op_swap}; - table[OP_SWAP8] = {op_swap}; - table[OP_SWAP9] = {op_swap}; - table[OP_SWAP10] = {op_swap}; - table[OP_SWAP11] = {op_swap}; - table[OP_SWAP12] = {op_swap}; - table[OP_SWAP13] = {op_swap}; - table[OP_SWAP14] = {op_swap}; - table[OP_SWAP15] = {op_swap}; - table[OP_SWAP16] = {op_swap}; - - table[OP_LOG0] = {op_log}; - table[OP_LOG1] = {op_log}; - table[OP_LOG2] = {op_log}; - table[OP_LOG3] = {op_log}; - table[OP_LOG4] = {op_log}; - - table[OP_CREATE] = {op_create}; - table[OP_CALL] = {op_call}; - table[OP_CALLCODE] = {op_call}; - table[OP_RETURN] = {op_return}; - table[OP_INVALID] = {op_invalid}; - table[OP_SELFDESTRUCT] = {op_selfdestruct}; + table[op] = {op_push_full, 3, 0, 1}; + + table[OP_DUP1] = {op_dup, 3, 1, 1}; + table[OP_DUP2] = {op_dup, 3, 2, 1}; + table[OP_DUP3] = {op_dup, 3, 3, 1}; + table[OP_DUP4] = {op_dup, 3, 4, 1}; + table[OP_DUP5] = {op_dup, 3, 5, 1}; + table[OP_DUP6] = {op_dup, 3, 6, 1}; + table[OP_DUP7] = {op_dup, 3, 7, 1}; + table[OP_DUP8] = {op_dup, 3, 8, 1}; + table[OP_DUP9] = {op_dup, 3, 9, 1}; + table[OP_DUP10] = {op_dup, 3, 10, 1}; + table[OP_DUP11] = {op_dup, 3, 11, 1}; + table[OP_DUP12] = {op_dup, 3, 12, 1}; + table[OP_DUP13] = {op_dup, 3, 13, 1}; + table[OP_DUP14] = {op_dup, 3, 14, 1}; + table[OP_DUP15] = {op_dup, 3, 15, 1}; + table[OP_DUP16] = {op_dup, 3, 16, 1}; + + table[OP_SWAP1] = {op_swap, 3, 2, 0}; + table[OP_SWAP2] = {op_swap, 3, 3, 0}; + table[OP_SWAP3] = {op_swap, 3, 4, 0}; + table[OP_SWAP4] = {op_swap, 3, 5, 0}; + table[OP_SWAP5] = {op_swap, 3, 6, 0}; + table[OP_SWAP6] = {op_swap, 3, 7, 0}; + table[OP_SWAP7] = {op_swap, 3, 8, 0}; + table[OP_SWAP8] = {op_swap, 3, 9, 0}; + table[OP_SWAP9] = {op_swap, 3, 10, 0}; + table[OP_SWAP10] = {op_swap, 3, 11, 0}; + table[OP_SWAP11] = {op_swap, 3, 12, 0}; + table[OP_SWAP12] = {op_swap, 3, 13, 0}; + table[OP_SWAP13] = {op_swap, 3, 14, 0}; + table[OP_SWAP14] = {op_swap, 3, 15, 0}; + table[OP_SWAP15] = {op_swap, 3, 16, 0}; + table[OP_SWAP16] = {op_swap, 3, 17, 0}; + + table[OP_LOG0] = {op_log, 1 * 375, 2, -2}; + table[OP_LOG1] = {op_log, 2 * 375, 3, -3}; + table[OP_LOG2] = {op_log, 3 * 375, 4, -4}; + table[OP_LOG3] = {op_log, 4 * 375, 5, -5}; + table[OP_LOG4] = {op_log, 5 * 375, 6, -6}; + + table[OP_CREATE] = {op_create, 32000, 3, -2}; + table[OP_CALL] = {op_call, 40, 7, -6}; + table[OP_CALLCODE] = {op_call, 40, 7, -6}; + table[OP_RETURN] = {op_return, 0, 2, -2}; + table[OP_INVALID] = {op_invalid, 0, 0, 0}; + table[OP_SELFDESTRUCT] = {op_selfdestruct, 0, 1, -1}; return table; } constexpr op_table create_op_table_homestead() noexcept { auto table = create_op_table_frontier(); - table[OP_DELEGATECALL] = {op_delegatecall}; + table[OP_DELEGATECALL] = {op_delegatecall, 40, 6, -5}; return table; } -constexpr op_table create_op_table_byzantium() noexcept +constexpr op_table create_op_table_tangerine_whistle() noexcept { auto table = create_op_table_homestead(); - table[OP_RETURNDATASIZE] = {op_returndatasize}; - table[OP_RETURNDATACOPY] = {op_returndatacopy}; - table[OP_STATICCALL] = {op_staticcall}; - table[OP_REVERT] = {op_revert}; + table[OP_BALANCE].gas_cost = 400; + table[OP_EXTCODESIZE].gas_cost = 700; + table[OP_EXTCODECOPY].gas_cost = 700; + table[OP_SLOAD].gas_cost = 200; + table[OP_CALL].gas_cost = 700; + table[OP_CALLCODE].gas_cost = 700; + table[OP_DELEGATECALL].gas_cost = 700; + table[OP_SELFDESTRUCT].gas_cost = 5000; + return table; +} + +constexpr op_table create_op_table_byzantium() noexcept +{ + auto table = create_op_table_tangerine_whistle(); + table[OP_RETURNDATASIZE] = {op_returndatasize, 2, 0, 1}; + table[OP_RETURNDATACOPY] = {op_returndatacopy, 3, 3, -3}; + table[OP_STATICCALL] = {op_staticcall, 700, 6, -5}; + table[OP_REVERT] = {op_revert, 0, 2, -2}; return table; } constexpr op_table create_op_table_constantinople() noexcept { auto table = create_op_table_byzantium(); - table[OP_SHL] = {op_shl}; - table[OP_SHR] = {op_shr}; - table[OP_SAR] = {op_sar}; - table[OP_EXTCODEHASH] = {op_extcodehash}; - table[OP_CREATE2] = {op_create2}; + table[OP_SHL] = {op_shl, 3, 2, -1}; + table[OP_SHR] = {op_shr, 3, 2, -1}; + table[OP_SAR] = {op_sar, 3, 2, -1}; + table[OP_EXTCODEHASH] = {op_extcodehash, 400, 1, 0}; + table[OP_CREATE2] = {op_create2, 32000, 4, -3}; return table; } @@ -1369,14 +1384,14 @@ constexpr op_table create_op_table_istanbul() noexcept } constexpr op_table op_tables[] = { - create_op_table_frontier(), // Frontier - create_op_table_homestead(), // Homestead - create_op_table_homestead(), // Tangerine Whistle - create_op_table_homestead(), // Spurious Dragon - create_op_table_byzantium(), // Byzantium - create_op_table_constantinople(), // Constantinople - create_op_table_constantinople(), // Petersburg - create_op_table_istanbul(), // Istanbul + create_op_table_frontier(), // Frontier + create_op_table_homestead(), // Homestead + create_op_table_tangerine_whistle(), // Tangerine Whistle + create_op_table_tangerine_whistle(), // Spurious Dragon + create_op_table_byzantium(), // Byzantium + create_op_table_constantinople(), // Constantinople + create_op_table_constantinople(), // Petersburg + create_op_table_istanbul(), // Istanbul }; static_assert(sizeof(op_tables) / sizeof(op_tables[0]) > EVMC_MAX_REVISION, "op table entry missing for an EVMC revision"); From 70ec3483e848379cf098880c3f2d1cf010d5bb68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Sep 2019 21:22:57 +0200 Subject: [PATCH 5/6] Use metrics from op_table --- lib/evmone/CMakeLists.txt | 2 +- lib/evmone/analysis.cpp | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/evmone/CMakeLists.txt b/lib/evmone/CMakeLists.txt index e57eb523fe..c4184340b6 100644 --- a/lib/evmone/CMakeLists.txt +++ b/lib/evmone/CMakeLists.txt @@ -18,7 +18,7 @@ add_library(evmone limits.hpp opcodes_helpers.h ) -target_link_libraries(evmone PUBLIC evmc::evmc PRIVATE intx::intx evmc::instructions ethash::keccak) +target_link_libraries(evmone PUBLIC evmc::evmc PRIVATE intx::intx ethash::keccak) target_include_directories(evmone PUBLIC $$ ) diff --git a/lib/evmone/analysis.cpp b/lib/evmone/analysis.cpp index 0df6ad5ea0..9e4ef770c4 100644 --- a/lib/evmone/analysis.cpp +++ b/lib/evmone/analysis.cpp @@ -44,8 +44,6 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) const auto max_args_storage_size = code_size + 1; analysis.push_values.reserve(max_args_storage_size); - const auto* instr_table = evmc_get_instruction_metrics_table(rev); - // Create first block. analysis.instrs.emplace_back(opx_beginblock_fn); auto block = block_analysis{0}; @@ -56,17 +54,13 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) while (code_pos != code_end) { const auto opcode = *code_pos++; + const auto& opcode_info = op_tbl[opcode]; - const auto metrics = instr_table[opcode]; - const auto instr_stack_req = metrics.num_stack_arguments; - const auto instr_stack_change = metrics.num_stack_returned_items - instr_stack_req; - - block.stack_req = std::max(block.stack_req, instr_stack_req - block.stack_change); - block.stack_change += instr_stack_change; + block.stack_req = std::max(block.stack_req, opcode_info.stack_req - block.stack_change); + block.stack_change += opcode_info.stack_change; block.stack_max_growth = std::max(block.stack_max_growth, block.stack_change); - if (metrics.gas_cost > 0) // can be -1 for undefined instruction - block.gas_cost += metrics.gas_cost; + block.gas_cost += opcode_info.gas_cost; if (opcode == OP_JUMPDEST) { @@ -77,7 +71,7 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) static_cast(analysis.instrs.size() - 1)); } else - analysis.instrs.emplace_back(op_tbl[opcode].fn); + analysis.instrs.emplace_back(opcode_info.fn); auto& instr = analysis.instrs.back(); From 867a4ecf0420726b92bd23711032d47b116d631c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Sep 2019 12:37:54 +0200 Subject: [PATCH 6/6] test: Compare EVMC and evmone instruction tables --- test/unittests/CMakeLists.txt | 3 ++- test/unittests/op_table_test.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test/unittests/op_table_test.cpp diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index 41349b8e5f..f6280edaec 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -21,10 +21,11 @@ add_executable(evmone-unittests analysis_test.cpp bytecode_test.cpp evmone_test.cpp + op_table_test.cpp utils_test.cpp vm_loader_evmone.cpp ) -target_link_libraries(evmone-unittests PRIVATE evm-unittests evmone testutils GTest::gtest GTest::gtest_main) +target_link_libraries(evmone-unittests PRIVATE evm-unittests evmone testutils evmc::instructions GTest::gtest GTest::gtest_main) target_include_directories(evmone-unittests PRIVATE ${evmone_private_include_dir}) gtest_discover_tests(evmone-unittests TEST_PREFIX ${PROJECT_NAME}/unittests/) diff --git a/test/unittests/op_table_test.cpp b/test/unittests/op_table_test.cpp new file mode 100644 index 0000000000..3ce4ee6945 --- /dev/null +++ b/test/unittests/op_table_test.cpp @@ -0,0 +1,30 @@ +// evmone: Fast Ethereum Virtual Machine implementation +// Copyright 2019 The evmone Authors. +// Licensed under the Apache License, Version 2.0. + +#include +#include +#include + +TEST(op_table, compare_with_evmc_instruction_tables) +{ + for (int r = EVMC_FRONTIER; r <= EVMC_MAX_REVISION; ++r) + { + const auto rev = static_cast(r); + const auto& evmone_tbl = evmone::get_op_table(rev); + const auto* evmc_tbl = evmc_get_instruction_metrics_table(rev); + + for (size_t i = 0; i < evmone_tbl.size(); ++i) + { + const auto& metrics = evmone_tbl[i]; + const auto& ref_metrics = evmc_tbl[i]; + + // Compare gas costs. Normalize -1 values in EVMC for undefined instructions. + EXPECT_EQ(metrics.gas_cost, std::max(ref_metrics.gas_cost, int16_t{0})); + + EXPECT_EQ(metrics.stack_req, ref_metrics.num_stack_arguments); + EXPECT_EQ(metrics.stack_change, + ref_metrics.num_stack_returned_items - ref_metrics.num_stack_arguments); + } + } +}