Skip to content

Commit

Permalink
eof: Serve data section from CodeAnalysis
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed Sep 12, 2024
1 parent ab3ab50 commit 3016caf
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 39 deletions.
13 changes: 6 additions & 7 deletions lib/evmone/advanced_analysis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,9 @@ struct AdvancedExecutionState : ExecutionState
AdvancedExecutionState() noexcept = default;

AdvancedExecutionState(const evmc_message& message, evmc_revision revision,
const evmc_host_interface& host_interface, evmc_host_context* host_ctx, bytes_view _code,
bytes_view _data) noexcept
: ExecutionState{message, revision, host_interface, host_ctx, _code, _data},
gas_left{message.gas}
const evmc_host_interface& host_interface, evmc_host_context* host_ctx,
bytes_view _code) noexcept
: ExecutionState{message, revision, host_interface, host_ctx, _code}, gas_left{message.gas}
{}

/// Computes the current EVM stack height.
Expand All @@ -72,10 +71,10 @@ struct AdvancedExecutionState : ExecutionState

/// Resets the contents of the execution_state so that it could be reused.
void reset(const evmc_message& message, evmc_revision revision,
const evmc_host_interface& host_interface, evmc_host_context* host_ctx, bytes_view _code,
bytes_view _data) noexcept
const evmc_host_interface& host_interface, evmc_host_context* host_ctx,
bytes_view _code) noexcept
{
ExecutionState::reset(message, revision, host_interface, host_ctx, _code, _data);
ExecutionState::reset(message, revision, host_interface, host_ctx, _code);
gas_left = message.gas;
stack = stack_space.bottom();
analysis.advanced = nullptr; // For consistency with previous behavior.
Expand Down
3 changes: 1 addition & 2 deletions lib/evmone/advanced_execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ evmc_result execute(evmc_vm* /*unused*/, const evmc_host_interface* host, evmc_h
}
else
analysis = analyze(rev, container);
auto state =
std::make_unique<AdvancedExecutionState>(*msg, rev, *host, ctx, container, bytes_view{});
auto state = std::make_unique<AdvancedExecutionState>(*msg, rev, *host, ctx, container);
return execute(*state, analysis);
}
} // namespace evmone::advanced
3 changes: 3 additions & 0 deletions lib/evmone/baseline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class CodeAnalysis
/// Reference to the EOF header.
[[nodiscard]] const EOF1Header& eof_header() const noexcept { return m_eof_header; }

/// Reference to the EOF data section. May be empty.
[[nodiscard]] bytes_view eof_data() const noexcept { return m_eof_header.get_data(m_raw_code); }

/// Check if given position is valid jump destination. Use only for legacy code.
[[nodiscard]] bool check_jumpdest(uint64_t position) const noexcept
{
Expand Down
3 changes: 1 addition & 2 deletions lib/evmone/baseline_execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,7 @@ evmc_result execute(evmc_vm* c_vm, const evmc_host_interface* host, evmc_host_co
}

const auto code_analysis = analyze(container, eof_enabled);
const auto data = code_analysis.eof_header().get_data(container);
auto state = std::make_unique<ExecutionState>(*msg, rev, *host, ctx, container, data);
auto state = std::make_unique<ExecutionState>(*msg, rev, *host, ctx, container);
return execute(*vm, msg->gas, *state, code_analysis);
}
} // namespace evmone::baseline
18 changes: 5 additions & 13 deletions lib/evmone/execution_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,6 @@ class ExecutionState
/// For EOF-formatted code this is a reference to entire container.
bytes_view original_code;

/// Reference to the EOF data section. May be empty.
bytes_view data;

evmc_status_code status = EVMC_SUCCESS;
size_t output_offset = 0;
size_t output_size = 0;
Expand Down Expand Up @@ -195,19 +192,15 @@ class ExecutionState
ExecutionState() noexcept = default;

ExecutionState(const evmc_message& message, evmc_revision revision,
const evmc_host_interface& host_interface, evmc_host_context* host_ctx, bytes_view _code,
bytes_view _data) noexcept
: msg{&message},
host{host_interface, host_ctx},
rev{revision},
original_code{_code},
data{_data}
const evmc_host_interface& host_interface, evmc_host_context* host_ctx,
bytes_view _code) noexcept
: msg{&message}, host{host_interface, host_ctx}, rev{revision}, original_code{_code}
{}

/// Resets the contents of the ExecutionState so that it could be reused.
void reset(const evmc_message& message, evmc_revision revision,
const evmc_host_interface& host_interface, evmc_host_context* host_ctx, bytes_view _code,
bytes_view _data) noexcept
const evmc_host_interface& host_interface, evmc_host_context* host_ctx,
bytes_view _code) noexcept
{
gas_refund = 0;
memory.clear();
Expand All @@ -216,7 +209,6 @@ class ExecutionState
rev = revision;
return_data.clear();
original_code = _code;
data = _data;
status = EVMC_SUCCESS;
output_offset = 0;
output_size = 0;
Expand Down
23 changes: 12 additions & 11 deletions lib/evmone/instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -985,38 +985,40 @@ inline Result mcopy(StackTop stack, int64_t gas_left, ExecutionState& state) noe

inline void dataload(StackTop stack, ExecutionState& state) noexcept
{
const auto data = state.analysis.baseline->eof_data();
auto& index = stack.top();

if (state.data.size() < index)
if (data.size() < index)
index = 0;
else
{
const auto begin = static_cast<size_t>(index);
const auto end = std::min(begin + 32, state.data.size());
const auto end = std::min(begin + 32, data.size());

uint8_t data[32] = {};
uint8_t d[32] = {};
for (size_t i = 0; i < (end - begin); ++i)
data[i] = state.data[begin + i];
d[i] = data[begin + i];

index = intx::be::unsafe::load<uint256>(data);
index = intx::be::unsafe::load<uint256>(d);
}
}

inline void datasize(StackTop stack, ExecutionState& state) noexcept
{
stack.push(state.data.size());
stack.push(state.analysis.baseline->eof_data().size());
}

inline code_iterator dataloadn(StackTop stack, ExecutionState& state, code_iterator pos) noexcept
{
const auto index = read_uint16_be(&pos[1]);

stack.push(intx::be::unsafe::load<uint256>(&state.data[index]));
stack.push(intx::be::unsafe::load<uint256>(&state.analysis.baseline->eof_data()[index]));
return pos + 3;
}

inline Result datacopy(StackTop stack, int64_t gas_left, ExecutionState& state) noexcept
{
const auto data = state.analysis.baseline->eof_data();
const auto& mem_index = stack.pop();
const auto& data_index = stack.pop();
const auto& size = stack.pop();
Expand All @@ -1026,16 +1028,15 @@ inline Result datacopy(StackTop stack, int64_t gas_left, ExecutionState& state)

const auto dst = static_cast<size_t>(mem_index);
// TODO why?
const auto src =
state.data.size() < data_index ? state.data.size() : static_cast<size_t>(data_index);
const auto src = data.size() < data_index ? data.size() : static_cast<size_t>(data_index);
const auto s = static_cast<size_t>(size);
const auto copy_size = std::min(s, state.data.size() - src);
const auto copy_size = std::min(s, data.size() - src);

if (const auto cost = copy_cost(s); (gas_left -= cost) < 0)
return {EVMC_OUT_OF_GAS, gas_left};

if (copy_size > 0)
std::memcpy(&state.memory[dst], &state.data[src], copy_size);
std::memcpy(&state.memory[dst], &data[src], copy_size);

if (s - copy_size > 0)
std::memset(&state.memory[dst + copy_size], 0, s - copy_size);
Expand Down
4 changes: 2 additions & 2 deletions test/bench/helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ inline evmc::Result advanced_execute(evmc::VM& /*vm*/, advanced::AdvancedExecuti
const advanced::AdvancedCodeAnalysis& analysis, const evmc_message& msg, evmc_revision rev,
evmc::Host& host, bytes_view code)
{
exec_state.reset(msg, rev, host.get_interface(), host.to_context(), code, {});
exec_state.reset(msg, rev, host.get_interface(), host.to_context(), code);

Check warning on line 58 in test/bench/helpers.hpp

View check run for this annotation

Codecov / codecov/patch

test/bench/helpers.hpp#L58

Added line #L58 was not covered by tests
return evmc::Result{execute(exec_state, analysis)};
}

Expand All @@ -64,7 +64,7 @@ inline evmc::Result baseline_execute(evmc::VM& c_vm, ExecutionState& exec_state,
evmc::Host& host, bytes_view code)
{
const auto& vm = *static_cast<evmone::VM*>(c_vm.get_raw_pointer());
exec_state.reset(msg, rev, host.get_interface(), host.to_context(), code, {});
exec_state.reset(msg, rev, host.get_interface(), host.to_context(), code);

Check warning on line 67 in test/bench/helpers.hpp

View check run for this annotation

Codecov / codecov/patch

test/bench/helpers.hpp#L67

Added line #L67 was not covered by tests
return evmc::Result{baseline::execute(vm, msg.gas, exec_state, analysis)};
}

Expand Down
4 changes: 2 additions & 2 deletions test/unittests/execution_state_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ TEST(execution_state, construct)
const evmc_host_interface host_interface{};
const uint8_t code[]{0x0f};
const evmone::ExecutionState st{
msg, EVMC_MAX_REVISION, host_interface, nullptr, {code, std::size(code)}, {}};
msg, EVMC_MAX_REVISION, host_interface, nullptr, {code, std::size(code)}};

EXPECT_EQ(st.memory.size(), 0);
EXPECT_EQ(st.msg, &msg);
Expand Down Expand Up @@ -107,7 +107,7 @@ TEST(execution_state, reset_advanced)
const evmc_host_interface host_interface2{};
const uint8_t code2[]{0x80, 0x81};

st.reset(msg2, EVMC_HOMESTEAD, host_interface2, nullptr, {code2, std::size(code2)}, {});
st.reset(msg2, EVMC_HOMESTEAD, host_interface2, nullptr, {code2, std::size(code2)});

// TODO: We are not able to test HostContext with current API. It may require an execution
// test.
Expand Down

0 comments on commit 3016caf

Please sign in to comment.