Browse Source

Simplify ExecutionEngine interface. It is possible to pass raw code instead of LLVM module.

cl-refactor
Paweł Bylica 10 years ago
parent
commit
2fd2446330
  1. 2
      evmcc/evmcc.cpp
  2. 10
      libevmjit-cpp/JitVM.cpp
  3. 3
      libevmjit-cpp/JitVM.h
  4. 27
      libevmjit/Common.h
  5. 20
      libevmjit/ExecutionEngine.cpp
  6. 15
      libevmjit/ExecutionEngine.h
  7. 4
      libevmjit/Ext.cpp
  8. 5
      libevmjit/Runtime.h
  9. 8
      libevmjit/RuntimeData.h
  10. 6
      libevmjit/Stack.cpp
  11. 12
      libevmjit/Type.h
  12. 14
      libevmjit/Utils.h

2
evmcc/evmcc.cpp

@ -171,7 +171,7 @@ int main(int argc, char** argv)
if (options.count("interpret")) if (options.count("interpret"))
{ {
auto engine = eth::jit::ExecutionEngine(); eth::jit::ExecutionEngine engine;
u256 gas = initialGas; u256 gas = initialGas;
// Create fake ExtVM interface // Create fake ExtVM interface

10
libevmjit-cpp/JitVM.cpp

@ -1,9 +1,8 @@
#include "JitVM.h" #include "JitVM.h"
#include <libevm/VMFace.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <evmjit/libevmjit/ExecutionEngine.h> #include <evmjit/libevmjit/ExecutionEngine.h>
#include <evmjit/libevmjit/Compiler.h> #include <evmjit/libevmjit/Utils.h>
namespace dev namespace dev
{ {
@ -14,9 +13,6 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
{ {
using namespace jit; using namespace jit;
Compiler::Options defaultOptions;
auto module = Compiler(defaultOptions).compile(_ext.code);
RuntimeData data = {}; RuntimeData data = {};
#define set(INDEX, VALUE) data.elems[INDEX] = eth2llvm(VALUE) #define set(INDEX, VALUE) data.elems[INDEX] = eth2llvm(VALUE)
@ -40,9 +36,9 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
ExecutionEngine engine; ExecutionEngine engine;
auto env = reinterpret_cast<Env*>(&_ext); auto env = reinterpret_cast<Env*>(&_ext);
auto exitCode = engine.run(std::move(module), &data, env); auto exitCode = engine.run(_ext.code, &data, env);
switch (static_cast<ReturnCode>(exitCode)) switch (exitCode)
{ {
case ReturnCode::BadJumpDestination: case ReturnCode::BadJumpDestination:
BOOST_THROW_EXCEPTION(BadJumpDestination()); BOOST_THROW_EXCEPTION(BadJumpDestination());

3
libevmjit-cpp/JitVM.h

@ -1,9 +1,6 @@
#pragma once #pragma once
#include <libdevcore/Common.h>
#include <libevm/VMFace.h> #include <libevm/VMFace.h>
#include <libevm/ExtVMFace.h>
namespace dev namespace dev
{ {

27
libevmjit/Common.h

@ -17,6 +17,33 @@ using bigint = boost::multiprecision::cpp_int;
struct NoteChannel {}; // FIXME: Use some log library? struct NoteChannel {}; // FIXME: Use some log library?
enum class ReturnCode
{
Stop = 0,
Return = 1,
Suicide = 2,
BadJumpDestination = 101,
OutOfGas = 102,
StackTooSmall = 103,
BadInstruction = 104,
LLVMConfigError = 201,
LLVMCompileError = 202,
LLVMLinkError = 203,
};
/// Representation of 256-bit value binary compatible with LLVM i256
// TODO: Replace with h256
struct i256
{
uint64_t a;
uint64_t b;
uint64_t c;
uint64_t d;
};
static_assert(sizeof(i256) == 32, "Wrong i265 size");
} }
} }
} }

20
libevmjit/ExecutionEngine.cpp

@ -24,6 +24,7 @@
#include "Memory.h" #include "Memory.h"
#include "Stack.h" #include "Stack.h"
#include "Type.h" #include "Type.h"
#include "Compiler.h"
namespace dev namespace dev
{ {
@ -32,12 +33,19 @@ namespace eth
namespace jit namespace jit
{ {
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, RuntimeData* _data, Env* _env) ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env)
{
Compiler::Options defaultOptions;
auto module = Compiler(defaultOptions).compile(_code);
return run(std::move(module), _data, _env);
}
ReturnCode ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, RuntimeData* _data, Env* _env)
{ {
auto module = _module.get(); // Keep ownership of the module in _module auto module = _module.get(); // Keep ownership of the module in _module
llvm::sys::PrintStackTraceOnErrorSignal(); llvm::sys::PrintStackTraceOnErrorSignal();
static const auto program = "evmcc"; static const auto program = "EVM JIT";
llvm::PrettyStackTraceProgram X(1, &program); llvm::PrettyStackTraceProgram X(1, &program);
auto&& context = llvm::getGlobalContext(); auto&& context = llvm::getGlobalContext();
@ -66,10 +74,10 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, RuntimeData* _da
auto exec = std::unique_ptr<llvm::ExecutionEngine>(builder.create()); auto exec = std::unique_ptr<llvm::ExecutionEngine>(builder.create());
if (!exec) if (!exec)
return -1; // FIXME: Handle internal errors return ReturnCode::LLVMConfigError;
_module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
auto finalizationStartTime = std::chrono::high_resolution_clock::now(); // FIXME: It's not compilation time auto finalizationStartTime = std::chrono::high_resolution_clock::now();
exec->finalizeObject(); exec->finalizeObject();
auto finalizationEndTime = std::chrono::high_resolution_clock::now(); auto finalizationEndTime = std::chrono::high_resolution_clock::now();
clog(JIT) << " + " << std::chrono::duration_cast<std::chrono::milliseconds>(finalizationEndTime - finalizationStartTime).count(); clog(JIT) << " + " << std::chrono::duration_cast<std::chrono::milliseconds>(finalizationEndTime - finalizationStartTime).count();
@ -78,7 +86,7 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, RuntimeData* _da
auto entryFunc = module->getFunction("main"); auto entryFunc = module->getFunction("main");
if (!entryFunc) if (!entryFunc)
return -2; // FIXME: Handle internal errors return ReturnCode::LLVMLinkError;
ReturnCode returnCode; ReturnCode returnCode;
std::jmp_buf buf; std::jmp_buf buf;
@ -111,7 +119,7 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, RuntimeData* _da
clog(JIT) << "\n"; clog(JIT) << "\n";
return static_cast<int>(returnCode); return returnCode;
} }
} }

15
libevmjit/ExecutionEngine.h

@ -1,9 +1,11 @@
#pragma once #pragma once
#include <llvm/IR/Module.h> namespace llvm
{
class Module;
}
#include "Runtime.h" #include "RuntimeData.h"
namespace dev namespace dev
{ {
@ -15,9 +17,12 @@ namespace jit
class ExecutionEngine class ExecutionEngine
{ {
public: public:
// FIXME: constructor? ExecutionEngine(); ExecutionEngine() = default;
ExecutionEngine(ExecutionEngine const&) = delete;
void operator=(ExecutionEngine) = delete;
int run(std::unique_ptr<llvm::Module> module, RuntimeData* _data, Env* _env); ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env);
ReturnCode run(std::unique_ptr<llvm::Module> module, RuntimeData* _data, Env* _env);
bytes returnData; bytes returnData;
}; };

4
libevmjit/Ext.cpp

@ -65,7 +65,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan):
m_getExtCode = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, getExtCodeArgsTypes, false), Linkage::ExternalLinkage, "env_getExtCode", module); m_getExtCode = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, getExtCodeArgsTypes, false), Linkage::ExternalLinkage, "env_getExtCode", module);
// Helper function, not client Env interface // Helper function, not client Env interface
llvm::Type* callDataLoadArgsTypes[] = {Type::RuntimePtr, Type::WordPtr, Type::WordPtr}; llvm::Type* callDataLoadArgsTypes[] = {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr};
m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, callDataLoadArgsTypes, false), Linkage::ExternalLinkage, "ext_calldataload", module); m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, callDataLoadArgsTypes, false), Linkage::ExternalLinkage, "ext_calldataload", module);
} }
@ -86,7 +86,7 @@ void Ext::sstore(llvm::Value* _index, llvm::Value* _value)
llvm::Value* Ext::calldataload(llvm::Value* _index) llvm::Value* Ext::calldataload(llvm::Value* _index)
{ {
m_builder.CreateStore(_index, m_args[0]); m_builder.CreateStore(_index, m_args[0]);
createCall(m_calldataload, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); createCall(m_calldataload, getRuntimeManager().getDataPtr(), m_args[0], m_args[1]);
auto ret = m_builder.CreateLoad(m_args[1]); auto ret = m_builder.CreateLoad(m_args[1]);
return Endianness::toNative(m_builder, ret); return Endianness::toNative(m_builder, ret);
} }

5
libevmjit/Runtime.h

@ -27,9 +27,6 @@ using StackImpl = std::vector<i256>;
using MemoryImpl = bytes; using MemoryImpl = bytes;
using JmpBufRef = decltype(&jmp_buf{}[0]); using JmpBufRef = decltype(&jmp_buf{}[0]);
/// VM Environment (ExtVM) opaque type
struct Env;
class Runtime class Runtime
{ {
public: public:
@ -38,8 +35,6 @@ public:
Runtime(const Runtime&) = delete; Runtime(const Runtime&) = delete;
void operator=(const Runtime&) = delete; void operator=(const Runtime&) = delete;
RuntimeData* getDataPtr() { return &m_data; } // FIXME: Remove
StackImpl& getStack() { return m_stack; } StackImpl& getStack() { return m_stack; }
MemoryImpl& getMemory() { return m_memory; } MemoryImpl& getMemory() { return m_memory; }
Env* getEnvPtr() { return &m_env; } Env* getEnvPtr() { return &m_env; }

8
libevmjit/RuntimeData.h

@ -1,9 +1,6 @@
#pragma once #pragma once
#include <csetjmp> #include "Common.h"
#include "Utils.h"
namespace dev namespace dev
@ -43,6 +40,9 @@ struct RuntimeData
byte const* code; byte const* code;
}; };
/// VM Environment (ExtVM) opaque type
struct Env;
} }
} }
} }

6
libevmjit/Stack.cpp

@ -109,7 +109,7 @@ extern "C"
*(stack.rbegin() + _index) = *_word; *(stack.rbegin() + _index) = *_word;
} }
EXPORT void ext_calldataload(Runtime* _rt, i256* _index, byte* o_value) EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value)
{ {
// It asumes all indexes are less than 2^64 // It asumes all indexes are less than 2^64
@ -117,8 +117,8 @@ extern "C"
if (_index->b || _index->c || _index->d) // if bigger that 2^64 if (_index->b || _index->c || _index->d) // if bigger that 2^64
index = std::numeric_limits<decltype(index)>::max(); // set max to fill with 0 leter index = std::numeric_limits<decltype(index)>::max(); // set max to fill with 0 leter
auto data = _rt->getDataPtr()->callData; auto data = _rtData->callData;
auto size = _rt->getDataPtr()->elems[RuntimeData::CallDataSize].a; auto size = _rtData->elems[RuntimeData::CallDataSize].a;
for (auto i = 0; i < 32; ++i) for (auto i = 0; i < 32; ++i)
{ {
if (index < size) if (index < size)

12
libevmjit/Type.h

@ -39,18 +39,6 @@ struct Type
static void init(llvm::LLVMContext& _context); static void init(llvm::LLVMContext& _context);
}; };
enum class ReturnCode
{
Stop = 0,
Return = 1,
Suicide = 2,
BadJumpDestination = 101,
OutOfGas = 102,
StackTooSmall = 103,
BadInstruction = 104,
};
struct Constant struct Constant
{ {
/// Returns word-size constant /// Returns word-size constant

14
libevmjit/Utils.h

@ -1,8 +1,5 @@
#pragma once #pragma once
#include <llvm/IR/IRBuilder.h>
#include "Common.h" #include "Common.h"
namespace dev namespace dev
@ -16,17 +13,6 @@ struct JIT: public NoteChannel { static const char* name() { return "JIT"; } };
#define clog(CHANNEL) std::cerr #define clog(CHANNEL) std::cerr
/// Representation of 256-bit value binary compatible with LLVM i256
// TODO: Replace with h256
struct i256
{
uint64_t a;
uint64_t b;
uint64_t c;
uint64_t d;
};
static_assert(sizeof(i256) == 32, "Wrong i265 size");
u256 llvm2eth(i256); u256 llvm2eth(i256);
i256 eth2llvm(u256); i256 eth2llvm(u256);

Loading…
Cancel
Save