From 5046dd4bb0e5ad2611ede4f7a1ed8d8cfb815ff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 18 May 2015 13:59:16 +0200 Subject: [PATCH] EVM JIT C++ interface in one header. --- evmjit/include/evmjit/DataTypes.h | 68 ----------- evmjit/include/evmjit/JIT.h | 160 +++++++++++++++++++++++++- evmjit/libevmjit-cpp/Env.cpp | 1 - evmjit/libevmjit-cpp/JitVM.cpp | 1 - evmjit/libevmjit-cpp/JitVM.h | 2 +- evmjit/libevmjit-cpp/Utils.h | 2 +- evmjit/libevmjit/Arith256.cpp | 1 - evmjit/libevmjit/BasicBlock.h | 6 +- evmjit/libevmjit/CMakeLists.txt | 6 +- evmjit/libevmjit/Common.h | 8 +- evmjit/libevmjit/Compiler.h | 1 - evmjit/libevmjit/ExecutionContext.cpp | 33 ------ evmjit/libevmjit/ExecutionContext.h | 110 ------------------ evmjit/libevmjit/Instruction.h | 2 +- evmjit/libevmjit/JIT.cpp | 25 +++- evmjit/libevmjit/RuntimeManager.h | 1 - evmjit/libevmjit/Type.h | 2 +- evmjit/libevmjit/interface.cpp | 1 - 18 files changed, 192 insertions(+), 238 deletions(-) delete mode 100644 evmjit/include/evmjit/DataTypes.h delete mode 100644 evmjit/libevmjit/ExecutionContext.cpp delete mode 100644 evmjit/libevmjit/ExecutionContext.h diff --git a/evmjit/include/evmjit/DataTypes.h b/evmjit/include/evmjit/DataTypes.h deleted file mode 100644 index 6f06a81d6..000000000 --- a/evmjit/include/evmjit/DataTypes.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include -#include - -#ifdef _MSC_VER -#define EXPORT __declspec(dllexport) -#define _ALLOW_KEYWORD_MACROS -#define noexcept throw() -#else -#define EXPORT -#endif - -namespace dev -{ -namespace evmjit -{ - -using byte = uint8_t; -using bytes_ref = std::tuple; -using code_iterator = byte const*; - -struct h256 -{ - uint64_t words[4]; -}; - -inline bool operator==(h256 _h1, h256 _h2) -{ - return _h1.words[0] == _h2.words[0] && - _h1.words[1] == _h2.words[1] && - _h1.words[2] == _h2.words[2] && - _h1.words[3] == _h2.words[3]; -} - -/// Representation of 256-bit value binary compatible with LLVM i256 -struct i256 -{ - uint64_t a = 0; - uint64_t b = 0; - uint64_t c = 0; - uint64_t d = 0; - - i256() = default; - i256(h256 _h) - { - a = _h.words[0]; - b = _h.words[1]; - c = _h.words[2]; - d = _h.words[3]; - } -}; - -} -} - -namespace std -{ -template<> struct hash -{ - size_t operator()(dev::evmjit::h256 const& _h) const - { - /// This implementation expects the argument to be a full 256-bit Keccak hash. - /// It does nothing more than returning a slice of the input hash. - return static_cast(_h.words[0]); - }; -}; -} diff --git a/evmjit/include/evmjit/JIT.h b/evmjit/include/evmjit/JIT.h index 58c19b426..cbf0e6e78 100644 --- a/evmjit/include/evmjit/JIT.h +++ b/evmjit/include/evmjit/JIT.h @@ -1,13 +1,153 @@ #pragma once -#include "evmjit/DataTypes.h" +#include +#include + +#ifdef _MSC_VER +#define EXPORT __declspec(dllexport) +#define _ALLOW_KEYWORD_MACROS +#define noexcept throw() +#else +#define EXPORT +#endif namespace dev { namespace evmjit { -enum class ReturnCode; -class ExecutionContext; + +using byte = uint8_t; +using bytes_ref = std::tuple; + +struct h256 +{ + uint64_t words[4]; +}; + +inline bool operator==(h256 _h1, h256 _h2) +{ + return _h1.words[0] == _h2.words[0] && + _h1.words[1] == _h2.words[1] && + _h1.words[2] == _h2.words[2] && + _h1.words[3] == _h2.words[3]; +} + +/// Representation of 256-bit value binary compatible with LLVM i256 +struct i256 +{ + uint64_t a = 0; + uint64_t b = 0; + uint64_t c = 0; + uint64_t d = 0; + + i256() = default; + i256(h256 _h) + { + a = _h.words[0]; + b = _h.words[1]; + c = _h.words[2]; + d = _h.words[3]; + } +}; + +struct RuntimeData +{ + enum Index + { + Gas, + GasPrice, + CallData, + CallDataSize, + Address, + Caller, + Origin, + CallValue, + CoinBase, + Difficulty, + GasLimit, + Number, + Timestamp, + Code, + CodeSize, + + SuicideDestAddress = Address, ///< Suicide balance destination address + ReturnData = CallData, ///< Return data pointer (set only in case of RETURN) + ReturnDataSize = CallDataSize, ///< Return data size (set only in case of RETURN) + }; + + int64_t gas = 0; + int64_t gasPrice = 0; + byte const* callData = nullptr; + uint64_t callDataSize = 0; + i256 address; + i256 caller; + i256 origin; + i256 callValue; + i256 coinBase; + i256 difficulty; + i256 gasLimit; + uint64_t number = 0; + int64_t timestamp = 0; + byte const* code = nullptr; + uint64_t codeSize = 0; + h256 codeHash; +}; + +/// VM Environment (ExtVM) opaque type +struct Env; + +enum class ReturnCode +{ + // Success codes + Stop = 0, + Return = 1, + Suicide = 2, + + // Standard error codes + OutOfGas = -1, + StackUnderflow = -2, + BadJumpDestination = -3, + BadInstruction = -4, + Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected + + // Internal error codes + LLVMConfigError = -101, + LLVMCompileError = -102, + LLVMLinkError = -103, + + UnexpectedException = -111, + + LinkerWorkaround = -299, +}; + +class ExecutionContext +{ +public: + ExecutionContext() = default; + ExecutionContext(RuntimeData& _data, Env* _env) { init(_data, _env); } + ExecutionContext(ExecutionContext const&) = delete; + ExecutionContext& operator=(ExecutionContext const&) = delete; + EXPORT ~ExecutionContext(); + + void init(RuntimeData& _data, Env* _env) { m_data = &_data; m_env = _env; } + + byte const* code() const { return m_data->code; } + uint64_t codeSize() const { return m_data->codeSize; } + h256 const& codeHash() const { return m_data->codeHash; } + + bytes_ref getReturnData() const; + +private: + RuntimeData* m_data = nullptr; ///< Pointer to data. Expected by compiled contract. + Env* m_env = nullptr; ///< Pointer to environment proxy. Expected by compiled contract. + byte* m_memData = nullptr; + uint64_t m_memSize = 0; + uint64_t m_memCap = 0; + +public: + /// Reference to returned data (RETURN opcode used) + bytes_ref returnData; +}; class JIT { @@ -24,3 +164,17 @@ public: } } + +namespace std +{ +template<> struct hash +{ + size_t operator()(dev::evmjit::h256 const& _h) const + { + /// This implementation expects the argument to be a full 256-bit Keccak hash. + /// It does nothing more than returning a slice of the input hash. + return static_cast(_h.words[0]); + }; +}; +} + diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index a5a60f48c..366f5704a 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "Utils.h" diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index d40aa2b1c..e9559026a 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include "Utils.h" diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h index 5bba7b5f0..fdc87248a 100644 --- a/evmjit/libevmjit-cpp/JitVM.h +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include namespace dev { diff --git a/evmjit/libevmjit-cpp/Utils.h b/evmjit/libevmjit-cpp/Utils.h index f9b9b2ef4..d52861fcc 100644 --- a/evmjit/libevmjit-cpp/Utils.h +++ b/evmjit/libevmjit-cpp/Utils.h @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace dev { diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 9d6494730..6c1f8f160 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -8,7 +8,6 @@ #include #include "preprocessor/llvm_includes_end.h" -#include "evmjit/DataTypes.h" #include "Type.h" #include "Endianness.h" #include "Utils.h" diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index 9960a0d1c..321499196 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -2,8 +2,7 @@ #include - -#include "evmjit/DataTypes.h" +#include "Common.h" #include "Stack.h" namespace dev @@ -12,9 +11,8 @@ namespace eth { namespace jit { - -using instr_idx = uint64_t; using namespace evmjit; +using instr_idx = uint64_t; class BasicBlock { diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt index 525030285..80108e15b 100644 --- a/evmjit/libevmjit/CMakeLists.txt +++ b/evmjit/libevmjit/CMakeLists.txt @@ -1,22 +1,20 @@ set(TARGET_NAME evmjit) set(SOURCES + JIT.cpp ${EVMJIT_INCLUDE_DIR}/evmjit/JIT.h Arith256.cpp Arith256.h Array.cpp Array.h BasicBlock.cpp BasicBlock.h Cache.cpp Cache.h - Common.h + Common.h Compiler.cpp Compiler.h CompilerHelper.cpp CompilerHelper.h - ${EVMJIT_INCLUDE_DIR}/evmjit/DataTypes.h Endianness.cpp Endianness.h ExecStats.cpp ExecStats.h - ExecutionContext.cpp ExecutionContext.h Ext.cpp Ext.h GasMeter.cpp GasMeter.h Instruction.cpp Instruction.h interface.cpp interface.h - JIT.cpp ${EVMJIT_INCLUDE_DIR}/evmjit/JIT.h Memory.cpp Memory.h Optimizer.cpp Optimizer.h RuntimeManager.cpp RuntimeManager.h diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index 5067f4fb1..4a6d7b4f3 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -1,18 +1,16 @@ #pragma once -#include #include namespace dev { -namespace eth +namespace evmjit { -namespace jit{ - +using byte = uint8_t; +using code_iterator = byte const*; #define UNTESTED assert(false) } } -} diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index 9b9fe7160..0b31ae0f2 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/evmjit/libevmjit/Compiler.h @@ -1,6 +1,5 @@ #pragma once -#include "Common.h" #include "BasicBlock.h" namespace dev diff --git a/evmjit/libevmjit/ExecutionContext.cpp b/evmjit/libevmjit/ExecutionContext.cpp deleted file mode 100644 index fab6fad87..000000000 --- a/evmjit/libevmjit/ExecutionContext.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "ExecutionContext.h" -#include - -namespace dev -{ -namespace evmjit -{ - -extern "C" void ext_free(void* _data) noexcept; - -ExecutionContext::~ExecutionContext() -{ - if (m_memData) - ext_free(m_memData); // Use helper free to check memory leaks -} - -bytes_ref ExecutionContext::getReturnData() const -{ - auto data = m_data->callData; - auto size = static_cast(m_data->callDataSize); - - if (data < m_memData || data >= m_memData + m_memSize || size == 0) - { - assert(size == 0); // data can be an invalid pointer only if size is 0 - m_data->callData = nullptr; - return {}; - } - - return bytes_ref{data, size}; -} - -} -} diff --git a/evmjit/libevmjit/ExecutionContext.h b/evmjit/libevmjit/ExecutionContext.h deleted file mode 100644 index fd7e8f11a..000000000 --- a/evmjit/libevmjit/ExecutionContext.h +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include "evmjit/DataTypes.h" - -namespace dev -{ -namespace evmjit -{ - -struct RuntimeData -{ - enum Index - { - Gas, - GasPrice, - CallData, - CallDataSize, - Address, - Caller, - Origin, - CallValue, - CoinBase, - Difficulty, - GasLimit, - Number, - Timestamp, - Code, - CodeSize, - - SuicideDestAddress = Address, ///< Suicide balance destination address - ReturnData = CallData, ///< Return data pointer (set only in case of RETURN) - ReturnDataSize = CallDataSize, ///< Return data size (set only in case of RETURN) - }; - - int64_t gas = 0; - int64_t gasPrice = 0; - byte const* callData = nullptr; - uint64_t callDataSize = 0; - i256 address; - i256 caller; - i256 origin; - i256 callValue; - i256 coinBase; - i256 difficulty; - i256 gasLimit; - uint64_t number = 0; - int64_t timestamp = 0; - byte const* code = nullptr; - uint64_t codeSize = 0; - h256 codeHash; -}; - -/// VM Environment (ExtVM) opaque type -struct Env; - -enum class ReturnCode -{ - // Success codes - Stop = 0, - Return = 1, - Suicide = 2, - - // Standard error codes - OutOfGas = -1, - StackUnderflow = -2, - BadJumpDestination = -3, - BadInstruction = -4, - Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected - - // Internal error codes - LLVMConfigError = -101, - LLVMCompileError = -102, - LLVMLinkError = -103, - - UnexpectedException = -111, - - LinkerWorkaround = -299, -}; - -class ExecutionContext -{ -public: - ExecutionContext() = default; - ExecutionContext(RuntimeData& _data, Env* _env) { init(_data, _env); } - ExecutionContext(ExecutionContext const&) = delete; - ExecutionContext& operator=(ExecutionContext const&) = delete; - EXPORT ~ExecutionContext(); - - void init(RuntimeData& _data, Env* _env) { m_data = &_data; m_env = _env; } - - byte const* code() const { return m_data->code; } - uint64_t codeSize() const { return m_data->codeSize; } - h256 const& codeHash() const { return m_data->codeHash; } - - bytes_ref getReturnData() const; - -private: - RuntimeData* m_data = nullptr; ///< Pointer to data. Expected by compiled contract. - Env* m_env = nullptr; ///< Pointer to environment proxy. Expected by compiled contract. - byte* m_memData = nullptr; - uint64_t m_memSize = 0; - uint64_t m_memCap = 0; - -public: - /// Reference to returned data (RETURN opcode used) - bytes_ref returnData; -}; - -} -} diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h index 2da3c4c65..89add0958 100644 --- a/evmjit/libevmjit/Instruction.h +++ b/evmjit/libevmjit/Instruction.h @@ -1,6 +1,6 @@ #pragma once -#include "evmjit/DataTypes.h" +#include "Common.h" namespace llvm { diff --git a/evmjit/libevmjit/JIT.cpp b/evmjit/libevmjit/JIT.cpp index c4ce24ee2..f8b4d4c00 100644 --- a/evmjit/libevmjit/JIT.cpp +++ b/evmjit/libevmjit/JIT.cpp @@ -10,7 +10,6 @@ #include #include "preprocessor/llvm_includes_end.h" -#include "ExecutionContext.h" #include "Compiler.h" #include "Optimizer.h" #include "Cache.h" @@ -211,5 +210,29 @@ ReturnCode JIT::exec(ExecutionContext& _context) return returnCode; } + +extern "C" void ext_free(void* _data) noexcept; + +ExecutionContext::~ExecutionContext() +{ + if (m_memData) + ext_free(m_memData); // Use helper free to check memory leaks +} + +bytes_ref ExecutionContext::getReturnData() const +{ + auto data = m_data->callData; + auto size = static_cast(m_data->callDataSize); + + if (data < m_memData || data >= m_memData + m_memSize || size == 0) + { + assert(size == 0); // data can be an invalid pointer only if size is 0 + m_data->callData = nullptr; + return {}; + } + + return bytes_ref{data, size}; +} + } } diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index 088611093..5ce749933 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -1,6 +1,5 @@ #pragma once -#include "ExecutionContext.h" #include "CompilerHelper.h" #include "Type.h" #include "Instruction.h" diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index b1b6d1ad4..b54d101cb 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -6,7 +6,7 @@ #include #include "preprocessor/llvm_includes_end.h" // FIXME: LLVM 3.7: check if needed -#include "ExecutionContext.h" // FIXME: crappy dependence +#include "evmjit/JIT.h" // ReturnCode namespace dev { diff --git a/evmjit/libevmjit/interface.cpp b/evmjit/libevmjit/interface.cpp index 34491e772..7136f6798 100644 --- a/evmjit/libevmjit/interface.cpp +++ b/evmjit/libevmjit/interface.cpp @@ -1,5 +1,4 @@ #include "evmjit/JIT.h" -#include "ExecutionContext.h" extern "C" {