From a90c69f3ff538189268701900f522e1b591cab54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jul 2019 12:00:03 +0200 Subject: [PATCH 1/9] cmake: Disable MSVC warning about alignment --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 531452a8ac..fd82c1f061 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,9 @@ cable_configure_compiler(NO_PEDANTIC NO_CONVERSION_WARNINGS) if(CABLE_COMPILER_GNULIKE) # Prepend to CXX flags to allow overriding. set(CMAKE_CXX_FLAGS "-fvisibility=hidden ${CMAKE_CXX_FLAGS}") +elseif(MSVC) + add_compile_options(/wd4324) # Disabled warning about alignment caused by alignas. + add_compile_options(/wd5030) # Allow using unknown attributes. endif() set(include_dir ${CMAKE_CURRENT_SOURCE_DIR}/include) From d945e911bfb0873ab70b7838ea8e7e23c100f7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jul 2019 12:01:20 +0200 Subject: [PATCH 2/9] cmake: Allow using unknown attributes --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index fd82c1f061..8ed05d08d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,8 @@ add_subdirectory(evmc) cable_configure_compiler(NO_PEDANTIC NO_CONVERSION_WARNINGS) if(CABLE_COMPILER_GNULIKE) + add_compile_options(-Wno-attributes) # Allow using unknown attributes. + # Prepend to CXX flags to allow overriding. set(CMAKE_CXX_FLAGS "-fvisibility=hidden ${CMAKE_CXX_FLAGS}") elseif(MSVC) From 0040179d36254bc561628d3e1f1dd14542670517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jul 2019 09:44:10 +0200 Subject: [PATCH 3/9] Allocate the execution state on heap --- lib/evmone/execution.cpp | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/evmone/execution.cpp b/lib/evmone/execution.cpp index b41ba8d523..af5169a460 100644 --- a/lib/evmone/execution.cpp +++ b/lib/evmone/execution.cpp @@ -9,6 +9,8 @@ #include #include +#include + namespace evmone { extern const exec_fn_table op_table[]; @@ -18,37 +20,37 @@ evmc_result execute(evmc_instance*, evmc_context* ctx, evmc_revision rev, const { auto analysis = analyze(op_table[rev], rev, code, code_size); - execution_state state; - state.analysis = &analysis; - state.msg = msg; - state.code = code; - state.code_size = code_size; - state.host = evmc::HostContext{ctx}; - state.gas_left = msg->gas; - state.rev = rev; - while (state.status == continue_status) + auto state = std::make_unique(); + state->analysis = &analysis; + state->msg = msg; + state->code = code; + state->code_size = code_size; + state->host = evmc::HostContext{ctx}; + state->gas_left = msg->gas; + state->rev = rev; + while (state->status == continue_status) { - auto& instr = analysis.instrs[state.pc]; + auto& instr = analysis.instrs[state->pc]; // Advance the PC not to allow jump opcodes to overwrite it. - ++state.pc; + ++state->pc; - instr.fn(state, instr.arg); + instr.fn(*state, instr.arg); } evmc_result result{}; // Assign status code, revert the "stop" status back to "continue" status - see .exit(). - result.status_code = state.status != stop_status ? state.status : continue_status; + result.status_code = state->status != stop_status ? state->status : continue_status; if (result.status_code == EVMC_SUCCESS || result.status_code == EVMC_REVERT) - result.gas_left = state.gas_left; + result.gas_left = state->gas_left; - if (state.output_size > 0) + if (state->output_size > 0) { - result.output_size = state.output_size; + result.output_size = state->output_size; auto output_data = static_cast(std::malloc(result.output_size)); - std::memcpy(output_data, &state.memory[state.output_offset], result.output_size); + std::memcpy(output_data, &state->memory[state->output_offset], result.output_size); result.output_data = output_data; result.release = [](const evmc_result* r) noexcept { From 613df9e2eca57afd13b9f2f2f5a35b8b1cb5ed39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jul 2019 11:55:56 +0200 Subject: [PATCH 4/9] Add evm_stack data structure to preallocate storage for all stack items --- lib/evmone/analysis.hpp | 44 +++++++++++++++++++++++++++++++++++-- lib/evmone/instructions.cpp | 2 +- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index 0f49b597bb..1fdec14a7b 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -32,13 +32,53 @@ static_assert(continue_status == 0, "The 'continue' status is not 0"); /// The EVMC_INTERNAL_ERROR MUST NOT be used in evmone for any other case. constexpr auto stop_status = EVMC_INTERNAL_ERROR; +/// The stack for 256-bit EVM words. +/// +/// This implementation reserves memory inplace for all possible stack items (1024), +/// so this type is big. Make sure it is allocated on heap. +struct evm_stack +{ + /// The maximum number of stack items. + static constexpr auto limit = 1024; + + /// The pointer to the top item, or below the stack bottom if stack is empty. + uint256* top_item; + + /// The storage allocated for maximum possible number of items. + /// This is also the pointer to the bottom item. + uint256 storage[limit]; + + /// Default constructor. Sets the top_item pointer to below the stack bottom. + [[clang::no_sanitize("bounds")]] evm_stack() noexcept : top_item{storage - 1} {} + + /// The current number of items on the stack. + int size() noexcept { return static_cast(top_item + 1 - storage); } + + /// Returns the reference to the stack item on given position from the stack top. + /// TODO: Rename to get(), at() or operator[]. + uint256& item(int index) noexcept { return *(top_item - index); } + + /// Pushes an item on the stack. The stack limit is not checked. + /// TODO: Rename to push(). + void push_back(const uint256& item) noexcept { *++top_item = item; } + + /// Deprecated. + void emplace_back(const uint256& item) noexcept { return push_back(item); } + + /// Pops the top item from the stack. + /// TODO: Rename to pop(). + /// TODO: Add arg to pop more items at once. + /// TODO: Return the item? + void pop_back() noexcept { --top_item; } +}; + struct execution_state { evmc_status_code status = EVMC_SUCCESS; size_t pc = 0; int64_t gas_left = 0; - std::vector stack; + evm_stack stack; std::vector memory; // TODO: Use bytes. int64_t memory_prev_cost = 0; @@ -61,7 +101,7 @@ struct execution_state evmc_revision rev = {}; - uint256& item(size_t index) noexcept { return stack[stack.size() - index - 1]; } + uint256& item(int index) noexcept { return stack.item(index); } /// Terminates the execution with the given status code. void exit(evmc_status_code status_code) noexcept diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index ac4e903655..0841b1f0ef 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -1221,7 +1221,7 @@ void opx_beginblock(execution_state& state, instr_argument arg) noexcept if (static_cast(state.stack.size()) < block.stack_req) return state.exit(EVMC_STACK_UNDERFLOW); - if (static_cast(state.stack.size()) + block.stack_max > 1024) + if (static_cast(state.stack.size()) + block.stack_max > evm_stack::limit) return state.exit(EVMC_STACK_OVERFLOW); state.current_block_cost = block.gas_cost; From 67e282af37cf8d3ade44386010027a097bb45741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jul 2019 09:59:47 +0200 Subject: [PATCH 5/9] Rename evm_stack::push_back() to evm_stack::push() --- lib/evmone/analysis.hpp | 6 +--- lib/evmone/instructions.cpp | 60 ++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 39 deletions(-) diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index 1fdec14a7b..9bad27bdcd 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -59,11 +59,7 @@ struct evm_stack uint256& item(int index) noexcept { return *(top_item - index); } /// Pushes an item on the stack. The stack limit is not checked. - /// TODO: Rename to push(). - void push_back(const uint256& item) noexcept { *++top_item = item; } - - /// Deprecated. - void emplace_back(const uint256& item) noexcept { return push_back(item); } + void push(const uint256& item) noexcept { *++top_item = item; } /// Pops the top item from the stack. /// TODO: Rename to pop(). diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index 0841b1f0ef..3590dbc143 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -302,8 +302,7 @@ void op_address(execution_state& state, instr_argument) noexcept // TODO: Might be generalized using pointers to class member. uint8_t data[32] = {}; std::memcpy(&data[12], state.msg->destination.bytes, sizeof(state.msg->destination)); - auto a = intx::be::uint256(data); - state.stack.push_back(a); + state.stack.push(intx::be::uint256(data)); } void op_balance(execution_state& state, instr_argument) noexcept @@ -320,8 +319,7 @@ void op_origin(execution_state& state, instr_argument) noexcept { uint8_t data[32] = {}; std::memcpy(&data[12], state.host.get_tx_context().tx_origin.bytes, sizeof(evmc_address)); - auto x = intx::be::uint256(data); - state.stack.push_back(x); + state.stack.push(intx::be::uint256(data)); } void op_caller(execution_state& state, instr_argument) noexcept @@ -329,14 +327,12 @@ void op_caller(execution_state& state, instr_argument) noexcept // TODO: Might be generalized using pointers to class member. uint8_t data[32] = {}; std::memcpy(&data[12], state.msg->sender.bytes, sizeof(state.msg->sender)); - auto a = intx::be::uint256(data); - state.stack.push_back(a); + state.stack.push(intx::be::uint256(data)); } void op_callvalue(execution_state& state, instr_argument) noexcept { - auto a = intx::be::uint256(state.msg->value.bytes); - state.stack.push_back(a); + state.stack.push(intx::be::uint256(state.msg->value.bytes)); } void op_calldataload(execution_state& state, instr_argument) noexcept @@ -360,8 +356,7 @@ void op_calldataload(execution_state& state, instr_argument) noexcept void op_calldatasize(execution_state& state, instr_argument) noexcept { - auto s = intx::uint256{state.msg->input_size}; - state.stack.push_back(s); + state.stack.push(state.msg->input_size); } void op_calldatacopy(execution_state& state, instr_argument) noexcept @@ -396,8 +391,7 @@ void op_calldatacopy(execution_state& state, instr_argument) noexcept void op_codesize(execution_state& state, instr_argument) noexcept { - auto s = intx::uint256{state.code_size}; - state.stack.push_back(s); + state.stack.push(state.code_size); } void op_codecopy(execution_state& state, instr_argument) noexcept @@ -539,25 +533,24 @@ void op_jumpi(execution_state& state, instr_argument arg) noexcept void op_pc(execution_state& state, instr_argument arg) noexcept { - state.stack.emplace_back(arg.p.number); + state.stack.push(arg.p.number); } void op_msize(execution_state& state, instr_argument) noexcept { - state.stack.emplace_back(state.memory.size()); + state.stack.push(state.memory.size()); } void op_gas(execution_state& state, instr_argument arg) noexcept { - auto correction = state.current_block_cost - arg.p.number; - intx::uint256 gas = static_cast(state.gas_left + correction); - state.stack.push_back(gas); + const auto correction = state.current_block_cost - arg.p.number; + const auto gas = static_cast(state.gas_left + correction); + state.stack.push(gas); } void op_gasprice(execution_state& state, instr_argument) noexcept { - auto x = intx::be::uint256(state.host.get_tx_context().tx_gas_price.bytes); - state.stack.push_back(x); + state.stack.push(intx::be::uint256(state.host.get_tx_context().tx_gas_price.bytes)); } void op_extcodesize(execution_state& state, instr_argument) noexcept @@ -608,7 +601,7 @@ void op_extcodecopy(execution_state& state, instr_argument) noexcept void op_returndatasize(execution_state& state, instr_argument) noexcept { - state.stack.emplace_back(state.return_data.size()); + state.stack.push(state.return_data.size()); } void op_returndatacopy(execution_state& state, instr_argument) noexcept @@ -669,39 +662,38 @@ void op_coinbase(execution_state& state, instr_argument) noexcept { uint8_t data[32] = {}; std::memcpy(&data[12], state.host.get_tx_context().block_coinbase.bytes, sizeof(evmc_address)); - auto x = intx::be::uint256(data); - state.stack.push_back(x); + state.stack.push(intx::be::uint256(data)); } void op_timestamp(execution_state& state, instr_argument) noexcept { - auto x = intx::uint256{static_cast(state.host.get_tx_context().block_timestamp)}; - state.stack.push_back(x); + // TODO: Add tests for negative timestamp? + const auto timestamp = static_cast(state.host.get_tx_context().block_timestamp); + state.stack.push(timestamp); } void op_number(execution_state& state, instr_argument) noexcept { - auto x = intx::uint256{static_cast(state.host.get_tx_context().block_number)}; - state.stack.push_back(x); + // TODO: Add tests for negative block number? + const auto block_number = static_cast(state.host.get_tx_context().block_number); + state.stack.push(block_number); } void op_difficulty(execution_state& state, instr_argument) noexcept { - auto x = intx::be::uint256(state.host.get_tx_context().block_difficulty.bytes); - state.stack.push_back(x); + state.stack.push(intx::be::uint256(state.host.get_tx_context().block_difficulty.bytes)); } void op_gaslimit(execution_state& state, instr_argument) noexcept { - auto x = intx::uint256{static_cast(state.host.get_tx_context().block_gas_limit)}; - state.stack.push_back(x); + const auto block_gas_limit = static_cast(state.host.get_tx_context().block_gas_limit); + state.stack.push(block_gas_limit); } void op_push_full(execution_state& state, instr_argument arg) noexcept { // OPT: For smaller pushes, use pointer data directly. - auto x = intx::be::uint256(arg.data); - state.stack.push_back(x); + state.stack.push(intx::be::uint256(arg.data)); } void op_pop(execution_state& state, instr_argument) noexcept @@ -711,12 +703,12 @@ void op_pop(execution_state& state, instr_argument) noexcept void op_dup(execution_state& state, instr_argument arg) noexcept { - state.stack.push_back(state.item(static_cast(arg.p.number))); + state.stack.push(state.item(arg.p.number)); } void op_swap(execution_state& state, instr_argument arg) noexcept { - std::swap(state.item(0), state.item(static_cast(arg.p.number))); + std::swap(state.item(0), state.item(arg.p.number)); } void op_log(execution_state& state, instr_argument arg) noexcept From a323c0a2dfc94e5b6397fe879fec9c639a3759f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jul 2019 10:41:00 +0200 Subject: [PATCH 6/9] Cleanup usage of evm_stack::pop() --- lib/evmone/analysis.hpp | 7 +- lib/evmone/instructions.cpp | 213 ++++++++++++++---------------------- 2 files changed, 87 insertions(+), 133 deletions(-) diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index 9bad27bdcd..515874baa7 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -61,11 +61,8 @@ struct evm_stack /// Pushes an item on the stack. The stack limit is not checked. void push(const uint256& item) noexcept { *++top_item = item; } - /// Pops the top item from the stack. - /// TODO: Rename to pop(). - /// TODO: Add arg to pop more items at once. - /// TODO: Return the item? - void pop_back() noexcept { --top_item; } + /// Returns an item popped from the top of the stack. + uint256 pop() noexcept { return *top_item--; } }; struct execution_state diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index 3590dbc143..1436d6b78d 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -62,78 +62,72 @@ void op_stop(execution_state& state, instr_argument) noexcept void op_add(execution_state& state, instr_argument) noexcept { - state.item(1) += state.item(0); - state.stack.pop_back(); + state.item(0) += state.stack.pop(); } void op_mul(execution_state& state, instr_argument) noexcept { - state.item(1) *= state.item(0); - state.stack.pop_back(); + state.item(0) *= state.stack.pop(); } void op_sub(execution_state& state, instr_argument) noexcept { state.item(1) = state.item(0) - state.item(1); - state.stack.pop_back(); + state.stack.pop(); } void op_div(execution_state& state, instr_argument) noexcept { auto& v = state.item(1); v = v != 0 ? state.item(0) / v : 0; - state.stack.pop_back(); + state.stack.pop(); } void op_sdiv(execution_state& state, instr_argument) noexcept { auto& v = state.item(1); v = v != 0 ? intx::sdivrem(state.item(0), v).quot : 0; - state.stack.pop_back(); + state.stack.pop(); } void op_mod(execution_state& state, instr_argument) noexcept { auto& v = state.item(1); v = v != 0 ? state.item(0) % v : 0; - state.stack.pop_back(); + state.stack.pop(); } void op_smod(execution_state& state, instr_argument) noexcept { auto& v = state.item(1); v = v != 0 ? intx::sdivrem(state.item(0), v).rem : 0; - state.stack.pop_back(); + state.stack.pop(); } void op_addmod(execution_state& state, instr_argument) noexcept { using intx::uint512; - auto x = state.item(0); - auto y = state.item(1); - auto m = state.item(2); - state.stack.pop_back(); - state.stack.pop_back(); + const auto x = state.stack.pop(); + const auto y = state.stack.pop(); + auto& m = state.item(0); - state.item(0) = m != 0 ? ((uint512{x} + uint512{y}) % uint512{m}).lo : 0; + m = m != 0 ? ((uint512{x} + uint512{y}) % uint512{m}).lo : 0; } void op_mulmod(execution_state& state, instr_argument) noexcept { using intx::uint512; - auto x = state.item(0); - auto y = state.item(1); - auto m = state.item(2); - state.stack.pop_back(); - state.stack.pop_back(); + const auto x = state.stack.pop(); + const auto y = state.stack.pop(); + auto& m = state.item(0); - state.item(0) = m != 0 ? ((uint512{x} * uint512{y}) % uint512{m}).lo : 0; + m = m != 0 ? ((uint512{x} * uint512{y}) % uint512{m}).lo : 0; } void op_exp(execution_state& state, instr_argument) noexcept { - const auto base = state.item(0); - auto& exponent = state.item(1); + const auto base = state.stack.pop(); + auto& exponent = state.item(0); const auto exponent_significant_bytes = intx::count_significant_words(exponent); const auto exponent_cost = state.rev >= EVMC_SPURIOUS_DRAGON ? 50 : 10; @@ -142,13 +136,11 @@ void op_exp(execution_state& state, instr_argument) noexcept return state.exit(EVMC_OUT_OF_GAS); exponent = intx::exp(base, exponent); - state.stack.pop_back(); } void op_signextend(execution_state& state, instr_argument) noexcept { - auto ext = state.item(0); - state.stack.pop_back(); + const auto ext = state.stack.pop(); auto& x = state.item(0); if (ext < 31) @@ -165,13 +157,13 @@ void op_lt(execution_state& state, instr_argument) noexcept { // OPT: Have single function implementing all comparisons. state.item(1) = state.item(0) < state.item(1); - state.stack.pop_back(); + state.stack.pop(); } void op_gt(execution_state& state, instr_argument) noexcept { state.item(1) = state.item(1) < state.item(0); - state.stack.pop_back(); + state.stack.pop(); } void op_slt(execution_state& state, instr_argument) noexcept @@ -181,7 +173,7 @@ void op_slt(execution_state& state, instr_argument) noexcept auto x_neg = static_cast(x >> 255); auto y_neg = static_cast(y >> 255); state.item(1) = (x_neg ^ y_neg) ? x_neg : x < y; - state.stack.pop_back(); + state.stack.pop(); } void op_sgt(execution_state& state, instr_argument) noexcept @@ -191,13 +183,13 @@ void op_sgt(execution_state& state, instr_argument) noexcept auto x_neg = static_cast(x >> 255); auto y_neg = static_cast(y >> 255); state.item(1) = (x_neg ^ y_neg) ? y_neg : y < x; - state.stack.pop_back(); + state.stack.pop(); } void op_eq(execution_state& state, instr_argument) noexcept { state.item(1) = state.item(0) == state.item(1); - state.stack.pop_back(); + state.stack.pop(); } void op_iszero(execution_state& state, instr_argument) noexcept @@ -207,20 +199,17 @@ void op_iszero(execution_state& state, instr_argument) noexcept void op_and(execution_state& state, instr_argument) noexcept { - state.item(1) &= state.item(0); - state.stack.pop_back(); + state.item(0) &= state.stack.pop(); } void op_or(execution_state& state, instr_argument) noexcept { - state.item(1) |= state.item(0); - state.stack.pop_back(); + state.item(0) |= state.stack.pop(); } void op_xor(execution_state& state, instr_argument) noexcept { - state.item(1) ^= state.item(0); - state.stack.pop_back(); + state.item(0) ^= state.stack.pop(); } void op_not(execution_state& state, instr_argument) noexcept @@ -230,8 +219,8 @@ void op_not(execution_state& state, instr_argument) noexcept void op_byte(execution_state& state, instr_argument) noexcept { - auto n = state.item(0); - auto& x = state.item(1); + const auto n = state.stack.pop(); + auto& x = state.item(0); if (n > 31) x = 0; @@ -241,20 +230,16 @@ void op_byte(execution_state& state, instr_argument) noexcept auto y = x >> sh; x = y & 0xff; } - - state.stack.pop_back(); } void op_shl(execution_state& state, instr_argument) noexcept { - state.item(1) <<= state.item(0); - state.stack.pop_back(); + state.item(0) <<= state.stack.pop(); } void op_shr(execution_state& state, instr_argument) noexcept { - state.item(1) >>= state.item(0); - state.stack.pop_back(); + state.item(0) >>= state.stack.pop(); } void op_sar(execution_state& state, instr_argument arg) noexcept @@ -272,13 +257,13 @@ void op_sar(execution_state& state, instr_argument arg) noexcept state.item(1) = (state.item(1) >> shift) | (allones << (256 - shift)); } - state.stack.pop_back(); + state.stack.pop(); } void op_sha3(execution_state& state, instr_argument) noexcept { - auto index = state.item(0); - auto size = state.item(1); + const auto index = state.stack.pop(); + auto& size = state.item(0); if (!check_memory(state, index, size)) return; @@ -293,8 +278,7 @@ void op_sha3(execution_state& state, instr_argument) noexcept auto data = s != 0 ? &state.memory[i] : nullptr; auto h = ethash::keccak256(data, s); - state.stack.pop_back(); - state.item(0) = intx::be::uint256(h.bytes); + size = intx::be::uint256(h.bytes); } void op_address(execution_state& state, instr_argument) noexcept @@ -361,9 +345,9 @@ void op_calldatasize(execution_state& state, instr_argument) noexcept void op_calldatacopy(execution_state& state, instr_argument) noexcept { - auto mem_index = state.item(0); - auto input_index = state.item(1); - auto size = state.item(2); + const auto mem_index = state.stack.pop(); + const auto input_index = state.stack.pop(); + const auto size = state.stack.pop(); if (!check_memory(state, mem_index, size)) return; @@ -383,10 +367,6 @@ void op_calldatacopy(execution_state& state, instr_argument) noexcept if (s - copy_size > 0) std::memset(&state.memory[dst + copy_size], 0, s - copy_size); - - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); } void op_codesize(execution_state& state, instr_argument) noexcept @@ -396,9 +376,11 @@ void op_codesize(execution_state& state, instr_argument) noexcept void op_codecopy(execution_state& state, instr_argument) noexcept { - auto mem_index = state.item(0); - auto input_index = state.item(1); - auto size = state.item(2); + // TODO: Similar to op_calldatacopy(). + + const auto mem_index = state.stack.pop(); + const auto input_index = state.stack.pop(); + const auto size = state.stack.pop(); if (!check_memory(state, mem_index, size)) return; @@ -418,10 +400,6 @@ void op_codecopy(execution_state& state, instr_argument) noexcept if (s - copy_size > 0) std::memset(&state.memory[dst + copy_size], 0, s - copy_size); - - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); } void op_mload(execution_state& state, instr_argument) noexcept @@ -436,30 +414,24 @@ void op_mload(execution_state& state, instr_argument) noexcept void op_mstore(execution_state& state, instr_argument) noexcept { - auto index = state.item(0); - auto x = state.item(1); + const auto index = state.stack.pop(); + const auto value = state.stack.pop(); if (!check_memory(state, index, 32)) return; - intx::be::store(&state.memory[static_cast(index)], x); - - state.stack.pop_back(); - state.stack.pop_back(); + intx::be::store(&state.memory[static_cast(index)], value); } void op_mstore8(execution_state& state, instr_argument) noexcept { - auto index = state.item(0); - auto x = state.item(1); + const auto index = state.stack.pop(); + const auto value = state.stack.pop(); if (!check_memory(state, index, 1)) return; - state.memory[static_cast(index)] = static_cast(x); - - state.stack.pop_back(); - state.stack.pop_back(); + state.memory[static_cast(index)] = static_cast(value); } void op_sload(execution_state& state, instr_argument) noexcept @@ -478,10 +450,8 @@ void op_sstore(execution_state& state, instr_argument) noexcept evmc_bytes32 key; evmc_bytes32 value; - intx::be::store(key.bytes, state.item(0)); - intx::be::store(value.bytes, state.item(1)); - state.stack.pop_back(); - state.stack.pop_back(); + intx::be::store(key.bytes, state.stack.pop()); + intx::be::store(value.bytes, state.stack.pop()); auto status = state.host.set_storage(state.msg->destination, key, value); int cost = 0; switch (status) @@ -508,14 +478,13 @@ void op_sstore(execution_state& state, instr_argument) noexcept void op_jump(execution_state& state, instr_argument) noexcept { - const auto dst = state.item(0); + const auto dst = state.stack.pop(); auto pc = -1; if (std::numeric_limits::max() < dst || (pc = state.analysis->find_jumpdest(static_cast(dst))) < 0) return state.exit(EVMC_BAD_JUMP_DESTINATION); state.pc = static_cast(pc); - state.stack.pop_back(); } void op_jumpi(execution_state& state, instr_argument arg) noexcept @@ -523,12 +492,12 @@ void op_jumpi(execution_state& state, instr_argument arg) noexcept if (state.item(1) != 0) op_jump(state, arg); else - state.stack.pop_back(); + state.stack.pop(); // OPT: The pc must be the BEGINBLOCK (even in fallback case), // so we can execute it straight away. - state.stack.pop_back(); + state.stack.pop(); } void op_pc(execution_state& state, instr_argument arg) noexcept @@ -565,10 +534,10 @@ void op_extcodesize(execution_state& state, instr_argument) noexcept void op_extcodecopy(execution_state& state, instr_argument) noexcept { - auto addr_data = state.item(0); - auto mem_index = state.item(1); - auto input_index = state.item(2); - auto size = state.item(3); + const auto addr_data = state.stack.pop(); + const auto mem_index = state.stack.pop(); + const auto input_index = state.stack.pop(); + const auto size = state.stack.pop(); if (!check_memory(state, mem_index, size)) return; @@ -592,11 +561,6 @@ void op_extcodecopy(execution_state& state, instr_argument) noexcept auto num_bytes_copied = state.host.copy_code(addr, src, data, s); if (s - num_bytes_copied > 0) std::memset(&state.memory[dst + num_bytes_copied], 0, s - num_bytes_copied); - - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); } void op_returndatasize(execution_state& state, instr_argument) noexcept @@ -606,13 +570,9 @@ void op_returndatasize(execution_state& state, instr_argument) noexcept void op_returndatacopy(execution_state& state, instr_argument) noexcept { - auto mem_index = state.item(0); - auto input_index = state.item(1); - auto size = state.item(2); - - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); + const auto mem_index = state.stack.pop(); + const auto input_index = state.stack.pop(); + const auto size = state.stack.pop(); if (!check_memory(state, mem_index, size)) return; @@ -698,7 +658,7 @@ void op_push_full(execution_state& state, instr_argument arg) noexcept void op_pop(execution_state& state, instr_argument) noexcept { - state.stack.pop_back(); + state.stack.pop(); } void op_dup(execution_state& state, instr_argument arg) noexcept @@ -716,8 +676,8 @@ void op_log(execution_state& state, instr_argument arg) noexcept if (state.msg->flags & EVMC_STATIC) return state.exit(EVMC_STATIC_MODE_VIOLATION); - auto offset = state.item(0); - auto size = state.item(1); + const auto offset = state.stack.pop(); + const auto size = state.stack.pop(); if (!check_memory(state, offset, size)) return; @@ -729,14 +689,11 @@ void op_log(execution_state& state, instr_argument arg) noexcept if ((state.gas_left -= cost) < 0) state.exit(EVMC_OUT_OF_GAS); - state.stack.pop_back(); - state.stack.pop_back(); - std::array topics; for (auto i = 0; i < arg.p.number; ++i) { intx::be::store(topics[i].bytes, state.item(0)); - state.stack.pop_back(); + state.stack.pop(); } auto data = s != 0 ? &state.memory[o] : nullptr; @@ -790,12 +747,12 @@ void op_call(execution_state& state, instr_argument arg) noexcept auto output_offset = state.item(5); auto output_size = state.item(6); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); state.item(0) = 0; if (!check_memory(state, input_offset, input_size)) @@ -911,11 +868,11 @@ void op_delegatecall(execution_state& state, instr_argument arg) noexcept auto output_offset = state.item(4); auto output_size = state.item(5); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); state.item(0) = 0; if (!check_memory(state, input_offset, input_size)) @@ -983,11 +940,11 @@ void op_staticcall(execution_state& state, instr_argument arg) noexcept auto output_offset = state.item(4); auto output_size = state.item(5); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); state.item(0) = 0; if (!check_memory(state, input_offset, input_size)) @@ -1045,8 +1002,8 @@ void op_create(execution_state& state, instr_argument arg) noexcept auto init_code_offset = state.item(1); auto init_code_size = state.item(2); - state.stack.pop_back(); - state.stack.pop_back(); + state.stack.pop(); + state.stack.pop(); state.item(0) = 0; if (!check_memory(state, init_code_offset, init_code_size)) @@ -1106,9 +1063,9 @@ void op_create2(execution_state& state, instr_argument arg) noexcept auto init_code_size = state.item(2); auto salt = state.item(3); - state.stack.pop_back(); - state.stack.pop_back(); - state.stack.pop_back(); + state.stack.pop(); + state.stack.pop(); + state.stack.pop(); state.item(0) = 0; if (!check_memory(state, init_code_offset, init_code_size)) From d00ea73870fc5a5aa75acd3cbdde8fd07f2b5640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jul 2019 11:03:34 +0200 Subject: [PATCH 7/9] Add evm_stack::top() --- lib/evmone/analysis.hpp | 5 ++++ lib/evmone/instructions.cpp | 46 ++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index 515874baa7..0bd5ffce72 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -46,6 +46,8 @@ struct evm_stack /// The storage allocated for maximum possible number of items. /// This is also the pointer to the bottom item. + /// + /// OPT: The items are not 256-bit aligned, so access will cross a cache line. uint256 storage[limit]; /// Default constructor. Sets the top_item pointer to below the stack bottom. @@ -54,6 +56,9 @@ struct evm_stack /// The current number of items on the stack. int size() noexcept { return static_cast(top_item + 1 - storage); } + /// Returns the reference to the top item. + uint256& top() noexcept { return *top_item; } + /// Returns the reference to the stack item on given position from the stack top. /// TODO: Rename to get(), at() or operator[]. uint256& item(int index) noexcept { return *(top_item - index); } diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index 1436d6b78d..c19837e2a8 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -62,12 +62,12 @@ void op_stop(execution_state& state, instr_argument) noexcept void op_add(execution_state& state, instr_argument) noexcept { - state.item(0) += state.stack.pop(); + state.stack.top() += state.stack.pop(); } void op_mul(execution_state& state, instr_argument) noexcept { - state.item(0) *= state.stack.pop(); + state.stack.top() *= state.stack.pop(); } void op_sub(execution_state& state, instr_argument) noexcept @@ -109,7 +109,7 @@ void op_addmod(execution_state& state, instr_argument) noexcept using intx::uint512; const auto x = state.stack.pop(); const auto y = state.stack.pop(); - auto& m = state.item(0); + auto& m = state.stack.top(); m = m != 0 ? ((uint512{x} + uint512{y}) % uint512{m}).lo : 0; } @@ -119,7 +119,7 @@ void op_mulmod(execution_state& state, instr_argument) noexcept using intx::uint512; const auto x = state.stack.pop(); const auto y = state.stack.pop(); - auto& m = state.item(0); + auto& m = state.stack.top(); m = m != 0 ? ((uint512{x} * uint512{y}) % uint512{m}).lo : 0; } @@ -127,7 +127,7 @@ void op_mulmod(execution_state& state, instr_argument) noexcept void op_exp(execution_state& state, instr_argument) noexcept { const auto base = state.stack.pop(); - auto& exponent = state.item(0); + auto& exponent = state.stack.top(); const auto exponent_significant_bytes = intx::count_significant_words(exponent); const auto exponent_cost = state.rev >= EVMC_SPURIOUS_DRAGON ? 50 : 10; @@ -141,7 +141,7 @@ void op_exp(execution_state& state, instr_argument) noexcept void op_signextend(execution_state& state, instr_argument) noexcept { const auto ext = state.stack.pop(); - auto& x = state.item(0); + auto& x = state.stack.top(); if (ext < 31) { @@ -194,33 +194,33 @@ void op_eq(execution_state& state, instr_argument) noexcept void op_iszero(execution_state& state, instr_argument) noexcept { - state.item(0) = state.item(0) == 0; + state.stack.top() = state.stack.top() == 0; } void op_and(execution_state& state, instr_argument) noexcept { - state.item(0) &= state.stack.pop(); + state.stack.top() &= state.stack.pop(); } void op_or(execution_state& state, instr_argument) noexcept { - state.item(0) |= state.stack.pop(); + state.stack.top() |= state.stack.pop(); } void op_xor(execution_state& state, instr_argument) noexcept { - state.item(0) ^= state.stack.pop(); + state.stack.top() ^= state.stack.pop(); } void op_not(execution_state& state, instr_argument) noexcept { - state.item(0) = ~state.item(0); + state.stack.top() = ~state.stack.top(); } void op_byte(execution_state& state, instr_argument) noexcept { const auto n = state.stack.pop(); - auto& x = state.item(0); + auto& x = state.stack.top(); if (n > 31) x = 0; @@ -234,12 +234,12 @@ void op_byte(execution_state& state, instr_argument) noexcept void op_shl(execution_state& state, instr_argument) noexcept { - state.item(0) <<= state.stack.pop(); + state.stack.top() <<= state.stack.pop(); } void op_shr(execution_state& state, instr_argument) noexcept { - state.item(0) >>= state.stack.pop(); + state.stack.top() >>= state.stack.pop(); } void op_sar(execution_state& state, instr_argument arg) noexcept @@ -263,7 +263,7 @@ void op_sar(execution_state& state, instr_argument arg) noexcept void op_sha3(execution_state& state, instr_argument) noexcept { const auto index = state.stack.pop(); - auto& size = state.item(0); + auto& size = state.stack.top(); if (!check_memory(state, index, size)) return; @@ -291,7 +291,7 @@ void op_address(execution_state& state, instr_argument) noexcept void op_balance(execution_state& state, instr_argument) noexcept { - auto& x = state.item(0); + auto& x = state.stack.top(); uint8_t data[32]; intx::be::store(data, x); evmc_address addr; @@ -321,7 +321,7 @@ void op_callvalue(execution_state& state, instr_argument) noexcept void op_calldataload(execution_state& state, instr_argument) noexcept { - auto& index = state.item(0); + auto& index = state.stack.top(); if (state.msg->input_size < index) index = 0; @@ -404,7 +404,7 @@ void op_codecopy(execution_state& state, instr_argument) noexcept void op_mload(execution_state& state, instr_argument) noexcept { - auto& index = state.item(0); + auto& index = state.stack.top(); if (!check_memory(state, index, 32)) return; @@ -436,7 +436,7 @@ void op_mstore8(execution_state& state, instr_argument) noexcept void op_sload(execution_state& state, instr_argument) noexcept { - auto& x = state.item(0); + auto& x = state.stack.top(); evmc_bytes32 key; intx::be::store(key.bytes, x); x = intx::be::uint256(state.host.get_storage(state.msg->destination, key).bytes); @@ -524,7 +524,7 @@ void op_gasprice(execution_state& state, instr_argument) noexcept void op_extcodesize(execution_state& state, instr_argument) noexcept { - auto& x = state.item(0); + auto& x = state.stack.top(); uint8_t data[32]; intx::be::store(data, x); evmc_address addr; @@ -597,7 +597,7 @@ void op_returndatacopy(execution_state& state, instr_argument) noexcept void op_extcodehash(execution_state& state, instr_argument) noexcept { - auto& x = state.item(0); + auto& x = state.stack.top(); uint8_t data[32]; intx::be::store(data, x); evmc_address addr; @@ -607,7 +607,7 @@ void op_extcodehash(execution_state& state, instr_argument) noexcept void op_blockhash(execution_state& state, instr_argument) noexcept { - auto& number = state.item(0); + auto& number = state.stack.top(); auto upper_bound = state.host.get_tx_context().block_number; auto lower_bound = std::max(upper_bound - 256, decltype(upper_bound){0}); @@ -668,7 +668,7 @@ void op_dup(execution_state& state, instr_argument arg) noexcept void op_swap(execution_state& state, instr_argument arg) noexcept { - std::swap(state.item(0), state.item(arg.p.number)); + std::swap(state.stack.top(), state.item(arg.p.number)); } void op_log(execution_state& state, instr_argument arg) noexcept From 6fb04a20dd71c45ca7aa7e60da6217c2321c3a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jul 2019 11:13:27 +0200 Subject: [PATCH 8/9] Add evm_stack::operator[] for accessing items --- lib/evmone/analysis.hpp | 5 +- lib/evmone/instructions.cpp | 139 ++++++++++++++++++------------------ 2 files changed, 69 insertions(+), 75 deletions(-) diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index 0bd5ffce72..f04233f3d0 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -60,8 +60,7 @@ struct evm_stack uint256& top() noexcept { return *top_item; } /// Returns the reference to the stack item on given position from the stack top. - /// TODO: Rename to get(), at() or operator[]. - uint256& item(int index) noexcept { return *(top_item - index); } + uint256& operator[](int index) noexcept { return *(top_item - index); } /// Pushes an item on the stack. The stack limit is not checked. void push(const uint256& item) noexcept { *++top_item = item; } @@ -99,8 +98,6 @@ struct execution_state evmc_revision rev = {}; - uint256& item(int index) noexcept { return stack.item(index); } - /// Terminates the execution with the given status code. void exit(evmc_status_code status_code) noexcept { diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index c19837e2a8..f12390c1b6 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -72,35 +72,35 @@ void op_mul(execution_state& state, instr_argument) noexcept void op_sub(execution_state& state, instr_argument) noexcept { - state.item(1) = state.item(0) - state.item(1); + state.stack[1] = state.stack[0] - state.stack[1]; state.stack.pop(); } void op_div(execution_state& state, instr_argument) noexcept { - auto& v = state.item(1); - v = v != 0 ? state.item(0) / v : 0; + auto& v = state.stack[1]; + v = v != 0 ? state.stack[0] / v : 0; state.stack.pop(); } void op_sdiv(execution_state& state, instr_argument) noexcept { - auto& v = state.item(1); - v = v != 0 ? intx::sdivrem(state.item(0), v).quot : 0; + auto& v = state.stack[1]; + v = v != 0 ? intx::sdivrem(state.stack[0], v).quot : 0; state.stack.pop(); } void op_mod(execution_state& state, instr_argument) noexcept { - auto& v = state.item(1); - v = v != 0 ? state.item(0) % v : 0; + auto& v = state.stack[1]; + v = v != 0 ? state.stack[0] % v : 0; state.stack.pop(); } void op_smod(execution_state& state, instr_argument) noexcept { - auto& v = state.item(1); - v = v != 0 ? intx::sdivrem(state.item(0), v).rem : 0; + auto& v = state.stack[1]; + v = v != 0 ? intx::sdivrem(state.stack[0], v).rem : 0; state.stack.pop(); } @@ -156,39 +156,39 @@ void op_signextend(execution_state& state, instr_argument) noexcept void op_lt(execution_state& state, instr_argument) noexcept { // OPT: Have single function implementing all comparisons. - state.item(1) = state.item(0) < state.item(1); + state.stack[1] = state.stack[0] < state.stack[1]; state.stack.pop(); } void op_gt(execution_state& state, instr_argument) noexcept { - state.item(1) = state.item(1) < state.item(0); + state.stack[1] = state.stack[1] < state.stack[0]; state.stack.pop(); } void op_slt(execution_state& state, instr_argument) noexcept { - auto x = state.item(0); - auto y = state.item(1); + auto x = state.stack[0]; + auto y = state.stack[1]; auto x_neg = static_cast(x >> 255); auto y_neg = static_cast(y >> 255); - state.item(1) = (x_neg ^ y_neg) ? x_neg : x < y; + state.stack[1] = (x_neg ^ y_neg) ? x_neg : x < y; state.stack.pop(); } void op_sgt(execution_state& state, instr_argument) noexcept { - auto x = state.item(0); - auto y = state.item(1); + auto x = state.stack[0]; + auto y = state.stack[1]; auto x_neg = static_cast(x >> 255); auto y_neg = static_cast(y >> 255); - state.item(1) = (x_neg ^ y_neg) ? y_neg : y < x; + state.stack[1] = (x_neg ^ y_neg) ? y_neg : y < x; state.stack.pop(); } void op_eq(execution_state& state, instr_argument) noexcept { - state.item(1) = state.item(0) == state.item(1); + state.stack[1] = state.stack[0] == state.stack[1]; state.stack.pop(); } @@ -244,17 +244,17 @@ void op_shr(execution_state& state, instr_argument) noexcept void op_sar(execution_state& state, instr_argument arg) noexcept { - if ((state.item(1) & (intx::uint256{1} << 255)) == 0) + if ((state.stack[1] & (intx::uint256{1} << 255)) == 0) return op_shr(state, arg); constexpr auto allones = ~uint256{}; - if (state.item(0) >= 256) - state.item(1) = allones; + if (state.stack[0] >= 256) + state.stack[1] = allones; else { - const auto shift = static_cast(state.item(0)); - state.item(1) = (state.item(1) >> shift) | (allones << (256 - shift)); + const auto shift = static_cast(state.stack[0]); + state.stack[1] = (state.stack[1] >> shift) | (allones << (256 - shift)); } state.stack.pop(); @@ -489,7 +489,7 @@ void op_jump(execution_state& state, instr_argument) noexcept void op_jumpi(execution_state& state, instr_argument arg) noexcept { - if (state.item(1) != 0) + if (state.stack[1] != 0) op_jump(state, arg); else state.stack.pop(); @@ -663,12 +663,12 @@ void op_pop(execution_state& state, instr_argument) noexcept void op_dup(execution_state& state, instr_argument arg) noexcept { - state.stack.push(state.item(arg.p.number)); + state.stack.push(state.stack[arg.p.number]); } void op_swap(execution_state& state, instr_argument arg) noexcept { - std::swap(state.stack.top(), state.item(arg.p.number)); + std::swap(state.stack.top(), state.stack[arg.p.number]); } void op_log(execution_state& state, instr_argument arg) noexcept @@ -691,10 +691,7 @@ void op_log(execution_state& state, instr_argument arg) noexcept std::array topics; for (auto i = 0; i < arg.p.number; ++i) - { - intx::be::store(topics[i].bytes, state.item(0)); - state.stack.pop(); - } + intx::be::store(topics[i].bytes, state.stack.pop()); auto data = s != 0 ? &state.memory[o] : nullptr; state.host.emit_log( @@ -708,8 +705,8 @@ void op_invalid(execution_state& state, instr_argument) noexcept void op_return(execution_state& state, instr_argument) noexcept { - auto offset = state.item(0); - auto size = state.item(1); + auto offset = state.stack[0]; + auto size = state.stack[1]; if (!check_memory(state, offset, size)) return; @@ -721,8 +718,8 @@ void op_return(execution_state& state, instr_argument) noexcept void op_revert(execution_state& state, instr_argument) noexcept { - auto offset = state.item(0); - auto size = state.item(1); + auto offset = state.stack[0]; + auto size = state.stack[1]; if (!check_memory(state, offset, size)) return; @@ -734,18 +731,18 @@ void op_revert(execution_state& state, instr_argument) noexcept void op_call(execution_state& state, instr_argument arg) noexcept { - auto gas = state.item(0); + auto gas = state.stack[0]; uint8_t data[32]; - intx::be::store(data, state.item(1)); + intx::be::store(data, state.stack[1]); auto dst = evmc_address{}; std::memcpy(dst.bytes, &data[12], sizeof(dst)); - auto value = state.item(2); - auto input_offset = state.item(3); - auto input_size = state.item(4); - auto output_offset = state.item(5); - auto output_size = state.item(6); + auto value = state.stack[2]; + auto input_offset = state.stack[3]; + auto input_size = state.stack[4]; + auto output_offset = state.stack[5]; + auto output_size = state.stack[6]; state.stack.pop(); state.stack.pop(); @@ -753,7 +750,7 @@ void op_call(execution_state& state, instr_argument arg) noexcept state.stack.pop(); state.stack.pop(); state.stack.pop(); - state.item(0) = 0; + state.stack[0] = 0; if (!check_memory(state, input_offset, input_size)) return; @@ -840,7 +837,7 @@ void op_call(execution_state& state, instr_argument arg) noexcept state.return_data.assign(result.output_data, result.output_size); - state.item(0) = result.status_code == EVMC_SUCCESS; + state.stack[0] = result.status_code == EVMC_SUCCESS; if (auto copy_size = std::min(size_t(output_size), result.output_size); copy_size > 0) std::memcpy(&state.memory[size_t(output_offset)], result.output_data, copy_size); @@ -856,24 +853,24 @@ void op_call(execution_state& state, instr_argument arg) noexcept void op_delegatecall(execution_state& state, instr_argument arg) noexcept { - auto gas = state.item(0); + auto gas = state.stack[0]; uint8_t data[32]; - intx::be::store(data, state.item(1)); + intx::be::store(data, state.stack[1]); auto dst = evmc_address{}; std::memcpy(dst.bytes, &data[12], sizeof(dst)); - auto input_offset = state.item(2); - auto input_size = state.item(3); - auto output_offset = state.item(4); - auto output_size = state.item(5); + auto input_offset = state.stack[2]; + auto input_size = state.stack[3]; + auto output_offset = state.stack[4]; + auto output_size = state.stack[5]; state.stack.pop(); state.stack.pop(); state.stack.pop(); state.stack.pop(); state.stack.pop(); - state.item(0) = 0; + state.stack[0] = 0; if (!check_memory(state, input_offset, input_size)) return; @@ -915,7 +912,7 @@ void op_delegatecall(execution_state& state, instr_argument arg) noexcept auto result = state.host.call(msg); state.return_data.assign(result.output_data, result.output_size); - state.item(0) = result.status_code == EVMC_SUCCESS; + state.stack[0] = result.status_code == EVMC_SUCCESS; if (const auto copy_size = std::min(size_t(output_size), result.output_size); copy_size > 0) std::memcpy(&state.memory[size_t(output_offset)], result.output_data, copy_size); @@ -928,24 +925,24 @@ void op_delegatecall(execution_state& state, instr_argument arg) noexcept void op_staticcall(execution_state& state, instr_argument arg) noexcept { - auto gas = state.item(0); + auto gas = state.stack[0]; uint8_t data[32]; - intx::be::store(data, state.item(1)); + intx::be::store(data, state.stack[1]); auto dst = evmc_address{}; std::memcpy(dst.bytes, &data[12], sizeof(dst)); - auto input_offset = state.item(2); - auto input_size = state.item(3); - auto output_offset = state.item(4); - auto output_size = state.item(5); + auto input_offset = state.stack[2]; + auto input_size = state.stack[3]; + auto output_offset = state.stack[4]; + auto output_size = state.stack[5]; state.stack.pop(); state.stack.pop(); state.stack.pop(); state.stack.pop(); state.stack.pop(); - state.item(0) = 0; + state.stack[0] = 0; if (!check_memory(state, input_offset, input_size)) return; @@ -982,7 +979,7 @@ void op_staticcall(execution_state& state, instr_argument arg) noexcept auto result = state.host.call(msg); state.return_data.assign(result.output_data, result.output_size); - state.item(0) = result.status_code == EVMC_SUCCESS; + state.stack[0] = result.status_code == EVMC_SUCCESS; if (auto copy_size = std::min(size_t(output_size), result.output_size); copy_size > 0) std::memcpy(&state.memory[size_t(output_offset)], result.output_data, copy_size); @@ -998,13 +995,13 @@ void op_create(execution_state& state, instr_argument arg) noexcept if (state.msg->flags & EVMC_STATIC) return state.exit(EVMC_STATIC_MODE_VIOLATION); - auto endowment = state.item(0); - auto init_code_offset = state.item(1); - auto init_code_size = state.item(2); + auto endowment = state.stack[0]; + auto init_code_offset = state.stack[1]; + auto init_code_size = state.stack[2]; state.stack.pop(); state.stack.pop(); - state.item(0) = 0; + state.stack[0] = 0; if (!check_memory(state, init_code_offset, init_code_size)) return; @@ -1046,7 +1043,7 @@ void op_create(execution_state& state, instr_argument arg) noexcept { uint8_t data[32] = {}; std::memcpy(&data[12], &result.create_address, sizeof(result.create_address)); - state.item(0) = intx::be::uint256(data); + state.stack[0] = intx::be::uint256(data); } if ((state.gas_left -= msg.gas - result.gas_left) < 0) @@ -1058,15 +1055,15 @@ void op_create2(execution_state& state, instr_argument arg) noexcept if (state.msg->flags & EVMC_STATIC) return state.exit(EVMC_STATIC_MODE_VIOLATION); - auto endowment = state.item(0); - auto init_code_offset = state.item(1); - auto init_code_size = state.item(2); - auto salt = state.item(3); + auto endowment = state.stack[0]; + auto init_code_offset = state.stack[1]; + auto init_code_size = state.stack[2]; + auto salt = state.stack[3]; state.stack.pop(); state.stack.pop(); state.stack.pop(); - state.item(0) = 0; + state.stack[0] = 0; if (!check_memory(state, init_code_offset, init_code_size)) return; @@ -1111,7 +1108,7 @@ void op_create2(execution_state& state, instr_argument arg) noexcept { uint8_t data[32] = {}; std::memcpy(&data[12], &result.create_address, sizeof(result.create_address)); - state.item(0) = intx::be::uint256(data); + state.stack[0] = intx::be::uint256(data); } if ((state.gas_left -= msg.gas - result.gas_left) < 0) @@ -1129,7 +1126,7 @@ void op_selfdestruct(execution_state& state, instr_argument) noexcept return state.exit(EVMC_STATIC_MODE_VIOLATION); uint8_t data[32]; - intx::be::store(data, state.item(0)); + intx::be::store(data, state.stack[0]); evmc_address addr; std::memcpy(addr.bytes, &data[12], sizeof(addr)); From 7f1f3b719c9a000a6404a665a4ac0b337e86f7ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jul 2019 11:31:28 +0200 Subject: [PATCH 9/9] Align stack items to 256 bits --- lib/evmone/analysis.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/evmone/analysis.hpp b/lib/evmone/analysis.hpp index f04233f3d0..037ae013b1 100644 --- a/lib/evmone/analysis.hpp +++ b/lib/evmone/analysis.hpp @@ -46,9 +46,8 @@ struct evm_stack /// The storage allocated for maximum possible number of items. /// This is also the pointer to the bottom item. - /// - /// OPT: The items are not 256-bit aligned, so access will cross a cache line. - uint256 storage[limit]; + /// Items are aligned to 256 bits for better packing in cache lines. + alignas(sizeof(uint256)) uint256 storage[limit]; /// Default constructor. Sets the top_item pointer to below the stack bottom. [[clang::no_sanitize("bounds")]] evm_stack() noexcept : top_item{storage - 1} {}