Browse Source

Merge pull request #747 from imapp-pl/pr/evmjit

EVM JIT update: latest PoC-8 changes, cleanups and improvments
cl-refactor
Gav Wood 10 years ago
parent
commit
2351e58c6b
  1. 2
      evmjit/CMakeLists.txt
  2. 19
      evmjit/libevmjit/BasicBlock.cpp
  3. 26
      evmjit/libevmjit/BasicBlock.h
  4. 40
      evmjit/libevmjit/Cache.cpp
  5. 2
      evmjit/libevmjit/Cache.h
  6. 8
      evmjit/libevmjit/Common.h
  7. 121
      evmjit/libevmjit/Compiler.cpp
  8. 14
      evmjit/libevmjit/Compiler.h
  9. 16
      evmjit/libevmjit/ExecutionEngine.cpp
  10. 4
      evmjit/libevmjit/Ext.cpp
  11. 4
      evmjit/libevmjit/Ext.h
  12. 2
      evmjit/libevmjit/GasMeter.cpp
  13. 40
      evmjit/libevmjit/Instruction.cpp
  14. 6
      evmjit/libevmjit/Instruction.h
  15. 2
      evmjit/libevmjit/Runtime.h
  16. 19
      evmjit/libevmjit/Utils.cpp

2
evmjit/CMakeLists.txt

@ -19,6 +19,8 @@ else()
set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm")
endif() endif()
add_definitions(-D_SCL_SECURE_NO_WARNINGS) # LLVM needs it on Windows
# Boost # Boost
find_package(Boost REQUIRED) find_package(Boost REQUIRED)

19
evmjit/libevmjit/BasicBlock.cpp

@ -20,20 +20,21 @@ namespace jit
const char* BasicBlock::NamePrefix = "Instr."; const char* BasicBlock::NamePrefix = "Instr.";
BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) :
m_beginInstIdx(_beginInstIdx), m_begin(_begin),
m_endInstIdx(_endInstIdx), m_end(_end),
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)), // TODO: Add begin index to name
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)),
m_stack(*this), m_stack(*this),
m_builder(_builder) m_builder(_builder),
m_isJumpDest(isJumpDest)
{} {}
BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) :
m_beginInstIdx(0),
m_endInstIdx(0),
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)),
m_stack(*this), m_stack(*this),
m_builder(_builder) m_builder(_builder),
m_isJumpDest(isJumpDest)
{} {}
BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) :

26
evmjit/libevmjit/BasicBlock.h

@ -1,9 +1,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <llvm/IR/BasicBlock.h> #include <llvm/IR/BasicBlock.h>
#include "Common.h"
#include "Stack.h" #include "Stack.h"
namespace dev namespace dev
@ -52,23 +50,21 @@ public:
BasicBlock& m_bblock; BasicBlock& m_bblock;
}; };
/// Basic block name prefix. The rest is beging instruction index. /// Basic block name prefix. The rest is instruction index.
static const char* NamePrefix; static const char* NamePrefix;
explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
BasicBlock(const BasicBlock&) = delete; BasicBlock(const BasicBlock&) = delete;
void operator=(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete;
operator llvm::BasicBlock*() { return m_llvmBB; }
llvm::BasicBlock* llvm() { return m_llvmBB; } llvm::BasicBlock* llvm() { return m_llvmBB; }
ProgramCounter begin() { return m_beginInstIdx; } bytes::const_iterator begin() { return m_begin; }
ProgramCounter end() { return m_endInstIdx; } bytes::const_iterator end() { return m_end; }
bool isJumpDest() const { return m_isJumpDest; } bool isJumpDest() const { return m_isJumpDest; }
void markAsJumpDest() { m_isJumpDest = true; }
LocalStack& localStack() { return m_stack; } LocalStack& localStack() { return m_stack; }
@ -85,8 +81,8 @@ public:
void dump(std::ostream& os, bool _dotOutput = false); void dump(std::ostream& os, bool _dotOutput = false);
private: private:
ProgramCounter const m_beginInstIdx; bytes::const_iterator const m_begin;
ProgramCounter const m_endInstIdx; bytes::const_iterator const m_end;
llvm::BasicBlock* const m_llvmBB; llvm::BasicBlock* const m_llvmBB;
@ -102,12 +98,12 @@ private:
/// the item below the top and so on. The stack grows as the code /// the item below the top and so on. The stack grows as the code
/// accesses more items on the EVM stack but once a value is put on /// accesses more items on the EVM stack but once a value is put on
/// the stack, it will never be replaced. /// the stack, it will never be replaced.
std::vector<llvm::Value*> m_initialStack = {}; std::vector<llvm::Value*> m_initialStack;
/// This stack tracks the contents of the EVM stack as the basic block /// This stack tracks the contents of the EVM stack as the basic block
/// executes. It may grow on both sides, as the code pushes items on /// executes. It may grow on both sides, as the code pushes items on
/// top of the stack or changes existing items. /// top of the stack or changes existing items.
std::vector<llvm::Value*> m_currentStack = {}; std::vector<llvm::Value*> m_currentStack;
/// How many items higher is the current stack than the initial one. /// How many items higher is the current stack than the initial one.
/// May be negative. /// May be negative.
@ -115,7 +111,7 @@ private:
/// Is the basic block a valid jump destination. /// Is the basic block a valid jump destination.
/// JUMPDEST is the first instruction of the basic block. /// JUMPDEST is the first instruction of the basic block.
bool m_isJumpDest = false; bool const m_isJumpDest = false;
}; };
} }

40
evmjit/libevmjit/Cache.cpp

@ -3,6 +3,7 @@
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/Support/Path.h> #include <llvm/Support/Path.h>
#include <llvm/Support/FileSystem.h> #include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_os_ostream.h> #include <llvm/Support/raw_os_ostream.h>
@ -23,6 +24,32 @@ ObjectCache* Cache::getObjectCache()
return &objectCache; return &objectCache;
} }
namespace
{
llvm::MemoryBuffer* lastObject;
}
std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
{
assert(!lastObject);
llvm::SmallString<256> cachePath;
llvm::sys::path::system_temp_directory(false, cachePath);
llvm::sys::path::append(cachePath, "evm_objs", id);
if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false))
lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))
std::cerr << r.getError().message(); // TODO: Add log
if (lastObject) // if object found create fake module
{
auto module = std::unique_ptr<llvm::Module>(new llvm::Module(id, llvm::getGlobalContext()));
auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false);
auto func = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get());
}
return nullptr;
}
void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object)
{ {
@ -43,16 +70,9 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory
llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module)
{ {
auto&& id = _module->getModuleIdentifier(); auto o = lastObject;
llvm::SmallString<256> cachePath; lastObject = nullptr;
llvm::sys::path::system_temp_directory(false, cachePath); return o;
llvm::sys::path::append(cachePath, "evm_objs", id);
if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false))
return llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))
std::cerr << r.getError().message(); // TODO: Add log
return nullptr;
} }
} }

2
evmjit/libevmjit/Cache.h

@ -2,7 +2,6 @@
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/ObjectCache.h> #include <llvm/ExecutionEngine/ObjectCache.h>
@ -34,6 +33,7 @@ class Cache
{ {
public: public:
static ObjectCache* getObjectCache(); static ObjectCache* getObjectCache();
static std::unique_ptr<llvm::Module> getObject(std::string const& id);
}; };
} }

8
evmjit/libevmjit/Common.h

@ -37,10 +37,10 @@ enum class ReturnCode
// TODO: Replace with h256 // TODO: Replace with h256
struct i256 struct i256
{ {
uint64_t a; uint64_t a = 0;
uint64_t b; uint64_t b = 0;
uint64_t c; uint64_t c = 0;
uint64_t d; uint64_t d = 0;
}; };
static_assert(sizeof(i256) == 32, "Wrong i265 size"); static_assert(sizeof(i256) == 32, "Wrong i265 size");

121
evmjit/libevmjit/Compiler.cpp

@ -40,77 +40,69 @@ Compiler::Compiler(Options const& _options):
void Compiler::createBasicBlocks(bytes const& _bytecode) void Compiler::createBasicBlocks(bytes const& _bytecode)
{ {
// FIXME: Simplify this algorithm. All can be done in one pass /// Helper function that skips push data and finds next iterator (can be the end)
auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end)
std::set<ProgramCounter> splitPoints; // Sorted collections of instruction indices where basic blocks start/end
std::vector<ProgramCounter> indirectJumpTargets;
splitPoints.insert(0); // First basic block
for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr)
{
ProgramCounter currentPC = curr - _bytecode.begin();
auto inst = Instruction(*curr);
switch (inst)
{ {
static const auto push1 = static_cast<size_t>(Instruction::PUSH1);
static const auto push32 = static_cast<size_t>(Instruction::PUSH32);
size_t offset = 1;
if (*_curr >= push1 && *_curr <= push32)
offset += std::min<size_t>(*_curr - push1 + 1, (_end - _curr) - 1);
return _curr + offset;
};
case Instruction::ANY_PUSH: auto begin = _bytecode.begin();
bool nextJumpDest = false;
for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next)
{ {
readPushData(curr, _bytecode.end()); next = skipPushDataAndGetNext(curr, _bytecode.end());
break;
}
case Instruction::JUMPDEST: bool isEnd = false;
switch (Instruction(*curr))
{ {
// A basic block starts here.
splitPoints.insert(currentPC);
indirectJumpTargets.push_back(currentPC);
break;
}
case Instruction::JUMP: case Instruction::JUMP:
case Instruction::JUMPI: case Instruction::JUMPI:
case Instruction::RETURN: case Instruction::RETURN:
case Instruction::STOP: case Instruction::STOP:
case Instruction::SUICIDE: case Instruction::SUICIDE:
{ isEnd = true;
// Create a basic block starting at the following instruction. break;
if (curr + 1 < _bytecode.end())
splitPoints.insert(currentPC + 1); case Instruction::JUMPDEST:
nextJumpDest = true;
break; break;
}
default: default:
break; break;
} }
}
for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) assert(next <= _bytecode.end());
if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST)
isEnd = true;
if (isEnd)
{ {
auto beginInstIdx = *it; auto beginIdx = begin - _bytecode.begin();
++it; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx),
auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest));
basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); nextJumpDest = false;
begin = next;
}
} }
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it)
basicBlocks.find(*it)->second.markAsJumpDest();
} }
llvm::BasicBlock* Compiler::getJumpTableBlock() llvm::BasicBlock* Compiler::getJumpTableBlock()
{ {
if (!m_jumpTableBlock) if (!m_jumpTableBlock)
{ {
m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder)); m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true));
InsertPointGuard g{m_builder}; InsertPointGuard g{m_builder};
m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
auto dest = m_jumpTableBlock->localStack().pop(); auto dest = m_jumpTableBlock->localStack().pop();
auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock());
for (auto&& p : basicBlocks) for (auto&& p : m_basicBlocks)
{ {
if (p.second.isJumpDest()) if (p.second.isJumpDest())
switchInstr->addCase(Constant::get(p.first), p.second.llvm()); switchInstr->addCase(Constant::get(p.first), p.second.llvm());
@ -123,7 +115,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock()
{ {
if (!m_badJumpBlock) if (!m_badJumpBlock)
{ {
m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder)); m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true));
InsertPointGuard g{m_builder}; InsertPointGuard g{m_builder};
m_builder.SetInsertPoint(m_badJumpBlock->llvm()); m_builder.SetInsertPoint(m_badJumpBlock->llvm());
m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination));
@ -155,14 +147,14 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
Stack stack(m_builder, runtimeManager); Stack stack(m_builder, runtimeManager);
Arith256 arith(m_builder); Arith256 arith(m_builder);
m_builder.CreateBr(basicBlocks.begin()->second); m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm());
for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt)
{ {
auto& basicBlock = basicBlockPairIt->second; auto& basicBlock = basicBlockPairIt->second;
auto iterCopy = basicBlockPairIt; auto iterCopy = basicBlockPairIt;
++iterCopy; ++iterCopy;
auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock);
} }
@ -178,7 +170,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
if (m_options.optimizeStack) if (m_options.optimizeStack)
{ {
std::vector<BasicBlock*> blockList; std::vector<BasicBlock*> blockList;
for (auto& entry : basicBlocks) for (auto& entry : m_basicBlocks)
blockList.push_back(&entry.second); blockList.push_back(&entry.second);
if (m_jumpTableBlock) if (m_jumpTableBlock)
@ -189,7 +181,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
dumpCFGifRequired("blocks-opt.dot"); dumpCFGifRequired("blocks-opt.dot");
} }
for (auto& entry : basicBlocks) for (auto& entry : m_basicBlocks)
entry.second.synchronizeLocalStack(stack); entry.second.synchronizeLocalStack(stack);
if (m_jumpTableBlock) if (m_jumpTableBlock)
m_jumpTableBlock->synchronizeLocalStack(stack); m_jumpTableBlock->synchronizeLocalStack(stack);
@ -219,9 +211,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
m_builder.SetInsertPoint(_basicBlock.llvm()); m_builder.SetInsertPoint(_basicBlock.llvm());
auto& stack = _basicBlock.localStack(); auto& stack = _basicBlock.localStack();
for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) for (auto it = _basicBlock.begin(); it != _basicBlock.end(); ++it)
{ {
auto inst = static_cast<Instruction>(_bytecode[currentPC]); auto inst = Instruction(*it);
_gasMeter.count(inst); _gasMeter.count(inst);
@ -483,10 +475,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::ANY_PUSH: case Instruction::ANY_PUSH:
{ {
auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator auto value = readPushData(it, _basicBlock.end());
auto value = readPushData(curr, _bytecode.end());
currentPC = curr - _bytecode.begin();
stack.push(Constant::get(value)); stack.push(Constant::get(value));
break; break;
} }
@ -561,24 +550,16 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(target)) if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(target))
{ {
auto&& c = constant->getValue(); auto&& c = constant->getValue();
if (c.ult(_bytecode.size())) auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1;
{ auto it = m_basicBlocks.find(targetIdx);
auto v = c.getZExtValue(); targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock();
auto it = basicBlocks.find(v);
if (it != basicBlocks.end() && it->second.isJumpDest())
targetBlock = it->second.llvm();
}
if (!targetBlock)
targetBlock = getBadJumpBlock();
} }
// TODO: Improve; check for constants
if (inst == Instruction::JUMP) if (inst == Instruction::JUMP)
{ {
if (targetBlock) if (targetBlock)
{ {
// The target address is computed at compile time,
// just pop it without looking...
m_builder.CreateBr(targetBlock); m_builder.CreateBr(targetBlock);
} }
else else
@ -614,7 +595,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::PC: case Instruction::PC:
{ {
auto value = Constant::get(currentPC); auto value = Constant::get(it - _bytecode.begin());
stack.push(value); stack.push(value);
break; break;
} }
@ -832,13 +813,13 @@ void Compiler::removeDeadBlocks()
do do
{ {
sthErased = false; sthErased = false;
for (auto it = basicBlocks.begin(); it != basicBlocks.end();) for (auto it = m_basicBlocks.begin(); it != m_basicBlocks.end();)
{ {
auto llvmBB = it->second.llvm(); auto llvmBB = it->second.llvm();
if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB))
{ {
llvmBB->eraseFromParent(); llvmBB->eraseFromParent();
basicBlocks.erase(it++); m_basicBlocks.erase(it++);
sthErased = true; sthErased = true;
} }
else else
@ -866,7 +847,7 @@ void Compiler::dumpCFGtoStream(std::ostream& _out)
<< " entry [share=record, label=\"entry block\"];\n"; << " entry [share=record, label=\"entry block\"];\n";
std::vector<BasicBlock*> blocks; std::vector<BasicBlock*> blocks;
for (auto& pair : basicBlocks) for (auto& pair : m_basicBlocks)
blocks.push_back(&pair.second); blocks.push_back(&pair.second);
if (m_jumpTableBlock) if (m_jumpTableBlock)
blocks.push_back(m_jumpTableBlock.get()); blocks.push_back(m_jumpTableBlock.get());
@ -905,7 +886,7 @@ void Compiler::dumpCFGtoStream(std::ostream& _out)
void Compiler::dump() void Compiler::dump()
{ {
for (auto& entry : basicBlocks) for (auto& entry : m_basicBlocks)
entry.second.dump(); entry.second.dump();
if (m_jumpTableBlock != nullptr) if (m_jumpTableBlock != nullptr)
m_jumpTableBlock->dump(); m_jumpTableBlock->dump();

14
evmjit/libevmjit/Compiler.h

@ -20,19 +20,13 @@ public:
struct Options struct Options
{ {
/// Optimize stack operations between basic blocks /// Optimize stack operations between basic blocks
bool optimizeStack; bool optimizeStack = true;
/// Rewrite switch instructions to sequences of branches /// Rewrite switch instructions to sequences of branches
bool rewriteSwitchToBranches; bool rewriteSwitchToBranches = true;
/// Dump CFG as a .dot file for graphviz /// Dump CFG as a .dot file for graphviz
bool dumpCFG; bool dumpCFG = false;
Options():
optimizeStack(true),
rewriteSwitchToBranches(true),
dumpCFG(false)
{}
}; };
using ProgramCounter = uint64_t; using ProgramCounter = uint64_t;
@ -69,7 +63,7 @@ private:
llvm::IRBuilder<> m_builder; llvm::IRBuilder<> m_builder;
/// Maps a program counter pc to a basic block that starts at pc (if any). /// Maps a program counter pc to a basic block that starts at pc (if any).
std::map<ProgramCounter, BasicBlock> basicBlocks; std::map<ProgramCounter, BasicBlock> m_basicBlocks;
/// Stop basic block - terminates execution with STOP code (0) /// Stop basic block - terminates execution with STOP code (0)
llvm::BasicBlock* m_stopBB = nullptr; llvm::BasicBlock* m_stopBB = nullptr;

16
evmjit/libevmjit/ExecutionEngine.cpp

@ -4,8 +4,13 @@
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/ADT/Triple.h> #include <llvm/ADT/Triple.h>
#pragma warning(push)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <llvm/ExecutionEngine/ExecutionEngine.h> #include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h> #include <llvm/ExecutionEngine/SectionMemoryManager.h>
#pragma warning(pop)
#pragma GCC diagnostic pop
#include <llvm/ExecutionEngine/MCJIT.h> #include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/TargetSelect.h> #include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Host.h> #include <llvm/Support/Host.h>
@ -69,7 +74,13 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en
} }
else else
{ {
auto module = Compiler({}).compile(_code, mainFuncName); bool objectCacheEnabled = true;
auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr;
std::unique_ptr<llvm::Module> module;
if (objectCache)
module = Cache::getObject(mainFuncName);
if (!module)
module = Compiler({}).compile(_code, mainFuncName);
//module->dump(); //module->dump();
if (!ee) if (!ee)
{ {
@ -95,7 +106,8 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en
module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
memoryManager.release(); // and memory manager memoryManager.release(); // and memory manager
ee->setObjectCache(Cache::getObjectCache()); if (objectCache)
ee->setObjectCache(objectCache);
entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
} }
else else

4
evmjit/libevmjit/Ext.cpp

@ -22,7 +22,9 @@ namespace jit
Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan):
RuntimeHelper(_runtimeManager), RuntimeHelper(_runtimeManager),
m_memoryMan(_memoryMan) m_memoryMan(_memoryMan),
m_funcs{},
m_argAllocas{}
{ {
m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size");
} }

4
evmjit/libevmjit/Ext.h

@ -65,8 +65,8 @@ private:
llvm::Value* m_size; llvm::Value* m_size;
llvm::Value* m_data = nullptr; llvm::Value* m_data = nullptr;
std::array<llvm::Function*, sizeOf<EnvFunc>::value> m_funcs = {}; std::array<llvm::Function*, sizeOf<EnvFunc>::value> m_funcs;
std::array<llvm::Value*, 8> m_argAllocas = {}; std::array<llvm::Value*, 8> m_argAllocas;
size_t m_argCounter = 0; size_t m_argCounter = 0;
llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list<llvm::Value*> const& _args); llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list<llvm::Value*> const& _args);

2
evmjit/libevmjit/GasMeter.cpp

@ -41,7 +41,7 @@ uint64_t const c_logDataGas = 1;
uint64_t const c_logTopicGas = 32; uint64_t const c_logTopicGas = 32;
uint64_t const c_copyGas = 1; uint64_t const c_copyGas = 1;
uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted) uint64_t getStepCost(Instruction inst)
{ {
switch (inst) switch (inst)
{ {

40
evmjit/libevmjit/Instruction.cpp

@ -0,0 +1,40 @@
#include "Instruction.h"
#include <llvm/ADT/APInt.h>
namespace dev
{
namespace eth
{
namespace jit
{
llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
{
auto pushInst = *_curr;
assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);
auto numBytes = pushInst - static_cast<size_t>(Instruction::PUSH1) + 1;
llvm::APInt value(256, 0);
++_curr; // Point the data
for (decltype(numBytes) i = 0; i < numBytes; ++i)
{
byte b = (_curr != _end) ? *_curr++ : 0;
value <<= 8;
value |= b;
}
--_curr; // Point the last real byte read
return value;
}
void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
{
auto pushInst = *_curr;
assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);
auto numBytes = pushInst - static_cast<size_t>(Instruction::PUSH1) + 1;
--_end;
for (decltype(numBytes) i = 0; i < numBytes && _curr < _end; ++i, ++_curr) {}
}
}
}
}

6
evmjit/libevmjit/Instruction.h

@ -160,9 +160,13 @@ enum class Instruction: uint8_t
/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it /// Reads PUSH data from pointed fragment of bytecode and constructs number out of it
/// Reading out of bytecode means reading 0 /// Reading out of bytecode means reading 0
/// @param _curr is updates and points the last real byte read /// @param _curr is updated and points the last real byte read
llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end);
/// Skips PUSH data in pointed fragment of bytecode.
/// @param _curr is updated and points the last real byte skipped
void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end);
#define ANY_PUSH PUSH1: \ #define ANY_PUSH PUSH1: \
case Instruction::PUSH2: \ case Instruction::PUSH2: \
case Instruction::PUSH3: \ case Instruction::PUSH3: \

2
evmjit/libevmjit/Runtime.h

@ -48,7 +48,7 @@ private:
Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract.
jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract.
byte* m_memoryData = nullptr; byte* m_memoryData = nullptr;
i256 m_memorySize = {}; i256 m_memorySize;
std::jmp_buf m_jmpBuf; std::jmp_buf m_jmpBuf;
StackImpl m_stack; StackImpl m_stack;
MemoryImpl m_memory; MemoryImpl m_memory;

19
evmjit/libevmjit/Utils.cpp

@ -1,7 +1,5 @@
#include <llvm/ADT/APInt.h>
#include "Utils.h" #include "Utils.h"
#include "Instruction.h"
namespace dev namespace dev
{ {
@ -37,23 +35,6 @@ i256 eth2llvm(u256 _u)
return i; return i;
} }
llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
{
auto pushInst = *_curr;
assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);
auto numBytes = pushInst - static_cast<size_t>(Instruction::PUSH1) + 1;
llvm::APInt value(256, 0);
++_curr; // Point the data
for (decltype(numBytes) i = 0; i < numBytes; ++i)
{
byte b = (_curr != _end) ? *_curr++ : 0;
value <<= 8;
value |= b;
}
--_curr; // Point the last real byte read
return value;
}
} }
} }
} }

Loading…
Cancel
Save