diff --git a/lib/evmone/analysis.cpp b/lib/evmone/analysis.cpp index c2c59151c8..ac6f48a1e9 100644 --- a/lib/evmone/analysis.cpp +++ b/lib/evmone/analysis.cpp @@ -77,19 +77,12 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) auto& instr = analysis.instrs.back(); - bool is_terminator = false; // A flag whenever this is a block terminating instruction. - switch (opcode) + switch (opcode_info.kind) { - case OP_JUMP: - case OP_JUMPI: - case OP_STOP: - case OP_RETURN: - case OP_REVERT: - case OP_SELFDESTRUCT: - is_terminator = true; + default: break; - case ANY_SMALL_PUSH: + case op_kind::small_push: { const auto push_size = size_t(opcode - OP_PUSH1 + 1); const auto push_end = code_pos + push_size; @@ -104,7 +97,7 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) break; } - case ANY_LARGE_PUSH: + case op_kind::large_push: { const auto push_size = size_t(opcode - OP_PUSH1 + 1); const auto push_end = code_pos + push_size; @@ -130,23 +123,18 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) break; } - case OP_GAS: - case OP_CALL: - case OP_CALLCODE: - case OP_DELEGATECALL: - case OP_STATICCALL: - case OP_CREATE: - case OP_CREATE2: + case op_kind::gas_counter_access: instr.arg.number = block.gas_cost; break; - case OP_PC: + case op_kind::pc: instr.arg.number = static_cast(code_pos - code - 1); break; } // If this is a terminating instruction or the next instruction is a JUMPDEST. - if (is_terminator || (code_pos != code_end && *code_pos == OP_JUMPDEST)) + if (opcode_info.kind == op_kind::terminator || + (code_pos != code_end && *code_pos == OP_JUMPDEST)) { // Save current block. const auto stack_req = block.stack_req <= stack_req_max ? diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index 04a0c1101f..5f4c229166 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -170,13 +170,26 @@ enum intrinsic_opcodes OPX_BEGINBLOCK = OP_JUMPDEST }; +/// Defines classification of EVM instructions. +enum class op_kind +{ + regular, ///< Totally uninteresting instruction. + terminator, ///< Terminator instruction. + small_push, ///< Push instruction up to 8 bytes of value. + large_push, ///< Push instruction with more than 8 bytes of value. + gas_counter_access, ///< Instruction that requires access to the gas counter. + pc ///< The PC instruction. +}; + struct op_table_entry { exec_fn fn; int16_t gas_cost; int8_t stack_req; int8_t stack_change; + op_kind kind; }; +static_assert(sizeof(op_table_entry) <= 2 * sizeof(void*)); using op_table = std::array; diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index 2543b78bbb..3becf070ea 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -1223,122 +1223,122 @@ constexpr op_table create_op_table_frontier() noexcept // First, mark all opcodes as undefined. for (auto& t : table) - 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. + t = {op_undefined, 0, 0, 0, op_kind::regular}; + + table[OP_STOP] = {op_stop, 0, 0, 0, op_kind::terminator}; + table[OP_ADD] = {op_add, 3, 2, -1, op_kind::regular}; + table[OP_MUL] = {op_mul, 5, 2, -1, op_kind::regular}; + table[OP_SUB] = {op_sub, 3, 2, -1, op_kind::regular}; + table[OP_DIV] = {op_div, 5, 2, -1, op_kind::regular}; + table[OP_SDIV] = {op_sdiv, 5, 2, -1, op_kind::regular}; + table[OP_MOD] = {op_mod, 5, 2, -1, op_kind::regular}; + table[OP_SMOD] = {op_smod, 5, 2, -1, op_kind::regular}; + table[OP_ADDMOD] = {op_addmod, 8, 3, -2, op_kind::regular}; + table[OP_MULMOD] = {op_mulmod, 8, 3, -2, op_kind::regular}; + table[OP_EXP] = {op_exp, 10, 2, -1, op_kind::regular}; + table[OP_SIGNEXTEND] = {op_signextend, 5, 2, -1, op_kind::regular}; + table[OP_LT] = {op_lt, 3, 2, -1, op_kind::regular}; + table[OP_GT] = {op_gt, 3, 2, -1, op_kind::regular}; + table[OP_SLT] = {op_slt, 3, 2, -1, op_kind::regular}; + table[OP_SGT] = {op_sgt, 3, 2, -1, op_kind::regular}; + table[OP_EQ] = {op_eq, 3, 2, -1, op_kind::regular}; + table[OP_ISZERO] = {op_iszero, 3, 1, 0, op_kind::regular}; + table[OP_AND] = {op_and, 3, 2, -1, op_kind::regular}; + table[OP_OR] = {op_or, 3, 2, -1, op_kind::regular}; + table[OP_XOR] = {op_xor, 3, 2, -1, op_kind::regular}; + table[OP_NOT] = {op_not, 3, 1, 0, op_kind::regular}; + table[OP_BYTE] = {op_byte, 3, 2, -1, op_kind::regular}; + table[OP_SHA3] = {op_sha3, 30, 2, -1, op_kind::regular}; + table[OP_ADDRESS] = {op_address, 2, 0, 1, op_kind::regular}; + table[OP_BALANCE] = {op_balance, 20, 1, 0, op_kind::regular}; + table[OP_ORIGIN] = {op_origin, 2, 0, 1, op_kind::regular}; + table[OP_CALLER] = {op_caller, 2, 0, 1, op_kind::regular}; + table[OP_CALLVALUE] = {op_callvalue, 2, 0, 1, op_kind::regular}; + table[OP_CALLDATALOAD] = {op_calldataload, 3, 1, 0, op_kind::regular}; + table[OP_CALLDATASIZE] = {op_calldatasize, 2, 0, 1, op_kind::regular}; + table[OP_CALLDATACOPY] = {op_calldatacopy, 3, 3, -3, op_kind::regular}; + table[OP_CODESIZE] = {op_codesize, 2, 0, 1, op_kind::regular}; + table[OP_CODECOPY] = {op_codecopy, 3, 3, -3, op_kind::regular}; + table[OP_GASPRICE] = {op_gasprice, 2, 0, 1, op_kind::regular}; + table[OP_EXTCODESIZE] = {op_extcodesize, 20, 1, 0, op_kind::regular}; + table[OP_EXTCODECOPY] = {op_extcodecopy, 20, 4, -4, op_kind::regular}; + table[OP_BLOCKHASH] = {op_blockhash, 20, 1, 0, op_kind::regular}; + table[OP_COINBASE] = {op_coinbase, 2, 0, 1, op_kind::regular}; + table[OP_TIMESTAMP] = {op_timestamp, 2, 0, 1, op_kind::regular}; + table[OP_NUMBER] = {op_number, 2, 0, 1, op_kind::regular}; + table[OP_DIFFICULTY] = {op_difficulty, 2, 0, 1, op_kind::regular}; + table[OP_GASLIMIT] = {op_gaslimit, 2, 0, 1, op_kind::regular}; + table[OP_POP] = {op_pop, 2, 1, -1, op_kind::regular}; + table[OP_MLOAD] = {op_mload, 3, 1, 0, op_kind::regular}; + table[OP_MSTORE] = {op_mstore, 3, 2, -2, op_kind::regular}; + table[OP_MSTORE8] = {op_mstore8, 3, 2, -2, op_kind::regular}; + table[OP_SLOAD] = {op_sload, 50, 1, 0, op_kind::regular}; + table[OP_SSTORE] = {op_sstore, 0, 2, -2, op_kind::regular}; + table[OP_JUMP] = {op_jump, 8, 1, -1, op_kind::terminator}; + table[OP_JUMPI] = {op_jumpi, 10, 2, -2, op_kind::terminator}; + table[OP_PC] = {op_pc, 2, 0, 1, op_kind::pc}; + table[OP_MSIZE] = {op_msize, 2, 0, 1, op_kind::regular}; + table[OP_GAS] = {op_gas, 2, 0, 1, op_kind::gas_counter_access}; + table[OPX_BEGINBLOCK] = {opx_beginblock, 1, 0, 0, op_kind::regular}; // Replaces JUMPDEST. for (auto op = size_t{OP_PUSH1}; op <= OP_PUSH8; ++op) - table[op] = {op_push_small, 3, 0, 1}; + table[op] = {op_push_small, 3, 0, 1, op_kind::small_push}; for (auto op = size_t{OP_PUSH9}; op <= OP_PUSH32; ++op) - 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}; + table[op] = {op_push_full, 3, 0, 1, op_kind::large_push}; + + table[OP_DUP1] = {op_dup, 3, 1, 1, op_kind::regular}; + table[OP_DUP2] = {op_dup, 3, 2, 1, op_kind::regular}; + table[OP_DUP3] = {op_dup, 3, 3, 1, op_kind::regular}; + table[OP_DUP4] = {op_dup, 3, 4, 1, op_kind::regular}; + table[OP_DUP5] = {op_dup, 3, 5, 1, op_kind::regular}; + table[OP_DUP6] = {op_dup, 3, 6, 1, op_kind::regular}; + table[OP_DUP7] = {op_dup, 3, 7, 1, op_kind::regular}; + table[OP_DUP8] = {op_dup, 3, 8, 1, op_kind::regular}; + table[OP_DUP9] = {op_dup, 3, 9, 1, op_kind::regular}; + table[OP_DUP10] = {op_dup, 3, 10, 1, op_kind::regular}; + table[OP_DUP11] = {op_dup, 3, 11, 1, op_kind::regular}; + table[OP_DUP12] = {op_dup, 3, 12, 1, op_kind::regular}; + table[OP_DUP13] = {op_dup, 3, 13, 1, op_kind::regular}; + table[OP_DUP14] = {op_dup, 3, 14, 1, op_kind::regular}; + table[OP_DUP15] = {op_dup, 3, 15, 1, op_kind::regular}; + table[OP_DUP16] = {op_dup, 3, 16, 1, op_kind::regular}; + + table[OP_SWAP1] = {op_swap, 3, 2, 0, op_kind::regular}; + table[OP_SWAP2] = {op_swap, 3, 3, 0, op_kind::regular}; + table[OP_SWAP3] = {op_swap, 3, 4, 0, op_kind::regular}; + table[OP_SWAP4] = {op_swap, 3, 5, 0, op_kind::regular}; + table[OP_SWAP5] = {op_swap, 3, 6, 0, op_kind::regular}; + table[OP_SWAP6] = {op_swap, 3, 7, 0, op_kind::regular}; + table[OP_SWAP7] = {op_swap, 3, 8, 0, op_kind::regular}; + table[OP_SWAP8] = {op_swap, 3, 9, 0, op_kind::regular}; + table[OP_SWAP9] = {op_swap, 3, 10, 0, op_kind::regular}; + table[OP_SWAP10] = {op_swap, 3, 11, 0, op_kind::regular}; + table[OP_SWAP11] = {op_swap, 3, 12, 0, op_kind::regular}; + table[OP_SWAP12] = {op_swap, 3, 13, 0, op_kind::regular}; + table[OP_SWAP13] = {op_swap, 3, 14, 0, op_kind::regular}; + table[OP_SWAP14] = {op_swap, 3, 15, 0, op_kind::regular}; + table[OP_SWAP15] = {op_swap, 3, 16, 0, op_kind::regular}; + table[OP_SWAP16] = {op_swap, 3, 17, 0, op_kind::regular}; + + table[OP_LOG0] = {op_log, 1 * 375, 2, -2, op_kind::regular}; + table[OP_LOG1] = {op_log, 2 * 375, 3, -3, op_kind::regular}; + table[OP_LOG2] = {op_log, 3 * 375, 4, -4, op_kind::regular}; + table[OP_LOG3] = {op_log, 4 * 375, 5, -5, op_kind::regular}; + table[OP_LOG4] = {op_log, 5 * 375, 6, -6, op_kind::regular}; + + table[OP_CREATE] = {op_create, 32000, 3, -2, op_kind::gas_counter_access}; + table[OP_CALL] = {op_call, 40, 7, -6, op_kind::gas_counter_access}; + table[OP_CALLCODE] = {op_call, 40, 7, -6, op_kind::gas_counter_access}; + table[OP_RETURN] = {op_return, 0, 2, -2, op_kind::terminator}; + table[OP_INVALID] = {op_invalid, 0, 0, 0, op_kind::regular}; + table[OP_SELFDESTRUCT] = {op_selfdestruct, 0, 1, -1, op_kind::terminator}; return table; } constexpr op_table create_op_table_homestead() noexcept { auto table = create_op_table_frontier(); - table[OP_DELEGATECALL] = {op_delegatecall, 40, 6, -5}; + table[OP_DELEGATECALL] = {op_delegatecall, 40, 6, -5, op_kind::gas_counter_access}; return table; } @@ -1359,21 +1359,21 @@ constexpr op_table create_op_table_tangerine_whistle() noexcept 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}; + table[OP_RETURNDATASIZE] = {op_returndatasize, 2, 0, 1, op_kind::regular}; + table[OP_RETURNDATACOPY] = {op_returndatacopy, 3, 3, -3, op_kind::regular}; + table[OP_STATICCALL] = {op_staticcall, 700, 6, -5, op_kind::gas_counter_access}; + table[OP_REVERT] = {op_revert, 0, 2, -2, op_kind::terminator}; return table; } constexpr op_table create_op_table_constantinople() noexcept { auto table = create_op_table_byzantium(); - 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}; + table[OP_SHL] = {op_shl, 3, 2, -1, op_kind::regular}; + table[OP_SHR] = {op_shr, 3, 2, -1, op_kind::regular}; + table[OP_SAR] = {op_sar, 3, 2, -1, op_kind::regular}; + table[OP_EXTCODEHASH] = {op_extcodehash, 400, 1, 0, op_kind::regular}; + table[OP_CREATE2] = {op_create2, 32000, 4, -3, op_kind::gas_counter_access}; return table; }