diff --git a/lib/evmone/baseline_analysis.cpp b/lib/evmone/baseline_analysis.cpp index 85efe8f2a4..640fe307da 100644 --- a/lib/evmone/baseline_analysis.cpp +++ b/lib/evmone/baseline_analysis.cpp @@ -6,6 +6,7 @@ #include "eof.hpp" #include "instructions.hpp" #include +#include namespace evmone::baseline { @@ -16,8 +17,37 @@ static_assert(!std::is_copy_assignable_v); namespace { +/// Heuristic that checks if the given opcode as the first instruction in a code +/// terminates the execution for any reason. +/// This heuristic may have false negatives. +constexpr bool first_instruction_terminates(uint8_t op) noexcept +{ + return op < OP_ADDRESS || op > OP_PUSH32; +} + +consteval bool proof_first_instruction_terminates(uint8_t op) noexcept +{ + if (!first_instruction_terminates(op)) // ignore if not positive + return true; + + const auto& tr = instr::traits[op]; + if (!tr.since.has_value()) // is undefined in all revisions + return true; + if (tr.is_terminating) // terminates normally + return true; + if (tr.stack_height_required > 0) // causes stack underflow + return true; + return false; +} +static_assert(std::ranges::all_of( + std::views::iota(uint8_t{0}) | std::views::take(256), proof_first_instruction_terminates)); +static_assert(first_instruction_terminates(0xEF)); // EOF is included. + CodeAnalysis::JumpdestMap analyze_jumpdests(bytes_view code) { + if (code.empty() || first_instruction_terminates(code[0])) + return {}; + // To find if op is any PUSH opcode (OP_PUSH1 <= op <= OP_PUSH32) // it can be noticed that OP_PUSH32 is INT8_MAX (0x7f) therefore // static_cast(op) <= OP_PUSH32 is always true and can be skipped. diff --git a/lib/evmone/baseline_instruction_table.cpp b/lib/evmone/baseline_instruction_table.cpp index 5fab960f9e..5ce155a073 100644 --- a/lib/evmone/baseline_instruction_table.cpp +++ b/lib/evmone/baseline_instruction_table.cpp @@ -9,108 +9,29 @@ namespace evmone::baseline { namespace { -constexpr auto common_cost_tables = []() noexcept { +consteval auto build_cost_tables(bool eof) noexcept +{ std::array tables{}; for (size_t r = EVMC_FRONTIER; r <= EVMC_MAX_REVISION; ++r) { auto& table = tables[r]; - for (size_t i = 0; i < table.size(); ++i) + for (size_t op = 0; op < table.size(); ++op) { - table[i] = instr::gas_costs[r][i]; // Include instr::undefined in the table. + const auto& tr = instr::traits[op]; + const auto since = eof ? tr.eof_since : tr.since; + table[op] = (since && r >= *since) ? instr::gas_costs[r][op] : instr::undefined; } } return tables; -}(); - -constexpr auto legacy_cost_tables = []() noexcept { - auto tables = common_cost_tables; - tables[EVMC_PRAGUE][OP_RJUMP] = instr::undefined; - tables[EVMC_PRAGUE][OP_RJUMPI] = instr::undefined; - tables[EVMC_PRAGUE][OP_RJUMPV] = instr::undefined; - tables[EVMC_PRAGUE][OP_CALLF] = instr::undefined; - tables[EVMC_PRAGUE][OP_RETF] = instr::undefined; - tables[EVMC_PRAGUE][OP_JUMPF] = instr::undefined; - tables[EVMC_PRAGUE][OP_DATALOAD] = instr::undefined; - tables[EVMC_PRAGUE][OP_DATALOADN] = instr::undefined; - tables[EVMC_PRAGUE][OP_DATASIZE] = instr::undefined; - tables[EVMC_PRAGUE][OP_DATACOPY] = instr::undefined; - tables[EVMC_PRAGUE][OP_DUPN] = instr::undefined; - tables[EVMC_PRAGUE][OP_SWAPN] = instr::undefined; - tables[EVMC_PRAGUE][OP_EXCHANGE] = instr::undefined; - tables[EVMC_PRAGUE][OP_RETURNDATALOAD] = instr::undefined; - tables[EVMC_PRAGUE][OP_EXTCALL] = instr::undefined; - tables[EVMC_PRAGUE][OP_EXTSTATICCALL] = instr::undefined; - tables[EVMC_PRAGUE][OP_EXTDELEGATECALL] = instr::undefined; - tables[EVMC_PRAGUE][OP_EOFCREATE] = instr::undefined; - tables[EVMC_PRAGUE][OP_RETURNCONTRACT] = instr::undefined; - - tables[EVMC_OSAKA][OP_RJUMP] = instr::undefined; - tables[EVMC_OSAKA][OP_RJUMPI] = instr::undefined; - tables[EVMC_OSAKA][OP_RJUMPV] = instr::undefined; - tables[EVMC_OSAKA][OP_CALLF] = instr::undefined; - tables[EVMC_OSAKA][OP_RETF] = instr::undefined; - tables[EVMC_OSAKA][OP_JUMPF] = instr::undefined; - tables[EVMC_OSAKA][OP_DATALOAD] = instr::undefined; - tables[EVMC_OSAKA][OP_DATALOADN] = instr::undefined; - tables[EVMC_OSAKA][OP_DATASIZE] = instr::undefined; - tables[EVMC_OSAKA][OP_DATACOPY] = instr::undefined; - tables[EVMC_OSAKA][OP_DUPN] = instr::undefined; - tables[EVMC_OSAKA][OP_SWAPN] = instr::undefined; - tables[EVMC_OSAKA][OP_EXCHANGE] = instr::undefined; - tables[EVMC_OSAKA][OP_RETURNDATALOAD] = instr::undefined; - tables[EVMC_OSAKA][OP_EXTCALL] = instr::undefined; - tables[EVMC_OSAKA][OP_EXTSTATICCALL] = instr::undefined; - tables[EVMC_OSAKA][OP_EXTDELEGATECALL] = instr::undefined; - tables[EVMC_OSAKA][OP_EOFCREATE] = instr::undefined; - tables[EVMC_OSAKA][OP_RETURNCONTRACT] = instr::undefined; - tables[EVMC_OSAKA][OP_TXCREATE] = instr::undefined; - - return tables; -}(); - -constexpr auto eof_cost_tables = []() noexcept { - auto tables = common_cost_tables; - tables[EVMC_PRAGUE][OP_JUMP] = instr::undefined; - tables[EVMC_PRAGUE][OP_JUMPI] = instr::undefined; - tables[EVMC_PRAGUE][OP_PC] = instr::undefined; - tables[EVMC_PRAGUE][OP_CALLCODE] = instr::undefined; - tables[EVMC_PRAGUE][OP_SELFDESTRUCT] = instr::undefined; - tables[EVMC_PRAGUE][OP_CALL] = instr::undefined; - tables[EVMC_PRAGUE][OP_STATICCALL] = instr::undefined; - tables[EVMC_PRAGUE][OP_DELEGATECALL] = instr::undefined; - tables[EVMC_PRAGUE][OP_CREATE] = instr::undefined; - tables[EVMC_PRAGUE][OP_CREATE2] = instr::undefined; - tables[EVMC_PRAGUE][OP_CODESIZE] = instr::undefined; - tables[EVMC_PRAGUE][OP_CODECOPY] = instr::undefined; - tables[EVMC_PRAGUE][OP_EXTCODESIZE] = instr::undefined; - tables[EVMC_PRAGUE][OP_EXTCODECOPY] = instr::undefined; - tables[EVMC_PRAGUE][OP_EXTCODEHASH] = instr::undefined; - tables[EVMC_PRAGUE][OP_GAS] = instr::undefined; - - tables[EVMC_OSAKA][OP_JUMP] = instr::undefined; - tables[EVMC_OSAKA][OP_JUMPI] = instr::undefined; - tables[EVMC_OSAKA][OP_PC] = instr::undefined; - tables[EVMC_OSAKA][OP_CALLCODE] = instr::undefined; - tables[EVMC_OSAKA][OP_SELFDESTRUCT] = instr::undefined; - tables[EVMC_OSAKA][OP_CALL] = instr::undefined; - tables[EVMC_OSAKA][OP_STATICCALL] = instr::undefined; - tables[EVMC_OSAKA][OP_DELEGATECALL] = instr::undefined; - tables[EVMC_OSAKA][OP_CREATE] = instr::undefined; - tables[EVMC_OSAKA][OP_CREATE2] = instr::undefined; - tables[EVMC_OSAKA][OP_CODESIZE] = instr::undefined; - tables[EVMC_OSAKA][OP_CODECOPY] = instr::undefined; - tables[EVMC_OSAKA][OP_EXTCODESIZE] = instr::undefined; - tables[EVMC_OSAKA][OP_EXTCODECOPY] = instr::undefined; - tables[EVMC_OSAKA][OP_EXTCODEHASH] = instr::undefined; - tables[EVMC_OSAKA][OP_GAS] = instr::undefined; - return tables; -}(); +} +constexpr auto LEGACY_COST_TABLES = build_cost_tables(false); +constexpr auto EOF_COST_TABLES = build_cost_tables(true); } // namespace const CostTable& get_baseline_cost_table(evmc_revision rev, uint8_t eof_version) noexcept { - const auto& tables = (eof_version == 0) ? legacy_cost_tables : eof_cost_tables; + const auto& tables = (eof_version == 0) ? LEGACY_COST_TABLES : EOF_COST_TABLES; return tables[rev]; } } // namespace evmone::baseline diff --git a/lib/evmone/instructions_traits.hpp b/lib/evmone/instructions_traits.hpp index b38242e85b..12323622f8 100644 --- a/lib/evmone/instructions_traits.hpp +++ b/lib/evmone/instructions_traits.hpp @@ -200,6 +200,9 @@ constexpr inline GasCostTable gas_costs = []() noexcept { static_assert(gas_costs[EVMC_MAX_REVISION][OP_ADD] > 0, "gas costs missing for a revision"); +constexpr auto REV_EOF1 = EVMC_PRAGUE; + + /// The EVM instruction traits. struct Traits { @@ -223,6 +226,8 @@ struct Traits /// every EVM revision the value is ::EVMC_FRONTIER. For undefined instructions the value is not /// available. std::optional since; + + std::optional eof_since; }; /// Determines if an instruction has constant base gas cost across all revisions. @@ -244,187 +249,187 @@ consteval bool has_const_gas_cost(Opcode op) noexcept constexpr inline std::array traits = []() noexcept { std::array table{}; - table[OP_STOP] = {"STOP", 0, true, 0, 0, EVMC_FRONTIER}; - table[OP_ADD] = {"ADD", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_MUL] = {"MUL", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_SUB] = {"SUB", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_DIV] = {"DIV", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_SDIV] = {"SDIV", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_MOD] = {"MOD", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_SMOD] = {"SMOD", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_ADDMOD] = {"ADDMOD", 0, false, 3, -2, EVMC_FRONTIER}; - table[OP_MULMOD] = {"MULMOD", 0, false, 3, -2, EVMC_FRONTIER}; - table[OP_EXP] = {"EXP", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_SIGNEXTEND] = {"SIGNEXTEND", 0, false, 2, -1, EVMC_FRONTIER}; - - table[OP_LT] = {"LT", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_GT] = {"GT", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_SLT] = {"SLT", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_SGT] = {"SGT", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_EQ] = {"EQ", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_ISZERO] = {"ISZERO", 0, false, 1, 0, EVMC_FRONTIER}; - table[OP_AND] = {"AND", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_OR] = {"OR", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_XOR] = {"XOR", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_NOT] = {"NOT", 0, false, 1, 0, EVMC_FRONTIER}; - table[OP_BYTE] = {"BYTE", 0, false, 2, -1, EVMC_FRONTIER}; - table[OP_SHL] = {"SHL", 0, false, 2, -1, EVMC_CONSTANTINOPLE}; - table[OP_SHR] = {"SHR", 0, false, 2, -1, EVMC_CONSTANTINOPLE}; - table[OP_SAR] = {"SAR", 0, false, 2, -1, EVMC_CONSTANTINOPLE}; - - table[OP_KECCAK256] = {"KECCAK256", 0, false, 2, -1, EVMC_FRONTIER}; - - table[OP_ADDRESS] = {"ADDRESS", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_BALANCE] = {"BALANCE", 0, false, 1, 0, EVMC_FRONTIER}; - table[OP_ORIGIN] = {"ORIGIN", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_CALLER] = {"CALLER", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_CALLVALUE] = {"CALLVALUE", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_CALLDATALOAD] = {"CALLDATALOAD", 0, false, 1, 0, EVMC_FRONTIER}; - table[OP_CALLDATASIZE] = {"CALLDATASIZE", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_CALLDATACOPY] = {"CALLDATACOPY", 0, false, 3, -3, EVMC_FRONTIER}; + table[OP_STOP] = {"STOP", 0, true, 0, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_ADD] = {"ADD", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_MUL] = {"MUL", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_SUB] = {"SUB", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DIV] = {"DIV", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_SDIV] = {"SDIV", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_MOD] = {"MOD", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_SMOD] = {"SMOD", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_ADDMOD] = {"ADDMOD", 0, false, 3, -2, EVMC_FRONTIER, REV_EOF1}; + table[OP_MULMOD] = {"MULMOD", 0, false, 3, -2, EVMC_FRONTIER, REV_EOF1}; + table[OP_EXP] = {"EXP", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_SIGNEXTEND] = {"SIGNEXTEND", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + + table[OP_LT] = {"LT", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_GT] = {"GT", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_SLT] = {"SLT", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_SGT] = {"SGT", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_EQ] = {"EQ", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_ISZERO] = {"ISZERO", 0, false, 1, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_AND] = {"AND", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_OR] = {"OR", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_XOR] = {"XOR", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_NOT] = {"NOT", 0, false, 1, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_BYTE] = {"BYTE", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_SHL] = {"SHL", 0, false, 2, -1, EVMC_CONSTANTINOPLE, REV_EOF1}; + table[OP_SHR] = {"SHR", 0, false, 2, -1, EVMC_CONSTANTINOPLE, REV_EOF1}; + table[OP_SAR] = {"SAR", 0, false, 2, -1, EVMC_CONSTANTINOPLE, REV_EOF1}; + + table[OP_KECCAK256] = {"KECCAK256", 0, false, 2, -1, EVMC_FRONTIER, REV_EOF1}; + + table[OP_ADDRESS] = {"ADDRESS", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_BALANCE] = {"BALANCE", 0, false, 1, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_ORIGIN] = {"ORIGIN", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_CALLER] = {"CALLER", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_CALLVALUE] = {"CALLVALUE", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_CALLDATALOAD] = {"CALLDATALOAD", 0, false, 1, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_CALLDATASIZE] = {"CALLDATASIZE", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_CALLDATACOPY] = {"CALLDATACOPY", 0, false, 3, -3, EVMC_FRONTIER, REV_EOF1}; table[OP_CODESIZE] = {"CODESIZE", 0, false, 0, 1, EVMC_FRONTIER}; table[OP_CODECOPY] = {"CODECOPY", 0, false, 3, -3, EVMC_FRONTIER}; - table[OP_GASPRICE] = {"GASPRICE", 0, false, 0, 1, EVMC_FRONTIER}; + table[OP_GASPRICE] = {"GASPRICE", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; table[OP_EXTCODESIZE] = {"EXTCODESIZE", 0, false, 1, 0, EVMC_FRONTIER}; table[OP_EXTCODECOPY] = {"EXTCODECOPY", 0, false, 4, -4, EVMC_FRONTIER}; - table[OP_RETURNDATASIZE] = {"RETURNDATASIZE", 0, false, 0, 1, EVMC_BYZANTIUM}; - table[OP_RETURNDATACOPY] = {"RETURNDATACOPY", 0, false, 3, -3, EVMC_BYZANTIUM}; + table[OP_RETURNDATASIZE] = {"RETURNDATASIZE", 0, false, 0, 1, EVMC_BYZANTIUM, REV_EOF1}; + table[OP_RETURNDATACOPY] = {"RETURNDATACOPY", 0, false, 3, -3, EVMC_BYZANTIUM, REV_EOF1}; table[OP_EXTCODEHASH] = {"EXTCODEHASH", 0, false, 1, 0, EVMC_CONSTANTINOPLE}; - table[OP_BLOCKHASH] = {"BLOCKHASH", 0, false, 1, 0, EVMC_FRONTIER}; - table[OP_COINBASE] = {"COINBASE", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_TIMESTAMP] = {"TIMESTAMP", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_NUMBER] = {"NUMBER", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_PREVRANDAO] = {"PREVRANDAO", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_GASLIMIT] = {"GASLIMIT", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_CHAINID] = {"CHAINID", 0, false, 0, 1, EVMC_ISTANBUL}; - table[OP_SELFBALANCE] = {"SELFBALANCE", 0, false, 0, 1, EVMC_ISTANBUL}; - table[OP_BASEFEE] = {"BASEFEE", 0, false, 0, 1, EVMC_LONDON}; - table[OP_BLOBHASH] = {"BLOBHASH", 0, false, 1, 0, EVMC_CANCUN}; - table[OP_BLOBBASEFEE] = {"BLOBBASEFEE", 0, false, 0, 1, EVMC_CANCUN}; - - table[OP_POP] = {"POP", 0, false, 1, -1, EVMC_FRONTIER}; - table[OP_MLOAD] = {"MLOAD", 0, false, 1, 0, EVMC_FRONTIER}; - table[OP_MSTORE] = {"MSTORE", 0, false, 2, -2, EVMC_FRONTIER}; - table[OP_MSTORE8] = {"MSTORE8", 0, false, 2, -2, EVMC_FRONTIER}; - table[OP_SLOAD] = {"SLOAD", 0, false, 1, 0, EVMC_FRONTIER}; - table[OP_SSTORE] = {"SSTORE", 0, false, 2, -2, EVMC_FRONTIER}; + table[OP_BLOCKHASH] = {"BLOCKHASH", 0, false, 1, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_COINBASE] = {"COINBASE", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_TIMESTAMP] = {"TIMESTAMP", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_NUMBER] = {"NUMBER", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PREVRANDAO] = {"PREVRANDAO", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_GASLIMIT] = {"GASLIMIT", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_CHAINID] = {"CHAINID", 0, false, 0, 1, EVMC_ISTANBUL, REV_EOF1}; + table[OP_SELFBALANCE] = {"SELFBALANCE", 0, false, 0, 1, EVMC_ISTANBUL, REV_EOF1}; + table[OP_BASEFEE] = {"BASEFEE", 0, false, 0, 1, EVMC_LONDON, REV_EOF1}; + table[OP_BLOBHASH] = {"BLOBHASH", 0, false, 1, 0, EVMC_CANCUN, REV_EOF1}; + table[OP_BLOBBASEFEE] = {"BLOBBASEFEE", 0, false, 0, 1, EVMC_CANCUN, REV_EOF1}; + + table[OP_POP] = {"POP", 0, false, 1, -1, EVMC_FRONTIER, REV_EOF1}; + table[OP_MLOAD] = {"MLOAD", 0, false, 1, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_MSTORE] = {"MSTORE", 0, false, 2, -2, EVMC_FRONTIER, REV_EOF1}; + table[OP_MSTORE8] = {"MSTORE8", 0, false, 2, -2, EVMC_FRONTIER, REV_EOF1}; + table[OP_SLOAD] = {"SLOAD", 0, false, 1, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SSTORE] = {"SSTORE", 0, false, 2, -2, EVMC_FRONTIER, REV_EOF1}; table[OP_JUMP] = {"JUMP", 0, false, 1, -1, EVMC_FRONTIER}; table[OP_JUMPI] = {"JUMPI", 0, false, 2, -2, EVMC_FRONTIER}; table[OP_PC] = {"PC", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_MSIZE] = {"MSIZE", 0, false, 0, 1, EVMC_FRONTIER}; + table[OP_MSIZE] = {"MSIZE", 0, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; table[OP_GAS] = {"GAS", 0, false, 0, 1, EVMC_FRONTIER}; - table[OP_JUMPDEST] = {"JUMPDEST", 0, false, 0, 0, EVMC_FRONTIER}; - table[OP_RJUMP] = {"RJUMP", 2, false, 0, 0, EVMC_PRAGUE}; - table[OP_RJUMPI] = {"RJUMPI", 2, false, 1, -1, EVMC_PRAGUE}; + table[OP_JUMPDEST] = {"JUMPDEST", 0, false, 0, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_RJUMP] = {"RJUMP", 2, false, 0, 0, {}, REV_EOF1}; + table[OP_RJUMPI] = {"RJUMPI", 2, false, 1, -1, {}, REV_EOF1}; table[OP_RJUMPV] = { - "RJUMPV", 1 /* 1 byte static immediate + dynamic immediate */, false, 1, -1, EVMC_PRAGUE}; - - table[OP_TLOAD] = {"TLOAD", 0, false, 1, 0, EVMC_CANCUN}; - table[OP_TSTORE] = {"TSTORE", 0, false, 2, -2, EVMC_CANCUN}; - table[OP_PUSH0] = {"PUSH0", 0, false, 0, 1, EVMC_SHANGHAI}; - - table[OP_PUSH1] = {"PUSH1", 1, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH2] = {"PUSH2", 2, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH3] = {"PUSH3", 3, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH4] = {"PUSH4", 4, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH5] = {"PUSH5", 5, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH6] = {"PUSH6", 6, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH7] = {"PUSH7", 7, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH8] = {"PUSH8", 8, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH9] = {"PUSH9", 9, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH10] = {"PUSH10", 10, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH11] = {"PUSH11", 11, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH12] = {"PUSH12", 12, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH13] = {"PUSH13", 13, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH14] = {"PUSH14", 14, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH15] = {"PUSH15", 15, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH16] = {"PUSH16", 16, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH17] = {"PUSH17", 17, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH18] = {"PUSH18", 18, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH19] = {"PUSH19", 19, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH20] = {"PUSH20", 20, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH21] = {"PUSH21", 21, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH22] = {"PUSH22", 22, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH23] = {"PUSH23", 23, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH24] = {"PUSH24", 24, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH25] = {"PUSH25", 25, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH26] = {"PUSH26", 26, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH27] = {"PUSH27", 27, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH28] = {"PUSH28", 28, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH29] = {"PUSH29", 29, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH30] = {"PUSH30", 30, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH31] = {"PUSH31", 31, false, 0, 1, EVMC_FRONTIER}; - table[OP_PUSH32] = {"PUSH32", 32, false, 0, 1, EVMC_FRONTIER}; - - table[OP_DUP1] = {"DUP1", 0, false, 1, 1, EVMC_FRONTIER}; - table[OP_DUP2] = {"DUP2", 0, false, 2, 1, EVMC_FRONTIER}; - table[OP_DUP3] = {"DUP3", 0, false, 3, 1, EVMC_FRONTIER}; - table[OP_DUP4] = {"DUP4", 0, false, 4, 1, EVMC_FRONTIER}; - table[OP_DUP5] = {"DUP5", 0, false, 5, 1, EVMC_FRONTIER}; - table[OP_DUP6] = {"DUP6", 0, false, 6, 1, EVMC_FRONTIER}; - table[OP_DUP7] = {"DUP7", 0, false, 7, 1, EVMC_FRONTIER}; - table[OP_DUP8] = {"DUP8", 0, false, 8, 1, EVMC_FRONTIER}; - table[OP_DUP9] = {"DUP9", 0, false, 9, 1, EVMC_FRONTIER}; - table[OP_DUP10] = {"DUP10", 0, false, 10, 1, EVMC_FRONTIER}; - table[OP_DUP11] = {"DUP11", 0, false, 11, 1, EVMC_FRONTIER}; - table[OP_DUP12] = {"DUP12", 0, false, 12, 1, EVMC_FRONTIER}; - table[OP_DUP13] = {"DUP13", 0, false, 13, 1, EVMC_FRONTIER}; - table[OP_DUP14] = {"DUP14", 0, false, 14, 1, EVMC_FRONTIER}; - table[OP_DUP15] = {"DUP15", 0, false, 15, 1, EVMC_FRONTIER}; - table[OP_DUP16] = {"DUP16", 0, false, 16, 1, EVMC_FRONTIER}; - - table[OP_SWAP1] = {"SWAP1", 0, false, 2, 0, EVMC_FRONTIER}; - table[OP_SWAP2] = {"SWAP2", 0, false, 3, 0, EVMC_FRONTIER}; - table[OP_SWAP3] = {"SWAP3", 0, false, 4, 0, EVMC_FRONTIER}; - table[OP_SWAP4] = {"SWAP4", 0, false, 5, 0, EVMC_FRONTIER}; - table[OP_SWAP5] = {"SWAP5", 0, false, 6, 0, EVMC_FRONTIER}; - table[OP_SWAP6] = {"SWAP6", 0, false, 7, 0, EVMC_FRONTIER}; - table[OP_SWAP7] = {"SWAP7", 0, false, 8, 0, EVMC_FRONTIER}; - table[OP_SWAP8] = {"SWAP8", 0, false, 9, 0, EVMC_FRONTIER}; - table[OP_SWAP9] = {"SWAP9", 0, false, 10, 0, EVMC_FRONTIER}; - table[OP_SWAP10] = {"SWAP10", 0, false, 11, 0, EVMC_FRONTIER}; - table[OP_SWAP11] = {"SWAP11", 0, false, 12, 0, EVMC_FRONTIER}; - table[OP_SWAP12] = {"SWAP12", 0, false, 13, 0, EVMC_FRONTIER}; - table[OP_SWAP13] = {"SWAP13", 0, false, 14, 0, EVMC_FRONTIER}; - table[OP_SWAP14] = {"SWAP14", 0, false, 15, 0, EVMC_FRONTIER}; - table[OP_SWAP15] = {"SWAP15", 0, false, 16, 0, EVMC_FRONTIER}; - table[OP_SWAP16] = {"SWAP16", 0, false, 17, 0, EVMC_FRONTIER}; - - table[OP_LOG0] = {"LOG0", 0, false, 2, -2, EVMC_FRONTIER}; - table[OP_LOG1] = {"LOG1", 0, false, 3, -3, EVMC_FRONTIER}; - table[OP_LOG2] = {"LOG2", 0, false, 4, -4, EVMC_FRONTIER}; - table[OP_LOG3] = {"LOG3", 0, false, 5, -5, EVMC_FRONTIER}; - table[OP_LOG4] = {"LOG4", 0, false, 6, -6, EVMC_FRONTIER}; - - table[OP_DUPN] = {"DUPN", 1, false, 0, 1, EVMC_PRAGUE}; - table[OP_SWAPN] = {"SWAPN", 1, false, 0, 0, EVMC_PRAGUE}; - table[OP_EXCHANGE] = {"EXCHANGE", 1, false, 0, 0, EVMC_PRAGUE}; - table[OP_MCOPY] = {"MCOPY", 0, false, 3, -3, EVMC_CANCUN}; - table[OP_DATALOAD] = {"DATALOAD", 0, false, 1, 0, EVMC_PRAGUE}; - table[OP_DATALOADN] = {"DATALOADN", 2, false, 0, 1, EVMC_PRAGUE}; - table[OP_DATASIZE] = {"DATASIZE", 0, false, 0, 1, EVMC_PRAGUE}; - table[OP_DATACOPY] = {"DATACOPY", 0, false, 3, -3, EVMC_PRAGUE}; + "RJUMPV", 1 /* 1 byte static immediate + dynamic immediate */, false, 1, -1, {}, REV_EOF1}; + + table[OP_TLOAD] = {"TLOAD", 0, false, 1, 0, EVMC_CANCUN, REV_EOF1}; + table[OP_TSTORE] = {"TSTORE", 0, false, 2, -2, EVMC_CANCUN, REV_EOF1}; + table[OP_PUSH0] = {"PUSH0", 0, false, 0, 1, EVMC_SHANGHAI, REV_EOF1}; + + table[OP_PUSH1] = {"PUSH1", 1, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH2] = {"PUSH2", 2, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH3] = {"PUSH3", 3, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH4] = {"PUSH4", 4, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH5] = {"PUSH5", 5, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH6] = {"PUSH6", 6, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH7] = {"PUSH7", 7, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH8] = {"PUSH8", 8, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH9] = {"PUSH9", 9, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH10] = {"PUSH10", 10, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH11] = {"PUSH11", 11, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH12] = {"PUSH12", 12, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH13] = {"PUSH13", 13, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH14] = {"PUSH14", 14, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH15] = {"PUSH15", 15, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH16] = {"PUSH16", 16, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH17] = {"PUSH17", 17, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH18] = {"PUSH18", 18, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH19] = {"PUSH19", 19, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH20] = {"PUSH20", 20, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH21] = {"PUSH21", 21, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH22] = {"PUSH22", 22, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH23] = {"PUSH23", 23, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH24] = {"PUSH24", 24, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH25] = {"PUSH25", 25, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH26] = {"PUSH26", 26, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH27] = {"PUSH27", 27, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH28] = {"PUSH28", 28, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH29] = {"PUSH29", 29, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH30] = {"PUSH30", 30, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH31] = {"PUSH31", 31, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_PUSH32] = {"PUSH32", 32, false, 0, 1, EVMC_FRONTIER, REV_EOF1}; + + table[OP_DUP1] = {"DUP1", 0, false, 1, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP2] = {"DUP2", 0, false, 2, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP3] = {"DUP3", 0, false, 3, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP4] = {"DUP4", 0, false, 4, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP5] = {"DUP5", 0, false, 5, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP6] = {"DUP6", 0, false, 6, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP7] = {"DUP7", 0, false, 7, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP8] = {"DUP8", 0, false, 8, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP9] = {"DUP9", 0, false, 9, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP10] = {"DUP10", 0, false, 10, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP11] = {"DUP11", 0, false, 11, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP12] = {"DUP12", 0, false, 12, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP13] = {"DUP13", 0, false, 13, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP14] = {"DUP14", 0, false, 14, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP15] = {"DUP15", 0, false, 15, 1, EVMC_FRONTIER, REV_EOF1}; + table[OP_DUP16] = {"DUP16", 0, false, 16, 1, EVMC_FRONTIER, REV_EOF1}; + + table[OP_SWAP1] = {"SWAP1", 0, false, 2, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP2] = {"SWAP2", 0, false, 3, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP3] = {"SWAP3", 0, false, 4, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP4] = {"SWAP4", 0, false, 5, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP5] = {"SWAP5", 0, false, 6, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP6] = {"SWAP6", 0, false, 7, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP7] = {"SWAP7", 0, false, 8, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP8] = {"SWAP8", 0, false, 9, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP9] = {"SWAP9", 0, false, 10, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP10] = {"SWAP10", 0, false, 11, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP11] = {"SWAP11", 0, false, 12, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP12] = {"SWAP12", 0, false, 13, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP13] = {"SWAP13", 0, false, 14, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP14] = {"SWAP14", 0, false, 15, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP15] = {"SWAP15", 0, false, 16, 0, EVMC_FRONTIER, REV_EOF1}; + table[OP_SWAP16] = {"SWAP16", 0, false, 17, 0, EVMC_FRONTIER, REV_EOF1}; + + table[OP_LOG0] = {"LOG0", 0, false, 2, -2, EVMC_FRONTIER, REV_EOF1}; + table[OP_LOG1] = {"LOG1", 0, false, 3, -3, EVMC_FRONTIER, REV_EOF1}; + table[OP_LOG2] = {"LOG2", 0, false, 4, -4, EVMC_FRONTIER, REV_EOF1}; + table[OP_LOG3] = {"LOG3", 0, false, 5, -5, EVMC_FRONTIER, REV_EOF1}; + table[OP_LOG4] = {"LOG4", 0, false, 6, -6, EVMC_FRONTIER, REV_EOF1}; + + table[OP_DUPN] = {"DUPN", 1, false, 0, 1, {}, REV_EOF1}; + table[OP_SWAPN] = {"SWAPN", 1, false, 0, 0, {}, REV_EOF1}; + table[OP_EXCHANGE] = {"EXCHANGE", 1, false, 0, 0, {}, REV_EOF1}; + table[OP_MCOPY] = {"MCOPY", 0, false, 3, -3, EVMC_CANCUN, REV_EOF1}; + table[OP_DATALOAD] = {"DATALOAD", 0, false, 1, 0, {}, REV_EOF1}; + table[OP_DATALOADN] = {"DATALOADN", 2, false, 0, 1, {}, REV_EOF1}; + table[OP_DATASIZE] = {"DATASIZE", 0, false, 0, 1, {}, REV_EOF1}; + table[OP_DATACOPY] = {"DATACOPY", 0, false, 3, -3, {}, REV_EOF1}; table[OP_CREATE] = {"CREATE", 0, false, 3, -2, EVMC_FRONTIER}; table[OP_CALL] = {"CALL", 0, false, 7, -6, EVMC_FRONTIER}; table[OP_CALLCODE] = {"CALLCODE", 0, false, 7, -6, EVMC_FRONTIER}; - table[OP_RETURN] = {"RETURN", 0, true, 2, -2, EVMC_FRONTIER}; + table[OP_RETURN] = {"RETURN", 0, true, 2, -2, EVMC_FRONTIER, REV_EOF1}; table[OP_DELEGATECALL] = {"DELEGATECALL", 0, false, 6, -5, EVMC_HOMESTEAD}; table[OP_CREATE2] = {"CREATE2", 0, false, 4, -3, EVMC_CONSTANTINOPLE}; - table[OP_RETURNDATALOAD] = {"RETURNDATALOAD", 0, false, 1, 0, EVMC_PRAGUE}; - table[OP_EOFCREATE] = {"EOFCREATE", 1, false, 4, -3, EVMC_PRAGUE}; - table[OP_TXCREATE] = {"TXCREATE", 0, false, 5, -4, EVMC_OSAKA}; - table[OP_RETURNCONTRACT] = {"RETURNCONTRACT", 1, true, 2, -2, EVMC_PRAGUE}; - table[OP_EXTCALL] = {"EXTCALL", 0, false, 4, -3, EVMC_PRAGUE}; - table[OP_EXTDELEGATECALL] = {"EXTDELEGATECALL", 0, false, 3, -2, EVMC_PRAGUE}; + table[OP_RETURNDATALOAD] = {"RETURNDATALOAD", 0, false, 1, 0, {}, REV_EOF1}; + table[OP_EOFCREATE] = {"EOFCREATE", 1, false, 4, -3, {}, REV_EOF1}; + table[OP_TXCREATE] = {"TXCREATE", 0, false, 5, -4, {}, EVMC_OSAKA}; + table[OP_RETURNCONTRACT] = {"RETURNCONTRACT", 1, true, 2, -2, {}, REV_EOF1}; + table[OP_EXTCALL] = {"EXTCALL", 0, false, 4, -3, {}, REV_EOF1}; + table[OP_EXTDELEGATECALL] = {"EXTDELEGATECALL", 0, false, 3, -2, {}, REV_EOF1}; table[OP_STATICCALL] = {"STATICCALL", 0, false, 6, -5, EVMC_BYZANTIUM}; - table[OP_EXTSTATICCALL] = {"EXTSTATICCALL", 0, false, 3, -2, EVMC_PRAGUE}; - table[OP_CALLF] = {"CALLF", 2, false, 0, 0, EVMC_PRAGUE}; - table[OP_RETF] = {"RETF", 0, true, 0, 0, EVMC_PRAGUE}; - table[OP_JUMPF] = {"JUMPF", 2, true, 0, 0, EVMC_PRAGUE}; - table[OP_REVERT] = {"REVERT", 0, true, 2, -2, EVMC_BYZANTIUM}; - table[OP_INVALID] = {"INVALID", 0, true, 0, 0, EVMC_FRONTIER}; + table[OP_EXTSTATICCALL] = {"EXTSTATICCALL", 0, false, 3, -2, {}, REV_EOF1}; + table[OP_CALLF] = {"CALLF", 2, false, 0, 0, {}, REV_EOF1}; + table[OP_RETF] = {"RETF", 0, true, 0, 0, {}, REV_EOF1}; + table[OP_JUMPF] = {"JUMPF", 2, true, 0, 0, {}, REV_EOF1}; + table[OP_REVERT] = {"REVERT", 0, true, 2, -2, EVMC_BYZANTIUM, REV_EOF1}; + table[OP_INVALID] = {"INVALID", 0, true, 0, 0, EVMC_FRONTIER, REV_EOF1}; table[OP_SELFDESTRUCT] = {"SELFDESTRUCT", 0, true, 1, -1, EVMC_FRONTIER}; return table; diff --git a/test/unittests/instructions_test.cpp b/test/unittests/instructions_test.cpp index c0c00e72bb..db1524f495 100644 --- a/test/unittests/instructions_test.cpp +++ b/test/unittests/instructions_test.cpp @@ -75,7 +75,11 @@ constexpr void validate_traits_of() noexcept // since constexpr auto expected_rev = get_revision_defined_in(Op); - static_assert(tr.since.has_value() ? *tr.since == expected_rev : expected_rev == unspecified); + constexpr auto since = + tr.since.has_value() ? + tr.eof_since.has_value() ? std::min(*tr.since, *tr.eof_since) : *tr.since : + tr.eof_since; + static_assert(since.has_value() ? *since == expected_rev : expected_rev == unspecified); } template