Skip to content

Commit fd1d149

Browse files
authored
baseline: VM-level execution states (#1005)
This adds an array of `ExecutionState` objects to the `VM` instance. They are used internally in the Baseline interpreter instead of passing one via API. This removes the need of maintaining object pool for execution states. However, this also makes the `VM` non-thread safe, but it is fine for current users. We can improve on this in the future by spiting the the VM into two parts: non-thread safe opaque execution context and a thread-safe VM with user configuration.
2 parents 1358b17 + 112ff3c commit fd1d149

5 files changed

Lines changed: 38 additions & 17 deletions

File tree

lib/evmone/baseline.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ EVMC_EXPORT CodeAnalysis analyze(bytes_view code, bool eof_enabled);
8080
evmc_result execute(evmc_vm* vm, const evmc_host_interface* host, evmc_host_context* ctx,
8181
evmc_revision rev, const evmc_message* msg, const uint8_t* code, size_t code_size) noexcept;
8282

83-
/// Executes in Baseline interpreter on the given external and initialized state.
84-
EVMC_EXPORT evmc_result execute(
85-
const VM&, int64_t gas_limit, ExecutionState& state, const CodeAnalysis& analysis) noexcept;
83+
/// Executes in Baseline interpreter with the pre-processed code.
84+
EVMC_EXPORT evmc_result execute(VM&, const evmc_host_interface& host, evmc_host_context* ctx,
85+
evmc_revision rev, const evmc_message& msg, const CodeAnalysis& analysis) noexcept;
8686

8787
} // namespace baseline
8888
} // namespace evmone

lib/evmone/baseline_execution.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,16 @@ int64_t dispatch_cgoto(
287287
#endif
288288
} // namespace
289289

290-
evmc_result execute(
291-
const VM& vm, int64_t gas, ExecutionState& state, const CodeAnalysis& analysis) noexcept
290+
evmc_result execute(VM& vm, const evmc_host_interface& host, evmc_host_context* ctx,
291+
evmc_revision rev, const evmc_message& msg, const CodeAnalysis& analysis) noexcept
292292
{
293-
state.analysis.baseline = &analysis; // Assign code analysis for instruction implementations.
294-
295293
const auto code = analysis.executable_code();
294+
auto gas = msg.gas;
295+
296+
auto& state = vm.get_execution_state(static_cast<size_t>(msg.depth));
297+
state.reset(msg, rev, host, ctx, analysis.raw_code());
298+
299+
state.analysis.baseline = &analysis; // Assign code analysis for instruction implementations.
296300

297301
const auto& cost_table = get_baseline_cost_table(state.rev, analysis.eof_header().version);
298302

@@ -349,7 +353,6 @@ evmc_result execute(evmc_vm* c_vm, const evmc_host_interface* host, evmc_host_co
349353
}
350354

351355
const auto code_analysis = analyze(container, eof_enabled);
352-
auto state = std::make_unique<ExecutionState>(*msg, rev, *host, ctx, container);
353-
return execute(*vm, msg->gas, *state, code_analysis);
356+
return execute(*vm, *host, ctx, rev, *msg, code_analysis);
354357
}
355358
} // namespace evmone::baseline

lib/evmone/vm.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ evmc_set_option_result set_option(evmc_vm* c_vm, char const* c_name, char const*
7272
} // namespace
7373

7474

75-
inline constexpr VM::VM() noexcept
75+
VM::VM() noexcept
7676
: evmc_vm{
7777
EVMC_ABI_VERSION,
7878
"evmone",
@@ -82,7 +82,20 @@ inline constexpr VM::VM() noexcept
8282
evmone::get_capabilities,
8383
evmone::set_option,
8484
}
85-
{}
85+
{
86+
m_execution_states.reserve(1025);
87+
}
88+
89+
ExecutionState& VM::get_execution_state(size_t depth) noexcept
90+
{
91+
// Vector already has the capacity for all possible depths,
92+
// so reallocation never happens (therefore: noexcept).
93+
// The ExecutionStates are lazily created because they pre-allocate EVM memory and stack.
94+
assert(depth < m_execution_states.capacity());
95+
if (m_execution_states.size() <= depth)
96+
m_execution_states.resize(depth + 1);
97+
return m_execution_states[depth];
98+
}
8699

87100
} // namespace evmone
88101

lib/evmone/vm.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
// SPDX-License-Identifier: Apache-2.0
44
#pragma once
55

6+
#include "execution_state.hpp"
67
#include "tracing.hpp"
78
#include <evmc/evmc.h>
9+
#include <vector>
810

911
#if defined(_MSC_VER) && !defined(__clang__)
1012
#define EVMONE_CGOTO_SUPPORTED 0
@@ -22,10 +24,13 @@ class VM : public evmc_vm
2224
bool validate_eof = false;
2325

2426
private:
27+
std::vector<ExecutionState> m_execution_states;
2528
std::unique_ptr<Tracer> m_first_tracer;
2629

2730
public:
28-
inline constexpr VM() noexcept;
31+
VM() noexcept;
32+
33+
[[nodiscard]] ExecutionState& get_execution_state(size_t depth) noexcept;
2934

3035
void add_tracer(std::unique_ptr<Tracer> tracer) noexcept
3136
{

test/bench/helpers.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ inline evmc::Result advanced_execute(evmc::VM& /*vm*/, advanced::AdvancedExecuti
5959
return evmc::Result{execute(exec_state, analysis)};
6060
}
6161

62-
inline evmc::Result baseline_execute(evmc::VM& c_vm, ExecutionState& exec_state,
62+
inline evmc::Result baseline_execute(evmc::VM& c_vm, [[maybe_unused]] ExecutionState& exec_state,
6363
const baseline::CodeAnalysis& analysis, const evmc_message& msg, evmc_revision rev,
64-
evmc::Host& host, bytes_view code)
64+
evmc::Host& host, [[maybe_unused]] bytes_view code)
6565
{
66-
const auto& vm = *static_cast<evmone::VM*>(c_vm.get_raw_pointer());
67-
exec_state.reset(msg, rev, host.get_interface(), host.to_context(), code);
68-
return evmc::Result{baseline::execute(vm, msg.gas, exec_state, analysis)};
66+
auto& vm = *static_cast<evmone::VM*>(c_vm.get_raw_pointer());
67+
return evmc::Result{
68+
baseline::execute(vm, host.get_interface(), host.to_context(), rev, msg, analysis)};
6969
}
7070

7171
inline evmc::Result evmc_execute(evmc::VM& vm, FakeExecutionState& /*exec_state*/,

0 commit comments

Comments
 (0)