Merge commit '3dcf30463b961e3fe47b48b2024bbf3d5b5ce675' into evmjit

Conflicts:
	evmjit/CMakeLists.txt
	evmjit/libevmjit-cpp/CMakeLists.txt
	evmjit/libevmjit-cpp/Env.cpp
	evmjit/libevmjit-cpp/JitVM.cpp
	evmjit/libevmjit/Arith256.cpp
	evmjit/libevmjit/BasicBlock.cpp
	evmjit/libevmjit/BasicBlock.h
	evmjit/libevmjit/CMakeLists.txt
	evmjit/libevmjit/Cache.cpp
	evmjit/libevmjit/Common.h
	evmjit/libevmjit/Compiler.cpp
	evmjit/libevmjit/ExecutionEngine.cpp
	evmjit/libevmjit/ExecutionEngine.h
	evmjit/libevmjit/Ext.cpp
	evmjit/libevmjit/Ext.h
	evmjit/libevmjit/Runtime.cpp
	evmjit/libevmjit/Runtime.h
	evmjit/libevmjit/RuntimeData.h
	evmjit/libevmjit/Utils.cpp
	evmjit/libevmjit/Utils.h
	evmjit/libevmjit/interface.cpp
This commit is contained in:
Paweł Bylica 2015-01-20 15:17:12 +01:00
commit 3ef945a431
22 changed files with 365 additions and 179 deletions

View file

@ -4,17 +4,18 @@ project(evmjit)
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
else () else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -fPIC")
endif() endif()
if(APPLE) if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") # Do not allow unresovled symbols in shared library (default on linux)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
endif() endif()
# LLVM # LLVM
if(LLVM_DIR) # local LLVM build if(LLVM_DIR OR APPLE) # local LLVM build
find_package(LLVM REQUIRED CONFIG) find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
@ -28,11 +29,9 @@ else()
message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}") message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}")
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")
add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS) add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS)
link_directories(/usr/lib/llvm-3.5/lib)
endif() endif()
# Boost
find_package(Boost REQUIRED)
add_subdirectory(libevmjit) add_subdirectory(libevmjit)
if(EVMJIT_CPP) if(EVMJIT_CPP)

View file

@ -1,5 +1,8 @@
set(TARGET_NAME evmjit-cpp) set(TARGET_NAME evmjit-cpp)
# Boost
find_package(Boost REQUIRED)
set(SOURCES set(SOURCES
Env.cpp Env.cpp
JitVM.cpp JitVM.h JitVM.cpp JitVM.h

View file

@ -3,7 +3,7 @@
#include <libevm/FeeStructure.h> #include <libevm/FeeStructure.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include <evmjit/libevmjit/Utils.h> #include "Utils.h"
extern "C" extern "C"
{ {
@ -16,7 +16,6 @@ extern "C"
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
using jit::i256; using jit::i256;
using jit::eth2llvm;
EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value)
{ {
@ -89,7 +88,7 @@ extern "C"
*o_hash = hash; *o_hash = hash;
} }
EXPORT byte const* env_getExtCode(ExtVMFace* _env, h256* _addr256, uint64_t* o_size) EXPORT byte const* env_extcode(ExtVMFace* _env, h256* _addr256, uint64_t* o_size)
{ {
auto addr = right160(*_addr256); auto addr = right160(*_addr256);
auto& code = _env->codeAt(addr); auto& code = _env->codeAt(addr);

View file

@ -2,7 +2,7 @@
#include "JitVM.h" #include "JitVM.h"
#include <libevm/VM.h> #include <libevm/VM.h>
#include <evmjit/libevmjit/ExecutionEngine.h> #include <evmjit/libevmjit/ExecutionEngine.h>
#include <evmjit/libevmjit/Utils.h> #include "Utils.h"
namespace dev namespace dev
{ {
@ -13,19 +13,19 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
{ {
using namespace jit; using namespace jit;
m_data.set(RuntimeData::Gas, m_gas); m_data.elems[RuntimeData::Gas] = eth2llvm(m_gas);
m_data.set(RuntimeData::Address, fromAddress(_ext.myAddress)); m_data.elems[RuntimeData::Address] = eth2llvm(fromAddress(_ext.myAddress));
m_data.set(RuntimeData::Caller, fromAddress(_ext.caller)); m_data.elems[RuntimeData::Caller] = eth2llvm(fromAddress(_ext.caller));
m_data.set(RuntimeData::Origin, fromAddress(_ext.origin)); m_data.elems[RuntimeData::Origin] = eth2llvm(fromAddress(_ext.origin));
m_data.set(RuntimeData::CallValue, _ext.value); m_data.elems[RuntimeData::CallValue] = eth2llvm(_ext.value);
m_data.set(RuntimeData::CallDataSize, _ext.data.size()); m_data.elems[RuntimeData::CallDataSize] = eth2llvm(_ext.data.size());
m_data.set(RuntimeData::GasPrice, _ext.gasPrice); m_data.elems[RuntimeData::GasPrice] = eth2llvm(_ext.gasPrice);
m_data.set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress)); m_data.elems[RuntimeData::CoinBase] = eth2llvm(fromAddress(_ext.currentBlock.coinbaseAddress));
m_data.set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp); m_data.elems[RuntimeData::TimeStamp] = eth2llvm(_ext.currentBlock.timestamp);
m_data.set(RuntimeData::Number, _ext.currentBlock.number); m_data.elems[RuntimeData::Number] = eth2llvm(_ext.currentBlock.number);
m_data.set(RuntimeData::Difficulty, _ext.currentBlock.difficulty); m_data.elems[RuntimeData::Difficulty] = eth2llvm(_ext.currentBlock.difficulty);
m_data.set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); m_data.elems[RuntimeData::GasLimit] = eth2llvm(_ext.currentBlock.gasLimit);
m_data.set(RuntimeData::CodeSize, _ext.code.size()); m_data.elems[RuntimeData::CodeSize] = eth2llvm(_ext.code.size());
m_data.callData = _ext.data.data(); m_data.callData = _ext.data.data();
m_data.code = _ext.code.data(); m_data.code = _ext.code.data();
@ -34,7 +34,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
switch (exitCode) switch (exitCode)
{ {
case ReturnCode::Suicide: case ReturnCode::Suicide:
_ext.suicide(right160(m_data.get(RuntimeData::SuicideDestAddress))); _ext.suicide(right160(llvm2eth(m_data.elems[RuntimeData::SuicideDestAddress])));
break; break;
case ReturnCode::BadJumpDestination: case ReturnCode::BadJumpDestination:
@ -50,7 +50,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
} }
m_gas = llvm2eth(m_data.elems[RuntimeData::Gas]); m_gas = llvm2eth(m_data.elems[RuntimeData::Gas]);
return {m_engine.returnData.data(), m_engine.returnData.size()}; // TODO: This all bytesConstRef is problematic, review. return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)};
} }
} }

View file

@ -0,0 +1,38 @@
#pragma once
#include <evmjit/libevmjit/Common.h>
namespace dev
{
namespace eth
{
inline u256 llvm2eth(jit::i256 _i)
{
u256 u = 0;
u |= _i.d;
u <<= 64;
u |= _i.c;
u <<= 64;
u |= _i.b;
u <<= 64;
u |= _i.a;
return u;
}
inline jit::i256 eth2llvm(u256 _u)
{
jit::i256 i;
u256 mask = 0xFFFFFFFFFFFFFFFF;
i.a = static_cast<uint64_t>(_u & mask);
_u >>= 64;
i.b = static_cast<uint64_t>(_u & mask);
_u >>= 64;
i.c = static_cast<uint64_t>(_u & mask);
_u >>= 64;
i.d = static_cast<uint64_t>(_u & mask);
return i;
}
}
}

View file

@ -1,8 +1,10 @@
#include "Arith256.h" #include "Arith256.h"
#include "Runtime.h" #include "Runtime.h"
#include "Type.h" #include "Type.h"
#include "Endianness.h"
#include <llvm/IR/Function.h> #include <llvm/IR/Function.h>
#include <gmp.h>
namespace dev namespace dev
{ {
@ -63,6 +65,8 @@ llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2)
llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2)
{ {
//return Endianness::toNative(m_builder, binaryOp(m_div, Endianness::toBE(m_builder, _arg1), Endianness::toBE(m_builder, _arg2)));
return binaryOp(m_div, _arg1, _arg2); return binaryOp(m_div, _arg1, _arg2);
} }
@ -98,25 +102,104 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu
namespace namespace
{ {
using s256 = boost::multiprecision::int256_t; using uint128 = __uint128_t;
inline s256 u2s(u256 _u) // uint128 add(uint128 a, uint128 b) { return a + b; }
// uint128 mul(uint128 a, uint128 b) { return a * b; }
//
// uint128 mulq(uint64_t x, uint64_t y)
// {
// return (uint128)x * (uint128)y;
// }
//
// uint128 addc(uint64_t x, uint64_t y)
// {
// return (uint128)x * (uint128)y;
// }
struct uint256
{ {
static const bigint c_end = (bigint)1 << 256; uint64_t lo;
static const u256 c_send = (u256)1 << 255; uint64_t mid;
if (_u < c_send) uint128 hi;
return (s256)_u; };
else
return (s256)-(c_end - _u); // uint256 add(uint256 x, uint256 y)
// {
// auto lo = (uint128) x.lo + y.lo;
// auto mid = (uint128) x.mid + y.mid + (lo >> 64);
// return {lo, mid, x.hi + y.hi + (mid >> 64)};
// }
uint256 mul(uint256 x, uint256 y)
{
auto t1 = (uint128) x.lo * y.lo;
auto t2 = (uint128) x.lo * y.mid;
auto t3 = x.lo * y.hi;
auto t4 = (uint128) x.mid * y.lo;
auto t5 = (uint128) x.mid * y.mid;
auto t6 = x.mid * y.hi;
auto t7 = x.hi * y.lo;
auto t8 = x.hi * y.mid;
auto lo = (uint64_t) t1;
auto m1 = (t1 >> 64) + (uint64_t) t2;
auto m2 = (uint64_t) m1;
auto mid = (uint128) m2 + (uint64_t) t4;
auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7
+ (t8 << 64) + (m1 >> 64) + (mid >> 64);
return {lo, (uint64_t)mid, hi};
} }
inline u256 s2u(s256 _u) bool isZero(i256 const* _n)
{ {
static const bigint c_end = (bigint)1 << 256; return _n->a == 0 && _n->b == 0 && _n->c == 0 && _n->d == 0;
if (_u >= 0) }
return (u256)_u;
else const auto nLimbs = sizeof(i256) / sizeof(mp_limb_t);
return (u256)(c_end + _u);
// FIXME: Not thread-safe
static mp_limb_t mod_limbs[] = {0, 0, 0, 0, 1};
static_assert(sizeof(mod_limbs) / sizeof(mod_limbs[0]) == nLimbs + 1, "mp_limb_t size mismatch");
static const mpz_t mod{nLimbs + 1, nLimbs + 1, &mod_limbs[0]};
static mp_limb_t tmp_limbs[nLimbs + 2];
static mpz_t tmp{nLimbs + 2, 0, &tmp_limbs[0]};
int countLimbs(i256 const* _n)
{
static const auto limbsInWord = sizeof(_n->a) / sizeof(mp_limb_t);
static_assert(limbsInWord == 1, "E?");
int l = nLimbs;
if (_n->d != 0) return l;
l -= limbsInWord;
if (_n->c != 0) return l;
l -= limbsInWord;
if (_n->b != 0) return l;
l -= limbsInWord;
if (_n->a != 0) return l;
return 0;
}
void u2s(mpz_t _u)
{
if (static_cast<std::make_signed<mp_limb_t>::type>(_u->_mp_d[nLimbs - 1]) < 0)
{
mpz_sub(tmp, mod, _u);
mpz_set(_u, tmp);
_u->_mp_size = -_u->_mp_size;
}
}
void s2u(mpz_t _s)
{
if (_s->_mp_size < 0)
{
mpz_add(tmp, mod, _s);
mpz_set(_s, tmp);
}
} }
} }
@ -130,69 +213,120 @@ extern "C"
using namespace dev::eth::jit; using namespace dev::eth::jit;
EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result) EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result)
{ {
auto arg1 = llvm2eth(*_arg1); *o_result = mul(*_arg1, *_arg2);
auto arg2 = llvm2eth(*_arg2);
*o_result = eth2llvm(arg1 * arg2);
} }
EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result) EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result)
{ {
auto arg1 = llvm2eth(*_arg1); *o_result = {};
auto arg2 = llvm2eth(*_arg2); if (isZero(_arg2))
*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); return;
mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast<mp_limb_t*>(_arg1)};
mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast<mp_limb_t*>(_arg2)};
mpz_t z{nLimbs, 0, reinterpret_cast<mp_limb_t*>(o_result)};
mpz_tdiv_q(z, x, y);
// auto arg1 = llvm2eth(*_arg1);
// auto arg2 = llvm2eth(*_arg2);
// auto res = arg2 == 0 ? arg2 : arg1 / arg2;
// std::cout << "DIV " << arg1 << "/" << arg2 << " = " << res << std::endl;
// gmp_printf("GMP %Zd / %Zd = %Zd\n", x, y, z);
} }
EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result) EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result)
{ {
auto arg1 = llvm2eth(*_arg1); *o_result = {};
auto arg2 = llvm2eth(*_arg2); if (isZero(_arg2))
*o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); return;
mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast<mp_limb_t*>(_arg1)};
mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast<mp_limb_t*>(_arg2)};
mpz_t z{nLimbs, 0, reinterpret_cast<mp_limb_t*>(o_result)};
mpz_tdiv_r(z, x, y);
} }
EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result) EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result)
{ {
auto arg1 = llvm2eth(*_arg1); *o_result = {};
auto arg2 = llvm2eth(*_arg2); if (isZero(_arg2))
*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) / u2s(arg2))); return;
mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast<mp_limb_t*>(_arg1)};
mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast<mp_limb_t*>(_arg2)};
mpz_t z{nLimbs, 0, reinterpret_cast<mp_limb_t*>(o_result)};
u2s(x);
u2s(y);
mpz_tdiv_q(z, x, y);
s2u(z);
} }
EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result) EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result)
{ {
auto arg1 = llvm2eth(*_arg1); *o_result = {};
auto arg2 = llvm2eth(*_arg2); if (isZero(_arg2))
*o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) % u2s(arg2))); return;
mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast<mp_limb_t*>(_arg1)};
mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast<mp_limb_t*>(_arg2)};
mpz_t z{nLimbs, 0, reinterpret_cast<mp_limb_t*>(o_result)};
u2s(x);
u2s(y);
mpz_tdiv_r(z, x, y);
s2u(z);
} }
EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result) EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result)
{ {
bigint left = llvm2eth(*_arg1); *o_result = {};
bigint right = llvm2eth(*_arg2);
auto ret = static_cast<u256>(boost::multiprecision::powm(left, right, bigint(2) << 256)); static mp_limb_t mod_limbs[nLimbs + 1] = {};
*o_result = eth2llvm(ret); mod_limbs[nLimbs] = 1;
static const mpz_t mod{nLimbs + 1, nLimbs + 1, &mod_limbs[0]};
mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast<mp_limb_t*>(_arg1)};
mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast<mp_limb_t*>(_arg2)};
mpz_t z{nLimbs, 0, reinterpret_cast<mp_limb_t*>(o_result)};
mpz_powm(z, x, y, mod);
} }
EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
{ {
auto arg1 = llvm2eth(*_arg1);
auto arg2 = llvm2eth(*_arg2);
auto arg3 = llvm2eth(*_arg3);
if (arg3 != 0)
*o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3));
else
*o_result = {}; *o_result = {};
if (isZero(_arg3))
return;
mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast<mp_limb_t*>(_arg1)};
mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast<mp_limb_t*>(_arg2)};
mpz_t m{nLimbs, countLimbs(_arg3), reinterpret_cast<mp_limb_t*>(_arg3)};
mpz_t z{nLimbs, 0, reinterpret_cast<mp_limb_t*>(o_result)};
static mp_limb_t p_limbs[nLimbs * 2] = {};
static mpz_t p{nLimbs * 2, 0, &p_limbs[0]};
mpz_mul(p, x, y);
mpz_tdiv_r(z, p, m);
} }
EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result)
{ {
auto arg1 = llvm2eth(*_arg1);
auto arg2 = llvm2eth(*_arg2);
auto arg3 = llvm2eth(*_arg3);
if (arg3 != 0)
*o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3));
else
*o_result = {}; *o_result = {};
if (isZero(_arg3))
return;
mpz_t x{nLimbs, countLimbs(_arg1), reinterpret_cast<mp_limb_t*>(_arg1)};
mpz_t y{nLimbs, countLimbs(_arg2), reinterpret_cast<mp_limb_t*>(_arg2)};
mpz_t m{nLimbs, countLimbs(_arg3), reinterpret_cast<mp_limb_t*>(_arg3)};
mpz_t z{nLimbs, 0, reinterpret_cast<mp_limb_t*>(o_result)};
static mp_limb_t s_limbs[nLimbs + 1] = {};
static mpz_t s{nLimbs + 1, 0, &s_limbs[0]};
mpz_add(s, x, y);
mpz_tdiv_r(z, s, m);
} }
} }

View file

@ -168,16 +168,13 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack)
if (val == nullptr) if (val == nullptr)
continue; continue;
assert(llvm::isa<llvm::PHINode>(val));
llvm::PHINode* phi = llvm::cast<llvm::PHINode>(val); llvm::PHINode* phi = llvm::cast<llvm::PHINode>(val);
if (! phi->use_empty())
{
// Insert call to get() just before the PHI node and replace // Insert call to get() just before the PHI node and replace
// the uses of PHI with the uses of this new instruction. // the uses of PHI with the uses of this new instruction.
m_builder.SetInsertPoint(phi); m_builder.SetInsertPoint(phi);
auto newVal = _evmStack.get(idx); auto newVal = _evmStack.get(idx); // OPT: Value may be never user but we need to check stack heigth
// It is probably a good idea to keep heigth as a local variable accesible by LLVM directly
phi->replaceAllUsesWith(newVal); phi->replaceAllUsesWith(newVal);
}
phi->eraseFromParent(); phi->eraseFromParent();
} }

View file

@ -57,7 +57,7 @@ public:
explicit BasicBlock(std::string _name, 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; BasicBlock(const BasicBlock&) = delete;
void operator=(const BasicBlock&) = delete; BasicBlock& operator=(const BasicBlock&) = delete;
llvm::BasicBlock* llvm() { return m_llvmBB; } llvm::BasicBlock* llvm() { return m_llvmBB; }
@ -66,6 +66,9 @@ public:
bool isJumpDest() const { return m_isJumpDest; } bool isJumpDest() const { return m_isJumpDest; }
llvm::Value* getJumpTarget() const { return m_jumpTarget; }
void setJumpTarget(llvm::Value* _jumpTarget) { m_jumpTarget = _jumpTarget; }
LocalStack& localStack() { return m_stack; } LocalStack& localStack() { return m_stack; }
/// Optimization: propagates values between local stacks in basic blocks /// Optimization: propagates values between local stacks in basic blocks
@ -112,6 +115,9 @@ 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 const m_isJumpDest = false; bool const m_isJumpDest = false;
/// If block finishes with dynamic jump target index is stored here
llvm::Value* m_jumpTarget = nullptr;
}; };
} }

View file

@ -2,24 +2,24 @@ set(TARGET_NAME evmjit)
file(GLOB SOURCES "*.cpp") file(GLOB SOURCES "*.cpp")
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
set(INTERFACE_HEADERS interface.h)
source_group("" FILES ${HEADERS}) source_group("" FILES ${HEADERS})
source_group("" FILES ${SOURCES}) source_group("" FILES ${SOURCES})
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# Disable rtti for Cache as LLVM has no rtti # Disable rtti for Cache as LLVM has no rtti
set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti)
endif () endif()
link_directories(/usr/lib/llvm-3.5/lib)
add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS})
set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs")
include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${LLVM_LIBS}) target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS})
target_link_libraries(${TARGET_NAME} PRIVATE gmp)
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
#install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib)
#install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME})

View file

@ -36,6 +36,20 @@ std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id)
llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::system_temp_directory(false, cachePath);
llvm::sys::path::append(cachePath, "evm_objs", id); llvm::sys::path::append(cachePath, "evm_objs", id);
#if defined(__GNUC__) && !defined(NDEBUG)
llvm::sys::fs::file_status st;
auto err = llvm::sys::fs::status(cachePath.str(), st);
if (err)
return nullptr;
auto mtime = st.getLastModificationTime().toEpochTime();
std::tm tm;
strptime(__DATE__ __TIME__, " %b %d %Y %H:%M:%S", &tm);
auto btime = (uint64_t)std::mktime(&tm);
if (btime > mtime)
return nullptr;
#endif
if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false))
lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <boost/multiprecision/cpp_int.hpp> #include <tuple>
namespace dev namespace dev
{ {
@ -12,8 +12,7 @@ namespace jit
using byte = uint8_t; using byte = uint8_t;
using bytes = std::vector<byte>; using bytes = std::vector<byte>;
using u256 = boost::multiprecision::uint256_t; using bytes_ref = std::tuple<byte const*, size_t>;
using bigint = boost::multiprecision::cpp_int;
struct NoteChannel {}; // FIXME: Use some log library? struct NoteChannel {}; // FIXME: Use some log library?
@ -34,7 +33,6 @@ enum class ReturnCode
}; };
/// Representation of 256-bit value binary compatible with LLVM i256 /// Representation of 256-bit value binary compatible with LLVM i256
// TODO: Replace with h256
struct i256 struct i256
{ {
uint64_t a = 0; uint64_t a = 0;

View file

@ -4,6 +4,7 @@
#include <functional> #include <functional>
#include <fstream> #include <fstream>
#include <chrono> #include <chrono>
#include <sstream>
#include <llvm/ADT/PostOrderIterator.h> #include <llvm/ADT/PostOrderIterator.h>
#include <llvm/IR/CFG.h> #include <llvm/IR/CFG.h>
@ -100,7 +101,7 @@ llvm::BasicBlock* Compiler::getJumpTableBlock()
m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true)); 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_builder.CreatePHI(Type::Word, 8, "target");
auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock());
for (auto&& p : m_basicBlocks) for (auto&& p : m_basicBlocks)
{ {
@ -165,6 +166,26 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
removeDeadBlocks(); removeDeadBlocks();
// Link jump table target index
if (m_jumpTableBlock)
{
auto phi = llvm::cast<llvm::PHINode>(&m_jumpTableBlock->llvm()->getInstList().front());
for (auto predIt = llvm::pred_begin(m_jumpTableBlock->llvm()); predIt != llvm::pred_end(m_jumpTableBlock->llvm()); ++predIt)
{
BasicBlock* pred = nullptr;
for (auto&& p : m_basicBlocks)
{
if (p.second.llvm() == *predIt)
{
pred = &p.second;
break;
}
}
phi->addIncoming(pred->getJumpTarget(), pred->llvm());
}
}
dumpCFGifRequired("blocks-init.dot"); dumpCFGifRequired("blocks-init.dot");
if (m_options.optimizeStack) if (m_options.optimizeStack)
@ -394,7 +415,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
value = Endianness::toBE(m_builder, value); value = Endianness::toBE(m_builder, value);
auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes");
auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); auto safeByteNum = m_builder.CreateZExt(m_builder.CreateTrunc(byteNum, m_builder.getIntNTy(5)), Type::lowPrecision); // Trim index, large values can crash
auto byte = m_builder.CreateExtractElement(bytes, safeByteNum, "byte");
value = m_builder.CreateZExt(byte, Type::Word); value = m_builder.CreateZExt(byte, Type::Word);
auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32));
@ -564,7 +586,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
} }
else else
{ {
stack.push(target); _basicBlock.setJumpTarget(target);
m_builder.CreateBr(getJumpTableBlock()); m_builder.CreateBr(getJumpTableBlock());
} }
} }
@ -580,7 +602,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
} }
else else
{ {
stack.push(target); _basicBlock.setJumpTarget(target);
m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock);
} }
} }
@ -644,7 +666,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
case Instruction::EXTCODESIZE: case Instruction::EXTCODESIZE:
{ {
auto addr = stack.pop(); auto addr = stack.pop();
auto codeRef = _ext.getExtCode(addr); auto codeRef = _ext.extcode(addr);
stack.push(codeRef.size); stack.push(codeRef.size);
break; break;
} }
@ -682,7 +704,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
auto srcIdx = stack.pop(); auto srcIdx = stack.pop();
auto reqBytes = stack.pop(); auto reqBytes = stack.pop();
auto codeRef = _ext.getExtCode(addr); auto codeRef = _ext.extcode(addr);
_memory.copyBytes(codeRef.ptr, codeRef.size, srcIdx, destMemIdx, reqBytes); _memory.copyBytes(codeRef.ptr, codeRef.size, srcIdx, destMemIdx, reqBytes);
break; break;

View file

@ -19,7 +19,12 @@
#include "Compiler.h" #include "Compiler.h"
#include "Cache.h" #include "Cache.h"
extern "C" void env_sha3(dev::eth::jit::byte const* _begin, uint64_t _size, std::array<dev::eth::jit::byte, 32>* o_hash); #if defined(NDEBUG)
#define DEBUG_ENV_OPTION(name) false
#else
#include <cstdlib>
#define DEBUG_ENV_OPTION(name) (std::getenv(#name) != nullptr)
#endif
namespace dev namespace dev
{ {
@ -49,14 +54,17 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime)
std::string codeHash(bytes const& _code) std::string codeHash(bytes const& _code)
{ {
std::array<byte, 32> binHash; uint32_t hash = 0;
env_sha3(_code.data(), _code.size(), &binHash); for (auto b : _code)
{
std::ostringstream os; hash += b;
for (auto i: binHash) hash += (hash << 10);
os << std::hex << std::setfill('0') << std::setw(2) << (int)(std::make_unsigned<decltype(i)>::type)i; hash ^= (hash >> 6);
}
return os.str(); hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return std::to_string(hash);
} }
} }
@ -64,6 +72,8 @@ std::string codeHash(bytes const& _code)
ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env)
{ {
static std::unique_ptr<llvm::ExecutionEngine> ee; // TODO: Use Managed Objects from LLVM? 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 mainFuncName = codeHash(_code);
EntryFuncPtr entryFuncPtr{}; EntryFuncPtr entryFuncPtr{};
@ -74,14 +84,14 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en
} }
else else
{ {
bool objectCacheEnabled = true;
auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr;
std::unique_ptr<llvm::Module> module; std::unique_ptr<llvm::Module> module;
if (objectCache) if (objectCache)
module = Cache::getObject(mainFuncName); module = Cache::getObject(mainFuncName);
if (!module) if (!module)
module = Compiler({}).compile(_code, mainFuncName); module = Compiler({}).compile(_code, mainFuncName);
//module->dump(); if (debugDumpModule)
module->dump();
if (!ee) if (!ee)
{ {
llvm::InitializeNativeTarget(); llvm::InitializeNativeTarget();
@ -92,7 +102,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en
builder.setUseMCJIT(true); builder.setUseMCJIT(true);
std::unique_ptr<llvm::SectionMemoryManager> memoryManager(new llvm::SectionMemoryManager); std::unique_ptr<llvm::SectionMemoryManager> memoryManager(new llvm::SectionMemoryManager);
builder.setMCJITMemoryManager(memoryManager.get()); builder.setMCJITMemoryManager(memoryManager.get());
builder.setOptLevel(llvm::CodeGenOpt::Default); builder.setOptLevel(llvm::CodeGenOpt::None);
auto triple = llvm::Triple(llvm::sys::getProcessTriple()); auto triple = llvm::Triple(llvm::sys::getProcessTriple());
if (triple.getOS() == llvm::Triple::OSType::Win32) if (triple.getOS() == llvm::Triple::OSType::Win32)
@ -126,7 +136,10 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en
auto returnCode = runEntryFunc(entryFuncPtr, &runtime); auto returnCode = runEntryFunc(entryFuncPtr, &runtime);
if (returnCode == ReturnCode::Return) if (returnCode == ReturnCode::Return)
this->returnData = runtime.getReturnData(); {
returnData = runtime.getReturnData(); // Save reference to return data
std::swap(m_memory, runtime.getMemory()); // Take ownership of memory
}
auto executionEndTime = std::chrono::high_resolution_clock::now(); auto executionEndTime = std::chrono::high_resolution_clock::now();
clog(JIT) << " + " << std::chrono::duration_cast<std::chrono::milliseconds>(executionEndTime - executionStartTime).count() << " ms\n"; clog(JIT) << " + " << std::chrono::duration_cast<std::chrono::milliseconds>(executionEndTime - executionStartTime).count() << " ms\n";

View file

@ -18,7 +18,13 @@ public:
ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env);
bytes returnData; /// Reference to returned data (RETURN opcode used)
bytes_ref returnData;
private:
/// After execution, if RETURN used, memory is moved there
/// to allow client copy the returned data
bytes m_memory;
}; };
} }

View file

@ -5,9 +5,6 @@
#include <llvm/IR/TypeBuilder.h> #include <llvm/IR/TypeBuilder.h>
#include <llvm/IR/IntrinsicInst.h> #include <llvm/IR/IntrinsicInst.h>
//#include <libdevcrypto/SHA3.h>
//#include <libevm/FeeStructure.h>
#include "RuntimeManager.h" #include "RuntimeManager.h"
#include "Memory.h" #include "Memory.h"
#include "Type.h" #include "Type.h"
@ -22,10 +19,10 @@ 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({}), // The only std::array initialization that works in both Visual Studio & GCC
m_argAllocas({})
{ {
m_funcs = decltype(m_funcs)();
m_argAllocas = decltype(m_argAllocas)();
m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size");
} }
@ -48,7 +45,7 @@ std::array<FuncDesc, sizeOf<EnvFunc>::value> const& getEnvFuncDescs()
FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})},
FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})},
FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})},
FuncDesc{"env_getExtCode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})},
FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})},
}}; }};
@ -71,7 +68,6 @@ llvm::Value* Ext::getArgAlloca()
getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI());
a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg");
} }
return a; return a;
} }
@ -166,10 +162,10 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize)
return hash; return hash;
} }
MemoryRef Ext::getExtCode(llvm::Value* _addr) MemoryRef Ext::extcode(llvm::Value* _addr)
{ {
auto addr = Endianness::toBE(m_builder, _addr); auto addr = Endianness::toBE(m_builder, _addr);
auto code = createCall(EnvFunc::getExtCode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size}); auto code = createCall(EnvFunc::extcode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size});
auto codeSize = m_builder.CreateLoad(m_size); auto codeSize = m_builder.CreateLoad(m_size);
auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word);
return {code, codeSize256}; return {code, codeSize256};

View file

@ -34,7 +34,7 @@ enum class EnvFunc
call, call,
log, log,
blockhash, blockhash,
getExtCode, extcode,
calldataload, // Helper function, not client Env interface calldataload, // Helper function, not client Env interface
_size _size
@ -55,7 +55,7 @@ public:
llvm::Value* blockhash(llvm::Value* _number); llvm::Value* blockhash(llvm::Value* _number);
llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize);
MemoryRef getExtCode(llvm::Value* _addr); MemoryRef extcode(llvm::Value* _addr);
void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array<llvm::Value*,4> const& _topics); void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array<llvm::Value*,4> const& _topics);

View file

@ -18,18 +18,18 @@ Runtime::Runtime(RuntimeData* _data, Env* _env) :
m_currJmpBuf(m_jmpBuf) m_currJmpBuf(m_jmpBuf)
{} {}
bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy bytes_ref Runtime::getReturnData() const
{ {
// TODO: Handle large indexes // TODO: Handle large indexes
auto offset = static_cast<size_t>(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset])); auto offset = static_cast<size_t>(m_data.elems[RuntimeData::ReturnDataOffset].a);
auto size = static_cast<size_t>(llvm2eth(m_data.elems[RuntimeData::ReturnDataSize])); auto size = static_cast<size_t>(m_data.elems[RuntimeData::ReturnDataSize].a);
assert(offset + size <= m_memory.size() || size == 0); assert(offset + size <= m_memory.size() || size == 0);
if (offset + size > m_memory.size()) if (offset + size > m_memory.size())
return {}; return {};
auto dataBeg = m_memory.begin() + offset; auto dataBeg = m_memory.data() + offset;
return {dataBeg, dataBeg + size}; return bytes_ref{dataBeg, size};
} }
} }

View file

@ -2,15 +2,8 @@
#pragma once #pragma once
#include <csetjmp> #include <csetjmp>
#include <vector>
#include "Instruction.h"
#include "CompilerHelper.h"
#include "Utils.h"
#include "Type.h"
#include "RuntimeData.h" #include "RuntimeData.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#define EXPORT __declspec(dllexport) #define EXPORT __declspec(dllexport)
#else #else
@ -34,13 +27,13 @@ public:
Runtime(RuntimeData* _data, Env* _env); Runtime(RuntimeData* _data, Env* _env);
Runtime(const Runtime&) = delete; Runtime(const Runtime&) = delete;
void operator=(const Runtime&) = delete; Runtime& operator=(const Runtime&) = delete;
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; }
bytes getReturnData() const; bytes_ref getReturnData() const;
jmp_buf_ref getJmpBuf() { return m_jmpBuf; } jmp_buf_ref getJmpBuf() { return m_jmpBuf; }
private: private:

View file

@ -38,9 +38,6 @@ struct RuntimeData
i256 elems[_size] = {}; i256 elems[_size] = {};
byte const* callData = nullptr; byte const* callData = nullptr;
byte const* code = nullptr; byte const* code = nullptr;
void set(Index _index, u256 _value) { elems[_index] = eth2llvm(_value); }
u256 get(Index _index) { return llvm2eth(elems[_index]); }
}; };
/// VM Environment (ExtVM) opaque type /// VM Environment (ExtVM) opaque type

View file

@ -8,32 +8,6 @@ namespace eth
namespace jit namespace jit
{ {
u256 llvm2eth(i256 _i)
{
u256 u = 0;
u |= _i.d;
u <<= 64;
u |= _i.c;
u <<= 64;
u |= _i.b;
u <<= 64;
u |= _i.a;
return u;
}
i256 eth2llvm(u256 _u)
{
i256 i;
u256 mask = 0xFFFFFFFFFFFFFFFF;
i.a = static_cast<uint64_t>(_u & mask);
_u >>= 64;
i.b = static_cast<uint64_t>(_u & mask);
_u >>= 64;
i.c = static_cast<uint64_t>(_u & mask);
_u >>= 64;
i.d = static_cast<uint64_t>(_u & mask);
return i;
}
} }
} }

View file

@ -14,9 +14,6 @@ struct JIT: public NoteChannel { static const char* name() { return "JIT"; } };
//#define clog(CHANNEL) std::cerr //#define clog(CHANNEL) std::cerr
#define clog(CHANNEL) std::ostream(nullptr) #define clog(CHANNEL) std::ostream(nullptr)
u256 llvm2eth(i256);
i256 eth2llvm(u256);
} }
} }
} }

View file

@ -1,5 +1,5 @@
#include "interface.h" #include "interface.h"
#include <cstdio> #include <cstring>
#include "ExecutionEngine.h" #include "ExecutionEngine.h"
extern "C" extern "C"
@ -20,12 +20,12 @@ evmjit_result evmjit_run(void* _data, void* _env)
auto returnCode = engine.run(bytecode, data, static_cast<Env*>(_env)); auto returnCode = engine.run(bytecode, data, static_cast<Env*>(_env));
evmjit_result result = {static_cast<int32_t>(returnCode), 0, nullptr}; evmjit_result result = {static_cast<int32_t>(returnCode), 0, nullptr};
if (returnCode == ReturnCode::Return && !engine.returnData.empty()) if (returnCode == ReturnCode::Return && std::get<0>(engine.returnData))
{ {
// TODO: Optimized returning data. Allocating memory on client side by callback function might be a good idea // TODO: Optimized returning data. Allocating memory on client side by callback function might be a good idea
result.returnDataSize = engine.returnData.size(); result.returnDataSize = std::get<1>(engine.returnData);
result.returnData = std::malloc(result.returnDataSize); result.returnData = std::malloc(result.returnDataSize);
std::memcpy(result.returnData, engine.returnData.data(), result.returnDataSize); std::memcpy(result.returnData, std::get<0>(engine.returnData), result.returnDataSize);
} }
return result; return result;