Browse Source

Replacing code references (usually vector<byte>&) with code_iterator pair. Code is now extracted from RuntimeData what removes copy in C interface.

cl-refactor
Paweł Bylica 10 years ago
parent
commit
932ce6650c
  1. 2
      evmjit/libevmjit-cpp/JitVM.cpp
  2. 2
      evmjit/libevmjit/BasicBlock.cpp
  3. 10
      evmjit/libevmjit/BasicBlock.h
  4. 1
      evmjit/libevmjit/Common.h
  5. 27
      evmjit/libevmjit/Compiler.cpp
  6. 8
      evmjit/libevmjit/Compiler.h
  7. 15
      evmjit/libevmjit/ExecutionEngine.cpp
  8. 2
      evmjit/libevmjit/ExecutionEngine.h
  9. 4
      evmjit/libevmjit/Instruction.cpp
  10. 4
      evmjit/libevmjit/Instruction.h
  11. 11
      evmjit/libevmjit/interface.cpp

2
evmjit/libevmjit-cpp/JitVM.cpp

@ -47,7 +47,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
m_data.codeSize = _ext.code.size();
auto env = reinterpret_cast<Env*>(&_ext);
auto exitCode = m_engine.run(_ext.code, &m_data, env);
auto exitCode = m_engine.run(&m_data, env);
switch (exitCode)
{
case ReturnCode::Suicide:

2
evmjit/libevmjit/BasicBlock.cpp

@ -20,7 +20,7 @@ namespace jit
const char* BasicBlock::NamePrefix = "Instr.";
BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) :
BasicBlock::BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) :
m_begin(_begin),
m_end(_end),
// TODO: Add begin index to name

10
evmjit/libevmjit/BasicBlock.h

@ -53,7 +53,7 @@ public:
/// Basic block name prefix. The rest is instruction index.
static const char* NamePrefix;
explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
explicit BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
BasicBlock(const BasicBlock&) = delete;
@ -61,8 +61,8 @@ public:
llvm::BasicBlock* llvm() { return m_llvmBB; }
bytes::const_iterator begin() { return m_begin; }
bytes::const_iterator end() { return m_end; }
code_iterator begin() { return m_begin; }
code_iterator end() { return m_end; }
bool isJumpDest() const { return m_isJumpDest; }
@ -84,8 +84,8 @@ public:
void dump(std::ostream& os, bool _dotOutput = false);
private:
bytes::const_iterator const m_begin;
bytes::const_iterator const m_end;
code_iterator const m_begin = {};
code_iterator const m_end = {};
llvm::BasicBlock* const m_llvmBB;

1
evmjit/libevmjit/Common.h

@ -20,6 +20,7 @@ namespace jit
using byte = uint8_t;
using bytes = std::vector<byte>;
using bytes_ref = std::tuple<byte const*, size_t>;
using code_iterator = byte const*;
struct NoteChannel {}; // FIXME: Use some log library?

27
evmjit/libevmjit/Compiler.cpp

@ -39,10 +39,10 @@ Compiler::Compiler(Options const& _options):
Type::init(m_builder.getContext());
}
void Compiler::createBasicBlocks(bytes const& _bytecode)
void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd)
{
/// Helper function that skips push data and finds next iterator (can be the end)
auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end)
auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end)
{
static const auto push1 = static_cast<size_t>(Instruction::PUSH1);
static const auto push32 = static_cast<size_t>(Instruction::PUSH32);
@ -52,11 +52,11 @@ void Compiler::createBasicBlocks(bytes const& _bytecode)
return _curr + offset;
};
auto begin = _bytecode.begin();
auto begin = _codeBegin; // begin of current block
bool nextJumpDest = false;
for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next)
for (auto curr = begin, next = begin; curr != _codeEnd; curr = next)
{
next = skipPushDataAndGetNext(curr, _bytecode.end());
next = skipPushDataAndGetNext(curr, _codeEnd);
bool isEnd = false;
switch (Instruction(*curr))
@ -77,13 +77,13 @@ void Compiler::createBasicBlocks(bytes const& _bytecode)
break;
}
assert(next <= _bytecode.end());
if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST)
assert(next <= _codeEnd);
if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST)
isEnd = true;
if (isEnd)
{
auto beginIdx = begin - _bytecode.begin();
auto beginIdx = begin - _codeBegin;
m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx),
std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest));
nextJumpDest = false;
@ -124,7 +124,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock()
return m_badJumpBlock->llvm();
}
std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::string const& _id)
std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id)
{
auto compilationStartTime = std::chrono::high_resolution_clock::now();
auto module = std::unique_ptr<llvm::Module>(new llvm::Module(_id, m_builder.getContext()));
@ -138,7 +138,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc);
m_builder.SetInsertPoint(entryBlock);
createBasicBlocks(_bytecode);
m_codeBegin = _begin;
createBasicBlocks(_begin, _end);
// Init runtime structures.
RuntimeManager runtimeManager(m_builder);
@ -156,7 +157,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
auto iterCopy = basicBlockPairIt;
++iterCopy;
auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock);
compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock);
}
// Code for special blocks:
@ -223,7 +224,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
}
void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager,
void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager,
Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock)
{
if (!_nextBasicBlock) // this is the last block in the code
@ -622,7 +623,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::PC:
{
auto value = Constant::get(it - _bytecode.begin());
auto value = Constant::get(it - m_codeBegin);
stack.push(value);
break;
}

8
evmjit/libevmjit/Compiler.h

@ -33,13 +33,13 @@ public:
Compiler(Options const& _options);
std::unique_ptr<llvm::Module> compile(bytes const& _bytecode, std::string const& _id);
std::unique_ptr<llvm::Module> compile(code_iterator _begin, code_iterator _end, std::string const& _id);
private:
void createBasicBlocks(bytes const& _bytecode);
void createBasicBlocks(code_iterator _begin, code_iterator _end);
void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock);
void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock);
llvm::BasicBlock* getJumpTableBlock();
@ -76,6 +76,8 @@ private:
/// Main program function
llvm::Function* m_mainFunc = nullptr;
code_iterator m_codeBegin = {};
};
}

15
evmjit/libevmjit/ExecutionEngine.cpp

@ -52,15 +52,15 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime)
return returnCode;
}
std::string codeHash(bytes const& _code)
std::string codeHash(code_iterator _begin, code_iterator _end)
{
uint32_t hash = 0;
for (auto b : _code)
std::for_each(_begin, _end, [&hash](decltype(*_begin) b)
{
hash += b;
hash += (hash << 10);
hash ^= (hash >> 6);
}
});
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
@ -69,13 +69,16 @@ std::string codeHash(bytes const& _code)
}
ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env)
ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
{
static std::unique_ptr<llvm::ExecutionEngine> ee; // TODO: Use Managed Objects from LLVM?
static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE);
static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF);
auto mainFuncName = codeHash(_code);
auto codeBegin = _data->code;
auto codeEnd = codeBegin + _data->codeSize;
assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code?
auto mainFuncName = codeHash(codeBegin, codeEnd);
EntryFuncPtr entryFuncPtr{};
Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls
@ -89,7 +92,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en
if (objectCache)
module = Cache::getObject(mainFuncName);
if (!module)
module = Compiler({}).compile(_code, mainFuncName);
module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName);
if (debugDumpModule)
module->dump();
if (!ee)

2
evmjit/libevmjit/ExecutionEngine.h

@ -16,7 +16,7 @@ public:
ExecutionEngine(ExecutionEngine const&) = delete;
void operator=(ExecutionEngine) = delete;
EXPORT ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env);
EXPORT ReturnCode run(RuntimeData* _data, Env* _env);
/// Reference to returned data (RETURN opcode used)
bytes_ref returnData;

4
evmjit/libevmjit/Instruction.cpp

@ -9,7 +9,7 @@ namespace eth
namespace jit
{
llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
llvm::APInt readPushData(code_iterator& _curr, code_iterator _end)
{
auto pushInst = *_curr;
assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);
@ -26,7 +26,7 @@ llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _en
return value;
}
void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
void skipPushData(code_iterator& _curr, code_iterator _end)
{
auto pushInst = *_curr;
assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);

4
evmjit/libevmjit/Instruction.h

@ -161,11 +161,11 @@ enum class Instruction: uint8_t
/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it
/// Reading out of bytecode means reading 0
/// @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(code_iterator& _curr, code_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);
void skipPushData(code_iterator& _curr, code_iterator _end);
#define ANY_PUSH PUSH1: \
case Instruction::PUSH2: \

11
evmjit/libevmjit/interface.cpp

@ -12,6 +12,7 @@ using namespace dev::eth::jit;
EXPORT void* evmjit_create() noexcept
{
// TODO: Make sure ExecutionEngine constructor does not throw
return new(std::nothrow) ExecutionEngine;
}
@ -22,14 +23,12 @@ EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept
EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept
{
if (!_engine || !_data)
return static_cast<int>(ReturnCode::UnexpectedException);
try
{
auto codePtr = _data->code;
auto codeSize = _data->codeSize;
bytes bytecode;
bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize);
auto returnCode = _engine->run(bytecode, _data, _env);
auto returnCode = _engine->run(_data, _env);
return static_cast<int>(returnCode);
}
catch(...)

Loading…
Cancel
Save