Browse Source

Merge branch 'develop-evmcc' into pr-jit

cl-refactor
Paweł Bylica 10 years ago
parent
commit
d70ec1c442
  1. 17
      CMakeLists.txt
  2. 2
      eth/CMakeLists.txt
  3. 7
      evmcc/CMakeLists.txt
  4. 2
      evmcc/evmcc.cpp
  5. 1
      evmcc/test/arith/arith_bnot.evm
  6. 14
      evmcc/test/arith/arith_bnot.lll
  7. 1
      evmcc/test/ext/store_delete.evm
  8. 9
      evmcc/test/ext/store_delete.lll
  9. 1
      evmcc/test/jump/jumpi_at_the_end.evm
  10. 1
      evmcc/test/jump/jumpi_at_the_end.lll
  11. 90
      evmcc/test/vmtests/vmPerformanceTest.json
  12. 41
      evmcc/test/vmtests/vm_jump.json
  13. 2
      exp/CMakeLists.txt
  14. 3
      libevm/VMFace.cpp
  15. 104
      libevmjit/Arith256.cpp
  16. 10
      libevmjit/BasicBlock.cpp
  17. 2
      libevmjit/BasicBlock.h
  18. 7
      libevmjit/CMakeLists.txt
  19. 109
      libevmjit/Compiler.cpp
  20. 15
      libevmjit/ExecutionEngine.cpp
  21. 211
      libevmjit/Ext.cpp
  22. 2
      libevmjit/Ext.h
  23. 24
      libevmjit/GasMeter.cpp
  24. 55
      libevmjit/Memory.cpp
  25. 2
      libevmjit/Memory.h
  26. 4
      libevmjit/Runtime.cpp
  27. 3
      libevmjit/Runtime.h
  28. 86
      libevmjit/Stack.cpp
  29. 2
      libevmjit/Stack.h
  30. 10
      libevmjit/Type.cpp
  31. 2
      libevmjit/Type.h
  32. 6
      libevmjit/VM.cpp
  33. 2
      neth/CMakeLists.txt
  34. 9
      test/CMakeLists.txt
  35. 2
      windows/LLVM.props

17
CMakeLists.txt

@ -15,6 +15,7 @@ function(createDefaultCacheConfig)
set(LANGUAGES OFF CACHE BOOL "Limit build to Serpent/LLL tools")
set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)")
set(PARANOIA OFF CACHE BOOL "Additional run-time checks")
set(EVMJIT OFF CACHE BOOL "Build a just-in-time compiler for EVM code (requires LLVM)")
endfunction()
@ -39,6 +40,14 @@ function(configureProject)
message(FATAL_ERROR "VM tracing requires debug.")
endif ()
endif ()
if (EVMJIT)
if (LANGUAGES)
message(FATAL_ERROR "Unset LANGUAGES to build EVMJIT")
else()
add_definitions(-DETH_EVMJIT)
endif()
endif()
endfunction()
@ -75,7 +84,7 @@ cmake_policy(SET CMP0015 NEW)
createDefaultCacheConfig()
configureProject()
message("-- LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}")
message("-- LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}; EVMJIT: ${EVMJIT}")
# Default TARGET_PLATFORM to "linux".
@ -158,9 +167,9 @@ if (NOT LANGUAGES)
endif()
endif()
if (EVMCC)
add_subdirectory(libevmjit)
add_subdirectory(evmcc)
if (EVMJIT)
add_subdirectory(libevmjit)
add_subdirectory(evmcc)
endif()

2
eth/CMakeLists.txt

@ -15,7 +15,7 @@ target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} gmp)
if(EVMCC)
if(EVMJIT)
target_link_libraries(${EXECUTABLE} evmjit)
endif()

7
evmcc/CMakeLists.txt

@ -25,8 +25,6 @@ if ("${TARGET_PLATFORM}" STREQUAL "w64")
target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
else ()
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
@ -42,13 +40,12 @@ message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen)
target_link_libraries(evmcc ${llvm_libs})
# llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen)
# target_link_libraries(evmcc ${llvm_libs})
# end of LLVM specific commands
install( TARGETS ${EXECUTABLE} DESTINATION bin )
cmake_policy(SET CMP0015 NEW)

2
evmcc/evmcc.cpp

@ -8,8 +8,6 @@
#include <boost/algorithm/string.hpp>
#include <llvm/Support/raw_os_ostream.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.h>

1
evmcc/test/arith/arith_bnot.evm

@ -0,0 +1 @@
6201e2406000546000530960005460206000f2

14
evmcc/test/arith/arith_bnot.lll

@ -0,0 +1,14 @@
(asm
123456
0
MSTORE
0
MLOAD
BNOT
0
MSTORE
32
0
RETURN
)

1
evmcc/test/ext/store_delete.evm

@ -0,0 +1 @@
6104d26063576000606357

9
evmcc/test/ext/store_delete.lll

@ -0,0 +1,9 @@
(asm
1234
99
SSTORE
0
99
SSTORE
)

1
evmcc/test/jump/jumpi_at_the_end.evm

@ -0,0 +1 @@
600a6000545d6000536001900380600054600659

1
evmcc/test/jump/jumpi_at_the_end.lll

@ -0,0 +1 @@
(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)

90
evmcc/test/vmtests/vmPerformanceTest.json

@ -1,5 +1,47 @@
{
"for100000" : {
"mulmodloop" : {
"callcreates" : [ ],
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"code" : "0x60015d68010000000000000000908060010115600358",
"data" : "0x",
"gas" : "1000000",
"gasPrice" : "100000000000000",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000"
},
"gas" : "0",
"out" : "0x0",
"post" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x60015d68010000000000000000908060010115600358",
"nonce" : "0",
"storage" : {
}
}
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x60015d68010000000000000000908060010115600358",
"nonce" : "0",
"storage" : { }
}
}
},
"for-1e06" : {
"callcreates" : [ ],
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
@ -40,7 +82,7 @@
}
},
"recloop" : {
"recloop0x40000" : {
"callcreates" : [ ],
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
@ -166,4 +208,48 @@
}
}
},
"jumptable100" : {
"callcreates" : [
],
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "10000000",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"code" : "0x6127105d600190038060000e6104615961001b600160005458005d610026600260005458005d610031600360005458005d61003c600460005458005d610047600560005458005d610052600660005458005d61005d600760005458005d610068600860005458005d610073600960005458005d61007e600a60005458005d610089600b60005458005d610094600c60005458005d61009f600d60005458005d6100aa600e60005458005d6100b5600f60005458005d6100c0601060005458005d6100cb601160005458005d6100d6601260005458005d6100e1601360005458005d6100ec601460005458005d6100f7601560005458005d610102601660005458005d61010d601760005458005d610118601860005458005d610123601960005458005d61012e601a60005458005d610139601b60005458005d610144601c60005458005d61014f601d60005458005d61015a601e60005458005d610165601f60005458005d610170602060005458005d61017b602160005458005d610186602260005458005d610191602360005458005d61019c602460005458005d6101a7602560005458005d6101b2602660005458005d6101bd602760005458005d6101c8602860005458005d6101d3602960005458005d6101de602a60005458005d6101e9602b60005458005d6101f4602c60005458005d6101ff602d60005458005d61020a602e60005458005d610215602f60005458005d610220603060005458005d61022b603160005458005d610236603260005458005d610241603360005458005d61024c603460005458005d610257603560005458005d610262603660005458005d61026d603760005458005d610278603860005458005d610283603960005458005d61028e603a60005458005d610299603b60005458005d6102a4603c60005458005d6102af603d60005458005d6102ba603e60005458005d6102c5603f60005458005d6102d0604060005458005d6102db604160005458005d6102e6604260005458005d6102f1604360005458005d6102fc604460005458005d610307604560005458005d610312604660005458005d61031d604760005458005d610328604860005458005d610333604960005458005d61033e604a60005458005d610349604b60005458005d610354604c60005458005d61035f604d60005458005d61036a604e60005458005d610375604f60005458005d610380605060005458005d61038b605160005458005d610396605260005458005d6103a1605360005458005d6103ac605460005458005d6103b7605560005458005d6103c2605660005458005d6103cd605760005458005d6103d8605860005458005d6103e3605960005458005d6103ee605a60005458005d6103f9605b60005458005d610404605c60005458005d61040f605d60005458005d61041a605e60005458005d610425605f60005458005d610430606060005458005d61043b606160005458005d610446606260005458005d610451606360005458005d61045c606460005458005d610004585d60206000f2",
"data" : "0x",
"gas" : "10000000",
"gasPrice" : "100000000000000",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000"
},
"gas" : "4900496",
"out" : "0x0000000000000000000000000000000000000000000000000000000000000064",
"post" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x6127105d600190038060000e6104615961001b600160005458005d610026600260005458005d610031600360005458005d61003c600460005458005d610047600560005458005d610052600660005458005d61005d600760005458005d610068600860005458005d610073600960005458005d61007e600a60005458005d610089600b60005458005d610094600c60005458005d61009f600d60005458005d6100aa600e60005458005d6100b5600f60005458005d6100c0601060005458005d6100cb601160005458005d6100d6601260005458005d6100e1601360005458005d6100ec601460005458005d6100f7601560005458005d610102601660005458005d61010d601760005458005d610118601860005458005d610123601960005458005d61012e601a60005458005d610139601b60005458005d610144601c60005458005d61014f601d60005458005d61015a601e60005458005d610165601f60005458005d610170602060005458005d61017b602160005458005d610186602260005458005d610191602360005458005d61019c602460005458005d6101a7602560005458005d6101b2602660005458005d6101bd602760005458005d6101c8602860005458005d6101d3602960005458005d6101de602a60005458005d6101e9602b60005458005d6101f4602c60005458005d6101ff602d60005458005d61020a602e60005458005d610215602f60005458005d610220603060005458005d61022b603160005458005d610236603260005458005d610241603360005458005d61024c603460005458005d610257603560005458005d610262603660005458005d61026d603760005458005d610278603860005458005d610283603960005458005d61028e603a60005458005d610299603b60005458005d6102a4603c60005458005d6102af603d60005458005d6102ba603e60005458005d6102c5603f60005458005d6102d0604060005458005d6102db604160005458005d6102e6604260005458005d6102f1604360005458005d6102fc604460005458005d610307604560005458005d610312604660005458005d61031d604760005458005d610328604860005458005d610333604960005458005d61033e604a60005458005d610349604b60005458005d610354604c60005458005d61035f604d60005458005d61036a604e60005458005d610375604f60005458005d610380605060005458005d61038b605160005458005d610396605260005458005d6103a1605360005458005d6103ac605460005458005d6103b7605560005458005d6103c2605660005458005d6103cd605760005458005d6103d8605860005458005d6103e3605960005458005d6103ee605a60005458005d6103f9605b60005458005d610404605c60005458005d61040f605d60005458005d61041a605e60005458005d610425605f60005458005d610430606060005458005d61043b606160005458005d610446606260005458005d610451606360005458005d61045c606460005458005d610004585d60206000f2",
"nonce" : "0",
"storage" : {
}
}
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x6127105d600190038060000e6104615961001b600160005458005d610026600260005458005d610031600360005458005d61003c600460005458005d610047600560005458005d610052600660005458005d61005d600760005458005d610068600860005458005d610073600960005458005d61007e600a60005458005d610089600b60005458005d610094600c60005458005d61009f600d60005458005d6100aa600e60005458005d6100b5600f60005458005d6100c0601060005458005d6100cb601160005458005d6100d6601260005458005d6100e1601360005458005d6100ec601460005458005d6100f7601560005458005d610102601660005458005d61010d601760005458005d610118601860005458005d610123601960005458005d61012e601a60005458005d610139601b60005458005d610144601c60005458005d61014f601d60005458005d61015a601e60005458005d610165601f60005458005d610170602060005458005d61017b602160005458005d610186602260005458005d610191602360005458005d61019c602460005458005d6101a7602560005458005d6101b2602660005458005d6101bd602760005458005d6101c8602860005458005d6101d3602960005458005d6101de602a60005458005d6101e9602b60005458005d6101f4602c60005458005d6101ff602d60005458005d61020a602e60005458005d610215602f60005458005d610220603060005458005d61022b603160005458005d610236603260005458005d610241603360005458005d61024c603460005458005d610257603560005458005d610262603660005458005d61026d603760005458005d610278603860005458005d610283603960005458005d61028e603a60005458005d610299603b60005458005d6102a4603c60005458005d6102af603d60005458005d6102ba603e60005458005d6102c5603f60005458005d6102d0604060005458005d6102db604160005458005d6102e6604260005458005d6102f1604360005458005d6102fc604460005458005d610307604560005458005d610312604660005458005d61031d604760005458005d610328604860005458005d610333604960005458005d61033e604a60005458005d610349604b60005458005d610354604c60005458005d61035f604d60005458005d61036a604e60005458005d610375604f60005458005d610380605060005458005d61038b605160005458005d610396605260005458005d6103a1605360005458005d6103ac605460005458005d6103b7605560005458005d6103c2605660005458005d6103cd605760005458005d6103d8605860005458005d6103e3605960005458005d6103ee605a60005458005d6103f9605b60005458005d610404605c60005458005d61040f605d60005458005d61041a605e60005458005d610425605f60005458005d610430606060005458005d61043b606160005458005d610446606260005458005d610451606360005458005d61045c606460005458005d610004585d60206000f2",
"nonce" : "0",
"storage" : {
}
}
}
},
}

41
evmcc/test/vmtests/vm_jump.json

@ -0,0 +1,41 @@
{
"jumpi_at_the_end" : {
"callcreates" : [ ],
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "10000000",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)",
"data" : "0x",
"gas" : "1000",
"gasPrice" : "100000000000000",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000"
},
"gas" : "895",
"out" : "0x0",
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)",
"nonce" : "0",
"storage" : {}
}
},
"post" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)",
"nonce" : "0",
"storage" : {}
}
}
}
}

2
exp/CMakeLists.txt

@ -17,7 +17,7 @@ target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS})
endif()
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
if(EVMCC)
if(EVMJIT)
target_link_libraries(${EXECUTABLE} evmjit)
endif()

3
libevm/VMFace.cpp

@ -25,9 +25,10 @@ using namespace dev::eth;
std::unique_ptr<VMFace> VMFace::create(VMFace::Kind _kind, u256 _gas)
{
std::unique_ptr<VMFace> vm;
#if ETH_JIT
#if ETH_EVMJIT
vm.reset(_kind == Kind::JIT ? static_cast<VMFace*>(new jit::VM) : new VM);
#else
(void) _kind; // suppress unused var warning
vm.reset(new VM);
#endif
vm->reset(_gas);

104
libevmjit/Arith256.cpp

@ -101,58 +101,58 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu
extern "C"
{
using namespace dev::eth::jit;
EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg1 * arg2);
}
EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2);
}
EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2);
}
EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2)));
}
EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) % dev::u2s(arg2)));
}
EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
dev::u256 arg3 = llvm2eth(*_arg3);
*_result = eth2llvm(dev::u256((dev::bigint(arg1) * dev::bigint(arg2)) % arg3));
}
EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
dev::u256 arg3 = llvm2eth(*_arg3);
*_result = eth2llvm(dev::u256((dev::bigint(arg1) + dev::bigint(arg2)) % arg3));
}
using namespace dev::eth::jit;
EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg1 * arg2);
}
EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2);
}
EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2);
}
EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2)));
}
EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) % dev::u2s(arg2)));
}
EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
dev::u256 arg3 = llvm2eth(*_arg3);
*_result = eth2llvm(dev::u256((dev::bigint(arg1) * dev::bigint(arg2)) % arg3));
}
EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result)
{
dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2);
dev::u256 arg3 = llvm2eth(*_arg3);
*_result = eth2llvm(dev::u256((dev::bigint(arg1) + dev::bigint(arg2)) % arg3));
}
}

10
libevmjit/BasicBlock.cpp

@ -109,7 +109,7 @@ void BasicBlock::LocalStack::synchronize(Stack& _evmStack)
}
// Push new values
for ( ; currIter < endIter; ++currIter)
for (; currIter < endIter; ++currIter)
{
assert(*currIter != nullptr);
_evmStack.push(*currIter);
@ -243,11 +243,11 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
{
if (getenv("EVMCC_DEBUG_BLOCKS"))
{
for (auto& pair: cfg)
for (auto& pair : cfg)
std::cerr << pair.second.bblock.llvm()->getName().str()
<< ": in " << pair.second.inputItems
<< ", out " << pair.second.outputItems
<< "\n";
<< ", out " << pair.second.outputItems
<< "\n";
}
valuesChanged = false;
@ -347,7 +347,7 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput)
out << (_dotOutput ? "\\l" : "\n");
}
out << (_dotOutput ? "| " : "Instructions:\n");
out << (_dotOutput ? "| " : "Instructions:\n");
for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins)
out << *ins << (_dotOutput ? "\\l" : "\n");

2
libevmjit/BasicBlock.h

@ -14,7 +14,7 @@ namespace jit
{
using ProgramCounter = uint64_t; // TODO: Rename
class BasicBlock
{
public:

7
libevmjit/CMakeLists.txt

@ -20,6 +20,7 @@ target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} evmface)
if ("${TARGET_PLATFORM}" STREQUAL "w64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
target_link_libraries(${EXECUTABLE} gcc)
@ -30,14 +31,12 @@ if ("${TARGET_PLATFORM}" STREQUAL "w64")
target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
else ()
find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif ()
# LLVM specific commands
# LLVM specific config
find_package(LLVM REQUIRED CONFIG)
@ -50,7 +49,7 @@ add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen)
target_link_libraries(evmjit ${llvm_libs})
# end of LLVM specific commands
# end of LLVM specific config

109
libevmjit/Compiler.cpp

@ -33,7 +33,9 @@ namespace jit
{
Compiler::Compiler():
m_builder(llvm::getGlobalContext())
m_builder(llvm::getGlobalContext()),
m_jumpTableBlock(),
m_badJumpBlock()
{
Type::init(m_builder.getContext());
}
@ -46,7 +48,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
std::vector<ProgramCounter> indirectJumpTargets;
boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1)));
splitPoints.insert(0); // First basic block
splitPoints.insert(0); // First basic block
validJumpTargets[0] = true;
for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr)
@ -120,7 +122,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
}
// Remove split points generated from jumps out of code or into data.
for (auto it = splitPoints.cbegin(); it != splitPoints.cend(); )
for (auto it = splitPoints.cbegin(); it != splitPoints.cend();)
{
if (*it > bytecode.size() || !validJumpTargets[*it])
it = splitPoints.erase(it);
@ -128,7 +130,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
++it;
}
for (auto it = splitPoints.cbegin(); it != splitPoints.cend(); )
for (auto it = splitPoints.cbegin(); it != splitPoints.cend();)
{
auto beginInstIdx = *it;
++it;
@ -137,8 +139,8 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
}
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
m_badJumpBlock = std::make_unique<BasicBlock>("BadJumpBlock", m_mainFunc, m_builder);
m_jumpTableBlock = std::make_unique<BasicBlock>("JumpTableBlock", m_mainFunc, m_builder);
m_badJumpBlock = std::unique_ptr<BasicBlock>(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder));
m_jumpTableBlock = std::unique_ptr<BasicBlock>(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder));
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it)
{
@ -170,10 +172,10 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
{
auto module = std::make_unique<llvm::Module>("main", m_builder.getContext());
auto module = std::unique_ptr<llvm::Module>(new llvm::Module("main", m_builder.getContext()));
// Create main function
llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures
llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures
auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, mainFuncArgTypes, false);
m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get());
m_mainFunc->arg_begin()->getNextNode()->setName("rt");
@ -217,8 +219,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
if (m_indirectJumpTargets.size() > 0)
{
auto dest = m_jumpTableBlock->localStack().pop();
auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(),
m_indirectJumpTargets.size());
auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(),
m_indirectJumpTargets.size());
for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it)
{
auto& bb = *it;
@ -372,14 +374,13 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
break;
}
/*case Instruction::NEG:
case Instruction::BNOT:
{
auto top = stack.pop();
auto zero = Constant::get(0);
auto res = m_builder.CreateSub(zero, top);
stack.push(res);
auto value = stack.pop();
auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot");
stack.push(ret);
break;
}*/
}
case Instruction::LT:
{
@ -505,6 +506,36 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
break;
}
case Instruction::SIGNEXTEND:
{
auto idx = stack.pop();
auto word = stack.pop();
auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32");
auto k32 = m_builder.CreateZExt(k32_, Type::i256);
auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8");
// test for word >> (k * 8 + 7)
auto bitpos = m_builder.CreateAdd(k32x8, Constant::get(7), "bitpos");
auto bitval = m_builder.CreateLShr(word, bitpos, "bitval");
auto bittest = m_builder.CreateTrunc(bitval, m_builder.getInt1Ty(), "bittest");
auto mask_ = m_builder.CreateShl(Constant::get(1), bitpos);
auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask");
auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::i256), "negmask");
auto val1 = m_builder.CreateOr(word, negmask);
auto val0 = m_builder.CreateAnd(word, mask);
auto kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::i256, 30));
auto result = m_builder.CreateSelect(kInRange,
m_builder.CreateSelect(bittest, val1, val0),
word);
stack.push(result);
break;
}
case Instruction::SHA3:
{
auto inOff = stack.pop();
@ -523,29 +554,28 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
case Instruction::ANY_PUSH:
{
auto numBytes = static_cast<size_t>(inst)-static_cast<size_t>(Instruction::PUSH1) + 1;
const auto numBytes = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::PUSH1) + 1;
auto value = llvm::APInt(256, 0);
for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator
for (auto lastPC = currentPC + numBytes; currentPC < lastPC;)
{
++currentPC;
value <<= 8;
value |= bytecode[currentPC];
value |= bytecode[++currentPC];
}
auto c = m_builder.getInt(value);
stack.push(c);
stack.push(m_builder.getInt(value));
break;
}
case Instruction::ANY_DUP:
{
auto index = static_cast<size_t>(inst)-static_cast<size_t>(Instruction::DUP1);
auto index = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::DUP1);
stack.dup(index);
break;
}
case Instruction::ANY_SWAP:
{
auto index = static_cast<size_t>(inst)-static_cast<size_t>(Instruction::SWAP1) + 1;
auto index = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::SWAP1) + 1;
stack.swap(index);
break;
}
@ -610,9 +640,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
{
auto pairIter = m_directJumpTargets.find(currentPC);
if (pairIter != m_directJumpTargets.end())
{
targetBlock = pairIter->second;
}
}
if (inst == Instruction::JUMP)
@ -625,9 +653,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
m_builder.CreateBr(targetBlock);
}
else
{
m_builder.CreateBr(m_jumpTableBlock->llvm());
}
}
else // JUMPI
{
@ -636,8 +662,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
auto zero = Constant::get(0);
auto cond = m_builder.CreateICmpNE(val, zero, "nonzero");
// Assume the basic blocks are properly ordered:
assert(nextBasicBlock); // FIXME: JUMPI can be last instruction
if (!nextBasicBlock) // In case JUMPI is the last instruction
nextBasicBlock = m_stopBB;
if (targetBlock)
{
@ -645,9 +672,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock);
}
else
{
m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock);
}
}
break;
@ -721,7 +746,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
auto srcIdx = stack.pop();
auto reqBytes = stack.pop();
auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234
auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234
auto srcSize = _runtimeManager.get(RuntimeData::CodeSize);
memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes);
@ -826,12 +851,12 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
gasMeter.commitCostBlock();
if (!basicBlock.llvm()->getTerminator()) // If block not terminated
if (!basicBlock.llvm()->getTerminator()) // If block not terminated
{
if (nextBasicBlock)
m_builder.CreateBr(nextBasicBlock); // Branch to the next block
m_builder.CreateBr(nextBasicBlock); // Branch to the next block
else
m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code
m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code
}
}
@ -870,8 +895,8 @@ void Compiler::removeDeadBlocks()
void Compiler::dumpBasicBlockGraph(std::ostream& out)
{
out << "digraph BB {\n"
<< " node [shape=record, fontname=Courier, fontsize=10];\n"
<< " entry [share=record, label=\"entry block\"];\n";
<< " node [shape=record, fontname=Courier, fontsize=10];\n"
<< " entry [share=record, label=\"entry block\"];\n";
std::vector<BasicBlock*> blocks;
for (auto& pair : basicBlocks)
@ -903,10 +928,10 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out)
for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it)
{
out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" ["
<< ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "")
//<< "label = \""
//<< phiNodesPerBlock[bb]
<< "];\n";
<< ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "")
//<< "label = \""
//<< phiNodesPerBlock[bb]
<< "];\n";
}
}

15
libevmjit/ExecutionEngine.cpp

@ -1,9 +1,11 @@
#include "ExecutionEngine.h"
#include <csetjmp>
#include <chrono>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/ADT/Triple.h>
@ -16,6 +18,9 @@
#include <llvm/Support/PrettyStackTrace.h>
#include <llvm/Support/Host.h>
#pragma GCC diagnostic pop
#include <libevm/VM.h>
#include "Runtime.h"
@ -64,19 +69,19 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtV
auto triple = llvm::Triple(llvm::sys::getProcessTriple());
if (triple.getOS() == llvm::Triple::OSType::Win32)
triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format
triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format
module->setTargetTriple(triple.str());
auto exec = std::unique_ptr<llvm::ExecutionEngine>(builder.create());
if (!exec)
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment(errorMsg));
_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();
exec->finalizeObject();
auto finalizationEndTime = std::chrono::high_resolution_clock::now();
clog(JIT) << "Module finalization time: "
<< std::chrono::duration_cast<std::chrono::microseconds>(finalizationEndTime - finalizationStartTime).count();
<< std::chrono::duration_cast<std::chrono::microseconds>(finalizationEndTime - finalizationStartTime).count();
// Create fake ExtVM interface
if (!_ext)
@ -117,7 +122,7 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtV
auto executionEndTime = std::chrono::high_resolution_clock::now();
clog(JIT) << "Execution time : "
<< std::chrono::duration_cast<std::chrono::microseconds>(executionEndTime - executionStartTime).count();
<< std::chrono::duration_cast<std::chrono::microseconds>(executionEndTime - executionStartTime).count();
}
else

211
libevmjit/Ext.cpp

@ -6,6 +6,7 @@
#include <llvm/IR/IntrinsicInst.h>
#include <libdevcrypto/SHA3.h>
#include <libevm/FeeStructure.h>
#include "Runtime.h"
#include "Type.h"
@ -24,21 +25,14 @@ inline u256 fromAddress(Address _a)
return (u160)_a;
}
struct ExtData
{
const byte* calldata;
const byte* code;
};
Ext::Ext(RuntimeManager& _runtimeManager):
RuntimeHelper(_runtimeManager)
RuntimeHelper(_runtimeManager),
m_data()
{
auto&& ctx = m_builder.getContext();
auto module = getModule();
auto i256Ty = m_builder.getIntNTy(256);
auto i256PtrTy = i256Ty->getPointerTo();
auto i8PtrTy = m_builder.getInt8PtrTy();
m_args[0] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.index");
m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value");
@ -172,123 +166,128 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr)
extern "C"
{
using namespace dev::eth::jit;
using namespace dev::eth::jit;
EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value)
{
auto index = llvm2eth(*_index);
auto value = _rt->getExt().store(index); // Interface uses native endianness
*_value = eth2llvm(value);
}
EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value)
{
auto index = llvm2eth(*_index);
auto value = _rt->getExt().store(index); // Interface uses native endianness
*_value = eth2llvm(value);
}
EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value)
{
auto index = llvm2eth(*_index);
auto value = llvm2eth(*_value);
_rt->getExt().setStore(index, value); // Interface uses native endianness
}
EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value)
{
auto index = llvm2eth(*_index);
auto value = llvm2eth(*_value);
auto& ext = _rt->getExt();
EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value)
{
auto index = static_cast<size_t>(llvm2eth(*_index));
assert(index + 31 > index); // TODO: Handle large index
auto b = reinterpret_cast<byte*>(_value);
for (size_t i = index, j = 0; i <= index + 31; ++i, ++j)
b[j] = i < _rt->getExt().data.size() ? _rt->getExt().data[i] : 0; // Keep Big Endian
// TODO: It all can be done by adding padding to data or by using min() algorithm without branch
}
if (value == 0 && ext.store(index) != 0) // If delete
ext.sub.refunds += c_sstoreRefundGas; // Increase refund counter
EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* _value)
{
auto u = _rt->getExt().balance(right160(*_address));
*_value = eth2llvm(u);
}
ext.setStore(index, value); // Interface uses native endianness
}
EXPORT void ext_suicide(Runtime* _rt, h256* _address)
{
_rt->getExt().suicide(right160(*_address));
}
EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value)
{
auto index = static_cast<size_t>(llvm2eth(*_index));
assert(index + 31 > index); // TODO: Handle large index
auto b = reinterpret_cast<byte*>(_value);
for (size_t i = index, j = 0; i <= index + 31; ++i, ++j)
b[j] = i < _rt->getExt().data.size() ? _rt->getExt().data[i] : 0; // Keep Big Endian
// TODO: It all can be done by adding padding to data or by using min() algorithm without branch
}
EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* _address)
{
auto&& ext = _rt->getExt();
auto endowment = llvm2eth(*_endowment);
EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* _value)
{
auto u = _rt->getExt().balance(right160(*_address));
*_value = eth2llvm(u);
}
if (ext.balance(ext.myAddress) >= endowment)
EXPORT void ext_suicide(Runtime* _rt, h256* _address)
{
ext.subBalance(endowment);
u256 gas; // TODO: Handle gas
auto initOff = static_cast<size_t>(llvm2eth(*_initOff));
auto initSize = static_cast<size_t>(llvm2eth(*_initSize));
auto&& initRef = bytesConstRef(_rt->getMemory().data() + initOff, initSize);
OnOpFunc onOp{}; // TODO: Handle that thing
h256 address(ext.create(endowment, &gas, initRef, onOp), h256::AlignRight);
*_address = address;
_rt->getExt().suicide(right160(*_address));
}
else
*_address = {};
}
EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* _address)
{
auto&& ext = _rt->getExt();
auto endowment = llvm2eth(*_endowment);
if (ext.balance(ext.myAddress) >= endowment)
{
ext.subBalance(endowment);
u256 gas; // TODO: Handle gas
auto initOff = static_cast<size_t>(llvm2eth(*_initOff));
auto initSize = static_cast<size_t>(llvm2eth(*_initSize));
auto&& initRef = bytesConstRef(_rt->getMemory().data() + initOff, initSize);
OnOpFunc onOp {}; // TODO: Handle that thing
h256 address(ext.create(endowment, &gas, initRef, onOp), h256::AlignRight);
*_address = address;
}
else
*_address = {};
}
EXPORT void ext_call(Runtime* _rt, i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* _ret)
{
auto&& ext = _rt->getExt();
auto value = llvm2eth(*_value);
auto ret = false;
auto gas = llvm2eth(*_gas);
if (ext.balance(ext.myAddress) >= value)
EXPORT void ext_call(Runtime* _rt, i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* _ret)
{
auto&& ext = _rt->getExt();
auto value = llvm2eth(*_value);
auto ret = false;
auto gas = llvm2eth(*_gas);
if (ext.balance(ext.myAddress) >= value)
{
ext.subBalance(value);
auto receiveAddress = right160(*_receiveAddress);
auto inOff = static_cast<size_t>(llvm2eth(*_inOff));
auto inSize = static_cast<size_t>(llvm2eth(*_inSize));
auto outOff = static_cast<size_t>(llvm2eth(*_outOff));
auto outSize = static_cast<size_t>(llvm2eth(*_outSize));
auto&& inRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize);
auto&& outRef = bytesConstRef(_rt->getMemory().data() + outOff, outSize);
OnOpFunc onOp {}; // TODO: Handle that thing
auto codeAddress = right160(*_codeAddress);
ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress);
}
*_gas = eth2llvm(gas);
_ret->a = ret ? 1 : 0;
}
EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret)
{
ext.subBalance(value);
auto receiveAddress = right160(*_receiveAddress);
auto inOff = static_cast<size_t>(llvm2eth(*_inOff));
auto inSize = static_cast<size_t>(llvm2eth(*_inSize));
auto outOff = static_cast<size_t>(llvm2eth(*_outOff));
auto outSize = static_cast<size_t>(llvm2eth(*_outSize));
auto&& inRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize);
auto&& outRef = bytesConstRef(_rt->getMemory().data() + outOff, outSize);
OnOpFunc onOp{}; // TODO: Handle that thing
auto codeAddress = right160(*_codeAddress);
ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress);
auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize);
auto hash = sha3(dataRef);
*_ret = *reinterpret_cast<i256*>(&hash);
}
*_gas = eth2llvm(gas);
_ret->a = ret ? 1 : 0;
}
EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret)
{
auto inOff = static_cast<size_t>(llvm2eth(*_inOff));
auto inSize = static_cast<size_t>(llvm2eth(*_inSize));
auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize);
auto hash = sha3(dataRef);
*_ret = *reinterpret_cast<i256*>(&hash);
}
EXPORT void ext_exp(Runtime* _rt, i256* _left, i256* _right, i256* _ret)
{
bigint left = llvm2eth(*_left);
bigint right = llvm2eth(*_right);
auto ret = static_cast<u256>(boost::multiprecision::powm(left, right, bigint(2) << 256));
*_ret = eth2llvm(ret);
}
EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* _ret)
{
bigint left = llvm2eth(*_left);
bigint right = llvm2eth(*_right);
auto ret = static_cast<u256>(boost::multiprecision::powm(left, right, bigint(2) << 256));
*_ret = eth2llvm(ret);
}
EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256)
{
auto&& ext = _rt->getExt();
auto addr = right160(*_addr256);
auto& code = ext.codeAt(addr);
return const_cast<unsigned char*>(code.data());
}
EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256)
{
auto&& ext = _rt->getExt();
auto addr = right160(*_addr256);
auto& code = ext.codeAt(addr);
return const_cast<unsigned char*>(code.data());
}
EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret)
{
auto&& ext = _rt->getExt();
auto addr = right160(*_addr256);
auto& code = ext.codeAt(addr);
*_ret = eth2llvm(u256(code.size()));
}
EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret)
{
auto&& ext = _rt->getExt();
auto addr = right160(*_addr256);
auto& code = ext.codeAt(addr);
*_ret = eth2llvm(u256(code.size()));
}
}
}

2
libevmjit/Ext.h

@ -54,7 +54,7 @@ private:
llvm::Function* m_codeAt;
llvm::Function* m_codesizeAt;
};
}
}

24
libevmjit/GasMeter.cpp

@ -28,11 +28,9 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure
{
case Instruction::STOP:
case Instruction::SUICIDE:
case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore()
return 0;
case Instruction::SSTORE:
return static_cast<uint64_t>(c_sstoreResetGas); // FIXME: Check store gas
case Instruction::SLOAD:
return static_cast<uint64_t>(c_sloadGas);
@ -87,7 +85,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
auto module = getModule();
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", module);
InsertPointGuard guard(m_builder);
InsertPointGuard guard(m_builder);
auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc);
auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc);
@ -117,9 +115,8 @@ void GasMeter::count(Instruction _inst)
// Create gas check call with mocked block cost at begining of current cost-block
m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256));
}
if (_inst != Instruction::SSTORE) // Handle cost of SSTORE separately in countSStore()
m_blockCost += getStepCost(_inst);
m_blockCost += getStepCost(_inst);
if (isCostBlockEnd(_inst))
commitCostBlock();
@ -129,20 +126,15 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu
{
assert(!m_checkCall); // Everything should've been commited before
static const auto sstoreCost = static_cast<uint64_t>(c_sstoreResetGas); // FIXME: Check store gas
// [ADD] if oldValue == 0 and newValue != 0 => 2*cost
// [DEL] if oldValue != 0 and newValue == 0 => 0
auto oldValue = _ext.store(_index);
auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero");
auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero");
auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero");
auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
auto isAdd = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isAdd");
auto isDel = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDel");
auto cost = m_builder.CreateSelect(isAdd, Constant::get(2 * sstoreCost), Constant::get(sstoreCost), "cost");
cost = m_builder.CreateSelect(isDel, Constant::get(0), cost, "cost");
auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert");
auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete");
auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost");
cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost");
createCall(m_gasCheckFunc, cost);
}

55
libevmjit/Memory.cpp

@ -31,8 +31,8 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
auto i64Ty = m_builder.getInt64Ty();
llvm::Type* argTypes[] = {i64Ty, i64Ty};
auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false);
m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
"evmccrt_memory_dump", module);
m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
"evmccrt_memory_dump", module);
m_data = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data");
m_data->setUnnamedAddr(true); // Address is not important
@ -74,7 +74,8 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _
m_builder.SetInsertPoint(resizeBB);
// Check gas first
auto wordsRequired = m_builder.CreateUDiv(m_builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired");
auto words = m_builder.CreateUDiv(m_builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words");
sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeRequired");
auto words = m_builder.CreateUDiv(size, Constant::get(32), "words"); // size is always 32*k
auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
_gasMeter.checkMemory(newWords, m_builder);
// Resize
@ -89,7 +90,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _
return func;
}
llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter& _gasMeter)
llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&)
{
auto isWord = _valueType == Type::i256;
@ -103,7 +104,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet
m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
llvm::Value* index = func->arg_begin();
index->setName("index");
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
this->require(index, Constant::get(valueSize));
auto data = m_builder.CreateLoad(m_data, "data");
@ -175,7 +176,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size)
}
void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
{
auto zero256 = llvm::ConstantInt::get(Type::i256, 0);
@ -218,38 +219,14 @@ void Memory::dump(uint64_t _begin, uint64_t _end)
extern "C"
{
using namespace dev::eth::jit;
EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size)
{
auto size = _size->a; // Trunc to 64-bit
auto& memory = _rt->getMemory();
memory.resize(size);
return memory.data();
}
EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end)
{
//if (_end == 0)
// _end = Runtime::getMemory().size();
using namespace dev::eth::jit;
//std::cerr << "MEMORY: active size: " << std::dec
// << Runtime::getMemory().size() / 32 << " words\n";
//std::cerr << "MEMORY: dump from " << std::dec
// << _begin << " to " << _end << ":";
//if (_end <= _begin)
// return;
//_begin = _begin / 16 * 16;
//for (size_t i = _begin; i < _end; i++)
//{
// if ((i - _begin) % 16 == 0)
// std::cerr << '\n' << std::dec << i << ": ";
// auto b = Runtime::getMemory()[i];
// std::cerr << std::hex << std::setw(2) << static_cast<int>(b) << ' ';
//}
//std::cerr << std::endl;
}
EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size)
{
auto size = _size->a; // Trunc to 64-bit
auto& memory = _rt->getMemory();
memory.resize(size);
return memory.data();
}
} // extern "C"
} // extern "C"

2
libevmjit/Memory.h

@ -22,7 +22,7 @@ public:
llvm::Value* getData();
llvm::Value* getSize();
void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex,
llvm::Value* _destMemIdx, llvm::Value* _byteCount);
llvm::Value* _destMemIdx, llvm::Value* _byteCount);
/// Requires this amount of memory. And counts gas fee for that memory.
void require(llvm::Value* _size);

4
libevmjit/Runtime.cpp

@ -73,7 +73,7 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf):
set(RuntimeData::Number, _ext.currentBlock.number);
set(RuntimeData::Difficulty, _ext.currentBlock.difficulty);
set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit);
set(RuntimeData::CodeSize, _ext.code.size()); // TODO: Use constant
set(RuntimeData::CodeSize, _ext.code.size()); // TODO: Use constant
m_data.callData = _ext.data.data();
m_data.code = _ext.code.data();
m_data.jmpBuf = _jmpBuf;
@ -116,7 +116,7 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui
llvm::Value* RuntimeManager::getRuntimePtr()
{
if (auto mainFunc = getMainFunction())
return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function
return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function
return m_builder.CreateLoad(m_dataPtr, "rt");
}

3
libevmjit/Runtime.h

@ -1,9 +1,8 @@
#pragma once
#include <setjmp.h>
#include <vector>
#include <csetjmp>
#include <libevm/ExtVMFace.h>

86
libevmjit/Stack.cpp

@ -14,8 +14,8 @@ namespace eth
namespace jit
{
Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
: CompilerHelper(_builder),
Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager):
CompilerHelper(_builder),
m_runtimeManager(_runtimeManager)
{
m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg");
@ -36,9 +36,6 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module);
}
Stack::~Stack()
{}
llvm::Value* Stack::get(size_t _index)
{
m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg);
@ -71,46 +68,45 @@ size_t Stack::maxStackSize = 0;
extern "C"
{
using namespace dev::eth::jit;
EXPORT void stack_pop(Runtime* _rt, uint64_t _count)
{
auto& stack = _rt->getStack();
if (stack.size() < _count)
longjmp(_rt->getJmpBuf(), static_cast<uint64_t>(ReturnCode::StackTooSmall));
stack.erase(stack.end() - _count, stack.end());
}
EXPORT void stack_push(Runtime* _rt, i256* _word)
{
auto& stack = _rt->getStack();
stack.push_back(*_word);
if (stack.size() > Stack::maxStackSize)
Stack::maxStackSize = stack.size();
}
EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* _ret)
{
auto& stack = _rt->getStack();
// TODO: encode _index and stack size in the return code
if (stack.size() <= _index)
longjmp(_rt->getJmpBuf(), static_cast<uint64_t>(ReturnCode::StackTooSmall));
*_ret = *(stack.rbegin() + _index);
}
EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256* _word)
{
auto& stack = _rt->getStack();
// TODO: encode _index and stack size in the return code
if (stack.size() <= _index)
longjmp(_rt->getJmpBuf(), static_cast<uint64_t>(ReturnCode::StackTooSmall));
*(stack.rbegin() + _index) = *_word;
}
using namespace dev::eth::jit;
EXPORT void stack_pop(Runtime* _rt, uint64_t _count)
{
auto& stack = _rt->getStack();
if (stack.size() < _count)
longjmp(_rt->getJmpBuf(), static_cast<uint64_t>(ReturnCode::StackTooSmall));
stack.erase(stack.end() - _count, stack.end());
}
EXPORT void stack_push(Runtime* _rt, i256* _word)
{
auto& stack = _rt->getStack();
stack.push_back(*_word);
if (stack.size() > Stack::maxStackSize)
Stack::maxStackSize = stack.size();
}
EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* _ret)
{
auto& stack = _rt->getStack();
// TODO: encode _index and stack size in the return code
if (stack.size() <= _index)
longjmp(_rt->getJmpBuf(), static_cast<uint64_t>(ReturnCode::StackTooSmall));
*_ret = *(stack.rbegin() + _index);
}
EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256* _word)
{
auto& stack = _rt->getStack();
// TODO: encode _index and stack size in the return code
if (stack.size() <= _index)
longjmp(_rt->getJmpBuf(), static_cast<uint64_t>(ReturnCode::StackTooSmall));
*(stack.rbegin() + _index) = *_word;
}
} // extern "C"

2
libevmjit/Stack.h

@ -15,9 +15,7 @@ class RuntimeManager;
class Stack : public CompilerHelper
{
public:
Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager);
virtual ~Stack();
llvm::Value* get(size_t _index);
void set(size_t _index, llvm::Value* _value);

10
libevmjit/Type.cpp

@ -41,6 +41,16 @@ llvm::ConstantInt* Constant::get(uint64_t _n)
return llvm::ConstantInt::get(Type::i256, _n);
}
llvm::ConstantInt* Constant::get(u256 _n)
{
auto& backend = _n.backend();
auto words = reinterpret_cast<uint64_t*>(backend.limbs());
auto nWords = backend.limb_bits == 64 ? backend.size() : (backend.size() + 1) / 2;
llvm::APInt n(256, nWords, words);
assert(n.toString(10, false) == _n.str());
return static_cast<llvm::ConstantInt*>(llvm::ConstantInt::get(Type::i256, n));
}
llvm::ConstantInt* Constant::get(ReturnCode _returnCode)
{
return llvm::ConstantInt::get(Type::MainReturn, static_cast<uint64_t>(_returnCode));

2
libevmjit/Type.h

@ -3,6 +3,7 @@
#include <llvm/IR/Type.h>
#include <llvm/IR/Constants.h>
#include <libdevcore/Common.h>
namespace dev
{
@ -51,6 +52,7 @@ struct Constant
{
/// Returns word-size constant
static llvm::ConstantInt* get(uint64_t _n);
static llvm::ConstantInt* get(u256 _n);
static llvm::ConstantInt* get(ReturnCode _returnCode);
};

6
libevmjit/VM.cpp

@ -28,13 +28,15 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
case ReturnCode::OutOfGas:
BOOST_THROW_EXCEPTION(OutOfGas());
case ReturnCode::StackTooSmall:
BOOST_THROW_EXCEPTION(StackTooSmall(1,0));
BOOST_THROW_EXCEPTION(StackTooSmall(1, 0));
case ReturnCode::BadInstruction:
BOOST_THROW_EXCEPTION(BadInstruction());
default:
break;
}
m_output = std::move(engine.returnData);
return {m_output.data(), m_output.size()}; // TODO: This all bytesConstRef stuff sucks
return {m_output.data(), m_output.size()}; // TODO: This all bytesConstRef stuff sucks
}
}

2
neth/CMakeLists.txt

@ -24,7 +24,7 @@ if(JSONRPC_LS)
target_link_libraries(${EXECUTABLE} ${JSONRPC_LS})
endif()
if(EVMCC)
if(EVMJIT)
target_link_libraries(${EXECUTABLE} evmjit)
endif()

9
test/CMakeLists.txt

@ -7,7 +7,6 @@ include_directories(..)
link_directories(../libethcore)
link_directories(../libethereum)
link_directories(../libevm)
link_directories(../libevmjit)
file(GLOB HEADERS "*.h")
add_executable(testeth ${SRC_LIST} ${HEADERS})
@ -20,13 +19,17 @@ target_link_libraries(testeth gmp)
target_link_libraries(testeth solidity)
target_link_libraries(testeth ${CRYPTOPP_LS})
target_link_libraries(testeth evm)
target_link_libraries(testeth evmjit)
if (EVMJIT)
target_link_libraries(testeth evmjit)
endif()
target_link_libraries(createRandomTest ethereum)
target_link_libraries(createRandomTest ethcore)
target_link_libraries(createRandomTest boost_chrono)
target_link_libraries(createRandomTest boost_unit_test_framework)
target_link_libraries(createRandomTest evmjit)
if (EVMJIT)
target_link_libraries(createRandomTest evmjit)
endif()
if ("${TARGET_PLATFORM}" STREQUAL "w64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")

2
windows/LLVM.props

@ -14,7 +14,7 @@
<ClCompile>
<AdditionalIncludeDirectories>$(LLVMIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PreprocessorDefinitions>ETH_JIT=$(LLVMEnabled);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>ETH_EVMJIT=$(LLVMEnabled);%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(LLVMLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

Loading…
Cancel
Save