Browse Source

Merge branch 'develop-evmcc' into pr-jit

cl-refactor
Paweł Bylica 11 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(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(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(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() endfunction()
@ -39,6 +40,14 @@ function(configureProject)
message(FATAL_ERROR "VM tracing requires debug.") message(FATAL_ERROR "VM tracing requires debug.")
endif () endif ()
endif () endif ()
if (EVMJIT)
if (LANGUAGES)
message(FATAL_ERROR "Unset LANGUAGES to build EVMJIT")
else()
add_definitions(-DETH_EVMJIT)
endif()
endif()
endfunction() endfunction()
@ -75,7 +84,7 @@ cmake_policy(SET CMP0015 NEW)
createDefaultCacheConfig() createDefaultCacheConfig()
configureProject() 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". # Default TARGET_PLATFORM to "linux".
@ -158,9 +167,9 @@ if (NOT LANGUAGES)
endif() endif()
endif() endif()
if (EVMCC) if (EVMJIT)
add_subdirectory(libevmjit) add_subdirectory(libevmjit)
add_subdirectory(evmcc) add_subdirectory(evmcc)
endif() endif()

2
eth/CMakeLists.txt

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

7
evmcc/CMakeLists.txt

@ -25,8 +25,6 @@ if ("${TARGET_PLATFORM}" STREQUAL "w64")
target_link_libraries(${EXECUTABLE} iphlpapi) target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
else () else ()
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) 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}) include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS}) add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen) # llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen)
target_link_libraries(evmcc ${llvm_libs}) # target_link_libraries(evmcc ${llvm_libs})
# end of LLVM specific commands # end of LLVM specific commands
install( TARGETS ${EXECUTABLE} DESTINATION bin ) install( TARGETS ${EXECUTABLE} DESTINATION bin )
cmake_policy(SET CMP0015 NEW) cmake_policy(SET CMP0015 NEW)

2
evmcc/evmcc.cpp

@ -8,8 +8,6 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <llvm/Support/raw_os_ostream.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.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" : [ ], "callcreates" : [ ],
"env" : { "env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
@ -40,7 +82,7 @@
} }
}, },
"recloop" : { "recloop0x40000" : {
"callcreates" : [ ], "callcreates" : [ ],
"env" : { "env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "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() endif()
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LS})
if(EVMCC) if(EVMJIT)
target_link_libraries(${EXECUTABLE} evmjit) target_link_libraries(${EXECUTABLE} evmjit)
endif() 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> VMFace::create(VMFace::Kind _kind, u256 _gas)
{ {
std::unique_ptr<VMFace> vm; std::unique_ptr<VMFace> vm;
#if ETH_JIT #if ETH_EVMJIT
vm.reset(_kind == Kind::JIT ? static_cast<VMFace*>(new jit::VM) : new VM); vm.reset(_kind == Kind::JIT ? static_cast<VMFace*>(new jit::VM) : new VM);
#else #else
(void) _kind; // suppress unused var warning
vm.reset(new VM); vm.reset(new VM);
#endif #endif
vm->reset(_gas); 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" extern "C"
{ {
using namespace dev::eth::jit; using namespace dev::eth::jit;
EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* _result) EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* _result)
{ {
dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2); dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg1 * arg2); *_result = eth2llvm(arg1 * arg2);
} }
EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* _result) EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* _result)
{ {
dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2); dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2);
} }
EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* _result) EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* _result)
{ {
dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2); dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2);
} }
EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* _result) EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* _result)
{ {
dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2); dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2))); *_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2)));
} }
EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* _result) EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* _result)
{ {
dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2); dev::u256 arg2 = llvm2eth(*_arg2);
*_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) % dev::u2s(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) EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result)
{ {
dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2); dev::u256 arg2 = llvm2eth(*_arg2);
dev::u256 arg3 = llvm2eth(*_arg3); dev::u256 arg3 = llvm2eth(*_arg3);
*_result = eth2llvm(dev::u256((dev::bigint(arg1) * dev::bigint(arg2)) % arg3)); *_result = eth2llvm(dev::u256((dev::bigint(arg1) * dev::bigint(arg2)) % arg3));
} }
EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result) EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* _result)
{ {
dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg1 = llvm2eth(*_arg1);
dev::u256 arg2 = llvm2eth(*_arg2); dev::u256 arg2 = llvm2eth(*_arg2);
dev::u256 arg3 = llvm2eth(*_arg3); dev::u256 arg3 = llvm2eth(*_arg3);
*_result = eth2llvm(dev::u256((dev::bigint(arg1) + dev::bigint(arg2)) % 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 // Push new values
for ( ; currIter < endIter; ++currIter) for (; currIter < endIter; ++currIter)
{ {
assert(*currIter != nullptr); assert(*currIter != nullptr);
_evmStack.push(*currIter); _evmStack.push(*currIter);
@ -243,11 +243,11 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
{ {
if (getenv("EVMCC_DEBUG_BLOCKS")) if (getenv("EVMCC_DEBUG_BLOCKS"))
{ {
for (auto& pair: cfg) for (auto& pair : cfg)
std::cerr << pair.second.bblock.llvm()->getName().str() std::cerr << pair.second.bblock.llvm()->getName().str()
<< ": in " << pair.second.inputItems << ": in " << pair.second.inputItems
<< ", out " << pair.second.outputItems << ", out " << pair.second.outputItems
<< "\n"; << "\n";
} }
valuesChanged = false; valuesChanged = false;
@ -347,7 +347,7 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput)
out << (_dotOutput ? "\\l" : "\n"); out << (_dotOutput ? "\\l" : "\n");
} }
out << (_dotOutput ? "| " : "Instructions:\n"); out << (_dotOutput ? "| " : "Instructions:\n");
for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins)
out << *ins << (_dotOutput ? "\\l" : "\n"); out << *ins << (_dotOutput ? "\\l" : "\n");

2
libevmjit/BasicBlock.h

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

7
libevmjit/CMakeLists.txt

@ -20,6 +20,7 @@ target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmface)
if ("${TARGET_PLATFORM}" STREQUAL "w64") if ("${TARGET_PLATFORM}" STREQUAL "w64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
target_link_libraries(${EXECUTABLE} gcc) target_link_libraries(${EXECUTABLE} gcc)
@ -30,14 +31,12 @@ if ("${TARGET_PLATFORM}" STREQUAL "w64")
target_link_libraries(${EXECUTABLE} iphlpapi) target_link_libraries(${EXECUTABLE} iphlpapi)
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
else () else ()
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT})
endif () endif ()
# LLVM specific commands # LLVM specific config
find_package(LLVM REQUIRED 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) llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen)
target_link_libraries(evmjit ${llvm_libs}) 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(): Compiler::Compiler():
m_builder(llvm::getGlobalContext()) m_builder(llvm::getGlobalContext()),
m_jumpTableBlock(),
m_badJumpBlock()
{ {
Type::init(m_builder.getContext()); Type::init(m_builder.getContext());
} }
@ -46,7 +48,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
std::vector<ProgramCounter> indirectJumpTargets; std::vector<ProgramCounter> indirectJumpTargets;
boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); 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; validJumpTargets[0] = true;
for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) 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. // 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]) if (*it > bytecode.size() || !validJumpTargets[*it])
it = splitPoints.erase(it); it = splitPoints.erase(it);
@ -128,7 +130,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
++it; ++it;
} }
for (auto it = splitPoints.cbegin(); it != splitPoints.cend(); ) for (auto it = splitPoints.cbegin(); it != splitPoints.cend();)
{ {
auto beginInstIdx = *it; auto beginInstIdx = *it;
++it; ++it;
@ -137,8 +139,8 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode)
} }
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
m_badJumpBlock = std::make_unique<BasicBlock>("BadJumpBlock", m_mainFunc, m_builder); m_badJumpBlock = std::unique_ptr<BasicBlock>(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder));
m_jumpTableBlock = std::make_unique<BasicBlock>("JumpTableBlock", 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) 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) 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 // 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); auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, mainFuncArgTypes, false);
m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get()); m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get());
m_mainFunc->arg_begin()->getNextNode()->setName("rt"); 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) if (m_indirectJumpTargets.size() > 0)
{ {
auto dest = m_jumpTableBlock->localStack().pop(); auto dest = m_jumpTableBlock->localStack().pop();
auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(),
m_indirectJumpTargets.size()); m_indirectJumpTargets.size());
for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it)
{ {
auto& bb = *it; auto& bb = *it;
@ -372,14 +374,13 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
break; break;
} }
/*case Instruction::NEG: case Instruction::BNOT:
{ {
auto top = stack.pop(); auto value = stack.pop();
auto zero = Constant::get(0); auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot");
auto res = m_builder.CreateSub(zero, top); stack.push(ret);
stack.push(res);
break; break;
}*/ }
case Instruction::LT: case Instruction::LT:
{ {
@ -505,6 +506,36 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
break; 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: case Instruction::SHA3:
{ {
auto inOff = stack.pop(); auto inOff = stack.pop();
@ -523,29 +554,28 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
case Instruction::ANY_PUSH: 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); 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 <<= 8;
value |= bytecode[currentPC]; value |= bytecode[++currentPC];
} }
auto c = m_builder.getInt(value);
stack.push(c); stack.push(m_builder.getInt(value));
break; break;
} }
case Instruction::ANY_DUP: 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); stack.dup(index);
break; break;
} }
case Instruction::ANY_SWAP: 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); stack.swap(index);
break; break;
} }
@ -610,9 +640,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
{ {
auto pairIter = m_directJumpTargets.find(currentPC); auto pairIter = m_directJumpTargets.find(currentPC);
if (pairIter != m_directJumpTargets.end()) if (pairIter != m_directJumpTargets.end())
{
targetBlock = pairIter->second; targetBlock = pairIter->second;
}
} }
if (inst == Instruction::JUMP) if (inst == Instruction::JUMP)
@ -625,9 +653,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
m_builder.CreateBr(targetBlock); m_builder.CreateBr(targetBlock);
} }
else else
{
m_builder.CreateBr(m_jumpTableBlock->llvm()); m_builder.CreateBr(m_jumpTableBlock->llvm());
}
} }
else // JUMPI else // JUMPI
{ {
@ -636,8 +662,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
auto zero = Constant::get(0); auto zero = Constant::get(0);
auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); 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) if (targetBlock)
{ {
@ -645,9 +672,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock);
} }
else else
{
m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock);
}
} }
break; break;
@ -721,7 +746,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
auto srcIdx = stack.pop(); auto srcIdx = stack.pop();
auto reqBytes = 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); auto srcSize = _runtimeManager.get(RuntimeData::CodeSize);
memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes);
@ -826,12 +851,12 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
gasMeter.commitCostBlock(); gasMeter.commitCostBlock();
if (!basicBlock.llvm()->getTerminator()) // If block not terminated if (!basicBlock.llvm()->getTerminator()) // If block not terminated
{ {
if (nextBasicBlock) if (nextBasicBlock)
m_builder.CreateBr(nextBasicBlock); // Branch to the next block m_builder.CreateBr(nextBasicBlock); // Branch to the next block
else 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) void Compiler::dumpBasicBlockGraph(std::ostream& out)
{ {
out << "digraph BB {\n" out << "digraph BB {\n"
<< " node [shape=record, fontname=Courier, fontsize=10];\n" << " node [shape=record, fontname=Courier, fontsize=10];\n"
<< " entry [share=record, label=\"entry block\"];\n"; << " entry [share=record, label=\"entry block\"];\n";
std::vector<BasicBlock*> blocks; std::vector<BasicBlock*> blocks;
for (auto& pair : basicBlocks) 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) for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it)
{ {
out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" ["
<< ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "")
//<< "label = \"" //<< "label = \""
//<< phiNodesPerBlock[bb] //<< phiNodesPerBlock[bb]
<< "];\n"; << "];\n";
} }
} }

15
libevmjit/ExecutionEngine.cpp

@ -1,9 +1,11 @@
#include "ExecutionEngine.h" #include "ExecutionEngine.h"
#include <csetjmp> #include <csetjmp>
#include <chrono> #include <chrono>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <llvm/IR/LLVMContext.h> #include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/ADT/Triple.h> #include <llvm/ADT/Triple.h>
@ -16,6 +18,9 @@
#include <llvm/Support/PrettyStackTrace.h> #include <llvm/Support/PrettyStackTrace.h>
#include <llvm/Support/Host.h> #include <llvm/Support/Host.h>
#pragma GCC diagnostic pop
#include <libevm/VM.h> #include <libevm/VM.h>
#include "Runtime.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()); auto triple = llvm::Triple(llvm::sys::getProcessTriple());
if (triple.getOS() == llvm::Triple::OSType::Win32) 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()); module->setTargetTriple(triple.str());
auto exec = std::unique_ptr<llvm::ExecutionEngine>(builder.create()); auto exec = std::unique_ptr<llvm::ExecutionEngine>(builder.create());
if (!exec) if (!exec)
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment(errorMsg)); 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(); auto finalizationStartTime = std::chrono::high_resolution_clock::now();
exec->finalizeObject(); exec->finalizeObject();
auto finalizationEndTime = std::chrono::high_resolution_clock::now(); auto finalizationEndTime = std::chrono::high_resolution_clock::now();
clog(JIT) << "Module finalization time: " 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 // Create fake ExtVM interface
if (!_ext) 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(); auto executionEndTime = std::chrono::high_resolution_clock::now();
clog(JIT) << "Execution time : " 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 else

211
libevmjit/Ext.cpp

@ -6,6 +6,7 @@
#include <llvm/IR/IntrinsicInst.h> #include <llvm/IR/IntrinsicInst.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libevm/FeeStructure.h>
#include "Runtime.h" #include "Runtime.h"
#include "Type.h" #include "Type.h"
@ -24,21 +25,14 @@ inline u256 fromAddress(Address _a)
return (u160)_a; return (u160)_a;
} }
struct ExtData
{
const byte* calldata;
const byte* code;
};
Ext::Ext(RuntimeManager& _runtimeManager): Ext::Ext(RuntimeManager& _runtimeManager):
RuntimeHelper(_runtimeManager) RuntimeHelper(_runtimeManager),
m_data()
{ {
auto&& ctx = m_builder.getContext(); auto&& ctx = m_builder.getContext();
auto module = getModule(); auto module = getModule();
auto i256Ty = m_builder.getIntNTy(256); 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[0] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.index");
m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value"); m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value");
@ -172,123 +166,128 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr)
extern "C" extern "C"
{ {
using namespace dev::eth::jit; using namespace dev::eth::jit;
EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value) EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value)
{ {
auto index = llvm2eth(*_index); auto index = llvm2eth(*_index);
auto value = _rt->getExt().store(index); // Interface uses native endianness auto value = _rt->getExt().store(index); // Interface uses native endianness
*_value = eth2llvm(value); *_value = eth2llvm(value);
} }
EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value) EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value)
{ {
auto index = llvm2eth(*_index); auto index = llvm2eth(*_index);
auto value = llvm2eth(*_value); auto value = llvm2eth(*_value);
_rt->getExt().setStore(index, value); // Interface uses native endianness auto& ext = _rt->getExt();
}
EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value) if (value == 0 && ext.store(index) != 0) // If delete
{ ext.sub.refunds += c_sstoreRefundGas; // Increase refund counter
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_balance(Runtime* _rt, h256* _address, i256* _value) ext.setStore(index, value); // Interface uses native endianness
{ }
auto u = _rt->getExt().balance(right160(*_address));
*_value = eth2llvm(u);
}
EXPORT void ext_suicide(Runtime* _rt, h256* _address) EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value)
{ {
_rt->getExt().suicide(right160(*_address)); 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) EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* _value)
{ {
auto&& ext = _rt->getExt(); auto u = _rt->getExt().balance(right160(*_address));
auto endowment = llvm2eth(*_endowment); *_value = eth2llvm(u);
}
if (ext.balance(ext.myAddress) >= endowment) EXPORT void ext_suicide(Runtime* _rt, h256* _address)
{ {
ext.subBalance(endowment); _rt->getExt().suicide(right160(*_address));
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_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; 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 gas = llvm2eth(*_gas); {
if (ext.balance(ext.myAddress) >= value) 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 inOff = static_cast<size_t>(llvm2eth(*_inOff));
auto inSize = static_cast<size_t>(llvm2eth(*_inSize)); auto inSize = static_cast<size_t>(llvm2eth(*_inSize));
auto outOff = static_cast<size_t>(llvm2eth(*_outOff)); auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize);
auto outSize = static_cast<size_t>(llvm2eth(*_outSize)); auto hash = sha3(dataRef);
auto&& inRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); *_ret = *reinterpret_cast<i256*>(&hash);
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); EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* _ret)
_ret->a = ret ? 1 : 0; {
} bigint left = llvm2eth(*_left);
bigint right = llvm2eth(*_right);
EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret) auto ret = static_cast<u256>(boost::multiprecision::powm(left, right, bigint(2) << 256));
{ *_ret = eth2llvm(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 unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256)
{ {
auto&& ext = _rt->getExt(); auto&& ext = _rt->getExt();
auto addr = right160(*_addr256); auto addr = right160(*_addr256);
auto& code = ext.codeAt(addr); auto& code = ext.codeAt(addr);
return const_cast<unsigned char*>(code.data()); return const_cast<unsigned char*>(code.data());
} }
EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret) EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret)
{ {
auto&& ext = _rt->getExt(); auto&& ext = _rt->getExt();
auto addr = right160(*_addr256); auto addr = right160(*_addr256);
auto& code = ext.codeAt(addr); auto& code = ext.codeAt(addr);
*_ret = eth2llvm(u256(code.size())); *_ret = eth2llvm(u256(code.size()));
} }
} }
} }

2
libevmjit/Ext.h

@ -54,7 +54,7 @@ private:
llvm::Function* m_codeAt; llvm::Function* m_codeAt;
llvm::Function* m_codesizeAt; 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::STOP:
case Instruction::SUICIDE: case Instruction::SUICIDE:
case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore()
return 0; return 0;
case Instruction::SSTORE:
return static_cast<uint64_t>(c_sstoreResetGas); // FIXME: Check store gas
case Instruction::SLOAD: case Instruction::SLOAD:
return static_cast<uint64_t>(c_sloadGas); return static_cast<uint64_t>(c_sloadGas);
@ -87,7 +85,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
auto module = getModule(); auto module = getModule();
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", module); 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 checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc);
auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", 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 // 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)); 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)) if (isCostBlockEnd(_inst))
commitCostBlock(); 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 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 oldValue = _ext.store(_index);
auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero"); auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero");
auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero"); auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero");
auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero"); auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero");
auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
auto isAdd = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isAdd"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert");
auto isDel = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDel"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete");
auto cost = m_builder.CreateSelect(isAdd, Constant::get(2 * sstoreCost), Constant::get(sstoreCost), "cost"); auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost");
cost = m_builder.CreateSelect(isDel, Constant::get(0), cost, "cost"); cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost");
createCall(m_gasCheckFunc, cost); createCall(m_gasCheckFunc, cost);
} }

55
libevmjit/Memory.cpp

@ -31,8 +31,8 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
auto i64Ty = m_builder.getInt64Ty(); auto i64Ty = m_builder.getInt64Ty();
llvm::Type* argTypes[] = {i64Ty, i64Ty}; llvm::Type* argTypes[] = {i64Ty, i64Ty};
auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false); auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false);
m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
"evmccrt_memory_dump", module); "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 = 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 m_data->setUnnamedAddr(true); // Address is not important
@ -74,7 +74,8 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _
m_builder.SetInsertPoint(resizeBB); m_builder.SetInsertPoint(resizeBB);
// Check gas first // Check gas first
auto wordsRequired = m_builder.CreateUDiv(m_builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired"); 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"); auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
_gasMeter.checkMemory(newWords, m_builder); _gasMeter.checkMemory(newWords, m_builder);
// Resize // Resize
@ -89,7 +90,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _
return func; 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; 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)); m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
llvm::Value* index = func->arg_begin(); llvm::Value* index = func->arg_begin();
index->setName("index"); index->setName("index");
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
this->require(index, Constant::get(valueSize)); this->require(index, Constant::get(valueSize));
auto data = m_builder.CreateLoad(m_data, "data"); 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, 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); auto zero256 = llvm::ConstantInt::get(Type::i256, 0);
@ -218,38 +219,14 @@ void Memory::dump(uint64_t _begin, uint64_t _end)
extern "C" extern "C"
{ {
using namespace dev::eth::jit; 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();
//std::cerr << "MEMORY: active size: " << std::dec EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size)
// << Runtime::getMemory().size() / 32 << " words\n"; {
//std::cerr << "MEMORY: dump from " << std::dec auto size = _size->a; // Trunc to 64-bit
// << _begin << " to " << _end << ":"; auto& memory = _rt->getMemory();
//if (_end <= _begin) memory.resize(size);
// return; return memory.data();
}
//_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;
}
} // extern "C" } // extern "C"

2
libevmjit/Memory.h

@ -22,7 +22,7 @@ public:
llvm::Value* getData(); llvm::Value* getData();
llvm::Value* getSize(); llvm::Value* getSize();
void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex, 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. /// Requires this amount of memory. And counts gas fee for that memory.
void require(llvm::Value* _size); 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::Number, _ext.currentBlock.number);
set(RuntimeData::Difficulty, _ext.currentBlock.difficulty); set(RuntimeData::Difficulty, _ext.currentBlock.difficulty);
set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); 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.callData = _ext.data.data();
m_data.code = _ext.code.data(); m_data.code = _ext.code.data();
m_data.jmpBuf = _jmpBuf; m_data.jmpBuf = _jmpBuf;
@ -116,7 +116,7 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui
llvm::Value* RuntimeManager::getRuntimePtr() llvm::Value* RuntimeManager::getRuntimePtr()
{ {
if (auto mainFunc = getMainFunction()) 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"); return m_builder.CreateLoad(m_dataPtr, "rt");
} }

3
libevmjit/Runtime.h

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

86
libevmjit/Stack.cpp

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

2
libevmjit/Stack.h

@ -15,9 +15,7 @@ class RuntimeManager;
class Stack : public CompilerHelper class Stack : public CompilerHelper
{ {
public: public:
Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager);
virtual ~Stack();
llvm::Value* get(size_t _index); llvm::Value* get(size_t _index);
void set(size_t _index, llvm::Value* _value); 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); 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) llvm::ConstantInt* Constant::get(ReturnCode _returnCode)
{ {
return llvm::ConstantInt::get(Type::MainReturn, static_cast<uint64_t>(_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/Type.h>
#include <llvm/IR/Constants.h> #include <llvm/IR/Constants.h>
#include <libdevcore/Common.h>
namespace dev namespace dev
{ {
@ -51,6 +52,7 @@ struct Constant
{ {
/// Returns word-size constant /// Returns word-size constant
static llvm::ConstantInt* get(uint64_t _n); static llvm::ConstantInt* get(uint64_t _n);
static llvm::ConstantInt* get(u256 _n);
static llvm::ConstantInt* get(ReturnCode _returnCode); 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: case ReturnCode::OutOfGas:
BOOST_THROW_EXCEPTION(OutOfGas()); BOOST_THROW_EXCEPTION(OutOfGas());
case ReturnCode::StackTooSmall: case ReturnCode::StackTooSmall:
BOOST_THROW_EXCEPTION(StackTooSmall(1,0)); BOOST_THROW_EXCEPTION(StackTooSmall(1, 0));
case ReturnCode::BadInstruction: case ReturnCode::BadInstruction:
BOOST_THROW_EXCEPTION(BadInstruction()); BOOST_THROW_EXCEPTION(BadInstruction());
default:
break;
} }
m_output = std::move(engine.returnData); 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}) target_link_libraries(${EXECUTABLE} ${JSONRPC_LS})
endif() endif()
if(EVMCC) if(EVMJIT)
target_link_libraries(${EXECUTABLE} evmjit) target_link_libraries(${EXECUTABLE} evmjit)
endif() endif()

9
test/CMakeLists.txt

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

2
windows/LLVM.props

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

Loading…
Cancel
Save