mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
Simplify ExecutionEngine interface. It is possible to pass raw code instead of LLVM module.
This commit is contained in:
parent
bd40486c7b
commit
2fd2446330
12 changed files with 64 additions and 62 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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…
Reference in a new issue