Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EOF "1.0" #563

Merged
merged 7 commits into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/evmone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ if(CABLE_COMPILER_GNULIKE)
target_compile_options(
evmone PRIVATE
-fno-exceptions
$<$<CXX_COMPILER_ID:GNU>:-Wstack-usage=2500>
$<$<CXX_COMPILER_ID:GNU>:-Wstack-usage=2600>
gumb0 marked this conversation as resolved.
Show resolved Hide resolved
)
if(NOT SANITIZE MATCHES undefined)
# RTTI can be disabled except for UBSan which checks vptr integrity.
Expand Down
2 changes: 1 addition & 1 deletion lib/evmone/advanced_execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ evmc_result execute(evmc_vm* /*unused*/, const evmc_host_interface* host, evmc_h
if (rev >= EVMC_CANCUN)
{
const auto eof1_header = read_valid_eof1_header(container);
analysis = analyze(rev, {&container[eof1_header.code_begin()], eof1_header.code_size});
analysis = analyze(rev, eof1_header.get_code(container, 0));
}
else
// Skip analysis, because it will recognize 01 section id as OP_ADD and return
Expand Down
6 changes: 6 additions & 0 deletions lib/evmone/advanced_instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,12 @@ constexpr std::array<instruction_exec_fn, 256> instruction_implementations = [](
table[OP_CREATE2] = op_create<OP_CREATE2>;
table[OP_STATICCALL] = op_call<OP_STATICCALL>;

table[OP_RJUMP] = op_undefined;
table[OP_RJUMPI] = op_undefined;
table[OP_RJUMPV] = op_undefined;
table[OP_CALLF] = op_undefined;
table[OP_RETF] = op_undefined;

table[OP_DUPN] = op_undefined;
table[OP_SWAPN] = op_undefined;

Expand Down
31 changes: 24 additions & 7 deletions lib/evmone/baseline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,37 @@ CodeAnalysis analyze_legacy(bytes_view code)
return {pad_code(code), code.size(), analyze_jumpdests(code)};
}

CodeAnalysis analyze_eof1(bytes_view eof_container, const EOF1Header& header)
CodeAnalysis analyze_eof1(bytes_view container)
{
const auto executable_code = eof_container.substr(header.code_begin(), header.code_size);
return {executable_code, analyze_jumpdests(executable_code)};
const auto header = read_valid_eof1_header(container);

// Extract all code sections as single buffer reference.
axic marked this conversation as resolved.
Show resolved Hide resolved
// TODO: It would be much easier if header had code_sections_offset and data_section_offset
// with code_offsets[] being relative to code_sections_offset.
const auto code_sections_offset = header.code_offsets[0];
const auto code_sections_end = size_t{header.code_offsets.back()} + header.code_sizes.back();
const auto executable_code =
container.substr(code_sections_offset, code_sections_end - code_sections_offset);

// Code section offsets relative to the beginning of the first code section.
// Execution starts at position 0 (first code section).
// The implementation of CALLF uses these offsets.
CodeAnalysis::CodeOffsets relative_offsets;
relative_offsets.reserve(header.code_offsets.size());
for (const auto offset : header.code_offsets)
relative_offsets.push_back(offset - code_sections_offset);

// FIXME: Better way of getting EOF version.
const auto eof_version = container[2];
return CodeAnalysis{executable_code, {}, eof_version, relative_offsets};
}
} // namespace

CodeAnalysis analyze(evmc_revision rev, bytes_view code)
{
if (rev < EVMC_CANCUN || !is_eof_container(code))
return analyze_legacy(code);

const auto eof1_header = read_valid_eof1_header(code);
return analyze_eof1(code, eof1_header);
return analyze_eof1(code);
}

namespace
Expand Down Expand Up @@ -321,7 +338,7 @@ evmc_result execute(const VM& vm, ExecutionState& state, const CodeAnalysis& ana

const auto code = analysis.executable_code;

const auto& cost_table = get_baseline_cost_table(state.rev);
const auto& cost_table = get_baseline_cost_table(state.rev, analysis.eof_version);

auto* tracer = vm.get_tracer();
if (INTX_UNLIKELY(tracer != nullptr))
Expand Down
12 changes: 10 additions & 2 deletions lib/evmone/baseline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@ class CodeAnalysis
{
public:
using JumpdestMap = std::vector<bool>;
using CodeOffsets = std::vector<uint16_t>;

bytes_view executable_code; ///< Executable code section.
JumpdestMap jumpdest_map; ///< Map of valid jump destinations.
uint8_t eof_version = 0; ///< The EOF version, 0 means legacy code.
/// Offset of each code section relative to the beginning of the first code
/// section. We flatten the sections for cheap execution.
CodeOffsets code_offsets;

private:
/// Padded code for faster legacy code execution.
Expand All @@ -38,8 +43,11 @@ class CodeAnalysis
m_padded_code{std::move(padded_code)}
{}

CodeAnalysis(bytes_view code, JumpdestMap map)
: executable_code{code}, jumpdest_map{std::move(map)}
CodeAnalysis(bytes_view code, JumpdestMap map, uint8_t version, CodeOffsets offsets)
: executable_code{code},
jumpdest_map{std::move(map)},
eof_version{version},
code_offsets{std::move(offsets)}
{}
};
static_assert(std::is_move_constructible_v<CodeAnalysis>);
Expand Down
49 changes: 37 additions & 12 deletions lib/evmone/baseline_instruction_table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,46 @@

namespace evmone::baseline
{
const CostTable& get_baseline_cost_table(evmc_revision rev) noexcept
namespace
{
static constexpr auto cost_tables = []() noexcept {
std::array<CostTable, EVMC_MAX_REVISION + 1> tables{};
for (size_t r = EVMC_FRONTIER; r <= EVMC_MAX_REVISION; ++r)
constexpr auto common_cost_tables = []() noexcept {
std::array<CostTable, EVMC_MAX_REVISION + 1> 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)
{
auto& table = tables[r];
for (size_t i = 0; i < table.size(); ++i)
{
table[i] = instr::gas_costs[r][i]; // Include instr::undefined in the table.
}
table[i] = instr::gas_costs[r][i]; // Include instr::undefined in the table.
}
return tables;
}();
}
return tables;
}();

return cost_tables[rev];
constexpr auto legacy_cost_tables = []() noexcept {
auto tables = common_cost_tables;
tables[EVMC_CANCUN][OP_RJUMP] = instr::undefined;
tables[EVMC_CANCUN][OP_RJUMPI] = instr::undefined;
gumb0 marked this conversation as resolved.
Show resolved Hide resolved
tables[EVMC_CANCUN][OP_RJUMPV] = instr::undefined;
tables[EVMC_CANCUN][OP_CALLF] = instr::undefined;
tables[EVMC_CANCUN][OP_RETF] = instr::undefined;
return tables;
}();

constexpr auto eof_cost_tables = []() noexcept {
auto tables = common_cost_tables;
tables[EVMC_CANCUN][OP_JUMP] = instr::undefined;
tables[EVMC_CANCUN][OP_JUMPI] = instr::undefined;
tables[EVMC_CANCUN][OP_PC] = instr::undefined;
tables[EVMC_CANCUN][OP_CALLCODE] = instr::undefined;
tables[EVMC_CANCUN][OP_SELFDESTRUCT] = instr::undefined;
return tables;
}();

} // 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;
return tables[rev];
}
} // namespace evmone::baseline
4 changes: 3 additions & 1 deletion lib/evmone/baseline_instruction_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ namespace evmone::baseline
{
using CostTable = std::array<int16_t, 256>;

const CostTable& get_baseline_cost_table(evmc_revision rev) noexcept;
const CostTable& get_baseline_cost_table(evmc_revision rev, uint8_t eof_version) noexcept;

const CostTable& get_baseline_legacy_cost_table(evmc_revision rev) noexcept;
} // namespace evmone::baseline
Loading