Fabcoin Core  0.16.2
P2P Digital Currency
JIT.cpp
Go to the documentation of this file.
1 #include "JIT.h"
2 
3 #include <mutex>
4 
6 #include <llvm/IR/Module.h>
7 #include <llvm/ADT/StringSwitch.h>
8 #include <llvm/ADT/Triple.h>
9 #include <llvm/ExecutionEngine/MCJIT.h>
10 #include <llvm/ExecutionEngine/SectionMemoryManager.h>
11 #include <llvm/Support/TargetSelect.h>
12 #include <llvm/Support/Host.h>
13 #include <llvm/Support/CommandLine.h>
14 #include <llvm/Support/ManagedStatic.h>
16 
17 #include "Compiler.h"
18 #include "Optimizer.h"
19 #include "Cache.h"
20 #include "ExecStats.h"
21 #include "Utils.h"
22 #include "BuildInfo.gen.h"
23 
24 
25 static_assert(sizeof(evm_uint256be) == 32, "evm_uint256be is too big");
26 static_assert(sizeof(evm_uint160be) == 20, "evm_uint160be is too big");
27 static_assert(sizeof(evm_result) <= 64, "evm_result does not fit cache line");
28 
29 // Check enums match int size.
30 // On GCC/clang the underlying type should be unsigned int, on MSVC int
31 static_assert(sizeof(evm_query_key) == sizeof(int), "Enum `evm_query_key` is not the size of int");
32 static_assert(sizeof(evm_update_key) == sizeof(int), "Enum `evm_update_key` is not the size of int");
33 static_assert(sizeof(evm_call_kind) == sizeof(int), "Enum `evm_call_kind` is not the size of int");
34 static_assert(sizeof(evm_mode) == sizeof(int), "Enum `evm_mode` is not the size of int");
35 
36 
37 namespace dev
38 {
39 namespace evmjit
40 {
41 using namespace eth::jit;
42 
43 namespace
44 {
45 using ExecFunc = ReturnCode(*)(ExecutionContext*);
46 
47 char modeToChar(evm_mode mode)
48 {
49  switch (mode)
50  {
51  case EVM_FRONTIER: return 'F';
52  case EVM_HOMESTEAD: return 'H';
53  case EVM_ANTI_DOS: return 'A';
54  case EVM_CLEARING: return 'C';
55  }
56  LLVM_BUILTIN_UNREACHABLE;
57 }
58 
60 std::string makeCodeId(evm_uint256be codeHash, evm_mode mode)
61 {
62  static const auto hexChars = "0123456789abcdef";
63  std::string str;
64  str.reserve(sizeof(codeHash) * 2 + 1);
65  for (auto b: codeHash.bytes)
66  {
67  str.push_back(hexChars[b & 0xf]);
68  str.push_back(hexChars[b >> 4]);
69  }
70  str.push_back(modeToChar(mode));
71  return str;
72 }
73 
74 void printVersion()
75 {
76  std::cout << "Ethereum EVM JIT Compiler (http://github.com/ethereum/evmjit):\n"
77  << " EVMJIT version " << EVMJIT_VERSION << "\n"
78 #ifdef NDEBUG
79  << " Optimized build, "
80 #else
81  << " DEBUG build, "
82 #endif
83  << __DATE__ << " (" << __TIME__ << ")\n"
84  << std::endl;
85 }
86 
87 namespace cl = llvm::cl;
88 cl::opt<bool> g_optimize{"O", cl::desc{"Optimize"}};
89 cl::opt<CacheMode> g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"},
90  cl::values(
91  clEnumValN(CacheMode::off, "0", "Disabled"),
92  clEnumValN(CacheMode::on, "1", "Enabled"),
93  clEnumValN(CacheMode::read, "r", "Read only. No new objects are added to cache."),
94  clEnumValN(CacheMode::write, "w", "Write only. No objects are loaded from cache."),
95  clEnumValN(CacheMode::clear, "c", "Clear the cache storage. Cache is disabled."),
96  clEnumValN(CacheMode::preload, "p", "Preload all cached objects."),
97  clEnumValEnd)};
98 cl::opt<bool> g_stats{"st", cl::desc{"Statistics"}};
99 cl::opt<bool> g_dump{"dump", cl::desc{"Dump LLVM IR module"}};
100 
101 void parseOptions()
102 {
103  static llvm::llvm_shutdown_obj shutdownObj{};
104  cl::AddExtraVersionPrinter(printVersion);
105  cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler");
106 }
107 
108 class JITImpl: public evm_instance
109 {
110  std::unique_ptr<llvm::ExecutionEngine> m_engine;
111  mutable std::mutex x_codeMap;
112  std::unordered_map<std::string, ExecFunc> m_codeMap;
113 
114  static llvm::LLVMContext& getLLVMContext()
115  {
116  // TODO: This probably should be thread_local, but for now that causes
117  // a crash when MCJIT is destroyed.
118  static llvm::LLVMContext llvmContext;
119  return llvmContext;
120  }
121 
122 public:
123  static JITImpl& instance()
124  {
125  // We need to keep this a singleton.
126  // so we only call changeVersion on it.
127  static JITImpl s_instance;
128  return s_instance;
129  }
130 
131  JITImpl();
132 
133  llvm::ExecutionEngine& engine() { return *m_engine; }
134 
135  ExecFunc getExecFunc(std::string const& _codeIdentifier) const;
136  void mapExecFunc(std::string const& _codeIdentifier, ExecFunc _funcAddr);
137 
138  ExecFunc compile(evm_mode _mode, byte const* _code, uint64_t _codeSize, std::string const& _codeIdentifier);
139 
142  evm_call_fn callFn = nullptr;
143 };
144 
145 
146 class SymbolResolver : public llvm::SectionMemoryManager
147 {
148  llvm::RuntimeDyld::SymbolInfo findSymbol(std::string const& _name) override
149  {
150  auto& jit = JITImpl::instance();
151  auto addr = llvm::StringSwitch<uint64_t>(_name)
152  .Case("env_sha3", reinterpret_cast<uint64_t>(&keccak))
153  .Case("evm.query", reinterpret_cast<uint64_t>(jit.queryFn))
154  .Case("evm.update", reinterpret_cast<uint64_t>(jit.updateFn))
155  .Case("evm.call", reinterpret_cast<uint64_t>(jit.callFn))
156  .Default(0);
157  if (addr)
158  return {addr, llvm::JITSymbolFlags::Exported};
159 
160  // Fallback to default implementation that would search for the symbol
161  // in the current process.
162  // TODO: In the future we should control the whole set of requested
163  // symbols (like memcpy, memset, etc) to improve performance.
164  return llvm::SectionMemoryManager::findSymbol(_name);
165  }
166 
167  void reportMemorySize(size_t _addedSize)
168  {
169  if (!g_stats)
170  return;
171 
172  m_totalMemorySize += _addedSize;
174  {
175  static const auto M = 1024 * 1024;
176  auto value = double(m_totalMemorySize) / M;
177  std::cerr << "EVMJIT total memory size: " << value << '\n';
178  m_printMemoryLimit += M;
179  }
180  }
181 
182  uint8_t* allocateCodeSection(uintptr_t _size, unsigned _a, unsigned _id,
183  llvm::StringRef _name) override
184  {
185  reportMemorySize(_size);
186  return llvm::SectionMemoryManager::allocateCodeSection(_size, _a, _id, _name);
187  }
188 
189  uint8_t* allocateDataSection(uintptr_t _size, unsigned _a, unsigned _id,
190  llvm::StringRef _name, bool _ro) override
191  {
192  reportMemorySize(_size);
193  return llvm::SectionMemoryManager::allocateDataSection(_size, _a, _id, _name, _ro);
194  }
195 
196  size_t m_totalMemorySize = 0;
197  size_t m_printMemoryLimit = 1024 * 1024;
198 };
199 
200 
201 
202 
203 ExecFunc JITImpl::getExecFunc(std::string const& _codeIdentifier) const
204 {
205  std::lock_guard<std::mutex> lock{x_codeMap};
206  auto it = m_codeMap.find(_codeIdentifier);
207  if (it != m_codeMap.end())
208  return it->second;
209  return nullptr;
210 }
211 
212 void JITImpl::mapExecFunc(std::string const& _codeIdentifier, ExecFunc _funcAddr)
213 {
214  std::lock_guard<std::mutex> lock{x_codeMap};
215  m_codeMap.emplace(_codeIdentifier, _funcAddr);
216 }
217 
218 ExecFunc JITImpl::compile(evm_mode _mode, byte const* _code, uint64_t _codeSize,
219  std::string const& _codeIdentifier)
220 {
221  auto module = Cache::getObject(_codeIdentifier, getLLVMContext());
222  if (!module)
223  {
224  // TODO: Listener support must be redesigned. These should be a feature of JITImpl
225  //listener->stateChanged(ExecState::Compilation);
226  assert(_code || !_codeSize);
227  //TODO: Can the Compiler be stateless?
228  module = Compiler({}, _mode, getLLVMContext()).compile(_code, _code + _codeSize, _codeIdentifier);
229 
230  if (g_optimize)
231  {
232  //listener->stateChanged(ExecState::Optimization);
233  optimize(*module);
234  }
235 
236  prepare(*module);
237  }
238  if (g_dump)
239  module->dump();
240 
241  m_engine->addModule(std::move(module));
242  //listener->stateChanged(ExecState::CodeGen);
243  return (ExecFunc)m_engine->getFunctionAddress(_codeIdentifier);
244 }
245 
246 } // anonymous namespace
247 
248 
250 {
251  if (m_memData)
252  std::free(m_memData); // Use helper free to check memory leaks
253 }
254 
256 {
257  auto data = m_data->callData;
258  auto size = static_cast<size_t>(m_data->callDataSize);
259 
260  if (data < m_memData || data >= m_memData + m_memSize || size == 0)
261  {
262  assert(size == 0); // data can be an invalid pointer only if size is 0
263  m_data->callData = nullptr;
264  return {};
265  }
266 
267  return bytes_ref{data, size};
268 }
269 
270 
271 extern "C"
272 {
273 
276 {
277  // Let's always return the same instance. It's a bit of faking, but actually
278  // this might be a compliant implementation.
279  auto& jit = JITImpl::instance();
280  jit.queryFn = queryFn;
281  jit.updateFn = updateFn;
282  jit.callFn = callFn;
283  return &jit;
284 }
285 
286 static void destroy(evm_instance* instance)
287 {
288  (void)instance;
289  assert(instance == static_cast<void*>(&JITImpl::instance()));
290 }
291 
292 static void release_result(evm_result const* result)
293 {
294  if (result->internal_memory)
295  std::free(result->internal_memory);
296 }
297 
298 static evm_result execute(evm_instance* instance, evm_env* env, evm_mode mode,
299  evm_uint256be code_hash, uint8_t const* code, size_t code_size,
300  int64_t gas, uint8_t const* input, size_t input_size, evm_uint256be value)
301 {
302  auto& jit = *reinterpret_cast<JITImpl*>(instance);
303 
304  RuntimeData rt;
305  rt.code = code;
306  rt.codeSize = code_size;
307  rt.gas = gas;
308  rt.callData = input;
309  rt.callDataSize = input_size;
310  std::memcpy(&rt.apparentValue, &value, sizeof(value));
311 
312  ExecutionContext ctx{rt, env};
313 
314  evm_result result;
315  result.code = EVM_SUCCESS;
316  result.gas_left = 0;
317  result.output_data = nullptr;
318  result.output_size = 0;
319  result.error_message = nullptr;
320  result.internal_memory = nullptr;
321  result.release = release_result;
322 
323  auto codeIdentifier = makeCodeId(code_hash, mode);
324  auto execFunc = jit.getExecFunc(codeIdentifier);
325  if (!execFunc)
326  {
327  execFunc = jit.compile(mode, ctx.code(), ctx.codeSize(), codeIdentifier);
328  if (!execFunc)
329  return result;
330  jit.mapExecFunc(codeIdentifier, execFunc);
331  }
332 
333  auto returnCode = execFunc(&ctx);
334 
335  if (returnCode == ReturnCode::OutOfGas)
336  {
337  // EVMJIT does not provide information what exactly type of failure
338  // it was, so use generic EVM_FAILURE.
339  result.code = EVM_FAILURE;
340  }
341  else
342  {
343  // In case of success return the amount of gas left.
344  result.gas_left = rt.gas;
345  }
346 
347  if (returnCode == ReturnCode::Return)
348  {
349  auto out = ctx.getReturnData();
350  result.output_data = std::get<0>(out);
351  result.output_size = std::get<1>(out);
352  }
353 
354  // Take care of the internal memory.
355  result.internal_memory = ctx.m_memData;
356  ctx.m_memData = nullptr;
357 
358  return result;
359 }
360 
361 static int set_option(evm_instance* instance, char const* name,
362  char const* value)
363 {
364  (void)instance, (void)name, (void)value;
365  return 0;
366 }
367 
368 static evm_code_status get_code_status(evm_instance* instance,
369  evm_mode mode, evm_uint256be code_hash)
370 {
371  auto& jit = *reinterpret_cast<JITImpl*>(instance);
372  auto codeIdentifier = makeCodeId(code_hash, mode);
373  if (jit.getExecFunc(codeIdentifier) != nullptr)
374  return EVM_READY;
375  // TODO: Add support for EVM_CACHED.
376  return EVM_UNKNOWN;
377 }
378 
379 static void prepare_code(evm_instance* instance, evm_mode mode,
380  evm_uint256be code_hash, unsigned char const* code, size_t code_size)
381 {
382  auto& jit = *reinterpret_cast<JITImpl*>(instance);
383  auto codeIdentifier = makeCodeId(code_hash, mode);
384  auto execFunc = jit.compile(mode, code, code_size, codeIdentifier);
385  if (execFunc) // FIXME: What with error?
386  jit.mapExecFunc(codeIdentifier, execFunc);
387 }
388 
390 {
391  return {EVM_ABI_VERSION, create};
392 }
393 
394 } // extern "C"
395 
396 JITImpl::JITImpl():
397  evm_instance({evmjit::destroy,
398  evmjit::execute,
399  evmjit::get_code_status,
400  evmjit::prepare_code,
401  evmjit::set_option})
402 {
403  parseOptions();
404 
405  bool preloadCache = g_cache == CacheMode::preload;
406  if (preloadCache)
407  g_cache = CacheMode::on;
408 
409  llvm::InitializeNativeTarget();
410  llvm::InitializeNativeTargetAsmPrinter();
411 
412  auto module = llvm::make_unique<llvm::Module>("", getLLVMContext());
413 
414  // FIXME: LLVM 3.7: test on Windows
415  auto triple = llvm::Triple(llvm::sys::getProcessTriple());
416  if (triple.getOS() == llvm::Triple::OSType::Win32)
417  triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format
418  module->setTargetTriple(triple.str());
419 
420  llvm::EngineBuilder builder(std::move(module));
421  builder.setEngineKind(llvm::EngineKind::JIT);
422  builder.setMCJITMemoryManager(llvm::make_unique<SymbolResolver>());
423  builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None);
424 #ifndef NDEBUG
425  builder.setVerifyModules(true);
426 #endif
427 
428  m_engine.reset(builder.create());
429 
430  // TODO: Update cache listener
431  m_engine->setObjectCache(Cache::init(g_cache, nullptr));
432 
433  // FIXME: Disabled during API changes
434  //if (preloadCache)
435  // Cache::preload(*m_engine, funcCache);
436 }
437 
438 }
439 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
~ExecutionContext() noexcept
Definition: JIT.cpp:249
uint8_t bytes[32]
The 32 bytes of the big-endian integer or hash.
Definition: evm.h:38
uint8_t byte
Definition: Common.h:57
evm_update_fn updateFn
Definition: JIT.cpp:141
size_t m_totalMemorySize
Definition: JIT.cpp:196
Big-endian 256-bit integer.
Definition: evm.h:36
char const * error_message
The error message explaining the result code.
Definition: evm.h:99
bool prepare(llvm::Module &_module)
Definition: Optimizer.cpp:163
uint8_t const * output_data
The reference to output data.
Definition: evm.h:82
evm_mode mode
Definition: SmartVM.cpp:47
evm_call_fn callFn
Definition: JIT.cpp:142
void keccak(uint8_t const *_data, uint64_t _size, uint8_t *o_hash)
Definition: Utils.cpp:178
int64_t gas_left
The amount of gas left after the execution.
Definition: evm.h:78
assert(len-trim+(2 *lenIndices)<=WIDTH)
evm_release_result_fn release
The pointer to the result release implementation.
Definition: evm.h:92
Execution finished with success.
Definition: evm.h:49
bytes code
Definition: SmartVM.cpp:45
The code has been compiled and is available in memory.
Definition: evm.h:404
evm_code_status
Status of a code in VM. Useful for JIT-like implementations.
Definition: evm.h:399
byte const * callData
Definition: JIT.h:47
#define EXPORT
Definition: evmjit.h:13
std::unordered_map< std::string, ExecFunc > m_codeMap
Definition: JIT.cpp:112
size_t m_printMemoryLimit
Definition: JIT.cpp:197
evm_update_key
The update callback key.
Definition: evm.h:238
static std::unique_ptr< llvm::Module > getObject(std::string const &id, llvm::LLVMContext &_llvmContext)
Definition: Cache.cpp:106
The EVM instance factory.
Definition: evm.h:455
enum evm_result_code code
The execution result code.
Definition: evm.h:73
size_t output_size
The size of the output data.
Definition: evm.h:85
const char * name
Definition: rest.cpp:36
void * internal_memory
The pointer to EVM-owned memory.
Definition: evm.h:103
evm_query_fn queryFn
Definition: JIT.cpp:140
Big-endian 160-bit hash suitable for keeping an Ethereum address.
Definition: evm.h:42
The EVM instance.
Definition: evm.h:429
evm_call_kind
The kind of call-like instruction.
Definition: evm.h:277
uint64_t codeSize
Definition: JIT.h:51
evm_mode
EVM compatibility mode aka chain mode.
Definition: evm.h:359
byte const * code
Definition: JIT.h:50
#define b(i, j)
The EVM code execution result.
Definition: evm.h:71
EXPORT evm_factory evmjit_get_factory()
Get EVMJIT instance.
Definition: JIT.cpp:389
ReturnCode
Definition: JIT.h:86
h256 codeHash
Definition: SmartVM.cpp:46
std::tuple< byte const *, size_t > bytes_ref
Definition: JIT.h:16
uint8_t const size_t const size
Definition: sha3.h:20
void(* evm_update_fn)(struct evm_env *env, enum evm_update_key key, const union evm_variant *arg1, const union evm_variant *arg2)
Update callback function.
Definition: evm.h:271
void * memcpy(void *a, const void *b, size_t c)
static ObjectCache * init(CacheMode _mode, JITListener *_listener)
Definition: Cache.cpp:46
std::mutex x_codeMap
Definition: JIT.cpp:111
uint64_t callDataSize
Definition: JIT.h:48
bool optimize(llvm::Module &_module)
Definition: Optimizer.cpp:74
void(* evm_query_fn)(union evm_variant *result, struct evm_env *env, enum evm_query_key key, const union evm_variant *arg)
Query callback function.
Definition: evm.h:232
The code is uknown to the VM.
Definition: evm.h:401
evm_query_key
The query callback key.
Definition: evm.h:109
int64_t(* evm_call_fn)(struct evm_env *env, enum evm_call_kind kind, int64_t gas, const struct evm_uint160be *address, const struct evm_uint256be *value, uint8_t const *input, size_t input_size, uint8_t *output, size_t output_size)
Pointer to the callback function supporting EVM calls.
Definition: evm.h:308
uint8_t const * data
Definition: sha3.h:19
std::unique_ptr< llvm::ExecutionEngine > m_engine
Definition: JIT.cpp:110
Generic execution failure.
Definition: evm.h:50
bytes_ref getReturnData() const
Definition: JIT.cpp:255