Skip to content

Commit 969295c

Browse files
committed
Start code analysis
1 parent fc1d18a commit 969295c

12 files changed

Lines changed: 459 additions & 0 deletions

File tree

.clang-format

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
Language: Cpp
3+
BasedOnStyle: Chromium
4+
AccessModifierOffset: -4
5+
AlignAfterOpenBracket: DontAlign
6+
BinPackParameters: true
7+
BraceWrapping:
8+
AfterClass: true
9+
AfterControlStatement: true
10+
AfterEnum: true
11+
AfterFunction: true
12+
AfterNamespace: true
13+
AfterObjCDeclaration: true
14+
AfterStruct: true
15+
AfterUnion: true
16+
BeforeCatch: true
17+
BeforeElse: true
18+
SplitEmptyFunction: false
19+
BreakBeforeBraces: Custom
20+
BreakBeforeTernaryOperators: false
21+
ColumnLimit: 100
22+
ConstructorInitializerIndentWidth: 2
23+
IncludeCategories:
24+
- Regex: '^".*'
25+
Priority: 1
26+
- Regex: '^<boost.*'
27+
Priority: 98
28+
- Regex: '^<.*\.(h|hpp)>'
29+
Priority: 2
30+
- Regex: '^<.*'
31+
Priority: 99
32+
- Regex: '.*'
33+
Priority: 4
34+
IncludeIsMainRegex: '(Test)?$'
35+
IndentCaseLabels: false
36+
IndentWidth: 4
37+
MaxEmptyLinesToKeep: 2
38+
PenaltyBreakAssignment: 1
39+
PenaltyBreakComment: 50
40+
TabWidth: 4
41+
...

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/build
2+
/cmake-build-*
3+
/.idea

CMakeLists.txt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# evmone: Ethereum Virtual Machine
2+
# Copyright 2018 Pawel Bylica.
3+
# Licensed under the Apache License, Version 2.0.
4+
5+
cmake_minimum_required(VERSION 3.5)
6+
7+
option(EVMONE_TESTING "Build tests and test tools" OFF)
8+
9+
include(cmake/cable/bootstrap.cmake)
10+
include(CableBuildType)
11+
include(CableCompilerSettings)
12+
include(CableToolchains)
13+
include(CMakePackageConfigHelpers)
14+
include(GNUInstallDirs)
15+
16+
cable_configure_toolchain(DEFAULT cxx17-pic)
17+
18+
if(EVMONE_TESTING)
19+
include(HunterConfig)
20+
endif()
21+
22+
project(evmone)
23+
set(PROJECT_VERSION 0.1.0-dev)
24+
25+
cable_set_build_type(DEFAULT Release CONFIGURATION_TYPES Debug Release)
26+
cable_configure_compiler()
27+
28+
add_subdirectory(evmc)
29+
add_subdirectory(lib)
30+
31+
if(EVMONE_TESTING)
32+
enable_testing()
33+
add_subdirectory(test)
34+
endif()
35+

cmake/HunterConfig.cmake

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# evmone: Fast Ethereum Virtual Machine implementation
2+
# Copyright 2018 Pawel Bylica.
3+
# Licensed under the Apache License, Version 2.0.
4+
5+
set(HUNTER_CONFIGURATION_TYPES Release CACHE STRING "Build type of Hunter packages")
6+
7+
include(HunterGate)
8+
9+
HunterGate(
10+
URL "https://github.com/ruslo/hunter/archive/v0.23.64.tar.gz"
11+
SHA1 "a5f3c4999e03173d28b8469c4da4545dea740a41"
12+
)

cmake/toolchains/cxx17-pic.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
set(CMAKE_CXX_STANDARD 17)
2+
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
3+
set(CMAKE_CXX_EXTENSIONS OFF)
4+
5+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

lib/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# evmone: Fast Ethereum Virtual Machine implementation
2+
# Copyright 2018 Pawel Bylica.
3+
# Licensed under the Apache License, Version 2.0.
4+
5+
add_subdirectory(evmone)

lib/evmone/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# evmone: Fast Ethereum Virtual Machine implementation
2+
# Copyright 2018 Pawel Bylica.
3+
# Licensed under the Apache License, Version 2.0.
4+
5+
add_library(evmone analysis.cpp)
6+
target_link_libraries(evmone PRIVATE evmc::instructions)

lib/evmone/analysis.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// evmone: Fast Ethereum Virtual Machine implementation
2+
// Copyright 2018 Pawel Bylica.
3+
// Licensed under the Apache License, Version 2.0.
4+
5+
#include "analysis.hpp"
6+
7+
#include <evmc/instructions.h>
8+
9+
namespace evmone
10+
{
11+
namespace
12+
{
13+
bool is_terminator(uint8_t c) noexcept
14+
{
15+
return c == OP_JUMP || c == OP_JUMPI || c == OP_STOP || c == OP_RETURN || c == OP_REVERT ||
16+
c == OP_SELFDESTRUCT;
17+
}
18+
}
19+
20+
int code_analysis::find_jumpdest(int offset) noexcept
21+
{
22+
// TODO: Replace with lower_bound().
23+
for (const auto& d : jumpdest_map)
24+
{
25+
if (d.first == offset)
26+
return d.second;
27+
}
28+
return -1;
29+
}
30+
31+
code_analysis analyze(const exec_fn_table& fns, const uint8_t* code, size_t code_size) noexcept
32+
{
33+
code_analysis analysis;
34+
analysis.instrs.reserve(code_size + 1);
35+
36+
auto* instr_table = evmc_get_instruction_metrics_table(EVMC_BYZANTIUM);
37+
38+
block_info* block = nullptr;
39+
int instr_index = 0;
40+
for (size_t i = 0; i < code_size; ++i, ++instr_index)
41+
{
42+
const auto c = code[i];
43+
auto& instr = analysis.instrs.emplace_back(fns[c]);
44+
45+
const bool jumpdest = c == OP_JUMPDEST;
46+
if (!block || jumpdest)
47+
{
48+
// Create new block.
49+
block = &analysis.blocks.emplace_back();
50+
instr.block_index = static_cast<int>(analysis.blocks.size() - 1);
51+
52+
if (jumpdest)
53+
analysis.jumpdest_map.emplace_back(static_cast<int>(i), instr_index);
54+
}
55+
56+
auto metrics = instr_table[c];
57+
block->gas_cost += metrics.gas_cost;
58+
auto stack_req = metrics.num_stack_arguments - block->stack_diff;
59+
block->stack_diff += (metrics.num_stack_returned_items - metrics.num_stack_arguments);
60+
block->stack_req = std::max(block->stack_req, stack_req);
61+
block->stack_max = std::max(block->stack_max, block->stack_diff);
62+
63+
// Skip PUSH data.
64+
if (c >= OP_PUSH1 && c <= OP_PUSH32)
65+
{
66+
++i;
67+
auto push_size = size_t(c - OP_PUSH1 + 1);
68+
analysis.extra.emplace_back();
69+
auto& extra = analysis.extra.back();
70+
71+
auto leading_zeros = 32 - push_size;
72+
for (auto& b : extra.bytes)
73+
b = 0;
74+
for (size_t j = 0; j < push_size && (i + j) < code_size; ++j)
75+
extra.bytes[leading_zeros + j] = code[i + j];
76+
instr.extra_data_index = static_cast<int>(analysis.extra.size() - 1);
77+
i += push_size - 1;
78+
}
79+
else if (is_terminator(c))
80+
block = nullptr;
81+
}
82+
83+
// Not terminated block.
84+
if (block)
85+
analysis.instrs.emplace_back(nullptr);
86+
87+
return analysis;
88+
}
89+
90+
} // namespace evmone

lib/evmone/analysis.hpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// evmone: Fast Ethereum Virtual Machine implementation
2+
// Copyright 2018 Pawel Bylica.
3+
// Licensed under the Apache License, Version 2.0.
4+
5+
#include <array>
6+
#include <cstdint>
7+
#include <vector>
8+
9+
namespace evmone
10+
{
11+
using exec_fn = void (*)();
12+
13+
using exec_fn_table = std::array<exec_fn, 256>;
14+
15+
struct instr_info
16+
{
17+
exec_fn fn = nullptr;
18+
int extra_data_index = -1;
19+
int block_index = -1;
20+
21+
explicit constexpr instr_info(exec_fn fn) noexcept : fn{fn} {};
22+
};
23+
24+
struct block_info
25+
{
26+
int64_t gas_cost = 0;
27+
int stack_req = 0;
28+
int stack_max = 0;
29+
int stack_diff = 0;
30+
};
31+
32+
struct extra_data
33+
{
34+
uint8_t bytes[32];
35+
};
36+
37+
struct code_analysis
38+
{
39+
std::vector<instr_info> instrs;
40+
std::vector<block_info> blocks;
41+
std::vector<extra_data> extra;
42+
std::vector<std::pair<int, int>> jumpdest_map;
43+
44+
int find_jumpdest(int offset) noexcept;
45+
};
46+
47+
code_analysis analyze(const exec_fn_table& fns, const uint8_t* code, size_t code_size) noexcept;
48+
49+
} // namespace evmone

test/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# evmone: Fast Ethereum Virtual Machine implementation
2+
# Copyright 2018 Pawel Bylica.
3+
# Licensed under the Apache License, Version 2.0.
4+
5+
set(evmone_private_include_dir ${PROJECT_SOURCE_DIR}/lib)
6+
7+
add_subdirectory(unittests)

0 commit comments

Comments
 (0)