From 0a78fe0756bc94c3f2113c3ee0ffe9c88c819302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 25 Sep 2014 11:07:49 +0200 Subject: [PATCH 001/396] Init of evmcc - EVM Code Compiler --- CMakeLists.txt | 5 ++ evmcc/CMakeLists.txt | 49 ++++++++++++ evmcc/bytecode/kv.evm | 1 + evmcc/evmcc.cpp | 180 ++++++++++++++++++++++++++++++++++++++++++ evmcc/lll/kv.lll | 10 +++ 5 files changed, 245 insertions(+) create mode 100644 evmcc/CMakeLists.txt create mode 100644 evmcc/bytecode/kv.evm create mode 100644 evmcc/evmcc.cpp create mode 100644 evmcc/lll/kv.lll diff --git a/CMakeLists.txt b/CMakeLists.txt index 46cc0753f..d69e1e958 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -374,6 +374,11 @@ if (NOT LANGUAGES) endif() endif() +if (EVMCC) + add_subdirectory(evmcc) +endif() + + set(CMAKE_INCLUDE_CURRENT_DIR ON) set(SRC_LIST BuildInfo.h) diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt new file mode 100644 index 000000000..b91b2d257 --- /dev/null +++ b/evmcc/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_policy(SET CMP0015 NEW) + +aux_source_directory(. SRC_LIST) + +include_directories(..) + +set(EXECUTABLE evmcc) + +add_executable(${EXECUTABLE} ${SRC_LIST}) + +target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} devcore) + +if ("${TARGET_PLATFORM}" STREQUAL "w64") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") + target_link_libraries(${EXECUTABLE} gcc) + target_link_libraries(${EXECUTABLE} gdi32) + target_link_libraries(${EXECUTABLE} ws2_32) + target_link_libraries(${EXECUTABLE} mswsock) + target_link_libraries(${EXECUTABLE} shlwapi) + target_link_libraries(${EXECUTABLE} iphlpapi) + target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) + set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) +elseif (UNIX) +else () + find_package(Threads REQUIRED) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +endif () + +# LLVM specific commands + +find_package(LLVM REQUIRED CONFIG) + +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) + +llvm_map_components_to_libnames(llvm_libs support core irreader) +target_link_libraries(etc ${llvm_libs}) + +# end of LLVM specific commands + + + +install( TARGETS ${EXECUTABLE} DESTINATION bin ) + +cmake_policy(SET CMP0015 NEW) diff --git a/evmcc/bytecode/kv.evm b/evmcc/bytecode/kv.evm new file mode 100644 index 000000000..55141ea59 --- /dev/null +++ b/evmcc/bytecode/kv.evm @@ -0,0 +1 @@ +33604557602a8060106000396000f200604556330e0f602a59366080530a0f602a59602060805301356080533557604060805301608054600958 diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp new file mode 100644 index 000000000..94fcb956b --- /dev/null +++ b/evmcc/evmcc.cpp @@ -0,0 +1,180 @@ +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace dev; + +class EVMCCompiler +{ + +private: + + struct + { + llvm::Type* word8; + llvm::Type* word8ptr; + llvm::Type* word256; + llvm::Type* word256ptr; + llvm::Type* word256arr; + llvm::Type* size; + } Types; + +public: + + EVMCCompiler() + { + auto& context = llvm::getGlobalContext(); + Types.word8 = llvm::Type::getInt8Ty(context); + Types.word8ptr = llvm::Type::getInt8PtrTy(context); + Types.word256 = llvm::Type::getIntNTy(context, 256); + Types.word256ptr = Types.word256->getPointerTo(); + Types.word256arr = llvm::ArrayType::get(Types.word256, 100); + Types.size = llvm::Type::getInt64Ty(context); + } + + void compile(const bytes& bytecode) + { + using namespace llvm; + + auto& context = getGlobalContext(); + + Module* module = new Module("main", context); + IRBuilder<> builder(context); + + // Create globals for memory, memory size, stack and stack top + auto memory = new GlobalVariable(*module, Types.word8ptr, false, + GlobalValue::LinkageTypes::PrivateLinkage, + Constant::getNullValue(Types.word8ptr), "memory"); + auto memSize = new GlobalVariable(*module, Types.size, false, + GlobalValue::LinkageTypes::PrivateLinkage, + ConstantInt::get(Types.size, 0), "memsize"); + auto stack = new GlobalVariable(*module, Types.word256arr, false, + GlobalValue::LinkageTypes::PrivateLinkage, + ConstantAggregateZero::get(Types.word256arr), "stack"); + auto stackTop = new GlobalVariable(*module, Types.size, false, + GlobalValue::LinkageTypes::PrivateLinkage, + ConstantInt::get(Types.size, 0), "stackTop"); + + // Create value for void* malloc(size_t) + std::vector mallocArgTypes = { Types.size }; + Value* mallocVal = Function::Create(FunctionType::get(Types.word8ptr, mallocArgTypes, false), + GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module); + + // Create main function + FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false); + Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module); + + BasicBlock* entryBlock = BasicBlock::Create(context, "entry", mainFunc); + builder.SetInsertPoint(entryBlock); + + // Initialize memory with call to malloc, update memsize + std::vector mallocMemArgs = { ConstantInt::get(Types.size, 100) }; + auto mallocMemCall = builder.CreateCall(mallocVal, mallocMemArgs, "malloc_mem"); + builder.CreateStore(mallocMemCall, memory); + builder.CreateStore(ConstantInt::get(Types.size, 100), memSize); + + /* + std::vector mallocStackArgs = { ConstantInt::get(sizeTy, 200) }; + auto mallocStackCall = builder.CreateCall(mallocVal, mallocStackArgs, "malloc_stack"); + auto mallocCast = builder.CreatePointerBitCastOrAddrSpaceCast(mallocStackCall, int256ptr); + builder.CreateStore(mallocCast, stackVal); + */ + + builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 0)); + + module->dump(); + } + +}; + +void show_usage() +{ + // FIXME: Use arg[0] as program name? + std::cerr << "usage: evmcc (-b|-c|-d)+ \n"; +} + +int main(int argc, char** argv) +{ + + std::string input_file; + bool opt_dissassemble = false; + bool opt_show_bytes = false; + bool opt_compile = false; + bool opt_unknown = false; + + for (int i = 1; i < argc; i++) + { + std::string option = argv[i]; + if (option == "-b") + { + opt_show_bytes = true; + } + else if (option == "-c") + { + opt_compile = true; + } + else if (option == "-d") + { + opt_dissassemble = true; + } + else if (option[0] != '-' && input_file.empty()) + { + input_file = option; + } + else + { + opt_unknown = true; + break; + } + } + + if (opt_unknown || + input_file.empty() || + (!opt_show_bytes && !opt_compile && !opt_dissassemble)) + { + show_usage(); + exit(1); + } + + std::ifstream ifs(input_file); + if (!ifs.is_open()) + { + std::cerr << "cannot open file " << input_file << std::endl; + exit(1); + } + + std::string src((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + + boost::algorithm::trim(src); + + bytes bytecode = fromHex(src); + + if (opt_show_bytes) + { + std::cout << dev::memDump(bytecode) << std::endl; + } + + if (opt_dissassemble) + { + std::string assembly = eth::disassemble(bytecode); + std::cout << assembly << std::endl; + } + + if (opt_compile) + { + EVMCCompiler().compile(bytecode); + } + + return 0; +} diff --git a/evmcc/lll/kv.lll b/evmcc/lll/kv.lll new file mode 100644 index 000000000..c62d9fa70 --- /dev/null +++ b/evmcc/lll/kv.lll @@ -0,0 +1,10 @@ +{ + [[69]] (caller) + (return 0 (lll + (when (= (caller) @@69) + (for {} (< @i (calldatasize)) [i](+ @i 64) + [[ (calldataload @i) ]] (calldataload (+ @i 32)) + ) + ) + 0)) +} From a3a33112be79ba72eac1a8cd07f15a3a9345374c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 25 Sep 2014 10:46:12 +0100 Subject: [PATCH 002/396] etc --> evmcc in cmakefile --- evmcc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index b91b2d257..550492583 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -38,7 +38,7 @@ include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(llvm_libs support core irreader) -target_link_libraries(etc ${llvm_libs}) +target_link_libraries(evmcc ${llvm_libs}) # end of LLVM specific commands From 76975a1b42ba7a06f787bac4b25a9b8f314c7433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 25 Sep 2014 18:14:00 +0200 Subject: [PATCH 003/396] Visual Studio project config for evmcc --- windows/Ethereum.sln | 2 + windows/evmcc.vcxproj | 170 ++++++++++++++++++++++++++++++++++ windows/evmcc.vcxproj.filters | 6 ++ 3 files changed, 178 insertions(+) create mode 100644 windows/evmcc.vcxproj create mode 100644 windows/evmcc.vcxproj.filters diff --git a/windows/Ethereum.sln b/windows/Ethereum.sln index 26fe794c2..96b5f4c9e 100644 --- a/windows/Ethereum.sln +++ b/windows/Ethereum.sln @@ -37,6 +37,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sc", "Sc.vcxproj", "{90068D EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lllc", "Lllc.vcxproj", "{255BDC68-B8DB-465F-8220-981E77684189}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "evmcc", "evmcc.vcxproj", "{D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj new file mode 100644 index 000000000..f521a8264 --- /dev/null +++ b/windows/evmcc.vcxproj @@ -0,0 +1,170 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} + Win32Proj + evmcc + + + + Application + true + v120 + Unicode + + + Application + true + v120 + + + Application + false + v120 + true + Unicode + + + Application + false + v120 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + true + ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ + ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ + + + true + + + false + ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ + ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + ../ + + + Console + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + ../../llvm-3.5.0/include;../../builds/llvm3.5/include;%(AdditionalIncludeDirectories) + 4068;4244;4267;4800 + + + Console + true + ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) + LibEthereum.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + ../../llvm-3.5.0/include;../../builds/llvm3.5/include;%(AdditionalIncludeDirectories) + 4068;4244;4267;4800 + + + Console + true + true + true + ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) + LibEthereum.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters new file mode 100644 index 000000000..6be5386a1 --- /dev/null +++ b/windows/evmcc.vcxproj.filters @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From f4c7a514e9255dec382743e6f19f1419738054ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 26 Sep 2014 11:12:16 +0200 Subject: [PATCH 004/396] Fixing evmcc Visual Studio project settings --- windows/Ethereum.sln | 14 ++++++-------- windows/evmcc.vcxproj | 4 ++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/windows/Ethereum.sln b/windows/Ethereum.sln index 96b5f4c9e..c894b8a79 100644 --- a/windows/Ethereum.sln +++ b/windows/Ethereum.sln @@ -111,14 +111,6 @@ Global {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|Win32.Build.0 = Release|Win32 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|x64.ActiveCfg = Release|x64 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|x64.Build.0 = Release|x64 - {326EF470-463F-4751-A22A-48BBAAD8B143}.Debug|Win32.ActiveCfg = Debug|Win32 - {326EF470-463F-4751-A22A-48BBAAD8B143}.Debug|Win32.Build.0 = Debug|Win32 - {326EF470-463F-4751-A22A-48BBAAD8B143}.Debug|x64.ActiveCfg = Debug|x64 - {326EF470-463F-4751-A22A-48BBAAD8B143}.Debug|x64.Build.0 = Debug|x64 - {326EF470-463F-4751-A22A-48BBAAD8B143}.Release|Win32.ActiveCfg = Release|Win32 - {326EF470-463F-4751-A22A-48BBAAD8B143}.Release|Win32.Build.0 = Release|Win32 - {326EF470-463F-4751-A22A-48BBAAD8B143}.Release|x64.ActiveCfg = Release|x64 - {326EF470-463F-4751-A22A-48BBAAD8B143}.Release|x64.Build.0 = Release|x64 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Debug|Win32.ActiveCfg = Debug|Win32 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Debug|Win32.Build.0 = Debug|Win32 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Debug|x64.ActiveCfg = Debug|x64 @@ -175,6 +167,12 @@ Global {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.Build.0 = Release|Win32 {255BDC68-B8DB-465F-8220-981E77684189}.Release|x64.ActiveCfg = Release|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Release|x64.Build.0 = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.ActiveCfg = Debug|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.Build.0 = Debug|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|x64.ActiveCfg = Debug|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.ActiveCfg = Release|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.Build.0 = Release|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|x64.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index f521a8264..5b09e5f0d 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -104,6 +104,8 @@ Console true + ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) + LibEthereum.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -140,6 +142,8 @@ true true true + ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) + LibEthereum.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) From f378909442c2b64217c710080dbf9ea2eaa2c594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 26 Sep 2014 11:14:37 +0200 Subject: [PATCH 005/396] Moving Compiler to separated files --- evmcc/Compiler.cpp | 75 +++++++++++++++++++++++++++ evmcc/Compiler.h | 34 +++++++++++++ evmcc/evmcc.cpp | 96 +++-------------------------------- windows/evmcc.vcxproj | 4 ++ windows/evmcc.vcxproj.filters | 4 ++ 5 files changed, 124 insertions(+), 89 deletions(-) create mode 100644 evmcc/Compiler.cpp create mode 100644 evmcc/Compiler.h diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp new file mode 100644 index 000000000..209e79c6f --- /dev/null +++ b/evmcc/Compiler.cpp @@ -0,0 +1,75 @@ + +#include "Compiler.h" + +#include +#include + +namespace evmcc +{ + +Compiler::Compiler() +{ + auto& context = llvm::getGlobalContext(); + Types.word8 = llvm::Type::getInt8Ty(context); + Types.word8ptr = llvm::Type::getInt8PtrTy(context); + Types.word256 = llvm::Type::getIntNTy(context, 256); + Types.word256ptr = Types.word256->getPointerTo(); + Types.word256arr = llvm::ArrayType::get(Types.word256, 100); + Types.size = llvm::Type::getInt64Ty(context); +} + + +void Compiler::compile(const dev::bytes& bytecode) +{ + using namespace llvm; + + auto& context = getGlobalContext(); + + Module* module = new Module("main", context); + IRBuilder<> builder(context); + + // Create globals for memory, memory size, stack and stack top + auto memory = new GlobalVariable(*module, Types.word8ptr, false, + GlobalValue::LinkageTypes::PrivateLinkage, + Constant::getNullValue(Types.word8ptr), "memory"); + auto memSize = new GlobalVariable(*module, Types.size, false, + GlobalValue::LinkageTypes::PrivateLinkage, + ConstantInt::get(Types.size, 0), "memsize"); + auto stack = new GlobalVariable(*module, Types.word256arr, false, + GlobalValue::LinkageTypes::PrivateLinkage, + ConstantAggregateZero::get(Types.word256arr), "stack"); + auto stackTop = new GlobalVariable(*module, Types.size, false, + GlobalValue::LinkageTypes::PrivateLinkage, + ConstantInt::get(Types.size, 0), "stackTop"); + + // Create value for void* malloc(size_t) + std::vector mallocArgTypes = { Types.size }; + Value* mallocVal = Function::Create(FunctionType::get(Types.word8ptr, mallocArgTypes, false), + GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module); + + // Create main function + FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false); + Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module); + + BasicBlock* entryBlock = BasicBlock::Create(context, "entry", mainFunc); + builder.SetInsertPoint(entryBlock); + + // Initialize memory with call to malloc, update memsize + std::vector mallocMemArgs = { ConstantInt::get(Types.size, 100) }; + auto mallocMemCall = builder.CreateCall(mallocVal, mallocMemArgs, "malloc_mem"); + builder.CreateStore(mallocMemCall, memory); + builder.CreateStore(ConstantInt::get(Types.size, 100), memSize); + + /* + std::vector mallocStackArgs = { ConstantInt::get(sizeTy, 200) }; + auto mallocStackCall = builder.CreateCall(mallocVal, mallocStackArgs, "malloc_stack"); + auto mallocCast = builder.CreatePointerBitCastOrAddrSpaceCast(mallocStackCall, int256ptr); + builder.CreateStore(mallocCast, stackVal); + */ + + builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 0)); + + module->dump(); +} + +} \ No newline at end of file diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h new file mode 100644 index 000000000..1e6cca57f --- /dev/null +++ b/evmcc/Compiler.h @@ -0,0 +1,34 @@ + +#pragma once + +#include + +#include + +namespace evmcc +{ + +class Compiler +{ + +private: + + struct + { + llvm::Type* word8; + llvm::Type* word8ptr; + llvm::Type* word256; + llvm::Type* word256ptr; + llvm::Type* word256arr; + llvm::Type* size; + } Types; + +public: + + Compiler(); + + void compile(const dev::bytes& bytecode); + +}; + +} \ No newline at end of file diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 94fcb956b..fc0b03a99 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -1,101 +1,19 @@ -#include -#include - -#include -#include -#include - -#include #include #include #include #include -using namespace dev; - -class EVMCCompiler -{ - -private: - - struct - { - llvm::Type* word8; - llvm::Type* word8ptr; - llvm::Type* word256; - llvm::Type* word256ptr; - llvm::Type* word256arr; - llvm::Type* size; - } Types; +#include -public: +#include +#include +#include - EVMCCompiler() - { - auto& context = llvm::getGlobalContext(); - Types.word8 = llvm::Type::getInt8Ty(context); - Types.word8ptr = llvm::Type::getInt8PtrTy(context); - Types.word256 = llvm::Type::getIntNTy(context, 256); - Types.word256ptr = Types.word256->getPointerTo(); - Types.word256arr = llvm::ArrayType::get(Types.word256, 100); - Types.size = llvm::Type::getInt64Ty(context); - } +#include "Compiler.h" - void compile(const bytes& bytecode) - { - using namespace llvm; - - auto& context = getGlobalContext(); - - Module* module = new Module("main", context); - IRBuilder<> builder(context); - - // Create globals for memory, memory size, stack and stack top - auto memory = new GlobalVariable(*module, Types.word8ptr, false, - GlobalValue::LinkageTypes::PrivateLinkage, - Constant::getNullValue(Types.word8ptr), "memory"); - auto memSize = new GlobalVariable(*module, Types.size, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantInt::get(Types.size, 0), "memsize"); - auto stack = new GlobalVariable(*module, Types.word256arr, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantAggregateZero::get(Types.word256arr), "stack"); - auto stackTop = new GlobalVariable(*module, Types.size, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantInt::get(Types.size, 0), "stackTop"); - - // Create value for void* malloc(size_t) - std::vector mallocArgTypes = { Types.size }; - Value* mallocVal = Function::Create(FunctionType::get(Types.word8ptr, mallocArgTypes, false), - GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module); - - // Create main function - FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false); - Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module); - - BasicBlock* entryBlock = BasicBlock::Create(context, "entry", mainFunc); - builder.SetInsertPoint(entryBlock); - - // Initialize memory with call to malloc, update memsize - std::vector mallocMemArgs = { ConstantInt::get(Types.size, 100) }; - auto mallocMemCall = builder.CreateCall(mallocVal, mallocMemArgs, "malloc_mem"); - builder.CreateStore(mallocMemCall, memory); - builder.CreateStore(ConstantInt::get(Types.size, 100), memSize); - - /* - std::vector mallocStackArgs = { ConstantInt::get(sizeTy, 200) }; - auto mallocStackCall = builder.CreateCall(mallocVal, mallocStackArgs, "malloc_stack"); - auto mallocCast = builder.CreatePointerBitCastOrAddrSpaceCast(mallocStackCall, int256ptr); - builder.CreateStore(mallocCast, stackVal); - */ - - builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 0)); - - module->dump(); - } +using namespace dev; -}; void show_usage() { @@ -173,7 +91,7 @@ int main(int argc, char** argv) if (opt_compile) { - EVMCCompiler().compile(bytecode); + evmcc::Compiler().compile(bytecode); } return 0; diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 5b09e5f0d..d82699495 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -19,8 +19,12 @@ + + + + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} Win32Proj diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 6be5386a1..7c10c71cc 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -2,5 +2,9 @@ + + + + \ No newline at end of file From ec7609f0ad9f00e81612cba10877a3d9672c544f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 26 Sep 2014 11:37:18 +0200 Subject: [PATCH 006/396] ExecutionEngine stub and -i program option for interpreting EVM Code --- evmcc/ExecutionEngine.cpp | 18 ++++++++++++++++++ evmcc/ExecutionEngine.h | 17 +++++++++++++++++ evmcc/evmcc.cpp | 29 ++++++++++++++++------------- windows/evmcc.vcxproj | 2 ++ windows/evmcc.vcxproj.filters | 2 ++ 5 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 evmcc/ExecutionEngine.cpp create mode 100644 evmcc/ExecutionEngine.h diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp new file mode 100644 index 000000000..2fe56f373 --- /dev/null +++ b/evmcc/ExecutionEngine.cpp @@ -0,0 +1,18 @@ + +#include "ExecutionEngine.h" + +namespace evmcc +{ + +ExecutionEngine::ExecutionEngine() +{ + +} + + +int ExecutionEngine::run(const dev::bytes& bytecode) +{ + return 0; +} + +} \ No newline at end of file diff --git a/evmcc/ExecutionEngine.h b/evmcc/ExecutionEngine.h new file mode 100644 index 000000000..e0c2693fa --- /dev/null +++ b/evmcc/ExecutionEngine.h @@ -0,0 +1,17 @@ + +#pragma once + +#include + +namespace evmcc +{ + +class ExecutionEngine +{ +public: + ExecutionEngine(); + + int run(const dev::bytes& bytecode); +}; + +} \ No newline at end of file diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index fc0b03a99..a7ed341a0 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -11,6 +11,7 @@ #include #include "Compiler.h" +#include "ExecutionEngine.h" using namespace dev; @@ -27,28 +28,23 @@ int main(int argc, char** argv) std::string input_file; bool opt_dissassemble = false; bool opt_show_bytes = false; - bool opt_compile = false; + bool opt_compile = false; + bool opt_interpret = false; bool opt_unknown = false; for (int i = 1; i < argc; i++) { std::string option = argv[i]; if (option == "-b") - { opt_show_bytes = true; - } else if (option == "-c") - { opt_compile = true; - } else if (option == "-d") - { - opt_dissassemble = true; - } - else if (option[0] != '-' && input_file.empty()) - { - input_file = option; - } + opt_dissassemble = true; + else if (option == "-i") + opt_interpret = true; + else if (option[0] != '-' && input_file.empty()) + input_file = option; else { opt_unknown = true; @@ -58,7 +54,7 @@ int main(int argc, char** argv) if (opt_unknown || input_file.empty() || - (!opt_show_bytes && !opt_compile && !opt_dissassemble)) + (!opt_show_bytes && !opt_compile && !opt_dissassemble && !opt_interpret)) { show_usage(); exit(1); @@ -94,5 +90,12 @@ int main(int argc, char** argv) evmcc::Compiler().compile(bytecode); } + if (opt_interpret) + { + auto engine = evmcc::ExecutionEngine(); + auto result = engine.run(bytecode); + return result; + } + return 0; } diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index d82699495..22df8b85d 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -21,9 +21,11 @@ + + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 7c10c71cc..34635bd78 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -3,8 +3,10 @@ + + \ No newline at end of file From 75d7b8592efcea738f06fd28c2bebfa70ba867c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 26 Sep 2014 12:13:13 +0200 Subject: [PATCH 007/396] Remove public LLVM dependency in Compiler --- evmcc/Compiler.cpp | 10 ++++++++++ evmcc/Compiler.h | 15 --------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 209e79c6f..6ef70d4fe 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -7,6 +7,16 @@ namespace evmcc { +struct +{ + llvm::Type* word8; + llvm::Type* word8ptr; + llvm::Type* word256; + llvm::Type* word256ptr; + llvm::Type* word256arr; + llvm::Type* size; +} Types; + Compiler::Compiler() { auto& context = llvm::getGlobalContext(); diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 1e6cca57f..6801a89d4 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -1,8 +1,6 @@ #pragma once -#include - #include namespace evmcc @@ -10,19 +8,6 @@ namespace evmcc class Compiler { - -private: - - struct - { - llvm::Type* word8; - llvm::Type* word8ptr; - llvm::Type* word256; - llvm::Type* word256ptr; - llvm::Type* word256arr; - llvm::Type* size; - } Types; - public: Compiler(); From 9ddc25a664e24165035f2c304a6491607f82fe11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 26 Sep 2014 15:18:56 +0200 Subject: [PATCH 008/396] Implementation of ExecutionEngine with LLVM MCJIT --- evmcc/Compiler.cpp | 13 ++++---- evmcc/Compiler.h | 4 ++- evmcc/ExecutionEngine.cpp | 67 +++++++++++++++++++++++++++++++++++++-- evmcc/ExecutionEngine.h | 4 ++- evmcc/evmcc.cpp | 6 ++-- windows/evmcc.vcxproj | 16 +++++++--- 6 files changed, 93 insertions(+), 17 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 6ef70d4fe..fa3349ea2 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -2,7 +2,6 @@ #include "Compiler.h" #include -#include namespace evmcc { @@ -29,13 +28,13 @@ Compiler::Compiler() } -void Compiler::compile(const dev::bytes& bytecode) +std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { using namespace llvm; auto& context = getGlobalContext(); - Module* module = new Module("main", context); + auto module = std::make_unique("main", context); IRBuilder<> builder(context); // Create globals for memory, memory size, stack and stack top @@ -55,11 +54,11 @@ void Compiler::compile(const dev::bytes& bytecode) // Create value for void* malloc(size_t) std::vector mallocArgTypes = { Types.size }; Value* mallocVal = Function::Create(FunctionType::get(Types.word8ptr, mallocArgTypes, false), - GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module); + GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module.get()); // Create main function FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false); - Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module); + Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module.get()); BasicBlock* entryBlock = BasicBlock::Create(context, "entry", mainFunc); builder.SetInsertPoint(entryBlock); @@ -77,9 +76,9 @@ void Compiler::compile(const dev::bytes& bytecode) builder.CreateStore(mallocCast, stackVal); */ - builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 0)); + builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 13)); - module->dump(); + return module; } } \ No newline at end of file diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 6801a89d4..ae7033ac0 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -1,6 +1,8 @@ #pragma once +#include + #include namespace evmcc @@ -12,7 +14,7 @@ public: Compiler(); - void compile(const dev::bytes& bytecode); + std::unique_ptr compile(const dev::bytes& bytecode); }; diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 2fe56f373..e59d6024a 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -1,6 +1,18 @@ #include "ExecutionEngine.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + namespace evmcc { @@ -10,9 +22,60 @@ ExecutionEngine::ExecutionEngine() } -int ExecutionEngine::run(const dev::bytes& bytecode) +int ExecutionEngine::run(std::unique_ptr _module) { - return 0; + auto module = _module.get(); // Keep ownership of the module in _module + + llvm::sys::PrintStackTraceOnErrorSignal(); + static const auto program = "evmcc"; + llvm::PrettyStackTraceProgram X(1, &program); + + auto&& context = llvm::getGlobalContext(); + + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::InitializeNativeTargetAsmParser(); + + std::string errorMsg; + llvm::EngineBuilder builder(module); + //builder.setMArch(MArch); + //builder.setMCPU(MCPU); + //builder.setMAttrs(MAttrs); + //builder.setRelocationModel(RelocModel); + //builder.setCodeModel(CMModel); + builder.setErrorStr(&errorMsg); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + builder.setMCJITMemoryManager(new llvm::SectionMemoryManager()); + builder.setOptLevel(llvm::CodeGenOpt::None); + + 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 + module->setTargetTriple(triple.str()); + + auto exec = std::unique_ptr(builder.create()); + if (!exec) + { + if (!errorMsg.empty()) + std::cerr << "error creating EE: " << errorMsg << std::endl; + else + std::cerr << "unknown error creating llvm::ExecutionEngine" << std::endl; + exit(1); + } + _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + exec->finalizeObject(); + + auto entryFunc = module->getFunction("main"); + if (!entryFunc) + { + std::cerr << "main function not found\n"; + exit(1); + } + + auto result = exec->runFunction(entryFunc, {}); + auto intResult = result.IntVal.getZExtValue(); + return intResult; } } \ No newline at end of file diff --git a/evmcc/ExecutionEngine.h b/evmcc/ExecutionEngine.h index e0c2693fa..1bdf8c564 100644 --- a/evmcc/ExecutionEngine.h +++ b/evmcc/ExecutionEngine.h @@ -1,6 +1,8 @@ #pragma once +#include + #include namespace evmcc @@ -11,7 +13,7 @@ class ExecutionEngine public: ExecutionEngine(); - int run(const dev::bytes& bytecode); + int run(std::unique_ptr module); }; } \ No newline at end of file diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index a7ed341a0..bdc3681db 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -87,13 +87,15 @@ int main(int argc, char** argv) if (opt_compile) { - evmcc::Compiler().compile(bytecode); + evmcc::Compiler().compile(bytecode)->dump(); } if (opt_interpret) { auto engine = evmcc::ExecutionEngine(); - auto result = engine.run(bytecode); + auto module = evmcc::Compiler().compile(bytecode); + module->dump(); + auto result = engine.run(std::move(module)); return result; } diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 22df8b85d..c75167852 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -85,17 +85,21 @@ true ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ + false true + false false ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ + false false + false @@ -106,12 +110,13 @@ WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ../ + false Console true ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + LibEthereum.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -124,12 +129,13 @@ true ../../llvm-3.5.0/include;../../builds/llvm3.5/include;%(AdditionalIncludeDirectories) 4068;4244;4267;4800 + false Console true ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + LibEthereum.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -142,6 +148,7 @@ true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true + false Console @@ -149,7 +156,7 @@ true true ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + LibEthereum.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -164,6 +171,7 @@ true ../../llvm-3.5.0/include;../../builds/llvm3.5/include;%(AdditionalIncludeDirectories) 4068;4244;4267;4800 + false Console @@ -171,7 +179,7 @@ true true ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + LibEthereum.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) From b47adc68c79ec9c52833a1f095e77565309b5dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 26 Sep 2014 17:23:22 +0200 Subject: [PATCH 009/396] Staring with Stack helper --- evmcc/Compiler.cpp | 23 +++++++++++++++--- evmcc/Stack.cpp | 46 +++++++++++++++++++++++++++++++++++ windows/evmcc.vcxproj | 1 + windows/evmcc.vcxproj.filters | 1 + 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 evmcc/Stack.cpp diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index fa3349ea2..7478dd683 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -14,6 +14,7 @@ struct llvm::Type* word256ptr; llvm::Type* word256arr; llvm::Type* size; + llvm::Type* Void; } Types; Compiler::Compiler() @@ -25,6 +26,7 @@ Compiler::Compiler() Types.word256ptr = Types.word256->getPointerTo(); Types.word256arr = llvm::ArrayType::get(Types.word256, 100); Types.size = llvm::Type::getInt64Ty(context); + Types.Void = llvm::Type::getVoidTy(context); } @@ -44,7 +46,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto memSize = new GlobalVariable(*module, Types.size, false, GlobalValue::LinkageTypes::PrivateLinkage, ConstantInt::get(Types.size, 0), "memsize"); - auto stack = new GlobalVariable(*module, Types.word256arr, false, + auto stack2 = new GlobalVariable(*module, Types.word256arr, false, GlobalValue::LinkageTypes::PrivateLinkage, ConstantAggregateZero::get(Types.word256arr), "stack"); auto stackTop = new GlobalVariable(*module, Types.size, false, @@ -52,10 +54,16 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) ConstantInt::get(Types.size, 0), "stackTop"); // Create value for void* malloc(size_t) - std::vector mallocArgTypes = { Types.size }; - Value* mallocVal = Function::Create(FunctionType::get(Types.word8ptr, mallocArgTypes, false), + auto mallocVal = Function::Create(FunctionType::get(Types.word8ptr, { Types.size }, false), GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module.get()); + // Create stack_create declaration + auto stackCreate = Function::Create(FunctionType::get(Types.word8ptr, false), + GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_create", module.get()); + + auto stackPush = Function::Create(FunctionType::get(Types.Void, std::vector{ Types.word8ptr, Types.word256 }, false), + GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_push", module.get()); + // Create main function FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false); Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module.get()); @@ -69,6 +77,15 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) builder.CreateStore(mallocMemCall, memory); builder.CreateStore(ConstantInt::get(Types.size, 100), memSize); + auto stack = builder.CreateCall(stackCreate, "stack"); + + uint64_t words[] = { 1, 2, 3, 4 }; + auto val = llvm::APInt(256, 4, words); + auto c = ConstantInt::get(Types.word256, val); + + Value* args[] = { stack, c }; + builder.CreateCall(stackPush, args); + /* std::vector mallocStackArgs = { ConstantInt::get(sizeTy, 200) }; auto mallocStackCall = builder.CreateCall(mallocVal, mallocStackArgs, "malloc_stack"); diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp new file mode 100644 index 000000000..e3faffd7e --- /dev/null +++ b/evmcc/Stack.cpp @@ -0,0 +1,46 @@ + +#include +#include +#include +#include + +#ifdef _MSC_VER + #define EXPORT __declspec(dllexport) +#else + #define EXPORT +#endif + +struct i256 +{ + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; +}; + +using Stack = std::vector; + +extern "C" +{ + +EXPORT void* evmccrt_stack_create() +{ + std::cerr << "STACK create: "; + auto stack = new Stack; + std::cerr << stack << "\n"; + return stack; +} + +EXPORT void evmccrt_stack_push(void* _stack, uint64_t _partA, uint64_t _partB, uint64_t _partC, uint64_t _partD) +{ + std::cerr << "STACK push: " << _partA << " (" << std::hex << std::setfill('0') + << std::setw(16) << _partD << " " + << std::setw(16) << _partC << " " + << std::setw(16) << _partB << " " + << std::setw(16) << _partA; + auto stack = static_cast(_stack); + stack->push_back({_partA, _partB, _partC, _partD}); + std::cerr << ")\n"; +} + +} // extern "C" diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index c75167852..82a7b4c56 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -22,6 +22,7 @@ + diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 34635bd78..f4be3b7d4 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -4,6 +4,7 @@ + From cb143c44c32f878b36e07c49f07e8521aa26269a Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Sat, 27 Sep 2014 13:20:19 +0100 Subject: [PATCH 010/396] Fixed size_t to bool warning and internal compiler error with MSVC. --- eth/main.cpp | 8 +++++++- libwebthree/WebThree.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index a9ea43f14..03be8b969 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -300,7 +300,13 @@ int main(int argc, char** argv) cout << credits(); NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal); - dev::WebThreeDirect web3("Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), dbPath, false, mode == NodeMode::Full ? set{"eth", "shh"} : set{}, netPrefs); + dev::WebThreeDirect web3( + "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), + dbPath, + false, + mode == NodeMode::Full ? set{"eth", "shh"} : set(), + netPrefs + ); web3.setIdealPeerCount(peers); eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr; diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index 06717ee26..cae6fd6f8 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -93,7 +93,7 @@ public: void connect(std::string const& _seedHost, unsigned short _port = 30303); /// Is the network subsystem up? - bool haveNetwork() { return peerCount(); } + bool haveNetwork() { return peerCount() != 0; } /// Save peers dev::bytes savePeers(); From a23fea0917459494322c3077f4ff8a46cb53a67b Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Sat, 27 Sep 2014 13:23:02 +0100 Subject: [PATCH 011/396] Suppress warnings from boost mpl during moc compile. --- alethzero/MainWin.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index ce1a9b670..7aee0c376 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -21,6 +21,9 @@ #pragma once +#ifdef Q_MOC_RUN +#define BOOST_MPL_IF_HPP_INCLUDED +#endif #include #include From 6857416c09d783519798cb034048232be544df01 Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Sat, 27 Sep 2014 13:23:19 +0100 Subject: [PATCH 012/396] Update MSVC projects. --- libdevcore/_libdevcore.cpp | 2 ++ windows/Alethzero.vcxproj | 3 ++- windows/Alethzero.vcxproj.filters | 2 ++ windows/LibEthereum.vcxproj | 30 ++++++++++++++++++++++++++++- windows/LibEthereum.vcxproj.filters | 27 ++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) diff --git a/libdevcore/_libdevcore.cpp b/libdevcore/_libdevcore.cpp index 4160a7602..1b34a5911 100644 --- a/libdevcore/_libdevcore.cpp +++ b/libdevcore/_libdevcore.cpp @@ -6,5 +6,7 @@ #include "FixedHash.cpp" #include "Guards.cpp" #include "Log.cpp" +#include "RangeMask.cpp" #include "RLP.cpp" +#include "Worker.cpp" #endif diff --git a/windows/Alethzero.vcxproj b/windows/Alethzero.vcxproj index d418e5d03..38dbd6265 100644 --- a/windows/Alethzero.vcxproj +++ b/windows/Alethzero.vcxproj @@ -176,6 +176,7 @@ + @@ -307,4 +308,4 @@ - + \ No newline at end of file diff --git a/windows/Alethzero.vcxproj.filters b/windows/Alethzero.vcxproj.filters index e8f008522..ef47bdba0 100644 --- a/windows/Alethzero.vcxproj.filters +++ b/windows/Alethzero.vcxproj.filters @@ -11,6 +11,7 @@ + @@ -31,5 +32,6 @@ Windows + \ No newline at end of file diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 134171843..db1362363 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -49,12 +49,24 @@ true true + + true + true + true + true + true true true true + + true + true + true + true + @@ -90,6 +102,7 @@ + @@ -159,6 +172,7 @@ true + true true @@ -223,6 +237,12 @@ true true + + true + true + true + true + true true @@ -235,6 +255,12 @@ true true + + true + true + true + true + @@ -289,6 +315,7 @@ + @@ -376,6 +403,7 @@ true true + true true @@ -527,4 +555,4 @@ - + \ No newline at end of file diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index b6e2dc070..848b8308d 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -178,6 +178,18 @@ libethereum + + libdevcore + + + libdevcore + + + libethereum + + + libwebthree + @@ -390,6 +402,18 @@ libethereum + + libdevcore + + + libdevcore + + + libethereum + + + libwebthree + @@ -422,5 +446,8 @@ {36748e80-c977-4fee-84e6-699c039dff87} + + {d838fece-fc20-42f6-bff5-97c236159b80} + \ No newline at end of file From c3b165684c6b437905a6fe3e6cd80a2c6233afd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Sat, 27 Sep 2014 14:58:50 +0200 Subject: [PATCH 013/396] evmcc's CMakeLists updated: * added std=c++14 for gcc (required for std::make_unique) * added required llvm libnames --- evmcc/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index 550492583..82647ca02 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -22,6 +22,7 @@ if ("${TARGET_PLATFORM}" STREQUAL "w64") 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}) @@ -37,7 +38,7 @@ message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) -llvm_map_components_to_libnames(llvm_libs support core irreader) +llvm_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen) target_link_libraries(evmcc ${llvm_libs}) # end of LLVM specific commands From 26a952cd1d367e33cda1abe193362367f01a2f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 29 Sep 2014 14:39:17 +0200 Subject: [PATCH 014/396] Stack interface and implementation --- evmcc/Compiler.cpp | 23 +++---- evmcc/Stack.cpp | 118 ++++++++++++++++++++++++++++++---- evmcc/Stack.h | 26 ++++++++ windows/evmcc.vcxproj | 1 + windows/evmcc.vcxproj.filters | 1 + 5 files changed, 145 insertions(+), 24 deletions(-) create mode 100644 evmcc/Stack.h diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 7478dd683..4c3a8a5f2 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -3,6 +3,8 @@ #include +#include "Stack.h" + namespace evmcc { @@ -49,7 +51,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto stack2 = new GlobalVariable(*module, Types.word256arr, false, GlobalValue::LinkageTypes::PrivateLinkage, ConstantAggregateZero::get(Types.word256arr), "stack"); - auto stackTop = new GlobalVariable(*module, Types.size, false, + auto stackTop2 = new GlobalVariable(*module, Types.size, false, GlobalValue::LinkageTypes::PrivateLinkage, ConstantInt::get(Types.size, 0), "stackTop"); @@ -57,13 +59,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto mallocVal = Function::Create(FunctionType::get(Types.word8ptr, { Types.size }, false), GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module.get()); - // Create stack_create declaration - auto stackCreate = Function::Create(FunctionType::get(Types.word8ptr, false), - GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_create", module.get()); - - auto stackPush = Function::Create(FunctionType::get(Types.Void, std::vector{ Types.word8ptr, Types.word256 }, false), - GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_push", module.get()); - // Create main function FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false); Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module.get()); @@ -77,14 +72,20 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) builder.CreateStore(mallocMemCall, memory); builder.CreateStore(ConstantInt::get(Types.size, 100), memSize); - auto stack = builder.CreateCall(stackCreate, "stack"); + auto stack = Stack(builder, module.get()); uint64_t words[] = { 1, 2, 3, 4 }; auto val = llvm::APInt(256, 4, words); auto c = ConstantInt::get(Types.word256, val); - Value* args[] = { stack, c }; - builder.CreateCall(stackPush, args); + stack.push(c); + stack.push(ConstantInt::get(Types.word256, 0x1122334455667788)); + + auto top = stack.top(); + stack.push(top); // dup + + stack.pop(); + /* std::vector mallocStackArgs = { ConstantInt::get(sizeTy, 200) }; diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index e3faffd7e..d23456de6 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -1,8 +1,13 @@ +#include "Stack.h" + #include #include #include #include +#include + +#include #ifdef _MSC_VER #define EXPORT __declspec(dllexport) @@ -10,6 +15,9 @@ #define EXPORT #endif +namespace evmcc +{ + struct i256 { uint64_t a; @@ -17,30 +25,114 @@ struct i256 uint64_t c; uint64_t d; }; +static_assert(sizeof(i256) == 32, "Wrong i265 size"); + +using StackImpl = std::vector; + + +Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) + : m_builder(_builder) +{ + // TODO: Clean up LLVM types + auto stackPtrTy = m_builder.getInt8PtrTy(); + auto i256Ty = m_builder.getIntNTy(256); + auto i256PtrTy = i256Ty->getPointerTo(); + auto voidTy = m_builder.getVoidTy(); + + auto stackCreate = llvm::Function::Create(llvm::FunctionType::get(stackPtrTy, false), + llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_create", _module); + + llvm::Type* argsTypes[] = {stackPtrTy, i256PtrTy}; + auto funcType = llvm::FunctionType::get(voidTy, argsTypes, false); + m_stackPush = llvm::Function::Create(funcType, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_push", _module); -using Stack = std::vector; + m_stackTop = llvm::Function::Create(funcType, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_top", _module); + + m_stackPop = llvm::Function::Create(funcType, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_pop", _module); + + m_args[0] = m_builder.CreateCall(stackCreate, "stack.ptr"); + m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "stack.val"); +} + + +void Stack::push(llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_args[1]); // copy value to memory + m_builder.CreateCall(m_stackPush, m_args); +} + + +llvm::Value* Stack::top() +{ + m_builder.CreateCall(m_stackTop, m_args); + return m_builder.CreateLoad(m_args[1]); +} + + +llvm::Value* Stack::pop() +{ + m_builder.CreateCall(m_stackPop, m_args); + return m_builder.CreateLoad(m_args[1]); +} + + +void debugStack(const char* op, const i256& word) +{ + std::cerr << "STACK " << std::setw(4) << std::setfill(' ') << op << ": " + << std::dec << word.a + << " HEX: " << std::hex << std::setfill('0'); + if (word.b || word.c || word.d) + { + std::cerr << std::setw(16) << word.d << " " + << std::setw(16) << word.c << " " + << std::setw(16) << word.b << " "; + } + std::cerr << std::setw(16) << word.a << "\n"; +} + +} extern "C" { + using namespace evmcc; EXPORT void* evmccrt_stack_create() { - std::cerr << "STACK create: "; - auto stack = new Stack; - std::cerr << stack << "\n"; + auto stack = new StackImpl; + std::cerr << "STACK create\n"; return stack; } -EXPORT void evmccrt_stack_push(void* _stack, uint64_t _partA, uint64_t _partB, uint64_t _partC, uint64_t _partD) +EXPORT void evmccrt_stack_push(void* _stack, void* _pWord) +{ + auto stack = static_cast(_stack); + auto word = static_cast(_pWord); + debugStack("push", *word); + stack->push_back(*word); +} + +EXPORT void evmccrt_stack_top(void* _stack, void* _pWord) +{ + auto stack = static_cast(_stack); + assert(!stack->empty()); + auto word = &stack->back(); + debugStack("top", *word); + auto outWord = static_cast(_pWord); + *outWord = *word; +} + +EXPORT void evmccrt_stack_pop(void* _stack, void* _pWord) { - std::cerr << "STACK push: " << _partA << " (" << std::hex << std::setfill('0') - << std::setw(16) << _partD << " " - << std::setw(16) << _partC << " " - << std::setw(16) << _partB << " " - << std::setw(16) << _partA; - auto stack = static_cast(_stack); - stack->push_back({_partA, _partB, _partC, _partD}); - std::cerr << ")\n"; + auto stack = static_cast(_stack); + assert(!stack->empty()); + auto word = &stack->back(); + debugStack("pop", *word); + auto outWord = static_cast(_pWord); + stack->pop_back(); + *outWord = *word; } } // extern "C" diff --git a/evmcc/Stack.h b/evmcc/Stack.h new file mode 100644 index 000000000..e8b6a8e2d --- /dev/null +++ b/evmcc/Stack.h @@ -0,0 +1,26 @@ + +#pragma once + +#include + +namespace evmcc +{ + +class Stack +{ +public: + Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module); + + void push(llvm::Value* _value); + llvm::Value* top(); + llvm::Value* pop(); + +private: + llvm::IRBuilder<>& m_builder; + llvm::Value* m_args[2]; + llvm::Function* m_stackPush; + llvm::Function* m_stackTop; + llvm::Function* m_stackPop; +}; + +} \ No newline at end of file diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 82a7b4c56..3a1869cd5 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -27,6 +27,7 @@ + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index f4be3b7d4..7db055ebf 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -9,5 +9,6 @@ + \ No newline at end of file From 9051a2198ac8486ca3f22ca062332e6d32a5dc3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 29 Sep 2014 15:33:07 +0200 Subject: [PATCH 015/396] Output compilation (option -c) result to standard output by default --- evmcc/evmcc.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index bdc3681db..222bcffb3 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -6,6 +6,8 @@ #include +#include + #include #include #include @@ -87,7 +89,9 @@ int main(int argc, char** argv) if (opt_compile) { - evmcc::Compiler().compile(bytecode)->dump(); + auto module = evmcc::Compiler().compile(bytecode); + llvm::raw_os_ostream out(std::cout); + module->print(out, nullptr); } if (opt_interpret) From a9bdd81d49afa84168157a0ca60f6067d68a7dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 29 Sep 2014 17:17:39 +0200 Subject: [PATCH 016/396] PUSH instruction implementation --- evmcc/Compiler.cpp | 123 +++++++++++++++++++++-------------- evmcc/bytecode/push_test.evm | 1 + evmcc/lll/push_test.lll | 35 ++++++++++ 3 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 evmcc/bytecode/push_test.evm create mode 100644 evmcc/lll/push_test.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 4c3a8a5f2..854492ee3 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -3,6 +3,8 @@ #include +#include + #include "Stack.h" namespace evmcc @@ -37,64 +39,87 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) using namespace llvm; auto& context = getGlobalContext(); - auto module = std::make_unique("main", context); IRBuilder<> builder(context); - // Create globals for memory, memory size, stack and stack top - auto memory = new GlobalVariable(*module, Types.word8ptr, false, - GlobalValue::LinkageTypes::PrivateLinkage, - Constant::getNullValue(Types.word8ptr), "memory"); - auto memSize = new GlobalVariable(*module, Types.size, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantInt::get(Types.size, 0), "memsize"); - auto stack2 = new GlobalVariable(*module, Types.word256arr, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantAggregateZero::get(Types.word256arr), "stack"); - auto stackTop2 = new GlobalVariable(*module, Types.size, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantInt::get(Types.size, 0), "stackTop"); - - // Create value for void* malloc(size_t) - auto mallocVal = Function::Create(FunctionType::get(Types.word8ptr, { Types.size }, false), - GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module.get()); - // Create main function - FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false); - Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module.get()); + auto mainFuncType = FunctionType::get(llvm::Type::getInt32Ty(context), false); + auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get()); - BasicBlock* entryBlock = BasicBlock::Create(context, "entry", mainFunc); + auto entryBlock = BasicBlock::Create(context, "entry", mainFunc); builder.SetInsertPoint(entryBlock); - // Initialize memory with call to malloc, update memsize - std::vector mallocMemArgs = { ConstantInt::get(Types.size, 100) }; - auto mallocMemCall = builder.CreateCall(mallocVal, mallocMemArgs, "malloc_mem"); - builder.CreateStore(mallocMemCall, memory); - builder.CreateStore(ConstantInt::get(Types.size, 100), memSize); - + // Init stack auto stack = Stack(builder, module.get()); - uint64_t words[] = { 1, 2, 3, 4 }; - auto val = llvm::APInt(256, 4, words); - auto c = ConstantInt::get(Types.word256, val); - - stack.push(c); - stack.push(ConstantInt::get(Types.word256, 0x1122334455667788)); - - auto top = stack.top(); - stack.push(top); // dup - - stack.pop(); - - - /* - std::vector mallocStackArgs = { ConstantInt::get(sizeTy, 200) }; - auto mallocStackCall = builder.CreateCall(mallocVal, mallocStackArgs, "malloc_stack"); - auto mallocCast = builder.CreatePointerBitCastOrAddrSpaceCast(mallocStackCall, int256ptr); - builder.CreateStore(mallocCast, stackVal); - */ - - builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 13)); + for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) + { + using dev::eth::Instruction; + + auto inst = static_cast(*pc); + switch (inst) + { + case Instruction::PUSH1: + case Instruction::PUSH2: + case Instruction::PUSH3: + case Instruction::PUSH4: + case Instruction::PUSH5: + case Instruction::PUSH6: + case Instruction::PUSH7: + case Instruction::PUSH8: + case Instruction::PUSH9: + case Instruction::PUSH10: + case Instruction::PUSH11: + case Instruction::PUSH12: + case Instruction::PUSH13: + case Instruction::PUSH14: + case Instruction::PUSH15: + case Instruction::PUSH16: + case Instruction::PUSH17: + case Instruction::PUSH18: + case Instruction::PUSH19: + case Instruction::PUSH20: + case Instruction::PUSH21: + case Instruction::PUSH22: + case Instruction::PUSH23: + case Instruction::PUSH24: + case Instruction::PUSH25: + case Instruction::PUSH26: + case Instruction::PUSH27: + case Instruction::PUSH28: + case Instruction::PUSH29: + case Instruction::PUSH30: + case Instruction::PUSH31: + case Instruction::PUSH32: + { + auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; + auto value = llvm::APInt(256, 0); + for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator + { + ++pc; + value <<= 8; + value |= *pc; + } + auto c = builder.getInt(value); + stack.push(c); + break; + } + } + } + + //uint64_t words[] = { 1, 2, 3, 4 }; + //auto val = llvm::APInt(256, 4, words); + //auto c = ConstantInt::get(Types.word256, val); + + //stack.push(c); + //stack.push(ConstantInt::get(Types.word256, 0x1122334455667788)); + + //auto top = stack.top(); + //stack.push(top); // dup + + //stack.pop(); + + builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 0)); return module; } diff --git a/evmcc/bytecode/push_test.evm b/evmcc/bytecode/push_test.evm new file mode 100644 index 000000000..d624cee1d --- /dev/null +++ b/evmcc/bytecode/push_test.evm @@ -0,0 +1 @@ +60656107d26204a0c763026921f4640bc5588eb165372d0f1dca6e661ba1d901961c71670c55f7bc23038e3868056bc75e2d630fffff69021e19e0c9bab24000016a085d1c6e8050f0ea1c71bd6b0688be36543f3c36e638e37a6c03d41f73d55d0d482ae55555376dc76810d0fe03c91964d31c71c6f46e615dd0360c07d931663b14e38e38b16f2da3f99955a3adcf27ebb1caaaaaaa6e7014ccba6a8bb1ed35bd86bf065c71c71c2b7109491c5d4781b79c9009de6bfb8e38e38de8720414a0f6fdec81304d4c563e740bffffffffa573118427b3b4a05bc8a8a4de8459868000000000017406eb15e7331e727940d4ac54b7cdca1c71c71c71bd750567a91c9fefc96ebaa626a22f98c5e638e38e38e37a76032abd16c5b68006e15d5aa307e383f4e55555555555377701a6427bdc4f0d58eab5f48a3ec67f64e21c71c71c71c6f478080dd0a0c9b9ff2c2a0c740b06853a0a980ee38e38e38e38b17903c679cb5e8f2f9cb3b5d6652b0e7334f746faaaaaaaaaaaaa6e7a01b873815917ebb2bf3b890a1af495d6235bae3c71c71c71c71c2b7b07ae4cca96e1a55dfa49c85ad3c3e60e426b92fb8e38e38e38e38de87c036018bf074e292bcc7d6c8bea0f9699443046178bffffffffffffffa57d0e7d34c64a9c85d4460dbbca87196b61618a4bd2168000000000000000017e05b901f48a5b994d6572502bc4ea43140486666416aa1c71c71c71c71c71bd7f047889870c178fc477414ea231d70467a388fffe31b4e638e38e38e38e38e37a diff --git a/evmcc/lll/push_test.lll b/evmcc/lll/push_test.lll new file mode 100644 index 000000000..832daaec1 --- /dev/null +++ b/evmcc/lll/push_test.lll @@ -0,0 +1,35 @@ + +(asm +101 ;; PUSH1 +2002 ;; PUSH2 +303303 ;; PUSH3 +40444404 ;; PUSH4 +50555555505 ;; PUSH5 +60666666666606 +7777777777777777 +888888888888888888 +99999999999999999999 +10000000000000000000001 +10111111111111111111111101 +2022222222222222222222222202 +303333333333333333333333333303 +4044444444444444444444444444444404 +505555555555555555555555555555555505 +60666666666666666666666666666666666606 +7077777777777777777777777777777777777707 +808888888888888888888888888888888888888808 +90999999999999999999999999999999999999999909 +100000000000000000000000000000000000000000000001 +10111111111111111111111111111111111111111111111101 +2022222222222222222222222222222222222222222222222202 +303333333333333333333333333333333333333333333333333303 +40444444444444444444444444444444444444444444444444444404 +50555555555555555555555555555555555555555555555555555555505 +6066666666666666666666666666666666666666666666666666666666606 +707777777777777777777777777777777777777777777777777777777777707 +808888888888888888888888888888888888888888888888888888888888888808 +90999999999999999999999999999999999999999999999999999999999999999909 +100000000000000000000000000000000000000000000000000000000000000000000001 +10111111111111111111111111111111111111111111111111111111111111111111111101 +2022222222222222222222222222222222222222222222222222222222222222222222222202 ;; PUSH32 +) \ No newline at end of file From 646f954ac6985d22d37eceb37a4b139cfd868309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Sep 2014 09:32:53 +0200 Subject: [PATCH 017/396] POP and DUP* instructions --- evmcc/Compiler.cpp | 42 +++++++++++++++++++++++++---------- evmcc/Stack.cpp | 37 ++++++++++++++++++------------ evmcc/Stack.h | 5 +++-- evmcc/bytecode/stack_test.evm | 1 + evmcc/lll/stack_test.lll | 22 ++++++++++++++++++ 5 files changed, 79 insertions(+), 28 deletions(-) create mode 100644 evmcc/bytecode/stack_test.evm create mode 100644 evmcc/lll/stack_test.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 854492ee3..454c61450 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -59,6 +59,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto inst = static_cast(*pc); switch (inst) { + case Instruction::POP: + { + stack.pop(); + break; + } + case Instruction::PUSH1: case Instruction::PUSH2: case Instruction::PUSH3: @@ -104,20 +110,32 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) stack.push(c); break; } - } - } - - //uint64_t words[] = { 1, 2, 3, 4 }; - //auto val = llvm::APInt(256, 4, words); - //auto c = ConstantInt::get(Types.word256, val); - //stack.push(c); - //stack.push(ConstantInt::get(Types.word256, 0x1122334455667788)); - - //auto top = stack.top(); - //stack.push(top); // dup + case Instruction::DUP1: + case Instruction::DUP2: + case Instruction::DUP3: + case Instruction::DUP4: + case Instruction::DUP5: + case Instruction::DUP6: + case Instruction::DUP7: + case Instruction::DUP8: + case Instruction::DUP9: + case Instruction::DUP10: + case Instruction::DUP11: + case Instruction::DUP12: + case Instruction::DUP13: + case Instruction::DUP14: + case Instruction::DUP15: + case Instruction::DUP16: + { + auto index = static_cast(inst) - static_cast(Instruction::DUP1); + auto value = stack.get(index); + stack.push(value); + break; + } - //stack.pop(); + } + } builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 0)); diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index d23456de6..4c5a19e8a 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -47,12 +47,14 @@ Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) m_stackPush = llvm::Function::Create(funcType, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_push", _module); - m_stackTop = llvm::Function::Create(funcType, - llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_top", _module); - m_stackPop = llvm::Function::Create(funcType, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_pop", _module); + llvm::Type* getArgsTypes[] = {stackPtrTy, m_builder.getInt32Ty(), i256PtrTy}; + auto getFuncType = llvm::FunctionType::get(voidTy, getArgsTypes); + m_stackGet = llvm::Function::Create(getFuncType, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_get", _module); + m_args[0] = m_builder.CreateCall(stackCreate, "stack.ptr"); m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "stack.val"); } @@ -65,20 +67,27 @@ void Stack::push(llvm::Value* _value) } -llvm::Value* Stack::top() +llvm::Value* Stack::pop() { - m_builder.CreateCall(m_stackTop, m_args); + m_builder.CreateCall(m_stackPop, m_args); return m_builder.CreateLoad(m_args[1]); } -llvm::Value* Stack::pop() +llvm::Value* Stack::get(uint32_t _index) { - m_builder.CreateCall(m_stackPop, m_args); + llvm::Value* args[] = {m_args[0], m_builder.getInt32(_index), m_args[1]}; + m_builder.CreateCall(m_stackGet, args); return m_builder.CreateLoad(m_args[1]); } +llvm::Value* Stack::top() +{ + return get(0); +} + + void debugStack(const char* op, const i256& word) { std::cerr << "STACK " << std::setw(4) << std::setfill(' ') << op << ": " @@ -114,24 +123,24 @@ EXPORT void evmccrt_stack_push(void* _stack, void* _pWord) stack->push_back(*word); } -EXPORT void evmccrt_stack_top(void* _stack, void* _pWord) +EXPORT void evmccrt_stack_pop(void* _stack, void* _pWord) { auto stack = static_cast(_stack); assert(!stack->empty()); auto word = &stack->back(); - debugStack("top", *word); + debugStack("pop", *word); auto outWord = static_cast(_pWord); + stack->pop_back(); *outWord = *word; } -EXPORT void evmccrt_stack_pop(void* _stack, void* _pWord) +EXPORT void evmccrt_stack_get(void* _stack, uint32_t _index, void* _pWord) { auto stack = static_cast(_stack); - assert(!stack->empty()); - auto word = &stack->back(); - debugStack("pop", *word); + assert(_index < stack->size()); + auto word = &(*stack)[stack->size() - _index - 1]; + debugStack("get", *word); auto outWord = static_cast(_pWord); - stack->pop_back(); *outWord = *word; } diff --git a/evmcc/Stack.h b/evmcc/Stack.h index e8b6a8e2d..e4d93bd8c 100644 --- a/evmcc/Stack.h +++ b/evmcc/Stack.h @@ -12,15 +12,16 @@ public: Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module); void push(llvm::Value* _value); - llvm::Value* top(); llvm::Value* pop(); + llvm::Value* top(); + llvm::Value* get(uint32_t _index); private: llvm::IRBuilder<>& m_builder; llvm::Value* m_args[2]; llvm::Function* m_stackPush; - llvm::Function* m_stackTop; llvm::Function* m_stackPop; + llvm::Function* m_stackGet; }; } \ No newline at end of file diff --git a/evmcc/bytecode/stack_test.evm b/evmcc/bytecode/stack_test.evm new file mode 100644 index 000000000..6eba9fdca --- /dev/null +++ b/evmcc/bytecode/stack_test.evm @@ -0,0 +1 @@ +65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae8182 diff --git a/evmcc/lll/stack_test.lll b/evmcc/lll/stack_test.lll new file mode 100644 index 000000000..0edf06624 --- /dev/null +++ b/evmcc/lll/stack_test.lll @@ -0,0 +1,22 @@ + +(asm +60666666666606 +7077777777777707 +DUP1 +DUP3 +DUP1 +DUP5 +DUP2 +DUP5 +POP +POP +POP +POP +POP +POP +POP +1111 +2222 +DUP2 +DUP3 +) \ No newline at end of file From 2eabdb0ceda6891ca2dad79801461f22570562a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Sep 2014 10:05:43 +0200 Subject: [PATCH 018/396] SWAP* instructions --- evmcc/Compiler.cpp | 25 ++++++++++++++++++++ evmcc/Stack.cpp | 43 ++++++++++++++++++++++++++--------- evmcc/Stack.h | 2 ++ evmcc/bytecode/stack_test.evm | 2 +- evmcc/lll/stack_test.lll | 4 +++- 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 454c61450..0b1793244 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -134,6 +134,31 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::SWAP1: + case Instruction::SWAP2: + case Instruction::SWAP3: + case Instruction::SWAP4: + case Instruction::SWAP5: + case Instruction::SWAP6: + case Instruction::SWAP7: + case Instruction::SWAP8: + case Instruction::SWAP9: + case Instruction::SWAP10: + case Instruction::SWAP11: + case Instruction::SWAP12: + case Instruction::SWAP13: + case Instruction::SWAP14: + case Instruction::SWAP15: + case Instruction::SWAP16: + { + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; + auto loValue = stack.get(index); + auto hiValue = stack.get(0); + stack.set(index, hiValue); + stack.set(0, loValue); + break; + } + } } diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index 4c5a19e8a..f0af2087a 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -55,6 +55,9 @@ Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) m_stackGet = llvm::Function::Create(getFuncType, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_get", _module); + m_stackSet = llvm::Function::Create(getFuncType, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_set", _module); + m_args[0] = m_builder.CreateCall(stackCreate, "stack.ptr"); m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "stack.val"); } @@ -82,24 +85,33 @@ llvm::Value* Stack::get(uint32_t _index) } +void Stack::set(uint32_t _index, llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_args[1]); // copy value to memory + llvm::Value* args[] = {m_args[0], m_builder.getInt32(_index), m_args[1]}; + m_builder.CreateCall(m_stackSet, args); +} + + llvm::Value* Stack::top() { return get(0); } -void debugStack(const char* op, const i256& word) +void debugStack(const char* _op, const i256& _word, uint32_t _index = 0) { - std::cerr << "STACK " << std::setw(4) << std::setfill(' ') << op << ": " - << std::dec << word.a - << " HEX: " << std::hex << std::setfill('0'); - if (word.b || word.c || word.d) + std::cerr << "STACK " << std::setw(4) << std::setfill(' ') << _op + << " [" << std::setw(2) << std::setfill('0') << _index << "] " + << std::dec << _word.a + << " HEX: " << std::hex; + if (_word.b || _word.c || _word.d) { - std::cerr << std::setw(16) << word.d << " " - << std::setw(16) << word.c << " " - << std::setw(16) << word.b << " "; + std::cerr << std::setw(16) << _word.d << " " + << std::setw(16) << _word.c << " " + << std::setw(16) << _word.b << " "; } - std::cerr << std::setw(16) << word.a << "\n"; + std::cerr << std::setw(16) << _word.a << "\n"; } } @@ -138,10 +150,19 @@ EXPORT void evmccrt_stack_get(void* _stack, uint32_t _index, void* _pWord) { auto stack = static_cast(_stack); assert(_index < stack->size()); - auto word = &(*stack)[stack->size() - _index - 1]; - debugStack("get", *word); + auto word = stack->rbegin() + _index; + debugStack("get", *word, _index); auto outWord = static_cast(_pWord); *outWord = *word; } +EXPORT void evmccrt_stack_set(void* _stack, uint32_t _index, void* _pWord) +{ + auto stack = static_cast(_stack); + auto word = static_cast(_pWord); + assert(_index < stack->size()); + *(stack->rbegin() + _index) = *word; + debugStack("set", *word, _index); +} + } // extern "C" diff --git a/evmcc/Stack.h b/evmcc/Stack.h index e4d93bd8c..a25de56e6 100644 --- a/evmcc/Stack.h +++ b/evmcc/Stack.h @@ -15,6 +15,7 @@ public: llvm::Value* pop(); llvm::Value* top(); llvm::Value* get(uint32_t _index); + void set(uint32_t _index, llvm::Value* _value); private: llvm::IRBuilder<>& m_builder; @@ -22,6 +23,7 @@ private: llvm::Function* m_stackPush; llvm::Function* m_stackPop; llvm::Function* m_stackGet; + llvm::Function* m_stackSet; }; } \ No newline at end of file diff --git a/evmcc/bytecode/stack_test.evm b/evmcc/bytecode/stack_test.evm index 6eba9fdca..02417c967 100644 --- a/evmcc/bytecode/stack_test.evm +++ b/evmcc/bytecode/stack_test.evm @@ -1 +1 @@ -65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae8182 +65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae81819290 diff --git a/evmcc/lll/stack_test.lll b/evmcc/lll/stack_test.lll index 0edf06624..e6581563c 100644 --- a/evmcc/lll/stack_test.lll +++ b/evmcc/lll/stack_test.lll @@ -18,5 +18,7 @@ POP 1111 2222 DUP2 -DUP3 +DUP2 +SWAP3 +SWAP1 ) \ No newline at end of file From 4ec1ebc82cc5d3c63fe29489e9f0ffc56fd84701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Sep 2014 11:26:58 +0200 Subject: [PATCH 019/396] Basic arithmetic, limited precision for MUL, DIV and MOD. --- evmcc/Compiler.cpp | 83 ++++++++++++++++++++++++++++++ evmcc/bytecode/arithmetic_test.evm | 1 + evmcc/bytecode/fib1.evm | 1 + evmcc/lll/arithmetic_test.lll | 29 +++++++++++ evmcc/lll/fib1.lll | 57 ++++++++++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 evmcc/bytecode/arithmetic_test.evm create mode 100644 evmcc/bytecode/fib1.evm create mode 100644 evmcc/lll/arithmetic_test.lll create mode 100644 evmcc/lll/fib1.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 0b1793244..3cd12833f 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -19,6 +19,7 @@ struct llvm::Type* word256arr; llvm::Type* size; llvm::Type* Void; + llvm::Type* WordLowPrecision; } Types; Compiler::Compiler() @@ -31,6 +32,9 @@ Compiler::Compiler() Types.word256arr = llvm::ArrayType::get(Types.word256, 100); Types.size = llvm::Type::getInt64Ty(context); Types.Void = llvm::Type::getVoidTy(context); + + // TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required + Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64); } @@ -59,6 +63,85 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto inst = static_cast(*pc); switch (inst) { + + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::MUL: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateMul(lhs128, rhs128); + auto res256 = builder.CreateZExt(res128, Types.word256); + stack.push(res256); + break; + } + + case Instruction::DIV: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateUDiv(lhs128, rhs128); + auto res256 = builder.CreateZExt(res128, Types.word256); + stack.push(res256); + break; + } + + case Instruction::SDIV: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateSDiv(lhs128, rhs128); + auto res256 = builder.CreateSExt(res128, Types.word256); + stack.push(res256); + break; + } + + case Instruction::MOD: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateURem(lhs128, rhs128); + auto res256 = builder.CreateZExt(res128, Types.word256); + stack.push(res256); + break; + } + + case Instruction::SMOD: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateSRem(lhs128, rhs128); + auto res256 = builder.CreateSExt(res128, Types.word256); + stack.push(res256); + break; + } + case Instruction::POP: { stack.pop(); diff --git a/evmcc/bytecode/arithmetic_test.evm b/evmcc/bytecode/arithmetic_test.evm new file mode 100644 index 000000000..67e86b310 --- /dev/null +++ b/evmcc/bytecode/arithmetic_test.evm @@ -0,0 +1 @@ +60016001900160070260050160029004600490066021900560150160030260059007600303 diff --git a/evmcc/bytecode/fib1.evm b/evmcc/bytecode/fib1.evm new file mode 100644 index 000000000..4c141314e --- /dev/null +++ b/evmcc/bytecode/fib1.evm @@ -0,0 +1 @@ +60016001818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101 diff --git a/evmcc/lll/arithmetic_test.lll b/evmcc/lll/arithmetic_test.lll new file mode 100644 index 000000000..e2c14d4c7 --- /dev/null +++ b/evmcc/lll/arithmetic_test.lll @@ -0,0 +1,29 @@ + +(asm +1 +1 +SWAP1 +ADD ;; 2 +7 +MUL ;; 14 +5 +ADD ;; 19 +2 +SWAP1 +DIV ;; 9 +4 +SWAP1 +MOD ;; 1 +33 +SWAP1 +SDIV;; 0 +21 +ADD ;; 21 +3 +MUL ;; 63 +5 +SWAP1 +SMOD;; 3 +3 +SUB ;; 0 +) \ No newline at end of file diff --git a/evmcc/lll/fib1.lll b/evmcc/lll/fib1.lll new file mode 100644 index 000000000..286bed275 --- /dev/null +++ b/evmcc/lll/fib1.lll @@ -0,0 +1,57 @@ +;; Fibbonacci unrolled + +(asm +1 +1 +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +) \ No newline at end of file From 72bb2d3e0cdbfb0aed369c1f022496992e66ab6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Sep 2014 11:27:53 +0200 Subject: [PATCH 020/396] Fix stack set/get bad function signature --- evmcc/Stack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index f0af2087a..aa02a846e 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -51,7 +51,7 @@ Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_pop", _module); llvm::Type* getArgsTypes[] = {stackPtrTy, m_builder.getInt32Ty(), i256PtrTy}; - auto getFuncType = llvm::FunctionType::get(voidTy, getArgsTypes); + auto getFuncType = llvm::FunctionType::get(voidTy, getArgsTypes, false); m_stackGet = llvm::Function::Create(getFuncType, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_get", _module); From 6eab61a1aed3c03b2f5b9a157e25f64ed814aadc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Sep 2014 17:11:50 +0200 Subject: [PATCH 021/396] Starting ExtVM binary interface --- evmcc/Compiler.cpp | 3 ++ evmcc/ExecutionEngine.cpp | 5 ++++ evmcc/Ext.cpp | 52 +++++++++++++++++++++++++++++++++++ evmcc/Ext.h | 22 +++++++++++++++ windows/evmcc.vcxproj | 6 ++-- windows/evmcc.vcxproj.filters | 2 ++ 6 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 evmcc/Ext.cpp create mode 100644 evmcc/Ext.h diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 3cd12833f..4237b59aa 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -6,6 +6,7 @@ #include #include "Stack.h" +#include "Ext.h" namespace evmcc { @@ -56,6 +57,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Init stack auto stack = Stack(builder, module.get()); + auto ext = Ext(builder); + for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) { using dev::eth::Instruction; diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index e59d6024a..3b3205af4 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -13,6 +13,8 @@ #include #include +#include "Ext.h" + namespace evmcc { @@ -66,6 +68,9 @@ int ExecutionEngine::run(std::unique_ptr _module) _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module exec->finalizeObject(); + auto ext = std::make_unique(); + Ext::init(std::move(ext)); + auto entryFunc = module->getFunction("main"); if (!entryFunc) { diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp new file mode 100644 index 000000000..1384694be --- /dev/null +++ b/evmcc/Ext.cpp @@ -0,0 +1,52 @@ + +#include "Ext.h" + +#include +#include + +#ifdef _MSC_VER +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +using namespace llvm; +using llvm::types::i; +using Linkage = llvm::GlobalValue::LinkageTypes; + +namespace evmcc +{ + +std::unique_ptr g_ext; + +void Ext::init(std::unique_ptr _ext) +{ + g_ext = std::move(_ext); +} + +Ext::Ext(llvm::IRBuilder<>& _builder) + : m_builder(_builder) +{ + auto module = m_builder.GetInsertBlock()->getParent()->getParent(); + auto&& ctx = _builder.getContext(); + + Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); + Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); +} + +extern "C" +{ + +EXPORT void ext_store(void* _index, void* _value) +{ + +} + +EXPORT void ext_setStore(void* _index, void* _value) +{ + +} + +} + +} \ No newline at end of file diff --git a/evmcc/Ext.h b/evmcc/Ext.h new file mode 100644 index 000000000..f1c88d849 --- /dev/null +++ b/evmcc/Ext.h @@ -0,0 +1,22 @@ + +#include + +#include + +namespace evmcc +{ + + + +class Ext +{ +public: + Ext(llvm::IRBuilder<>& _builder); + static void init(std::unique_ptr _ext); + +private: + llvm::IRBuilder<>& m_builder; +}; + + +} \ No newline at end of file diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 3a1869cd5..d10235ee3 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -22,11 +22,13 @@ + + @@ -136,8 +138,8 @@ Console true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;../../_build/LibSecp256k1/x64_Debug;../../_build/LibCryptoPP/x64_Debug;%(AdditionalLibraryDirectories) + LibEthereum.lib;LibSecp256k1.lib;LibCryptoPP.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 7db055ebf..7b0ee824a 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -5,10 +5,12 @@ + + \ No newline at end of file From 8a63213b6ba0c19492790b21ee655f1038dd6f0c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 30 Sep 2014 21:32:21 +0100 Subject: [PATCH 022/396] initial implementation of memory --- evmcc/Compiler.cpp | 42 ++++--------- evmcc/Compiler.h | 2 +- evmcc/Memory.cpp | 145 +++++++++++++++++++++++++++++++++++++++++++++ evmcc/Memory.h | 26 ++++++++ 4 files changed, 182 insertions(+), 33 deletions(-) create mode 100644 evmcc/Memory.cpp create mode 100644 evmcc/Memory.h diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 4c3a8a5f2..1114bde52 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -3,6 +3,7 @@ #include +#include "Memory.h" #include "Stack.h" namespace evmcc @@ -41,24 +42,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto module = std::make_unique("main", context); IRBuilder<> builder(context); - // Create globals for memory, memory size, stack and stack top - auto memory = new GlobalVariable(*module, Types.word8ptr, false, - GlobalValue::LinkageTypes::PrivateLinkage, - Constant::getNullValue(Types.word8ptr), "memory"); - auto memSize = new GlobalVariable(*module, Types.size, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantInt::get(Types.size, 0), "memsize"); - auto stack2 = new GlobalVariable(*module, Types.word256arr, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantAggregateZero::get(Types.word256arr), "stack"); - auto stackTop2 = new GlobalVariable(*module, Types.size, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantInt::get(Types.size, 0), "stackTop"); - - // Create value for void* malloc(size_t) - auto mallocVal = Function::Create(FunctionType::get(Types.word8ptr, { Types.size }, false), - GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module.get()); - // Create main function FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false); Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module.get()); @@ -66,13 +49,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) BasicBlock* entryBlock = BasicBlock::Create(context, "entry", mainFunc); builder.SetInsertPoint(entryBlock); - // Initialize memory with call to malloc, update memsize - std::vector mallocMemArgs = { ConstantInt::get(Types.size, 100) }; - auto mallocMemCall = builder.CreateCall(mallocVal, mallocMemArgs, "malloc_mem"); - builder.CreateStore(mallocMemCall, memory); - builder.CreateStore(ConstantInt::get(Types.size, 100), memSize); auto stack = Stack(builder, module.get()); + auto memory = Memory(builder, module.get()); uint64_t words[] = { 1, 2, 3, 4 }; auto val = llvm::APInt(256, 4, words); @@ -83,20 +62,19 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto top = stack.top(); stack.push(top); // dup - stack.pop(); + auto index = ConstantInt::get(Types.word256, 123); + memory.storeWord(index, c); - /* - std::vector mallocStackArgs = { ConstantInt::get(sizeTy, 200) }; - auto mallocStackCall = builder.CreateCall(mallocVal, mallocStackArgs, "malloc_stack"); - auto mallocCast = builder.CreatePointerBitCastOrAddrSpaceCast(mallocStackCall, int256ptr); - builder.CreateStore(mallocCast, stackVal); - */ + memory.dump(123, 123+32); - builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 13)); + auto index2 = ConstantInt::get(Types.word256, 123 + 16); + auto byte = memory.loadByte(index2); + auto result = builder.CreateZExt(byte, builder.getInt32Ty()); + builder.CreateRet(result); // should return 3 return module; } -} \ No newline at end of file +} diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index ae7033ac0..5a07e685d 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -18,4 +18,4 @@ public: }; -} \ No newline at end of file +} diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp new file mode 100644 index 000000000..9e3c2942e --- /dev/null +++ b/evmcc/Memory.cpp @@ -0,0 +1,145 @@ +#include "Memory.h" + +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef _MSC_VER + #define EXPORT __declspec(dllexport) +#else + #define EXPORT +#endif + +namespace evmcc +{ + +struct i256 +{ + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; +}; +static_assert(sizeof(i256) == 32, "Wrong i256 size"); + +using MemoryImpl = dev::bytes; + + +Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) + : m_builder(_builder) +{ + auto memoryCreate = llvm::Function::Create(llvm::FunctionType::get(m_builder.getVoidTy(), false), + llvm::GlobalValue::LinkageTypes::ExternalLinkage, + "evmccrt_memory_create", _module); + m_builder.CreateCall(memoryCreate); + + + auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), m_builder.getInt64Ty(), false); + m_memRequire = llvm::Function::Create(memRequireTy, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, + "evmccrt_memory_require", _module); + + auto i64Ty = m_builder.getInt64Ty(); + std::vector argTypes = {i64Ty, i64Ty}; + auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); + m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, + "evmccrt_memory_dump", _module); +} + + +llvm::Value* Memory::loadByte(llvm::Value* _addr) +{ + // trunc _addr (an i256) to i64 index and use it to index the memory + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); + + // load from evmccrt_memory_require()[index] + auto base = m_builder.CreateCall(m_memRequire, index, "base"); + auto ptr = m_builder.CreateGEP(base, index, "ptr"); + auto byte = m_builder.CreateLoad(ptr, "byte"); + return byte; +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); + auto index32 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 32), "index32"); + + auto base = m_builder.CreateCall(m_memRequire, index32, "base"); + auto ptr = m_builder.CreateGEP(base, index, "ptr"); + + auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); + auto wordPtr = m_builder.CreateBitCast(ptr, i256ptrTy, "wordptr"); + m_builder.CreateStore(_word, wordPtr); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _byte) +{ + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); + + auto base = m_builder.CreateCall(m_memRequire, index, "base"); + auto ptr = m_builder.CreateGEP(base, index, "ptr"); + m_builder.CreateStore(_byte, ptr); +} + +void Memory::dump(uint64_t _begin, uint64_t _end) +{ + auto beginVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _begin); + auto endVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _end); + + std::vector args = {beginVal, endVal}; + m_builder.CreateCall(m_memDump, llvm::ArrayRef(args)); +} + +} // namespace evmcc + +extern "C" +{ + using namespace evmcc; + +EXPORT MemoryImpl* evmccrt_memory; + +EXPORT void evmccrt_memory_create(void) +{ + evmccrt_memory = new MemoryImpl(1); + std::cerr << "MEMORY: create(), initial size = " << evmccrt_memory->size() + << std::endl; +} + +// Resizes memory to contain at least _size bytes and returns the base address. +EXPORT void* evmccrt_memory_require(uint64_t _size) +{ + std::cerr << "MEMORY: require(), current size = " << evmccrt_memory->size() + << ", required size = " << _size + << std::endl; + + if (evmccrt_memory->size() < _size) + evmccrt_memory->resize(_size); + + return &(*evmccrt_memory)[0]; +} + +EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) +{ + std::cerr << "Memory dump from " << std::hex << _begin << " to " << std::hex << _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 << ": "; + + uint8_t b = (*evmccrt_memory)[i]; + std::cerr << std::hex << std::setw(2) << static_cast(b) << ' '; + } + std::cerr << std::endl; +} + +} // extern "C" diff --git a/evmcc/Memory.h b/evmcc/Memory.h new file mode 100644 index 000000000..16a7ab4ca --- /dev/null +++ b/evmcc/Memory.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace evmcc +{ + +class Memory +{ +public: + Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); + + llvm::Value* loadByte(llvm::Value* _addr); + void storeWord(llvm::Value* _addr, llvm::Value* _word); + void storeByte(llvm::Value* _addr, llvm::Value* _byte); + + void dump(uint64_t _begin, uint64_t _end); + +private: + llvm::IRBuilder<>& m_builder; + + llvm::Function* m_memRequire; + llvm::Function* m_memDump; +}; + +} From afb0de7f02262ee8c2555a3b7aad9f72fdd3d3fa Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 30 Sep 2014 23:50:15 +0200 Subject: [PATCH 023/396] added ethcore to libs required by evmcc --- evmcc/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index 82647ca02..14fbe52e7 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} devcore) +target_link_libraries(${EXECUTABLE} ethcore) if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") From 362acacfa289260bcc156591750301bf4452973c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 1 Oct 2014 10:28:46 +0200 Subject: [PATCH 024/396] Set/get values in Ext store - SSTORE & SLOAD --- evmcc/Compiler.cpp | 16 ++++++++++++++++ evmcc/Ext.cpp | 35 +++++++++++++++++++++++++++++------ evmcc/Ext.h | 9 +++++++++ evmcc/Stack.cpp | 11 ++--------- evmcc/Utils.cpp | 34 ++++++++++++++++++++++++++++++++++ evmcc/Utils.h | 24 ++++++++++++++++++++++++ evmcc/bytecode/store_test.evm | 1 + evmcc/lll/stack_test.lll | 26 +++++--------------------- evmcc/lll/store_test.lll | 14 ++++++++++++++ windows/evmcc.vcxproj | 4 ++++ windows/evmcc.vcxproj.filters | 4 ++++ 11 files changed, 142 insertions(+), 36 deletions(-) create mode 100644 evmcc/Utils.cpp create mode 100644 evmcc/Utils.h create mode 100644 evmcc/bytecode/store_test.evm create mode 100644 evmcc/lll/store_test.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index ab16c50f1..00f2fb00b 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -247,6 +247,22 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = ext.store(index); + stack.push(value); + break; + } + + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + ext.setStore(index, value); + break; + } + } } diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 1384694be..35606f67f 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -4,6 +4,8 @@ #include #include +#include "Utils.h" + #ifdef _MSC_VER #define EXPORT __declspec(dllexport) #else @@ -30,21 +32,42 @@ Ext::Ext(llvm::IRBuilder<>& _builder) auto module = m_builder.GetInsertBlock()->getParent()->getParent(); auto&& ctx = _builder.getContext(); - Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); - Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); + m_args[0] = m_builder.CreateAlloca(m_builder.getIntNTy(256), nullptr, "ext.index"); + m_args[1] = m_builder.CreateAlloca(m_builder.getIntNTy(256), nullptr, "ext.value"); + + m_store = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); + m_setStore = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); } -extern "C" +llvm::Value* Ext::store(llvm::Value* _index) { + m_builder.CreateStore(_index, m_args[0]); + m_builder.CreateCall(m_store, m_args); + return m_builder.CreateLoad(m_args[1]); +} -EXPORT void ext_store(void* _index, void* _value) +void Ext::setStore(llvm::Value* _index, llvm::Value* _value) { - + m_builder.CreateStore(_index, m_args[0]); + m_builder.CreateStore(_value, m_args[1]); + m_builder.CreateCall(m_setStore, m_args); } -EXPORT void ext_setStore(void* _index, void* _value) +extern "C" { +EXPORT void ext_store(i256* _index, i256* _value) +{ + auto index = llvm2eth(*_index); + auto value = g_ext->store(index); + *_value = eth2llvm(value); +} + +EXPORT void ext_setStore(i256* _index, i256* _value) +{ + auto index = llvm2eth(*_index); + auto value = llvm2eth(*_value); + g_ext->setStore(index, value); } } diff --git a/evmcc/Ext.h b/evmcc/Ext.h index f1c88d849..4de1c6645 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -1,4 +1,6 @@ +#pragma once + #include #include @@ -14,8 +16,15 @@ public: Ext(llvm::IRBuilder<>& _builder); static void init(std::unique_ptr _ext); + llvm::Value* store(llvm::Value* _index); + void setStore(llvm::Value* _index, llvm::Value* _value); + private: llvm::IRBuilder<>& m_builder; + + llvm::Value* m_args[2]; + llvm::Function* m_store; + llvm::Function* m_setStore; }; diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index aa02a846e..877b192d9 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -9,6 +9,8 @@ #include +#include "Utils.h" + #ifdef _MSC_VER #define EXPORT __declspec(dllexport) #else @@ -18,15 +20,6 @@ namespace evmcc { -struct i256 -{ - uint64_t a; - uint64_t b; - uint64_t c; - uint64_t d; -}; -static_assert(sizeof(i256) == 32, "Wrong i265 size"); - using StackImpl = std::vector; diff --git a/evmcc/Utils.cpp b/evmcc/Utils.cpp new file mode 100644 index 000000000..cef08a283 --- /dev/null +++ b/evmcc/Utils.cpp @@ -0,0 +1,34 @@ + +#include "Utils.h" + +namespace evmcc +{ + +dev::u256 llvm2eth(i256 _i) +{ + dev::u256 u = 0; + u |= _i.d; + u <<= 64; + u |= _i.c; + u <<= 64; + u |= _i.b; + u <<= 64; + u |= _i.a; + return u; +} + +i256 eth2llvm(dev::u256 _u) +{ + i256 i; + dev::u256 mask = 0xFFFFFFFFFFFFFFFF; + i.a = static_cast(_u & mask); + _u >>= 64; + i.b = static_cast(_u & mask); + _u >>= 64; + i.c = static_cast(_u & mask); + _u >>= 64; + i.d = static_cast(_u & mask); + return i; +} + +} \ No newline at end of file diff --git a/evmcc/Utils.h b/evmcc/Utils.h new file mode 100644 index 000000000..065698448 --- /dev/null +++ b/evmcc/Utils.h @@ -0,0 +1,24 @@ + +#pragma once + +#include + +#include + +namespace evmcc +{ + +/// Representation of 256-bit value binary compatible with LLVM i256 +struct i256 +{ + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; +}; +static_assert(sizeof(i256) == 32, "Wrong i265 size"); + +dev::u256 llvm2eth(i256); +i256 eth2llvm(dev::u256); + +} \ No newline at end of file diff --git a/evmcc/bytecode/store_test.evm b/evmcc/bytecode/store_test.evm new file mode 100644 index 000000000..54c9419b5 --- /dev/null +++ b/evmcc/bytecode/store_test.evm @@ -0,0 +1 @@ +607b607c60015760005760015660005603 diff --git a/evmcc/lll/stack_test.lll b/evmcc/lll/stack_test.lll index e6581563c..fdf83594c 100644 --- a/evmcc/lll/stack_test.lll +++ b/evmcc/lll/stack_test.lll @@ -1,24 +1,8 @@ (asm -60666666666606 -7077777777777707 -DUP1 -DUP3 -DUP1 -DUP5 -DUP2 -DUP5 -POP -POP -POP -POP -POP -POP -POP -1111 -2222 -DUP2 -DUP2 -SWAP3 -SWAP1 +123 +SSTORE +SLOAD +123 +SUB ) \ No newline at end of file diff --git a/evmcc/lll/store_test.lll b/evmcc/lll/store_test.lll new file mode 100644 index 000000000..c40471c40 --- /dev/null +++ b/evmcc/lll/store_test.lll @@ -0,0 +1,14 @@ + +(asm +123 +124 +1 +SSTORE +0 +SSTORE +1 +SLOAD +0 +SLOAD +SUB +) \ No newline at end of file diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index d10235ee3..7959c5a1b 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -23,13 +23,17 @@ + + + + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 7b0ee824a..99c43b89b 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -6,11 +6,15 @@ + + + + \ No newline at end of file From bd3cd40e96fb6390a8020ab610c43b0bda5b25e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 1 Oct 2014 10:43:48 +0200 Subject: [PATCH 025/396] Improve stack binary interface --- evmcc/Stack.cpp | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index 877b192d9..2e9bb495c 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -120,42 +120,34 @@ EXPORT void* evmccrt_stack_create() return stack; } -EXPORT void evmccrt_stack_push(void* _stack, void* _pWord) +EXPORT void evmccrt_stack_push(StackImpl* _stack, i256* _word) { - auto stack = static_cast(_stack); - auto word = static_cast(_pWord); - debugStack("push", *word); - stack->push_back(*word); + debugStack("push", *_word); + _stack->push_back(*_word); } -EXPORT void evmccrt_stack_pop(void* _stack, void* _pWord) +EXPORT void evmccrt_stack_pop(StackImpl* _stack, i256* _outWord) { - auto stack = static_cast(_stack); - assert(!stack->empty()); - auto word = &stack->back(); + assert(!_stack->empty()); + auto word = &_stack->back(); debugStack("pop", *word); - auto outWord = static_cast(_pWord); - stack->pop_back(); - *outWord = *word; + _stack->pop_back(); + *_outWord = *word; } -EXPORT void evmccrt_stack_get(void* _stack, uint32_t _index, void* _pWord) +EXPORT void evmccrt_stack_get(StackImpl* _stack, uint32_t _index, i256* _outWord) { - auto stack = static_cast(_stack); - assert(_index < stack->size()); - auto word = stack->rbegin() + _index; + assert(_index < _stack->size()); + auto word = _stack->rbegin() + _index; debugStack("get", *word, _index); - auto outWord = static_cast(_pWord); - *outWord = *word; + *_outWord = *word; } -EXPORT void evmccrt_stack_set(void* _stack, uint32_t _index, void* _pWord) +EXPORT void evmccrt_stack_set(StackImpl* _stack, uint32_t _index, i256* _word) { - auto stack = static_cast(_stack); - auto word = static_cast(_pWord); - assert(_index < stack->size()); - *(stack->rbegin() + _index) = *word; - debugStack("set", *word, _index); + assert(_index < _stack->size()); + *(_stack->rbegin() + _index) = *_word; + debugStack("set", *_word, _index); } } // extern "C" From 10e5182860a814cd631d7bd34331d1d74bbad465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 1 Oct 2014 12:23:10 +0200 Subject: [PATCH 026/396] Send Ext static data to running contract. ADDRESS instruction --- evmcc/Compiler.cpp | 7 +++++ evmcc/ExecutionEngine.cpp | 1 + evmcc/Ext.cpp | 59 ++++++++++++++++++++++++++++++++++--- evmcc/Ext.h | 4 +++ evmcc/bytecode/ext_test.evm | 1 + evmcc/lll/ext_test.lll | 4 +++ 6 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 evmcc/bytecode/ext_test.evm create mode 100644 evmcc/lll/ext_test.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 00f2fb00b..0bbcafafb 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -263,6 +263,13 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::ADDRESS: + { + auto value = ext.address(); + stack.push(value); + break; + } + } } diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 3b3205af4..2b305e04a 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -69,6 +69,7 @@ int ExecutionEngine::run(std::unique_ptr _module) exec->finalizeObject(); auto ext = std::make_unique(); + ext->myAddress = dev::Address(1122334455667788); Ext::init(std::move(ext)); auto entryFunc = module->getFunction("main"); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 35606f67f..c6658f80c 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -19,6 +19,12 @@ using Linkage = llvm::GlobalValue::LinkageTypes; namespace evmcc { +// TODO: Copy of dev::eth::fromAddress in VM.h +inline dev::u256 fromAddress(dev::Address _a) +{ + return (dev::u160)_a; +} + std::unique_ptr g_ext; void Ext::init(std::unique_ptr _ext) @@ -26,17 +32,45 @@ void Ext::init(std::unique_ptr _ext) g_ext = std::move(_ext); } +struct ExtData +{ + i256 address; + i256 caller; + i256 origin; + i256 callvalue; + i256 gasprice; + i256 calldatasize; + const byte* calldata; +}; + Ext::Ext(llvm::IRBuilder<>& _builder) : m_builder(_builder) { auto module = m_builder.GetInsertBlock()->getParent()->getParent(); auto&& ctx = _builder.getContext(); - m_args[0] = m_builder.CreateAlloca(m_builder.getIntNTy(256), nullptr, "ext.index"); - m_args[1] = m_builder.CreateAlloca(m_builder.getIntNTy(256), nullptr, "ext.value"); - - m_store = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); + auto i256Ty = m_builder.getIntNTy(256); + m_args[0] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.index"); + m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value"); + + Type* elements[] = { + i256Ty, + i256Ty, + i256Ty, + i256Ty, + i256Ty, + i256Ty, + m_builder.getInt8PtrTy() + }; + auto extDataTy = StructType::create(elements, "ext.Data"); + + m_data = m_builder.CreateAlloca(extDataTy, nullptr, "ext.data"); + + m_init = Function::Create(FunctionType::get(m_builder.getVoidTy(), extDataTy->getPointerTo(), false), Linkage::ExternalLinkage, "ext_init", module); + m_store = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); m_setStore = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); + + m_builder.CreateCall(m_init, m_data); } llvm::Value* Ext::store(llvm::Value* _index) @@ -53,9 +87,26 @@ void Ext::setStore(llvm::Value* _index, llvm::Value* _value) m_builder.CreateCall(m_setStore, m_args); } +Value* Ext::address() +{ + auto valuePtr = m_builder.CreateStructGEP(m_data, 0); + return m_builder.CreateLoad(valuePtr); +} + extern "C" { +EXPORT void ext_init(ExtData* _extData) +{ + _extData->address = eth2llvm(fromAddress(g_ext->myAddress)); + _extData->caller = eth2llvm(fromAddress(g_ext->caller)); + _extData->origin = eth2llvm(fromAddress(g_ext->origin)); + _extData->callvalue = eth2llvm(g_ext->value); + _extData->gasprice = eth2llvm(g_ext->gasPrice); + _extData->calldatasize = eth2llvm(g_ext->data.size()); + _extData->calldata = g_ext->data.data(); +} + EXPORT void ext_store(i256* _index, i256* _value) { auto index = llvm2eth(*_index); diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 4de1c6645..f1e6ccc66 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -19,10 +19,14 @@ public: llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); + llvm::Value* address(); + private: llvm::IRBuilder<>& m_builder; llvm::Value* m_args[2]; + llvm::Value* m_data; + llvm::Function* m_init; llvm::Function* m_store; llvm::Function* m_setStore; }; diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm new file mode 100644 index 000000000..64bb6b746 --- /dev/null +++ b/evmcc/bytecode/ext_test.evm @@ -0,0 +1 @@ +30 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll new file mode 100644 index 000000000..627f6f96e --- /dev/null +++ b/evmcc/lll/ext_test.lll @@ -0,0 +1,4 @@ + +(asm +ADDRESS +) \ No newline at end of file From 696f6ae62eac4af03cd05cb6e000c2a162b4b16b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 1 Oct 2014 12:44:45 +0200 Subject: [PATCH 027/396] Accessing Ext static data: CALLER, ORIGIN, CALLVALUE, CALLDATASIZE, GASPRICE --- evmcc/Compiler.cpp | 35 +++++++++++++++++++++++++++++++++++ evmcc/ExecutionEngine.cpp | 6 ++++++ evmcc/Ext.cpp | 11 +++++++++-- evmcc/Ext.h | 8 ++++++++ evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 5 +++++ 6 files changed, 64 insertions(+), 3 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 0bbcafafb..77aaaa92f 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -270,6 +270,41 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::CALLER: + { + auto value = ext.caller(); + stack.push(value); + break; + } + + case Instruction::ORIGIN: + { + auto value = ext.origin(); + stack.push(value); + break; + } + + case Instruction::CALLVALUE: + { + auto value = ext.callvalue(); + stack.push(value); + break; + } + + case Instruction::CALLDATASIZE: + { + auto value = ext.calldatasize(); + stack.push(value); + break; + } + + case Instruction::GASPRICE: + { + auto value = ext.gasprice(); + stack.push(value); + break; + } + } } diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 2b305e04a..9011ac694 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -70,6 +70,12 @@ int ExecutionEngine::run(std::unique_ptr _module) auto ext = std::make_unique(); ext->myAddress = dev::Address(1122334455667788); + ext->caller = dev::Address(0xfacefacefaceface); + ext->origin = dev::Address(101010101010101010); + ext->value = 0xabcd; + ext->gasPrice = 1002; + std::string calldata = "Hello World!"; + ext->data = calldata; Ext::init(std::move(ext)); auto entryFunc = module->getFunction("main"); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index c6658f80c..309ef21a3 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -87,12 +87,19 @@ void Ext::setStore(llvm::Value* _index, llvm::Value* _value) m_builder.CreateCall(m_setStore, m_args); } -Value* Ext::address() +Value* Ext::getDataElem(unsigned _index, const Twine& _name) { - auto valuePtr = m_builder.CreateStructGEP(m_data, 0); + auto valuePtr = m_builder.CreateStructGEP(m_data, _index, _name); return m_builder.CreateLoad(valuePtr); } +Value* Ext::address() { return getDataElem(0, "address"); } +Value* Ext::caller() { return getDataElem(1, "caller"); } +Value* Ext::origin() { return getDataElem(2, "origin"); } +Value* Ext::callvalue() { return getDataElem(3, "callvalue"); } +Value* Ext::calldatasize() { return getDataElem(5, "calldatasize"); } +Value* Ext::gasprice() { return getDataElem(4, "gasprice"); } + extern "C" { diff --git a/evmcc/Ext.h b/evmcc/Ext.h index f1e6ccc66..60efe9f6f 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -20,6 +20,14 @@ public: void setStore(llvm::Value* _index, llvm::Value* _value); llvm::Value* address(); + llvm::Value* caller(); + llvm::Value* origin(); + llvm::Value* callvalue(); + llvm::Value* calldatasize(); + llvm::Value* gasprice(); + +private: + llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); private: llvm::IRBuilder<>& m_builder; diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index 64bb6b746..afbe4e752 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -30 +30333234363a diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index 627f6f96e..27dceabde 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -1,4 +1,9 @@ (asm ADDRESS +CALLER +ORIGIN +CALLVALUE +CALLDATASIZE +GASPRICE ) \ No newline at end of file From 9ee462570bb4741ead8d42da386797d72d766b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 1 Oct 2014 14:23:49 +0200 Subject: [PATCH 028/396] Push call data on stack - CALLDATALOAD --- evmcc/Compiler.cpp | 8 ++++++++ evmcc/ExecutionEngine.cpp | 2 +- evmcc/Ext.cpp | 18 ++++++++++++++++++ evmcc/Ext.h | 3 +++ evmcc/Utils.h | 1 + evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 6 ++++++ 7 files changed, 38 insertions(+), 2 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 77aaaa92f..1b3edd8bd 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -298,6 +298,14 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = ext.calldataload(index); + stack.push(value); + break; + } + case Instruction::GASPRICE: { auto value = ext.gasprice(); diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 9011ac694..616bde402 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -74,7 +74,7 @@ int ExecutionEngine::run(std::unique_ptr _module) ext->origin = dev::Address(101010101010101010); ext->value = 0xabcd; ext->gasPrice = 1002; - std::string calldata = "Hello World!"; + std::string calldata = "Hello the Beautiful World of Ethereum!"; ext->data = calldata; Ext::init(std::move(ext)); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 309ef21a3..0c38f73d3 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -69,6 +69,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder) m_init = Function::Create(FunctionType::get(m_builder.getVoidTy(), extDataTy->getPointerTo(), false), Linkage::ExternalLinkage, "ext_init", module); m_store = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); m_setStore = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); + m_calldataload = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_calldataload", module); m_builder.CreateCall(m_init, m_data); } @@ -100,6 +101,13 @@ Value* Ext::callvalue() { return getDataElem(3, "callvalue"); } Value* Ext::calldatasize() { return getDataElem(5, "calldatasize"); } Value* Ext::gasprice() { return getDataElem(4, "gasprice"); } +Value* Ext::calldataload(Value* _index) +{ + m_builder.CreateStore(_index, m_args[0]); + m_builder.CreateCall(m_calldataload, m_args); + return m_builder.CreateLoad(m_args[1]); +} + extern "C" { @@ -128,6 +136,16 @@ EXPORT void ext_setStore(i256* _index, i256* _value) g_ext->setStore(index, value); } +EXPORT void ext_calldataload(i256* _index, i256* _value) +{ + auto index = static_cast(llvm2eth(*_index)); + assert(index + 31 > index); // TODO: Handle large index + auto b = reinterpret_cast(_value); + for (size_t i = index, j = 31; i <= index + 31; ++i, --j) + b[j] = i < g_ext->data.size() ? g_ext->data[i] : 0; + // TODO: It all can be done by adding padding to data or by using min() algorithm without branch +} + } } \ No newline at end of file diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 60efe9f6f..a579dca81 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -26,6 +26,8 @@ public: llvm::Value* calldatasize(); llvm::Value* gasprice(); + llvm::Value* calldataload(llvm::Value* _index); + private: llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); @@ -37,6 +39,7 @@ private: llvm::Function* m_init; llvm::Function* m_store; llvm::Function* m_setStore; + llvm::Function* m_calldataload; }; diff --git a/evmcc/Utils.h b/evmcc/Utils.h index 065698448..8233ac9e3 100644 --- a/evmcc/Utils.h +++ b/evmcc/Utils.h @@ -9,6 +9,7 @@ namespace evmcc { /// Representation of 256-bit value binary compatible with LLVM i256 +// TODO: Replace with h256 struct i256 { uint64_t a; diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index afbe4e752..ccca5e56b 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -30333234363a +30333234363a600035602635601335 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index 27dceabde..f6680f2a7 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -6,4 +6,10 @@ ORIGIN CALLVALUE CALLDATASIZE GASPRICE +0 +CALLDATALOAD +38 +CALLDATALOAD +19 +CALLDATALOAD ) \ No newline at end of file From 638bb9390cc0e32819a58b6378cc9b4d302e2e8c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 1 Oct 2014 15:46:46 +0200 Subject: [PATCH 029/396] Implemented MLOAD, MSTORE, MSTORE8 and MSIZE --- evmcc/Compiler.cpp | 31 ++++++++++++++++++++ evmcc/Memory.cpp | 64 +++++++++++++++++++++++++++++++++--------- evmcc/Memory.h | 6 ++-- evmcc/lll/memtest1.lll | 17 +++++++++++ 4 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 evmcc/lll/memtest1.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 77aaaa92f..2b27c6e32 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -247,6 +247,37 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = memory.loadWord(addr); + stack.push(word); + break; + } + + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeWord(addr, word); + break; + } + + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeByte(addr, word); + break; + } + + case Instruction::MSIZE: + { + auto word = memory.getSize(); + stack.push(word); + break; + } + case Instruction::SLOAD: { auto index = stack.pop(); diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 9e3c2942e..bba929576 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -34,18 +34,25 @@ using MemoryImpl = dev::bytes; Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) : m_builder(_builder) { - auto memoryCreate = llvm::Function::Create(llvm::FunctionType::get(m_builder.getVoidTy(), false), + auto voidTy = m_builder.getVoidTy(); + auto i64Ty = m_builder.getInt64Ty(); + + auto memoryCreate = llvm::Function::Create(llvm::FunctionType::get(voidTy, false), llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_memory_create", _module); m_builder.CreateCall(memoryCreate); - auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), m_builder.getInt64Ty(), false); + auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false); m_memRequire = llvm::Function::Create(memRequireTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_memory_require", _module); - auto i64Ty = m_builder.getInt64Ty(); + auto memSizeTy = llvm::FunctionType::get(i64Ty, false); + m_memSize = llvm::Function::Create(memSizeTy, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, + "evmccrt_memory_size", _module); + std::vector argTypes = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, @@ -53,7 +60,7 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) } -llvm::Value* Memory::loadByte(llvm::Value* _addr) +llvm::Value* Memory::loadWord(llvm::Value* _addr) { // trunc _addr (an i256) to i64 index and use it to index the memory auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); @@ -61,7 +68,12 @@ llvm::Value* Memory::loadByte(llvm::Value* _addr) // load from evmccrt_memory_require()[index] auto base = m_builder.CreateCall(m_memRequire, index, "base"); auto ptr = m_builder.CreateGEP(base, index, "ptr"); - auto byte = m_builder.CreateLoad(ptr, "byte"); + + auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); + auto wordPtr = m_builder.CreateBitCast(ptr, i256ptrTy, "wordptr"); + auto byte = m_builder.CreateLoad(wordPtr, "word"); + + dump(0); return byte; } @@ -76,19 +88,34 @@ void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); auto wordPtr = m_builder.CreateBitCast(ptr, i256ptrTy, "wordptr"); m_builder.CreateStore(_word, wordPtr); + + dump(0); } -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _byte) +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { + auto byte = m_builder.CreateTrunc(_word, m_builder.getInt8Ty(), "byte"); auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); auto base = m_builder.CreateCall(m_memRequire, index, "base"); auto ptr = m_builder.CreateGEP(base, index, "ptr"); - m_builder.CreateStore(_byte, ptr); + m_builder.CreateStore(byte, ptr); + + dump(0); +} + +llvm::Value* Memory::getSize() +{ + auto size = m_builder.CreateCall(m_memSize, "mem.size"); + auto word = m_builder.CreateZExt(size, m_builder.getIntNTy(256), "mem.wsize"); + return word; } void Memory::dump(uint64_t _begin, uint64_t _end) { + if (getenv("EVMCC_DEBUG_MEMORY") == nullptr) + return; + auto beginVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _begin); auto endVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _end); @@ -106,26 +133,37 @@ EXPORT MemoryImpl* evmccrt_memory; EXPORT void evmccrt_memory_create(void) { - evmccrt_memory = new MemoryImpl(1); + evmccrt_memory = new MemoryImpl(); std::cerr << "MEMORY: create(), initial size = " << evmccrt_memory->size() << std::endl; } -// Resizes memory to contain at least _size bytes and returns the base address. -EXPORT void* evmccrt_memory_require(uint64_t _size) +// Resizes memory to contain at least _index + 1 bytes and returns the base address. +EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) { + uint64_t size = _index + 1; + std::cerr << "MEMORY: require(), current size = " << evmccrt_memory->size() - << ", required size = " << _size + << ", required size = " << size << std::endl; - if (evmccrt_memory->size() < _size) - evmccrt_memory->resize(_size); + if (evmccrt_memory->size() < size) + evmccrt_memory->resize(size); return &(*evmccrt_memory)[0]; } +EXPORT uint64_t evmccrt_memory_size() +{ + return (evmccrt_memory->size() + 31) / 32; +} + EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) { + if (_end == 0) + _end = evmccrt_memory->size(); + + std::cerr << "Active memory size: " << evmccrt_memory_size() << " words\n"; std::cerr << "Memory dump from " << std::hex << _begin << " to " << std::hex << _end << ":"; if (_end <= _begin) return; diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 16a7ab4ca..8fbbe0a58 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -10,17 +10,19 @@ class Memory public: Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); - llvm::Value* loadByte(llvm::Value* _addr); + llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); void storeByte(llvm::Value* _addr, llvm::Value* _byte); + llvm::Value* getSize(); - void dump(uint64_t _begin, uint64_t _end); + void dump(uint64_t _begin, uint64_t _end = 0); private: llvm::IRBuilder<>& m_builder; llvm::Function* m_memRequire; llvm::Function* m_memDump; + llvm::Function* m_memSize; }; } diff --git a/evmcc/lll/memtest1.lll b/evmcc/lll/memtest1.lll new file mode 100644 index 000000000..016e4075f --- /dev/null +++ b/evmcc/lll/memtest1.lll @@ -0,0 +1,17 @@ + +(asm ;; [] +2 +0 +MSTORE8 ;; [02] +3 +1 +MSTORE8 ;; [02 03] +0 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +1 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +ADD +2 +MSTORE ;; [2 3 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] +) From 65908ab5e86df6ca9db1b6a4dbf74cae75f98950 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 1 Oct 2014 16:32:59 +0200 Subject: [PATCH 030/396] fixed bug in memory handling --- evmcc/Memory.cpp | 34 ++++++++++++++++++++-------------- evmcc/bytecode/memtest1.evm | 1 + evmcc/lll/memtest1.lll | 9 +++++---- 3 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 evmcc/bytecode/memtest1.evm diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index bba929576..219dfe7fa 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -63,10 +63,11 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) llvm::Value* Memory::loadWord(llvm::Value* _addr) { // trunc _addr (an i256) to i64 index and use it to index the memory - auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "mem.index"); + auto index31 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 31), "mem.index.31"); // load from evmccrt_memory_require()[index] - auto base = m_builder.CreateCall(m_memRequire, index, "base"); + auto base = m_builder.CreateCall(m_memRequire, index31, "base"); auto ptr = m_builder.CreateGEP(base, index, "ptr"); auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); @@ -79,10 +80,10 @@ llvm::Value* Memory::loadWord(llvm::Value* _addr) void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); - auto index32 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 32), "index32"); + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "mem.index"); + auto index31 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 31), "mem.index31"); - auto base = m_builder.CreateCall(m_memRequire, index32, "base"); + auto base = m_builder.CreateCall(m_memRequire, index31, "base"); auto ptr = m_builder.CreateGEP(base, index, "ptr"); auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); @@ -141,21 +142,24 @@ EXPORT void evmccrt_memory_create(void) // Resizes memory to contain at least _index + 1 bytes and returns the base address. EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) { - uint64_t size = _index + 1; + uint64_t requiredSize = (_index / 32 + 1) * 32; - std::cerr << "MEMORY: require(), current size = " << evmccrt_memory->size() - << ", required size = " << size - << std::endl; + if (evmccrt_memory->size() < requiredSize) + { + std::cerr << "MEMORY: current size: " << std::dec + << evmccrt_memory->size() << " bytes, required size: " + << requiredSize << " bytes" + << std::endl; - if (evmccrt_memory->size() < size) - evmccrt_memory->resize(size); + evmccrt_memory->resize(requiredSize); + } return &(*evmccrt_memory)[0]; } EXPORT uint64_t evmccrt_memory_size() { - return (evmccrt_memory->size() + 31) / 32; + return evmccrt_memory->size() / 32; } EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) @@ -163,8 +167,10 @@ EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) if (_end == 0) _end = evmccrt_memory->size(); - std::cerr << "Active memory size: " << evmccrt_memory_size() << " words\n"; - std::cerr << "Memory dump from " << std::hex << _begin << " to " << std::hex << _end << ":"; + std::cerr << "MEMORY: active size: " << std::dec + << evmccrt_memory_size() << " words\n"; + std::cerr << "MEMORY: dump from " << std::dec + << _begin << " to " << _end << ":"; if (_end <= _begin) return; diff --git a/evmcc/bytecode/memtest1.evm b/evmcc/bytecode/memtest1.evm new file mode 100644 index 000000000..0506bf928 --- /dev/null +++ b/evmcc/bytecode/memtest1.evm @@ -0,0 +1 @@ +6002600055600360015560005360015301600254 diff --git a/evmcc/lll/memtest1.lll b/evmcc/lll/memtest1.lll index 016e4075f..4b4389ad8 100644 --- a/evmcc/lll/memtest1.lll +++ b/evmcc/lll/memtest1.lll @@ -9,9 +9,10 @@ MSTORE8 ;; [02 03] 0 MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 1 -MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] ADD 2 -MSTORE ;; [2 3 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] -) +MSTORE ;; [2 3 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +) \ No newline at end of file From f41550077a084183e69b70404c6f7b89f0acdb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 1 Oct 2014 16:48:02 +0200 Subject: [PATCH 031/396] Implementing RETURN and STOP instructions --- evmcc/Compiler.cpp | 48 ++++++++++++++++++++++++++++++++++--- evmcc/ExecutionEngine.cpp | 10 ++++++-- evmcc/Memory.cpp | 15 ++++-------- evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 5 ++++ 5 files changed, 63 insertions(+), 17 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 1b3edd8bd..e258f840d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -49,7 +49,10 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) IRBuilder<> builder(context); // Create main function - auto mainFuncType = FunctionType::get(llvm::Type::getInt32Ty(context), false); + const auto i32Ty = builder.getInt32Ty(); + Type* retTypeElems[] = {i32Ty, i32Ty}; + auto retType = StructType::create(retTypeElems, "MemRef", true); + auto mainFuncType = FunctionType::get(builder.getInt64Ty(), false); auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get()); auto entryBlock = BasicBlock::Create(context, "entry", mainFunc); @@ -61,7 +64,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto ext = Ext(builder); - for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) + auto userRet = false; + auto finished = false; + for (auto pc = bytecode.cbegin(); pc != bytecode.cend() && !finished; ++pc) { using dev::eth::Instruction; @@ -313,10 +318,47 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::CODESIZE: + { + auto value = builder.getIntN(256, bytecode.size()); + stack.push(value); + break; + } + + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); + + // MCJIT does not support returning structs + //auto index32 = builder.CreateTrunc(index, i32Ty, "index32"); + //auto size32 = builder.CreateTrunc(size, i32Ty, "size32"); + //auto ret = builder.CreateInsertValue(UndefValue::get(retType), index32, 0, "ret"); + //ret = builder.CreateInsertValue(ret, size32, 1, "ret"); + + auto ret = builder.CreateTrunc(index, builder.getInt64Ty()); + ret = builder.CreateShl(ret, 32); + size = builder.CreateTrunc(size, i32Ty); + size = builder.CreateZExt(size, builder.getInt64Ty()); + ret = builder.CreateOr(ret, size); + + builder.CreateRet(ret); + finished = true; + userRet = true; + break; + } + + case Instruction::STOP: + { + finished = true; + break; + } + } } - builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 0)); + if (!userRet) + builder.CreateRet(builder.getInt64(0)); return module; } diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 616bde402..410e80a0b 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -86,8 +86,14 @@ int ExecutionEngine::run(std::unique_ptr _module) } auto result = exec->runFunction(entryFunc, {}); - auto intResult = result.IntVal.getZExtValue(); - return intResult; + if (auto intResult = result.IntVal.getZExtValue()) + { + auto index = intResult >> 32; + auto size = 0xFFFFFFFF & intResult; + // TODO: Get the data from memory + return 10; + } + return 0; } } \ No newline at end of file diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 9e3c2942e..7c8d2d54a 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -10,6 +10,8 @@ #include +#include "Utils.h" + #ifdef _MSC_VER #define EXPORT __declspec(dllexport) #else @@ -19,15 +21,6 @@ namespace evmcc { -struct i256 -{ - uint64_t a; - uint64_t b; - uint64_t c; - uint64_t d; -}; -static_assert(sizeof(i256) == 32, "Wrong i256 size"); - using MemoryImpl = dev::bytes; @@ -102,7 +95,7 @@ extern "C" { using namespace evmcc; -EXPORT MemoryImpl* evmccrt_memory; +static MemoryImpl* evmccrt_memory; EXPORT void evmccrt_memory_create(void) { @@ -121,7 +114,7 @@ EXPORT void* evmccrt_memory_require(uint64_t _size) if (evmccrt_memory->size() < _size) evmccrt_memory->resize(_size); - return &(*evmccrt_memory)[0]; + return evmccrt_memory->data(); } EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index ccca5e56b..5bcc94ba1 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -30333234363a600035602635601335 +30333234363a600035602635601335380060016002f2 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index f6680f2a7..f32bfb440 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -12,4 +12,9 @@ CALLDATALOAD CALLDATALOAD 19 CALLDATALOAD +CODESIZE +STOP +1 +2 +RETURN ) \ No newline at end of file From f6759913e4aad3c577067ae089f0890fe93b73b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 1 Oct 2014 17:30:04 +0200 Subject: [PATCH 032/396] Print returned memory to standard output --- evmcc/Compiler.cpp | 2 +- evmcc/ExecutionEngine.cpp | 10 +++++++++- evmcc/Memory.cpp | 34 ++++++++++++++++------------------ evmcc/Memory.h | 6 +++++- evmcc/bytecode/return_test.evm | 1 + evmcc/lll/return_test.lll | 15 +++++++++++++++ 6 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 evmcc/bytecode/return_test.evm create mode 100644 evmcc/lll/return_test.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 51d74bb2f..c55b33cc6 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -60,7 +60,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Init stack and memory auto stack = Stack(builder, module.get()); - auto memory = Memory(builder, module.get()); + auto memory = Memory(builder); auto ext = Ext(builder); diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 410e80a0b..4d847388e 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -14,6 +14,7 @@ #include #include "Ext.h" +#include "Memory.h" namespace evmcc { @@ -68,6 +69,8 @@ int ExecutionEngine::run(std::unique_ptr _module) _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module exec->finalizeObject(); + auto&& memory = Memory::init(); + auto ext = std::make_unique(); ext->myAddress = dev::Address(1122334455667788); ext->caller = dev::Address(0xfacefacefaceface); @@ -90,7 +93,12 @@ int ExecutionEngine::run(std::unique_ptr _module) { auto index = intResult >> 32; auto size = 0xFFFFFFFF & intResult; - // TODO: Get the data from memory + + std::cout << "RETURN [ "; + for (dev::bytes::const_iterator it = memory.cbegin() + index, end = it + size; it != end; ++it) + std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; + std::cout << "]"; + return 10; } return 0; diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 9897496de..2a1a0f727 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -23,33 +23,40 @@ namespace evmcc using MemoryImpl = dev::bytes; +static MemoryImpl* evmccrt_memory; + -Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) +Memory::Memory(llvm::IRBuilder<>& _builder) : m_builder(_builder) { auto voidTy = m_builder.getVoidTy(); auto i64Ty = m_builder.getInt64Ty(); - - auto memoryCreate = llvm::Function::Create(llvm::FunctionType::get(voidTy, false), - llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_create", _module); - m_builder.CreateCall(memoryCreate); + auto module = _builder.GetInsertBlock()->getParent()->getParent(); auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false); m_memRequire = llvm::Function::Create(memRequireTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_require", _module); + "evmccrt_memory_require", module); auto memSizeTy = llvm::FunctionType::get(i64Ty, false); m_memSize = llvm::Function::Create(memSizeTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_size", _module); + "evmccrt_memory_size", module); std::vector argTypes = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_dump", _module); + "evmccrt_memory_dump", module); +} + +const dev::bytes& Memory::init() +{ + evmccrt_memory = new MemoryImpl(); + std::cerr << "MEMORY: create(), initial size = " << evmccrt_memory->size() + << std::endl; + + return *evmccrt_memory; } @@ -123,15 +130,6 @@ extern "C" { using namespace evmcc; -static MemoryImpl* evmccrt_memory; - -EXPORT void evmccrt_memory_create(void) -{ - evmccrt_memory = new MemoryImpl(); - std::cerr << "MEMORY: create(), initial size = " << evmccrt_memory->size() - << std::endl; -} - // Resizes memory to contain at least _index + 1 bytes and returns the base address. EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) { diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 8fbbe0a58..b36386325 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -2,13 +2,17 @@ #include +#include + namespace evmcc { class Memory { public: - Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); + Memory(llvm::IRBuilder<>& _builder); + + static const dev::bytes& init(); llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); diff --git a/evmcc/bytecode/return_test.evm b/evmcc/bytecode/return_test.evm new file mode 100644 index 000000000..977cf7c19 --- /dev/null +++ b/evmcc/bytecode/return_test.evm @@ -0,0 +1 @@ +60016064546002608454600360a45460606064f2 diff --git a/evmcc/lll/return_test.lll b/evmcc/lll/return_test.lll new file mode 100644 index 000000000..c87a2d812 --- /dev/null +++ b/evmcc/lll/return_test.lll @@ -0,0 +1,15 @@ + +(asm +1 +100 +MSTORE +2 +132 +MSTORE +3 +164 +MSTORE +96 +100 +RETURN +) \ No newline at end of file From ca49fe4897e53507fddbedd3024ee5ad09c0066b Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 11:00:28 +0200 Subject: [PATCH 033/396] initial implementation of JUMP/JUMPI (untested) --- evmcc/Compiler.cpp | 171 ++++++++++++++++++++++++++++++++++++++++++++- evmcc/Compiler.h | 16 +++++ 2 files changed, 184 insertions(+), 3 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 2a13e4a64..87c96a20d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -39,6 +39,117 @@ Compiler::Compiler() Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64); } +llvm::BasicBlock* Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc) +{ + llvm::BasicBlock* block = nullptr; + auto blockIter = basicBlocks.find(pc); + if (blockIter == basicBlocks.cend()) + { + // Create a basic block at targetPC. + std::ostringstream oss; + oss << "instr." << pc; + block = llvm::BasicBlock::Create(llvm::getGlobalContext(), oss.str()); + basicBlocks[pc] = block; + } + else + { + block = blockIter->second; + } + return block; +} + +void Compiler::createBasicBlocks(const dev::bytes& bytecode) +{ + for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr) + { + using dev::eth::Instruction; + + auto inst = static_cast(*curr); + switch (inst) + { + case Instruction::PUSH1: + case Instruction::PUSH2: + case Instruction::PUSH3: + case Instruction::PUSH4: + case Instruction::PUSH5: + case Instruction::PUSH6: + case Instruction::PUSH7: + case Instruction::PUSH8: + case Instruction::PUSH9: + case Instruction::PUSH10: + case Instruction::PUSH11: + case Instruction::PUSH12: + case Instruction::PUSH13: + case Instruction::PUSH14: + case Instruction::PUSH15: + case Instruction::PUSH16: + case Instruction::PUSH17: + case Instruction::PUSH18: + case Instruction::PUSH19: + case Instruction::PUSH20: + case Instruction::PUSH21: + case Instruction::PUSH22: + case Instruction::PUSH23: + case Instruction::PUSH24: + case Instruction::PUSH25: + case Instruction::PUSH26: + case Instruction::PUSH27: + case Instruction::PUSH28: + case Instruction::PUSH29: + case Instruction::PUSH30: + case Instruction::PUSH31: + case Instruction::PUSH32: + { + auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; + auto next = curr + numBytes + 1; + if (next == bytecode.cend()) + break; + + auto nextInst = static_cast(*next); + + if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) + { + // Compute target PC of the jump. + dev::u256 val = 0; + for (auto iter = curr + 1; iter < next; ++iter) + { + val <<= 8; + val |= *iter; + } + + // Create a block for the JUMP target. + ProgramCounter targetPC = val.convert_to(); + auto targetBlock = getOrCreateBasicBlockAtPC(targetPC); + + ProgramCounter jumpPC = (next - bytecode.cbegin()); + jumpTargets[jumpPC] = targetBlock; + + // Create a block following the JUMP. + if (next + 1 < bytecode.cend()) + { + ProgramCounter nextPC = (next + 1 - bytecode.cbegin()); + getOrCreateBasicBlockAtPC(nextPC); + } + + curr += 1; // skip over JUMP + } + + curr += numBytes; + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + { + std::cerr << "JUMP/JUMPI at " << (curr - bytecode.cbegin()) << " not preceded by PUSH\n"; + std::exit(1); + } + + default: + break; + } + } +} std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { @@ -52,23 +163,77 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto mainFuncType = FunctionType::get(llvm::Type::getInt32Ty(context), false); auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get()); - auto entryBlock = BasicBlock::Create(context, "entry", mainFunc); - builder.SetInsertPoint(entryBlock); - // Init stack and memory auto stack = Stack(builder, module.get()); auto memory = Memory(builder, module.get()); auto ext = Ext(builder); + // Create the basic blocks. + auto entryBlock = BasicBlock::Create(context, "entry", mainFunc); + basicBlocks[0] = entryBlock; + createBasicBlocks(bytecode); + + BasicBlock* currentBlock = nullptr; + for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) { using dev::eth::Instruction; + ProgramCounter currentPC = pc - bytecode.cbegin(); + + auto blockIter = basicBlocks.find(currentPC); + if (blockIter != basicBlocks.end()) + { + auto nextBlock = blockIter->second; + if (currentBlock != nullptr) + { + // Terminate the current block by jumping to the next one. + builder.CreateBr(nextBlock); + } + // Insert the next block into the main function. + if (nextBlock != entryBlock) + mainFunc->getBasicBlockList().push_back(nextBlock); + builder.SetInsertPoint(nextBlock); + currentBlock = nextBlock; + } + + assert(currentBlock != nullptr); + auto inst = static_cast(*pc); switch (inst) { + case Instruction::JUMP: + { + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + + auto targetBlock = jumpTargets[currentPC]; + builder.CreateBr(targetBlock); + + currentBlock = nullptr; + break; + } + + case Instruction::JUMPI: + { + assert(pc + 1 < bytecode.cend()); + + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + + auto cond = stack.pop(); + auto targetBlock = jumpTargets[currentPC]; + auto followBlock = basicBlocks[currentPC + 1]; + builder.CreateCondBr(cond, targetBlock, followBlock); + + currentBlock = nullptr; + break; + } + case Instruction::ADD: { auto lhs = stack.pop(); diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 5a07e685d..6e9fd8443 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -12,10 +12,26 @@ class Compiler { public: + using ProgramCounter = uint64_t; + Compiler(); std::unique_ptr compile(const dev::bytes& bytecode); +private: + + llvm::BasicBlock* getOrCreateBasicBlockAtPC(ProgramCounter pc); + void createBasicBlocks(const dev::bytes& bytecode); + + /** + * Maps a program counter pc to a basic block which starts at pc (if any). + */ + std::map basicBlocks; + + /** + * Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. + */ + std::map jumpTargets; }; } From d11127c94d8900b84983339eb0d1d487a2643621 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 11:14:09 +0200 Subject: [PATCH 034/396] Added Module* constructor argument to Memory and Ext. --- evmcc/Compiler.cpp | 11 +++++------ evmcc/Ext.cpp | 5 ++--- evmcc/Ext.h | 4 ++-- evmcc/Memory.cpp | 4 +--- evmcc/Memory.h | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 0dae87213..6c5229056 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -166,17 +166,16 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto mainFuncType = FunctionType::get(builder.getInt64Ty(), false); auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get()); - // Init stack and memory - auto stack = Stack(builder, module.get()); - auto memory = Memory(builder); - - auto ext = Ext(builder); - // Create the basic blocks. auto entryBlock = BasicBlock::Create(context, "entry", mainFunc); basicBlocks[0] = entryBlock; createBasicBlocks(bytecode); + // Init runtime structures. + auto stack = Stack(builder, module.get()); + auto memory = Memory(builder, module.get()); + auto ext = Ext(builder, module.get()); + auto userRet = false; auto finished = false; diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 0c38f73d3..e3bb17af6 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -43,10 +43,9 @@ struct ExtData const byte* calldata; }; -Ext::Ext(llvm::IRBuilder<>& _builder) +Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) : m_builder(_builder) { - auto module = m_builder.GetInsertBlock()->getParent()->getParent(); auto&& ctx = _builder.getContext(); auto i256Ty = m_builder.getIntNTy(256); @@ -148,4 +147,4 @@ EXPORT void ext_calldataload(i256* _index, i256* _value) } -} \ No newline at end of file +} diff --git a/evmcc/Ext.h b/evmcc/Ext.h index a579dca81..8c08acdfe 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -13,7 +13,7 @@ namespace evmcc class Ext { public: - Ext(llvm::IRBuilder<>& _builder); + Ext(llvm::IRBuilder<>& _builder, llvm::Module* module); static void init(std::unique_ptr _ext); llvm::Value* store(llvm::Value* _index); @@ -43,4 +43,4 @@ private: }; -} \ No newline at end of file +} diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 2a1a0f727..fd7727b59 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -26,13 +26,11 @@ using MemoryImpl = dev::bytes; static MemoryImpl* evmccrt_memory; -Memory::Memory(llvm::IRBuilder<>& _builder) +Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* module) : m_builder(_builder) { auto voidTy = m_builder.getVoidTy(); auto i64Ty = m_builder.getInt64Ty(); - auto module = _builder.GetInsertBlock()->getParent()->getParent(); - auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false); m_memRequire = llvm::Function::Create(memRequireTy, diff --git a/evmcc/Memory.h b/evmcc/Memory.h index b36386325..87ce27ed0 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -10,7 +10,7 @@ namespace evmcc class Memory { public: - Memory(llvm::IRBuilder<>& _builder); + Memory(llvm::IRBuilder<>& _builder, llvm::Module* module); static const dev::bytes& init(); From 0d283dfa7c62811400e219353a39731fd3892c7c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 11:45:54 +0200 Subject: [PATCH 035/396] fixed implementation of JUMPI (cond casted to bool) --- evmcc/Compiler.cpp | 76 ++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 6c5229056..1ce211e98 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -169,6 +169,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Create the basic blocks. auto entryBlock = BasicBlock::Create(context, "entry", mainFunc); basicBlocks[0] = entryBlock; + builder.SetInsertPoint(entryBlock); createBasicBlocks(bytecode); // Init runtime structures. @@ -179,7 +180,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto userRet = false; auto finished = false; - BasicBlock* currentBlock = nullptr; + BasicBlock* currentBlock = entryBlock; for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) { @@ -188,17 +189,13 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) ProgramCounter currentPC = pc - bytecode.cbegin(); auto blockIter = basicBlocks.find(currentPC); - if (blockIter != basicBlocks.end()) + if (currentPC > 0 && blockIter != basicBlocks.end()) { auto nextBlock = blockIter->second; - if (currentBlock != nullptr) - { - // Terminate the current block by jumping to the next one. - builder.CreateBr(nextBlock); - } + // Terminate the current block by jumping to the next one. + builder.CreateBr(nextBlock); // Insert the next block into the main function. - if (nextBlock != entryBlock) - mainFunc->getBasicBlockList().push_back(nextBlock); + mainFunc->getBasicBlockList().push_back(nextBlock); builder.SetInsertPoint(nextBlock); currentBlock = nextBlock; } @@ -209,36 +206,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) switch (inst) { - case Instruction::JUMP: - { - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); - - auto targetBlock = jumpTargets[currentPC]; - builder.CreateBr(targetBlock); - - currentBlock = nullptr; - break; - } - - case Instruction::JUMPI: - { - assert(pc + 1 < bytecode.cend()); - - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); - - auto cond = stack.pop(); - auto targetBlock = jumpTargets[currentPC]; - auto followBlock = basicBlocks[currentPC + 1]; - builder.CreateCondBr(cond, targetBlock, followBlock); - - currentBlock = nullptr; - break; - } - case Instruction::ADD: { auto lhs = stack.pop(); @@ -464,6 +431,37 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::JUMP: + { + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + + auto targetBlock = jumpTargets[currentPC]; + builder.CreateBr(targetBlock); + + currentBlock = nullptr; + break; + } + + case Instruction::JUMPI: + { + assert(pc + 1 < bytecode.cend()); + + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + + auto top = stack.pop(); + auto cond = builder.CreateTrunc(top, builder.getInt1Ty(), "cond"); + auto targetBlock = jumpTargets[currentPC]; + auto followBlock = basicBlocks[currentPC + 1]; + builder.CreateCondBr(cond, targetBlock, followBlock); + + currentBlock = nullptr; + break; + } + case Instruction::ADDRESS: { auto value = ext.address(); From d843ec660ad0300e6a63d8a7930dcb5abf05984f Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 12:22:47 +0200 Subject: [PATCH 036/396] fixes for JUMP/JUMPI (generating final basic block) implementation of NOT --- evmcc/Compiler.cpp | 35 +++++++++++++++++++++++++++++++---- evmcc/bytecode/if1.evm | 1 + evmcc/lll/if1.asm | 21 +++++++++++++++++++++ evmcc/lll/if1.lll | 5 +++++ 4 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 evmcc/bytecode/if1.evm create mode 100644 evmcc/lll/if1.asm create mode 100644 evmcc/lll/if1.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 1ce211e98..d5f39e053 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -60,6 +60,8 @@ llvm::BasicBlock* Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc) void Compiler::createBasicBlocks(const dev::bytes& bytecode) { + getOrCreateBasicBlockAtPC(0); + for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr) { using dev::eth::Instruction; @@ -168,7 +170,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Create the basic blocks. auto entryBlock = BasicBlock::Create(context, "entry", mainFunc); - basicBlocks[0] = entryBlock; builder.SetInsertPoint(entryBlock); createBasicBlocks(bytecode); @@ -189,11 +190,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) ProgramCounter currentPC = pc - bytecode.cbegin(); auto blockIter = basicBlocks.find(currentPC); - if (currentPC > 0 && blockIter != basicBlocks.end()) + if (blockIter != basicBlocks.end()) { auto nextBlock = blockIter->second; // Terminate the current block by jumping to the next one. - builder.CreateBr(nextBlock); + if (currentBlock != nullptr) + builder.CreateBr(nextBlock); // Insert the next block into the main function. mainFunc->getBasicBlockList().push_back(nextBlock); builder.SetInsertPoint(nextBlock); @@ -284,6 +286,16 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::NOT: + { + auto top = stack.pop(); + auto zero = ConstantInt::get(Types.word256, 0); + auto nonzero = builder.CreateICmpNE(top, zero, "nonzero"); + auto result = builder.CreateZExt(nonzero, Types.word256); + stack.push(result); + break; + } + case Instruction::POP: { stack.pop(); @@ -453,7 +465,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) stack.pop(); auto top = stack.pop(); - auto cond = builder.CreateTrunc(top, builder.getInt1Ty(), "cond"); + auto zero = ConstantInt::get(Types.word256, 0); + auto cond = builder.CreateICmpNE(top, zero, "nonzero"); auto targetBlock = jumpTargets[currentPC]; auto followBlock = basicBlocks[currentPC + 1]; builder.CreateCondBr(cond, targetBlock, followBlock); @@ -551,6 +564,20 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } } + // Generate final basic block (may be jumped to). + auto finalPC = bytecode.size(); + auto it = basicBlocks.find(finalPC); + if (it != basicBlocks.end()) + { + auto finalBlock = it->second; + + if (currentBlock != nullptr) + builder.CreateBr(finalBlock); + + mainFunc->getBasicBlockList().push_back(finalBlock); + builder.SetInsertPoint(finalBlock); + } + if (!userRet) builder.CreateRet(builder.getInt64(0)); diff --git a/evmcc/bytecode/if1.evm b/evmcc/bytecode/if1.evm new file mode 100644 index 000000000..ee9009294 --- /dev/null +++ b/evmcc/bytecode/if1.evm @@ -0,0 +1 @@ +600160805460006080530b6016596003608054601b586002608054 diff --git a/evmcc/lll/if1.asm b/evmcc/lll/if1.asm new file mode 100644 index 000000000..4a938adce --- /dev/null +++ b/evmcc/lll/if1.asm @@ -0,0 +1,21 @@ +.code: + PUSH 1 + PUSH 128 + MSTORE + PUSH 0 + PUSH 128 + MLOAD + GT + PUSH [tag0] + JUMPI + PUSH 3 + PUSH 128 + MSTORE + PUSH [tag1] + JUMP +tag0: + PUSH 2 + PUSH 128 + MSTORE +tag1: + diff --git a/evmcc/lll/if1.lll b/evmcc/lll/if1.lll new file mode 100644 index 000000000..a807b697d --- /dev/null +++ b/evmcc/lll/if1.lll @@ -0,0 +1,5 @@ +{ + [i] 1 + + ( if (> @i 0) [i] 2 [i] 3 ) +} \ No newline at end of file From 01cc09a2796e08b054d8bace30dea1d0fa1551ad Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 12:36:12 +0200 Subject: [PATCH 037/396] fixed implementation of NOT --- evmcc/Compiler.cpp | 4 ++-- evmcc/bytecode/when1.evm | 1 + evmcc/lll/when1.asm | 10 ++++++++++ evmcc/lll/when1.lll | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 evmcc/bytecode/when1.evm create mode 100644 evmcc/lll/when1.asm create mode 100644 evmcc/lll/when1.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index d5f39e053..f327f86ed 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -290,8 +290,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto top = stack.pop(); auto zero = ConstantInt::get(Types.word256, 0); - auto nonzero = builder.CreateICmpNE(top, zero, "nonzero"); - auto result = builder.CreateZExt(nonzero, Types.word256); + auto iszero = builder.CreateICmpEQ(top, zero, "iszero"); + auto result = builder.CreateZExt(iszero, Types.word256); stack.push(result); break; } diff --git a/evmcc/bytecode/when1.evm b/evmcc/bytecode/when1.evm new file mode 100644 index 000000000..303b02623 --- /dev/null +++ b/evmcc/bytecode/when1.evm @@ -0,0 +1 @@ +60010f600b59600d608054 diff --git a/evmcc/lll/when1.asm b/evmcc/lll/when1.asm new file mode 100644 index 000000000..01d41c266 --- /dev/null +++ b/evmcc/lll/when1.asm @@ -0,0 +1,10 @@ +.code: + PUSH 1 + NOT + PUSH [tag0] + JUMPI + PUSH 13 + PUSH 128 + MSTORE +tag0: + diff --git a/evmcc/lll/when1.lll b/evmcc/lll/when1.lll new file mode 100644 index 000000000..990a6e64a --- /dev/null +++ b/evmcc/lll/when1.lll @@ -0,0 +1,2 @@ +(when (> 1 0) [i] 13) + \ No newline at end of file From e5ff13180c7ed268d0b4b9b2279446d7fe129622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 2 Oct 2014 13:04:06 +0200 Subject: [PATCH 038/396] BALANCE --- evmcc/Compiler.cpp | 8 ++++++++ evmcc/Ext.cpp | 23 +++++++++++++++++++++++ evmcc/Ext.h | 5 +++++ evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 1 + 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index c55b33cc6..0a9c50fc6 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -306,6 +306,14 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = ext.balance(address); + stack.push(value); + break; + } + case Instruction::CALLER: { auto value = ext.caller(); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 0c38f73d3..a9013cbc5 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "Utils.h" @@ -15,6 +16,7 @@ using namespace llvm; using llvm::types::i; using Linkage = llvm::GlobalValue::LinkageTypes; +using dev::h256; namespace evmcc { @@ -70,6 +72,8 @@ Ext::Ext(llvm::IRBuilder<>& _builder) m_store = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); m_setStore = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); m_calldataload = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_calldataload", module); + m_balance = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_balance", module); + m_bswap = Intrinsic::getDeclaration(module, Intrinsic::bswap, i256Ty); m_builder.CreateCall(m_init, m_data); } @@ -108,6 +112,19 @@ Value* Ext::calldataload(Value* _index) return m_builder.CreateLoad(m_args[1]); } +Value* Ext::bswap(Value* _value) +{ + return m_builder.CreateCall(m_bswap, _value); +} + +Value* Ext::balance(Value* _address) +{ + auto address = bswap(_address); // to BigEndian // TODO: I don't get it. It seems not needed + m_builder.CreateStore(address, m_args[0]); + m_builder.CreateCall(m_balance, m_args); + return m_builder.CreateLoad(m_args[1]); +} + extern "C" { @@ -146,6 +163,12 @@ EXPORT void ext_calldataload(i256* _index, i256* _value) // TODO: It all can be done by adding padding to data or by using min() algorithm without branch } +EXPORT void ext_balance(h256* _address, i256* _value) +{ + auto u = g_ext->balance(dev::right160(*_address)); + *_value = eth2llvm(u); +} + } } \ No newline at end of file diff --git a/evmcc/Ext.h b/evmcc/Ext.h index a579dca81..1685ba259 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -26,11 +26,14 @@ public: llvm::Value* calldatasize(); llvm::Value* gasprice(); + llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); private: llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); + llvm::Value* bswap(llvm::Value*); + private: llvm::IRBuilder<>& m_builder; @@ -40,6 +43,8 @@ private: llvm::Function* m_store; llvm::Function* m_setStore; llvm::Function* m_calldataload; + llvm::Function* m_balance; + llvm::Function* m_bswap; }; diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index 5bcc94ba1..cdd04807f 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -30333234363a600035602635601335380060016002f2 +3031333234363a600035602635601335380060016002f2 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index f32bfb440..b0f3a4adb 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -1,6 +1,7 @@ (asm ADDRESS +BALANCE CALLER ORIGIN CALLVALUE From 8df1050fcbb2e0aa028a610cb2395e8caf5b3cf0 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 13:35:04 +0200 Subject: [PATCH 039/396] - implemented LT, GT - new tests for jumps and comparisons --- evmcc/Compiler.cpp | 20 ++++++++++++++++++++ evmcc/bytecode/for1.evm | 1 + evmcc/bytecode/for2.evm | 1 + evmcc/lll/for1.lll | 3 +++ evmcc/lll/for2.lll | 3 +++ 5 files changed, 28 insertions(+) create mode 100644 evmcc/bytecode/for1.evm create mode 100644 evmcc/bytecode/for2.evm create mode 100644 evmcc/lll/for1.lll create mode 100644 evmcc/lll/for2.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index f327f86ed..bb4d65971 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -286,6 +286,26 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpULT(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } + + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpUGT(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } + case Instruction::NOT: { auto top = stack.pop(); diff --git a/evmcc/bytecode/for1.evm b/evmcc/bytecode/for1.evm new file mode 100644 index 000000000..f8e65cbf2 --- /dev/null +++ b/evmcc/bytecode/for1.evm @@ -0,0 +1 @@ +600a60805460006080530b0f60255960a0536080530160a054600160805303608054600558 diff --git a/evmcc/bytecode/for2.evm b/evmcc/bytecode/for2.evm new file mode 100644 index 000000000..628297778 --- /dev/null +++ b/evmcc/bytecode/for2.evm @@ -0,0 +1 @@ +6000608054600a6080530a0f60255960a0536080530160a054600160805301608054600558 diff --git a/evmcc/lll/for1.lll b/evmcc/lll/for1.lll new file mode 100644 index 000000000..419fc9b54 --- /dev/null +++ b/evmcc/lll/for1.lll @@ -0,0 +1,3 @@ +(for [i]:10 (> @i 0) [i](- @i 1) + [j](+ @i @j) +) diff --git a/evmcc/lll/for2.lll b/evmcc/lll/for2.lll new file mode 100644 index 000000000..de17d65ac --- /dev/null +++ b/evmcc/lll/for2.lll @@ -0,0 +1,3 @@ +(for [i]:0 (< @i 10) [i](+ @i 1) + [j](+ @i @j) +) From 9479a70b00bf88e18047565ec54cf282400c0318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 2 Oct 2014 13:58:57 +0200 Subject: [PATCH 040/396] Block Information instructions: PREVHASH, COINBASE, TIMESTAMP, NUMBER, DIFFICULTY, GASLIMIT --- evmcc/Compiler.cpp | 44 +++++++++++++++++++++++++++++++++- evmcc/ExecutionEngine.cpp | 6 +++++ evmcc/Ext.cpp | 48 +++++++++++++++++++++++++++---------- evmcc/Ext.h | 6 +++++ evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 7 ++++++ 6 files changed, 99 insertions(+), 14 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index ccdf0b951..39483bc7f 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -183,7 +183,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) BasicBlock* currentBlock = entryBlock; - for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) + for (auto pc = bytecode.cbegin(); pc != bytecode.cend() && !finished; ++pc) { using dev::eth::Instruction; @@ -540,6 +540,48 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::PREVHASH: + { + auto value = ext.prevhash(); + stack.push(value); + break; + } + + case Instruction::COINBASE: + { + auto value = ext.coinbase(); + stack.push(value); + break; + } + + case Instruction::TIMESTAMP: + { + auto value = ext.timestamp(); + stack.push(value); + break; + } + + case Instruction::NUMBER: + { + auto value = ext.number(); + stack.push(value); + break; + } + + case Instruction::DIFFICULTY: + { + auto value = ext.difficulty(); + stack.push(value); + break; + } + + case Instruction::GASLIMIT: + { + auto value = ext.gaslimit(); + stack.push(value); + break; + } + case Instruction::RETURN: { auto index = stack.pop(); diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 4d847388e..b9a71827a 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -77,6 +77,12 @@ int ExecutionEngine::run(std::unique_ptr _module) ext->origin = dev::Address(101010101010101010); ext->value = 0xabcd; ext->gasPrice = 1002; + ext->previousBlock.hash = dev::u256(1003); + ext->currentBlock.coinbaseAddress = dev::Address(1004); + ext->currentBlock.timestamp = 1005; + ext->currentBlock.number = 1006; + ext->currentBlock.difficulty = 1007; + ext->currentBlock.gasLimit = 1008; std::string calldata = "Hello the Beautiful World of Ethereum!"; ext->data = calldata; Ext::init(std::move(ext)); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 6ae84a286..5690b8ccd 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -34,14 +34,20 @@ void Ext::init(std::unique_ptr _ext) g_ext = std::move(_ext); } -struct ExtData +struct ExtData { i256 address; i256 caller; i256 origin; i256 callvalue; - i256 gasprice; i256 calldatasize; + i256 gasprice; + i256 prevhash; + i256 coinbase; + i256 timestamp; + i256 number; + i256 difficulty; + i256 gaslimit; const byte* calldata; }; @@ -55,13 +61,19 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value"); Type* elements[] = { - i256Ty, - i256Ty, - i256Ty, - i256Ty, - i256Ty, - i256Ty, - m_builder.getInt8PtrTy() + i256Ty, // i256 address; + i256Ty, // i256 caller; + i256Ty, // i256 origin; + i256Ty, // i256 callvalue; + i256Ty, // i256 calldatasize; + i256Ty, // i256 gasprice; + i256Ty, // i256 prevhash; + i256Ty, // i256 coinbase; + i256Ty, // i256 timestamp; + i256Ty, // i256 number; + i256Ty, // i256 difficulty; + i256Ty, // i256 gaslimit; + //m_builder.getInt8PtrTy() }; auto extDataTy = StructType::create(elements, "ext.Data"); @@ -101,8 +113,14 @@ Value* Ext::address() { return getDataElem(0, "address"); } Value* Ext::caller() { return getDataElem(1, "caller"); } Value* Ext::origin() { return getDataElem(2, "origin"); } Value* Ext::callvalue() { return getDataElem(3, "callvalue"); } -Value* Ext::calldatasize() { return getDataElem(5, "calldatasize"); } -Value* Ext::gasprice() { return getDataElem(4, "gasprice"); } +Value* Ext::calldatasize() { return getDataElem(4, "calldatasize"); } +Value* Ext::gasprice() { return getDataElem(5, "gasprice"); } +Value* Ext::prevhash() { return getDataElem(6, "prevhash"); } +Value* Ext::coinbase() { return getDataElem(7, "coinbase"); } +Value* Ext::timestamp() { return getDataElem(8, "timestamp"); } +Value* Ext::number() { return getDataElem(9, "number"); } +Value* Ext::difficulty() { return getDataElem(10, "difficulty"); } +Value* Ext::gaslimit() { return getDataElem(11, "gaslimit"); } Value* Ext::calldataload(Value* _index) { @@ -135,7 +153,13 @@ EXPORT void ext_init(ExtData* _extData) _extData->callvalue = eth2llvm(g_ext->value); _extData->gasprice = eth2llvm(g_ext->gasPrice); _extData->calldatasize = eth2llvm(g_ext->data.size()); - _extData->calldata = g_ext->data.data(); + _extData->prevhash = eth2llvm(g_ext->previousBlock.hash); + _extData->coinbase = eth2llvm(fromAddress(g_ext->currentBlock.coinbaseAddress)); + _extData->timestamp = eth2llvm(g_ext->currentBlock.timestamp); + _extData->number = eth2llvm(g_ext->currentBlock.number); + _extData->difficulty = eth2llvm(g_ext->currentBlock.difficulty); + _extData->gaslimit = eth2llvm(g_ext->currentBlock.gasLimit); + //_extData->calldata = g_ext->data.data(); } EXPORT void ext_store(i256* _index, i256* _value) diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 138028927..c44e5899b 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -25,6 +25,12 @@ public: llvm::Value* callvalue(); llvm::Value* calldatasize(); llvm::Value* gasprice(); + llvm::Value* prevhash(); + llvm::Value* coinbase(); + llvm::Value* timestamp(); + llvm::Value* number(); + llvm::Value* difficulty(); + llvm::Value* gaslimit(); llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index cdd04807f..c4a833296 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -3031333234363a600035602635601335380060016002f2 +3031333234363a40414243444536600035602635601335380060016002f2 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index b0f3a4adb..85c0b236e 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -7,6 +7,13 @@ ORIGIN CALLVALUE CALLDATASIZE GASPRICE +PREVHASH +COINBASE +TIMESTAMP +NUMBER +DIFFICULTY +GASLIMIT +CALLDATASIZE 0 CALLDATALOAD 38 From 397763be63e41d9593f1cbf5993309d75b6a3fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 2 Oct 2014 14:18:50 +0200 Subject: [PATCH 041/396] PC instructions --- evmcc/Compiler.cpp | 7 +++++++ evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index e66aad25d..06dbbec72 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -495,6 +495,13 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::PC: + { + auto value = builder.getIntN(256, currentPC); + stack.push(value); + break; + } + case Instruction::ADDRESS: { auto value = ext.address(); diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index c4a833296..d1e373df0 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -3031333234363a40414243444536600035602635601335380060016002f2 +5a3031333234363a4041424344455a36600035602635601335380060016002f2 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index 85c0b236e..1a1dde653 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -1,5 +1,6 @@ (asm +PC ADDRESS BALANCE CALLER @@ -13,6 +14,7 @@ TIMESTAMP NUMBER DIFFICULTY GASLIMIT +PC CALLDATASIZE 0 CALLDATALOAD From 7c46d7946c749f73ee27e52f9aebf5276a42dffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 2 Oct 2014 15:03:59 +0200 Subject: [PATCH 042/396] Bitwise operators: AND, OR, XOR --- evmcc/Compiler.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 06dbbec72..2f15d087d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -315,6 +315,33 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) stack.push(result); break; } + + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } case Instruction::POP: { From b92c8a6c102120f9f64a1380c755b078bb1480fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 2 Oct 2014 15:44:00 +0200 Subject: [PATCH 043/396] TODO: implement BYTE --- evmcc/Compiler.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 2f15d087d..5b3da6a5c 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -343,6 +343,29 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::BYTE: + { + auto byteNum = stack.pop(); + + // TODO + //auto value = stack.pop(); + + /* + if (byteNum < 32) - use select + { + value <<= byteNum*8; + value >>= (31-byteNum)*8; + push value + } + else + { + push 0 + } + */ + + break; + } + case Instruction::POP: { stack.pop(); From b39692ba72061cb1db546a74a4a1830e67ef23b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 2 Oct 2014 17:30:39 +0200 Subject: [PATCH 044/396] BYTE instruction implementation (with bug on BYTE 0) --- evmcc/Compiler.cpp | 27 ++++++----- evmcc/bytecode/byte.evm | 1 + evmcc/lll/byte.lll | 105 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 evmcc/bytecode/byte.evm create mode 100644 evmcc/lll/byte.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 5b3da6a5c..4b22c0241 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -345,24 +345,29 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::BYTE: { - auto byteNum = stack.pop(); - - // TODO - //auto value = stack.pop(); + const auto byteNum = stack.pop(); + auto value = stack.pop(); /* if (byteNum < 32) - use select { - value <<= byteNum*8; - value >>= (31-byteNum)*8; - push value - } - else - { - push 0 + value <<= byteNum*8 + value >>= 31*8 + push value } + else push 0 */ + // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 + + auto shbits = builder.CreateShl(byteNum, builder.getIntN(256, 3)); + value = builder.CreateShl(value, shbits); + value = builder.CreateLShr(value, builder.getIntN(256, 31 * 8)); + + auto byteNumValid = builder.CreateICmpULT(byteNum, builder.getIntN(256, 32)); + value = builder.CreateSelect(byteNumValid, value, builder.getIntN(256, 0)); + stack.push(value); + break; } diff --git a/evmcc/bytecode/byte.evm b/evmcc/bytecode/byte.evm new file mode 100644 index 000000000..ab63431ee --- /dev/null +++ b/evmcc/bytecode/byte.evm @@ -0,0 +1 @@ +7f112233445566778899001122334455667788990011223344556677889900aabb6000137f112233445566778899001122334455667788990011223344556677889900aabb6001137f112233445566778899001122334455667788990011223344556677889900aabb6002137f112233445566778899001122334455667788990011223344556677889900aabb6003137f112233445566778899001122334455667788990011223344556677889900aabb6004137f112233445566778899001122334455667788990011223344556677889900aabb6005137f112233445566778899001122334455667788990011223344556677889900aabb6006137f112233445566778899001122334455667788990011223344556677889900aabb6007137f112233445566778899001122334455667788990011223344556677889900aabb6008137f112233445566778899001122334455667788990011223344556677889900aabb6009137f112233445566778899001122334455667788990011223344556677889900aabb600a137f112233445566778899001122334455667788990011223344556677889900aabb600b137f112233445566778899001122334455667788990011223344556677889900aabb600c137f112233445566778899001122334455667788990011223344556677889900aabb600d137f112233445566778899001122334455667788990011223344556677889900aabb600e137f112233445566778899001122334455667788990011223344556677889900aabb600f137f112233445566778899001122334455667788990011223344556677889900aabb6010137f112233445566778899001122334455667788990011223344556677889900aabb6011137f112233445566778899001122334455667788990011223344556677889900aabb6012137f112233445566778899001122334455667788990011223344556677889900aabb6013137f112233445566778899001122334455667788990011223344556677889900aabb6014137f112233445566778899001122334455667788990011223344556677889900aabb6015137f112233445566778899001122334455667788990011223344556677889900aabb6016137f112233445566778899001122334455667788990011223344556677889900aabb6017137f112233445566778899001122334455667788990011223344556677889900aabb6018137f112233445566778899001122334455667788990011223344556677889900aabb6019137f112233445566778899001122334455667788990011223344556677889900aabb601a137f112233445566778899001122334455667788990011223344556677889900aabb601b137f112233445566778899001122334455667788990011223344556677889900aabb601c137f112233445566778899001122334455667788990011223344556677889900aabb601d137f112233445566778899001122334455667788990011223344556677889900aabb601e137f112233445566778899001122334455667788990011223344556677889900aabb601f137f112233445566778899001122334455667788990011223344556677889900aabb6020137f112233445566778899001122334455667788990011223344556677889900aabb6107de13 diff --git a/evmcc/lll/byte.lll b/evmcc/lll/byte.lll new file mode 100644 index 000000000..95b0f99dc --- /dev/null +++ b/evmcc/lll/byte.lll @@ -0,0 +1,105 @@ + +(asm +0x112233445566778899001122334455667788990011223344556677889900aabb +0 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +1 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +2 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +3 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +4 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +5 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +6 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +7 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +8 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +9 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +10 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +11 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +12 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +13 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +14 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +15 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +16 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +17 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +18 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +19 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +20 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +21 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +22 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +23 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +24 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +25 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +26 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +27 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +28 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +29 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +30 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +31 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +32 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +2014 +BYTE +) \ No newline at end of file From 24a99ef798cc9b4e14f1a5342359a435f5b589d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 3 Oct 2014 11:04:39 +0200 Subject: [PATCH 045/396] Runtime class that inits and keeps stack, memory and ExtVM interface --- evmcc/Compiler.cpp | 6 ++--- evmcc/ExecutionEngine.cpp | 12 +++++----- evmcc/Ext.cpp | 44 +++++++++++++++-------------------- evmcc/Memory.cpp | 31 +++++++----------------- evmcc/Memory.h | 2 -- evmcc/Runtime.cpp | 36 ++++++++++++++++++++++++++++ evmcc/Runtime.h | 35 ++++++++++++++++++++++++++++ evmcc/Stack.cpp | 14 +++++------ windows/evmcc.vcxproj | 2 ++ windows/evmcc.vcxproj.filters | 2 ++ 10 files changed, 118 insertions(+), 66 deletions(-) create mode 100644 evmcc/Runtime.cpp create mode 100644 evmcc/Runtime.h diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 4b22c0241..4b50b2302 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -351,9 +351,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) /* if (byteNum < 32) - use select { - value <<= byteNum*8 - value >>= 31*8 - push value + value <<= byteNum*8 + value >>= 31*8 + push value } else push 0 */ diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index b9a71827a..6983b9cda 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -13,8 +13,7 @@ #include #include -#include "Ext.h" -#include "Memory.h" +#include "Runtime.h" namespace evmcc { @@ -69,8 +68,7 @@ int ExecutionEngine::run(std::unique_ptr _module) _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module exec->finalizeObject(); - auto&& memory = Memory::init(); - + // Create fake ExtVM interface auto ext = std::make_unique(); ext->myAddress = dev::Address(1122334455667788); ext->caller = dev::Address(0xfacefacefaceface); @@ -85,7 +83,9 @@ int ExecutionEngine::run(std::unique_ptr _module) ext->currentBlock.gasLimit = 1008; std::string calldata = "Hello the Beautiful World of Ethereum!"; ext->data = calldata; - Ext::init(std::move(ext)); + + // Init runtime + Runtime runtime(std::move(ext)); auto entryFunc = module->getFunction("main"); if (!entryFunc) @@ -101,7 +101,7 @@ int ExecutionEngine::run(std::unique_ptr _module) auto size = 0xFFFFFFFF & intResult; std::cout << "RETURN [ "; - for (dev::bytes::const_iterator it = memory.cbegin() + index, end = it + size; it != end; ++it) + for (dev::bytes::const_iterator it = Runtime::getMemory().cbegin() + index, end = it + size; it != end; ++it) std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; std::cout << "]"; diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 5690b8ccd..0ec9c532a 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -5,7 +5,7 @@ #include #include -#include "Utils.h" +#include "Runtime.h" #ifdef _MSC_VER #define EXPORT __declspec(dllexport) @@ -27,13 +27,6 @@ inline dev::u256 fromAddress(dev::Address _a) return (dev::u160)_a; } -std::unique_ptr g_ext; - -void Ext::init(std::unique_ptr _ext) -{ - g_ext = std::move(_ext); -} - struct ExtData { i256 address; @@ -147,25 +140,26 @@ extern "C" EXPORT void ext_init(ExtData* _extData) { - _extData->address = eth2llvm(fromAddress(g_ext->myAddress)); - _extData->caller = eth2llvm(fromAddress(g_ext->caller)); - _extData->origin = eth2llvm(fromAddress(g_ext->origin)); - _extData->callvalue = eth2llvm(g_ext->value); - _extData->gasprice = eth2llvm(g_ext->gasPrice); - _extData->calldatasize = eth2llvm(g_ext->data.size()); - _extData->prevhash = eth2llvm(g_ext->previousBlock.hash); - _extData->coinbase = eth2llvm(fromAddress(g_ext->currentBlock.coinbaseAddress)); - _extData->timestamp = eth2llvm(g_ext->currentBlock.timestamp); - _extData->number = eth2llvm(g_ext->currentBlock.number); - _extData->difficulty = eth2llvm(g_ext->currentBlock.difficulty); - _extData->gaslimit = eth2llvm(g_ext->currentBlock.gasLimit); - //_extData->calldata = g_ext->data.data(); + auto&& ext = Runtime::getExt(); + _extData->address = eth2llvm(fromAddress(ext.myAddress)); + _extData->caller = eth2llvm(fromAddress(ext.caller)); + _extData->origin = eth2llvm(fromAddress(ext.origin)); + _extData->callvalue = eth2llvm(ext.value); + _extData->gasprice = eth2llvm(ext.gasPrice); + _extData->calldatasize = eth2llvm(ext.data.size()); + _extData->prevhash = eth2llvm(ext.previousBlock.hash); + _extData->coinbase = eth2llvm(fromAddress(ext.currentBlock.coinbaseAddress)); + _extData->timestamp = eth2llvm(ext.currentBlock.timestamp); + _extData->number = eth2llvm(ext.currentBlock.number); + _extData->difficulty = eth2llvm(ext.currentBlock.difficulty); + _extData->gaslimit = eth2llvm(ext.currentBlock.gasLimit); + //_extData->calldata = ext.data.data(); } EXPORT void ext_store(i256* _index, i256* _value) { auto index = llvm2eth(*_index); - auto value = g_ext->store(index); + auto value = Runtime::getExt().store(index); *_value = eth2llvm(value); } @@ -173,7 +167,7 @@ EXPORT void ext_setStore(i256* _index, i256* _value) { auto index = llvm2eth(*_index); auto value = llvm2eth(*_value); - g_ext->setStore(index, value); + Runtime::getExt().setStore(index, value); } EXPORT void ext_calldataload(i256* _index, i256* _value) @@ -182,13 +176,13 @@ EXPORT void ext_calldataload(i256* _index, i256* _value) assert(index + 31 > index); // TODO: Handle large index auto b = reinterpret_cast(_value); for (size_t i = index, j = 31; i <= index + 31; ++i, --j) - b[j] = i < g_ext->data.size() ? g_ext->data[i] : 0; + b[j] = i < Runtime::getExt().data.size() ? Runtime::getExt().data[i] : 0; // TODO: It all can be done by adding padding to data or by using min() algorithm without branch } EXPORT void ext_balance(h256* _address, i256* _value) { - auto u = g_ext->balance(dev::right160(*_address)); + auto u = Runtime::getExt().balance(dev::right160(*_address)); *_value = eth2llvm(u); } diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index fd7727b59..e3bbd5d40 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -10,7 +10,7 @@ #include -#include "Utils.h" +#include "Runtime.h" #ifdef _MSC_VER #define EXPORT __declspec(dllexport) @@ -21,11 +21,6 @@ namespace evmcc { -using MemoryImpl = dev::bytes; - -static MemoryImpl* evmccrt_memory; - - Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* module) : m_builder(_builder) { @@ -48,15 +43,6 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* module) "evmccrt_memory_dump", module); } -const dev::bytes& Memory::init() -{ - evmccrt_memory = new MemoryImpl(); - std::cerr << "MEMORY: create(), initial size = " << evmccrt_memory->size() - << std::endl; - - return *evmccrt_memory; -} - llvm::Value* Memory::loadWord(llvm::Value* _addr) { @@ -132,29 +118,30 @@ extern "C" EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) { uint64_t requiredSize = (_index / 32 + 1) * 32; + auto&& memory = Runtime::getMemory(); - if (evmccrt_memory->size() < requiredSize) + if (memory.size() < requiredSize) { std::cerr << "MEMORY: current size: " << std::dec - << evmccrt_memory->size() << " bytes, required size: " + << memory.size() << " bytes, required size: " << requiredSize << " bytes" << std::endl; - evmccrt_memory->resize(requiredSize); + memory.resize(requiredSize); } - return evmccrt_memory->data(); + return memory.data(); } EXPORT uint64_t evmccrt_memory_size() { - return evmccrt_memory->size() / 32; + return Runtime::getMemory().size() / 32; } EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) { if (_end == 0) - _end = evmccrt_memory->size(); + _end = Runtime::getMemory().size(); std::cerr << "MEMORY: active size: " << std::dec << evmccrt_memory_size() << " words\n"; @@ -169,7 +156,7 @@ EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) if ((i - _begin) % 16 == 0) std::cerr << '\n' << std::dec << i << ": "; - uint8_t b = (*evmccrt_memory)[i]; + auto b = Runtime::getMemory()[i]; std::cerr << std::hex << std::setw(2) << static_cast(b) << ' '; } std::cerr << std::endl; diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 87ce27ed0..da6662fef 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -12,8 +12,6 @@ class Memory public: Memory(llvm::IRBuilder<>& _builder, llvm::Module* module); - static const dev::bytes& init(); - llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); void storeByte(llvm::Value* _addr, llvm::Value* _byte); diff --git a/evmcc/Runtime.cpp b/evmcc/Runtime.cpp new file mode 100644 index 000000000..9d0738f05 --- /dev/null +++ b/evmcc/Runtime.cpp @@ -0,0 +1,36 @@ + +#include "Runtime.h" + +namespace evmcc +{ + +static Runtime* g_runtime; + +Runtime::Runtime(std::unique_ptr _ext) + : m_ext(std::move(_ext)) +{ + assert(!g_runtime); + g_runtime = this; +} + +Runtime::~Runtime() +{ + g_runtime = nullptr; +} + +StackImpl& Runtime::getStack() +{ + return g_runtime->m_stack; +} + +MemoryImpl& Runtime::getMemory() +{ + return g_runtime->m_memory; +} + +dev::eth::ExtVMFace& Runtime::getExt() +{ + return *g_runtime->m_ext; +} + +} \ No newline at end of file diff --git a/evmcc/Runtime.h b/evmcc/Runtime.h new file mode 100644 index 000000000..71c917b9d --- /dev/null +++ b/evmcc/Runtime.h @@ -0,0 +1,35 @@ + +#pragma once + +#include + +#include + +#include "Utils.h" + +namespace evmcc +{ + +using StackImpl = std::vector; +using MemoryImpl = dev::bytes; + +class Runtime +{ +public: + Runtime(std::unique_ptr _ext); + ~Runtime(); + + Runtime(const Runtime&) = delete; + void operator=(const Runtime&) = delete; + + static StackImpl& getStack(); + static MemoryImpl& getMemory(); + static dev::eth::ExtVMFace& getExt(); + +private: + StackImpl m_stack; + MemoryImpl m_memory; + std::unique_ptr m_ext; +}; + +} \ No newline at end of file diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index 2e9bb495c..540c4bedc 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -9,7 +9,7 @@ #include -#include "Utils.h" +#include "Runtime.h" #ifdef _MSC_VER #define EXPORT __declspec(dllexport) @@ -20,9 +20,6 @@ namespace evmcc { -using StackImpl = std::vector; - - Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) : m_builder(_builder) { @@ -115,7 +112,8 @@ extern "C" EXPORT void* evmccrt_stack_create() { - auto stack = new StackImpl; + // TODO: Simplify stack pointer passing + auto stack = &Runtime::getStack(); std::cerr << "STACK create\n"; return stack; } @@ -130,7 +128,7 @@ EXPORT void evmccrt_stack_pop(StackImpl* _stack, i256* _outWord) { assert(!_stack->empty()); auto word = &_stack->back(); - debugStack("pop", *word); + //debugStack("pop", *word); _stack->pop_back(); *_outWord = *word; } @@ -139,7 +137,7 @@ EXPORT void evmccrt_stack_get(StackImpl* _stack, uint32_t _index, i256* _outWord { assert(_index < _stack->size()); auto word = _stack->rbegin() + _index; - debugStack("get", *word, _index); + //debugStack("get", *word, _index); *_outWord = *word; } @@ -147,7 +145,7 @@ EXPORT void evmccrt_stack_set(StackImpl* _stack, uint32_t _index, i256* _word) { assert(_index < _stack->size()); *(_stack->rbegin() + _index) = *_word; - debugStack("set", *_word, _index); + //debugStack("set", *_word, _index); } } // extern "C" diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 7959c5a1b..c3add28cd 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -24,6 +24,7 @@ + @@ -32,6 +33,7 @@ + diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 99c43b89b..de7fd20bf 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -8,6 +8,7 @@ + @@ -16,5 +17,6 @@ + \ No newline at end of file From 09341eaf84e1abe8a1dcebca6fababca335d8007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 3 Oct 2014 11:21:07 +0200 Subject: [PATCH 046/396] Stack functions simplified --- evmcc/Stack.cpp | 61 +++++++++++++++++++------------------------------ evmcc/Stack.h | 2 +- 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index 540c4bedc..ef99d603b 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -29,18 +29,14 @@ Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) auto i256PtrTy = i256Ty->getPointerTo(); auto voidTy = m_builder.getVoidTy(); - auto stackCreate = llvm::Function::Create(llvm::FunctionType::get(stackPtrTy, false), - llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_create", _module); - - llvm::Type* argsTypes[] = {stackPtrTy, i256PtrTy}; - auto funcType = llvm::FunctionType::get(voidTy, argsTypes, false); + auto funcType = llvm::FunctionType::get(voidTy, i256PtrTy, false); m_stackPush = llvm::Function::Create(funcType, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_push", _module); m_stackPop = llvm::Function::Create(funcType, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_pop", _module); - llvm::Type* getArgsTypes[] = {stackPtrTy, m_builder.getInt32Ty(), i256PtrTy}; + llvm::Type* getArgsTypes[] = {m_builder.getInt32Ty(), i256PtrTy}; auto getFuncType = llvm::FunctionType::get(voidTy, getArgsTypes, false); m_stackGet = llvm::Function::Create(getFuncType, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_get", _module); @@ -48,37 +44,36 @@ Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) m_stackSet = llvm::Function::Create(getFuncType, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_set", _module); - m_args[0] = m_builder.CreateCall(stackCreate, "stack.ptr"); - m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "stack.val"); + m_stackVal = m_builder.CreateAlloca(i256Ty, nullptr, "stack.val"); } void Stack::push(llvm::Value* _value) { - m_builder.CreateStore(_value, m_args[1]); // copy value to memory - m_builder.CreateCall(m_stackPush, m_args); + m_builder.CreateStore(_value, m_stackVal); // copy value to memory + m_builder.CreateCall(m_stackPush, m_stackVal); } llvm::Value* Stack::pop() { - m_builder.CreateCall(m_stackPop, m_args); - return m_builder.CreateLoad(m_args[1]); + m_builder.CreateCall(m_stackPop, m_stackVal); + return m_builder.CreateLoad(m_stackVal); } llvm::Value* Stack::get(uint32_t _index) { - llvm::Value* args[] = {m_args[0], m_builder.getInt32(_index), m_args[1]}; + llvm::Value* args[] = {m_builder.getInt32(_index), m_stackVal}; m_builder.CreateCall(m_stackGet, args); - return m_builder.CreateLoad(m_args[1]); + return m_builder.CreateLoad(m_stackVal); } void Stack::set(uint32_t _index, llvm::Value* _value) { - m_builder.CreateStore(_value, m_args[1]); // copy value to memory - llvm::Value* args[] = {m_args[0], m_builder.getInt32(_index), m_args[1]}; + m_builder.CreateStore(_value, m_stackVal); // copy value to memory + llvm::Value* args[] = {m_builder.getInt32(_index), m_stackVal}; m_builder.CreateCall(m_stackSet, args); } @@ -110,41 +105,33 @@ extern "C" { using namespace evmcc; -EXPORT void* evmccrt_stack_create() -{ - // TODO: Simplify stack pointer passing - auto stack = &Runtime::getStack(); - std::cerr << "STACK create\n"; - return stack; -} - -EXPORT void evmccrt_stack_push(StackImpl* _stack, i256* _word) +EXPORT void evmccrt_stack_push(i256* _word) { - debugStack("push", *_word); - _stack->push_back(*_word); + //debugStack("push", *_word); + Runtime::getStack().push_back(*_word); } -EXPORT void evmccrt_stack_pop(StackImpl* _stack, i256* _outWord) +EXPORT void evmccrt_stack_pop(i256* _outWord) { - assert(!_stack->empty()); - auto word = &_stack->back(); + assert(!Runtime::getStack().empty()); + auto word = &Runtime::getStack().back(); //debugStack("pop", *word); - _stack->pop_back(); + Runtime::getStack().pop_back(); *_outWord = *word; } -EXPORT void evmccrt_stack_get(StackImpl* _stack, uint32_t _index, i256* _outWord) +EXPORT void evmccrt_stack_get(uint32_t _index, i256* _outWord) { - assert(_index < _stack->size()); - auto word = _stack->rbegin() + _index; + assert(_index < Runtime::getStack().size()); + auto word = Runtime::getStack().rbegin() + _index; //debugStack("get", *word, _index); *_outWord = *word; } -EXPORT void evmccrt_stack_set(StackImpl* _stack, uint32_t _index, i256* _word) +EXPORT void evmccrt_stack_set(uint32_t _index, i256* _word) { - assert(_index < _stack->size()); - *(_stack->rbegin() + _index) = *_word; + assert(_index < Runtime::getStack().size()); + *(Runtime::getStack().rbegin() + _index) = *_word; //debugStack("set", *_word, _index); } diff --git a/evmcc/Stack.h b/evmcc/Stack.h index a25de56e6..53e935a8a 100644 --- a/evmcc/Stack.h +++ b/evmcc/Stack.h @@ -19,7 +19,7 @@ public: private: llvm::IRBuilder<>& m_builder; - llvm::Value* m_args[2]; + llvm::Value* m_stackVal; llvm::Function* m_stackPush; llvm::Function* m_stackPop; llvm::Function* m_stackGet; From f34340d4c1c89ad92d8bbf88881f3b73aa0ab564 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 3 Oct 2014 11:30:15 +0200 Subject: [PATCH 047/396] - fixes for RETURN and STOP - codegen for SLT, SGT, EQ and NEG --- evmcc/Compiler.cpp | 83 +++++++++++++++++++++++++++++--------- evmcc/bytecode/return1.evm | 1 + evmcc/lll/return1.lll | 6 +++ 3 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 evmcc/bytecode/return1.evm create mode 100644 evmcc/lll/return1.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 4b22c0241..796db093e 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -61,6 +61,7 @@ llvm::BasicBlock* Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc) void Compiler::createBasicBlocks(const dev::bytes& bytecode) { getOrCreateBasicBlockAtPC(0); + getOrCreateBasicBlockAtPC(bytecode.size()); for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr) { @@ -147,6 +148,18 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) std::exit(1); } + case Instruction::RETURN: + case Instruction::STOP: + { + // Create a basic block starting at the following instruction. + if (curr + 1 < bytecode.cend()) + { + ProgramCounter nextPC = (curr + 1 - bytecode.cbegin()); + getOrCreateBasicBlockAtPC(nextPC); + } + break; + } + default: break; } @@ -178,12 +191,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto memory = Memory(builder, module.get()); auto ext = Ext(builder, module.get()); - auto userRet = false; - auto finished = false; - BasicBlock* currentBlock = entryBlock; - for (auto pc = bytecode.cbegin(); pc != bytecode.cend() && !finished; ++pc) + for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) { using dev::eth::Instruction; @@ -286,6 +296,15 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::NEG: + { + auto top = stack.pop(); + auto zero = ConstantInt::get(Types.word256, 0); + auto res = builder.CreateSub(zero, top); + stack.push(res); + break; + } + case Instruction::LT: { auto lhs = stack.pop(); @@ -306,6 +325,36 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpSLT(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } + + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpSGT(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } + + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpEQ(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } + case Instruction::NOT: { auto top = stack.pop(); @@ -682,36 +731,32 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) ret = builder.CreateOr(ret, size); builder.CreateRet(ret); - finished = true; - userRet = true; + currentBlock = nullptr; break; } case Instruction::STOP: { - finished = true; + builder.CreateRet(builder.getInt64(0)); + currentBlock = nullptr; break; } } } - // Generate final basic block (may be jumped to). + // Generate the final basic block. auto finalPC = bytecode.size(); auto it = basicBlocks.find(finalPC); - if (it != basicBlocks.end()) - { - auto finalBlock = it->second; + assert(it != basicBlocks.end()); + auto finalBlock = it->second; - if (currentBlock != nullptr) - builder.CreateBr(finalBlock); - - mainFunc->getBasicBlockList().push_back(finalBlock); - builder.SetInsertPoint(finalBlock); - } + if (currentBlock != nullptr) + builder.CreateBr(finalBlock); - if (!userRet) - builder.CreateRet(builder.getInt64(0)); + mainFunc->getBasicBlockList().push_back(finalBlock); + builder.SetInsertPoint(finalBlock); + builder.CreateRet(builder.getInt64(0)); return module; } diff --git a/evmcc/bytecode/return1.evm b/evmcc/bytecode/return1.evm new file mode 100644 index 000000000..8092cb007 --- /dev/null +++ b/evmcc/bytecode/return1.evm @@ -0,0 +1 @@ +600160805460006080530b601b59600160005460206000f2602a58602760005460206000f26002608054 diff --git a/evmcc/lll/return1.lll b/evmcc/lll/return1.lll new file mode 100644 index 000000000..159d15ca3 --- /dev/null +++ b/evmcc/lll/return1.lll @@ -0,0 +1,6 @@ +;; code should return 39 +;; i should remain 1 +{ + [i] 1 + ( if (> @i 0) { (return 39) [i] 2 } (return 1) ) +} \ No newline at end of file From cdebe9f9f72445a221a5e36d747c159ce39e5b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 3 Oct 2014 13:19:35 +0200 Subject: [PATCH 048/396] CREATE instruction. Still needs some work with ExtVM interface. [#79510898] --- evmcc/Compiler.cpp | 11 +++++++++++ evmcc/Ext.cpp | 39 ++++++++++++++++++++++++++++++++++++- evmcc/Ext.h | 4 ++++ evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 7 +++++++ 5 files changed, 61 insertions(+), 2 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 0c0076a80..acb7be26d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -712,6 +712,17 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) stack.push(value); break; } + + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); + + auto address = ext.create(endowment, initOff, initSize); + stack.push(address); + break; + } case Instruction::RETURN: { diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 0ec9c532a..4ef0dc3f8 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -17,6 +17,7 @@ using namespace llvm; using llvm::types::i; using Linkage = llvm::GlobalValue::LinkageTypes; using dev::h256; +using dev::u256; namespace evmcc { @@ -52,6 +53,8 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) auto i256Ty = m_builder.getIntNTy(256); m_args[0] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.index"); m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value"); + m_arg2 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg2"); + m_arg3 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg3"); Type* elements[] = { i256Ty, // i256 address; @@ -77,8 +80,10 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_setStore = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); m_calldataload = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_calldataload", module); m_balance = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_balance", module); + m_create = Function::Create(TypeBuilder*, i<256>*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_create", module); m_bswap = Intrinsic::getDeclaration(module, Intrinsic::bswap, i256Ty); + m_builder.CreateCall(m_init, m_data); } @@ -129,12 +134,24 @@ Value* Ext::bswap(Value* _value) Value* Ext::balance(Value* _address) { - auto address = bswap(_address); // to BigEndian // TODO: I don't get it. It seems not needed + auto address = bswap(_address); // to BE m_builder.CreateStore(address, m_args[0]); m_builder.CreateCall(m_balance, m_args); return m_builder.CreateLoad(m_args[1]); } +Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +{ + m_builder.CreateStore(_endowment, m_args[0]); + m_builder.CreateStore(_initOff, m_arg2); + m_builder.CreateStore(_initSize, m_arg3); + Value* args[] = {m_args[0], m_arg2, m_arg3, m_args[1]}; + m_builder.CreateCall(m_create, args); + Value* address = m_builder.CreateLoad(m_args[1]); + address = bswap(address); // to LE + return address; +} + extern "C" { @@ -186,6 +203,26 @@ EXPORT void ext_balance(h256* _address, i256* _value) *_value = eth2llvm(u); } +EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) +{ + auto&& ext = Runtime::getExt(); + auto endowment = llvm2eth(*_endowment); + auto initOff = static_cast(llvm2eth(*_initOff)); + auto initSize = static_cast(llvm2eth(*_initSize)); + + if (ext.balance(ext.myAddress) >= endowment) + { + ext.subBalance(endowment); + u256 gas; // TODO: Handle gas + auto&& initRef = dev::bytesConstRef(Runtime::getMemory().data() + initOff, initSize); + auto&& onOp = dev::bytesConstRef(); // TODO: Handle that thing + h256 address = ext.create(endowment, &gas, initRef, onOp); + *_address = address; + } + else + *_address = {}; +} + } } diff --git a/evmcc/Ext.h b/evmcc/Ext.h index c44e5899b..aa6016253 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -34,6 +34,7 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); + llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); private: llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); @@ -44,12 +45,15 @@ private: llvm::IRBuilder<>& m_builder; llvm::Value* m_args[2]; + llvm::Value* m_arg2; + llvm::Value* m_arg3; llvm::Value* m_data; llvm::Function* m_init; llvm::Function* m_store; llvm::Function* m_setStore; llvm::Function* m_calldataload; llvm::Function* m_balance; + llvm::Function* m_create; llvm::Function* m_bswap; }; diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index d1e373df0..97ef267d6 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -5a3031333234363a4041424344455a36600035602635601335380060016002f2 +5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f00060016002f2 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index 1a1dde653..60a8bc332 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -23,6 +23,13 @@ CALLDATALOAD 19 CALLDATALOAD CODESIZE +0x1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff +0 +MSTORE +32 +0 +0 +CREATE STOP 1 2 From a33863d931cd999b759f99b92719bec674ec13c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 3 Oct 2014 15:19:47 +0200 Subject: [PATCH 049/396] CALL instruction. Still needs gas counting and callback support. [Delivers #79510898] --- evmcc/Compiler.cpp | 15 +++++++++++ evmcc/Ext.cpp | 53 +++++++++++++++++++++++++++++++++++-- evmcc/Ext.h | 6 +++++ evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 8 ++++++ 5 files changed, 81 insertions(+), 3 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index acb7be26d..5227fa5cb 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -724,6 +724,21 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::CALL: + { + auto gas = stack.pop(); + auto receiveAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize); + stack.push(ret); + break; + } + case Instruction::RETURN: { auto index = stack.pop(); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 4ef0dc3f8..e82a91ae9 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -51,10 +51,15 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) auto&& ctx = _builder.getContext(); auto i256Ty = m_builder.getIntNTy(256); + auto i256PtrTy = i256Ty->getPointerTo(); m_args[0] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.index"); m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value"); m_arg2 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg2"); m_arg3 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg3"); + m_arg4 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg4"); + m_arg5 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg5"); + m_arg6 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg6"); + m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg7"); Type* elements[] = { i256Ty, // i256 address; @@ -81,6 +86,8 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_calldataload = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_calldataload", module); m_balance = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_balance", module); m_create = Function::Create(TypeBuilder*, i<256>*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_create", module); + Type* args[] = {i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy}; + m_call = Function::Create(FunctionType::get(m_builder.getVoidTy(), args, false), Linkage::ExternalLinkage, "ext_call", module); m_bswap = Intrinsic::getDeclaration(module, Intrinsic::bswap, i256Ty); @@ -152,6 +159,21 @@ Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* return address; } +llvm::Value* Ext::call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize) +{ + m_builder.CreateStore(_gas, m_args[0]); + auto receiveAddress = bswap(_receiveAddress); // to BE + m_builder.CreateStore(receiveAddress, m_arg2); + m_builder.CreateStore(_value, m_arg3); + m_builder.CreateStore(_inOff, m_arg4); + m_builder.CreateStore(_inSize, m_arg5); + m_builder.CreateStore(_outOff, m_arg6); + m_builder.CreateStore(_outSize, m_arg7); + llvm::Value* args[] = {m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_args[1]}; + m_builder.CreateCall(m_call, args); + return m_builder.CreateLoad(m_args[1]); +} + extern "C" { @@ -207,13 +229,13 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* { auto&& ext = Runtime::getExt(); auto endowment = llvm2eth(*_endowment); - auto initOff = static_cast(llvm2eth(*_initOff)); - auto initSize = static_cast(llvm2eth(*_initSize)); if (ext.balance(ext.myAddress) >= endowment) { ext.subBalance(endowment); u256 gas; // TODO: Handle gas + auto initOff = static_cast(llvm2eth(*_initOff)); + auto initSize = static_cast(llvm2eth(*_initSize)); auto&& initRef = dev::bytesConstRef(Runtime::getMemory().data() + initOff, initSize); auto&& onOp = dev::bytesConstRef(); // TODO: Handle that thing h256 address = ext.create(endowment, &gas, initRef, onOp); @@ -223,6 +245,33 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* *_address = {}; } + + +EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, i256* _ret) +{ + auto&& ext = Runtime::getExt(); + auto value = llvm2eth(*_value); + + auto ret = false; + if (ext.balance(ext.myAddress) >= value) + { + ext.subBalance(value); + auto gas = llvm2eth(*_gas); + auto receiveAddress = dev::right160(*_receiveAddress); + auto inOff = static_cast(llvm2eth(*_inOff)); + auto inSize = static_cast(llvm2eth(*_inSize)); + auto outOff = static_cast(llvm2eth(*_outOff)); + auto outSize = static_cast(llvm2eth(*_outSize)); + auto&& inRef = dev::bytesConstRef(Runtime::getMemory().data() + inOff, inSize); + auto&& outRef = dev::bytesConstRef(Runtime::getMemory().data() + outOff, outSize); + dev::eth::OnOpFunc onOp{}; // TODO: Handle that thing + auto ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, receiveAddress); + } + + // m_gas += gas; // TODO: Handle gas + _ret->a = ret ? 1 : 0; +} + } } diff --git a/evmcc/Ext.h b/evmcc/Ext.h index aa6016253..88fad15a1 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -35,6 +35,7 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize); private: llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); @@ -47,6 +48,10 @@ private: llvm::Value* m_args[2]; llvm::Value* m_arg2; llvm::Value* m_arg3; + llvm::Value* m_arg4; + llvm::Value* m_arg5; + llvm::Value* m_arg6; + llvm::Value* m_arg7; llvm::Value* m_data; llvm::Function* m_init; llvm::Function* m_store; @@ -54,6 +59,7 @@ private: llvm::Function* m_calldataload; llvm::Function* m_balance; llvm::Function* m_create; + llvm::Function* m_call; llvm::Function* m_bswap; }; diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index 97ef267d6..e8da21f45 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f00060016002f2 +5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f10060016002f2 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index 60a8bc332..5e359cb7f 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -30,6 +30,14 @@ MSTORE 0 0 CREATE +32 +0 +32 +0 +0 +ADDRESS +3000 +CALL STOP 1 2 From 1835251b5249c37f9d317109a606096062a82853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 6 Oct 2014 09:42:19 +0200 Subject: [PATCH 050/396] SUICIDE instruction [Delivers #79510898] --- evmcc/Compiler.cpp | 7 +++++++ evmcc/Ext.cpp | 13 +++++++++++++ evmcc/Ext.h | 2 ++ evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 3 ++- 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 5227fa5cb..48b74e501 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -150,6 +150,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) case Instruction::RETURN: case Instruction::STOP: + case Instruction::SUICIDE: { // Create a basic block starting at the following instruction. if (curr + 1 < bytecode.cend()) @@ -761,6 +762,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::SUICIDE: + { + auto address = stack.pop(); + ext.suicide(address); + // Fall through + } case Instruction::STOP: { builder.CreateRet(builder.getInt64(0)); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index e82a91ae9..9fad58fa7 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -85,6 +85,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_setStore = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); m_calldataload = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_calldataload", module); m_balance = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_balance", module); + m_suicide = Function::Create(TypeBuilder*), true>::get(ctx), Linkage::ExternalLinkage, "ext_suicide", module); m_create = Function::Create(TypeBuilder*, i<256>*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_create", module); Type* args[] = {i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy}; m_call = Function::Create(FunctionType::get(m_builder.getVoidTy(), args, false), Linkage::ExternalLinkage, "ext_call", module); @@ -147,6 +148,13 @@ Value* Ext::balance(Value* _address) return m_builder.CreateLoad(m_args[1]); } +void Ext::suicide(Value* _address) +{ + auto address = bswap(_address); // to BE + m_builder.CreateStore(address, m_args[0]); + m_builder.CreateCall(m_suicide, m_args[0]); +} + Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { m_builder.CreateStore(_endowment, m_args[0]); @@ -225,6 +233,11 @@ EXPORT void ext_balance(h256* _address, i256* _value) *_value = eth2llvm(u); } +EXPORT void ext_suicide(h256* _address) +{ + Runtime::getExt().suicide(dev::right160(*_address)); +} + EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) { auto&& ext = Runtime::getExt(); diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 88fad15a1..c2c9f8455 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -33,6 +33,7 @@ public: llvm::Value* gaslimit(); llvm::Value* balance(llvm::Value* _address); + void suicide(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); llvm::Value* call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize); @@ -58,6 +59,7 @@ private: llvm::Function* m_setStore; llvm::Function* m_calldataload; llvm::Function* m_balance; + llvm::Function* m_suicide; llvm::Function* m_create; llvm::Function* m_call; llvm::Function* m_bswap; diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index e8da21f45..6c99e8fa0 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f10060016002f2 +5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f130ff60016002f2 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index 5e359cb7f..0625afadc 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -38,7 +38,8 @@ CREATE ADDRESS 3000 CALL -STOP +ADDRESS +SUICIDE 1 2 RETURN From fe38de867e33f286138cace91b7a81866a97f29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 6 Oct 2014 10:47:31 +0200 Subject: [PATCH 051/396] SHA3 instruction [Delivers #79534494] --- evmcc/Compiler.cpp | 8 ++++++++ evmcc/Ext.cpp | 23 +++++++++++++++++++++++ evmcc/Ext.h | 3 +++ evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 9 +++++++++ 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 48b74e501..4fead05c0 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -421,6 +421,14 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::SHA3: + { + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto hash = ext.sha3(inOff, inSize); + stack.push(hash); + } + case Instruction::POP: { stack.pop(); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 9fad58fa7..8266bd728 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include "Runtime.h" #ifdef _MSC_VER @@ -90,6 +92,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) Type* args[] = {i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy}; m_call = Function::Create(FunctionType::get(m_builder.getVoidTy(), args, false), Linkage::ExternalLinkage, "ext_call", module); m_bswap = Intrinsic::getDeclaration(module, Intrinsic::bswap, i256Ty); + m_sha3 = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_sha3", module); m_builder.CreateCall(m_init, m_data); @@ -182,6 +185,17 @@ llvm::Value* Ext::call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Va return m_builder.CreateLoad(m_args[1]); } +llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) +{ + m_builder.CreateStore(_inOff, m_args[0]); + m_builder.CreateStore(_inSize, m_arg2); + llvm::Value* args[] = {m_args[0], m_arg2, m_args[1]}; + m_builder.CreateCall(m_sha3, args); + Value* hash = m_builder.CreateLoad(m_args[1]); + hash = bswap(hash); // to LE + return hash; +} + extern "C" { @@ -285,6 +299,15 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO _ret->a = ret ? 1 : 0; } +EXPORT void ext_sha3(i256* _inOff, i256* _inSize, i256* _ret) +{ + auto inOff = static_cast(llvm2eth(*_inOff)); + auto inSize = static_cast(llvm2eth(*_inSize)); + auto dataRef = dev::bytesConstRef(Runtime::getMemory().data() + inOff, inSize); + auto hash = dev::eth::sha3(dataRef); + *_ret = *reinterpret_cast(&hash); +} + } } diff --git a/evmcc/Ext.h b/evmcc/Ext.h index c2c9f8455..7801d0540 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -38,6 +38,8 @@ public: llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); llvm::Value* call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize); + llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); + private: llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); @@ -63,6 +65,7 @@ private: llvm::Function* m_create; llvm::Function* m_call; llvm::Function* m_bswap; + llvm::Function* m_sha3; }; diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index 6c99e8fa0..580bd9675 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f130ff60016002f2 +5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f1600053611000545b60200260002030ff60016002f2 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index 0625afadc..3287ae95f 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -38,6 +38,15 @@ CREATE ADDRESS 3000 CALL +0 +MLOAD +4096 +MSTORE +MSIZE +32 +MUL +0 +SHA3 ADDRESS SUICIDE 1 From 1bd7ade08b73c638de0d87b886a4a38fdefdef65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 6 Oct 2014 15:58:57 +0200 Subject: [PATCH 052/396] Basic stack implementation for basic block. Values on stack are not preserved between basic blocks (jumps) --- evmcc/Compiler.cpp | 16 +++++++--------- evmcc/Stack.cpp | 24 ++++++++++++++++++++++++ evmcc/Stack.h | 22 ++++++++++++++++++++++ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 4fead05c0..26b23bff0 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -188,11 +188,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) createBasicBlocks(bytecode); // Init runtime structures. - auto stack = Stack(builder, module.get()); + auto globalStack = Stack(builder, module.get()); auto memory = Memory(builder, module.get()); auto ext = Ext(builder, module.get()); BasicBlock* currentBlock = entryBlock; + BBStack stack; // Stack for current block for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) { @@ -211,6 +212,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) mainFunc->getBasicBlockList().push_back(nextBlock); builder.SetInsertPoint(nextBlock); currentBlock = nextBlock; + stack = BBStack(); // Reset stack } assert(currentBlock != nullptr); @@ -498,9 +500,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::DUP15: case Instruction::DUP16: { - auto index = static_cast(inst) - static_cast(Instruction::DUP1); - auto value = stack.get(index); - stack.push(value); + auto index = static_cast(inst) - static_cast(Instruction::DUP1); + stack.dup(index); break; } @@ -521,11 +522,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::SWAP15: case Instruction::SWAP16: { - auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; - auto loValue = stack.get(index); - auto hiValue = stack.get(0); - stack.set(index, hiValue); - stack.set(0, loValue); + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; + stack.swap(index); break; } diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index ef99d603b..6a4cf4d61 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -20,6 +20,30 @@ namespace evmcc { +void BBStack::push(llvm::Value* _value) +{ + m_state.push_back(_value); +} + +llvm::Value* BBStack::pop() +{ + auto top = m_state.back(); + m_state.pop_back(); + return top; +} + +void BBStack::dup(size_t _index) +{ + auto value = *(m_state.rbegin() + _index); + m_state.push_back(value); +} + +void BBStack::swap(size_t _index) +{ + assert(_index != 0); + std::swap(*m_state.rbegin(), *(m_state.rbegin() + _index)); +} + Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) : m_builder(_builder) { diff --git a/evmcc/Stack.h b/evmcc/Stack.h index 53e935a8a..6336f3412 100644 --- a/evmcc/Stack.h +++ b/evmcc/Stack.h @@ -1,6 +1,8 @@ #pragma once +#include + #include namespace evmcc @@ -26,4 +28,24 @@ private: llvm::Function* m_stackSet; }; +/** + Stack adapter for Basic Block + + Transforms stack to SSA: tracks values and their positions on the imaginary stack used inside a basic block. + */ +class BBStack +{ +public: + //BBStack(llvm::IRBuilder<>& _builder, llvm::Module* _module); + + void push(llvm::Value* _value); + llvm::Value* pop(); + void dup(size_t _index); + void swap(size_t _index); + +private: + std::vector m_state; ///< Basic black state vector - current values and their positions +}; + + } \ No newline at end of file From 3fa3bc8b308bca6f9163d58dee4801ad2e3c6747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 09:24:55 +0200 Subject: [PATCH 053/396] Pop entry state of basic block from external stack, push exit state to external stack. [Delivers #80113346] --- evmcc/Compiler.cpp | 10 +++++++--- evmcc/ExecutionEngine.cpp | 2 +- evmcc/Stack.cpp | 24 ++++++++++++++++++++++++ evmcc/Stack.h | 18 +++++++++++++++++- evmcc/bytecode/stackjump.evm | 1 + 5 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 evmcc/bytecode/stackjump.evm diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 26b23bff0..3a0da880d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -188,12 +188,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) createBasicBlocks(bytecode); // Init runtime structures. - auto globalStack = Stack(builder, module.get()); + auto extStack = Stack(builder, module.get()); auto memory = Memory(builder, module.get()); auto ext = Ext(builder, module.get()); BasicBlock* currentBlock = entryBlock; - BBStack stack; // Stack for current block + BBStack stack(extStack); // Stack for current block for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) { @@ -212,7 +212,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) mainFunc->getBasicBlockList().push_back(nextBlock); builder.SetInsertPoint(nextBlock); currentBlock = nextBlock; - stack = BBStack(); // Reset stack + assert(stack.empty()); // Stack should be empty } assert(currentBlock != nullptr); @@ -579,6 +579,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // The target address is computed at compile time, // just pop it without looking... stack.pop(); + stack.reset(); auto targetBlock = jumpTargets[currentPC]; builder.CreateBr(targetBlock); @@ -598,6 +599,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto top = stack.pop(); auto zero = ConstantInt::get(Types.word256, 0); auto cond = builder.CreateICmpNE(top, zero, "nonzero"); + stack.reset(); auto targetBlock = jumpTargets[currentPC]; auto followBlock = basicBlocks[currentPC + 1]; builder.CreateCondBr(cond, targetBlock, followBlock); @@ -764,6 +766,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) ret = builder.CreateOr(ret, size); builder.CreateRet(ret); + stack.clear(); currentBlock = nullptr; break; } @@ -777,6 +780,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::STOP: { builder.CreateRet(builder.getInt64(0)); + stack.clear(); currentBlock = nullptr; break; } diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 6983b9cda..6d9d85a4c 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -103,7 +103,7 @@ int ExecutionEngine::run(std::unique_ptr _module) std::cout << "RETURN [ "; for (dev::bytes::const_iterator it = Runtime::getMemory().cbegin() + index, end = it + size; it != end; ++it) std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; - std::cout << "]"; + std::cout << "]\n"; return 10; } diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index 6a4cf4d61..b4fb2cd23 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -20,6 +20,10 @@ namespace evmcc { +BBStack::BBStack(Stack& _extStack) + : m_extStack(_extStack) +{} + void BBStack::push(llvm::Value* _value) { m_state.push_back(_value); @@ -27,11 +31,31 @@ void BBStack::push(llvm::Value* _value) llvm::Value* BBStack::pop() { + if (m_state.empty()) + return m_extStack.pop(); + auto top = m_state.back(); m_state.pop_back(); return top; } +void BBStack::reset() +{ + for (auto&& value : m_state) + m_extStack.push(value); + m_state.clear(); +} + +void BBStack::clear() +{ + m_state.clear(); +} + +bool BBStack::empty() const +{ + return m_state.empty(); +} + void BBStack::dup(size_t _index) { auto value = *(m_state.rbegin() + _index); diff --git a/evmcc/Stack.h b/evmcc/Stack.h index 6336f3412..c420ad0bb 100644 --- a/evmcc/Stack.h +++ b/evmcc/Stack.h @@ -36,15 +36,31 @@ private: class BBStack { public: - //BBStack(llvm::IRBuilder<>& _builder, llvm::Module* _module); + BBStack(Stack& _extStack); void push(llvm::Value* _value); llvm::Value* pop(); void dup(size_t _index); void swap(size_t _index); + /** + Resets stack on basic block change. + Values left on local stack are pushed on external stack. + Local stack is empty after this operation and compilation of new basic block can be started. + */ + void reset(); + + /** + Dumps values on stack. + */ + void clear(); + + /// Debug only + bool empty() const; + private: std::vector m_state; ///< Basic black state vector - current values and their positions + Stack& m_extStack; ///< External (global) stack }; diff --git a/evmcc/bytecode/stackjump.evm b/evmcc/bytecode/stackjump.evm new file mode 100644 index 000000000..baddec42e --- /dev/null +++ b/evmcc/bytecode/stackjump.evm @@ -0,0 +1 @@ +600460066009601358600a036000545b6000f260005401600958 \ No newline at end of file From 5bf462e03ddab160a7d537b0a2b00f1817a85450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 12:14:55 +0200 Subject: [PATCH 054/396] Introducing BasicBlock class. It is a wrapper for llvm::BasicBlock to provide additional information needed by EVM compiler. For now the order of basic blocks might not match bytecode. [#80113672] --- evmcc/BasicBlock.cpp | 13 ++++++++++++ evmcc/BasicBlock.h | 22 ++++++++++++++++++++ evmcc/Compiler.cpp | 39 +++++++++++++---------------------- evmcc/Compiler.h | 13 ++++++++++-- windows/evmcc.vcxproj | 2 ++ windows/evmcc.vcxproj.filters | 2 ++ 6 files changed, 64 insertions(+), 27 deletions(-) create mode 100644 evmcc/BasicBlock.cpp create mode 100644 evmcc/BasicBlock.h diff --git a/evmcc/BasicBlock.cpp b/evmcc/BasicBlock.cpp new file mode 100644 index 000000000..51c3fe310 --- /dev/null +++ b/evmcc/BasicBlock.cpp @@ -0,0 +1,13 @@ + +#include "BasicBlock.h" + +#include + +namespace evmcc +{ + +BasicBlock::BasicBlock(ProgramCounter _instIdx, llvm::Function* _mainFunc) + : m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {"Instr.", std::to_string(_instIdx)}, _mainFunc)) +{} + +} \ No newline at end of file diff --git a/evmcc/BasicBlock.h b/evmcc/BasicBlock.h new file mode 100644 index 000000000..ad5033ed7 --- /dev/null +++ b/evmcc/BasicBlock.h @@ -0,0 +1,22 @@ + +#include + +namespace evmcc +{ + +using ProgramCounter = uint64_t; + +class BasicBlock +{ +public: + explicit BasicBlock(ProgramCounter _instIdx, llvm::Function* _mainFunc); + BasicBlock(const BasicBlock&) = delete; + void operator=(const BasicBlock&) = delete; + + operator llvm::BasicBlock*() { return m_llvmBB; } + +private: + llvm::BasicBlock* m_llvmBB; +}; + +} \ No newline at end of file diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 3a0da880d..25ae8aa9e 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -39,23 +39,15 @@ Compiler::Compiler() Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64); } -llvm::BasicBlock* Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc) +BasicBlock& Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc) { - llvm::BasicBlock* block = nullptr; auto blockIter = basicBlocks.find(pc); - if (blockIter == basicBlocks.cend()) + if (blockIter == basicBlocks.end()) { - // Create a basic block at targetPC. - std::ostringstream oss; - oss << "instr." << pc; - block = llvm::BasicBlock::Create(llvm::getGlobalContext(), oss.str()); - basicBlocks[pc] = block; + // Create a basic block at target pc directly in collection + blockIter = basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(pc), std::forward_as_tuple(pc, m_mainFunc)).first; } - else - { - block = blockIter->second; - } - return block; + return blockIter->second; } void Compiler::createBasicBlocks(const dev::bytes& bytecode) @@ -122,7 +114,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) // Create a block for the JUMP target. ProgramCounter targetPC = val.convert_to(); - auto targetBlock = getOrCreateBasicBlockAtPC(targetPC); + auto& targetBlock = getOrCreateBasicBlockAtPC(targetPC); ProgramCounter jumpPC = (next - bytecode.cbegin()); jumpTargets[jumpPC] = targetBlock; @@ -177,13 +169,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Create main function const auto i32Ty = builder.getInt32Ty(); - Type* retTypeElems[] = {i32Ty, i32Ty}; - auto retType = StructType::create(retTypeElems, "MemRef", true); - auto mainFuncType = FunctionType::get(builder.getInt64Ty(), false); - auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get()); + //Type* retTypeElems[] = {i32Ty, i32Ty}; + //auto retType = StructType::create(retTypeElems, "MemRef", true); + m_mainFunc = Function::Create(FunctionType::get(builder.getInt64Ty(), false), Function::ExternalLinkage, "main", module.get()); // Create the basic blocks. - auto entryBlock = BasicBlock::Create(context, "entry", mainFunc); + auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc); builder.SetInsertPoint(entryBlock); createBasicBlocks(bytecode); @@ -192,7 +183,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto memory = Memory(builder, module.get()); auto ext = Ext(builder, module.get()); - BasicBlock* currentBlock = entryBlock; + llvm::BasicBlock* currentBlock = entryBlock; BBStack stack(extStack); // Stack for current block for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) @@ -204,12 +195,11 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto blockIter = basicBlocks.find(currentPC); if (blockIter != basicBlocks.end()) { - auto nextBlock = blockIter->second; + auto& nextBlock = blockIter->second; // Terminate the current block by jumping to the next one. if (currentBlock != nullptr) builder.CreateBr(nextBlock); // Insert the next block into the main function. - mainFunc->getBasicBlockList().push_back(nextBlock); builder.SetInsertPoint(nextBlock); currentBlock = nextBlock; assert(stack.empty()); // Stack should be empty @@ -601,7 +591,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto cond = builder.CreateICmpNE(top, zero, "nonzero"); stack.reset(); auto targetBlock = jumpTargets[currentPC]; - auto followBlock = basicBlocks[currentPC + 1]; + auto& followBlock = basicBlocks.find(currentPC + 1)->second; builder.CreateCondBr(cond, targetBlock, followBlock); currentBlock = nullptr; @@ -792,12 +782,11 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto finalPC = bytecode.size(); auto it = basicBlocks.find(finalPC); assert(it != basicBlocks.end()); - auto finalBlock = it->second; + auto& finalBlock = it->second; if (currentBlock != nullptr) builder.CreateBr(finalBlock); - mainFunc->getBasicBlockList().push_back(finalBlock); builder.SetInsertPoint(finalBlock); builder.CreateRet(builder.getInt64(0)); diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 6e9fd8443..1404a99c5 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -5,6 +5,8 @@ #include +#include "BasicBlock.h" + namespace evmcc { @@ -20,18 +22,25 @@ public: private: - llvm::BasicBlock* getOrCreateBasicBlockAtPC(ProgramCounter pc); + BasicBlock& getOrCreateBasicBlockAtPC(ProgramCounter pc); void createBasicBlocks(const dev::bytes& bytecode); /** * Maps a program counter pc to a basic block which starts at pc (if any). */ - std::map basicBlocks; + std::map basicBlocks; /** * Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. */ std::map jumpTargets; + +private: + /// Collection of basic blocks in program + //std::vector m_basicBlocks; + + /// Main program function + llvm::Function* m_mainFunc; }; } diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index c3add28cd..8226abb6c 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -19,6 +19,7 @@ + @@ -29,6 +30,7 @@ + diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index de7fd20bf..05f375ac5 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -9,6 +9,7 @@ + @@ -18,5 +19,6 @@ + \ No newline at end of file From 07659c441a954dc1730ba9d4e15e07c6de8193ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 15:34:02 +0200 Subject: [PATCH 055/396] Link basic blocks with phi functions [#80113672] --- evmcc/BasicBlock.cpp | 5 +++-- evmcc/BasicBlock.h | 14 +++++++++++- evmcc/Compiler.cpp | 47 ++++++++++++++++++++++++++++++++------- evmcc/Stack.cpp | 52 ++++++++++++++++++++++++-------------------- evmcc/Stack.h | 20 +++++------------ 5 files changed, 89 insertions(+), 49 deletions(-) diff --git a/evmcc/BasicBlock.cpp b/evmcc/BasicBlock.cpp index 51c3fe310..19e1d68ec 100644 --- a/evmcc/BasicBlock.cpp +++ b/evmcc/BasicBlock.cpp @@ -6,8 +6,9 @@ namespace evmcc { -BasicBlock::BasicBlock(ProgramCounter _instIdx, llvm::Function* _mainFunc) - : m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {"Instr.", std::to_string(_instIdx)}, _mainFunc)) +BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, llvm::Function* _mainFunc): + m_beginInstIdx(_beginInstIdx), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {"Instr.", std::to_string(_beginInstIdx)}, _mainFunc)) {} } \ No newline at end of file diff --git a/evmcc/BasicBlock.h b/evmcc/BasicBlock.h index ad5033ed7..793dfaea2 100644 --- a/evmcc/BasicBlock.h +++ b/evmcc/BasicBlock.h @@ -1,4 +1,6 @@ +#include + #include namespace evmcc @@ -9,14 +11,24 @@ using ProgramCounter = uint64_t; class BasicBlock { public: - explicit BasicBlock(ProgramCounter _instIdx, llvm::Function* _mainFunc); + using State = std::vector; + + explicit BasicBlock(ProgramCounter _beginInstIdx, llvm::Function* _mainFunc); + BasicBlock(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete; operator llvm::BasicBlock*() { return m_llvmBB; } + llvm::BasicBlock* llvm() { return m_llvmBB; } + + State& getState() { return m_state; } private: + ProgramCounter m_beginInstIdx; llvm::BasicBlock* m_llvmBB; + + /// Basic black state vector - current/end values and their positions + State m_state; }; } \ No newline at end of file diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 25ae8aa9e..18b0a1d3b 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -2,6 +2,7 @@ #include "Compiler.h" #include +#include #include @@ -183,8 +184,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto memory = Memory(builder, module.get()); auto ext = Ext(builder, module.get()); - llvm::BasicBlock* currentBlock = entryBlock; - BBStack stack(extStack); // Stack for current block + BasicBlock* currentBlock = &basicBlocks.find(0)->second; // Any value, just to create branch for %entry to %Instr.0 + BBStack stack(builder, extStack); // Stack for current block for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) { @@ -192,6 +193,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) ProgramCounter currentPC = pc - bytecode.cbegin(); + // Change basic block auto blockIter = basicBlocks.find(currentPC); if (blockIter != basicBlocks.end()) { @@ -201,8 +203,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) builder.CreateBr(nextBlock); // Insert the next block into the main function. builder.SetInsertPoint(nextBlock); - currentBlock = nextBlock; - assert(stack.empty()); // Stack should be empty + currentBlock = &nextBlock; + stack.setBasicBlock(*currentBlock); } assert(currentBlock != nullptr); @@ -569,7 +571,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // The target address is computed at compile time, // just pop it without looking... stack.pop(); - stack.reset(); auto targetBlock = jumpTargets[currentPC]; builder.CreateBr(targetBlock); @@ -589,7 +590,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto top = stack.pop(); auto zero = ConstantInt::get(Types.word256, 0); auto cond = builder.CreateICmpNE(top, zero, "nonzero"); - stack.reset(); auto targetBlock = jumpTargets[currentPC]; auto& followBlock = basicBlocks.find(currentPC + 1)->second; builder.CreateCondBr(cond, targetBlock, followBlock); @@ -756,7 +756,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) ret = builder.CreateOr(ret, size); builder.CreateRet(ret); - stack.clear(); currentBlock = nullptr; break; } @@ -770,7 +769,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::STOP: { builder.CreateRet(builder.getInt64(0)); - stack.clear(); currentBlock = nullptr; break; } @@ -790,6 +788,39 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) builder.SetInsertPoint(finalBlock); builder.CreateRet(builder.getInt64(0)); + auto findBB = [this](llvm::BasicBlock* _llvmBB) + { + for (auto&& bb : basicBlocks) + { + if (bb.second.llvm() == _llvmBB) + return &bb.second; + } + return (BasicBlock*)nullptr; + }; + + // Link basic blocks + for (auto&& p : basicBlocks) + { + BasicBlock& bb = p.second; + llvm::BasicBlock* llvmBB = bb.llvm(); + + size_t i = 0; + for (auto& inst : *llvmBB) + { + if (auto phi = llvm::dyn_cast(&inst)) + { + for (auto preIt = llvm::pred_begin(llvmBB); preIt != llvm::pred_end(llvmBB); ++preIt) + { + llvm::BasicBlock* preBB = *preIt; + auto pbb = findBB(preBB); + assert(i < pbb->getState().size()); // TODO: Report error + phi->addIncoming(*(pbb->getState().rbegin() + i), preBB); + } + ++i; + } + } + } + return module; } diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index b4fb2cd23..1a453d396 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -9,6 +9,7 @@ #include +#include "BasicBlock.h" #include "Runtime.h" #ifdef _MSC_VER @@ -20,52 +21,55 @@ namespace evmcc { -BBStack::BBStack(Stack& _extStack) - : m_extStack(_extStack) +BBStack::BBStack(llvm::IRBuilder<>& _builder, Stack& _extStack): + m_extStack(_extStack), + m_builder(_builder) {} void BBStack::push(llvm::Value* _value) { - m_state.push_back(_value); + m_block->getState().push_back(_value); } llvm::Value* BBStack::pop() { - if (m_state.empty()) - return m_extStack.pop(); + auto&& state = m_block->getState(); + if (state.empty()) + { + // Create PHI node + auto first = m_block->llvm()->getFirstNonPHI(); + auto llvmBB = m_block->llvm(); + if (llvmBB->getInstList().empty()) + return llvm::PHINode::Create(m_builder.getIntNTy(256), 0, {}, m_block->llvm()); + return llvm::PHINode::Create(m_builder.getIntNTy(256), 0, {}, llvmBB->getFirstNonPHI()); + } - auto top = m_state.back(); - m_state.pop_back(); + auto top = state.back(); + state.pop_back(); return top; } -void BBStack::reset() -{ - for (auto&& value : m_state) - m_extStack.push(value); - m_state.clear(); -} - -void BBStack::clear() -{ - m_state.clear(); -} - -bool BBStack::empty() const +void BBStack::setBasicBlock(BasicBlock& _newBlock) { - return m_state.empty(); + // Current block keeps end state + // Just update pointer to current block + // New block should have empty state + assert(_newBlock.getState().empty()); + m_block = &_newBlock; } void BBStack::dup(size_t _index) { - auto value = *(m_state.rbegin() + _index); - m_state.push_back(value); + auto&& state = m_block->getState(); + auto value = *(state.rbegin() + _index); + state.push_back(value); } void BBStack::swap(size_t _index) { assert(_index != 0); - std::swap(*m_state.rbegin(), *(m_state.rbegin() + _index)); + auto&& state = m_block->getState(); + std::swap(*state.rbegin(), *(state.rbegin() + _index)); } Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) diff --git a/evmcc/Stack.h b/evmcc/Stack.h index c420ad0bb..06deff814 100644 --- a/evmcc/Stack.h +++ b/evmcc/Stack.h @@ -7,6 +7,7 @@ namespace evmcc { +class BasicBlock; class Stack { @@ -36,7 +37,7 @@ private: class BBStack { public: - BBStack(Stack& _extStack); + BBStack(llvm::IRBuilder<>& _builder, Stack& _extStack); void push(llvm::Value* _value); llvm::Value* pop(); @@ -44,23 +45,14 @@ public: void swap(size_t _index); /** - Resets stack on basic block change. - Values left on local stack are pushed on external stack. - Local stack is empty after this operation and compilation of new basic block can be started. + Changes current basic block with a new one with empty state. */ - void reset(); - - /** - Dumps values on stack. - */ - void clear(); - - /// Debug only - bool empty() const; + void setBasicBlock(BasicBlock& _newBlock); private: - std::vector m_state; ///< Basic black state vector - current values and their positions Stack& m_extStack; ///< External (global) stack + BasicBlock* m_block = nullptr; ///< Current basic block + llvm::IRBuilder<>& m_builder; }; From d9c1617e60720601eaac7fa22c71027fa776b813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 15:44:46 +0200 Subject: [PATCH 056/396] Correct the order of basic blocks --- evmcc/Compiler.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 18b0a1d3b..e951788e6 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -53,8 +53,7 @@ BasicBlock& Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc) void Compiler::createBasicBlocks(const dev::bytes& bytecode) { - getOrCreateBasicBlockAtPC(0); - getOrCreateBasicBlockAtPC(bytecode.size()); + getOrCreateBasicBlockAtPC(0); // First basic block for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr) { @@ -113,13 +112,6 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) val |= *iter; } - // Create a block for the JUMP target. - ProgramCounter targetPC = val.convert_to(); - auto& targetBlock = getOrCreateBasicBlockAtPC(targetPC); - - ProgramCounter jumpPC = (next - bytecode.cbegin()); - jumpTargets[jumpPC] = targetBlock; - // Create a block following the JUMP. if (next + 1 < bytecode.cend()) { @@ -127,6 +119,13 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) getOrCreateBasicBlockAtPC(nextPC); } + // Create a block for the JUMP target. + ProgramCounter targetPC = val.convert_to(); + auto& targetBlock = getOrCreateBasicBlockAtPC(targetPC); + + ProgramCounter jumpPC = (next - bytecode.cbegin()); + jumpTargets[jumpPC] = targetBlock; + curr += 1; // skip over JUMP } @@ -158,6 +157,8 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) break; } } + + getOrCreateBasicBlockAtPC(bytecode.size()); // Final basic block } std::unique_ptr Compiler::compile(const dev::bytes& bytecode) From bf7ca5cd013fc8c79ba21e50bf7096c87c2ad0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 15:47:08 +0200 Subject: [PATCH 057/396] Cleanups: move basic block linking to separated function --- evmcc/Compiler.cpp | 11 +++++++++-- evmcc/Compiler.h | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index e951788e6..7fccadbf1 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -789,6 +789,15 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) builder.SetInsertPoint(finalBlock); builder.CreateRet(builder.getInt64(0)); + linkBasicBlocks(); + + return module; +} + + +void Compiler::linkBasicBlocks() +{ + /// Helper function that finds basic block given LLVM basic block pointer auto findBB = [this](llvm::BasicBlock* _llvmBB) { for (auto&& bb : basicBlocks) @@ -821,8 +830,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } } } - - return module; } } diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 1404a99c5..de73fb7a5 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -25,6 +25,8 @@ private: BasicBlock& getOrCreateBasicBlockAtPC(ProgramCounter pc); void createBasicBlocks(const dev::bytes& bytecode); + void linkBasicBlocks(); + /** * Maps a program counter pc to a basic block which starts at pc (if any). */ From b644ff2d71b07a36609c6a878a6f8e638c74947d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 16:03:05 +0200 Subject: [PATCH 058/396] Stack cleanups --- evmcc/Compiler.cpp | 2 +- evmcc/Stack.cpp | 11 +++-------- evmcc/Stack.h | 21 +++++++++++++++------ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 7fccadbf1..1be4a3746 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -186,7 +186,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto ext = Ext(builder, module.get()); BasicBlock* currentBlock = &basicBlocks.find(0)->second; // Any value, just to create branch for %entry to %Instr.0 - BBStack stack(builder, extStack); // Stack for current block + BBStack stack; // Stack for current block for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) { diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index 1a453d396..1b8577159 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -21,11 +21,6 @@ namespace evmcc { -BBStack::BBStack(llvm::IRBuilder<>& _builder, Stack& _extStack): - m_extStack(_extStack), - m_builder(_builder) -{} - void BBStack::push(llvm::Value* _value) { m_block->getState().push_back(_value); @@ -37,11 +32,11 @@ llvm::Value* BBStack::pop() if (state.empty()) { // Create PHI node - auto first = m_block->llvm()->getFirstNonPHI(); + auto i256Ty = llvm::Type::getIntNTy(m_block->llvm()->getContext(), 256); auto llvmBB = m_block->llvm(); if (llvmBB->getInstList().empty()) - return llvm::PHINode::Create(m_builder.getIntNTy(256), 0, {}, m_block->llvm()); - return llvm::PHINode::Create(m_builder.getIntNTy(256), 0, {}, llvmBB->getFirstNonPHI()); + return llvm::PHINode::Create(i256Ty, 0, {}, m_block->llvm()); + return llvm::PHINode::Create(i256Ty, 0, {}, llvmBB->getFirstNonPHI()); } auto top = state.back(); diff --git a/evmcc/Stack.h b/evmcc/Stack.h index 06deff814..430389ef9 100644 --- a/evmcc/Stack.h +++ b/evmcc/Stack.h @@ -37,22 +37,31 @@ private: class BBStack { public: - BBStack(llvm::IRBuilder<>& _builder, Stack& _extStack); + BBStack() = default; + BBStack(const BBStack&) = delete; + void operator=(const BBStack&) = delete; + + /** + Changes current basic block (if any) with a new one with empty state. + */ + void setBasicBlock(BasicBlock& _newBlock); void push(llvm::Value* _value); llvm::Value* pop(); + + /** + Duplicates _index'th value on stack. + */ void dup(size_t _index); - void swap(size_t _index); /** - Changes current basic block with a new one with empty state. + Swaps _index'th value on stack with a value on stack top. + @param _index Index of value to be swaped. Cannot be 0. */ - void setBasicBlock(BasicBlock& _newBlock); + void swap(size_t _index); private: - Stack& m_extStack; ///< External (global) stack BasicBlock* m_block = nullptr; ///< Current basic block - llvm::IRBuilder<>& m_builder; }; From 0e7ae8ece92e086557c61315dab8f626c2490f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 16:09:50 +0200 Subject: [PATCH 059/396] Remove external stack --- evmcc/Compiler.cpp | 1 - evmcc/Stack.cpp | 130 +-------------------------------------------- evmcc/Stack.h | 24 +-------- 3 files changed, 3 insertions(+), 152 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 1be4a3746..e5fe6db8b 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -181,7 +181,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) createBasicBlocks(bytecode); // Init runtime structures. - auto extStack = Stack(builder, module.get()); auto memory = Memory(builder, module.get()); auto ext = Ext(builder, module.get()); diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index 1b8577159..86b39316c 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -1,22 +1,11 @@ #include "Stack.h" -#include -#include -#include -#include #include -#include +#include #include "BasicBlock.h" -#include "Runtime.h" - -#ifdef _MSC_VER - #define EXPORT __declspec(dllexport) -#else - #define EXPORT -#endif namespace evmcc { @@ -49,7 +38,7 @@ void BBStack::setBasicBlock(BasicBlock& _newBlock) // Current block keeps end state // Just update pointer to current block // New block should have empty state - assert(_newBlock.getState().empty()); + assert(_newBlock.getState().empty()); m_block = &_newBlock; } @@ -67,119 +56,4 @@ void BBStack::swap(size_t _index) std::swap(*state.rbegin(), *(state.rbegin() + _index)); } -Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module) - : m_builder(_builder) -{ - // TODO: Clean up LLVM types - auto stackPtrTy = m_builder.getInt8PtrTy(); - auto i256Ty = m_builder.getIntNTy(256); - auto i256PtrTy = i256Ty->getPointerTo(); - auto voidTy = m_builder.getVoidTy(); - - auto funcType = llvm::FunctionType::get(voidTy, i256PtrTy, false); - m_stackPush = llvm::Function::Create(funcType, - llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_push", _module); - - m_stackPop = llvm::Function::Create(funcType, - llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_pop", _module); - - llvm::Type* getArgsTypes[] = {m_builder.getInt32Ty(), i256PtrTy}; - auto getFuncType = llvm::FunctionType::get(voidTy, getArgsTypes, false); - m_stackGet = llvm::Function::Create(getFuncType, - llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_get", _module); - - m_stackSet = llvm::Function::Create(getFuncType, - llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_set", _module); - - m_stackVal = m_builder.CreateAlloca(i256Ty, nullptr, "stack.val"); -} - - -void Stack::push(llvm::Value* _value) -{ - m_builder.CreateStore(_value, m_stackVal); // copy value to memory - m_builder.CreateCall(m_stackPush, m_stackVal); -} - - -llvm::Value* Stack::pop() -{ - m_builder.CreateCall(m_stackPop, m_stackVal); - return m_builder.CreateLoad(m_stackVal); -} - - -llvm::Value* Stack::get(uint32_t _index) -{ - llvm::Value* args[] = {m_builder.getInt32(_index), m_stackVal}; - m_builder.CreateCall(m_stackGet, args); - return m_builder.CreateLoad(m_stackVal); -} - - -void Stack::set(uint32_t _index, llvm::Value* _value) -{ - m_builder.CreateStore(_value, m_stackVal); // copy value to memory - llvm::Value* args[] = {m_builder.getInt32(_index), m_stackVal}; - m_builder.CreateCall(m_stackSet, args); -} - - -llvm::Value* Stack::top() -{ - return get(0); } - - -void debugStack(const char* _op, const i256& _word, uint32_t _index = 0) -{ - std::cerr << "STACK " << std::setw(4) << std::setfill(' ') << _op - << " [" << std::setw(2) << std::setfill('0') << _index << "] " - << std::dec << _word.a - << " HEX: " << std::hex; - if (_word.b || _word.c || _word.d) - { - std::cerr << std::setw(16) << _word.d << " " - << std::setw(16) << _word.c << " " - << std::setw(16) << _word.b << " "; - } - std::cerr << std::setw(16) << _word.a << "\n"; -} - -} - -extern "C" -{ - using namespace evmcc; - -EXPORT void evmccrt_stack_push(i256* _word) -{ - //debugStack("push", *_word); - Runtime::getStack().push_back(*_word); -} - -EXPORT void evmccrt_stack_pop(i256* _outWord) -{ - assert(!Runtime::getStack().empty()); - auto word = &Runtime::getStack().back(); - //debugStack("pop", *word); - Runtime::getStack().pop_back(); - *_outWord = *word; -} - -EXPORT void evmccrt_stack_get(uint32_t _index, i256* _outWord) -{ - assert(_index < Runtime::getStack().size()); - auto word = Runtime::getStack().rbegin() + _index; - //debugStack("get", *word, _index); - *_outWord = *word; -} - -EXPORT void evmccrt_stack_set(uint32_t _index, i256* _word) -{ - assert(_index < Runtime::getStack().size()); - *(Runtime::getStack().rbegin() + _index) = *_word; - //debugStack("set", *_word, _index); -} - -} // extern "C" diff --git a/evmcc/Stack.h b/evmcc/Stack.h index 430389ef9..cc29a0074 100644 --- a/evmcc/Stack.h +++ b/evmcc/Stack.h @@ -1,34 +1,12 @@ #pragma once -#include - -#include +#include namespace evmcc { class BasicBlock; -class Stack -{ -public: - Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module); - - void push(llvm::Value* _value); - llvm::Value* pop(); - llvm::Value* top(); - llvm::Value* get(uint32_t _index); - void set(uint32_t _index, llvm::Value* _value); - -private: - llvm::IRBuilder<>& m_builder; - llvm::Value* m_stackVal; - llvm::Function* m_stackPush; - llvm::Function* m_stackPop; - llvm::Function* m_stackGet; - llvm::Function* m_stackSet; -}; - /** Stack adapter for Basic Block From 0cba3d90054716d6c62f1f312818ba54e553c839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 17:27:45 +0200 Subject: [PATCH 060/396] Improve basic blocks linking implementation --- evmcc/BasicBlock.cpp | 4 +++- evmcc/BasicBlock.h | 2 ++ evmcc/Compiler.cpp | 32 ++++++++++++++------------------ evmcc/Stack.cpp | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/evmcc/BasicBlock.cpp b/evmcc/BasicBlock.cpp index 19e1d68ec..9bdd6d31d 100644 --- a/evmcc/BasicBlock.cpp +++ b/evmcc/BasicBlock.cpp @@ -6,9 +6,11 @@ namespace evmcc { +const char* BasicBlock::NamePrefix = "Instr."; + BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, llvm::Function* _mainFunc): m_beginInstIdx(_beginInstIdx), - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {"Instr.", std::to_string(_beginInstIdx)}, _mainFunc)) + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)) {} } \ No newline at end of file diff --git a/evmcc/BasicBlock.h b/evmcc/BasicBlock.h index 793dfaea2..83df5da24 100644 --- a/evmcc/BasicBlock.h +++ b/evmcc/BasicBlock.h @@ -13,6 +13,8 @@ class BasicBlock public: using State = std::vector; + static const char* NamePrefix; + explicit BasicBlock(ProgramCounter _beginInstIdx, llvm::Function* _mainFunc); BasicBlock(const BasicBlock&) = delete; diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index e5fe6db8b..2ae7ab1e7 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -797,14 +797,13 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) void Compiler::linkBasicBlocks() { /// Helper function that finds basic block given LLVM basic block pointer - auto findBB = [this](llvm::BasicBlock* _llvmBB) + auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock& { - for (auto&& bb : basicBlocks) - { - if (bb.second.llvm() == _llvmBB) - return &bb.second; - } - return (BasicBlock*)nullptr; + // Name is used to get basic block index (index of first instruction) + // TODO: If basicBlocs are still a map - multikey map can be used + auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2); + auto idx = std::stoul(idxStr); + return basicBlocks.find(idx)->second; }; // Link basic blocks @@ -813,19 +812,16 @@ void Compiler::linkBasicBlocks() BasicBlock& bb = p.second; llvm::BasicBlock* llvmBB = bb.llvm(); - size_t i = 0; - for (auto& inst : *llvmBB) + size_t valueIdx = 0; + auto firstNonPhi = llvmBB->getFirstNonPHI(); + for (auto instIt = llvmBB->begin(); &*instIt != firstNonPhi; ++instIt, ++valueIdx) { - if (auto phi = llvm::dyn_cast(&inst)) + auto phi = llvm::cast(instIt); + for (auto predIt = llvm::pred_begin(llvmBB); predIt != llvm::pred_end(llvmBB); ++predIt) { - for (auto preIt = llvm::pred_begin(llvmBB); preIt != llvm::pred_end(llvmBB); ++preIt) - { - llvm::BasicBlock* preBB = *preIt; - auto pbb = findBB(preBB); - assert(i < pbb->getState().size()); // TODO: Report error - phi->addIncoming(*(pbb->getState().rbegin() + i), preBB); - } - ++i; + auto& predBB = findBasicBlock(*predIt); + assert(valueIdx < predBB.getState().size()); // TODO: Report error + phi->addIncoming(*(predBB.getState().rbegin() + valueIdx), predBB); } } } diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp index 86b39316c..fc359f103 100644 --- a/evmcc/Stack.cpp +++ b/evmcc/Stack.cpp @@ -23,7 +23,7 @@ llvm::Value* BBStack::pop() // Create PHI node auto i256Ty = llvm::Type::getIntNTy(m_block->llvm()->getContext(), 256); auto llvmBB = m_block->llvm(); - if (llvmBB->getInstList().empty()) + if (llvmBB->empty()) return llvm::PHINode::Create(i256Ty, 0, {}, m_block->llvm()); return llvm::PHINode::Create(i256Ty, 0, {}, llvmBB->getFirstNonPHI()); } From 40ebe55a20f5d8ac5bc09123243fd8d66abc7dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 18:44:42 +0200 Subject: [PATCH 061/396] Provide end instruction to basic block --- evmcc/BasicBlock.cpp | 3 ++- evmcc/BasicBlock.h | 5 ++++- evmcc/Compiler.cpp | 41 ++++++++++++++++------------------------- evmcc/Compiler.h | 7 +++---- evmcc/Stack.h | 1 + 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/evmcc/BasicBlock.cpp b/evmcc/BasicBlock.cpp index 9bdd6d31d..487de0239 100644 --- a/evmcc/BasicBlock.cpp +++ b/evmcc/BasicBlock.cpp @@ -8,8 +8,9 @@ namespace evmcc const char* BasicBlock::NamePrefix = "Instr."; -BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, llvm::Function* _mainFunc): +BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc) : m_beginInstIdx(_beginInstIdx), + m_endInstIdx(_endInstIdx), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)) {} diff --git a/evmcc/BasicBlock.h b/evmcc/BasicBlock.h index 83df5da24..c842841f9 100644 --- a/evmcc/BasicBlock.h +++ b/evmcc/BasicBlock.h @@ -15,7 +15,7 @@ public: static const char* NamePrefix; - explicit BasicBlock(ProgramCounter _beginInstIdx, llvm::Function* _mainFunc); + explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc); BasicBlock(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete; @@ -25,8 +25,11 @@ public: State& getState() { return m_state; } + void setEnd(ProgramCounter _endInstIdx) { m_endInstIdx = _endInstIdx; } + private: ProgramCounter m_beginInstIdx; + ProgramCounter m_endInstIdx; llvm::BasicBlock* m_llvmBB; /// Basic black state vector - current/end values and their positions diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 2ae7ab1e7..86fe94466 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -40,20 +40,10 @@ Compiler::Compiler() Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64); } -BasicBlock& Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc) -{ - auto blockIter = basicBlocks.find(pc); - if (blockIter == basicBlocks.end()) - { - // Create a basic block at target pc directly in collection - blockIter = basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(pc), std::forward_as_tuple(pc, m_mainFunc)).first; - } - return blockIter->second; -} - void Compiler::createBasicBlocks(const dev::bytes& bytecode) { - getOrCreateBasicBlockAtPC(0); // First basic block + std::set splitPoints; // Sorted collections of instruction indecies where basic blocks start/end + splitPoints.insert(0); // First basic block for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr) { @@ -116,15 +106,15 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) if (next + 1 < bytecode.cend()) { ProgramCounter nextPC = (next + 1 - bytecode.cbegin()); - getOrCreateBasicBlockAtPC(nextPC); + splitPoints.insert(nextPC); } // Create a block for the JUMP target. ProgramCounter targetPC = val.convert_to(); - auto& targetBlock = getOrCreateBasicBlockAtPC(targetPC); + splitPoints.insert(targetPC); ProgramCounter jumpPC = (next - bytecode.cbegin()); - jumpTargets[jumpPC] = targetBlock; + jumpTargets[jumpPC] = targetPC; curr += 1; // skip over JUMP } @@ -148,7 +138,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) if (curr + 1 < bytecode.cend()) { ProgramCounter nextPC = (curr + 1 - bytecode.cbegin()); - getOrCreateBasicBlockAtPC(nextPC); + splitPoints.insert(nextPC); } break; } @@ -158,7 +148,14 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) } } - getOrCreateBasicBlockAtPC(bytecode.size()); // Final basic block + splitPoints.insert(bytecode.size()); // For final block + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + auto beginInstIdx = *it; + ++it; + auto endInstIdx = it != splitPoints.cend() ? *it : beginInstIdx; // For final block + basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc)); + } } std::unique_ptr Compiler::compile(const dev::bytes& bytecode) @@ -572,7 +569,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // just pop it without looking... stack.pop(); - auto targetBlock = jumpTargets[currentPC]; + auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second; builder.CreateBr(targetBlock); currentBlock = nullptr; @@ -590,7 +587,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto top = stack.pop(); auto zero = ConstantInt::get(Types.word256, 0); auto cond = builder.CreateICmpNE(top, zero, "nonzero"); - auto targetBlock = jumpTargets[currentPC]; + auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second; auto& followBlock = basicBlocks.find(currentPC + 1)->second; builder.CreateCondBr(cond, targetBlock, followBlock); @@ -743,12 +740,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto index = stack.pop(); auto size = stack.pop(); - // MCJIT does not support returning structs - //auto index32 = builder.CreateTrunc(index, i32Ty, "index32"); - //auto size32 = builder.CreateTrunc(size, i32Ty, "size32"); - //auto ret = builder.CreateInsertValue(UndefValue::get(retType), index32, 0, "ret"); - //ret = builder.CreateInsertValue(ret, size32, 1, "ret"); - auto ret = builder.CreateTrunc(index, builder.getInt64Ty()); ret = builder.CreateShl(ret, 32); size = builder.CreateTrunc(size, i32Ty); diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index de73fb7a5..52a6bc9ac 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -22,7 +22,6 @@ public: private: - BasicBlock& getOrCreateBasicBlockAtPC(ProgramCounter pc); void createBasicBlocks(const dev::bytes& bytecode); void linkBasicBlocks(); @@ -33,16 +32,16 @@ private: std::map basicBlocks; /** - * Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. + * Maps a pc at which there is a JUMP or JUMPI to the target pc of the jump. */ - std::map jumpTargets; + std::map jumpTargets; private: /// Collection of basic blocks in program //std::vector m_basicBlocks; /// Main program function - llvm::Function* m_mainFunc; + llvm::Function* m_mainFunc = nullptr; }; } diff --git a/evmcc/Stack.h b/evmcc/Stack.h index cc29a0074..4b81986b0 100644 --- a/evmcc/Stack.h +++ b/evmcc/Stack.h @@ -11,6 +11,7 @@ class BasicBlock; Stack adapter for Basic Block Transforms stack to SSA: tracks values and their positions on the imaginary stack used inside a basic block. + TODO: Integrate into BasicBlock class */ class BBStack { From bec3e0fb361d7b91c128bbb0c35d3b449b665462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 7 Oct 2014 19:29:56 +0200 Subject: [PATCH 062/396] Cleanup Compiler --- evmcc/BasicBlock.h | 3 +- evmcc/Compiler.cpp | 1030 ++++++++++++++++++++++---------------------- 2 files changed, 511 insertions(+), 522 deletions(-) diff --git a/evmcc/BasicBlock.h b/evmcc/BasicBlock.h index c842841f9..ef53169d8 100644 --- a/evmcc/BasicBlock.h +++ b/evmcc/BasicBlock.h @@ -25,7 +25,8 @@ public: State& getState() { return m_state; } - void setEnd(ProgramCounter _endInstIdx) { m_endInstIdx = _endInstIdx; } + ProgramCounter begin() { return m_beginInstIdx; } + ProgramCounter end() { return m_endInstIdx; } private: ProgramCounter m_beginInstIdx; diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 86fe94466..9d29a166d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -181,604 +181,592 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto memory = Memory(builder, module.get()); auto ext = Ext(builder, module.get()); - BasicBlock* currentBlock = &basicBlocks.find(0)->second; // Any value, just to create branch for %entry to %Instr.0 - BBStack stack; // Stack for current block + // Jump to first instruction + builder.CreateBr(basicBlocks.begin()->second); - for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) + for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) { - using dev::eth::Instruction; - - ProgramCounter currentPC = pc - bytecode.cbegin(); - - // Change basic block - auto blockIter = basicBlocks.find(currentPC); - if (blockIter != basicBlocks.end()) - { - auto& nextBlock = blockIter->second; - // Terminate the current block by jumping to the next one. - if (currentBlock != nullptr) - builder.CreateBr(nextBlock); - // Insert the next block into the main function. - builder.SetInsertPoint(nextBlock); - currentBlock = &nextBlock; - stack.setBasicBlock(*currentBlock); - } + auto& basicBlock = basicBlockPairIt->second; - assert(currentBlock != nullptr); + BBStack stack; + stack.setBasicBlock(basicBlock); + builder.SetInsertPoint(basicBlock); - auto inst = static_cast(*pc); - switch (inst) + for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) { + using dev::eth::Instruction; + auto inst = static_cast(bytecode[currentPC]); + switch (inst) + { - case Instruction::ADD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = builder.CreateAdd(lhs, rhs); - stack.push(result); - break; - } + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } - case Instruction::SUB: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = builder.CreateSub(lhs, rhs); - stack.push(result); - break; - } + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } - case Instruction::MUL: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); - auto res128 = builder.CreateMul(lhs128, rhs128); - auto res256 = builder.CreateZExt(res128, Types.word256); - stack.push(res256); - break; - } + case Instruction::MUL: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateMul(lhs128, rhs128); + auto res256 = builder.CreateZExt(res128, Types.word256); + stack.push(res256); + break; + } - case Instruction::DIV: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); - auto res128 = builder.CreateUDiv(lhs128, rhs128); - auto res256 = builder.CreateZExt(res128, Types.word256); - stack.push(res256); - break; - } + case Instruction::DIV: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateUDiv(lhs128, rhs128); + auto res256 = builder.CreateZExt(res128, Types.word256); + stack.push(res256); + break; + } - case Instruction::SDIV: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); - auto res128 = builder.CreateSDiv(lhs128, rhs128); - auto res256 = builder.CreateSExt(res128, Types.word256); - stack.push(res256); - break; - } + case Instruction::SDIV: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateSDiv(lhs128, rhs128); + auto res256 = builder.CreateSExt(res128, Types.word256); + stack.push(res256); + break; + } - case Instruction::MOD: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); - auto res128 = builder.CreateURem(lhs128, rhs128); - auto res256 = builder.CreateZExt(res128, Types.word256); - stack.push(res256); - break; - } + case Instruction::MOD: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateURem(lhs128, rhs128); + auto res256 = builder.CreateZExt(res128, Types.word256); + stack.push(res256); + break; + } - case Instruction::SMOD: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); - auto res128 = builder.CreateSRem(lhs128, rhs128); - auto res256 = builder.CreateSExt(res128, Types.word256); - stack.push(res256); - break; - } + case Instruction::SMOD: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto res128 = builder.CreateSRem(lhs128, rhs128); + auto res256 = builder.CreateSExt(res128, Types.word256); + stack.push(res256); + break; + } - case Instruction::NEG: - { - auto top = stack.pop(); - auto zero = ConstantInt::get(Types.word256, 0); - auto res = builder.CreateSub(zero, top); - stack.push(res); - break; - } + case Instruction::NEG: + { + auto top = stack.pop(); + auto zero = ConstantInt::get(Types.word256, 0); + auto res = builder.CreateSub(zero, top); + stack.push(res); + break; + } - case Instruction::LT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = builder.CreateICmpULT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); - stack.push(res256); - break; - } + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpULT(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } - case Instruction::GT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = builder.CreateICmpUGT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); - stack.push(res256); - break; - } + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpUGT(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } - case Instruction::SLT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = builder.CreateICmpSLT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); - stack.push(res256); - break; - } + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpSLT(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } - case Instruction::SGT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = builder.CreateICmpSGT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); - stack.push(res256); - break; - } + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpSGT(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } - case Instruction::EQ: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = builder.CreateICmpEQ(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); - stack.push(res256); - break; - } + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = builder.CreateICmpEQ(lhs, rhs); + auto res256 = builder.CreateZExt(res1, Types.word256); + stack.push(res256); + break; + } - case Instruction::NOT: - { - auto top = stack.pop(); - auto zero = ConstantInt::get(Types.word256, 0); - auto iszero = builder.CreateICmpEQ(top, zero, "iszero"); - auto result = builder.CreateZExt(iszero, Types.word256); - stack.push(result); - break; - } - - case Instruction::AND: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = builder.CreateAnd(lhs, rhs); - stack.push(res); - break; - } + case Instruction::NOT: + { + auto top = stack.pop(); + auto zero = ConstantInt::get(Types.word256, 0); + auto iszero = builder.CreateICmpEQ(top, zero, "iszero"); + auto result = builder.CreateZExt(iszero, Types.word256); + stack.push(result); + break; + } - case Instruction::OR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = builder.CreateOr(lhs, rhs); - stack.push(res); - break; - } + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } - case Instruction::XOR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = builder.CreateXor(lhs, rhs); - stack.push(res); - break; - } + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } - case Instruction::BYTE: - { - const auto byteNum = stack.pop(); - auto value = stack.pop(); + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } - /* - if (byteNum < 32) - use select + case Instruction::BYTE: { + const auto byteNum = stack.pop(); + auto value = stack.pop(); + + /* + if (byteNum < 32) - use select + { value <<= byteNum*8 value >>= 31*8 push value - } - else push 0 - */ + } + else push 0 + */ - // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 - - auto shbits = builder.CreateShl(byteNum, builder.getIntN(256, 3)); - value = builder.CreateShl(value, shbits); - value = builder.CreateLShr(value, builder.getIntN(256, 31 * 8)); + // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 - auto byteNumValid = builder.CreateICmpULT(byteNum, builder.getIntN(256, 32)); - value = builder.CreateSelect(byteNumValid, value, builder.getIntN(256, 0)); - stack.push(value); + auto shbits = builder.CreateShl(byteNum, builder.getIntN(256, 3)); + value = builder.CreateShl(value, shbits); + value = builder.CreateLShr(value, builder.getIntN(256, 31 * 8)); - break; - } + auto byteNumValid = builder.CreateICmpULT(byteNum, builder.getIntN(256, 32)); + value = builder.CreateSelect(byteNumValid, value, builder.getIntN(256, 0)); + stack.push(value); - case Instruction::SHA3: - { - auto inOff = stack.pop(); - auto inSize = stack.pop(); - auto hash = ext.sha3(inOff, inSize); - stack.push(hash); - } + break; + } - case Instruction::POP: - { - stack.pop(); - break; - } + case Instruction::SHA3: + { + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto hash = ext.sha3(inOff, inSize); + stack.push(hash); + } - case Instruction::PUSH1: - case Instruction::PUSH2: - case Instruction::PUSH3: - case Instruction::PUSH4: - case Instruction::PUSH5: - case Instruction::PUSH6: - case Instruction::PUSH7: - case Instruction::PUSH8: - case Instruction::PUSH9: - case Instruction::PUSH10: - case Instruction::PUSH11: - case Instruction::PUSH12: - case Instruction::PUSH13: - case Instruction::PUSH14: - case Instruction::PUSH15: - case Instruction::PUSH16: - case Instruction::PUSH17: - case Instruction::PUSH18: - case Instruction::PUSH19: - case Instruction::PUSH20: - case Instruction::PUSH21: - case Instruction::PUSH22: - case Instruction::PUSH23: - case Instruction::PUSH24: - case Instruction::PUSH25: - case Instruction::PUSH26: - case Instruction::PUSH27: - case Instruction::PUSH28: - case Instruction::PUSH29: - case Instruction::PUSH30: - case Instruction::PUSH31: - case Instruction::PUSH32: - { - auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; - auto value = llvm::APInt(256, 0); - for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator + case Instruction::POP: { - ++pc; - value <<= 8; - value |= *pc; + stack.pop(); + break; } - auto c = builder.getInt(value); - stack.push(c); - break; - } - case Instruction::DUP1: - case Instruction::DUP2: - case Instruction::DUP3: - case Instruction::DUP4: - case Instruction::DUP5: - case Instruction::DUP6: - case Instruction::DUP7: - case Instruction::DUP8: - case Instruction::DUP9: - case Instruction::DUP10: - case Instruction::DUP11: - case Instruction::DUP12: - case Instruction::DUP13: - case Instruction::DUP14: - case Instruction::DUP15: - case Instruction::DUP16: - { - auto index = static_cast(inst) - static_cast(Instruction::DUP1); - stack.dup(index); - break; - } + case Instruction::PUSH1: + case Instruction::PUSH2: + case Instruction::PUSH3: + case Instruction::PUSH4: + case Instruction::PUSH5: + case Instruction::PUSH6: + case Instruction::PUSH7: + case Instruction::PUSH8: + case Instruction::PUSH9: + case Instruction::PUSH10: + case Instruction::PUSH11: + case Instruction::PUSH12: + case Instruction::PUSH13: + case Instruction::PUSH14: + case Instruction::PUSH15: + case Instruction::PUSH16: + case Instruction::PUSH17: + case Instruction::PUSH18: + case Instruction::PUSH19: + case Instruction::PUSH20: + case Instruction::PUSH21: + case Instruction::PUSH22: + case Instruction::PUSH23: + case Instruction::PUSH24: + case Instruction::PUSH25: + case Instruction::PUSH26: + case Instruction::PUSH27: + case Instruction::PUSH28: + case Instruction::PUSH29: + case Instruction::PUSH30: + case Instruction::PUSH31: + case Instruction::PUSH32: + { + auto numBytes = static_cast(inst)-static_cast(Instruction::PUSH1) + 1; + auto value = llvm::APInt(256, 0); + for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator + { + ++currentPC; + value <<= 8; + value |= bytecode[currentPC]; + } + auto c = builder.getInt(value); + stack.push(c); + break; + } - case Instruction::SWAP1: - case Instruction::SWAP2: - case Instruction::SWAP3: - case Instruction::SWAP4: - case Instruction::SWAP5: - case Instruction::SWAP6: - case Instruction::SWAP7: - case Instruction::SWAP8: - case Instruction::SWAP9: - case Instruction::SWAP10: - case Instruction::SWAP11: - case Instruction::SWAP12: - case Instruction::SWAP13: - case Instruction::SWAP14: - case Instruction::SWAP15: - case Instruction::SWAP16: - { - auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; - stack.swap(index); - break; - } + case Instruction::DUP1: + case Instruction::DUP2: + case Instruction::DUP3: + case Instruction::DUP4: + case Instruction::DUP5: + case Instruction::DUP6: + case Instruction::DUP7: + case Instruction::DUP8: + case Instruction::DUP9: + case Instruction::DUP10: + case Instruction::DUP11: + case Instruction::DUP12: + case Instruction::DUP13: + case Instruction::DUP14: + case Instruction::DUP15: + case Instruction::DUP16: + { + auto index = static_cast(inst)-static_cast(Instruction::DUP1); + stack.dup(index); + break; + } - case Instruction::MLOAD: - { - auto addr = stack.pop(); - auto word = memory.loadWord(addr); - stack.push(word); - break; - } + case Instruction::SWAP1: + case Instruction::SWAP2: + case Instruction::SWAP3: + case Instruction::SWAP4: + case Instruction::SWAP5: + case Instruction::SWAP6: + case Instruction::SWAP7: + case Instruction::SWAP8: + case Instruction::SWAP9: + case Instruction::SWAP10: + case Instruction::SWAP11: + case Instruction::SWAP12: + case Instruction::SWAP13: + case Instruction::SWAP14: + case Instruction::SWAP15: + case Instruction::SWAP16: + { + auto index = static_cast(inst)-static_cast(Instruction::SWAP1) + 1; + stack.swap(index); + break; + } - case Instruction::MSTORE: - { - auto addr = stack.pop(); - auto word = stack.pop(); - memory.storeWord(addr, word); - break; - } + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = memory.loadWord(addr); + stack.push(word); + break; + } - case Instruction::MSTORE8: - { - auto addr = stack.pop(); - auto word = stack.pop(); - memory.storeByte(addr, word); - break; - } + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeWord(addr, word); + break; + } - case Instruction::MSIZE: - { - auto word = memory.getSize(); - stack.push(word); - break; - } + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeByte(addr, word); + break; + } - case Instruction::SLOAD: - { - auto index = stack.pop(); - auto value = ext.store(index); - stack.push(value); - break; - } + case Instruction::MSIZE: + { + auto word = memory.getSize(); + stack.push(word); + break; + } - case Instruction::SSTORE: - { - auto index = stack.pop(); - auto value = stack.pop(); - ext.setStore(index, value); - break; - } + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = ext.store(index); + stack.push(value); + break; + } - case Instruction::JUMP: - { - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + ext.setStore(index, value); + break; + } - auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second; - builder.CreateBr(targetBlock); + case Instruction::JUMP: + { + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); - currentBlock = nullptr; - break; - } + auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second; + builder.CreateBr(targetBlock); + break; + } - case Instruction::JUMPI: - { - assert(pc + 1 < bytecode.cend()); + case Instruction::JUMPI: + { + assert(currentPC + 1 < bytecode.size()); + + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + + auto top = stack.pop(); + auto zero = ConstantInt::get(Types.word256, 0); + auto cond = builder.CreateICmpNE(top, zero, "nonzero"); + auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second; + auto& followBlock = basicBlocks.find(currentPC + 1)->second; + builder.CreateCondBr(cond, targetBlock, followBlock); + break; + } - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); + case Instruction::PC: + { + auto value = builder.getIntN(256, currentPC); + stack.push(value); + break; + } - auto top = stack.pop(); - auto zero = ConstantInt::get(Types.word256, 0); - auto cond = builder.CreateICmpNE(top, zero, "nonzero"); - auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second; - auto& followBlock = basicBlocks.find(currentPC + 1)->second; - builder.CreateCondBr(cond, targetBlock, followBlock); + case Instruction::ADDRESS: + { + auto value = ext.address(); + stack.push(value); + break; + } - currentBlock = nullptr; - break; - } + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = ext.balance(address); + stack.push(value); + break; + } - case Instruction::PC: - { - auto value = builder.getIntN(256, currentPC); - stack.push(value); - break; - } + case Instruction::CALLER: + { + auto value = ext.caller(); + stack.push(value); + break; + } - case Instruction::ADDRESS: - { - auto value = ext.address(); - stack.push(value); - break; - } + case Instruction::ORIGIN: + { + auto value = ext.origin(); + stack.push(value); + break; + } - case Instruction::BALANCE: - { - auto address = stack.pop(); - auto value = ext.balance(address); - stack.push(value); - break; - } + case Instruction::CALLVALUE: + { + auto value = ext.callvalue(); + stack.push(value); + break; + } - case Instruction::CALLER: - { - auto value = ext.caller(); - stack.push(value); - break; - } + case Instruction::CALLDATASIZE: + { + auto value = ext.calldatasize(); + stack.push(value); + break; + } - case Instruction::ORIGIN: - { - auto value = ext.origin(); - stack.push(value); - break; - } + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = ext.calldataload(index); + stack.push(value); + break; + } - case Instruction::CALLVALUE: - { - auto value = ext.callvalue(); - stack.push(value); - break; - } + case Instruction::GASPRICE: + { + auto value = ext.gasprice(); + stack.push(value); + break; + } - case Instruction::CALLDATASIZE: - { - auto value = ext.calldatasize(); - stack.push(value); - break; - } + case Instruction::CODESIZE: + { + auto value = builder.getIntN(256, bytecode.size()); + stack.push(value); + break; + } - case Instruction::CALLDATALOAD: - { - auto index = stack.pop(); - auto value = ext.calldataload(index); - stack.push(value); - break; - } + case Instruction::PREVHASH: + { + auto value = ext.prevhash(); + stack.push(value); + break; + } - case Instruction::GASPRICE: - { - auto value = ext.gasprice(); - stack.push(value); - break; - } + case Instruction::COINBASE: + { + auto value = ext.coinbase(); + stack.push(value); + break; + } - case Instruction::CODESIZE: - { - auto value = builder.getIntN(256, bytecode.size()); - stack.push(value); - break; - } + case Instruction::TIMESTAMP: + { + auto value = ext.timestamp(); + stack.push(value); + break; + } - case Instruction::PREVHASH: - { - auto value = ext.prevhash(); - stack.push(value); - break; - } + case Instruction::NUMBER: + { + auto value = ext.number(); + stack.push(value); + break; + } - case Instruction::COINBASE: - { - auto value = ext.coinbase(); - stack.push(value); - break; - } + case Instruction::DIFFICULTY: + { + auto value = ext.difficulty(); + stack.push(value); + break; + } - case Instruction::TIMESTAMP: - { - auto value = ext.timestamp(); - stack.push(value); - break; - } + case Instruction::GASLIMIT: + { + auto value = ext.gaslimit(); + stack.push(value); + break; + } - case Instruction::NUMBER: - { - auto value = ext.number(); - stack.push(value); - break; - } + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); - case Instruction::DIFFICULTY: - { - auto value = ext.difficulty(); - stack.push(value); - break; - } + auto address = ext.create(endowment, initOff, initSize); + stack.push(address); + break; + } - case Instruction::GASLIMIT: - { - auto value = ext.gaslimit(); - stack.push(value); - break; - } - - case Instruction::CREATE: - { - auto endowment = stack.pop(); - auto initOff = stack.pop(); - auto initSize = stack.pop(); + case Instruction::CALL: + { + auto gas = stack.pop(); + auto receiveAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize); + stack.push(ret); + break; + } - auto address = ext.create(endowment, initOff, initSize); - stack.push(address); - break; - } + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); - case Instruction::CALL: - { - auto gas = stack.pop(); - auto receiveAddress = stack.pop(); - auto value = stack.pop(); - auto inOff = stack.pop(); - auto inSize = stack.pop(); - auto outOff = stack.pop(); - auto outSize = stack.pop(); - - auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize); - stack.push(ret); - break; - } + auto ret = builder.CreateTrunc(index, builder.getInt64Ty()); + ret = builder.CreateShl(ret, 32); + size = builder.CreateTrunc(size, i32Ty); + size = builder.CreateZExt(size, builder.getInt64Ty()); + ret = builder.CreateOr(ret, size); - case Instruction::RETURN: - { - auto index = stack.pop(); - auto size = stack.pop(); + builder.CreateRet(ret); + break; + } - auto ret = builder.CreateTrunc(index, builder.getInt64Ty()); - ret = builder.CreateShl(ret, 32); - size = builder.CreateTrunc(size, i32Ty); - size = builder.CreateZExt(size, builder.getInt64Ty()); - ret = builder.CreateOr(ret, size); + case Instruction::SUICIDE: + { + auto address = stack.pop(); + ext.suicide(address); + // Fall through + } + case Instruction::STOP: + { + builder.CreateRet(builder.getInt64(0)); + break; + } - builder.CreateRet(ret); - currentBlock = nullptr; - break; - } + } - case Instruction::SUICIDE: - { - auto address = stack.pop(); - ext.suicide(address); - // Fall through - } - case Instruction::STOP: - { - builder.CreateRet(builder.getInt64(0)); - currentBlock = nullptr; - break; } + if (!builder.GetInsertBlock()->getTerminator()) // If block not terminated + { + if (basicBlock.begin() == bytecode.size()) // Special final block + { + builder.CreateRet(builder.getInt64(0)); + } + else + { + auto iterCopy = basicBlockPairIt; + ++iterCopy; + auto& next = iterCopy->second; + builder.CreateBr(next); + } } } - // Generate the final basic block. - auto finalPC = bytecode.size(); - auto it = basicBlocks.find(finalPC); - assert(it != basicBlocks.end()); - auto& finalBlock = it->second; - - if (currentBlock != nullptr) - builder.CreateBr(finalBlock); - - builder.SetInsertPoint(finalBlock); - builder.CreateRet(builder.getInt64(0)); - linkBasicBlocks(); return module; From 66123e8b35bfabee15073ff09a8ddccfc62959a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 8 Oct 2014 12:45:46 +0200 Subject: [PATCH 063/396] JUMP test in assembly --- evmcc/lll/stackjump.lll | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 evmcc/lll/stackjump.lll diff --git a/evmcc/lll/stackjump.lll b/evmcc/lll/stackjump.lll new file mode 100644 index 000000000..f5da5e733 --- /dev/null +++ b/evmcc/lll/stackjump.lll @@ -0,0 +1,3 @@ +(asm +0x4 0x6 0x9 0x13 JUMP 0xa SUB 0x0 MSTORE MSIZE 0x0 RETURN 0x0 MSTORE ADD 0x9 JUMP +) From 0ec77d681c94fdf5cf2fad8978dcd7f654925db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 8 Oct 2014 14:56:26 +0200 Subject: [PATCH 064/396] Make the Stack an integral part of BasicBlock --- evmcc/BasicBlock.cpp | 37 +++++++++++++++++++++- evmcc/BasicBlock.h | 51 +++++++++++++++++++++++++----- evmcc/Compiler.cpp | 9 ++---- evmcc/Stack.cpp | 59 ----------------------------------- evmcc/Stack.h | 47 ---------------------------- windows/evmcc.vcxproj | 2 -- windows/evmcc.vcxproj.filters | 2 -- 7 files changed, 82 insertions(+), 125 deletions(-) delete mode 100644 evmcc/Stack.cpp delete mode 100644 evmcc/Stack.h diff --git a/evmcc/BasicBlock.cpp b/evmcc/BasicBlock.cpp index 487de0239..e5cdf386f 100644 --- a/evmcc/BasicBlock.cpp +++ b/evmcc/BasicBlock.cpp @@ -2,6 +2,7 @@ #include "BasicBlock.h" #include +#include namespace evmcc { @@ -11,7 +12,41 @@ const char* BasicBlock::NamePrefix = "Instr."; BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc) : m_beginInstIdx(_beginInstIdx), m_endInstIdx(_endInstIdx), - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)) + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)), + m_stack(m_llvmBB) {} + +void BasicBlock::Stack::push(llvm::Value* _value) +{ + m_backend.push_back(_value); +} + +llvm::Value* BasicBlock::Stack::pop() +{ + if (m_backend.empty()) + { + // Create PHI node + auto i256Ty = llvm::Type::getIntNTy(m_llvmBB->getContext(), 256); + if (m_llvmBB->empty()) + return llvm::PHINode::Create(i256Ty, 0, {}, m_llvmBB); + return llvm::PHINode::Create(i256Ty, 0, {}, m_llvmBB->getFirstNonPHI()); + } + + auto top = m_backend.back(); + m_backend.pop_back(); + return top; +} + +void BasicBlock::Stack::dup(size_t _index) +{ + m_backend.push_back(get(_index)); +} + +void BasicBlock::Stack::swap(size_t _index) +{ + assert(_index != 0); + std::swap(get(0), get(_index)); +} + } \ No newline at end of file diff --git a/evmcc/BasicBlock.h b/evmcc/BasicBlock.h index ef53169d8..500ddb95b 100644 --- a/evmcc/BasicBlock.h +++ b/evmcc/BasicBlock.h @@ -6,13 +6,47 @@ namespace evmcc { -using ProgramCounter = uint64_t; +using ProgramCounter = uint64_t; // TODO: Rename class BasicBlock { public: - using State = std::vector; + class Stack + { + public: + /// Pushes value on stack + void push(llvm::Value* _value); + /// Pops and returns top value + llvm::Value* pop(); + + /// Gets _index'th value from top (counting from 0) + llvm::Value*& get(size_t _index) { return *(m_backend.rbegin() + _index); } + + /// Duplicates _index'th value on stack. + void dup(size_t _index); + + /// Swaps _index'th value on stack with a value on stack top. + /// @param _index Index of value to be swaped. Cannot be 0. + void swap(size_t _index); + + /// Size of the stack + size_t size() const { return m_backend.size(); } + + private: + Stack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB) {} + Stack(const Stack&) = delete; + void operator=(const Stack&) = delete; + friend BasicBlock; + + private: + std::vector m_backend; + + /// LLVM Basic Block where phi nodes are inserted + llvm::BasicBlock* const m_llvmBB; + }; + + /// Basic block name prefix. The rest is beging instruction index. static const char* NamePrefix; explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc); @@ -23,18 +57,19 @@ public: operator llvm::BasicBlock*() { return m_llvmBB; } llvm::BasicBlock* llvm() { return m_llvmBB; } - State& getState() { return m_state; } + Stack& getStack() { return m_stack; } ProgramCounter begin() { return m_beginInstIdx; } ProgramCounter end() { return m_endInstIdx; } private: - ProgramCounter m_beginInstIdx; - ProgramCounter m_endInstIdx; - llvm::BasicBlock* m_llvmBB; + ProgramCounter const m_beginInstIdx; + ProgramCounter const m_endInstIdx; + llvm::BasicBlock* const m_llvmBB; - /// Basic black state vector - current/end values and their positions - State m_state; + /// Basic black state vector (stack) - current/end values and their positions on stack + /// @internal Must be AFTER m_llvmBB + Stack m_stack; }; } \ No newline at end of file diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 9d29a166d..c46dd72c5 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -7,7 +7,6 @@ #include #include "Memory.h" -#include "Stack.h" #include "Ext.h" namespace evmcc @@ -187,9 +186,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) { auto& basicBlock = basicBlockPairIt->second; - - BBStack stack; - stack.setBasicBlock(basicBlock); + auto& stack = basicBlock.getStack(); builder.SetInsertPoint(basicBlock); for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) @@ -799,8 +796,8 @@ void Compiler::linkBasicBlocks() for (auto predIt = llvm::pred_begin(llvmBB); predIt != llvm::pred_end(llvmBB); ++predIt) { auto& predBB = findBasicBlock(*predIt); - assert(valueIdx < predBB.getState().size()); // TODO: Report error - phi->addIncoming(*(predBB.getState().rbegin() + valueIdx), predBB); + assert(valueIdx < predBB.getStack().size()); // TODO: Report error + phi->addIncoming(predBB.getStack().get(valueIdx), predBB); } } } diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp deleted file mode 100644 index fc359f103..000000000 --- a/evmcc/Stack.cpp +++ /dev/null @@ -1,59 +0,0 @@ - -#include "Stack.h" - -#include - -#include - -#include "BasicBlock.h" - -namespace evmcc -{ - -void BBStack::push(llvm::Value* _value) -{ - m_block->getState().push_back(_value); -} - -llvm::Value* BBStack::pop() -{ - auto&& state = m_block->getState(); - if (state.empty()) - { - // Create PHI node - auto i256Ty = llvm::Type::getIntNTy(m_block->llvm()->getContext(), 256); - auto llvmBB = m_block->llvm(); - if (llvmBB->empty()) - return llvm::PHINode::Create(i256Ty, 0, {}, m_block->llvm()); - return llvm::PHINode::Create(i256Ty, 0, {}, llvmBB->getFirstNonPHI()); - } - - auto top = state.back(); - state.pop_back(); - return top; -} - -void BBStack::setBasicBlock(BasicBlock& _newBlock) -{ - // Current block keeps end state - // Just update pointer to current block - // New block should have empty state - assert(_newBlock.getState().empty()); - m_block = &_newBlock; -} - -void BBStack::dup(size_t _index) -{ - auto&& state = m_block->getState(); - auto value = *(state.rbegin() + _index); - state.push_back(value); -} - -void BBStack::swap(size_t _index) -{ - assert(_index != 0); - auto&& state = m_block->getState(); - std::swap(*state.rbegin(), *(state.rbegin() + _index)); -} - -} diff --git a/evmcc/Stack.h b/evmcc/Stack.h deleted file mode 100644 index 4b81986b0..000000000 --- a/evmcc/Stack.h +++ /dev/null @@ -1,47 +0,0 @@ - -#pragma once - -#include - -namespace evmcc -{ -class BasicBlock; - -/** - Stack adapter for Basic Block - - Transforms stack to SSA: tracks values and their positions on the imaginary stack used inside a basic block. - TODO: Integrate into BasicBlock class - */ -class BBStack -{ -public: - BBStack() = default; - BBStack(const BBStack&) = delete; - void operator=(const BBStack&) = delete; - - /** - Changes current basic block (if any) with a new one with empty state. - */ - void setBasicBlock(BasicBlock& _newBlock); - - void push(llvm::Value* _value); - llvm::Value* pop(); - - /** - Duplicates _index'th value on stack. - */ - void dup(size_t _index); - - /** - Swaps _index'th value on stack with a value on stack top. - @param _index Index of value to be swaped. Cannot be 0. - */ - void swap(size_t _index); - -private: - BasicBlock* m_block = nullptr; ///< Current basic block -}; - - -} \ No newline at end of file diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 8226abb6c..ecf23fa05 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -26,7 +26,6 @@ - @@ -36,7 +35,6 @@ - diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 05f375ac5..29ff77ba5 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -4,7 +4,6 @@ - @@ -14,7 +13,6 @@ - From 1a4cbdabef571bdfe2fcaba024f53fe8f64fbfc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 9 Oct 2014 09:33:31 +0200 Subject: [PATCH 065/396] EXP instruction. [Delivers #79736422] --- evmcc/Compiler.cpp | 9 +++++++++ evmcc/Ext.cpp | 18 ++++++++++++++++++ evmcc/Ext.h | 2 ++ evmcc/bytecode/arithmetic_test.evm | 2 +- evmcc/lll/arithmetic_test.lll | 8 ++++++++ 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index c46dd72c5..880487705 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -274,6 +274,15 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::EXP: + { + auto left = stack.pop(); + auto right = stack.pop(); + auto ret = ext.exp(left, right); + stack.push(ret); + break; + } + case Instruction::NEG: { auto top = stack.pop(); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 8266bd728..121103354 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -93,6 +93,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_call = Function::Create(FunctionType::get(m_builder.getVoidTy(), args, false), Linkage::ExternalLinkage, "ext_call", module); m_bswap = Intrinsic::getDeclaration(module, Intrinsic::bswap, i256Ty); m_sha3 = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_sha3", module); + m_exp = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_exp", module); m_builder.CreateCall(m_init, m_data); @@ -196,6 +197,15 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) return hash; } +llvm::Value* Ext::exp(llvm::Value* _left, llvm::Value* _right) +{ + m_builder.CreateStore(_left, m_args[0]); + m_builder.CreateStore(_right, m_arg2); + llvm::Value* args[] = {m_args[0], m_arg2, m_args[1]}; + m_builder.CreateCall(m_exp, args); + return m_builder.CreateLoad(m_args[1]); +} + extern "C" { @@ -308,6 +318,14 @@ EXPORT void ext_sha3(i256* _inOff, i256* _inSize, i256* _ret) *_ret = *reinterpret_cast(&hash); } +EXPORT void ext_exp(i256* _left, i256* _right, i256* _ret) +{ + dev::bigint left = llvm2eth(*_left); + dev::bigint right = llvm2eth(*_right); + auto ret = static_cast(boost::multiprecision::powm(left, right, dev::bigint(2) << 256)); + *_ret = eth2llvm(ret); +} + } } diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 7801d0540..302991854 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -39,6 +39,7 @@ public: llvm::Value* call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); + llvm::Value* exp(llvm::Value* _left, llvm::Value* _right); private: llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); @@ -66,6 +67,7 @@ private: llvm::Function* m_call; llvm::Function* m_bswap; llvm::Function* m_sha3; + llvm::Function* m_exp; }; diff --git a/evmcc/bytecode/arithmetic_test.evm b/evmcc/bytecode/arithmetic_test.evm index 67e86b310..c7a029f52 100644 --- a/evmcc/bytecode/arithmetic_test.evm +++ b/evmcc/bytecode/arithmetic_test.evm @@ -1 +1 @@ -60016001900160070260050160029004600490066021900560150160030260059007600303 +60016001900160070260050160029004600490066021900560150160030260059007600303600960110860005460086000f2 diff --git a/evmcc/lll/arithmetic_test.lll b/evmcc/lll/arithmetic_test.lll index e2c14d4c7..4757a7420 100644 --- a/evmcc/lll/arithmetic_test.lll +++ b/evmcc/lll/arithmetic_test.lll @@ -26,4 +26,12 @@ SWAP1 SMOD;; 3 3 SUB ;; 0 +9 +17 +EXP ;; 17^9 +0 +MSTORE +8 +0 +RETURN ) \ No newline at end of file From 5e3113e49e21818984001febb651e47ed418b83b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 9 Oct 2014 11:37:19 +0200 Subject: [PATCH 066/396] Introducing GasMeter --- evmcc/Compiler.cpp | 4 ++- evmcc/GasMeter.cpp | 49 +++++++++++++++++++++++++++++++++++ evmcc/GasMeter.h | 9 +++++++ windows/evmcc.vcxproj | 2 ++ windows/evmcc.vcxproj.filters | 2 ++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 evmcc/GasMeter.cpp create mode 100644 evmcc/GasMeter.h diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 880487705..91bc692eb 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -12,6 +12,9 @@ namespace evmcc { +using dev::eth::Instruction; +using namespace dev::eth; // We should move all the JIT code into dev::eth namespace + struct { llvm::Type* word8; @@ -191,7 +194,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) { - using dev::eth::Instruction; auto inst = static_cast(bytecode[currentPC]); switch (inst) { diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp new file mode 100644 index 000000000..3687cfed3 --- /dev/null +++ b/evmcc/GasMeter.cpp @@ -0,0 +1,49 @@ + +#include "GasMeter.h" + +#include +#include + +namespace evmcc +{ + +using namespace dev::eth; // We should move all the JIT code into dev::eth namespace + +namespace +{ + +uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to FeeSructure +{ + switch (inst) + { + case Instruction::STOP: + case Instruction::SUICIDE: + return 0; + + case Instruction::SSTORE: + return static_cast(c_sstoreGas); + + case Instruction::SLOAD: + return static_cast(c_sloadGas); + + case Instruction::SHA3: + return static_cast(c_sha3Gas); + + case Instruction::BALANCE: + return static_cast(c_sha3Gas); + + case Instruction::CALL: + case Instruction::CALLCODE: + return static_cast(c_callGas); + + case Instruction::CREATE: + return static_cast(c_createGas); + + default: // Assumes instruction code is valid + return static_cast(c_stepGas);; + } +} + +} + +} \ No newline at end of file diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h new file mode 100644 index 000000000..c234a4ab6 --- /dev/null +++ b/evmcc/GasMeter.h @@ -0,0 +1,9 @@ + +#pragma once + +#include + +namespace evmcc +{ + +} \ No newline at end of file diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index ecf23fa05..2a6eac0c5 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -24,6 +24,7 @@ + @@ -33,6 +34,7 @@ + diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 29ff77ba5..0fa1fc8c1 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -9,6 +9,7 @@ + @@ -18,5 +19,6 @@ + \ No newline at end of file From 989afa940604dd8417386010e2607bdc3f9d082f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 9 Oct 2014 12:52:48 +0200 Subject: [PATCH 067/396] Decrement global gas value by instruction step cost [#79942174] --- evmcc/Compiler.cpp | 4 ++++ evmcc/GasMeter.cpp | 22 +++++++++++++++++++++- evmcc/GasMeter.h | 17 +++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 91bc692eb..720570277 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -8,6 +8,7 @@ #include "Memory.h" #include "Ext.h" +#include "GasMeter.h" namespace evmcc { @@ -182,6 +183,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Init runtime structures. auto memory = Memory(builder, module.get()); auto ext = Ext(builder, module.get()); + GasMeter gasMeter(builder, module.get()); // Jump to first instruction builder.CreateBr(basicBlocks.begin()->second); @@ -195,6 +197,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) { auto inst = static_cast(bytecode[currentPC]); + gasMeter.check(inst); + switch (inst) { diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 3687cfed3..af08d13b7 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -1,6 +1,9 @@ #include "GasMeter.h" +#include +#include + #include #include @@ -9,7 +12,7 @@ namespace evmcc using namespace dev::eth; // We should move all the JIT code into dev::eth namespace -namespace +namespace // Helper functions { uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to FeeSructure @@ -46,4 +49,21 @@ uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to F } +GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): + m_builder(_builder) +{ + m_gas = new llvm::GlobalVariable(*_module, m_builder.getIntNTy(256), false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(m_builder.getIntNTy(256)), "gas"); + m_gas->setUnnamedAddr(true); // Address is not important + + //llvm::Function::Create() +} + +void GasMeter::check(Instruction _inst) +{ + auto stepCost = getStepCost(_inst); + auto before = m_builder.CreateLoad(m_gas, "gas.before"); + auto after = m_builder.CreateSub(before, m_builder.getIntN(256, stepCost)); + m_builder.CreateStore(after, m_gas); +} + } \ No newline at end of file diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index c234a4ab6..f50438c9a 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -1,9 +1,26 @@ #pragma once +#include + #include namespace evmcc { +class GasMeter +{ +public: + GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* module); + + GasMeter(const GasMeter&) = delete; + void operator=(GasMeter) = delete; + + void check(dev::eth::Instruction _inst); + +private: + llvm::IRBuilder<>& m_builder; + llvm::GlobalVariable* m_gas; +}; + } \ No newline at end of file From f8813b2843bd80cb68059e55ec515f745ae69956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 9 Oct 2014 13:17:54 +0200 Subject: [PATCH 068/396] Cleanup LLVM types usage --- evmcc/BasicBlock.cpp | 7 ++++--- evmcc/Compiler.cpp | 36 ++++++++++++++++------------------- evmcc/GasMeter.cpp | 4 +++- evmcc/Type.cpp | 16 ++++++++++++++++ evmcc/Type.h | 16 ++++++++++++++++ windows/evmcc.vcxproj | 2 ++ windows/evmcc.vcxproj.filters | 2 ++ 7 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 evmcc/Type.cpp create mode 100644 evmcc/Type.h diff --git a/evmcc/BasicBlock.cpp b/evmcc/BasicBlock.cpp index e5cdf386f..de18dbba0 100644 --- a/evmcc/BasicBlock.cpp +++ b/evmcc/BasicBlock.cpp @@ -4,6 +4,8 @@ #include #include +#include "Type.h" + namespace evmcc { @@ -27,10 +29,9 @@ llvm::Value* BasicBlock::Stack::pop() if (m_backend.empty()) { // Create PHI node - auto i256Ty = llvm::Type::getIntNTy(m_llvmBB->getContext(), 256); if (m_llvmBB->empty()) - return llvm::PHINode::Create(i256Ty, 0, {}, m_llvmBB); - return llvm::PHINode::Create(i256Ty, 0, {}, m_llvmBB->getFirstNonPHI()); + return llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB); + return llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI()); } auto top = m_backend.back(); diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 720570277..d26c7850e 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -6,6 +6,7 @@ #include +#include "Type.h" #include "Memory.h" #include "Ext.h" #include "GasMeter.h" @@ -20,9 +21,6 @@ struct { llvm::Type* word8; llvm::Type* word8ptr; - llvm::Type* word256; - llvm::Type* word256ptr; - llvm::Type* word256arr; llvm::Type* size; llvm::Type* Void; llvm::Type* WordLowPrecision; @@ -30,12 +28,10 @@ struct Compiler::Compiler() { + Type::init(llvm::getGlobalContext()); auto& context = llvm::getGlobalContext(); Types.word8 = llvm::Type::getInt8Ty(context); Types.word8ptr = llvm::Type::getInt8PtrTy(context); - Types.word256 = llvm::Type::getIntNTy(context, 256); - Types.word256ptr = Types.word256->getPointerTo(); - Types.word256arr = llvm::ArrayType::get(Types.word256, 100); Types.size = llvm::Type::getInt64Ty(context); Types.Void = llvm::Type::getVoidTy(context); @@ -227,7 +223,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); auto res128 = builder.CreateMul(lhs128, rhs128); - auto res256 = builder.CreateZExt(res128, Types.word256); + auto res256 = builder.CreateZExt(res128, Type::i256); stack.push(res256); break; } @@ -239,7 +235,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); auto res128 = builder.CreateUDiv(lhs128, rhs128); - auto res256 = builder.CreateZExt(res128, Types.word256); + auto res256 = builder.CreateZExt(res128, Type::i256); stack.push(res256); break; } @@ -251,7 +247,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); auto res128 = builder.CreateSDiv(lhs128, rhs128); - auto res256 = builder.CreateSExt(res128, Types.word256); + auto res256 = builder.CreateSExt(res128, Type::i256); stack.push(res256); break; } @@ -263,7 +259,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); auto res128 = builder.CreateURem(lhs128, rhs128); - auto res256 = builder.CreateZExt(res128, Types.word256); + auto res256 = builder.CreateZExt(res128, Type::i256); stack.push(res256); break; } @@ -275,7 +271,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); auto res128 = builder.CreateSRem(lhs128, rhs128); - auto res256 = builder.CreateSExt(res128, Types.word256); + auto res256 = builder.CreateSExt(res128, Type::i256); stack.push(res256); break; } @@ -292,7 +288,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::NEG: { auto top = stack.pop(); - auto zero = ConstantInt::get(Types.word256, 0); + auto zero = ConstantInt::get(Type::i256, 0); auto res = builder.CreateSub(zero, top); stack.push(res); break; @@ -303,7 +299,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = builder.CreateICmpULT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); + auto res256 = builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -313,7 +309,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = builder.CreateICmpUGT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); + auto res256 = builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -323,7 +319,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = builder.CreateICmpSLT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); + auto res256 = builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -333,7 +329,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = builder.CreateICmpSGT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); + auto res256 = builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -343,7 +339,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = builder.CreateICmpEQ(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Types.word256); + auto res256 = builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -351,9 +347,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::NOT: { auto top = stack.pop(); - auto zero = ConstantInt::get(Types.word256, 0); + auto zero = ConstantInt::get(Type::i256, 0); auto iszero = builder.CreateICmpEQ(top, zero, "iszero"); - auto result = builder.CreateZExt(iszero, Types.word256); + auto result = builder.CreateZExt(iszero, Type::i256); stack.push(result); break; } @@ -584,7 +580,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) stack.pop(); auto top = stack.pop(); - auto zero = ConstantInt::get(Types.word256, 0); + auto zero = ConstantInt::get(Type::i256, 0); auto cond = builder.CreateICmpNE(top, zero, "nonzero"); auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second; auto& followBlock = basicBlocks.find(currentPC + 1)->second; diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index af08d13b7..4fdfde469 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -7,6 +7,8 @@ #include #include +#include "Type.h" + namespace evmcc { @@ -52,7 +54,7 @@ uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to F GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_builder(_builder) { - m_gas = new llvm::GlobalVariable(*_module, m_builder.getIntNTy(256), false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(m_builder.getIntNTy(256)), "gas"); + m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::i256), "gas"); m_gas->setUnnamedAddr(true); // Address is not important //llvm::Function::Create() diff --git a/evmcc/Type.cpp b/evmcc/Type.cpp new file mode 100644 index 000000000..c66cd6de6 --- /dev/null +++ b/evmcc/Type.cpp @@ -0,0 +1,16 @@ + +#include "Type.h" + +#include + +namespace evmcc +{ + +llvm::Type* Type::i256; + +void Type::init(llvm::LLVMContext& _context) +{ + i256 = llvm::Type::getIntNTy(_context, 256); +} + +} \ No newline at end of file diff --git a/evmcc/Type.h b/evmcc/Type.h new file mode 100644 index 000000000..0d7f3e428 --- /dev/null +++ b/evmcc/Type.h @@ -0,0 +1,16 @@ + +#pragma once + +#include + +namespace evmcc +{ + +struct Type +{ + static llvm::Type* i256; + + static void init(llvm::LLVMContext& _context); +}; + +} \ No newline at end of file diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 2a6eac0c5..dbd9d1b57 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -27,6 +27,7 @@ + @@ -37,6 +38,7 @@ + diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 0fa1fc8c1..f84ec6ca3 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -10,6 +10,7 @@ + @@ -20,5 +21,6 @@ + \ No newline at end of file From 6c7de9fa0b3e4f2d7c63fcea8e0d05b0754570ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 9 Oct 2014 14:44:25 +0200 Subject: [PATCH 069/396] Cleanup LLVM types usage --- evmcc/Compiler.cpp | 36 ++++++++++-------------------------- evmcc/Type.cpp | 2 ++ evmcc/Type.h | 4 ++++ 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index d26c7850e..d1fd3eb1a 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -17,26 +17,10 @@ namespace evmcc using dev::eth::Instruction; using namespace dev::eth; // We should move all the JIT code into dev::eth namespace -struct -{ - llvm::Type* word8; - llvm::Type* word8ptr; - llvm::Type* size; - llvm::Type* Void; - llvm::Type* WordLowPrecision; -} Types; Compiler::Compiler() { Type::init(llvm::getGlobalContext()); - auto& context = llvm::getGlobalContext(); - Types.word8 = llvm::Type::getInt8Ty(context); - Types.word8ptr = llvm::Type::getInt8PtrTy(context); - Types.size = llvm::Type::getInt64Ty(context); - Types.Void = llvm::Type::getVoidTy(context); - - // TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required - Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64); } void Compiler::createBasicBlocks(const dev::bytes& bytecode) @@ -220,8 +204,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); auto res128 = builder.CreateMul(lhs128, rhs128); auto res256 = builder.CreateZExt(res128, Type::i256); stack.push(res256); @@ -232,8 +216,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); auto res128 = builder.CreateUDiv(lhs128, rhs128); auto res256 = builder.CreateZExt(res128, Type::i256); stack.push(res256); @@ -244,8 +228,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); auto res128 = builder.CreateSDiv(lhs128, rhs128); auto res256 = builder.CreateSExt(res128, Type::i256); stack.push(res256); @@ -256,8 +240,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); auto res128 = builder.CreateURem(lhs128, rhs128); auto res256 = builder.CreateZExt(res128, Type::i256); stack.push(res256); @@ -268,8 +252,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision); + auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); auto res128 = builder.CreateSRem(lhs128, rhs128); auto res256 = builder.CreateSExt(res128, Type::i256); stack.push(res256); diff --git a/evmcc/Type.cpp b/evmcc/Type.cpp index c66cd6de6..c19c49644 100644 --- a/evmcc/Type.cpp +++ b/evmcc/Type.cpp @@ -7,10 +7,12 @@ namespace evmcc { llvm::Type* Type::i256; +llvm::Type* Type::lowPrecision; void Type::init(llvm::LLVMContext& _context) { i256 = llvm::Type::getIntNTy(_context, 256); + lowPrecision = llvm::Type::getInt64Ty(_context); } } \ No newline at end of file diff --git a/evmcc/Type.h b/evmcc/Type.h index 0d7f3e428..425dae345 100644 --- a/evmcc/Type.h +++ b/evmcc/Type.h @@ -10,6 +10,10 @@ struct Type { static llvm::Type* i256; + /// Type for doing low precision arithmetics where 256-bit precision is not supported by native target + /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required + static llvm::Type* lowPrecision; + static void init(llvm::LLVMContext& _context); }; From b63b28b0987f34ed02c66d6db6af336710d2e8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 9 Oct 2014 15:44:41 +0200 Subject: [PATCH 070/396] Generate gas checking function --- evmcc/GasMeter.cpp | 16 ++++++++++++---- evmcc/GasMeter.h | 1 + evmcc/Type.cpp | 2 ++ evmcc/Type.h | 2 ++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 4fdfde469..2006f319f 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -57,15 +57,23 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::i256), "gas"); m_gas->setUnnamedAddr(true); // Address is not important - //llvm::Function::Create() + auto pt = m_builder.GetInsertPoint(); + auto bb = m_builder.GetInsertBlock(); + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", _module); + auto gasCheckBB = llvm::BasicBlock::Create(_builder.getContext(), {}, m_gasCheckFunc); + m_builder.SetInsertPoint(gasCheckBB); + llvm::Value* cost = m_gasCheckFunc->arg_begin(); + llvm::Value* gas = m_builder.CreateLoad(m_gas); + gas = m_builder.CreateSub(gas, cost); + m_builder.CreateStore(gas, m_gas); + m_builder.CreateRetVoid(); + m_builder.SetInsertPoint(bb, pt); } void GasMeter::check(Instruction _inst) { auto stepCost = getStepCost(_inst); - auto before = m_builder.CreateLoad(m_gas, "gas.before"); - auto after = m_builder.CreateSub(before, m_builder.getIntN(256, stepCost)); - m_builder.CreateStore(after, m_gas); + m_builder.CreateCall(m_gasCheckFunc, m_builder.getIntN(256, stepCost)); } } \ No newline at end of file diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index f50438c9a..e2ee26a71 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -21,6 +21,7 @@ public: private: llvm::IRBuilder<>& m_builder; llvm::GlobalVariable* m_gas; + llvm::Function* m_gasCheckFunc; }; } \ No newline at end of file diff --git a/evmcc/Type.cpp b/evmcc/Type.cpp index c19c49644..b9063569b 100644 --- a/evmcc/Type.cpp +++ b/evmcc/Type.cpp @@ -8,11 +8,13 @@ namespace evmcc llvm::Type* Type::i256; llvm::Type* Type::lowPrecision; +llvm::Type* Type::Void; void Type::init(llvm::LLVMContext& _context) { i256 = llvm::Type::getIntNTy(_context, 256); lowPrecision = llvm::Type::getInt64Ty(_context); + Void = llvm::Type::getVoidTy(_context); } } \ No newline at end of file diff --git a/evmcc/Type.h b/evmcc/Type.h index 425dae345..32459dca4 100644 --- a/evmcc/Type.h +++ b/evmcc/Type.h @@ -14,6 +14,8 @@ struct Type /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required static llvm::Type* lowPrecision; + static llvm::Type* Void; + static void init(llvm::LLVMContext& _context); }; From dd3ae798b468b759d302d5336c63a630e3f1b5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 9 Oct 2014 16:10:12 +0200 Subject: [PATCH 071/396] Disable gas checking for now (does not work and makes IR code hard to read) [#79942174] --- evmcc/Compiler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index d1fd3eb1a..9a46313b6 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -177,7 +177,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) { auto inst = static_cast(bytecode[currentPC]); - gasMeter.check(inst); + + // Disable for now + //gasMeter.check(inst); switch (inst) { From e9153795393a0cab8fd07d0b9c087dc059c67517 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 10 Oct 2014 10:01:26 +0100 Subject: [PATCH 072/396] Implementing JUMP/JUMPDEST (work in progress) --- evmcc/BasicBlock.cpp | 9 ++- evmcc/BasicBlock.h | 3 +- evmcc/Compiler.cpp | 179 ++++++++++++++++++++++++++++++++----------- evmcc/Compiler.h | 20 ++++- 4 files changed, 161 insertions(+), 50 deletions(-) diff --git a/evmcc/BasicBlock.cpp b/evmcc/BasicBlock.cpp index e5cdf386f..c7c98aca5 100644 --- a/evmcc/BasicBlock.cpp +++ b/evmcc/BasicBlock.cpp @@ -16,6 +16,13 @@ BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, m_stack(m_llvmBB) {} +BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc) : + m_beginInstIdx(0), + m_endInstIdx(0), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), + m_stack(m_llvmBB) +{} + void BasicBlock::Stack::push(llvm::Value* _value) { @@ -49,4 +56,4 @@ void BasicBlock::Stack::swap(size_t _index) std::swap(get(0), get(_index)); } -} \ No newline at end of file +} diff --git a/evmcc/BasicBlock.h b/evmcc/BasicBlock.h index 500ddb95b..3c47db328 100644 --- a/evmcc/BasicBlock.h +++ b/evmcc/BasicBlock.h @@ -50,6 +50,7 @@ public: static const char* NamePrefix; explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc); + explicit BasicBlock(std::string _name, llvm::Function* _mainFunc); BasicBlock(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete; @@ -72,4 +73,4 @@ private: Stack m_stack; }; -} \ No newline at end of file +} diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 880487705..02c391251 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -1,6 +1,8 @@ #include "Compiler.h" +#include + #include #include @@ -14,17 +16,19 @@ namespace evmcc struct { - llvm::Type* word8; + llvm::IntegerType* word8; llvm::Type* word8ptr; - llvm::Type* word256; + llvm::IntegerType* word256; llvm::Type* word256ptr; llvm::Type* word256arr; - llvm::Type* size; + llvm::IntegerType* size; llvm::Type* Void; llvm::Type* WordLowPrecision; } Types; Compiler::Compiler() + : m_finalBlock(nullptr) + , m_badJumpBlock(nullptr) { auto& context = llvm::getGlobalContext(); Types.word8 = llvm::Type::getInt8Ty(context); @@ -39,15 +43,31 @@ Compiler::Compiler() Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64); } +namespace +{ + void validateSplitPoints(cons dev::bytes& bytecode, std::set splitPoints) + { + + } +} + void Compiler::createBasicBlocks(const dev::bytes& bytecode) { - std::set splitPoints; // Sorted collections of instruction indecies where basic blocks start/end + std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end splitPoints.insert(0); // First basic block + std::map directJumpTargets; + std::vector indirectJumpTargets; + + boost::dynamic_bitset<> validJumpTargets(bytecode.size()); + for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr) { using dev::eth::Instruction; + ProgramCounter currentPC = curr - bytecode.cbegin(); + validJumpTargets[currentPC] = 1; + auto inst = static_cast(*curr); switch (inst) { @@ -86,7 +106,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) { auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; auto next = curr + numBytes + 1; - if (next == bytecode.cend()) + if (next >= bytecode.cend()) break; auto nextInst = static_cast(*next); @@ -101,34 +121,30 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) val |= *iter; } - // Create a block following the JUMP. - if (next + 1 < bytecode.cend()) - { - ProgramCounter nextPC = (next + 1 - bytecode.cbegin()); - splitPoints.insert(nextPC); - } - // Create a block for the JUMP target. ProgramCounter targetPC = val.convert_to(); + if (targetPC > bytecode.size()) + targetPC = bytecode.size(); splitPoints.insert(targetPC); ProgramCounter jumpPC = (next - bytecode.cbegin()); - jumpTargets[jumpPC] = targetPC; - - curr += 1; // skip over JUMP + directJumpTargets[jumpPC] = targetPC; } curr += numBytes; break; } - case Instruction::JUMP: - case Instruction::JUMPI: + case Instruction::JUMPDEST: { - std::cerr << "JUMP/JUMPI at " << (curr - bytecode.cbegin()) << " not preceded by PUSH\n"; - std::exit(1); + // A basic block starts here. + splitPoints.insert(currentPC); + indirectJumpTargets.push_back(currentPC); + break; } + case Instruction::JUMP: + case Instruction::JUMPI: case Instruction::RETURN: case Instruction::STOP: case Instruction::SUICIDE: @@ -136,8 +152,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) // Create a basic block starting at the following instruction. if (curr + 1 < bytecode.cend()) { - ProgramCounter nextPC = (curr + 1 - bytecode.cbegin()); - splitPoints.insert(nextPC); + splitPoints.insert(currentPC + 1); } break; } @@ -147,14 +162,40 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) } } - splitPoints.insert(bytecode.size()); // For final block - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + for (auto it = splitPoints.cbegin(); it != splitPoints.cend() && *it < bytecode.size(); ++it) + { + if (! validJumpTargets[*it]) + { + std::cerr "Jump to invalid PC " << *it << "\n"; + std::exit(1); + } + } + + for (auto it = splitPoints.cbegin(); it != splitPoints.cend() && *it < bytecode.size();) { auto beginInstIdx = *it; ++it; - auto endInstIdx = it != splitPoints.cend() ? *it : beginInstIdx; // For final block + auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size(); basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc)); } + + m_finalBlock = std::make_unique("FinalBlock", m_mainFunc); + m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc); + + for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) + { + if (it->second >= bytecode.size()) + m_directJumpTargets[it->first] = m_finalBlock.get(); + else + m_directJumpTargets[it->first] = &basicBlocks.find(it->second)->second; + } + for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) + { + if (*it >= bytecode.size()) + m_indirectJumpTargets.push_back(m_finalBlock.get()); + else + m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); + } } std::unique_ptr Compiler::compile(const dev::bytes& bytecode) @@ -559,30 +600,69 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } case Instruction::JUMP: + case Instruction::JUMPI: { - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); + // Generate direct jump iff: + // 1. this is not the first instruction in the block + // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) + // Otherwise generate a indirect jump (a switch). + if (currentPC != basicBlock.begin()) + { + auto pairIter = m_directJumpTargets.find(currentPC); + if (pairIter != m_directJumpTargets.end()) + { + auto targetBlock = pairIter->second; + + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + + if (inst == Instruction::JUMP) + { + builder.CreateBr(targetBlock->llvm()); + } + else // JUMPI + { + auto top = stack.pop(); + auto zero = ConstantInt::get(Types.word256, 0); + auto cond = builder.CreateICmpNE(top, zero, "nonzero"); + + // Assume the basic blocks are properly ordered: + auto nextBBIter = basicBlockPairIt; + ++nextBBIter; + assert (nextBBIter != basicBlocks.end()); + auto& followBlock = nextBBIter->second; + builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm()); + } + break; + } + } + + if (inst == Instruction::JUMPI) + { + std::cerr << "Indirect JUMPI is not supported yet (at PC " + << currentPC << ")\n"; + std::exit(1); + } + + // Generate switch for indirect jump. + auto dest = stack.pop(); + auto switchInstr = builder.CreateSwitch(dest, m_badJumpBlock->llvm(), + m_indirectJumpTargets.size()); + for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) + { + auto& bb = *it; + auto dest = ConstantInt::get(Types.word256, bb->begin()); + switchInstr->addCase(dest, bb->llvm()); + } - auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second; - builder.CreateBr(targetBlock); break; } - case Instruction::JUMPI: + case Instruction::JUMPDEST: { - assert(currentPC + 1 < bytecode.size()); - - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); - - auto top = stack.pop(); - auto zero = ConstantInt::get(Types.word256, 0); - auto cond = builder.CreateICmpNE(top, zero, "nonzero"); - auto& targetBlock = basicBlocks.find(jumpTargets[currentPC])->second; - auto& followBlock = basicBlocks.find(currentPC + 1)->second; - builder.CreateCondBr(cond, targetBlock, followBlock); + // Extra asserts just in case. + assert(currentPC == basicBlock.begin()); break; } @@ -754,17 +834,18 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } } - } if (!builder.GetInsertBlock()->getTerminator()) // If block not terminated { - if (basicBlock.begin() == bytecode.size()) // Special final block + if (basicBlock.end() == bytecode.size()) { - builder.CreateRet(builder.getInt64(0)); + // Branch from the last regular block to the final block. + builder.CreateBr(m_finalBlock->llvm()); } else { + // Branch to the next block. auto iterCopy = basicBlockPairIt; ++iterCopy; auto& next = iterCopy->second; @@ -773,6 +854,14 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } } + // Code for special blocks: + builder.SetInsertPoint(m_finalBlock->llvm()); + builder.CreateRet(builder.getInt64(0)); + + // TODO: throw an exception or something + builder.SetInsertPoint(m_badJumpBlock->llvm()); + builder.CreateRet(builder.getInt64(1)); + linkBasicBlocks(); return module; diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 52a6bc9ac..f57d800a4 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -32,14 +32,28 @@ private: std::map basicBlocks; /** - * Maps a pc at which there is a JUMP or JUMPI to the target pc of the jump. + * Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. */ - std::map jumpTargets; + std::map m_directJumpTargets; + + /** + * A list of possible blocks to which there may be indirect jumps. + */ + std::vector m_indirectJumpTargets; -private: /// Collection of basic blocks in program //std::vector m_basicBlocks; + /** + * Final block for normal (non-exceptional) execution. + */ + std::unique_ptr m_finalBlock; + + /** + * Default destination for indirect jumps. + */ + std::unique_ptr m_badJumpBlock; + /// Main program function llvm::Function* m_mainFunc = nullptr; }; From 209640c1f36db368ade2af76ee98e307bcc7ebf4 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 10 Oct 2014 10:03:12 +0100 Subject: [PATCH 073/396] test cases for JUMP --- evmcc/test/jump/jump1.evm | 1 + evmcc/test/jump/jump1.lll | 11 +++++++++++ evmcc/test/jump/jump2.evm | 1 + evmcc/test/jump/jump2.lll | 10 ++++++++++ evmcc/test/jump/jump3.evm | 1 + evmcc/test/jump/jump3.lll | 10 ++++++++++ evmcc/test/jump/jump4.evm | 1 + evmcc/test/jump/jump4.lll | 17 +++++++++++++++++ evmcc/test/jump/jump5.evm | 1 + evmcc/test/jump/jump5.lll | 16 ++++++++++++++++ evmcc/test/jump/jump6.evm | 1 + evmcc/test/jump/jump6.lll | 32 ++++++++++++++++++++++++++++++++ 12 files changed, 102 insertions(+) create mode 100644 evmcc/test/jump/jump1.evm create mode 100644 evmcc/test/jump/jump1.lll create mode 100644 evmcc/test/jump/jump2.evm create mode 100644 evmcc/test/jump/jump2.lll create mode 100644 evmcc/test/jump/jump3.evm create mode 100644 evmcc/test/jump/jump3.lll create mode 100644 evmcc/test/jump/jump4.evm create mode 100644 evmcc/test/jump/jump4.lll create mode 100644 evmcc/test/jump/jump5.evm create mode 100644 evmcc/test/jump/jump5.lll create mode 100644 evmcc/test/jump/jump6.evm create mode 100644 evmcc/test/jump/jump6.lll diff --git a/evmcc/test/jump/jump1.evm b/evmcc/test/jump/jump1.evm new file mode 100644 index 000000000..0df9b4036 --- /dev/null +++ b/evmcc/test/jump/jump1.evm @@ -0,0 +1 @@ +600458006001600154 diff --git a/evmcc/test/jump/jump1.lll b/evmcc/test/jump/jump1.lll new file mode 100644 index 000000000..33119edb3 --- /dev/null +++ b/evmcc/test/jump/jump1.lll @@ -0,0 +1,11 @@ +;; Direct JUMP. +;; output: memory[1] == 1 + +(asm +4 ;; 0 +JUMP ;; 2 +STOP ;; 3 +1 ;; 4 +1 ;; 6 +MSTORE ;; 8 +) \ No newline at end of file diff --git a/evmcc/test/jump/jump2.evm b/evmcc/test/jump/jump2.evm new file mode 100644 index 000000000..35d75941d --- /dev/null +++ b/evmcc/test/jump/jump2.evm @@ -0,0 +1 @@ +6008586001600154 diff --git a/evmcc/test/jump/jump2.lll b/evmcc/test/jump/jump2.lll new file mode 100644 index 000000000..a70d50ecb --- /dev/null +++ b/evmcc/test/jump/jump2.lll @@ -0,0 +1,10 @@ +;; Direct JUMP to the end of code. +;; output: memory should have size 0. + +(asm +8 ;; 0 +JUMP ;; 2 +1 ;; 3 +1 ;; 5 +MSTORE ;; 7 +) \ No newline at end of file diff --git a/evmcc/test/jump/jump3.evm b/evmcc/test/jump/jump3.evm new file mode 100644 index 000000000..599d4a764 --- /dev/null +++ b/evmcc/test/jump/jump3.evm @@ -0,0 +1 @@ +602a586001600154 diff --git a/evmcc/test/jump/jump3.lll b/evmcc/test/jump/jump3.lll new file mode 100644 index 000000000..bc897e30c --- /dev/null +++ b/evmcc/test/jump/jump3.lll @@ -0,0 +1,10 @@ +;; Direct JUMP past the end of code. +;; output: memory should have size 0. + +(asm +42 +JUMP +1 +1 +MSTORE +) \ No newline at end of file diff --git a/evmcc/test/jump/jump4.evm b/evmcc/test/jump/jump4.evm new file mode 100644 index 000000000..41713f43e --- /dev/null +++ b/evmcc/test/jump/jump4.evm @@ -0,0 +1 @@ +600b6009580000600558005d6001600154 diff --git a/evmcc/test/jump/jump4.lll b/evmcc/test/jump/jump4.lll new file mode 100644 index 000000000..131baee2d --- /dev/null +++ b/evmcc/test/jump/jump4.lll @@ -0,0 +1,17 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +(asm +11 ;; 0 +9 ;; 2 +JUMP ;; 4 --> 9 +STOP ;; 5 +STOP ;; 6 +5 ;; 7 +JUMP ;; 9 --> 11 +STOP ;; 10 +JUMPDEST +1 ;; 11 +1 +MSTORE +) \ No newline at end of file diff --git a/evmcc/test/jump/jump5.evm b/evmcc/test/jump/jump5.evm new file mode 100644 index 000000000..c36d9615b --- /dev/null +++ b/evmcc/test/jump/jump5.evm @@ -0,0 +1 @@ +6005600e585d600160015400600f5800 diff --git a/evmcc/test/jump/jump5.lll b/evmcc/test/jump/jump5.lll new file mode 100644 index 000000000..d28b7d4ac --- /dev/null +++ b/evmcc/test/jump/jump5.lll @@ -0,0 +1,16 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +(asm +5 ;; 0 +14 ;; 2 +JUMP ;; 4 --> 14 +JUMPDEST ;; 5 +1 ;; 6 +1 ;; 8 +MSTORE ;; 10 +STOP ;; 11 +15 ;; 12 +JUMP ;; 14 --> 5 +STOP ;; 15 +) \ No newline at end of file diff --git a/evmcc/test/jump/jump6.evm b/evmcc/test/jump/jump6.evm new file mode 100644 index 000000000..029db7191 --- /dev/null +++ b/evmcc/test/jump/jump6.evm @@ -0,0 +1 @@ +600358600f600d58006014600758005d6001600154005d600260025400 diff --git a/evmcc/test/jump/jump6.lll b/evmcc/test/jump/jump6.lll new file mode 100644 index 000000000..1116aa663 --- /dev/null +++ b/evmcc/test/jump/jump6.lll @@ -0,0 +1,32 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +;; 0, 2 --> 3 .. 7 --> 13 -*-> 15 .. 19 + +(asm +3 ;; 0 +JUMP ;; 2 + +15 ;; 3 <- start +13 ;; 5 +JUMP ;; 7 <- b +STOP ;; 8 + +20 ;; 9 +7 ;; 11 + +JUMP ;; 13 <- a +STOP ;; 14 + +JUMPDEST ;; 15 <- c +1 ;; 16 +1 ;; 18 +MSTORE ;; 19 +STOP ;; 20 + +JUMPDEST ;; 21 <- d +2 ;; 22 +2 ;; 24 +MSTORE ;; 26 +STOP ;; 27 +) \ No newline at end of file From 936aeab43c6937f6a9510a27794c38fe296ce5f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 10 Oct 2014 14:12:38 +0200 Subject: [PATCH 074/396] Group gas counting into block of instructions called cost-block. [#79942174] --- evmcc/Compiler.cpp | 3 +-- evmcc/GasMeter.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- evmcc/GasMeter.h | 4 ++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 9a46313b6..0e695df06 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -178,8 +178,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto inst = static_cast(bytecode[currentPC]); - // Disable for now - //gasMeter.check(inst); + gasMeter.check(inst); switch (inst) { diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 2006f319f..a40b8cb5c 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -49,6 +49,33 @@ uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to F } } +bool isCommitTrigger(Instruction _inst) +{ + switch (_inst) + { + case Instruction::STOP: + case Instruction::CALLDATACOPY: + case Instruction::CODECOPY: + case Instruction::MLOAD: + case Instruction::MSTORE: + case Instruction::MSTORE8: + case Instruction::SSTORE: + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::JUMPDEST: + case Instruction::GAS: + case Instruction::CREATE: + case Instruction::CALL: + case Instruction::CALLCODE: + case Instruction::RETURN: + case Instruction::SUICIDE: + return true; + + default: + return false; + } +} + } GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): @@ -72,8 +99,20 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): void GasMeter::check(Instruction _inst) { + if (!m_checkCall) + { + m_checkCall = m_builder.CreateCall(m_gasCheckFunc, m_builder.getIntN(256, 0)); + } + auto stepCost = getStepCost(_inst); - m_builder.CreateCall(m_gasCheckFunc, m_builder.getIntN(256, stepCost)); + m_blockCost += stepCost; + + auto isTrigger = isCommitTrigger(_inst); + if (isTrigger) + { + m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); + m_checkCall = nullptr; + } } } \ No newline at end of file diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index e2ee26a71..057391102 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -19,7 +19,11 @@ public: void check(dev::eth::Instruction _inst); private: + /// Cumulative gas cost of a block of instructions + /// @TODO Handle overflow + uint64_t m_blockCost = 0; llvm::IRBuilder<>& m_builder; + llvm::CallInst* m_checkCall; llvm::GlobalVariable* m_gas; llvm::Function* m_gasCheckFunc; }; From 85606447d86d14103c4d3d0a4b27d569023af08f Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 10 Oct 2014 13:35:45 +0100 Subject: [PATCH 075/396] test cases for jumps --- evmcc/test/jump/badjump1.evm | 1 + evmcc/test/jump/badjump1.lll | 9 +++++++++ evmcc/test/jump/call1.ethel | 3 +++ evmcc/test/jump/call1.evm | 1 + evmcc/test/jump/fib1.ethel | 5 +++++ evmcc/test/jump/fib1.evm | 1 + evmcc/test/jump/if1.ethel | 1 + evmcc/test/jump/if1.evm | 1 + evmcc/test/jump/if2.ethel | 1 + evmcc/test/jump/if2.evm | 1 + evmcc/test/jump/indirect1.evm | 1 + evmcc/test/jump/indirect1.lll | 13 +++++++++++++ evmcc/test/jump/indirect2.evm | 1 + evmcc/test/jump/indirect2.lll | 19 +++++++++++++++++++ 14 files changed, 58 insertions(+) create mode 100644 evmcc/test/jump/badjump1.evm create mode 100644 evmcc/test/jump/badjump1.lll create mode 100644 evmcc/test/jump/call1.ethel create mode 100644 evmcc/test/jump/call1.evm create mode 100644 evmcc/test/jump/fib1.ethel create mode 100644 evmcc/test/jump/fib1.evm create mode 100644 evmcc/test/jump/if1.ethel create mode 100644 evmcc/test/jump/if1.evm create mode 100644 evmcc/test/jump/if2.ethel create mode 100644 evmcc/test/jump/if2.evm create mode 100644 evmcc/test/jump/indirect1.evm create mode 100644 evmcc/test/jump/indirect1.lll create mode 100644 evmcc/test/jump/indirect2.evm create mode 100644 evmcc/test/jump/indirect2.lll diff --git a/evmcc/test/jump/badjump1.evm b/evmcc/test/jump/badjump1.evm new file mode 100644 index 000000000..b2a8aad67 --- /dev/null +++ b/evmcc/test/jump/badjump1.evm @@ -0,0 +1 @@ +601b602502585d diff --git a/evmcc/test/jump/badjump1.lll b/evmcc/test/jump/badjump1.lll new file mode 100644 index 000000000..c3f9f8d69 --- /dev/null +++ b/evmcc/test/jump/badjump1.lll @@ -0,0 +1,9 @@ +;; Bad indirect jump. Should go to BadJumpBlock. + +(asm +27 +37 +MUL +JUMP +JUMPDEST +) \ No newline at end of file diff --git a/evmcc/test/jump/call1.ethel b/evmcc/test/jump/call1.ethel new file mode 100644 index 000000000..206fb4c75 --- /dev/null +++ b/evmcc/test/jump/call1.ethel @@ -0,0 +1,3 @@ +let f n = n + 1 + +return f 2 diff --git a/evmcc/test/jump/call1.evm b/evmcc/test/jump/call1.evm new file mode 100644 index 000000000..1f50b683f --- /dev/null +++ b/evmcc/test/jump/call1.evm @@ -0,0 +1 @@ +630000000d60026300000016585d60005460206000f280600101915058 \ No newline at end of file diff --git a/evmcc/test/jump/fib1.ethel b/evmcc/test/jump/fib1.ethel new file mode 100644 index 000000000..6efd4ed2d --- /dev/null +++ b/evmcc/test/jump/fib1.ethel @@ -0,0 +1,5 @@ +let fib n = + if n < 3 then 1 + else fib (n-1) + fib (n-2) + +return fib 5 diff --git a/evmcc/test/jump/fib1.evm b/evmcc/test/jump/fib1.evm new file mode 100644 index 000000000..b5b5bf9c6 --- /dev/null +++ b/evmcc/test/jump/fib1.evm @@ -0,0 +1 @@ +630000000d60056300000016585d60005460206000f28060030a630000004759630000002f816001036300000016585d630000003f836002036300000016585d0163000000495860019350505058 \ No newline at end of file diff --git a/evmcc/test/jump/if1.ethel b/evmcc/test/jump/if1.ethel new file mode 100644 index 000000000..85c3e126b --- /dev/null +++ b/evmcc/test/jump/if1.ethel @@ -0,0 +1 @@ +return if 0 then 1 else 2 \ No newline at end of file diff --git a/evmcc/test/jump/if1.evm b/evmcc/test/jump/if1.evm new file mode 100644 index 000000000..51fbe04bd --- /dev/null +++ b/evmcc/test/jump/if1.evm @@ -0,0 +1 @@ +60006300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmcc/test/jump/if2.ethel b/evmcc/test/jump/if2.ethel new file mode 100644 index 000000000..2a58d6365 --- /dev/null +++ b/evmcc/test/jump/if2.ethel @@ -0,0 +1 @@ +return if 1 then 1 else 2 \ No newline at end of file diff --git a/evmcc/test/jump/if2.evm b/evmcc/test/jump/if2.evm new file mode 100644 index 000000000..6d823b374 --- /dev/null +++ b/evmcc/test/jump/if2.evm @@ -0,0 +1 @@ +60016300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmcc/test/jump/indirect1.evm b/evmcc/test/jump/indirect1.evm new file mode 100644 index 000000000..ab6928304 --- /dev/null +++ b/evmcc/test/jump/indirect1.evm @@ -0,0 +1 @@ +600460030158005d6001600054 diff --git a/evmcc/test/jump/indirect1.lll b/evmcc/test/jump/indirect1.lll new file mode 100644 index 000000000..1ee7dc347 --- /dev/null +++ b/evmcc/test/jump/indirect1.lll @@ -0,0 +1,13 @@ +;; Indirect JUMP + +(asm +4 ;; 0 +3 ;; 2 +ADD ;; 4 +JUMP ;; 5 +STOP ;; 6 +JUMPDEST ;; 7 +1 +0 +MSTORE +) \ No newline at end of file diff --git a/evmcc/test/jump/indirect2.evm b/evmcc/test/jump/indirect2.evm new file mode 100644 index 000000000..e9697eaa1 --- /dev/null +++ b/evmcc/test/jump/indirect2.evm @@ -0,0 +1 @@ +600860060158005d6001600054005d600260005400 diff --git a/evmcc/test/jump/indirect2.lll b/evmcc/test/jump/indirect2.lll new file mode 100644 index 000000000..9a4db8c14 --- /dev/null +++ b/evmcc/test/jump/indirect2.lll @@ -0,0 +1,19 @@ +;; Indirect JUMP + +(asm +8 ;; 0 +6 ;; 2 +ADD ;; 4 +JUMP ;; 5 +STOP ;; 6 +JUMPDEST ;; 7 +1 ;; 8 +0 ;; 10 +MSTORE ;; 12 +STOP ;; 13 +JUMPDEST ;; 14 +2 +0 +MSTORE +STOP +) \ No newline at end of file From a5e264d385b9d70d69dd1ad7843d2971bcd428ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 10 Oct 2014 14:56:06 +0200 Subject: [PATCH 076/396] Fix stack swap or dup not generating PHI nodes --- evmcc/BasicBlock.cpp | 29 ++++++++++++++++++++--------- evmcc/BasicBlock.h | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/evmcc/BasicBlock.cpp b/evmcc/BasicBlock.cpp index 5271c984f..3a2c1c548 100644 --- a/evmcc/BasicBlock.cpp +++ b/evmcc/BasicBlock.cpp @@ -33,17 +33,27 @@ void BasicBlock::Stack::push(llvm::Value* _value) llvm::Value* BasicBlock::Stack::pop() { - if (m_backend.empty()) + auto top = get(0); + m_backend.pop_back(); + return top; +} + +llvm::Value* BasicBlock::Stack::get(size_t _index) +{ + if (_index >= m_backend.size()) { - // Create PHI node - if (m_llvmBB->empty()) - return llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB); - return llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI()); + // Create PHI node for missing values + auto nMissingVals = _index - m_backend.size() + 1; + m_backend.insert(m_backend.begin(), nMissingVals, nullptr); + for (decltype(nMissingVals) i = 0; i < nMissingVals; ++i) + { + m_backend[i] = m_llvmBB->empty() ? + llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB) : + llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI()); + } } - auto top = m_backend.back(); - m_backend.pop_back(); - return top; + return *(m_backend.rbegin() + _index); } void BasicBlock::Stack::dup(size_t _index) @@ -54,7 +64,8 @@ void BasicBlock::Stack::dup(size_t _index) void BasicBlock::Stack::swap(size_t _index) { assert(_index != 0); - std::swap(get(0), get(_index)); + get(_index); // Create PHI nodes + std::swap(*m_backend.rbegin(), *(m_backend.rbegin() + _index)); } } diff --git a/evmcc/BasicBlock.h b/evmcc/BasicBlock.h index 3c47db328..598ab731c 100644 --- a/evmcc/BasicBlock.h +++ b/evmcc/BasicBlock.h @@ -21,7 +21,7 @@ public: llvm::Value* pop(); /// Gets _index'th value from top (counting from 0) - llvm::Value*& get(size_t _index) { return *(m_backend.rbegin() + _index); } + llvm::Value* get(size_t _index); /// Duplicates _index'th value on stack. void dup(size_t _index); From 40e73d035ca0c08eb7bd123491474df07ca56fe6 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 10 Oct 2014 14:22:21 +0100 Subject: [PATCH 077/396] Indirect jump: jump table generated in separate bblock. --- evmcc/Compiler.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++--- evmcc/Compiler.h | 5 +++++ evmcc/lll/if1.lll | 2 +- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 0e3603fe6..0d3487e10 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -147,6 +147,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) m_finalBlock = std::make_unique("FinalBlock", m_mainFunc); m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc); + m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc); for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { @@ -626,6 +627,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) std::exit(1); } + builder.CreateBr(m_jumpTableBlock->llvm()); + /* // Generate switch for indirect jump. auto dest = stack.pop(); auto switchInstr = builder.CreateSwitch(dest, m_badJumpBlock->llvm(), @@ -636,7 +639,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto dest = ConstantInt::get(Type::i256, bb->begin()); switchInstr->addCase(dest, bb->llvm()); } - + */ break; } @@ -836,12 +839,35 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } // Code for special blocks: + // TODO: move to separate function. + // Note: Right now the codegen for special blocks depends only on createBasicBlock(), + // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). builder.SetInsertPoint(m_finalBlock->llvm()); builder.CreateRet(builder.getInt64(0)); // TODO: throw an exception or something builder.SetInsertPoint(m_badJumpBlock->llvm()); - builder.CreateRet(builder.getInt64(1)); + builder.CreateRet(builder.getInt64(0)); + + builder.SetInsertPoint(m_jumpTableBlock->llvm()); + if (m_indirectJumpTargets.size() > 0) + { + auto& stack = m_jumpTableBlock->getStack(); + + auto dest = stack.pop(); + auto switchInstr = builder.CreateSwitch(dest, m_badJumpBlock->llvm(), + m_indirectJumpTargets.size()); + for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) + { + auto& bb = *it; + auto dest = ConstantInt::get(Type::i256, bb->begin()); + switchInstr->addCase(dest, bb->llvm()); + } + } + else + { + builder.CreateRet(builder.getInt64(0)); + } linkBasicBlocks(); @@ -861,10 +887,30 @@ void Compiler::linkBasicBlocks() return basicBlocks.find(idx)->second; }; + auto completePhiNodes = [findBasicBlock](llvm::BasicBlock* _llbb) -> void + { + size_t valueIdx = 0; + auto firstNonPhi = _llbb->getFirstNonPHI(); + for (auto instIt = _llbb->begin(); &*instIt != firstNonPhi; ++instIt, ++valueIdx) + { + auto phi = llvm::cast(instIt); + for (auto predIt = llvm::pred_begin(_llbb); predIt != llvm::pred_end(_llbb); ++predIt) + { + auto& predBB = findBasicBlock(*predIt); + // assert(valueIdx < predBB.getStack().size()); // TODO: Report error + phi->addIncoming(predBB.getStack().get(valueIdx), predBB); + } + } + }; + // Link basic blocks for (auto&& p : basicBlocks) { BasicBlock& bb = p.second; + completePhiNodes(bb.llvm()); + } + completePhiNodes(m_jumpTableBlock->llvm()); + /* llvm::BasicBlock* llvmBB = bb.llvm(); size_t valueIdx = 0; @@ -879,7 +925,7 @@ void Compiler::linkBasicBlocks() phi->addIncoming(predBB.getStack().get(valueIdx), predBB); } } - } + */ } } diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index f57d800a4..7d0cb4ab6 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -49,6 +49,11 @@ private: */ std::unique_ptr m_finalBlock; + /** + * Block with a jump table. + */ + std::unique_ptr m_jumpTableBlock; + /** * Default destination for indirect jumps. */ diff --git a/evmcc/lll/if1.lll b/evmcc/lll/if1.lll index a807b697d..7984807c1 100644 --- a/evmcc/lll/if1.lll +++ b/evmcc/lll/if1.lll @@ -2,4 +2,4 @@ [i] 1 ( if (> @i 0) [i] 2 [i] 3 ) -} \ No newline at end of file +} From 4b8d51e23e2d62b5e83a134d63e9b5c1e02f93bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 10 Oct 2014 17:17:45 +0200 Subject: [PATCH 078/396] Renames & comments --- evmcc/GasMeter.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index a40b8cb5c..013205ee6 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -49,7 +49,7 @@ uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to F } } -bool isCommitTrigger(Instruction _inst) +bool isCostBlockEnd(Instruction _inst) { switch (_inst) { @@ -101,17 +101,16 @@ void GasMeter::check(Instruction _inst) { if (!m_checkCall) { + // Create gas check call with mocked block cost at begining of current cost-block m_checkCall = m_builder.CreateCall(m_gasCheckFunc, m_builder.getIntN(256, 0)); } - auto stepCost = getStepCost(_inst); - m_blockCost += stepCost; + m_blockCost += getStepCost(_inst); - auto isTrigger = isCommitTrigger(_inst); - if (isTrigger) - { - m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); - m_checkCall = nullptr; + if (isCostBlockEnd(_inst)) + { + m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call + m_checkCall = nullptr; // End cost-block } } From 35605271f16d3e47452116c2e732efd9f92f4c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 10 Oct 2014 17:23:34 +0200 Subject: [PATCH 079/396] Fix for finding jumpTableBlock --- evmcc/Compiler.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 1e2982b29..806592287 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -879,6 +879,10 @@ void Compiler::linkBasicBlocks() /// Helper function that finds basic block given LLVM basic block pointer auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock& { + // TODO: Fix for finding jumpTableBlock + if (_llbb == this->m_jumpTableBlock->llvm()) + return *this->m_jumpTableBlock; + // Name is used to get basic block index (index of first instruction) // TODO: If basicBlocs are still a map - multikey map can be used auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2); From 4a1511309c20c48a2d6982aa97f24f3dbda5b96b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 10 Oct 2014 18:56:59 +0200 Subject: [PATCH 080/396] Generate mem.store function and dependencies (currently unused) [#80191662] --- evmcc/Memory.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++---- evmcc/Memory.h | 8 ++++++- evmcc/Type.cpp | 6 +++++ evmcc/Type.h | 4 ++++ 4 files changed, 73 insertions(+), 5 deletions(-) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index e3bbd5d40..1a988be0d 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -6,10 +6,12 @@ #include #include +#include #include #include +#include "Type.h" #include "Runtime.h" #ifdef _MSC_VER @@ -21,7 +23,7 @@ namespace evmcc { -Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* module) +Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) : m_builder(_builder) { auto voidTy = m_builder.getVoidTy(); @@ -30,17 +32,59 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* module) auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false); m_memRequire = llvm::Function::Create(memRequireTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_require", module); + "evmccrt_memory_require", _module); auto memSizeTy = llvm::FunctionType::get(i64Ty, false); m_memSize = llvm::Function::Create(memSizeTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_size", module); + "evmccrt_memory_size", _module); std::vector argTypes = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); 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->setUnnamedAddr(true); // Address is not important + + m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, m_builder.getIntN(256, 0), "mem.size"); + m_size->setUnnamedAddr(true); // Address is not important + + m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); + + llvm::Type* storeArgs[] = {Type::i256, Type::i256}; + m_store = llvm::Function::Create(llvm::FunctionType::get(Type::Void, storeArgs, false), llvm::Function::PrivateLinkage, "mem.store", _module); + auto origBB = m_builder.GetInsertBlock(); + auto origPt = m_builder.GetInsertPoint(); + + auto checkBB = llvm::BasicBlock::Create(m_store->getContext(), "check", m_store); + auto resizeBB = llvm::BasicBlock::Create(m_store->getContext(), "resize", m_store); + auto storeBB = llvm::BasicBlock::Create(m_store->getContext(), "store", m_store); + + m_builder.SetInsertPoint(checkBB); + llvm::Value* index = m_store->arg_begin(); + index->setName("index"); + llvm::Value* value = ++m_store->arg_begin(); + value->setName("value"); + auto sizeRequired = m_builder.CreateAdd(index, m_builder.getIntN(256, 32), "sizeRequired"); + auto size = m_builder.CreateLoad(m_size, "size"); + auto resizeNeeded = m_builder.CreateICmpULE(sizeRequired, size, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, storeBB); // OPT branch weights? + + m_builder.SetInsertPoint(resizeBB); + m_builder.CreateStore(sizeRequired, m_size); + llvm::Value* data = m_builder.CreateCall(m_resize, m_size, "data"); + m_builder.CreateStore(data, m_data); + m_builder.CreateBr(storeBB); + + m_builder.SetInsertPoint(storeBB); + data = m_builder.CreateLoad(m_data, "data"); + auto ptr = m_builder.CreateGEP(data, index, "ptr"); + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); + + m_builder.SetInsertPoint(origBB, origPt); } @@ -114,6 +158,14 @@ extern "C" { using namespace evmcc; +EXPORT uint8_t* mem_resize(i256* _size) +{ + auto size = _size->a; // Trunc to 64-bit + auto& memory = Runtime::getMemory(); + memory.resize(size); + return memory.data(); +} + // Resizes memory to contain at least _index + 1 bytes and returns the base address. EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) { diff --git a/evmcc/Memory.h b/evmcc/Memory.h index da6662fef..a28a3c91e 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -10,7 +10,7 @@ namespace evmcc class Memory { public: - Memory(llvm::IRBuilder<>& _builder, llvm::Module* module); + Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); @@ -22,6 +22,12 @@ public: private: llvm::IRBuilder<>& m_builder; + llvm::GlobalVariable* m_data; + llvm::GlobalVariable* m_size; + + llvm::Function* m_store; + llvm::Function* m_resize; + llvm::Function* m_memRequire; llvm::Function* m_memDump; llvm::Function* m_memSize; diff --git a/evmcc/Type.cpp b/evmcc/Type.cpp index f5c74c1e9..0c8b6d92e 100644 --- a/evmcc/Type.cpp +++ b/evmcc/Type.cpp @@ -7,13 +7,19 @@ namespace evmcc { llvm::IntegerType* Type::i256; +llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; +llvm::IntegerType* Type::Byte; +llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; void Type::init(llvm::LLVMContext& _context) { i256 = llvm::Type::getIntNTy(_context, 256); + WordPtr = i256->getPointerTo(); lowPrecision = llvm::Type::getInt64Ty(_context); + Byte = llvm::Type::getInt8Ty(_context); + BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); } diff --git a/evmcc/Type.h b/evmcc/Type.h index a25d7a9e9..fe4bce335 100644 --- a/evmcc/Type.h +++ b/evmcc/Type.h @@ -9,11 +9,15 @@ namespace evmcc struct Type { static llvm::IntegerType* i256; + static llvm::PointerType* WordPtr; /// Type for doing low precision arithmetics where 256-bit precision is not supported by native target /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required static llvm::IntegerType* lowPrecision; + static llvm::IntegerType* Byte; + static llvm::PointerType* BytePtr; + static llvm::Type* Void; static void init(llvm::LLVMContext& _context); From 2df83af3be925780211b4a80753c37cbff24742b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 10 Oct 2014 19:06:40 +0200 Subject: [PATCH 081/396] Use mem.store as implementation of MSTORE [#80191662] --- evmcc/Memory.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 1a988be0d..a1d3c9989 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -108,15 +108,7 @@ llvm::Value* Memory::loadWord(llvm::Value* _addr) void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "mem.index"); - auto index31 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 31), "mem.index31"); - - auto base = m_builder.CreateCall(m_memRequire, index31, "base"); - auto ptr = m_builder.CreateGEP(base, index, "ptr"); - - auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); - auto wordPtr = m_builder.CreateBitCast(ptr, i256ptrTy, "wordptr"); - m_builder.CreateStore(_word, wordPtr); + m_builder.CreateCall2(m_store, _addr, _word); dump(0); } @@ -160,6 +152,7 @@ extern "C" EXPORT uint8_t* mem_resize(i256* _size) { + assert(false); auto size = _size->a; // Trunc to 64-bit auto& memory = Runtime::getMemory(); memory.resize(size); From 0400b47357d0fc3e71d80f98bc7458c2e10cb026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 10 Oct 2014 19:43:07 +0200 Subject: [PATCH 082/396] store8 function added as implementation of MSTORE8 [#80191662] --- evmcc/Memory.cpp | 77 +++++++++++++++++++++++++----------------------- evmcc/Memory.h | 8 ++++- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index a1d3c9989..222db8482 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -51,40 +51,48 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) m_size->setUnnamedAddr(true); // Address is not important m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); + m_storeWord = createStoreFunc(Type::i256, _module); + m_storeByte = createStoreFunc(Type::Byte, _module); +} + +llvm::Function* Memory::createStoreFunc(llvm::Type* _valueType, llvm::Module* _module) +{ + auto wordValue = _valueType == Type::i256; - llvm::Type* storeArgs[] = {Type::i256, Type::i256}; - m_store = llvm::Function::Create(llvm::FunctionType::get(Type::Void, storeArgs, false), llvm::Function::PrivateLinkage, "mem.store", _module); - auto origBB = m_builder.GetInsertBlock(); - auto origPt = m_builder.GetInsertPoint(); + llvm::Type* storeArgs[] = {Type::i256, _valueType}; + auto name = wordValue ? "store" : "store8"; + auto storeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, storeArgs, false), llvm::Function::PrivateLinkage, name, _module); - auto checkBB = llvm::BasicBlock::Create(m_store->getContext(), "check", m_store); - auto resizeBB = llvm::BasicBlock::Create(m_store->getContext(), "resize", m_store); - auto storeBB = llvm::BasicBlock::Create(m_store->getContext(), "store", m_store); + auto checkBB = llvm::BasicBlock::Create(storeFunc->getContext(), "check", storeFunc); + auto resizeBB = llvm::BasicBlock::Create(storeFunc->getContext(), "resize", storeFunc); + auto storeBB = llvm::BasicBlock::Create(storeFunc->getContext(), "store", storeFunc); - m_builder.SetInsertPoint(checkBB); - llvm::Value* index = m_store->arg_begin(); + llvm::IRBuilder<> builder(checkBB); + llvm::Value* index = storeFunc->arg_begin(); index->setName("index"); - llvm::Value* value = ++m_store->arg_begin(); + llvm::Value* value = ++storeFunc->arg_begin(); value->setName("value"); - auto sizeRequired = m_builder.CreateAdd(index, m_builder.getIntN(256, 32), "sizeRequired"); - auto size = m_builder.CreateLoad(m_size, "size"); - auto resizeNeeded = m_builder.CreateICmpULE(sizeRequired, size, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, storeBB); // OPT branch weights? - - m_builder.SetInsertPoint(resizeBB); - m_builder.CreateStore(sizeRequired, m_size); - llvm::Value* data = m_builder.CreateCall(m_resize, m_size, "data"); - m_builder.CreateStore(data, m_data); - m_builder.CreateBr(storeBB); - - m_builder.SetInsertPoint(storeBB); - data = m_builder.CreateLoad(m_data, "data"); - auto ptr = m_builder.CreateGEP(data, index, "ptr"); - ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); - m_builder.CreateStore(value, ptr); - m_builder.CreateRetVoid(); - - m_builder.SetInsertPoint(origBB, origPt); + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; + auto sizeRequired = builder.CreateAdd(index, builder.getIntN(256, valueSize), "sizeRequired"); + auto size = builder.CreateLoad(m_size, "size"); + auto resizeNeeded = builder.CreateICmpULE(sizeRequired, size, "resizeNeeded"); + builder.CreateCondBr(resizeNeeded, resizeBB, storeBB); // OPT branch weights? + + builder.SetInsertPoint(resizeBB); + builder.CreateStore(sizeRequired, m_size); + auto newData = builder.CreateCall(m_resize, m_size, "newData"); + builder.CreateStore(newData, m_data); + builder.CreateBr(storeBB); + + builder.SetInsertPoint(storeBB); + auto data = builder.CreateLoad(m_data, "data"); + auto ptr = builder.CreateGEP(data, index, "ptr"); + if (wordValue) + ptr = builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + builder.CreateStore(value, ptr); + builder.CreateRetVoid(); + + return storeFunc; } @@ -108,19 +116,15 @@ llvm::Value* Memory::loadWord(llvm::Value* _addr) void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - m_builder.CreateCall2(m_store, _addr, _word); + m_builder.CreateCall2(m_storeWord, _addr, _word); dump(0); } void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { - auto byte = m_builder.CreateTrunc(_word, m_builder.getInt8Ty(), "byte"); - auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); - - auto base = m_builder.CreateCall(m_memRequire, index, "base"); - auto ptr = m_builder.CreateGEP(base, index, "ptr"); - m_builder.CreateStore(byte, ptr); + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + m_builder.CreateCall2(m_storeByte, _addr, byte); dump(0); } @@ -152,7 +156,6 @@ extern "C" EXPORT uint8_t* mem_resize(i256* _size) { - assert(false); auto size = _size->a; // Trunc to 64-bit auto& memory = Runtime::getMemory(); memory.resize(size); diff --git a/evmcc/Memory.h b/evmcc/Memory.h index a28a3c91e..f1d75e5b3 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -11,6 +11,8 @@ class Memory { public: Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); + Memory(const Memory&) = delete; + void operator=(Memory) = delete; llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); @@ -19,13 +21,17 @@ public: void dump(uint64_t _begin, uint64_t _end = 0); +private: + llvm::Function* createStoreFunc(llvm::Type* _type, llvm::Module* _module); + private: llvm::IRBuilder<>& m_builder; llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; - llvm::Function* m_store; + llvm::Function* m_storeWord; + llvm::Function* m_storeByte; llvm::Function* m_resize; llvm::Function* m_memRequire; From 48ed393fb3e8cf8b304f1aa6f4612e478f715438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 10 Oct 2014 20:10:09 +0200 Subject: [PATCH 083/396] mload function added as implementation of MLOAD [#80191662] --- evmcc/Memory.cpp | 67 +++++++++++++++++++++++------------------------- evmcc/Memory.h | 3 ++- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 222db8482..8f03c2144 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -51,67 +51,66 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) m_size->setUnnamedAddr(true); // Address is not important m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); - m_storeWord = createStoreFunc(Type::i256, _module); - m_storeByte = createStoreFunc(Type::Byte, _module); + m_loadWord = createFunc(false, Type::i256, _module); + m_storeWord = createFunc(true, Type::i256, _module); + m_storeByte = createFunc(true, Type::Byte, _module); } -llvm::Function* Memory::createStoreFunc(llvm::Type* _valueType, llvm::Module* _module) +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::Module* _module) { - auto wordValue = _valueType == Type::i256; + auto isWord = _valueType == Type::i256; llvm::Type* storeArgs[] = {Type::i256, _valueType}; - auto name = wordValue ? "store" : "store8"; - auto storeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, storeArgs, false), llvm::Function::PrivateLinkage, name, _module); + auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, _module); - auto checkBB = llvm::BasicBlock::Create(storeFunc->getContext(), "check", storeFunc); - auto resizeBB = llvm::BasicBlock::Create(storeFunc->getContext(), "resize", storeFunc); - auto storeBB = llvm::BasicBlock::Create(storeFunc->getContext(), "store", storeFunc); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func); + auto accessBB = llvm::BasicBlock::Create(func->getContext(), "access", func); llvm::IRBuilder<> builder(checkBB); - llvm::Value* index = storeFunc->arg_begin(); + llvm::Value* index = func->arg_begin(); index->setName("index"); - llvm::Value* value = ++storeFunc->arg_begin(); - value->setName("value"); auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; auto sizeRequired = builder.CreateAdd(index, builder.getIntN(256, valueSize), "sizeRequired"); auto size = builder.CreateLoad(m_size, "size"); auto resizeNeeded = builder.CreateICmpULE(sizeRequired, size, "resizeNeeded"); - builder.CreateCondBr(resizeNeeded, resizeBB, storeBB); // OPT branch weights? + builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights? builder.SetInsertPoint(resizeBB); builder.CreateStore(sizeRequired, m_size); auto newData = builder.CreateCall(m_resize, m_size, "newData"); builder.CreateStore(newData, m_data); - builder.CreateBr(storeBB); + builder.CreateBr(accessBB); - builder.SetInsertPoint(storeBB); + builder.SetInsertPoint(accessBB); auto data = builder.CreateLoad(m_data, "data"); auto ptr = builder.CreateGEP(data, index, "ptr"); - if (wordValue) + if (isWord) ptr = builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); - builder.CreateStore(value, ptr); - builder.CreateRetVoid(); - - return storeFunc; + if (_isStore) + { + llvm::Value* value = ++func->arg_begin(); + value->setName("value"); + builder.CreateStore(value, ptr); + builder.CreateRetVoid(); + } + else + { + auto ret = builder.CreateLoad(ptr); + builder.CreateRet(ret); + } + return func; } llvm::Value* Memory::loadWord(llvm::Value* _addr) { - // trunc _addr (an i256) to i64 index and use it to index the memory - auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "mem.index"); - auto index31 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 31), "mem.index.31"); - - // load from evmccrt_memory_require()[index] - auto base = m_builder.CreateCall(m_memRequire, index31, "base"); - auto ptr = m_builder.CreateGEP(base, index, "ptr"); - - auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); - auto wordPtr = m_builder.CreateBitCast(ptr, i256ptrTy, "wordptr"); - auto byte = m_builder.CreateLoad(wordPtr, "word"); + auto value = m_builder.CreateCall(m_loadWord, _addr); dump(0); - return byte; + return value; } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) @@ -131,9 +130,7 @@ void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) llvm::Value* Memory::getSize() { - auto size = m_builder.CreateCall(m_memSize, "mem.size"); - auto word = m_builder.CreateZExt(size, m_builder.getIntNTy(256), "mem.wsize"); - return word; + return m_builder.CreateLoad(m_size); } void Memory::dump(uint64_t _begin, uint64_t _end) diff --git a/evmcc/Memory.h b/evmcc/Memory.h index f1d75e5b3..2166abd14 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -22,7 +22,7 @@ public: void dump(uint64_t _begin, uint64_t _end = 0); private: - llvm::Function* createStoreFunc(llvm::Type* _type, llvm::Module* _module); + llvm::Function* createFunc(bool _isStore, llvm::Type* _type, llvm::Module* _module); private: llvm::IRBuilder<>& m_builder; @@ -30,6 +30,7 @@ private: llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; + llvm::Function* m_loadWord; llvm::Function* m_storeWord; llvm::Function* m_storeByte; llvm::Function* m_resize; From 01af0e88cd1c0d42d5639b78467a5e4f7b967d85 Mon Sep 17 00:00:00 2001 From: caktux Date: Sun, 12 Oct 2014 02:14:21 -0400 Subject: [PATCH 084/396] build status --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 7529fed50..d1568402c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ ## Ethereum C++ Client. +[![Build +Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build +Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop + By Gav Wood, 2014. Based on a design by Vitalik Buterin. From 7c157f68f6078e0f004c13ded80949c2bcdea3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 09:12:22 +0200 Subject: [PATCH 085/396] Wrong resize condition fixed [Delivers #80191662] --- evmcc/Memory.cpp | 2 +- evmcc/bytecode/mem2.evm | 1 + evmcc/lll/mem2.lll | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 evmcc/bytecode/mem2.evm create mode 100644 evmcc/lll/mem2.lll diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 8f03c2144..ba787614e 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -75,7 +75,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; auto sizeRequired = builder.CreateAdd(index, builder.getIntN(256, valueSize), "sizeRequired"); auto size = builder.CreateLoad(m_size, "size"); - auto resizeNeeded = builder.CreateICmpULE(sizeRequired, size, "resizeNeeded"); + auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights? builder.SetInsertPoint(resizeBB); diff --git a/evmcc/bytecode/mem2.evm b/evmcc/bytecode/mem2.evm new file mode 100644 index 000000000..c00de3089 --- /dev/null +++ b/evmcc/bytecode/mem2.evm @@ -0,0 +1 @@ +6001610d80556504409585d6df620493e05462061a8053 diff --git a/evmcc/lll/mem2.lll b/evmcc/lll/mem2.lll new file mode 100644 index 000000000..66c24c1e1 --- /dev/null +++ b/evmcc/lll/mem2.lll @@ -0,0 +1,11 @@ + +(asm ;; [] +1 +3456 +MSTORE8 ;; [02] +4675432994527 +300000 +MSTORE +400000 +MLOAD +) \ No newline at end of file From e1112c11c995037f5f3ded4deeb3dd113155a918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 10:04:48 +0200 Subject: [PATCH 086/396] MSIZE test --- evmcc/bytecode/mem2.evm | 2 +- evmcc/lll/mem2.lll | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/evmcc/bytecode/mem2.evm b/evmcc/bytecode/mem2.evm index c00de3089..49cc6e8b1 100644 --- a/evmcc/bytecode/mem2.evm +++ b/evmcc/bytecode/mem2.evm @@ -1 +1 @@ -6001610d80556504409585d6df620493e05462061a8053 +6001610d805b01556504409585d6df620493e05462061a80535b01 diff --git a/evmcc/lll/mem2.lll b/evmcc/lll/mem2.lll index 66c24c1e1..5345ee47c 100644 --- a/evmcc/lll/mem2.lll +++ b/evmcc/lll/mem2.lll @@ -2,10 +2,14 @@ (asm ;; [] 1 3456 +MSIZE +ADD MSTORE8 ;; [02] 4675432994527 300000 MSTORE 400000 MLOAD +MSIZE +ADD ) \ No newline at end of file From 48710b5e5cf03926e504adffd8ab8ebbd4b359ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 10:57:12 +0200 Subject: [PATCH 087/396] Count gas for additional memory [#79942174] --- evmcc/Compiler.cpp | 4 ++-- evmcc/GasMeter.cpp | 7 +++++++ evmcc/GasMeter.h | 3 +++ evmcc/Memory.cpp | 22 ++++++++++++++++------ evmcc/Memory.h | 5 +++-- 5 files changed, 31 insertions(+), 10 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 806592287..e532ce9f5 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -196,9 +196,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) createBasicBlocks(bytecode); // Init runtime structures. - auto memory = Memory(builder, module.get()); - auto ext = Ext(builder, module.get()); GasMeter gasMeter(builder, module.get()); + Memory memory(builder, module.get(), gasMeter); + Ext ext(builder, module.get()); // Jump to first instruction builder.CreateBr(basicBlocks.begin()->second); diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 013205ee6..eed9fa0ad 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -114,4 +114,11 @@ void GasMeter::check(Instruction _inst) } } +void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder) +{ + // Memory uses other builder, but that can be changes later + auto cost = _builder.CreateMul(_additionalMemoryInWords, _builder.getIntN(256, static_cast(c_memoryGas)), "memcost"); + _builder.CreateCall(m_gasCheckFunc, cost); +} + } \ No newline at end of file diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 057391102..73f0d6e1c 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -18,6 +18,9 @@ public: void check(dev::eth::Instruction _inst); + /// Generate code that checks the cost of additional memory used by program + void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); + private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index ba787614e..fa21237b7 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -13,6 +13,7 @@ #include "Type.h" #include "Runtime.h" +#include "GasMeter.h" #ifdef _MSC_VER #define EXPORT __declspec(dllexport) @@ -23,8 +24,8 @@ namespace evmcc { -Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) - : m_builder(_builder) +Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter): + m_builder(_builder) { auto voidTy = m_builder.getVoidTy(); auto i64Ty = m_builder.getInt64Ty(); @@ -51,12 +52,12 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) m_size->setUnnamedAddr(true); // Address is not important m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); - m_loadWord = createFunc(false, Type::i256, _module); - m_storeWord = createFunc(true, Type::i256, _module); - m_storeByte = createFunc(true, Type::Byte, _module); + m_loadWord = createFunc(false, Type::i256, _module, _gasMeter); + m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); + m_storeByte = createFunc(true, Type::Byte, _module, _gasMeter); } -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::Module* _module) +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::Module* _module, GasMeter& _gasMeter) { auto isWord = _valueType == Type::i256; @@ -69,6 +70,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func); auto accessBB = llvm::BasicBlock::Create(func->getContext(), "access", func); + // BB "check" llvm::IRBuilder<> builder(checkBB); llvm::Value* index = func->arg_begin(); index->setName("index"); @@ -78,12 +80,20 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights? + // BB "resize" builder.SetInsertPoint(resizeBB); + // Check gas first + auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, builder.getIntN(256, 31)), builder.getIntN(256, 32), "wordsRequired"); + auto words = builder.CreateUDiv(builder.CreateAdd(size, builder.getIntN(256, 31)), builder.getIntN(256, 32), "words"); + auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords"); + _gasMeter.checkMemory(newWords, builder); + // Resize builder.CreateStore(sizeRequired, m_size); auto newData = builder.CreateCall(m_resize, m_size, "newData"); builder.CreateStore(newData, m_data); builder.CreateBr(accessBB); + // BB "access" builder.SetInsertPoint(accessBB); auto data = builder.CreateLoad(m_data, "data"); auto ptr = builder.CreateGEP(data, index, "ptr"); diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 2166abd14..ed7273c5c 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -6,11 +6,12 @@ namespace evmcc { +class GasMeter; class Memory { public: - Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); + Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter); Memory(const Memory&) = delete; void operator=(Memory) = delete; @@ -22,7 +23,7 @@ public: void dump(uint64_t _begin, uint64_t _end = 0); private: - llvm::Function* createFunc(bool _isStore, llvm::Type* _type, llvm::Module* _module); + llvm::Function* createFunc(bool _isStore, llvm::Type* _type, llvm::Module* _module, GasMeter& _gasMeter); private: llvm::IRBuilder<>& m_builder; From a03d47083ed3474e924dd994eef82e2924045ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 11:35:46 +0200 Subject: [PATCH 088/396] Fix block cost counting (counter not reset) --- evmcc/GasMeter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index eed9fa0ad..26921dee3 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -111,6 +111,7 @@ void GasMeter::check(Instruction _inst) { m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block + m_blockCost = 0; } } From f6eef07d37f9e23860e731f7997788aa6e928d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 12:33:41 +0200 Subject: [PATCH 089/396] Use external counter for gas (external linkage global variable) [#79942174] --- evmcc/ExecutionEngine.cpp | 4 +++- evmcc/Ext.cpp | 6 ------ evmcc/GasMeter.cpp | 2 +- evmcc/Memory.cpp | 6 ------ evmcc/Runtime.cpp | 12 ++++++++++-- evmcc/Runtime.h | 10 +++++++++- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 6d9d85a4c..be45ff838 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -85,7 +85,8 @@ int ExecutionEngine::run(std::unique_ptr _module) ext->data = calldata; // Init runtime - Runtime runtime(std::move(ext)); + uint64_t gas = 1000000; + Runtime runtime(gas, std::move(ext)); auto entryFunc = module->getFunction("main"); if (!entryFunc) @@ -95,6 +96,7 @@ int ExecutionEngine::run(std::unique_ptr _module) } auto result = exec->runFunction(entryFunc, {}); + gas = static_cast(Runtime::getGas()); if (auto intResult = result.IntVal.getZExtValue()) { auto index = intResult >> 32; diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 121103354..1d309947d 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -9,12 +9,6 @@ #include "Runtime.h" -#ifdef _MSC_VER -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif - using namespace llvm; using llvm::types::i; using Linkage = llvm::GlobalValue::LinkageTypes; diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 26921dee3..fd68b9d40 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -81,7 +81,7 @@ bool isCostBlockEnd(Instruction _inst) GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_builder(_builder) { - m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::i256), "gas"); + m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); m_gas->setUnnamedAddr(true); // Address is not important auto pt = m_builder.GetInsertPoint(); diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index fa21237b7..8625d7b5b 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -15,12 +15,6 @@ #include "Runtime.h" #include "GasMeter.h" -#ifdef _MSC_VER - #define EXPORT __declspec(dllexport) -#else - #define EXPORT -#endif - namespace evmcc { diff --git a/evmcc/Runtime.cpp b/evmcc/Runtime.cpp index 9d0738f05..a373d9501 100644 --- a/evmcc/Runtime.cpp +++ b/evmcc/Runtime.cpp @@ -6,11 +6,14 @@ namespace evmcc static Runtime* g_runtime; -Runtime::Runtime(std::unique_ptr _ext) - : m_ext(std::move(_ext)) +extern "C" { EXPORT i256 gas; } + +Runtime::Runtime(dev::u256 _gas, std::unique_ptr _ext): + m_ext(std::move(_ext)) { assert(!g_runtime); g_runtime = this; + gas = eth2llvm(_gas); } Runtime::~Runtime() @@ -33,4 +36,9 @@ dev::eth::ExtVMFace& Runtime::getExt() return *g_runtime->m_ext; } +dev::u256 Runtime::getGas() +{ + return llvm2eth(gas); +} + } \ No newline at end of file diff --git a/evmcc/Runtime.h b/evmcc/Runtime.h index 71c917b9d..547e4bcf1 100644 --- a/evmcc/Runtime.h +++ b/evmcc/Runtime.h @@ -7,6 +7,13 @@ #include "Utils.h" + +#ifdef _MSC_VER + #define EXPORT __declspec(dllexport) +#else + #define EXPORT +#endif + namespace evmcc { @@ -16,7 +23,7 @@ using MemoryImpl = dev::bytes; class Runtime { public: - Runtime(std::unique_ptr _ext); + Runtime(dev::u256 _gas, std::unique_ptr _ext); ~Runtime(); Runtime(const Runtime&) = delete; @@ -25,6 +32,7 @@ public: static StackImpl& getStack(); static MemoryImpl& getMemory(); static dev::eth::ExtVMFace& getExt(); + static dev::u256 getGas(); private: StackImpl m_stack; From c0a7d82b216e60204db70146abf82b785be2df66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 12:50:23 +0200 Subject: [PATCH 090/396] Always commit cost blocks [#79942174] --- evmcc/Compiler.cpp | 4 +++- evmcc/GasMeter.cpp | 18 +++++++++++++----- evmcc/GasMeter.h | 6 +++++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index e532ce9f5..1fc4ef6a1 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -213,7 +213,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto inst = static_cast(bytecode[currentPC]); - gasMeter.check(inst); + gasMeter.count(inst); switch (inst) { @@ -819,6 +819,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } } + gasMeter.commitCostBlock(); + if (!builder.GetInsertBlock()->getTerminator()) // If block not terminated { if (basicBlock.end() == bytecode.size()) diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index fd68b9d40..7ba822e4a 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -97,22 +97,30 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_builder.SetInsertPoint(bb, pt); } -void GasMeter::check(Instruction _inst) +void GasMeter::count(Instruction _inst) { if (!m_checkCall) { // Create gas check call with mocked block cost at begining of current cost-block - m_checkCall = m_builder.CreateCall(m_gasCheckFunc, m_builder.getIntN(256, 0)); + m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256)); } m_blockCost += getStepCost(_inst); if (isCostBlockEnd(_inst)) - { - m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call + commitCostBlock(); +} + +void GasMeter::commitCostBlock() +{ + // If any uncommited block + if (m_checkCall) + { + m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block m_blockCost = 0; - } + } + assert(m_blockCost == 0); } void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder) diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 73f0d6e1c..38f780ca5 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -16,7 +16,11 @@ public: GasMeter(const GasMeter&) = delete; void operator=(GasMeter) = delete; - void check(dev::eth::Instruction _inst); + /// Count step cost of instruction + void count(dev::eth::Instruction _inst); + + /// Finalize cost block by checking gas needed for the block before the block + void commitCostBlock(); /// Generate code that checks the cost of additional memory used by program void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); From c968a3b594ffe349a7bec3a55a061cad3cdcf629 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 13:33:04 +0100 Subject: [PATCH 091/396] test cases for JUMP(I) --- evmcc/test/jump/badindirect1.evm | 1 + evmcc/test/jump/badindirect1.lll | 9 +++++++++ evmcc/test/jump/badindirect2.evm | 1 + evmcc/test/jump/badindirect2.lll | 12 ++++++++++++ evmcc/test/jump/badjump1.evm | 2 +- evmcc/test/jump/badjump1.lll | 7 ++----- evmcc/test/jump/badjump2.evm | 1 + evmcc/test/jump/badjump2.lll | 9 +++++++++ evmcc/test/jump/indirect2.lll | 4 ++-- evmcc/test/jump/indirect3.evm | 1 + evmcc/test/jump/indirect3.lll | 14 ++++++++++++++ evmcc/test/jump/indirect4.evm | 1 + evmcc/test/jump/indirect4.lll | 15 +++++++++++++++ 13 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 evmcc/test/jump/badindirect1.evm create mode 100644 evmcc/test/jump/badindirect1.lll create mode 100644 evmcc/test/jump/badindirect2.evm create mode 100644 evmcc/test/jump/badindirect2.lll create mode 100644 evmcc/test/jump/badjump2.evm create mode 100644 evmcc/test/jump/badjump2.lll create mode 100644 evmcc/test/jump/indirect3.evm create mode 100644 evmcc/test/jump/indirect3.lll create mode 100644 evmcc/test/jump/indirect4.evm create mode 100644 evmcc/test/jump/indirect4.lll diff --git a/evmcc/test/jump/badindirect1.evm b/evmcc/test/jump/badindirect1.evm new file mode 100644 index 000000000..b2a8aad67 --- /dev/null +++ b/evmcc/test/jump/badindirect1.evm @@ -0,0 +1 @@ +601b602502585d diff --git a/evmcc/test/jump/badindirect1.lll b/evmcc/test/jump/badindirect1.lll new file mode 100644 index 000000000..d6291be68 --- /dev/null +++ b/evmcc/test/jump/badindirect1.lll @@ -0,0 +1,9 @@ +;; Indirect jump out of code + +(asm +27 +37 +MUL +JUMP +JUMPDEST +) \ No newline at end of file diff --git a/evmcc/test/jump/badindirect2.evm b/evmcc/test/jump/badindirect2.evm new file mode 100644 index 000000000..22217523d --- /dev/null +++ b/evmcc/test/jump/badindirect2.evm @@ -0,0 +1 @@ +60016003600302596000600058 diff --git a/evmcc/test/jump/badindirect2.lll b/evmcc/test/jump/badindirect2.lll new file mode 100644 index 000000000..53a6294f7 --- /dev/null +++ b/evmcc/test/jump/badindirect2.lll @@ -0,0 +1,12 @@ +;; Indirect jump into data + +(asm +1 ;; 0 +3 +3 +MUL ;; 6 +JUMPI ;; 7 +0 ;; 8 +0 +JUMP +) \ No newline at end of file diff --git a/evmcc/test/jump/badjump1.evm b/evmcc/test/jump/badjump1.evm index b2a8aad67..5c11a8661 100644 --- a/evmcc/test/jump/badjump1.evm +++ b/evmcc/test/jump/badjump1.evm @@ -1 +1 @@ -601b602502585d +6103e758 diff --git a/evmcc/test/jump/badjump1.lll b/evmcc/test/jump/badjump1.lll index c3f9f8d69..1834a62ef 100644 --- a/evmcc/test/jump/badjump1.lll +++ b/evmcc/test/jump/badjump1.lll @@ -1,9 +1,6 @@ -;; Bad indirect jump. Should go to BadJumpBlock. +;; Direct jump out of code. (asm -27 -37 -MUL +999 JUMP -JUMPDEST ) \ No newline at end of file diff --git a/evmcc/test/jump/badjump2.evm b/evmcc/test/jump/badjump2.evm new file mode 100644 index 000000000..900a1c15a --- /dev/null +++ b/evmcc/test/jump/badjump2.evm @@ -0,0 +1 @@ +6004586000600058 diff --git a/evmcc/test/jump/badjump2.lll b/evmcc/test/jump/badjump2.lll new file mode 100644 index 000000000..ce61276d7 --- /dev/null +++ b/evmcc/test/jump/badjump2.lll @@ -0,0 +1,9 @@ +;; Direct jump into data + +(asm +4 ;; 0 0-3 +JUMP ;; 2 +0 ;; 3 3-4 +0 ;; 5 4-7 +JUMP ;; 6 +) \ No newline at end of file diff --git a/evmcc/test/jump/indirect2.lll b/evmcc/test/jump/indirect2.lll index 9a4db8c14..f2f068630 100644 --- a/evmcc/test/jump/indirect2.lll +++ b/evmcc/test/jump/indirect2.lll @@ -4,14 +4,14 @@ 8 ;; 0 6 ;; 2 ADD ;; 4 -JUMP ;; 5 +JUMP ;; 5 --> 14 STOP ;; 6 JUMPDEST ;; 7 1 ;; 8 0 ;; 10 MSTORE ;; 12 STOP ;; 13 -JUMPDEST ;; 14 +JUMPDEST ;; 14 2 0 MSTORE diff --git a/evmcc/test/jump/indirect3.evm b/evmcc/test/jump/indirect3.evm new file mode 100644 index 000000000..1fb0a356c --- /dev/null +++ b/evmcc/test/jump/indirect3.evm @@ -0,0 +1 @@ +6001600460050159005d6001600054 diff --git a/evmcc/test/jump/indirect3.lll b/evmcc/test/jump/indirect3.lll new file mode 100644 index 000000000..d6a679f9a --- /dev/null +++ b/evmcc/test/jump/indirect3.lll @@ -0,0 +1,14 @@ +;; Indirect JUMP + +(asm +1 ;; 0 +4 ;; 2 +5 ;; 4 +ADD ;; 6 +JUMPI ;; 7 +STOP ;; 8 +JUMPDEST ;; 9 +1 +0 +MSTORE +) \ No newline at end of file diff --git a/evmcc/test/jump/indirect4.evm b/evmcc/test/jump/indirect4.evm new file mode 100644 index 000000000..f0e31a8f4 --- /dev/null +++ b/evmcc/test/jump/indirect4.evm @@ -0,0 +1 @@ +60006007600501596001600054005d00 diff --git a/evmcc/test/jump/indirect4.lll b/evmcc/test/jump/indirect4.lll new file mode 100644 index 000000000..7fbe0b833 --- /dev/null +++ b/evmcc/test/jump/indirect4.lll @@ -0,0 +1,15 @@ +;; Indirect JUMP + +(asm +0 ;; 0 +7 ;; 2 +5 ;; 4 +ADD ;; 6 +JUMPI ;; 7 +1 ;; 8 +0 ;; 9 +MSTORE ;; 10 +STOP ;; 11 +JUMPDEST ;; 12 +STOP +) \ No newline at end of file From 1afcca2d0b3244073a6c4491eccd542e88714562 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 13:34:25 +0100 Subject: [PATCH 092/396] Implemented indirect JUMPI and fixes for JUMPs to invalid PCs --- evmcc/Compiler.cpp | 107 +++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 806592287..b6c420d53 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -137,7 +137,16 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) } } - for (auto it = splitPoints.cbegin(); it != splitPoints.cend() && *it < bytecode.size();) + // Remove split points generated from jumps out of code or into data. + for (auto it = splitPoints.cbegin(); it != splitPoints.cend(); ) + { + if (*it > bytecode.size() || !validJumpTargets[*it]) + it = splitPoints.erase(it); + else + ++it; + } + + for (auto it = splitPoints.cbegin(); it != splitPoints.cend(); ) { auto beginInstIdx = *it; ++it; @@ -151,28 +160,22 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { - if (it->second >= bytecode.size()) // Jump out of code + auto blockIter = basicBlocks.find(it->second); + if (blockIter != basicBlocks.end()) { - m_directJumpTargets[it->first] = m_finalBlock.get(); + m_directJumpTargets[it->first] = &(blockIter->second); } - else if (!validJumpTargets[it->second]) // Jump into data + else { std::cerr << "Bad JUMP at PC " << it->first << ": " << it->second << " is not a valid PC\n"; m_directJumpTargets[it->first] = m_badJumpBlock.get(); } - else - { - m_directJumpTargets[it->first] = &basicBlocks.find(it->second)->second; - } } for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) { - if (*it >= bytecode.size()) - m_indirectJumpTargets.push_back(m_finalBlock.get()); - else - m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); + m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); } } @@ -196,8 +199,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) createBasicBlocks(bytecode); // Init runtime structures. - auto memory = Memory(builder, module.get()); - auto ext = Ext(builder, module.get()); + Memory memory(builder, module.get()); + Ext ext(builder, module.get()); GasMeter gasMeter(builder, module.get()); // Jump to first instruction @@ -587,58 +590,56 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // 1. this is not the first instruction in the block // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) // Otherwise generate a indirect jump (a switch). + BasicBlock* targetBlock = nullptr; if (currentPC != basicBlock.begin()) { auto pairIter = m_directJumpTargets.find(currentPC); if (pairIter != m_directJumpTargets.end()) { - auto targetBlock = pairIter->second; + targetBlock = pairIter->second; + } + } + if (inst == Instruction::JUMP) + { + if (targetBlock) + { // The target address is computed at compile time, // just pop it without looking... stack.pop(); - - if (inst == Instruction::JUMP) - { - builder.CreateBr(targetBlock->llvm()); - } - else // JUMPI - { - auto top = stack.pop(); - auto zero = ConstantInt::get(Type::i256, 0); - auto cond = builder.CreateICmpNE(top, zero, "nonzero"); - - // Assume the basic blocks are properly ordered: - auto nextBBIter = basicBlockPairIt; - ++nextBBIter; - assert (nextBBIter != basicBlocks.end()); - auto& followBlock = nextBBIter->second; - builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm()); - } - break; + builder.CreateBr(targetBlock->llvm()); + } + else + { + // FIXME: this get(0) is a temporary workaround to get some of the jump tests running. + stack.get(0); + builder.CreateBr(m_jumpTableBlock->llvm()); } } - - if (inst == Instruction::JUMPI) + else // JUMPI { - std::cerr << "Indirect JUMPI is not supported yet (at PC " - << currentPC << ")\n"; - std::exit(1); + stack.swap(1); + auto val = stack.pop(); + auto zero = ConstantInt::get(Type::i256, 0); + auto cond = builder.CreateICmpNE(val, zero, "nonzero"); + + // Assume the basic blocks are properly ordered: + auto nextBBIter = basicBlockPairIt; + ++nextBBIter; + assert (nextBBIter != basicBlocks.end()); + auto& followBlock = nextBBIter->second; + + if (targetBlock) + { + stack.pop(); + builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm()); + } + else + { + builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), followBlock.llvm()); + } } - builder.CreateBr(m_jumpTableBlock->llvm()); - /* - // Generate switch for indirect jump. - auto dest = stack.pop(); - auto switchInstr = builder.CreateSwitch(dest, m_badJumpBlock->llvm(), - m_indirectJumpTargets.size()); - for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) - { - auto& bb = *it; - auto dest = ConstantInt::get(Type::i256, bb->begin()); - switchInstr->addCase(dest, bb->llvm()); - } - */ break; } @@ -865,7 +866,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } else { - builder.CreateRet(builder.getInt64(0)); + builder.CreateBr(m_badJumpBlock->llvm()); } linkBasicBlocks(); From deb0957087f8aa196cf4fb140b4e3f5c586f2067 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 14:46:21 +0100 Subject: [PATCH 093/396] test cases for JUMP --- evmcc/test/jump/call1.ethel | 2 ++ evmcc/test/jump/call1.evm | 2 +- evmcc/test/jump/call2.ethel | 5 +++++ evmcc/test/jump/call2.evm | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 evmcc/test/jump/call2.ethel create mode 100644 evmcc/test/jump/call2.evm diff --git a/evmcc/test/jump/call1.ethel b/evmcc/test/jump/call1.ethel index 206fb4c75..414ad0124 100644 --- a/evmcc/test/jump/call1.ethel +++ b/evmcc/test/jump/call1.ethel @@ -1,3 +1,5 @@ let f n = n + 1 return f 2 + + diff --git a/evmcc/test/jump/call1.evm b/evmcc/test/jump/call1.evm index 1f50b683f..252aaf778 100644 --- a/evmcc/test/jump/call1.evm +++ b/evmcc/test/jump/call1.evm @@ -1 +1 @@ -630000000d60026300000016585d60005460206000f280600101915058 \ No newline at end of file +600760026010585d60005460206000f28060010190509058 \ No newline at end of file diff --git a/evmcc/test/jump/call2.ethel b/evmcc/test/jump/call2.ethel new file mode 100644 index 000000000..bdeb9b734 --- /dev/null +++ b/evmcc/test/jump/call2.ethel @@ -0,0 +1,5 @@ +let f a b = a + b + +return f 2 3 + + diff --git a/evmcc/test/jump/call2.evm b/evmcc/test/jump/call2.evm new file mode 100644 index 000000000..6832e044d --- /dev/null +++ b/evmcc/test/jump/call2.evm @@ -0,0 +1 @@ +6009600260036012585d60005460206000f2818101905090509058 \ No newline at end of file From 3ec44144e5936cf0fd20c01569d65f7274fd360c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 16:05:06 +0200 Subject: [PATCH 094/396] Change basic block linking order to get better results (still not perfect) --- evmcc/Compiler.cpp | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 1fc4ef6a1..4be6066e5 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -5,6 +5,8 @@ #include #include +#include +//#include #include @@ -901,36 +903,26 @@ void Compiler::linkBasicBlocks() auto phi = llvm::cast(instIt); for (auto predIt = llvm::pred_begin(_llbb); predIt != llvm::pred_end(_llbb); ++predIt) { + // TODO: In case entry block is reached - report error auto& predBB = findBasicBlock(*predIt); - // assert(valueIdx < predBB.getStack().size()); // TODO: Report error - phi->addIncoming(predBB.getStack().get(valueIdx), predBB); + auto value = predBB.getStack().get(valueIdx); + phi->addIncoming(value, predBB); } } }; - // Link basic blocks - for (auto&& p : basicBlocks) + + // TODO: It is crappy visiting of basic blocks. + llvm::SmallPtrSet visitSet; + for (auto&& bb : basicBlocks) // TODO: External loop is to visit unreable blocks that can also have phi nodes { - BasicBlock& bb = p.second; - completePhiNodes(bb.llvm()); - } - completePhiNodes(m_jumpTableBlock->llvm()); - /* - llvm::BasicBlock* llvmBB = bb.llvm(); - - size_t valueIdx = 0; - auto firstNonPhi = llvmBB->getFirstNonPHI(); - for (auto instIt = llvmBB->begin(); &*instIt != firstNonPhi; ++instIt, ++valueIdx) + for (auto it = llvm::po_ext_begin(bb.second.llvm(), visitSet), + end = llvm::po_ext_end(bb.second.llvm(), visitSet); it != end; ++it) { - auto phi = llvm::cast(instIt); - for (auto predIt = llvm::pred_begin(llvmBB); predIt != llvm::pred_end(llvmBB); ++predIt) - { - auto& predBB = findBasicBlock(*predIt); - assert(valueIdx < predBB.getStack().size()); // TODO: Report error - phi->addIncoming(predBB.getStack().get(valueIdx), predBB); - } + std::cerr << it->getName().str() << std::endl; + completePhiNodes(*it); } - */ + } } } From 1de697df99c5c67a4a1ea712a4d91d2b20538a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 16:32:52 +0200 Subject: [PATCH 095/396] Do not commit gas costs on JUMPDEST instruction [#80544260] --- evmcc/GasMeter.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 7ba822e4a..906b4dcb0 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -51,24 +51,20 @@ uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to F bool isCostBlockEnd(Instruction _inst) { + // Basic block terminators like STOP are not needed on the list + // as cost will be commited at the end of basic block switch (_inst) { - case Instruction::STOP: case Instruction::CALLDATACOPY: case Instruction::CODECOPY: case Instruction::MLOAD: case Instruction::MSTORE: case Instruction::MSTORE8: case Instruction::SSTORE: - case Instruction::JUMP: - case Instruction::JUMPI: - case Instruction::JUMPDEST: case Instruction::GAS: case Instruction::CREATE: case Instruction::CALL: case Instruction::CALLCODE: - case Instruction::RETURN: - case Instruction::SUICIDE: return true; default: From 0c708339e58051df7423a39a8250eaa5e7c0860e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 16:33:51 +0200 Subject: [PATCH 096/396] Do not check gas cost of value 0 [Delivers #80544260] --- evmcc/GasMeter.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 906b4dcb0..13d81b080 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -112,7 +112,11 @@ void GasMeter::commitCostBlock() // If any uncommited block if (m_checkCall) { - m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call + if (m_blockCost > 0) // If any cost + m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call + else + m_checkCall->eraseFromParent(); // Remove the gas check call + m_checkCall = nullptr; // End cost-block m_blockCost = 0; } From 86949720b1a2c7e0f0e08797217236d76d738369 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 15:37:40 +0100 Subject: [PATCH 097/396] test cases for JUMPS/phi nodes --- evmcc/test/jump/loop1.evm | 1 + evmcc/test/jump/loop1.lll | 27 +++++++++++++++++++++++++++ evmcc/test/jump/loop2.evm | 1 + evmcc/test/jump/loop2.lll | 28 ++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 evmcc/test/jump/loop1.evm create mode 100644 evmcc/test/jump/loop1.lll create mode 100644 evmcc/test/jump/loop2.evm create mode 100644 evmcc/test/jump/loop2.lll diff --git a/evmcc/test/jump/loop1.evm b/evmcc/test/jump/loop1.evm new file mode 100644 index 000000000..b209951fa --- /dev/null +++ b/evmcc/test/jump/loop1.evm @@ -0,0 +1 @@ +600a600181038060025900 diff --git a/evmcc/test/jump/loop1.lll b/evmcc/test/jump/loop1.lll new file mode 100644 index 000000000..1d9483eb8 --- /dev/null +++ b/evmcc/test/jump/loop1.lll @@ -0,0 +1,27 @@ +;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits + +(asm +10 + +;; 2 +1 +DUP2 +SUB +DUP1 +2 +JUMPI + +;; stack = 1 2 3 4 5 6 7 8 9 10 +;;0 +;;MSTORE +;;1 +;;MSTORE +;;2 +;;MSTORE +;;3 +;;MSTORE + +STOP +) + + diff --git a/evmcc/test/jump/loop2.evm b/evmcc/test/jump/loop2.evm new file mode 100644 index 000000000..c95047707 --- /dev/null +++ b/evmcc/test/jump/loop2.evm @@ -0,0 +1 @@ +600a80600160800360a060025900 diff --git a/evmcc/test/jump/loop2.lll b/evmcc/test/jump/loop2.lll new file mode 100644 index 000000000..29d5e0ace --- /dev/null +++ b/evmcc/test/jump/loop2.lll @@ -0,0 +1,28 @@ +;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits + +(asm +10 + +;; 2 +DUP1 +1 +SWAP +SUB +DUP +2 +JUMPI + +;; stack = 1 2 3 4 5 6 7 8 9 10 +;;0 +;;MSTORE +;;1 +;;MSTORE +;;2 +;;MSTORE +;;3 +;;MSTORE + +STOP +) + + From b56a815d2cfbe447dc815f37002c4976b9a7c25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 17:39:27 +0200 Subject: [PATCH 098/396] Report error if static-analysed stack is too small --- evmcc/Compiler.cpp | 26 ++++++++++++++++++-------- evmcc/GasMeter.cpp | 2 +- evmcc/test/jump/loop1.evm | 2 +- evmcc/test/jump/loop1.lll | 12 ++++++------ evmcc/test/jump/loop2.evm | 2 +- evmcc/test/jump/loop2.lll | 16 ++++++++-------- 6 files changed, 35 insertions(+), 25 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 0fa2c5c03..2ee349a9e 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -882,17 +882,22 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) void Compiler::linkBasicBlocks() { /// Helper function that finds basic block given LLVM basic block pointer - auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock& + auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock* { // TODO: Fix for finding jumpTableBlock if (_llbb == this->m_jumpTableBlock->llvm()) - return *this->m_jumpTableBlock; + return this->m_jumpTableBlock.get(); + + for (auto&& bb : this->basicBlocks) + if (_llbb == bb.second.llvm()) + return &bb.second; + return nullptr; // Name is used to get basic block index (index of first instruction) // TODO: If basicBlocs are still a map - multikey map can be used - auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2); - auto idx = std::stoul(idxStr); - return basicBlocks.find(idx)->second; + //auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2); + //auto idx = std::stoul(idxStr); + //return basicBlocks.find(idx)->second; }; auto completePhiNodes = [findBasicBlock](llvm::BasicBlock* _llbb) -> void @@ -905,9 +910,14 @@ void Compiler::linkBasicBlocks() for (auto predIt = llvm::pred_begin(_llbb); predIt != llvm::pred_end(_llbb); ++predIt) { // TODO: In case entry block is reached - report error - auto& predBB = findBasicBlock(*predIt); - auto value = predBB.getStack().get(valueIdx); - phi->addIncoming(value, predBB); + auto predBB = findBasicBlock(*predIt); + if (!predBB) + { + std::cerr << "Stack too small in " << _llbb->getName().str() << std::endl; + std::exit(1); + } + auto value = predBB->getStack().get(valueIdx); + phi->addIncoming(value, predBB->llvm()); } } }; diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 13d81b080..1f0465126 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -45,7 +45,7 @@ uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to F return static_cast(c_createGas); default: // Assumes instruction code is valid - return static_cast(c_stepGas);; + return static_cast(c_stepGas); } } diff --git a/evmcc/test/jump/loop1.evm b/evmcc/test/jump/loop1.evm index b209951fa..7724d6308 100644 --- a/evmcc/test/jump/loop1.evm +++ b/evmcc/test/jump/loop1.evm @@ -1 +1 @@ -600a600181038060025900 +600a600181038060025960005460015460025400 diff --git a/evmcc/test/jump/loop1.lll b/evmcc/test/jump/loop1.lll index 1d9483eb8..0044ec1fb 100644 --- a/evmcc/test/jump/loop1.lll +++ b/evmcc/test/jump/loop1.lll @@ -12,12 +12,12 @@ DUP1 JUMPI ;; stack = 1 2 3 4 5 6 7 8 9 10 -;;0 -;;MSTORE -;;1 -;;MSTORE -;;2 -;;MSTORE +0 +MSTORE +1 +MSTORE +2 +MSTORE ;;3 ;;MSTORE diff --git a/evmcc/test/jump/loop2.evm b/evmcc/test/jump/loop2.evm index c95047707..faffa4e5b 100644 --- a/evmcc/test/jump/loop2.evm +++ b/evmcc/test/jump/loop2.evm @@ -1 +1 @@ -600a80600160800360a060025900 +600a80600190038060025960005460015460025400 diff --git a/evmcc/test/jump/loop2.lll b/evmcc/test/jump/loop2.lll index 29d5e0ace..9996c52ba 100644 --- a/evmcc/test/jump/loop2.lll +++ b/evmcc/test/jump/loop2.lll @@ -6,19 +6,19 @@ ;; 2 DUP1 1 -SWAP +SWAP1 SUB -DUP +DUP1 2 JUMPI ;; stack = 1 2 3 4 5 6 7 8 9 10 -;;0 -;;MSTORE -;;1 -;;MSTORE -;;2 -;;MSTORE +0 +MSTORE +1 +MSTORE +2 +MSTORE ;;3 ;;MSTORE From 6eb64ddcda93810a3c44f919049e3306deee2bf7 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 16:57:13 +0100 Subject: [PATCH 099/396] Codegen for GAS --- evmcc/Compiler.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 0fa2c5c03..91758984d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -659,6 +659,13 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::GAS: + { + auto value = builder.CreateLoad(gasMeter.getLLVMGasVar()); + stack.push(value); + break; + } + case Instruction::ADDRESS: { auto value = ext.address(); From 2031240485a4290345ad2828d84477767b0b1a68 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 17:22:56 +0100 Subject: [PATCH 100/396] Implemented ADDMOD, MULMOD and GAS [Delivers #80566276] --- evmcc/Compiler.cpp | 30 ++++++++++++++++++++++++++++++ evmcc/GasMeter.cpp | 7 ++++++- evmcc/GasMeter.h | 2 ++ evmcc/test/arith/addmod.evm | 1 + evmcc/test/arith/addmod.lll | 12 ++++++++++++ evmcc/test/arith/mulmod.evm | 1 + evmcc/test/arith/mulmod.lll | 12 ++++++++++++ 7 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 evmcc/test/arith/addmod.evm create mode 100644 evmcc/test/arith/addmod.lll create mode 100644 evmcc/test/arith/mulmod.evm create mode 100644 evmcc/test/arith/mulmod.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 91758984d..b5270d85a 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -434,6 +434,36 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::ADDMOD: + { + auto val1 = stack.pop(); + auto val2 = stack.pop(); + auto sum = builder.CreateAdd(val1, val2); + auto mod = stack.pop(); + + auto sum128 = builder.CreateTrunc(sum, Type::lowPrecision); + auto mod128 = builder.CreateTrunc(mod, Type::lowPrecision); + auto res128 = builder.CreateURem(sum128, mod128); + auto res256 = builder.CreateZExt(res128, Type::i256); + stack.push(res256); + break; + } + + case Instruction::MULMOD: + { + auto val1 = stack.pop(); + auto val2 = stack.pop(); + auto prod = builder.CreateMul(val1, val2); + auto mod = stack.pop(); + + auto prod128 = builder.CreateTrunc(prod, Type::lowPrecision); + auto mod128 = builder.CreateTrunc(mod, Type::lowPrecision); + auto res128 = builder.CreateURem(prod128, mod128); + auto res256 = builder.CreateZExt(res128, Type::i256); + stack.push(res256); + break; + } + case Instruction::SHA3: { auto inOff = stack.pop(); diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 13d81b080..918be7bf7 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -130,4 +130,9 @@ void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilde _builder.CreateCall(m_gasCheckFunc, cost); } -} \ No newline at end of file +llvm::GlobalVariable* GasMeter::getLLVMGasVar() +{ + return m_gas; +} + +} diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 1fcbe6459..c3ea9f84f 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -25,6 +25,8 @@ public: /// Generate code that checks the cost of additional memory used by program void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); + llvm::GlobalVariable* getLLVMGasVar(); + private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow diff --git a/evmcc/test/arith/addmod.evm b/evmcc/test/arith/addmod.evm new file mode 100644 index 000000000..4ca71e065 --- /dev/null +++ b/evmcc/test/arith/addmod.evm @@ -0,0 +1 @@ +60646107b760271460005560006001f2 diff --git a/evmcc/test/arith/addmod.lll b/evmcc/test/arith/addmod.lll new file mode 100644 index 000000000..11a6b2cb9 --- /dev/null +++ b/evmcc/test/arith/addmod.lll @@ -0,0 +1,12 @@ +;; Should return (1975 + 39) `mod` 100 = 14 = 0x0e +(asm +100 +1975 +39 +ADDMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/arith/mulmod.evm b/evmcc/test/arith/mulmod.evm new file mode 100644 index 000000000..e34a06154 --- /dev/null +++ b/evmcc/test/arith/mulmod.evm @@ -0,0 +1 @@ +6064601b60251560005560006001f2 diff --git a/evmcc/test/arith/mulmod.lll b/evmcc/test/arith/mulmod.lll new file mode 100644 index 000000000..5e87f0843 --- /dev/null +++ b/evmcc/test/arith/mulmod.lll @@ -0,0 +1,12 @@ +;; Should return (27 * 37) `mod` 100 = 99 = 0x63 +(asm +100 +27 +37 +MULMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file From 9c268561bd924484133129e561c26bb542172886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 18:43:33 +0200 Subject: [PATCH 101/396] Define constants and return codes --- evmcc/Type.cpp | 7 +++++++ evmcc/Type.h | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/evmcc/Type.cpp b/evmcc/Type.cpp index 0c8b6d92e..b71f12868 100644 --- a/evmcc/Type.cpp +++ b/evmcc/Type.cpp @@ -12,6 +12,7 @@ llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; +llvm::Type* Type::MainReturn; void Type::init(llvm::LLVMContext& _context) { @@ -21,6 +22,12 @@ void Type::init(llvm::LLVMContext& _context) Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); + MainReturn = llvm::Type::getInt32Ty(_context); +} + +llvm::Constant* Constant::get(ReturnCode _returnCode) +{ + return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); } } diff --git a/evmcc/Type.h b/evmcc/Type.h index fe4bce335..4b45a8453 100644 --- a/evmcc/Type.h +++ b/evmcc/Type.h @@ -2,6 +2,7 @@ #pragma once #include +#include namespace evmcc { @@ -20,7 +21,24 @@ struct Type static llvm::Type* Void; + /// Main function return type + static llvm::Type* MainReturn; + static void init(llvm::LLVMContext& _context); }; +enum class ReturnCode +{ + Stop = 0, + Return = 1, + Suicide = 2, + + BadJumpDestination = 101, +}; + +struct Constant +{ + static llvm::Constant* get(ReturnCode _returnCode); +}; + } From f9f08d3223cb8be4fac8b32092219b9b2dbf7492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 18:44:06 +0200 Subject: [PATCH 102/396] Change the way compiled program returns --- evmcc/Compiler.cpp | 19 ++++-------- evmcc/ExecutionEngine.cpp | 10 +++--- evmcc/Memory.cpp | 64 ++++++++++++++++----------------------- evmcc/Memory.h | 9 ++++-- 4 files changed, 45 insertions(+), 57 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 2ee349a9e..8035a4fad 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -190,10 +190,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) IRBuilder<> builder(context); // Create main function - const auto i32Ty = builder.getInt32Ty(); - //Type* retTypeElems[] = {i32Ty, i32Ty}; - //auto retType = StructType::create(retTypeElems, "MemRef", true); - m_mainFunc = Function::Create(FunctionType::get(builder.getInt64Ty(), false), Function::ExternalLinkage, "main", module.get()); + m_mainFunc = Function::Create(FunctionType::get(Type::MainReturn, false), Function::ExternalLinkage, "main", module.get()); // Create the basic blocks. auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc); @@ -797,13 +794,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto index = stack.pop(); auto size = stack.pop(); - auto ret = builder.CreateTrunc(index, builder.getInt64Ty()); - ret = builder.CreateShl(ret, 32); - size = builder.CreateTrunc(size, i32Ty); - size = builder.CreateZExt(size, builder.getInt64Ty()); - ret = builder.CreateOr(ret, size); + memory.registerReturnData(index, size); - builder.CreateRet(ret); + builder.CreateRet(Constant::get(ReturnCode::Return)); break; } @@ -815,7 +808,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } case Instruction::STOP: { - builder.CreateRet(builder.getInt64(0)); + builder.CreateRet(Constant::get(ReturnCode::Stop)); break; } @@ -847,11 +840,11 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Note: Right now the codegen for special blocks depends only on createBasicBlock(), // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). builder.SetInsertPoint(m_finalBlock->llvm()); - builder.CreateRet(builder.getInt64(0)); + builder.CreateRet(Constant::get(ReturnCode::Stop)); // TODO: throw an exception or something builder.SetInsertPoint(m_badJumpBlock->llvm()); - builder.CreateRet(builder.getInt64(0)); + builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index be45ff838..31c87d19b 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -14,6 +14,8 @@ #include #include "Runtime.h" +#include "Memory.h" +#include "Type.h" namespace evmcc { @@ -97,13 +99,13 @@ int ExecutionEngine::run(std::unique_ptr _module) auto result = exec->runFunction(entryFunc, {}); gas = static_cast(Runtime::getGas()); - if (auto intResult = result.IntVal.getZExtValue()) + auto returnCode = static_cast(result.IntVal.getZExtValue()); + if (returnCode == ReturnCode::Return) { - auto index = intResult >> 32; - auto size = 0xFFFFFFFF & intResult; + auto&& returnData = Memory::getReturnData(); std::cout << "RETURN [ "; - for (dev::bytes::const_iterator it = Runtime::getMemory().cbegin() + index, end = it + size; it != end; ++it) + for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; std::cout << "]\n"; diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 8625d7b5b..e585a9406 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -21,20 +21,8 @@ namespace evmcc Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter): m_builder(_builder) { - auto voidTy = m_builder.getVoidTy(); auto i64Ty = m_builder.getInt64Ty(); - - auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false); - m_memRequire = llvm::Function::Create(memRequireTy, - llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_require", _module); - - auto memSizeTy = llvm::FunctionType::get(i64Ty, false); - m_memSize = llvm::Function::Create(memSizeTy, - llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_size", _module); - - std::vector argTypes = {i64Ty, i64Ty}; + llvm::Type* argTypes[] = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_memory_dump", _module); @@ -45,6 +33,12 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, m_builder.getIntN(256, 0), "mem.size"); m_size->setUnnamedAddr(true); // Address is not important + m_returnDataOffset = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset"); + m_returnDataOffset->setUnnamedAddr(true); // Address is not important + + m_returnDataSize = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); + m_returnDataSize->setUnnamedAddr(true); // Address is not important + m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); m_loadWord = createFunc(false, Type::i256, _module, _gasMeter); m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); @@ -137,6 +131,12 @@ llvm::Value* Memory::getSize() return m_builder.CreateLoad(m_size); } +void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) +{ + m_builder.CreateStore(_index, m_returnDataOffset); + m_builder.CreateStore(_size, m_returnDataSize); +} + void Memory::dump(uint64_t _begin, uint64_t _end) { if (getenv("EVMCC_DEBUG_MEMORY") == nullptr) @@ -155,6 +155,9 @@ extern "C" { using namespace evmcc; +EXPORT i256 mem_returnDataOffset; +EXPORT i256 mem_returnDataSize; + EXPORT uint8_t* mem_resize(i256* _size) { auto size = _size->a; // Trunc to 64-bit @@ -163,37 +166,13 @@ EXPORT uint8_t* mem_resize(i256* _size) return memory.data(); } -// Resizes memory to contain at least _index + 1 bytes and returns the base address. -EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) -{ - uint64_t requiredSize = (_index / 32 + 1) * 32; - auto&& memory = Runtime::getMemory(); - - if (memory.size() < requiredSize) - { - std::cerr << "MEMORY: current size: " << std::dec - << memory.size() << " bytes, required size: " - << requiredSize << " bytes" - << std::endl; - - memory.resize(requiredSize); - } - - return memory.data(); -} - -EXPORT uint64_t evmccrt_memory_size() -{ - return Runtime::getMemory().size() / 32; -} - 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 - << evmccrt_memory_size() << " words\n"; + << Runtime::getMemory().size() / 32 << " words\n"; std::cerr << "MEMORY: dump from " << std::dec << _begin << " to " << _end << ":"; if (_end <= _begin) @@ -212,3 +191,12 @@ EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) } } // extern "C" + +dev::bytesConstRef evmcc::Memory::getReturnData() +{ + // TODO: Handle large indexes + auto offset = static_cast(llvm2eth(mem_returnDataOffset)); + auto size = static_cast(llvm2eth(mem_returnDataSize)); + auto& memory = Runtime::getMemory(); + return {memory.data() + offset, size}; +} diff --git a/evmcc/Memory.h b/evmcc/Memory.h index ed7273c5c..c01bd6ef8 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -20,6 +20,9 @@ public: void storeByte(llvm::Value* _addr, llvm::Value* _byte); llvm::Value* getSize(); + void registerReturnData(llvm::Value* _index, llvm::Value* _size); + static dev::bytesConstRef getReturnData(); + void dump(uint64_t _begin, uint64_t _end = 0); private: @@ -31,14 +34,16 @@ private: llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; + /// @TODO: m_data and m_size could be used + llvm::GlobalVariable* m_returnDataOffset; + llvm::GlobalVariable* m_returnDataSize; + llvm::Function* m_loadWord; llvm::Function* m_storeWord; llvm::Function* m_storeByte; llvm::Function* m_resize; - llvm::Function* m_memRequire; llvm::Function* m_memDump; - llvm::Function* m_memSize; }; } From 16023daf0b402094780185088a2467dbaad90c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 19:09:42 +0200 Subject: [PATCH 103/396] Allocate memory and count gas for RETURN instruction [#79942174] --- evmcc/ExecutionEngine.cpp | 2 +- evmcc/Memory.cpp | 3 +++ evmcc/Type.cpp | 5 +++++ evmcc/Type.h | 3 +++ evmcc/bytecode/return2.evm | 1 + evmcc/lll/return2.lll | 6 ++++++ 6 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 evmcc/bytecode/return2.evm create mode 100644 evmcc/lll/return2.lll diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 31c87d19b..0e6df0b24 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -102,7 +102,7 @@ int ExecutionEngine::run(std::unique_ptr _module) auto returnCode = static_cast(result.IntVal.getZExtValue()); if (returnCode == ReturnCode::Return) { - auto&& returnData = Memory::getReturnData(); + auto&& returnData = Memory::getReturnData(); // TODO: It might be better to place is in Runtime interface std::cout << "RETURN [ "; for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index e585a9406..f6eafb389 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -133,6 +133,9 @@ llvm::Value* Memory::getSize() void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) { + auto lastWord = m_builder.CreateAdd(_index, m_builder.CreateSub(_size, Constant::get(32)), "lastWord"); + loadWord(lastWord); // Make sure that memory is allocated and count gas + m_builder.CreateStore(_index, m_returnDataOffset); m_builder.CreateStore(_size, m_returnDataSize); } diff --git a/evmcc/Type.cpp b/evmcc/Type.cpp index b71f12868..4837829b4 100644 --- a/evmcc/Type.cpp +++ b/evmcc/Type.cpp @@ -25,6 +25,11 @@ void Type::init(llvm::LLVMContext& _context) MainReturn = llvm::Type::getInt32Ty(_context); } +llvm::Constant* Constant::get(uint64_t _n) +{ + return llvm::ConstantInt::get(Type::i256, _n); +} + llvm::Constant* Constant::get(ReturnCode _returnCode) { return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); diff --git a/evmcc/Type.h b/evmcc/Type.h index 4b45a8453..a8501d897 100644 --- a/evmcc/Type.h +++ b/evmcc/Type.h @@ -38,6 +38,9 @@ enum class ReturnCode struct Constant { + /// Returns word-size constant + static llvm::Constant* get(uint64_t _n); + static llvm::Constant* get(ReturnCode _returnCode); }; diff --git a/evmcc/bytecode/return2.evm b/evmcc/bytecode/return2.evm new file mode 100644 index 000000000..e29da7664 --- /dev/null +++ b/evmcc/bytecode/return2.evm @@ -0,0 +1 @@ +6001620f4240f2 diff --git a/evmcc/lll/return2.lll b/evmcc/lll/return2.lll new file mode 100644 index 000000000..f5ee68f6e --- /dev/null +++ b/evmcc/lll/return2.lll @@ -0,0 +1,6 @@ + +(asm +1 +1000000 +RETURN ;; return 1 byte from index 1M +) \ No newline at end of file From 05952064dc6e8d55bc67af7f7cfa9a47f47f30d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 13 Oct 2014 19:14:33 +0200 Subject: [PATCH 104/396] Use Constant::get() interface to create LLVM constants --- evmcc/Compiler.cpp | 12 ++++++------ evmcc/GasMeter.cpp | 4 ++-- evmcc/Memory.cpp | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 8035a4fad..fd295d891 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -420,12 +420,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 - auto shbits = builder.CreateShl(byteNum, builder.getIntN(256, 3)); + auto shbits = builder.CreateShl(byteNum, Constant::get(3)); value = builder.CreateShl(value, shbits); - value = builder.CreateLShr(value, builder.getIntN(256, 31 * 8)); + value = builder.CreateLShr(value, Constant::get(31 * 8)); - auto byteNumValid = builder.CreateICmpULT(byteNum, builder.getIntN(256, 32)); - value = builder.CreateSelect(byteNumValid, value, builder.getIntN(256, 0)); + auto byteNumValid = builder.CreateICmpULT(byteNum, Constant::get(32)); + value = builder.CreateSelect(byteNumValid, value, Constant::get(0)); stack.push(value); break; @@ -651,7 +651,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::PC: { - auto value = builder.getIntN(256, currentPC); + auto value = Constant::get(currentPC); stack.push(value); break; } @@ -716,7 +716,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::CODESIZE: { - auto value = builder.getIntN(256, bytecode.size()); + auto value = Constant::get(bytecode.size()); stack.push(value); break; } diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 1f0465126..cd88df646 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -113,7 +113,7 @@ void GasMeter::commitCostBlock() if (m_checkCall) { if (m_blockCost > 0) // If any cost - m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call + m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call else m_checkCall->eraseFromParent(); // Remove the gas check call @@ -126,7 +126,7 @@ void GasMeter::commitCostBlock() void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder) { // Memory uses other builder, but that can be changes later - auto cost = _builder.CreateMul(_additionalMemoryInWords, _builder.getIntN(256, static_cast(c_memoryGas)), "memcost"); + auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); _builder.CreateCall(m_gasCheckFunc, cost); } diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index f6eafb389..4d4a34928 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -30,7 +30,7 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga 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_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, m_builder.getIntN(256, 0), "mem.size"); + m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); m_size->setUnnamedAddr(true); // Address is not important m_returnDataOffset = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset"); @@ -63,7 +63,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: llvm::Value* index = func->arg_begin(); index->setName("index"); auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - auto sizeRequired = builder.CreateAdd(index, builder.getIntN(256, valueSize), "sizeRequired"); + auto sizeRequired = builder.CreateAdd(index, Constant::get(valueSize), "sizeRequired"); auto size = builder.CreateLoad(m_size, "size"); auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights? @@ -71,8 +71,8 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: // BB "resize" builder.SetInsertPoint(resizeBB); // Check gas first - auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, builder.getIntN(256, 31)), builder.getIntN(256, 32), "wordsRequired"); - auto words = builder.CreateUDiv(builder.CreateAdd(size, builder.getIntN(256, 31)), builder.getIntN(256, 32), "words"); + auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired"); + auto words = builder.CreateUDiv(builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words"); auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords"); _gasMeter.checkMemory(newWords, builder); // Resize From a5c239ffc9bf90aad71795cce10ba8ca570a56d6 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 09:24:33 +0100 Subject: [PATCH 105/396] Fixes in inline asm in some jump tests. --- evmcc/test/jump/loop1.evm | 2 +- evmcc/test/jump/loop1.lll | 16 ++++++++-------- evmcc/test/jump/loop2.evm | 2 +- evmcc/test/jump/loop2.lll | 22 +++++++++++----------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/evmcc/test/jump/loop1.evm b/evmcc/test/jump/loop1.evm index b209951fa..e7cbc4aa9 100644 --- a/evmcc/test/jump/loop1.evm +++ b/evmcc/test/jump/loop1.evm @@ -1 +1 @@ -600a600181038060025900 +600a600181038060025960005460015460025460035400 diff --git a/evmcc/test/jump/loop1.lll b/evmcc/test/jump/loop1.lll index 1d9483eb8..8ce24e4cd 100644 --- a/evmcc/test/jump/loop1.lll +++ b/evmcc/test/jump/loop1.lll @@ -12,14 +12,14 @@ DUP1 JUMPI ;; stack = 1 2 3 4 5 6 7 8 9 10 -;;0 -;;MSTORE -;;1 -;;MSTORE -;;2 -;;MSTORE -;;3 -;;MSTORE +0 +MSTORE +1 +MSTORE +2 +MSTORE +3 +MSTORE STOP ) diff --git a/evmcc/test/jump/loop2.evm b/evmcc/test/jump/loop2.evm index c95047707..6a55228a8 100644 --- a/evmcc/test/jump/loop2.evm +++ b/evmcc/test/jump/loop2.evm @@ -1 +1 @@ -600a80600160800360a060025900 +600a80600190038060025960005460015460025460035400 diff --git a/evmcc/test/jump/loop2.lll b/evmcc/test/jump/loop2.lll index 29d5e0ace..b53e6713d 100644 --- a/evmcc/test/jump/loop2.lll +++ b/evmcc/test/jump/loop2.lll @@ -5,22 +5,22 @@ ;; 2 DUP1 -1 -SWAP +1 +SWAP1 SUB -DUP +DUP1 2 JUMPI ;; stack = 1 2 3 4 5 6 7 8 9 10 -;;0 -;;MSTORE -;;1 -;;MSTORE -;;2 -;;MSTORE -;;3 -;;MSTORE +0 +MSTORE +1 +MSTORE +2 +MSTORE +3 +MSTORE STOP ) From c5c76cdf99987c84d5d0f8a689bfc72969cde090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 13:27:45 +0200 Subject: [PATCH 106/396] Count gas for CALL instructions [#79942174] --- evmcc/Compiler.cpp | 1 + evmcc/GasMeter.cpp | 23 ++++++++++++++++------- evmcc/GasMeter.h | 5 +++-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index fd295d891..c48036d62 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -784,6 +784,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto outOff = stack.pop(); auto outSize = stack.pop(); + gasMeter.commitCostBlock(gas); auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize); stack.push(ret); break; diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index cd88df646..6295ffe79 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -53,6 +53,9 @@ bool isCostBlockEnd(Instruction _inst) { // Basic block terminators like STOP are not needed on the list // as cost will be commited at the end of basic block + + // CALL & CALLCODE are commited manually + switch (_inst) { case Instruction::CALLDATACOPY: @@ -63,8 +66,6 @@ bool isCostBlockEnd(Instruction _inst) case Instruction::SSTORE: case Instruction::GAS: case Instruction::CREATE: - case Instruction::CALL: - case Instruction::CALLCODE: return true; default: @@ -107,16 +108,24 @@ void GasMeter::count(Instruction _inst) commitCostBlock(); } -void GasMeter::commitCostBlock() +void GasMeter::commitCostBlock(llvm::Value* _additionalCost) { + assert(!_additionalCost || m_checkCall); // _additionalCost => m_checkCall; Must be inside cost-block + // If any uncommited block if (m_checkCall) { - if (m_blockCost > 0) // If any cost - m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call - else + if (m_blockCost == 0 && !_additionalCost) // Do not check 0 + { m_checkCall->eraseFromParent(); // Remove the gas check call - + return; + } + + llvm::Value* cost = Constant::get(m_blockCost); + if (_additionalCost) + cost = m_builder.CreateAdd(cost, _additionalCost); + + m_checkCall->setArgOperand(0, cost); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block m_blockCost = 0; } diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 1fcbe6459..3a1f7ba66 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -19,8 +19,9 @@ public: /// Count step cost of instruction void count(dev::eth::Instruction _inst); - /// Finalize cost block by checking gas needed for the block before the block - void commitCostBlock(); + /// Finalize cost-block by checking gas needed for the block before the block + /// @param _additionalCost adds additional cost to cost-block before commit + void commitCostBlock(llvm::Value* _additionalCost = nullptr); /// Generate code that checks the cost of additional memory used by program void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); From 2999de9f1a2bb6a598bd44ad1a8aeffa2345f45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 14:29:19 +0200 Subject: [PATCH 107/396] Give back an amount of gas not used by CALL instructions [#79942174] --- evmcc/Compiler.cpp | 1 + evmcc/Ext.cpp | 7 ++++--- evmcc/Ext.h | 2 +- evmcc/GasMeter.cpp | 7 +++++++ evmcc/GasMeter.h | 3 +++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index c48036d62..37a4d89a1 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -786,6 +786,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) gasMeter.commitCostBlock(gas); auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize); + gasMeter.giveBack(gas); stack.push(ret); break; } diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 1d309947d..878f187f1 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -165,7 +165,7 @@ Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* return address; } -llvm::Value* Ext::call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize) +llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize) { m_builder.CreateStore(_gas, m_args[0]); auto receiveAddress = bswap(_receiveAddress); // to BE @@ -177,6 +177,7 @@ llvm::Value* Ext::call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Va m_builder.CreateStore(_outSize, m_arg7); llvm::Value* args[] = {m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_args[1]}; m_builder.CreateCall(m_call, args); + _gas = m_builder.CreateLoad(m_args[0]); // Return gas return m_builder.CreateLoad(m_args[1]); } @@ -284,10 +285,10 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO auto value = llvm2eth(*_value); auto ret = false; + auto gas = llvm2eth(*_gas); if (ext.balance(ext.myAddress) >= value) { ext.subBalance(value); - auto gas = llvm2eth(*_gas); auto receiveAddress = dev::right160(*_receiveAddress); auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); @@ -299,7 +300,7 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO auto ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, receiveAddress); } - // m_gas += gas; // TODO: Handle gas + *_gas = eth2llvm(gas); _ret->a = ret ? 1 : 0; } diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 302991854..778c6d941 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -36,7 +36,7 @@ public: void suicide(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); - llvm::Value* call(llvm::Value* _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize); + llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); llvm::Value* exp(llvm::Value* _left, llvm::Value* _right); diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 6295ffe79..d10833ca4 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -108,6 +108,13 @@ void GasMeter::count(Instruction _inst) commitCostBlock(); } +void GasMeter::giveBack(llvm::Value* _gas) +{ + llvm::Value* gasCounter = m_builder.CreateLoad(m_gas, "gas"); + gasCounter = m_builder.CreateAdd(gasCounter, _gas); + m_builder.CreateStore(gasCounter, m_gas); +} + void GasMeter::commitCostBlock(llvm::Value* _additionalCost) { assert(!_additionalCost || m_checkCall); // _additionalCost => m_checkCall; Must be inside cost-block diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 3a1f7ba66..46fa3522a 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -23,6 +23,9 @@ public: /// @param _additionalCost adds additional cost to cost-block before commit void commitCostBlock(llvm::Value* _additionalCost = nullptr); + /// Give back an amount of gas not used by a call + void giveBack(llvm::Value* _gas); + /// Generate code that checks the cost of additional memory used by program void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); From f0f5833c4ca42ba907f5b9cd86d68a66d2225bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 15:12:11 +0200 Subject: [PATCH 108/396] Private mem.require function that preallocates memory and counts gas fee --- evmcc/Memory.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++-- evmcc/Memory.h | 4 ++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 4d4a34928..cbc349250 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -43,6 +43,43 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga m_loadWord = createFunc(false, Type::i256, _module, _gasMeter); m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); m_storeByte = createFunc(true, Type::Byte, _module, _gasMeter); + + m_require = createRequireFunc(_module, _gasMeter); +} + +llvm::Function* Memory::createRequireFunc(llvm::Module* _module, GasMeter& _gasMeter) +{ + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", _module); + + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "return", func); + + // BB "check" + llvm::IRBuilder<> builder(checkBB); + llvm::Value* sizeRequired = func->arg_begin(); + sizeRequired->setName("sizeRequired"); + auto size = builder.CreateLoad(m_size, "size"); + auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); + builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "resize" + builder.SetInsertPoint(resizeBB); + // Check gas first + auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired"); + auto words = builder.CreateUDiv(builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words"); + auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords"); + _gasMeter.checkMemory(newWords, builder); + // Resize + builder.CreateStore(sizeRequired, m_size); + auto newData = builder.CreateCall(m_resize, m_size, "newData"); + builder.CreateStore(newData, m_data); + builder.CreateBr(returnBB); + + // BB "return" + builder.SetInsertPoint(returnBB); + builder.CreateRetVoid(); + return func; } llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::Module* _module, GasMeter& _gasMeter) @@ -131,10 +168,15 @@ llvm::Value* Memory::getSize() return m_builder.CreateLoad(m_size); } +void Memory::require(llvm::Value* _size) +{ + m_builder.CreateCall(m_require, _size); +} + void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) { - auto lastWord = m_builder.CreateAdd(_index, m_builder.CreateSub(_size, Constant::get(32)), "lastWord"); - loadWord(lastWord); // Make sure that memory is allocated and count gas + auto sizeRequired = m_builder.CreateAdd(_index, _size, "sizeRequired"); + require(sizeRequired); // Make sure that memory is allocated and count gas m_builder.CreateStore(_index, m_returnDataOffset); m_builder.CreateStore(_size, m_returnDataSize); diff --git a/evmcc/Memory.h b/evmcc/Memory.h index c01bd6ef8..e973d1016 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -20,6 +20,8 @@ public: void storeByte(llvm::Value* _addr, llvm::Value* _byte); llvm::Value* getSize(); + void require(llvm::Value* _size); + void registerReturnData(llvm::Value* _index, llvm::Value* _size); static dev::bytesConstRef getReturnData(); @@ -27,6 +29,7 @@ public: private: llvm::Function* createFunc(bool _isStore, llvm::Type* _type, llvm::Module* _module, GasMeter& _gasMeter); + llvm::Function* createRequireFunc(llvm::Module* _module, GasMeter& _gasMeter); private: llvm::IRBuilder<>& m_builder; @@ -41,6 +44,7 @@ private: llvm::Function* m_loadWord; llvm::Function* m_storeWord; llvm::Function* m_storeByte; + llvm::Function* m_require; llvm::Function* m_resize; llvm::Function* m_memDump; From 59000cd85d0688c107b4d5fe4a39efadb058bfbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 15:19:27 +0200 Subject: [PATCH 109/396] Convenient Memory::require() overload --- evmcc/Memory.cpp | 11 ++++++++--- evmcc/Memory.h | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index cbc349250..66a18e43f 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -173,10 +173,15 @@ void Memory::require(llvm::Value* _size) m_builder.CreateCall(m_require, _size); } -void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) +void Memory::require(llvm::Value* _offset, llvm::Value* _size) { - auto sizeRequired = m_builder.CreateAdd(_index, _size, "sizeRequired"); - require(sizeRequired); // Make sure that memory is allocated and count gas + auto sizeRequired = m_builder.CreateAdd(_offset, _size, "sizeRequired"); + require(sizeRequired); +} + +void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) +{ + require(_index, _size); // Make sure that memory is allocated and count gas m_builder.CreateStore(_index, m_returnDataOffset); m_builder.CreateStore(_size, m_returnDataSize); diff --git a/evmcc/Memory.h b/evmcc/Memory.h index e973d1016..8ea9bf082 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -20,8 +20,12 @@ public: void storeByte(llvm::Value* _addr, llvm::Value* _byte); llvm::Value* getSize(); + /// Requires this amount of memory. And counts gas fee for that memory. void require(llvm::Value* _size); + /// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory. + void require(llvm::Value* _offset, llvm::Value* _size); + void registerReturnData(llvm::Value* _index, llvm::Value* _size); static dev::bytesConstRef getReturnData(); From 07882137e3a5893272519979e151bea9c2bad1ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 15:48:27 +0200 Subject: [PATCH 110/396] Use mem.require in mload, mstore & mstore8 --- evmcc/Memory.cpp | 50 ++++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 66a18e43f..8f4809062 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -40,11 +40,10 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga m_returnDataSize->setUnnamedAddr(true); // Address is not important m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); + m_require = createRequireFunc(_module, _gasMeter); m_loadWord = createFunc(false, Type::i256, _module, _gasMeter); m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); m_storeByte = createFunc(true, Type::Byte, _module, _gasMeter); - - m_require = createRequireFunc(_module, _gasMeter); } llvm::Function* Memory::createRequireFunc(llvm::Module* _module, GasMeter& _gasMeter) @@ -91,51 +90,34 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false); auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, _module); - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func); - auto accessBB = llvm::BasicBlock::Create(func->getContext(), "access", func); + auto origBB = m_builder.GetInsertBlock(); + auto origPt = m_builder.GetInsertPoint(); - // BB "check" - llvm::IRBuilder<> builder(checkBB); + m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); llvm::Value* index = func->arg_begin(); index->setName("index"); + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - auto sizeRequired = builder.CreateAdd(index, Constant::get(valueSize), "sizeRequired"); - auto size = builder.CreateLoad(m_size, "size"); - auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); - builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights? - - // BB "resize" - builder.SetInsertPoint(resizeBB); - // Check gas first - auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired"); - auto words = builder.CreateUDiv(builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words"); - auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.checkMemory(newWords, builder); - // Resize - builder.CreateStore(sizeRequired, m_size); - auto newData = builder.CreateCall(m_resize, m_size, "newData"); - builder.CreateStore(newData, m_data); - builder.CreateBr(accessBB); - - // BB "access" - builder.SetInsertPoint(accessBB); - auto data = builder.CreateLoad(m_data, "data"); - auto ptr = builder.CreateGEP(data, index, "ptr"); + this->require(index, Constant::get(valueSize)); + auto data = m_builder.CreateLoad(m_data, "data"); + auto ptr = m_builder.CreateGEP(data, index, "ptr"); if (isWord) - ptr = builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); if (_isStore) { llvm::Value* value = ++func->arg_begin(); value->setName("value"); - builder.CreateStore(value, ptr); - builder.CreateRetVoid(); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); } else { - auto ret = builder.CreateLoad(ptr); - builder.CreateRet(ret); + auto ret = m_builder.CreateLoad(ptr); + m_builder.CreateRet(ret); } + + m_builder.SetInsertPoint(origBB, origPt); + return func; } From d005896a0b5c33623abad685dca19c8f2768048f Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 14:52:15 +0100 Subject: [PATCH 111/396] Initial implementation for CALLDATACOPY [Delivers #80644732] --- evmcc/Compiler.cpp | 30 ++++++++++++++++++++++++++++++ evmcc/Ext.cpp | 6 +++--- evmcc/Ext.h | 1 + evmcc/Memory.cpp | 5 +++++ evmcc/Memory.h | 1 + 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 5857040f8..47cbbf5c1 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -736,6 +736,36 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::CALLDATACOPY: + { + auto zero256 = ConstantInt::get(Type::i256, 0); + + auto destMemIdx = stack.pop(); + auto srcDataIdx = stack.pop(); + auto reqByteCount = stack.pop(); + + // FIXME: ensure memory size reqMemSize. + auto reqMemSize = builder.CreateAdd(destMemIdx, reqByteCount); + auto reqMemWord = builder.CreateSub(reqMemSize, ConstantInt::get(Type::i256, 32)); + memory.loadWord(reqMemWord); + + auto memPtr = memory.getData(); + auto destPtr = builder.CreateGEP(memPtr, destMemIdx); + + auto calldataPtr = ext.calldata(); + auto srcPtr = builder.CreateGEP(calldataPtr, srcDataIdx); + + auto calldataSize = ext.calldatasize(); + // remaining data bytes: + auto remDataSize = builder.CreateSub(calldataSize, srcDataIdx); + auto remSizeNegative = builder.CreateICmpSLT(remDataSize, zero256); + auto bytesToCopy = builder.CreateSelect(remSizeNegative, zero256, remDataSize); + + builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); + + break; + } + case Instruction::CALLDATALOAD: { auto index = stack.pop(); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 1d309947d..bb2a54870 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -14,7 +14,6 @@ using llvm::types::i; using Linkage = llvm::GlobalValue::LinkageTypes; using dev::h256; using dev::u256; - namespace evmcc { @@ -70,7 +69,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) i256Ty, // i256 number; i256Ty, // i256 difficulty; i256Ty, // i256 gaslimit; - //m_builder.getInt8PtrTy() + m_builder.getInt8PtrTy() // byte* calldata }; auto extDataTy = StructType::create(elements, "ext.Data"); @@ -125,6 +124,7 @@ Value* Ext::timestamp() { return getDataElem(8, "timestamp"); } Value* Ext::number() { return getDataElem(9, "number"); } Value* Ext::difficulty() { return getDataElem(10, "difficulty"); } Value* Ext::gaslimit() { return getDataElem(11, "gaslimit"); } +Value* Ext::calldata() { return getDataElem(12, "calldata"); } Value* Ext::calldataload(Value* _index) { @@ -218,7 +218,7 @@ EXPORT void ext_init(ExtData* _extData) _extData->number = eth2llvm(ext.currentBlock.number); _extData->difficulty = eth2llvm(ext.currentBlock.difficulty); _extData->gaslimit = eth2llvm(ext.currentBlock.gasLimit); - //_extData->calldata = ext.data.data(); + _extData->calldata = ext.data.data(); } EXPORT void ext_store(i256* _index, i256* _value) diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 302991854..5c683ffdf 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -31,6 +31,7 @@ public: llvm::Value* number(); llvm::Value* difficulty(); llvm::Value* gaslimit(); + llvm::Value* calldata(); llvm::Value* balance(llvm::Value* _address); void suicide(llvm::Value* _address); diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 4d4a34928..0098ed1f9 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -126,6 +126,11 @@ void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) dump(0); } +llvm::Value* Memory::getData() +{ + return m_builder.CreateLoad(m_data); +} + llvm::Value* Memory::getSize() { return m_builder.CreateLoad(m_size); diff --git a/evmcc/Memory.h b/evmcc/Memory.h index c01bd6ef8..8b22294d7 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -18,6 +18,7 @@ public: llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); void storeByte(llvm::Value* _addr, llvm::Value* _byte); + llvm::Value* getData(); llvm::Value* getSize(); void registerReturnData(llvm::Value* _index, llvm::Value* _size); From 54989e071f7f410d39d87a625e6a8deaf47e7bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 16:11:39 +0200 Subject: [PATCH 112/396] InsertPointGuard helper class for IRBuilder --- evmcc/GasMeter.cpp | 8 +++----- evmcc/Memory.cpp | 37 ++++++++++++++++++------------------- evmcc/Memory.h | 4 ++-- evmcc/Utils.h | 24 +++++++++++++++++++++++- 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index d10833ca4..06f6cc49d 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -8,6 +8,7 @@ #include #include "Type.h" +#include "Utils.h" namespace evmcc { @@ -81,17 +82,14 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); m_gas->setUnnamedAddr(true); // Address is not important - auto pt = m_builder.GetInsertPoint(); - auto bb = m_builder.GetInsertBlock(); m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", _module); - auto gasCheckBB = llvm::BasicBlock::Create(_builder.getContext(), {}, m_gasCheckFunc); - m_builder.SetInsertPoint(gasCheckBB); + InsertPointGuard guard(m_builder); + m_builder.SetInsertPoint(llvm::BasicBlock::Create(_builder.getContext(), {}, m_gasCheckFunc)); llvm::Value* cost = m_gasCheckFunc->arg_begin(); llvm::Value* gas = m_builder.CreateLoad(m_gas); gas = m_builder.CreateSub(gas, cost); m_builder.CreateStore(gas, m_gas); m_builder.CreateRetVoid(); - m_builder.SetInsertPoint(bb, pt); } void GasMeter::count(Instruction _inst) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 8f4809062..2312fb853 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -54,30 +54,32 @@ llvm::Function* Memory::createRequireFunc(llvm::Module* _module, GasMeter& _gasM auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func); auto returnBB = llvm::BasicBlock::Create(func->getContext(), "return", func); + InsertPointGuard guard(m_builder); // Restores insert point at function exit + // BB "check" - llvm::IRBuilder<> builder(checkBB); + m_builder.SetInsertPoint(checkBB); llvm::Value* sizeRequired = func->arg_begin(); sizeRequired->setName("sizeRequired"); - auto size = builder.CreateLoad(m_size, "size"); - auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); - builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + auto size = m_builder.CreateLoad(m_size, "size"); + auto resizeNeeded = m_builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? // BB "resize" - builder.SetInsertPoint(resizeBB); + m_builder.SetInsertPoint(resizeBB); // Check gas first - auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired"); - auto words = builder.CreateUDiv(builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words"); - auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.checkMemory(newWords, builder); + 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"); + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + _gasMeter.checkMemory(newWords, m_builder); // Resize - builder.CreateStore(sizeRequired, m_size); - auto newData = builder.CreateCall(m_resize, m_size, "newData"); - builder.CreateStore(newData, m_data); - builder.CreateBr(returnBB); + m_builder.CreateStore(sizeRequired, m_size); + auto newData = m_builder.CreateCall(m_resize, m_size, "newData"); + m_builder.CreateStore(newData, m_data); + m_builder.CreateBr(returnBB); // BB "return" - builder.SetInsertPoint(returnBB); - builder.CreateRetVoid(); + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); return func; } @@ -90,8 +92,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false); auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, _module); - auto origBB = m_builder.GetInsertBlock(); - auto origPt = m_builder.GetInsertPoint(); + InsertPointGuard guard(m_builder); // Restores insert point at function exit m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); llvm::Value* index = func->arg_begin(); @@ -116,8 +117,6 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: m_builder.CreateRet(ret); } - m_builder.SetInsertPoint(origBB, origPt); - return func; } diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 8ea9bf082..122899c86 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -45,11 +45,11 @@ private: llvm::GlobalVariable* m_returnDataOffset; llvm::GlobalVariable* m_returnDataSize; + llvm::Function* m_resize; + llvm::Function* m_require; llvm::Function* m_loadWord; llvm::Function* m_storeWord; llvm::Function* m_storeByte; - llvm::Function* m_require; - llvm::Function* m_resize; llvm::Function* m_memDump; }; diff --git a/evmcc/Utils.h b/evmcc/Utils.h index 8233ac9e3..f0224831c 100644 --- a/evmcc/Utils.h +++ b/evmcc/Utils.h @@ -1,7 +1,7 @@ #pragma once -#include +#include #include @@ -22,4 +22,26 @@ static_assert(sizeof(i256) == 32, "Wrong i265 size"); dev::u256 llvm2eth(i256); i256 eth2llvm(dev::u256); +struct InsertPointGuard +{ + InsertPointGuard(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_insertBB(m_builder.GetInsertBlock()), + m_insertPt(m_builder.GetInsertPoint()) + {} + + ~InsertPointGuard() + { + m_builder.SetInsertPoint(m_insertBB, m_insertPt); + } + +private: + llvm::IRBuilder<>& m_builder; + llvm::BasicBlock* m_insertBB; + llvm::BasicBlock::iterator m_insertPt; + + InsertPointGuard(const InsertPointGuard&) = delete; + void operator=(InsertPointGuard) = delete; +}; + } \ No newline at end of file From 2b383751b4374a55eb0964c6f097364986ebebb8 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 15:19:18 +0100 Subject: [PATCH 113/396] Fixes in CALLDATACOPY [Delivers #80644732] --- evmcc/Compiler.cpp | 16 +++++++++------- evmcc/test/ext/calldatacopy1.evm | 1 + evmcc/test/ext/calldatacopy1.lll | 13 +++++++++++++ evmcc/test/ext/calldatacopy2.evm | 1 + evmcc/test/ext/calldatacopy2.lll | 13 +++++++++++++ 5 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 evmcc/test/ext/calldatacopy1.evm create mode 100644 evmcc/test/ext/calldatacopy1.lll create mode 100644 evmcc/test/ext/calldatacopy2.evm create mode 100644 evmcc/test/ext/calldatacopy2.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 3037145c2..3bb0a843c 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -742,24 +742,26 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto destMemIdx = stack.pop(); auto srcDataIdx = stack.pop(); - auto reqByteCount = stack.pop(); + auto reqBytes = stack.pop(); // FIXME: ensure memory size reqMemSize. - auto reqMemSize = builder.CreateAdd(destMemIdx, reqByteCount); - auto reqMemWord = builder.CreateSub(reqMemSize, ConstantInt::get(Type::i256, 32)); - memory.loadWord(reqMemWord); + auto reqMemSize = builder.CreateAdd(destMemIdx, reqBytes, "req_mem_size"); + memory.require(reqMemSize); auto memPtr = memory.getData(); - auto destPtr = builder.CreateGEP(memPtr, destMemIdx); + auto destPtr = builder.CreateGEP(memPtr, destMemIdx, "dest_mem_ptr"); auto calldataPtr = ext.calldata(); - auto srcPtr = builder.CreateGEP(calldataPtr, srcDataIdx); + auto srcPtr = builder.CreateGEP(calldataPtr, srcDataIdx, "src_idx"); auto calldataSize = ext.calldatasize(); // remaining data bytes: auto remDataSize = builder.CreateSub(calldataSize, srcDataIdx); auto remSizeNegative = builder.CreateICmpSLT(remDataSize, zero256); - auto bytesToCopy = builder.CreateSelect(remSizeNegative, zero256, remDataSize); + auto remDataBytes = builder.CreateSelect(remSizeNegative, zero256, remDataSize, "rem_data_bytes"); + + auto tooLittleDataBytes = builder.CreateICmpULT(remDataBytes, reqBytes); + auto bytesToCopy = builder.CreateSelect(tooLittleDataBytes, remDataBytes, reqBytes, "bytes_to_copy"); builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); diff --git a/evmcc/test/ext/calldatacopy1.evm b/evmcc/test/ext/calldatacopy1.evm new file mode 100644 index 000000000..73c4d76b8 --- /dev/null +++ b/evmcc/test/ext/calldatacopy1.evm @@ -0,0 +1 @@ +60146000600a37600053600a6014f2 diff --git a/evmcc/test/ext/calldatacopy1.lll b/evmcc/test/ext/calldatacopy1.lll new file mode 100644 index 000000000..da3666c71 --- /dev/null +++ b/evmcc/test/ext/calldatacopy1.lll @@ -0,0 +1,13 @@ +(asm +20 ;; byte count +0 ;; source index in calldata array +10 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +10 +20 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/calldatacopy2.evm b/evmcc/test/ext/calldatacopy2.evm new file mode 100644 index 000000000..e8eea8da7 --- /dev/null +++ b/evmcc/test/ext/calldatacopy2.evm @@ -0,0 +1 @@ +606464e8d4a510006000376000536000600af2 diff --git a/evmcc/test/ext/calldatacopy2.lll b/evmcc/test/ext/calldatacopy2.lll new file mode 100644 index 000000000..6bbea48d8 --- /dev/null +++ b/evmcc/test/ext/calldatacopy2.lll @@ -0,0 +1,13 @@ +(asm +100 ;; byte count +1000000000000 ;; source index in calldata array +0 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file From 8267b453c7c2204f3b7602bf99facbbccf3ddbf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 16:28:38 +0200 Subject: [PATCH 114/396] Prealloc memory and count gas for SHA3 and CREATE instructions [#79942174] --- evmcc/Compiler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 37a4d89a1..4bc234455 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -435,6 +435,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto inOff = stack.pop(); auto inSize = stack.pop(); + memory.require(inOff, inSize); auto hash = ext.sha3(inOff, inSize); stack.push(hash); } @@ -768,6 +769,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto endowment = stack.pop(); auto initOff = stack.pop(); auto initSize = stack.pop(); + memory.require(initOff, initSize); auto address = ext.create(endowment, initOff, initSize); stack.push(address); From 52d3a3beb071d3aeff7ae6d895adc95de293c859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 16:52:53 +0200 Subject: [PATCH 115/396] Prealloc memory and count gas for CALL instruction [#79942174] --- evmcc/Compiler.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index ed1e31ca6..0fc72fd0d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -745,9 +745,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto srcDataIdx = stack.pop(); auto reqBytes = stack.pop(); - // FIXME: ensure memory size reqMemSize. - auto reqMemSize = builder.CreateAdd(destMemIdx, reqBytes, "req_mem_size"); - memory.require(reqMemSize); + memory.require(destMemIdx, reqBytes); auto memPtr = memory.getData(); auto destPtr = builder.CreateGEP(memPtr, destMemIdx, "dest_mem_ptr"); @@ -856,6 +854,14 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto outSize = stack.pop(); gasMeter.commitCostBlock(gas); + + // Require memory for the max of in and out buffers + auto inSizeReq = builder.CreateAdd(inOff, inSize, "inSizeReq"); + auto outSizeReq = builder.CreateAdd(outOff, outSize, "outSizeReq"); + auto cmp = builder.CreateICmpUGT(inSizeReq, outSizeReq); + auto sizeReq = builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); + memory.require(sizeReq); + auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize); gasMeter.giveBack(gas); stack.push(ret); From 2e3e764fb5bdb91fb6dedd80b4ec77e1e473aaac Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 16:06:34 +0100 Subject: [PATCH 116/396] Codegen for CODECOPY. [Delivers #80644732] --- evmcc/Compiler.cpp | 34 ++++++++++++++++---------------- evmcc/ExecutionEngine.cpp | 4 +++- evmcc/Ext.cpp | 16 ++++++++++++--- evmcc/Ext.h | 2 ++ evmcc/test/ext/calldatacopy1.evm | 2 +- evmcc/test/ext/calldatacopy1.lll | 2 +- evmcc/test/ext/codecopy1.evm | 1 + evmcc/test/ext/codecopy1.lll | 13 ++++++++++++ evmcc/test/ext/codecopy2.evm | 1 + evmcc/test/ext/codecopy2.lll | 13 ++++++++++++ evmcc/test/ext/codecopy3.evm | 1 + evmcc/test/ext/codecopy3.lll | 13 ++++++++++++ 12 files changed, 79 insertions(+), 23 deletions(-) create mode 100644 evmcc/test/ext/codecopy1.evm create mode 100644 evmcc/test/ext/codecopy1.lll create mode 100644 evmcc/test/ext/codecopy2.evm create mode 100644 evmcc/test/ext/codecopy2.lll create mode 100644 evmcc/test/ext/codecopy3.evm create mode 100644 evmcc/test/ext/codecopy3.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 3bb0a843c..fe1ccbae0 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -736,32 +736,39 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::CODESIZE: + { + auto value = ext.codesize(); + stack.push(value); + break; + } + case Instruction::CALLDATACOPY: + case Instruction::CODECOPY: { auto zero256 = ConstantInt::get(Type::i256, 0); auto destMemIdx = stack.pop(); - auto srcDataIdx = stack.pop(); + auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - // FIXME: ensure memory size reqMemSize. auto reqMemSize = builder.CreateAdd(destMemIdx, reqBytes, "req_mem_size"); memory.require(reqMemSize); auto memPtr = memory.getData(); auto destPtr = builder.CreateGEP(memPtr, destMemIdx, "dest_mem_ptr"); - auto calldataPtr = ext.calldata(); - auto srcPtr = builder.CreateGEP(calldataPtr, srcDataIdx, "src_idx"); + auto srcBasePtr = inst == Instruction::CALLDATACOPY ? ext.calldata() : ext.code(); + auto srcPtr = builder.CreateGEP(srcBasePtr, srcIdx, "src_idx"); - auto calldataSize = ext.calldatasize(); + auto srcSize = inst == Instruction::CALLDATACOPY ? ext.calldatasize() : ext.codesize(); // remaining data bytes: - auto remDataSize = builder.CreateSub(calldataSize, srcDataIdx); - auto remSizeNegative = builder.CreateICmpSLT(remDataSize, zero256); - auto remDataBytes = builder.CreateSelect(remSizeNegative, zero256, remDataSize, "rem_data_bytes"); + auto remSrcSize = builder.CreateSub(srcSize, srcIdx); + auto remSizeNegative = builder.CreateICmpSLT(remSrcSize, zero256); + auto remSrcBytes = builder.CreateSelect(remSizeNegative, zero256, remSrcSize, "rem_src_bytes"); - auto tooLittleDataBytes = builder.CreateICmpULT(remDataBytes, reqBytes); - auto bytesToCopy = builder.CreateSelect(tooLittleDataBytes, remDataBytes, reqBytes, "bytes_to_copy"); + auto tooLittleDataBytes = builder.CreateICmpULT(remSrcBytes, reqBytes); + auto bytesToCopy = builder.CreateSelect(tooLittleDataBytes, remSrcBytes, reqBytes, "bytes_to_copy"); builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); @@ -783,13 +790,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } - case Instruction::CODESIZE: - { - auto value = Constant::get(bytecode.size()); - stack.push(value); - break; - } - case Instruction::PREVHASH: { auto value = ext.prevhash(); diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 0e6df0b24..23507073a 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -85,6 +85,8 @@ int ExecutionEngine::run(std::unique_ptr _module) ext->currentBlock.gasLimit = 1008; std::string calldata = "Hello the Beautiful World of Ethereum!"; ext->data = calldata; + unsigned char fakecode[] = { 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf }; + ext->code = decltype(ext->code)(fakecode, 8); // Init runtime uint64_t gas = 1000000; @@ -114,4 +116,4 @@ int ExecutionEngine::run(std::unique_ptr _module) return 0; } -} \ No newline at end of file +} diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 1019a3986..9f72bd0ca 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -37,7 +37,9 @@ struct ExtData i256 number; i256 difficulty; i256 gaslimit; + i256 codesize; const byte* calldata; + const byte* code; }; Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) @@ -47,6 +49,8 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) 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"); m_arg2 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg2"); @@ -69,7 +73,10 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) i256Ty, // i256 number; i256Ty, // i256 difficulty; i256Ty, // i256 gaslimit; - m_builder.getInt8PtrTy() // byte* calldata + i256Ty, // i256 codesize + i8PtrTy, // byte* calldata + i8PtrTy, // byte* code + }; auto extDataTy = StructType::create(elements, "ext.Data"); @@ -88,7 +95,6 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_sha3 = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_sha3", module); m_exp = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_exp", module); - m_builder.CreateCall(m_init, m_data); } @@ -124,7 +130,9 @@ Value* Ext::timestamp() { return getDataElem(8, "timestamp"); } Value* Ext::number() { return getDataElem(9, "number"); } Value* Ext::difficulty() { return getDataElem(10, "difficulty"); } Value* Ext::gaslimit() { return getDataElem(11, "gaslimit"); } -Value* Ext::calldata() { return getDataElem(12, "calldata"); } +Value* Ext::codesize() { return getDataElem(12, "codesize"); } +Value* Ext::calldata() { return getDataElem(13, "calldata"); } +Value* Ext::code() { return getDataElem(14, "code"); } Value* Ext::calldataload(Value* _index) { @@ -219,7 +227,9 @@ EXPORT void ext_init(ExtData* _extData) _extData->number = eth2llvm(ext.currentBlock.number); _extData->difficulty = eth2llvm(ext.currentBlock.difficulty); _extData->gaslimit = eth2llvm(ext.currentBlock.gasLimit); + _extData->codesize = eth2llvm(ext.code.size()); _extData->calldata = ext.data.data(); + _extData->code = ext.code.data(); } EXPORT void ext_store(i256* _index, i256* _value) diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 91eea2c5f..873d941a0 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -31,7 +31,9 @@ public: llvm::Value* number(); llvm::Value* difficulty(); llvm::Value* gaslimit(); + llvm::Value* codesize(); llvm::Value* calldata(); + llvm::Value* code(); llvm::Value* balance(llvm::Value* _address); void suicide(llvm::Value* _address); diff --git a/evmcc/test/ext/calldatacopy1.evm b/evmcc/test/ext/calldatacopy1.evm index 73c4d76b8..f20019651 100644 --- a/evmcc/test/ext/calldatacopy1.evm +++ b/evmcc/test/ext/calldatacopy1.evm @@ -1 +1 @@ -60146000600a37600053600a6014f2 +60326000600a37600053600a6014f2 diff --git a/evmcc/test/ext/calldatacopy1.lll b/evmcc/test/ext/calldatacopy1.lll index da3666c71..3d2ae0a78 100644 --- a/evmcc/test/ext/calldatacopy1.lll +++ b/evmcc/test/ext/calldatacopy1.lll @@ -1,5 +1,5 @@ (asm -20 ;; byte count +50 ;; byte count 0 ;; source index in calldata array 10 ;; dest index in memory CALLDATACOPY diff --git a/evmcc/test/ext/codecopy1.evm b/evmcc/test/ext/codecopy1.evm new file mode 100644 index 000000000..d286f9232 --- /dev/null +++ b/evmcc/test/ext/codecopy1.evm @@ -0,0 +1 @@ +60146000600a39600053600a6014f2 diff --git a/evmcc/test/ext/codecopy1.lll b/evmcc/test/ext/codecopy1.lll new file mode 100644 index 000000000..85a02b5d7 --- /dev/null +++ b/evmcc/test/ext/codecopy1.lll @@ -0,0 +1,13 @@ +(asm +20 ;; byte count +0 ;; source index in code array +10 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +10 +20 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy2.evm b/evmcc/test/ext/codecopy2.evm new file mode 100644 index 000000000..71cd92525 --- /dev/null +++ b/evmcc/test/ext/codecopy2.evm @@ -0,0 +1 @@ +606464e8d4a510006000396000536000600af2 diff --git a/evmcc/test/ext/codecopy2.lll b/evmcc/test/ext/codecopy2.lll new file mode 100644 index 000000000..dcbbcaa46 --- /dev/null +++ b/evmcc/test/ext/codecopy2.lll @@ -0,0 +1,13 @@ +(asm +100 ;; byte count +1000000000000 ;; source index in code array +0 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy3.evm b/evmcc/test/ext/codecopy3.evm new file mode 100644 index 000000000..e4b6a9253 --- /dev/null +++ b/evmcc/test/ext/codecopy3.evm @@ -0,0 +1 @@ +3860006000396000536000600af2 diff --git a/evmcc/test/ext/codecopy3.lll b/evmcc/test/ext/codecopy3.lll new file mode 100644 index 000000000..80d9982c6 --- /dev/null +++ b/evmcc/test/ext/codecopy3.lll @@ -0,0 +1,13 @@ +(asm +CODESIZE ;; byte count +0 ;; source index in code array +0 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file From 01b95883f2b959244fd5621c88ad220a9e8fb639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 18:22:30 +0200 Subject: [PATCH 117/396] Count gas cost for SSTORE instruction [#79942174] --- evmcc/Compiler.cpp | 1 + evmcc/GasMeter.cpp | 25 ++++++++++++++++++++++++- evmcc/GasMeter.h | 3 +++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 0fc72fd0d..3d43e5e54 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -609,6 +609,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { auto index = stack.pop(); auto value = stack.pop(); + gasMeter.countSStore(ext, index, value); ext.setStore(index, value); break; } diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 99b5e549d..cd7f9eb33 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -9,6 +9,7 @@ #include "Type.h" #include "Utils.h" +#include "Ext.h" namespace evmcc { @@ -100,12 +101,34 @@ void GasMeter::count(Instruction _inst) m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256)); } - m_blockCost += getStepCost(_inst); + if (_inst != Instruction::SSTORE) // Handle cost of SSTORE separately in countSStore() + m_blockCost += getStepCost(_inst); if (isCostBlockEnd(_inst)) commitCostBlock(); } +void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) +{ + assert(!m_checkCall); // Everything should've been commited before + + static const auto sstoreCost = static_cast(c_sstoreGas); + + // [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"); + m_builder.CreateCall(m_gasCheckFunc, cost); +} + void GasMeter::giveBack(llvm::Value* _gas) { llvm::Value* gasCounter = m_builder.CreateLoad(m_gas, "gas"); diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 95e8eaf8d..a47bb2244 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -19,6 +19,9 @@ public: /// Count step cost of instruction void count(dev::eth::Instruction _inst); + /// Calculate & count gas cost for SSTORE instruction + void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); + /// Finalize cost-block by checking gas needed for the block before the block /// @param _additionalCost adds additional cost to cost-block before commit void commitCostBlock(llvm::Value* _additionalCost = nullptr); From 31a07cb1b878c92db8d9d4908fa9dcb89232018a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 18:26:47 +0200 Subject: [PATCH 118/396] Change a bit the implementation of GAS instruction [Delivers #79942174] --- evmcc/Compiler.cpp | 3 +-- evmcc/GasMeter.cpp | 4 ++-- evmcc/GasMeter.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 3d43e5e54..00ea5c12e 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -690,8 +690,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::GAS: { - auto value = builder.CreateLoad(gasMeter.getLLVMGasVar()); - stack.push(value); + stack.push(gasMeter.getGas()); break; } diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index cd7f9eb33..ab38bd85c 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -167,9 +167,9 @@ void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilde _builder.CreateCall(m_gasCheckFunc, cost); } -llvm::GlobalVariable* GasMeter::getLLVMGasVar() +llvm::Value* GasMeter::getGas() { - return m_gas; + m_builder.CreateLoad(m_gas, "gas"); } } diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index a47bb2244..60a1136b9 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -32,7 +32,7 @@ public: /// Generate code that checks the cost of additional memory used by program void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); - llvm::GlobalVariable* getLLVMGasVar(); + llvm::Value* getGas(); private: /// Cumulative gas cost of a block of instructions From 631330074602106ee034bc220b4b0991a25bc5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 19:03:04 +0200 Subject: [PATCH 119/396] Change a bit the implementation of GAS instruction (fix) [Delivers #79942174] --- evmcc/GasMeter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index ab38bd85c..11244c028 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -169,7 +169,7 @@ void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilde llvm::Value* GasMeter::getGas() { - m_builder.CreateLoad(m_gas, "gas"); + return m_builder.CreateLoad(m_gas, "gas"); } } From 1ffdda670516c10cad7bcf4e5a612c092278932f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 19:17:54 +0200 Subject: [PATCH 120/396] Some LLVM function attribute fun --- evmcc/Memory.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 1838afa4b..e40d61f3b 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -40,6 +40,10 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga m_returnDataSize->setUnnamedAddr(true); // Address is not important m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); + m_require = createRequireFunc(_module, _gasMeter); m_loadWord = createFunc(false, Type::i256, _module, _gasMeter); m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); From 70ad81dad25f509b409c989ab407238a2522db7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 20:15:43 +0200 Subject: [PATCH 121/396] Try to throw an OutOfGas exception when out of gas. The exception cannot be handled. [#80660432] --- evmcc/ExecutionEngine.cpp | 23 +++++++++++++++++------ evmcc/GasMeter.cpp | 20 ++++++++++++++++++-- evmcc/GasMeter.h | 1 + evmcc/Runtime.cpp | 17 ++++++++++++++++- evmcc/Type.h | 1 + 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 0e6df0b24..5cb94ddf0 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -13,6 +13,8 @@ #include #include +#include + #include "Runtime.h" #include "Memory.h" #include "Type.h" @@ -87,7 +89,7 @@ int ExecutionEngine::run(std::unique_ptr _module) ext->data = calldata; // Init runtime - uint64_t gas = 1000000; + uint64_t gas = 100; Runtime runtime(gas, std::move(ext)); auto entryFunc = module->getFunction("main"); @@ -97,9 +99,20 @@ int ExecutionEngine::run(std::unique_ptr _module) exit(1); } - auto result = exec->runFunction(entryFunc, {}); + + ReturnCode returnCode; + try + { + auto result = exec->runFunction(entryFunc, {}); + returnCode = static_cast(result.IntVal.getZExtValue()); + } + catch (const dev::eth::OutOfGas&) + { + returnCode = ReturnCode::OutOfGas; + } + gas = static_cast(Runtime::getGas()); - auto returnCode = static_cast(result.IntVal.getZExtValue()); + if (returnCode == ReturnCode::Return) { auto&& returnData = Memory::getReturnData(); // TODO: It might be better to place is in Runtime interface @@ -108,10 +121,8 @@ int ExecutionEngine::run(std::unique_ptr _module) for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; std::cout << "]\n"; - - return 10; } - return 0; + return static_cast(returnCode); } } \ No newline at end of file diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 11244c028..10a8fca98 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -83,11 +83,27 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); m_gas->setUnnamedAddr(true); // Address is not important + m_rtExit = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::MainReturn, false), llvm::Function::ExternalLinkage, "rt_exit", _module); + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", _module); InsertPointGuard guard(m_builder); - m_builder.SetInsertPoint(llvm::BasicBlock::Create(_builder.getContext(), {}, m_gasCheckFunc)); + + auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "check", m_gasCheckFunc); + auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "outOfGas", m_gasCheckFunc); + auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "update", m_gasCheckFunc); + + m_builder.SetInsertPoint(checkBB); llvm::Value* cost = m_gasCheckFunc->arg_begin(); - llvm::Value* gas = m_builder.CreateLoad(m_gas); + cost->setName("cost"); + llvm::Value* gas = m_builder.CreateLoad(m_gas, "gas"); + auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); + m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); + + m_builder.SetInsertPoint(outOfGasBB); + m_builder.CreateCall(m_rtExit, Constant::get(ReturnCode::OutOfGas)); + m_builder.CreateRetVoid(); + + m_builder.SetInsertPoint(updateBB); gas = m_builder.CreateSub(gas, cost); m_builder.CreateStore(gas, m_gas); m_builder.CreateRetVoid(); diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 60a1136b9..8738b49c0 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -41,6 +41,7 @@ private: llvm::IRBuilder<>& m_builder; llvm::CallInst* m_checkCall = nullptr; llvm::GlobalVariable* m_gas; + llvm::Function* m_rtExit; llvm::Function* m_gasCheckFunc; }; diff --git a/evmcc/Runtime.cpp b/evmcc/Runtime.cpp index a373d9501..834a8bbff 100644 --- a/evmcc/Runtime.cpp +++ b/evmcc/Runtime.cpp @@ -1,12 +1,27 @@ #include "Runtime.h" +#include + +#include "Type.h" + namespace evmcc { static Runtime* g_runtime; -extern "C" { EXPORT i256 gas; } +extern "C" +{ +EXPORT i256 gas; + +EXPORT void rt_exit(int32_t _returnCode) +{ + auto returnCode = static_cast(_returnCode); + if (returnCode == ReturnCode::OutOfGas) + BOOST_THROW_EXCEPTION(dev::eth::OutOfGas()); +} + +} Runtime::Runtime(dev::u256 _gas, std::unique_ptr _ext): m_ext(std::move(_ext)) diff --git a/evmcc/Type.h b/evmcc/Type.h index a8501d897..727183266 100644 --- a/evmcc/Type.h +++ b/evmcc/Type.h @@ -34,6 +34,7 @@ enum class ReturnCode Suicide = 2, BadJumpDestination = 101, + OutOfGas = 102, }; struct Constant From 471586cc824595ca3b883760b573d831deb08410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 20:49:48 +0200 Subject: [PATCH 122/396] Use longjmp to return OutOfGas code from main function (WIP) [#80660432] --- evmcc/Compiler.cpp | 15 ++++++++++++--- evmcc/Compiler.h | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 00ea5c12e..7b1f6de18 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -6,7 +6,7 @@ #include #include #include -//#include +#include #include @@ -159,6 +159,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) m_finalBlock = std::make_unique("FinalBlock", m_mainFunc); m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc); m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc); + m_outOfGasBlock = std::make_unique("OutOfGas", m_mainFunc); for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { @@ -195,6 +196,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Create the basic blocks. auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc); builder.SetInsertPoint(entryBlock); + createBasicBlocks(bytecode); // Init runtime structures. @@ -203,7 +205,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) Ext ext(builder, module.get()); // Jump to first instruction - builder.CreateBr(basicBlocks.begin()->second); + auto setjmpFunc = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); + auto jmpBufTy = llvm::ArrayType::get(builder.getInt64Ty(), 5); + auto jmpBuf = new llvm::GlobalVariable(*module, jmpBufTy, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(jmpBufTy), "jmpBuf"); + auto setjmpRet = builder.CreateCall(setjmpFunc, builder.CreateBitCast(jmpBuf, Type::BytePtr)); + auto isNormalFlow = builder.CreateICmpEQ(setjmpRet, builder.getInt32(0)); + builder.CreateCondBr(isNormalFlow, basicBlocks.begin()->second, m_outOfGasBlock->llvm()); for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) { @@ -921,10 +928,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) builder.SetInsertPoint(m_finalBlock->llvm()); builder.CreateRet(Constant::get(ReturnCode::Stop)); - // TODO: throw an exception or something builder.SetInsertPoint(m_badJumpBlock->llvm()); builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + builder.SetInsertPoint(m_outOfGasBlock->llvm()); + builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); + builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) { diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 7d0cb4ab6..509cf77df 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -59,6 +59,8 @@ private: */ std::unique_ptr m_badJumpBlock; + std::unique_ptr m_outOfGasBlock; + /// Main program function llvm::Function* m_mainFunc = nullptr; }; From 8498ab5695221acbb43d3141610cade3b88b08f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 11:11:07 +0200 Subject: [PATCH 123/396] Trying to implement "exceptions" with longjmp (does not work on Windows 64bit at least) --- evmcc/Compiler.cpp | 14 +++++++++----- evmcc/ExecutionEngine.cpp | 4 +++- evmcc/GasMeter.cpp | 15 +++++++++------ evmcc/GasMeter.h | 2 +- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 7b1f6de18..11e7569db 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -199,16 +199,20 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) createBasicBlocks(bytecode); + // Prepare jump buffer + auto jmpBufStorageTy = llvm::ArrayType::get(Type::Byte, 2048); + auto jmpBufStorage = new llvm::GlobalVariable(*module, jmpBufStorageTy, false, llvm::GlobalVariable::PrivateLinkage, llvm::ConstantAggregateZero::get(jmpBufStorageTy), "jmpBuf"); + jmpBufStorage->setAlignment(16); + auto jmpBuf = builder.CreateConstInBoundsGEP2_32(jmpBufStorage, 0, 0); + // Init runtime structures. - GasMeter gasMeter(builder, module.get()); + GasMeter gasMeter(builder, module.get(), jmpBuf); Memory memory(builder, module.get(), gasMeter); Ext ext(builder, module.get()); - // Jump to first instruction + // Create exception landing with setjmp and jump to first instruction auto setjmpFunc = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); - auto jmpBufTy = llvm::ArrayType::get(builder.getInt64Ty(), 5); - auto jmpBuf = new llvm::GlobalVariable(*module, jmpBufTy, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(jmpBufTy), "jmpBuf"); - auto setjmpRet = builder.CreateCall(setjmpFunc, builder.CreateBitCast(jmpBuf, Type::BytePtr)); + auto setjmpRet = builder.CreateCall(setjmpFunc, jmpBuf); auto isNormalFlow = builder.CreateICmpEQ(setjmpRet, builder.getInt32(0)); builder.CreateCondBr(isNormalFlow, basicBlocks.begin()->second, m_outOfGasBlock->llvm()); diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 5cb94ddf0..95c90ec19 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -121,7 +121,9 @@ int ExecutionEngine::run(std::unique_ptr _module) for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; std::cout << "]\n"; - } + } + + std::cout << "RETURN CODE: " << (int)returnCode << std::endl; return static_cast(returnCode); } diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 10a8fca98..0d0927563 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -77,7 +78,7 @@ bool isCostBlockEnd(Instruction _inst) } -GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): +GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Value* _jmpBuf) : m_builder(_builder) { m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); @@ -88,9 +89,9 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", _module); InsertPointGuard guard(m_builder); - auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "check", m_gasCheckFunc); - auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "outOfGas", m_gasCheckFunc); - auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "update", m_gasCheckFunc); + auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); + auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); + auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); m_builder.SetInsertPoint(checkBB); llvm::Value* cost = m_gasCheckFunc->arg_begin(); @@ -100,8 +101,10 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - m_builder.CreateCall(m_rtExit, Constant::get(ReturnCode::OutOfGas)); - m_builder.CreateRetVoid(); + + auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); + m_builder.CreateCall(longjmpFunc, _jmpBuf); + m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); gas = m_builder.CreateSub(gas, cost); diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 8738b49c0..5af117900 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -11,7 +11,7 @@ namespace evmcc class GasMeter { public: - GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* module); + GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Value* _jmpBuf); GasMeter(const GasMeter&) = delete; void operator=(GasMeter) = delete; From 8e93171d3d92e7e090ff5dde9a6a8d383e584a36 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 15 Oct 2014 10:32:37 +0100 Subject: [PATCH 124/396] Codegen for EXTCODESIZE & EXTCODECOPY [Delivers #80644732] --- evmcc/Compiler.cpp | 50 ++++++++++++++++++++++++++++++---------------- evmcc/Ext.cpp | 42 +++++++++++++++++++++++++++++++++++++- evmcc/Ext.h | 4 ++++ evmcc/Memory.cpp | 24 ++++++++++++++++++++++ evmcc/Memory.h | 2 ++ 5 files changed, 104 insertions(+), 18 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 80a01cc55..6b4320543 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -744,35 +744,51 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } - case Instruction::CALLDATACOPY: - case Instruction::CODECOPY: + case Instruction::EXTCODESIZE: { - auto zero256 = ConstantInt::get(Type::i256, 0); + auto addr = stack.pop(); + auto value = ext.codesizeAt(addr); + stack.push(value); + break; + } + case Instruction::CALLDATACOPY: + { auto destMemIdx = stack.pop(); auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto reqMemSize = builder.CreateAdd(destMemIdx, reqBytes, "req_mem_size"); - memory.require(reqMemSize); + auto srcPtr = ext.calldata(); + auto srcSize = ext.calldatasize(); + + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } - auto memPtr = memory.getData(); - auto destPtr = builder.CreateGEP(memPtr, destMemIdx, "dest_mem_ptr"); + case Instruction::CODECOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); - auto srcBasePtr = inst == Instruction::CALLDATACOPY ? ext.calldata() : ext.code(); - auto srcPtr = builder.CreateGEP(srcBasePtr, srcIdx, "src_idx"); + auto srcPtr = ext.code(); + auto srcSize = ext.codesize(); - auto srcSize = inst == Instruction::CALLDATACOPY ? ext.calldatasize() : ext.codesize(); - // remaining data bytes: - auto remSrcSize = builder.CreateSub(srcSize, srcIdx); - auto remSizeNegative = builder.CreateICmpSLT(remSrcSize, zero256); - auto remSrcBytes = builder.CreateSelect(remSizeNegative, zero256, remSrcSize, "rem_src_bytes"); + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } - auto tooLittleDataBytes = builder.CreateICmpULT(remSrcBytes, reqBytes); - auto bytesToCopy = builder.CreateSelect(tooLittleDataBytes, remSrcBytes, reqBytes, "bytes_to_copy"); + case Instruction::EXTCODECOPY: + { + auto extAddr = stack.pop(); + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); - builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); + auto srcPtr = ext.codeAt(extAddr); + auto srcSize = ext.codesizeAt(extAddr); + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); break; } diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 9f72bd0ca..2b3313b87 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -14,6 +14,7 @@ using llvm::types::i; using Linkage = llvm::GlobalValue::LinkageTypes; using dev::h256; using dev::u256; + namespace evmcc { @@ -94,6 +95,8 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_bswap = Intrinsic::getDeclaration(module, Intrinsic::bswap, i256Ty); m_sha3 = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_sha3", module); m_exp = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_exp", module); + m_codeAt = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codeAt", module); + m_codesizeAt = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codesizeAt", module); m_builder.CreateCall(m_init, m_data); } @@ -209,9 +212,32 @@ llvm::Value* Ext::exp(llvm::Value* _left, llvm::Value* _right) return m_builder.CreateLoad(m_args[1]); } +llvm::Value* Ext::codeAt(llvm::Value* _addr) +{ + auto addr = bswap(_addr); + m_builder.CreateStore(addr, m_args[0]); + llvm::Value* args[] = {m_args[0], m_args[1]}; + m_builder.CreateCall(m_codeAt, args); + return m_builder.CreateLoad(m_args[1]); +} + +llvm::Value* Ext::codesizeAt(llvm::Value* _addr) +{ + auto addr = bswap(_addr); + m_builder.CreateStore(addr, m_args[0]); + llvm::Value* args[] = {m_args[0], m_args[1]}; + m_builder.CreateCall(m_codesizeAt, args); + return m_builder.CreateLoad(m_args[1]); +} + +} + + extern "C" { +using namespace evmcc; + EXPORT void ext_init(ExtData* _extData) { auto&& ext = Runtime::getExt(); @@ -307,7 +333,7 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO auto&& inRef = dev::bytesConstRef(Runtime::getMemory().data() + inOff, inSize); auto&& outRef = dev::bytesConstRef(Runtime::getMemory().data() + outOff, outSize); dev::eth::OnOpFunc onOp{}; // TODO: Handle that thing - auto ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, receiveAddress); + ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, receiveAddress); } *_gas = eth2llvm(gas); @@ -331,6 +357,20 @@ EXPORT void ext_exp(i256* _left, i256* _right, i256* _ret) *_ret = eth2llvm(ret); } +EXPORT void ext_codeAt(h256* _addr256, i256* _ret) +{ + auto&& ext = Runtime::getExt(); + auto addr = dev::right160(*_addr256); + auto& code = ext.codeAt(addr); + *_ret = *reinterpret_cast(const_cast(&code[0])); +} + +EXPORT void ext_codesizeAt(h256* _addr256, i256* _ret) +{ + auto&& ext = Runtime::getExt(); + auto addr = dev::right160(*_addr256); + auto& code = ext.codeAt(addr); + *_ret = eth2llvm(u256(code.size())); } } diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 873d941a0..03ff90ba8 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -43,6 +43,8 @@ public: llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); llvm::Value* exp(llvm::Value* _left, llvm::Value* _right); + llvm::Value* codeAt(llvm::Value* _addr); + llvm::Value* codesizeAt(llvm::Value* _addr); private: llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); @@ -71,6 +73,8 @@ private: llvm::Function* m_bswap; llvm::Function* m_sha3; llvm::Function* m_exp; + llvm::Function* m_codeAt; + llvm::Function* m_codesizeAt; }; diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index e40d61f3b..cf82e7a50 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -177,6 +177,30 @@ void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) m_builder.CreateStore(_size, m_returnDataSize); } +void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) +{ + auto zero256 = llvm::ConstantInt::get(Type::i256, 0); + + auto reqMemSize = m_builder.CreateAdd(_destMemIdx, _reqBytes, "req_mem_size"); + require(reqMemSize); + + auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx"); + + auto memPtr = getData(); + auto destPtr = m_builder.CreateGEP(memPtr, _destMemIdx, "dest_mem_ptr"); + + // remaining source bytes: + auto remSrcSize = m_builder.CreateSub(_srcSize, _srcIdx); + auto remSizeNegative = m_builder.CreateICmpSLT(remSrcSize, zero256); + auto remSrcBytes = m_builder.CreateSelect(remSizeNegative, zero256, remSrcSize, "rem_src_bytes"); + + auto tooFewSrcBytes = m_builder.CreateICmpULT(remSrcBytes, _reqBytes); + auto bytesToCopy = m_builder.CreateSelect(tooFewSrcBytes, remSrcBytes, _reqBytes, "bytes_to_copy"); + + m_builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); +} + void Memory::dump(uint64_t _begin, uint64_t _end) { if (getenv("EVMCC_DEBUG_MEMORY") == nullptr) diff --git a/evmcc/Memory.h b/evmcc/Memory.h index fdf4a17f7..34b4c68a8 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -20,6 +20,8 @@ public: void storeByte(llvm::Value* _addr, llvm::Value* _byte); llvm::Value* getData(); llvm::Value* getSize(); + void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex, + llvm::Value* _destMemIdx, llvm::Value* _byteCount); /// Requires this amount of memory. And counts gas fee for that memory. void require(llvm::Value* _size); From fc9b9f32c94e379f322cad8b22444a801143beac Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 15 Oct 2014 13:40:04 +0100 Subject: [PATCH 125/396] * codegen for CODECALL * fixes for EXTCODECOPY --- evmcc/Compiler.cpp | 9 +++++++-- evmcc/ExecutionEngine.cpp | 1 - evmcc/Ext.cpp | 25 ++++++++++++++----------- evmcc/Ext.h | 3 ++- evmcc/test/ext/extcodecopy1.evm | 1 + evmcc/test/ext/extcodecopy1.lll | 11 +++++++++++ 6 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 evmcc/test/ext/extcodecopy1.evm create mode 100644 evmcc/test/ext/extcodecopy1.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index dd9b0b510..a113655f9 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -873,9 +873,10 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } case Instruction::CALL: + case Instruction::CALLCODE: { auto gas = stack.pop(); - auto receiveAddress = stack.pop(); + auto codeAddress = stack.pop(); auto value = stack.pop(); auto inOff = stack.pop(); auto inSize = stack.pop(); @@ -891,7 +892,11 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto sizeReq = builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); memory.require(sizeReq); - auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize); + auto receiveAddress = codeAddress; + if (inst == Instruction::CALLCODE) + receiveAddress = ext.address(); + + auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); gasMeter.giveBack(gas); stack.push(ret); break; diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index aeb720903..103842daf 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -27,7 +27,6 @@ ExecutionEngine::ExecutionEngine() } - int ExecutionEngine::run(std::unique_ptr _module) { auto module = _module.get(); // Keep ownership of the module in _module diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 2b3313b87..93c3616e0 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -60,6 +60,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_arg5 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg5"); m_arg6 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg6"); m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg7"); + m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8"); Type* elements[] = { i256Ty, // i256 address; @@ -90,12 +91,12 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_balance = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_balance", module); m_suicide = Function::Create(TypeBuilder*), true>::get(ctx), Linkage::ExternalLinkage, "ext_suicide", module); m_create = Function::Create(TypeBuilder*, i<256>*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_create", module); - Type* args[] = {i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy}; + Type* args[] = {i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy}; m_call = Function::Create(FunctionType::get(m_builder.getVoidTy(), args, false), Linkage::ExternalLinkage, "ext_call", module); m_bswap = Intrinsic::getDeclaration(module, Intrinsic::bswap, i256Ty); m_sha3 = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_sha3", module); m_exp = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_exp", module); - m_codeAt = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codeAt", module); + m_codeAt = Function::Create(TypeBuilder*(i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codeAt", module); m_codesizeAt = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codesizeAt", module); m_builder.CreateCall(m_init, m_data); @@ -176,7 +177,7 @@ Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* return address; } -llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize) +llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) { m_builder.CreateStore(_gas, m_args[0]); auto receiveAddress = bswap(_receiveAddress); // to BE @@ -186,7 +187,10 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V m_builder.CreateStore(_inSize, m_arg5); m_builder.CreateStore(_outOff, m_arg6); m_builder.CreateStore(_outSize, m_arg7); - llvm::Value* args[] = {m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_args[1]}; + auto codeAddress = bswap(_codeAddress); // toBE + m_builder.CreateStore(codeAddress, m_arg8); + + llvm::Value* args[] = {m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]}; m_builder.CreateCall(m_call, args); _gas = m_builder.CreateLoad(m_args[0]); // Return gas return m_builder.CreateLoad(m_args[1]); @@ -216,9 +220,7 @@ llvm::Value* Ext::codeAt(llvm::Value* _addr) { auto addr = bswap(_addr); m_builder.CreateStore(addr, m_args[0]); - llvm::Value* args[] = {m_args[0], m_args[1]}; - m_builder.CreateCall(m_codeAt, args); - return m_builder.CreateLoad(m_args[1]); + return m_builder.CreateCall(m_codeAt, m_args[0]); } llvm::Value* Ext::codesizeAt(llvm::Value* _addr) @@ -315,7 +317,7 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* -EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, i256* _ret) +EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* _ret) { auto&& ext = Runtime::getExt(); auto value = llvm2eth(*_value); @@ -333,7 +335,8 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO auto&& inRef = dev::bytesConstRef(Runtime::getMemory().data() + inOff, inSize); auto&& outRef = dev::bytesConstRef(Runtime::getMemory().data() + outOff, outSize); dev::eth::OnOpFunc onOp{}; // TODO: Handle that thing - ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, receiveAddress); + auto codeAddress = dev::right160(*_codeAddress); + ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); } *_gas = eth2llvm(gas); @@ -357,12 +360,12 @@ EXPORT void ext_exp(i256* _left, i256* _right, i256* _ret) *_ret = eth2llvm(ret); } -EXPORT void ext_codeAt(h256* _addr256, i256* _ret) +EXPORT unsigned char* ext_codeAt(h256* _addr256) { auto&& ext = Runtime::getExt(); auto addr = dev::right160(*_addr256); auto& code = ext.codeAt(addr); - *_ret = *reinterpret_cast(const_cast(&code[0])); + return const_cast(code.data()); } EXPORT void ext_codesizeAt(h256* _addr256, i256* _ret) diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 03ff90ba8..daf12b100 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -39,7 +39,7 @@ public: void suicide(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); - llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize); + llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); llvm::Value* exp(llvm::Value* _left, llvm::Value* _right); @@ -61,6 +61,7 @@ private: llvm::Value* m_arg5; llvm::Value* m_arg6; llvm::Value* m_arg7; + llvm::Value* m_arg8; llvm::Value* m_data; llvm::Function* m_init; llvm::Function* m_store; diff --git a/evmcc/test/ext/extcodecopy1.evm b/evmcc/test/ext/extcodecopy1.evm new file mode 100644 index 000000000..6132b52d8 --- /dev/null +++ b/evmcc/test/ext/extcodecopy1.evm @@ -0,0 +1 @@ +60c86000600a303c60005360006020f2 diff --git a/evmcc/test/ext/extcodecopy1.lll b/evmcc/test/ext/extcodecopy1.lll new file mode 100644 index 000000000..c37054574 --- /dev/null +++ b/evmcc/test/ext/extcodecopy1.lll @@ -0,0 +1,11 @@ +(asm +200 ;; byte count +0 ;; source index in code array +10 ;; dest index in memory +ADDRESS +EXTCODECOPY + +0 MLOAD ;; to dump memory + +0 32 RETURN +) \ No newline at end of file From 2909cac50e94cfbfdb855467dea457a937eb6168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 15:07:31 +0200 Subject: [PATCH 126/396] Working longjmp solution [#80660432] --- evmcc/Compiler.cpp | 14 ++------------ evmcc/ExecutionEngine.cpp | 16 ++++++++++------ evmcc/GasMeter.cpp | 9 ++++++--- evmcc/GasMeter.h | 2 +- 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 8c64c3fe2..5a84d32fc 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -199,22 +199,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) createBasicBlocks(bytecode); - // Prepare jump buffer - auto jmpBufStorageTy = llvm::ArrayType::get(Type::Byte, 2048); - auto jmpBufStorage = new llvm::GlobalVariable(*module, jmpBufStorageTy, false, llvm::GlobalVariable::PrivateLinkage, llvm::ConstantAggregateZero::get(jmpBufStorageTy), "jmpBuf"); - jmpBufStorage->setAlignment(16); - auto jmpBuf = builder.CreateConstInBoundsGEP2_32(jmpBufStorage, 0, 0); - // Init runtime structures. - GasMeter gasMeter(builder, module.get(), jmpBuf); + GasMeter gasMeter(builder, module.get()); Memory memory(builder, module.get(), gasMeter); Ext ext(builder, module.get()); - // Create exception landing with setjmp and jump to first instruction - auto setjmpFunc = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); - auto setjmpRet = builder.CreateCall(setjmpFunc, jmpBuf); - auto isNormalFlow = builder.CreateICmpEQ(setjmpRet, builder.getInt32(0)); - builder.CreateCondBr(isNormalFlow, basicBlocks.begin()->second, m_outOfGasBlock->llvm()); + builder.CreateBr(basicBlocks.begin()->second); for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) { diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index aeb720903..a5ed3681a 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -1,6 +1,8 @@ #include "ExecutionEngine.h" +#include + #include #include #include @@ -27,6 +29,8 @@ ExecutionEngine::ExecutionEngine() } +extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; } + int ExecutionEngine::run(std::unique_ptr _module) { @@ -101,17 +105,17 @@ int ExecutionEngine::run(std::unique_ptr _module) exit(1); } - ReturnCode returnCode; - try + std::jmp_buf buf; + auto r = setjmp(buf); + if (r == 0) { + rt_jmpBuf = &buf; auto result = exec->runFunction(entryFunc, {}); returnCode = static_cast(result.IntVal.getZExtValue()); } - catch (const dev::eth::OutOfGas&) - { - returnCode = ReturnCode::OutOfGas; - } + else + returnCode = static_cast(r); gas = static_cast(Runtime::getGas()); diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 0d0927563..adf7f407a 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -78,7 +78,7 @@ bool isCostBlockEnd(Instruction _inst) } -GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Value* _jmpBuf) : +GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module) : m_builder(_builder) { m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); @@ -102,8 +102,11 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Val m_builder.SetInsertPoint(outOfGasBB); - auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); - m_builder.CreateCall(longjmpFunc, _jmpBuf); + //auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); + auto extJmpBuf = new llvm::GlobalVariable(*_module, Type::BytePtr, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "rt_jmpBuf"); + llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; + auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", _module); + m_builder.CreateCall2(longjmpNative, m_builder.CreateLoad(extJmpBuf), Constant::get(ReturnCode::OutOfGas)); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 5af117900..099ce004e 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -11,7 +11,7 @@ namespace evmcc class GasMeter { public: - GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Value* _jmpBuf); + GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module); GasMeter(const GasMeter&) = delete; void operator=(GasMeter) = delete; From 5a6d8b3d2f4cbd3deaab1c20c3f15d7f833de78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 15:12:24 +0200 Subject: [PATCH 127/396] Unused rt_exit() function removed [#80660432] --- evmcc/GasMeter.cpp | 2 -- evmcc/GasMeter.h | 1 - evmcc/Runtime.cpp | 8 -------- 3 files changed, 11 deletions(-) diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index adf7f407a..1e3b607b8 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -84,8 +84,6 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module) : m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); m_gas->setUnnamedAddr(true); // Address is not important - m_rtExit = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::MainReturn, false), llvm::Function::ExternalLinkage, "rt_exit", _module); - m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", _module); InsertPointGuard guard(m_builder); diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 099ce004e..9774fbdaf 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -41,7 +41,6 @@ private: llvm::IRBuilder<>& m_builder; llvm::CallInst* m_checkCall = nullptr; llvm::GlobalVariable* m_gas; - llvm::Function* m_rtExit; llvm::Function* m_gasCheckFunc; }; diff --git a/evmcc/Runtime.cpp b/evmcc/Runtime.cpp index 834a8bbff..c37fa6702 100644 --- a/evmcc/Runtime.cpp +++ b/evmcc/Runtime.cpp @@ -13,14 +13,6 @@ static Runtime* g_runtime; extern "C" { EXPORT i256 gas; - -EXPORT void rt_exit(int32_t _returnCode) -{ - auto returnCode = static_cast(_returnCode); - if (returnCode == ReturnCode::OutOfGas) - BOOST_THROW_EXCEPTION(dev::eth::OutOfGas()); -} - } Runtime::Runtime(dev::u256 _gas, std::unique_ptr _ext): From c019b0394ae89146bffac8c032bb0ebab784c31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 15:35:26 +0200 Subject: [PATCH 128/396] Macros grouping PUSH, DUP and SWAP switch cases --- evmcc/Compiler.cpp | 102 +++------------------------------------------ evmcc/Utils.h | 67 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 96 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 45f21f29b..f71f4d2bf 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -14,6 +14,7 @@ #include "Memory.h" #include "Ext.h" #include "GasMeter.h" +#include "Utils.h" namespace evmcc { @@ -48,38 +49,8 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) auto inst = static_cast(*curr); switch (inst) { - case Instruction::PUSH1: - case Instruction::PUSH2: - case Instruction::PUSH3: - case Instruction::PUSH4: - case Instruction::PUSH5: - case Instruction::PUSH6: - case Instruction::PUSH7: - case Instruction::PUSH8: - case Instruction::PUSH9: - case Instruction::PUSH10: - case Instruction::PUSH11: - case Instruction::PUSH12: - case Instruction::PUSH13: - case Instruction::PUSH14: - case Instruction::PUSH15: - case Instruction::PUSH16: - case Instruction::PUSH17: - case Instruction::PUSH18: - case Instruction::PUSH19: - case Instruction::PUSH20: - case Instruction::PUSH21: - case Instruction::PUSH22: - case Instruction::PUSH23: - case Instruction::PUSH24: - case Instruction::PUSH25: - case Instruction::PUSH26: - case Instruction::PUSH27: - case Instruction::PUSH28: - case Instruction::PUSH29: - case Instruction::PUSH30: - case Instruction::PUSH31: - case Instruction::PUSH32: + + case Instruction::ANY_PUSH: { auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; auto next = curr + numBytes + 1; @@ -477,38 +448,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } - case Instruction::PUSH1: - case Instruction::PUSH2: - case Instruction::PUSH3: - case Instruction::PUSH4: - case Instruction::PUSH5: - case Instruction::PUSH6: - case Instruction::PUSH7: - case Instruction::PUSH8: - case Instruction::PUSH9: - case Instruction::PUSH10: - case Instruction::PUSH11: - case Instruction::PUSH12: - case Instruction::PUSH13: - case Instruction::PUSH14: - case Instruction::PUSH15: - case Instruction::PUSH16: - case Instruction::PUSH17: - case Instruction::PUSH18: - case Instruction::PUSH19: - case Instruction::PUSH20: - case Instruction::PUSH21: - case Instruction::PUSH22: - case Instruction::PUSH23: - case Instruction::PUSH24: - case Instruction::PUSH25: - case Instruction::PUSH26: - case Instruction::PUSH27: - case Instruction::PUSH28: - case Instruction::PUSH29: - case Instruction::PUSH30: - case Instruction::PUSH31: - case Instruction::PUSH32: + case Instruction::ANY_PUSH: { auto numBytes = static_cast(inst)-static_cast(Instruction::PUSH1) + 1; auto value = llvm::APInt(256, 0); @@ -523,44 +463,14 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } - case Instruction::DUP1: - case Instruction::DUP2: - case Instruction::DUP3: - case Instruction::DUP4: - case Instruction::DUP5: - case Instruction::DUP6: - case Instruction::DUP7: - case Instruction::DUP8: - case Instruction::DUP9: - case Instruction::DUP10: - case Instruction::DUP11: - case Instruction::DUP12: - case Instruction::DUP13: - case Instruction::DUP14: - case Instruction::DUP15: - case Instruction::DUP16: + case Instruction::ANY_DUP: { auto index = static_cast(inst)-static_cast(Instruction::DUP1); stack.dup(index); break; } - case Instruction::SWAP1: - case Instruction::SWAP2: - case Instruction::SWAP3: - case Instruction::SWAP4: - case Instruction::SWAP5: - case Instruction::SWAP6: - case Instruction::SWAP7: - case Instruction::SWAP8: - case Instruction::SWAP9: - case Instruction::SWAP10: - case Instruction::SWAP11: - case Instruction::SWAP12: - case Instruction::SWAP13: - case Instruction::SWAP14: - case Instruction::SWAP15: - case Instruction::SWAP16: + case Instruction::ANY_SWAP: { auto index = static_cast(inst)-static_cast(Instruction::SWAP1) + 1; stack.swap(index); diff --git a/evmcc/Utils.h b/evmcc/Utils.h index f0224831c..d5b136327 100644 --- a/evmcc/Utils.h +++ b/evmcc/Utils.h @@ -44,4 +44,71 @@ private: void operator=(InsertPointGuard) = delete; }; +#define ANY_PUSH PUSH1: \ + case Instruction::PUSH2: \ + case Instruction::PUSH3: \ + case Instruction::PUSH4: \ + case Instruction::PUSH5: \ + case Instruction::PUSH6: \ + case Instruction::PUSH7: \ + case Instruction::PUSH8: \ + case Instruction::PUSH9: \ + case Instruction::PUSH10: \ + case Instruction::PUSH11: \ + case Instruction::PUSH12: \ + case Instruction::PUSH13: \ + case Instruction::PUSH14: \ + case Instruction::PUSH15: \ + case Instruction::PUSH16: \ + case Instruction::PUSH17: \ + case Instruction::PUSH18: \ + case Instruction::PUSH19: \ + case Instruction::PUSH20: \ + case Instruction::PUSH21: \ + case Instruction::PUSH22: \ + case Instruction::PUSH23: \ + case Instruction::PUSH24: \ + case Instruction::PUSH25: \ + case Instruction::PUSH26: \ + case Instruction::PUSH27: \ + case Instruction::PUSH28: \ + case Instruction::PUSH29: \ + case Instruction::PUSH30: \ + case Instruction::PUSH31: \ + case Instruction::PUSH32 + +#define ANY_DUP DUP1: \ + case Instruction::DUP2: \ + case Instruction::DUP3: \ + case Instruction::DUP4: \ + case Instruction::DUP5: \ + case Instruction::DUP6: \ + case Instruction::DUP7: \ + case Instruction::DUP8: \ + case Instruction::DUP9: \ + case Instruction::DUP10: \ + case Instruction::DUP11: \ + case Instruction::DUP12: \ + case Instruction::DUP13: \ + case Instruction::DUP14: \ + case Instruction::DUP15: \ + case Instruction::DUP16 + +#define ANY_SWAP SWAP1: \ + case Instruction::SWAP2: \ + case Instruction::SWAP3: \ + case Instruction::SWAP4: \ + case Instruction::SWAP5: \ + case Instruction::SWAP6: \ + case Instruction::SWAP7: \ + case Instruction::SWAP8: \ + case Instruction::SWAP9: \ + case Instruction::SWAP10: \ + case Instruction::SWAP11: \ + case Instruction::SWAP12: \ + case Instruction::SWAP13: \ + case Instruction::SWAP14: \ + case Instruction::SWAP15: \ + case Instruction::SWAP16 + } \ No newline at end of file From e33be3bbdbc79b1f1e4a6e50889cb53e2db77833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 16:29:13 +0200 Subject: [PATCH 129/396] Change namespace from `evmcc` to `dev::eth::jit` [#80021262] --- evmcc/BasicBlock.cpp | 9 ++++++++- evmcc/BasicBlock.h | 9 ++++++++- evmcc/Compiler.cpp | 9 ++++++++- evmcc/Compiler.h | 8 +++++++- evmcc/ExecutionEngine.cpp | 12 +++++++++--- evmcc/ExecutionEngine.h | 10 ++++++++-- evmcc/Ext.cpp | 11 +++++++++-- evmcc/Ext.h | 11 ++++++++--- evmcc/GasMeter.cpp | 9 ++++++++- evmcc/GasMeter.h | 9 ++++++++- evmcc/Memory.cpp | 15 +++++++++++---- evmcc/Memory.h | 10 +++++++++- evmcc/Runtime.cpp | 10 ++++++++-- evmcc/Runtime.h | 10 ++++++++-- evmcc/Type.cpp | 9 ++++++++- evmcc/Type.h | 9 ++++++++- evmcc/Utils.cpp | 10 ++++++++-- evmcc/Utils.h | 10 ++++++++-- evmcc/evmcc.cpp | 10 +++++----- 19 files changed, 154 insertions(+), 36 deletions(-) diff --git a/evmcc/BasicBlock.cpp b/evmcc/BasicBlock.cpp index 3a2c1c548..02c85165d 100644 --- a/evmcc/BasicBlock.cpp +++ b/evmcc/BasicBlock.cpp @@ -6,7 +6,11 @@ #include "Type.h" -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { const char* BasicBlock::NamePrefix = "Instr."; @@ -69,3 +73,6 @@ void BasicBlock::Stack::swap(size_t _index) } } +} +} + diff --git a/evmcc/BasicBlock.h b/evmcc/BasicBlock.h index 598ab731c..71d8aa355 100644 --- a/evmcc/BasicBlock.h +++ b/evmcc/BasicBlock.h @@ -3,7 +3,11 @@ #include -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { using ProgramCounter = uint64_t; // TODO: Rename @@ -74,3 +78,6 @@ private: }; } +} +} + diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index f71f4d2bf..33e92b758 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -16,7 +16,11 @@ #include "GasMeter.h" #include "Utils.h" -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { using dev::eth::Instruction; @@ -945,3 +949,6 @@ void Compiler::linkBasicBlocks() } } +} +} + diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 509cf77df..17bed3f78 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -7,7 +7,11 @@ #include "BasicBlock.h" -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { class Compiler @@ -66,3 +70,5 @@ private: }; } +} +} diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index a5ed3681a..df2ea74d6 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -21,7 +21,11 @@ #include "Memory.h" #include "Type.h" -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { ExecutionEngine::ExecutionEngine() @@ -91,7 +95,7 @@ int ExecutionEngine::run(std::unique_ptr _module) ext->currentBlock.gasLimit = 1008; std::string calldata = "Hello the Beautiful World of Ethereum!"; ext->data = calldata; - unsigned char fakecode[] = { 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf }; + unsigned char fakecode[] = {0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf}; ext->code = decltype(ext->code)(fakecode, 8); // Init runtime @@ -118,7 +122,7 @@ int ExecutionEngine::run(std::unique_ptr _module) returnCode = static_cast(r); gas = static_cast(Runtime::getGas()); - + if (returnCode == ReturnCode::Return) { auto&& returnData = Memory::getReturnData(); // TODO: It might be better to place is in Runtime interface @@ -134,3 +138,5 @@ int ExecutionEngine::run(std::unique_ptr _module) } } +} +} diff --git a/evmcc/ExecutionEngine.h b/evmcc/ExecutionEngine.h index 1bdf8c564..158df0283 100644 --- a/evmcc/ExecutionEngine.h +++ b/evmcc/ExecutionEngine.h @@ -5,7 +5,11 @@ #include -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { class ExecutionEngine @@ -16,4 +20,6 @@ public: int run(std::unique_ptr module); }; -} \ No newline at end of file +} +} +} diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 93c3616e0..0f5a18795 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -15,7 +15,11 @@ using Linkage = llvm::GlobalValue::LinkageTypes; using dev::h256; using dev::u256; -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { // TODO: Copy of dev::eth::fromAddress in VM.h @@ -238,7 +242,7 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr) extern "C" { -using namespace evmcc; +using namespace dev::eth::jit; EXPORT void ext_init(ExtData* _extData) { @@ -377,3 +381,6 @@ EXPORT void ext_codesizeAt(h256* _addr256, i256* _ret) } } +} +} + diff --git a/evmcc/Ext.h b/evmcc/Ext.h index daf12b100..b8b93d61f 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -5,10 +5,12 @@ #include -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { - - class Ext { @@ -80,3 +82,6 @@ private: } +} +} + diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 1e3b607b8..2d2774c74 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -12,7 +12,11 @@ #include "Utils.h" #include "Ext.h" -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { using namespace dev::eth; // We should move all the JIT code into dev::eth namespace @@ -193,3 +197,6 @@ llvm::Value* GasMeter::getGas() } } +} +} + diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 9774fbdaf..c7c1a1bda 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -5,7 +5,11 @@ #include -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { class GasMeter @@ -45,3 +49,6 @@ private: }; } +} +} + diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index cf82e7a50..e9abad1c1 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -15,7 +15,11 @@ #include "Runtime.h" #include "GasMeter.h" -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter): @@ -213,11 +217,14 @@ void Memory::dump(uint64_t _begin, uint64_t _end) m_builder.CreateCall(m_memDump, llvm::ArrayRef(args)); } -} // namespace evmcc +} +} +} + extern "C" { - using namespace evmcc; + using namespace dev::eth::jit; EXPORT i256 mem_returnDataOffset; EXPORT i256 mem_returnDataSize; @@ -256,7 +263,7 @@ EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) } // extern "C" -dev::bytesConstRef evmcc::Memory::getReturnData() +dev::bytesConstRef dev::eth::jit::Memory::getReturnData() { // TODO: Handle large indexes auto offset = static_cast(llvm2eth(mem_returnDataOffset)); diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 34b4c68a8..73dff7842 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -4,8 +4,13 @@ #include -namespace evmcc +namespace dev { +namespace eth +{ +namespace jit +{ + class GasMeter; class Memory @@ -58,3 +63,6 @@ private: }; } +} +} + diff --git a/evmcc/Runtime.cpp b/evmcc/Runtime.cpp index c37fa6702..a7cc0126e 100644 --- a/evmcc/Runtime.cpp +++ b/evmcc/Runtime.cpp @@ -5,7 +5,11 @@ #include "Type.h" -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { static Runtime* g_runtime; @@ -48,4 +52,6 @@ dev::u256 Runtime::getGas() return llvm2eth(gas); } -} \ No newline at end of file +} +} +} diff --git a/evmcc/Runtime.h b/evmcc/Runtime.h index 547e4bcf1..b9cfe2309 100644 --- a/evmcc/Runtime.h +++ b/evmcc/Runtime.h @@ -14,7 +14,11 @@ #define EXPORT #endif -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { using StackImpl = std::vector; @@ -40,4 +44,6 @@ private: std::unique_ptr m_ext; }; -} \ No newline at end of file +} +} +} diff --git a/evmcc/Type.cpp b/evmcc/Type.cpp index 4837829b4..4804f99b8 100644 --- a/evmcc/Type.cpp +++ b/evmcc/Type.cpp @@ -3,7 +3,11 @@ #include -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { llvm::IntegerType* Type::i256; @@ -36,3 +40,6 @@ llvm::Constant* Constant::get(ReturnCode _returnCode) } } +} +} + diff --git a/evmcc/Type.h b/evmcc/Type.h index 727183266..ac3196ed2 100644 --- a/evmcc/Type.h +++ b/evmcc/Type.h @@ -4,7 +4,11 @@ #include #include -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { struct Type @@ -46,3 +50,6 @@ struct Constant }; } +} +} + diff --git a/evmcc/Utils.cpp b/evmcc/Utils.cpp index cef08a283..7ad6ca283 100644 --- a/evmcc/Utils.cpp +++ b/evmcc/Utils.cpp @@ -1,7 +1,11 @@ #include "Utils.h" -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { dev::u256 llvm2eth(i256 _i) @@ -31,4 +35,6 @@ i256 eth2llvm(dev::u256 _u) return i; } -} \ No newline at end of file +} +} +} diff --git a/evmcc/Utils.h b/evmcc/Utils.h index d5b136327..74ad2a4d0 100644 --- a/evmcc/Utils.h +++ b/evmcc/Utils.h @@ -5,7 +5,11 @@ #include -namespace evmcc +namespace dev +{ +namespace eth +{ +namespace jit { /// Representation of 256-bit value binary compatible with LLVM i256 @@ -111,4 +115,6 @@ private: case Instruction::SWAP15: \ case Instruction::SWAP16 -} \ No newline at end of file +} +} +} diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 222bcffb3..b49a2a372 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -15,8 +15,6 @@ #include "Compiler.h" #include "ExecutionEngine.h" -using namespace dev; - void show_usage() { @@ -74,6 +72,8 @@ int main(int argc, char** argv) boost::algorithm::trim(src); + using namespace dev; + bytes bytecode = fromHex(src); if (opt_show_bytes) @@ -89,15 +89,15 @@ int main(int argc, char** argv) if (opt_compile) { - auto module = evmcc::Compiler().compile(bytecode); + auto module = eth::jit::Compiler().compile(bytecode); llvm::raw_os_ostream out(std::cout); module->print(out, nullptr); } if (opt_interpret) { - auto engine = evmcc::ExecutionEngine(); - auto module = evmcc::Compiler().compile(bytecode); + auto engine = eth::jit::ExecutionEngine(); + auto module = eth::jit::Compiler().compile(bytecode); module->dump(); auto result = engine.run(std::move(module)); return result; From 91770a2e4d339c9e1b20989eb53a3c7bdf867916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 16:49:29 +0200 Subject: [PATCH 130/396] Eliminating some `using namespace` [#80021262] --- evmcc/Compiler.cpp | 22 ++++++++-------------- evmcc/Ext.cpp | 6 ++---- evmcc/GasMeter.cpp | 4 +--- evmcc/Memory.cpp | 3 ++- evmcc/Type.cpp | 6 +++--- evmcc/Type.h | 6 +++--- 6 files changed, 19 insertions(+), 28 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 33e92b758..1fbab5be8 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -23,10 +23,6 @@ namespace eth namespace jit { -using dev::eth::Instruction; -using namespace dev::eth; // We should move all the JIT code into dev::eth namespace - - Compiler::Compiler() : m_finalBlock(nullptr) , m_badJumpBlock(nullptr) @@ -159,14 +155,12 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { - using namespace llvm; - - auto& context = getGlobalContext(); - auto module = std::make_unique("main", context); - IRBuilder<> builder(context); + auto& context = llvm::getGlobalContext(); + auto module = std::make_unique("main", context); + llvm::IRBuilder<> builder(context); // Create main function - m_mainFunc = Function::Create(FunctionType::get(Type::MainReturn, false), Function::ExternalLinkage, "main", module.get()); + m_mainFunc = llvm::Function::Create(llvm::FunctionType::get(Type::MainReturn, false), llvm::Function::ExternalLinkage, "main", module.get()); // Create the basic blocks. auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc); @@ -286,7 +280,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::NEG: { auto top = stack.pop(); - auto zero = ConstantInt::get(Type::i256, 0); + auto zero = Constant::get(0); auto res = builder.CreateSub(zero, top); stack.push(res); break; @@ -345,7 +339,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) case Instruction::NOT: { auto top = stack.pop(); - auto zero = ConstantInt::get(Type::i256, 0); + auto zero = Constant::get(0); auto iszero = builder.CreateICmpEQ(top, zero, "iszero"); auto result = builder.CreateZExt(iszero, Type::i256); stack.push(result); @@ -566,7 +560,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) { stack.swap(1); auto val = stack.pop(); - auto zero = ConstantInt::get(Type::i256, 0); + auto zero = Constant::get(0); auto cond = builder.CreateICmpNE(val, zero, "nonzero"); // Assume the basic blocks are properly ordered: @@ -876,7 +870,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) { auto& bb = *it; - auto dest = ConstantInt::get(Type::i256, bb->begin()); + auto dest = Constant::get(bb->begin()); switchInstr->addCase(dest, bb->llvm()); } } diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 0f5a18795..e9618dcab 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -10,10 +10,6 @@ #include "Runtime.h" using namespace llvm; -using llvm::types::i; -using Linkage = llvm::GlobalValue::LinkageTypes; -using dev::h256; -using dev::u256; namespace dev { @@ -88,6 +84,8 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) m_data = m_builder.CreateAlloca(extDataTy, nullptr, "ext.data"); + using llvm::types::i; + using Linkage = llvm::GlobalValue::LinkageTypes; m_init = Function::Create(FunctionType::get(m_builder.getVoidTy(), extDataTy->getPointerTo(), false), Linkage::ExternalLinkage, "ext_init", module); m_store = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); m_setStore = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 2d2774c74..bfd688c61 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -19,12 +19,10 @@ namespace eth namespace jit { -using namespace dev::eth; // We should move all the JIT code into dev::eth namespace - namespace // Helper functions { -uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to FeeSructure +uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted) { switch (inst) { diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index e9abad1c1..7c742eb81 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -224,7 +224,8 @@ void Memory::dump(uint64_t _begin, uint64_t _end) extern "C" { - using namespace dev::eth::jit; + +using namespace dev::eth::jit; EXPORT i256 mem_returnDataOffset; EXPORT i256 mem_returnDataSize; diff --git a/evmcc/Type.cpp b/evmcc/Type.cpp index 4804f99b8..3ef339a1b 100644 --- a/evmcc/Type.cpp +++ b/evmcc/Type.cpp @@ -16,7 +16,7 @@ llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; -llvm::Type* Type::MainReturn; +llvm::IntegerType* Type::MainReturn; void Type::init(llvm::LLVMContext& _context) { @@ -29,12 +29,12 @@ void Type::init(llvm::LLVMContext& _context) MainReturn = llvm::Type::getInt32Ty(_context); } -llvm::Constant* Constant::get(uint64_t _n) +llvm::ConstantInt* Constant::get(uint64_t _n) { return llvm::ConstantInt::get(Type::i256, _n); } -llvm::Constant* Constant::get(ReturnCode _returnCode) +llvm::ConstantInt* Constant::get(ReturnCode _returnCode) { return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); } diff --git a/evmcc/Type.h b/evmcc/Type.h index ac3196ed2..06907b7df 100644 --- a/evmcc/Type.h +++ b/evmcc/Type.h @@ -26,7 +26,7 @@ struct Type static llvm::Type* Void; /// Main function return type - static llvm::Type* MainReturn; + static llvm::IntegerType* MainReturn; static void init(llvm::LLVMContext& _context); }; @@ -44,9 +44,9 @@ enum class ReturnCode struct Constant { /// Returns word-size constant - static llvm::Constant* get(uint64_t _n); + static llvm::ConstantInt* get(uint64_t _n); - static llvm::Constant* get(ReturnCode _returnCode); + static llvm::ConstantInt* get(ReturnCode _returnCode); }; } From 2c44470e87918810b0cff39b8b79d109168a79d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 16:58:15 +0200 Subject: [PATCH 131/396] Removing unnecessary `dev` name prefixes [#80021262] --- evmcc/Compiler.cpp | 8 +++----- evmcc/Compiler.h | 4 ++-- evmcc/ExecutionEngine.cpp | 12 ++++++------ evmcc/Ext.cpp | 38 +++++++++++++++++++------------------- evmcc/Ext.h | 2 +- evmcc/GasMeter.cpp | 2 +- evmcc/GasMeter.h | 2 +- evmcc/Memory.h | 2 +- evmcc/Runtime.cpp | 6 +++--- evmcc/Runtime.h | 10 +++++----- evmcc/Utils.cpp | 8 ++++---- evmcc/Utils.h | 4 ++-- evmcc/evmcc.cpp | 2 +- 13 files changed, 49 insertions(+), 51 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 1fbab5be8..5d474a0a8 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -30,7 +30,7 @@ Compiler::Compiler() Type::init(llvm::getGlobalContext()); } -void Compiler::createBasicBlocks(const dev::bytes& bytecode) +void Compiler::createBasicBlocks(const bytes& bytecode) { std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end splitPoints.insert(0); // First basic block @@ -41,8 +41,6 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr) { - using dev::eth::Instruction; - ProgramCounter currentPC = curr - bytecode.cbegin(); validJumpTargets[currentPC] = 1; @@ -62,7 +60,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) { // Compute target PC of the jump. - dev::u256 val = 0; + u256 val = 0; for (auto iter = curr + 1; iter < next; ++iter) { val <<= 8; @@ -153,7 +151,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) } } -std::unique_ptr Compiler::compile(const dev::bytes& bytecode) +std::unique_ptr Compiler::compile(const bytes& bytecode) { auto& context = llvm::getGlobalContext(); auto module = std::make_unique("main", context); diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 17bed3f78..62337d2de 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -22,11 +22,11 @@ public: Compiler(); - std::unique_ptr compile(const dev::bytes& bytecode); + std::unique_ptr compile(const bytes& bytecode); private: - void createBasicBlocks(const dev::bytes& bytecode); + void createBasicBlocks(const bytes& bytecode); void linkBasicBlocks(); diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index df2ea74d6..6a494f42a 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -81,14 +81,14 @@ int ExecutionEngine::run(std::unique_ptr _module) exec->finalizeObject(); // Create fake ExtVM interface - auto ext = std::make_unique(); - ext->myAddress = dev::Address(1122334455667788); - ext->caller = dev::Address(0xfacefacefaceface); - ext->origin = dev::Address(101010101010101010); + auto ext = std::make_unique(); + ext->myAddress = Address(1122334455667788); + ext->caller = Address(0xfacefacefaceface); + ext->origin = Address(101010101010101010); ext->value = 0xabcd; ext->gasPrice = 1002; - ext->previousBlock.hash = dev::u256(1003); - ext->currentBlock.coinbaseAddress = dev::Address(1004); + ext->previousBlock.hash = u256(1003); + ext->currentBlock.coinbaseAddress = Address(1004); ext->currentBlock.timestamp = 1005; ext->currentBlock.number = 1006; ext->currentBlock.difficulty = 1007; diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index e9618dcab..a300b586c 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -18,10 +18,10 @@ namespace eth namespace jit { -// TODO: Copy of dev::eth::fromAddress in VM.h -inline dev::u256 fromAddress(dev::Address _a) +// TODO: Copy of fromAddress in VM.h +inline u256 fromAddress(Address _a) { - return (dev::u160)_a; + return (u160)_a; } struct ExtData @@ -288,13 +288,13 @@ EXPORT void ext_calldataload(i256* _index, i256* _value) EXPORT void ext_balance(h256* _address, i256* _value) { - auto u = Runtime::getExt().balance(dev::right160(*_address)); + auto u = Runtime::getExt().balance(right160(*_address)); *_value = eth2llvm(u); } EXPORT void ext_suicide(h256* _address) { - Runtime::getExt().suicide(dev::right160(*_address)); + Runtime::getExt().suicide(right160(*_address)); } EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) @@ -308,8 +308,8 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* u256 gas; // TODO: Handle gas auto initOff = static_cast(llvm2eth(*_initOff)); auto initSize = static_cast(llvm2eth(*_initSize)); - auto&& initRef = dev::bytesConstRef(Runtime::getMemory().data() + initOff, initSize); - auto&& onOp = dev::bytesConstRef(); // TODO: Handle that thing + auto&& initRef = bytesConstRef(Runtime::getMemory().data() + initOff, initSize); + auto&& onOp = bytesConstRef(); // TODO: Handle that thing h256 address = ext.create(endowment, &gas, initRef, onOp); *_address = address; } @@ -329,15 +329,15 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO if (ext.balance(ext.myAddress) >= value) { ext.subBalance(value); - auto receiveAddress = dev::right160(*_receiveAddress); + auto receiveAddress = right160(*_receiveAddress); auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); auto outOff = static_cast(llvm2eth(*_outOff)); auto outSize = static_cast(llvm2eth(*_outSize)); - auto&& inRef = dev::bytesConstRef(Runtime::getMemory().data() + inOff, inSize); - auto&& outRef = dev::bytesConstRef(Runtime::getMemory().data() + outOff, outSize); - dev::eth::OnOpFunc onOp{}; // TODO: Handle that thing - auto codeAddress = dev::right160(*_codeAddress); + auto&& inRef = bytesConstRef(Runtime::getMemory().data() + inOff, inSize); + auto&& outRef = bytesConstRef(Runtime::getMemory().data() + outOff, outSize); + OnOpFunc onOp{}; // TODO: Handle that thing + auto codeAddress = right160(*_codeAddress); ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); } @@ -349,23 +349,23 @@ EXPORT void ext_sha3(i256* _inOff, i256* _inSize, i256* _ret) { auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); - auto dataRef = dev::bytesConstRef(Runtime::getMemory().data() + inOff, inSize); - auto hash = dev::eth::sha3(dataRef); + auto dataRef = bytesConstRef(Runtime::getMemory().data() + inOff, inSize); + auto hash = sha3(dataRef); *_ret = *reinterpret_cast(&hash); } EXPORT void ext_exp(i256* _left, i256* _right, i256* _ret) { - dev::bigint left = llvm2eth(*_left); - dev::bigint right = llvm2eth(*_right); - auto ret = static_cast(boost::multiprecision::powm(left, right, dev::bigint(2) << 256)); + bigint left = llvm2eth(*_left); + bigint right = llvm2eth(*_right); + auto ret = static_cast(boost::multiprecision::powm(left, right, bigint(2) << 256)); *_ret = eth2llvm(ret); } EXPORT unsigned char* ext_codeAt(h256* _addr256) { auto&& ext = Runtime::getExt(); - auto addr = dev::right160(*_addr256); + auto addr = right160(*_addr256); auto& code = ext.codeAt(addr); return const_cast(code.data()); } @@ -373,7 +373,7 @@ EXPORT unsigned char* ext_codeAt(h256* _addr256) EXPORT void ext_codesizeAt(h256* _addr256, i256* _ret) { auto&& ext = Runtime::getExt(); - auto addr = dev::right160(*_addr256); + auto addr = right160(*_addr256); auto& code = ext.codeAt(addr); *_ret = eth2llvm(u256(code.size())); } diff --git a/evmcc/Ext.h b/evmcc/Ext.h index b8b93d61f..227632291 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -16,7 +16,7 @@ class Ext { public: Ext(llvm::IRBuilder<>& _builder, llvm::Module* module); - static void init(std::unique_ptr _ext); + static void init(std::unique_ptr _ext); llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index bfd688c61..f57f2b2c8 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -22,7 +22,7 @@ namespace jit namespace // Helper functions { -uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted) +uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted) { switch (inst) { diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index c7c1a1bda..88c952acd 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -21,7 +21,7 @@ public: void operator=(GasMeter) = delete; /// Count step cost of instruction - void count(dev::eth::Instruction _inst); + void count(Instruction _inst); /// Calculate & count gas cost for SSTORE instruction void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 73dff7842..24ed81a0c 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -35,7 +35,7 @@ public: void require(llvm::Value* _offset, llvm::Value* _size); void registerReturnData(llvm::Value* _index, llvm::Value* _size); - static dev::bytesConstRef getReturnData(); + static bytesConstRef getReturnData(); void dump(uint64_t _begin, uint64_t _end = 0); diff --git a/evmcc/Runtime.cpp b/evmcc/Runtime.cpp index a7cc0126e..d85f484b3 100644 --- a/evmcc/Runtime.cpp +++ b/evmcc/Runtime.cpp @@ -19,7 +19,7 @@ extern "C" EXPORT i256 gas; } -Runtime::Runtime(dev::u256 _gas, std::unique_ptr _ext): +Runtime::Runtime(u256 _gas, std::unique_ptr _ext): m_ext(std::move(_ext)) { assert(!g_runtime); @@ -42,12 +42,12 @@ MemoryImpl& Runtime::getMemory() return g_runtime->m_memory; } -dev::eth::ExtVMFace& Runtime::getExt() +ExtVMFace& Runtime::getExt() { return *g_runtime->m_ext; } -dev::u256 Runtime::getGas() +u256 Runtime::getGas() { return llvm2eth(gas); } diff --git a/evmcc/Runtime.h b/evmcc/Runtime.h index b9cfe2309..0312e305b 100644 --- a/evmcc/Runtime.h +++ b/evmcc/Runtime.h @@ -22,12 +22,12 @@ namespace jit { using StackImpl = std::vector; -using MemoryImpl = dev::bytes; +using MemoryImpl = bytes; class Runtime { public: - Runtime(dev::u256 _gas, std::unique_ptr _ext); + Runtime(u256 _gas, std::unique_ptr _ext); ~Runtime(); Runtime(const Runtime&) = delete; @@ -35,13 +35,13 @@ public: static StackImpl& getStack(); static MemoryImpl& getMemory(); - static dev::eth::ExtVMFace& getExt(); - static dev::u256 getGas(); + static ExtVMFace& getExt(); + static u256 getGas(); private: StackImpl m_stack; MemoryImpl m_memory; - std::unique_ptr m_ext; + std::unique_ptr m_ext; }; } diff --git a/evmcc/Utils.cpp b/evmcc/Utils.cpp index 7ad6ca283..0fd9c0e41 100644 --- a/evmcc/Utils.cpp +++ b/evmcc/Utils.cpp @@ -8,9 +8,9 @@ namespace eth namespace jit { -dev::u256 llvm2eth(i256 _i) +u256 llvm2eth(i256 _i) { - dev::u256 u = 0; + u256 u = 0; u |= _i.d; u <<= 64; u |= _i.c; @@ -21,10 +21,10 @@ dev::u256 llvm2eth(i256 _i) return u; } -i256 eth2llvm(dev::u256 _u) +i256 eth2llvm(u256 _u) { i256 i; - dev::u256 mask = 0xFFFFFFFFFFFFFFFF; + u256 mask = 0xFFFFFFFFFFFFFFFF; i.a = static_cast(_u & mask); _u >>= 64; i.b = static_cast(_u & mask); diff --git a/evmcc/Utils.h b/evmcc/Utils.h index 74ad2a4d0..27189d5d0 100644 --- a/evmcc/Utils.h +++ b/evmcc/Utils.h @@ -23,8 +23,8 @@ struct i256 }; static_assert(sizeof(i256) == 32, "Wrong i265 size"); -dev::u256 llvm2eth(i256); -i256 eth2llvm(dev::u256); +u256 llvm2eth(i256); +i256 eth2llvm(u256); struct InsertPointGuard { diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index b49a2a372..d8bf9438b 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -78,7 +78,7 @@ int main(int argc, char** argv) if (opt_show_bytes) { - std::cout << dev::memDump(bytecode) << std::endl; + std::cout << memDump(bytecode) << std::endl; } if (opt_dissassemble) From 3beeb4226e075b4f2a83619f41e1cf6ea552a417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 17:31:36 +0200 Subject: [PATCH 132/396] Some changes about final/stop block --- evmcc/Compiler.cpp | 15 +++++---------- evmcc/Compiler.h | 13 +++---------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 5d474a0a8..cc2add6a5 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -24,8 +24,7 @@ namespace jit { Compiler::Compiler() - : m_finalBlock(nullptr) - , m_badJumpBlock(nullptr) + : m_badJumpBlock(nullptr) { Type::init(llvm::getGlobalContext()); } @@ -125,10 +124,9 @@ void Compiler::createBasicBlocks(const bytes& bytecode) basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc)); } - m_finalBlock = std::make_unique("FinalBlock", m_mainFunc); + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc); m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc); - m_outOfGasBlock = std::make_unique("OutOfGas", m_mainFunc); for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { @@ -830,8 +828,8 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { if (basicBlock.end() == bytecode.size()) { - // Branch from the last regular block to the final block. - builder.CreateBr(m_finalBlock->llvm()); + // Return STOP code + builder.CreateRet(Constant::get(ReturnCode::Stop)); } else { @@ -848,15 +846,12 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) // TODO: move to separate function. // Note: Right now the codegen for special blocks depends only on createBasicBlock(), // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). - builder.SetInsertPoint(m_finalBlock->llvm()); + builder.SetInsertPoint(m_stopBB); builder.CreateRet(Constant::get(ReturnCode::Stop)); builder.SetInsertPoint(m_badJumpBlock->llvm()); builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); - builder.SetInsertPoint(m_outOfGasBlock->llvm()); - builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); - builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) { diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 62337d2de..44eeebae4 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -31,7 +31,7 @@ private: void linkBasicBlocks(); /** - * Maps a program counter pc to a basic block which starts at pc (if any). + * Maps a program counter pc to a basic block that starts at pc (if any). */ std::map basicBlocks; @@ -45,13 +45,8 @@ private: */ std::vector m_indirectJumpTargets; - /// Collection of basic blocks in program - //std::vector m_basicBlocks; - - /** - * Final block for normal (non-exceptional) execution. - */ - std::unique_ptr m_finalBlock; + /// Stop basic block - terminates execution with STOP code (0) + llvm::BasicBlock* m_stopBB = nullptr; /** * Block with a jump table. @@ -63,8 +58,6 @@ private: */ std::unique_ptr m_badJumpBlock; - std::unique_ptr m_outOfGasBlock; - /// Main program function llvm::Function* m_mainFunc = nullptr; }; From 08c7dcc3d294139cda461fd361d3f430521222b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 19:06:35 +0200 Subject: [PATCH 133/396] Placing IRBuilder in Compiler class (for future refactoring) --- evmcc/Compiler.cpp | 177 ++++++++++++++++++++++----------------------- evmcc/Compiler.h | 4 +- 2 files changed, 90 insertions(+), 91 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index cc2add6a5..71ad61493 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include #include @@ -23,10 +23,10 @@ namespace eth namespace jit { -Compiler::Compiler() - : m_badJumpBlock(nullptr) +Compiler::Compiler(): + m_builder(llvm::getGlobalContext()) { - Type::init(llvm::getGlobalContext()); + Type::init(m_builder.getContext()); } void Compiler::createBasicBlocks(const bytes& bytecode) @@ -151,31 +151,29 @@ void Compiler::createBasicBlocks(const bytes& bytecode) std::unique_ptr Compiler::compile(const bytes& bytecode) { - auto& context = llvm::getGlobalContext(); - auto module = std::make_unique("main", context); - llvm::IRBuilder<> builder(context); + auto module = std::make_unique("main", m_builder.getContext()); // Create main function m_mainFunc = llvm::Function::Create(llvm::FunctionType::get(Type::MainReturn, false), llvm::Function::ExternalLinkage, "main", module.get()); // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc); - builder.SetInsertPoint(entryBlock); + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + m_builder.SetInsertPoint(entryBlock); createBasicBlocks(bytecode); // Init runtime structures. - GasMeter gasMeter(builder, module.get()); - Memory memory(builder, module.get(), gasMeter); - Ext ext(builder, module.get()); + GasMeter gasMeter(m_builder, module.get()); + Memory memory(m_builder, module.get(), gasMeter); + Ext ext(m_builder, module.get()); - builder.CreateBr(basicBlocks.begin()->second); + m_builder.CreateBr(basicBlocks.begin()->second); for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) { auto& basicBlock = basicBlockPairIt->second; auto& stack = basicBlock.getStack(); - builder.SetInsertPoint(basicBlock); + m_builder.SetInsertPoint(basicBlock); for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) { @@ -190,7 +188,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto result = builder.CreateAdd(lhs, rhs); + auto result = m_builder.CreateAdd(lhs, rhs); stack.push(result); break; } @@ -199,7 +197,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto result = builder.CreateSub(lhs, rhs); + auto result = m_builder.CreateSub(lhs, rhs); stack.push(result); break; } @@ -208,10 +206,10 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = builder.CreateMul(lhs128, rhs128); - auto res256 = builder.CreateZExt(res128, Type::i256); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateMul(lhs128, rhs128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); stack.push(res256); break; } @@ -220,10 +218,10 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = builder.CreateUDiv(lhs128, rhs128); - auto res256 = builder.CreateZExt(res128, Type::i256); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateUDiv(lhs128, rhs128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); stack.push(res256); break; } @@ -232,10 +230,10 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = builder.CreateSDiv(lhs128, rhs128); - auto res256 = builder.CreateSExt(res128, Type::i256); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateSDiv(lhs128, rhs128); + auto res256 = m_builder.CreateSExt(res128, Type::i256); stack.push(res256); break; } @@ -244,10 +242,10 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = builder.CreateURem(lhs128, rhs128); - auto res256 = builder.CreateZExt(res128, Type::i256); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateURem(lhs128, rhs128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); stack.push(res256); break; } @@ -256,10 +254,10 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs256 = stack.pop(); auto rhs256 = stack.pop(); - auto lhs128 = builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = builder.CreateSRem(lhs128, rhs128); - auto res256 = builder.CreateSExt(res128, Type::i256); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateSRem(lhs128, rhs128); + auto res256 = m_builder.CreateSExt(res128, Type::i256); stack.push(res256); break; } @@ -277,7 +275,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto top = stack.pop(); auto zero = Constant::get(0); - auto res = builder.CreateSub(zero, top); + auto res = m_builder.CreateSub(zero, top); stack.push(res); break; } @@ -286,8 +284,8 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res1 = builder.CreateICmpULT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Type::i256); + auto res1 = m_builder.CreateICmpULT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -296,8 +294,8 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res1 = builder.CreateICmpUGT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Type::i256); + auto res1 = m_builder.CreateICmpUGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -306,8 +304,8 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res1 = builder.CreateICmpSLT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Type::i256); + auto res1 = m_builder.CreateICmpSLT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -316,8 +314,8 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res1 = builder.CreateICmpSGT(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Type::i256); + auto res1 = m_builder.CreateICmpSGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -326,8 +324,8 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res1 = builder.CreateICmpEQ(lhs, rhs); - auto res256 = builder.CreateZExt(res1, Type::i256); + auto res1 = m_builder.CreateICmpEQ(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); stack.push(res256); break; } @@ -335,9 +333,8 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) case Instruction::NOT: { auto top = stack.pop(); - auto zero = Constant::get(0); - auto iszero = builder.CreateICmpEQ(top, zero, "iszero"); - auto result = builder.CreateZExt(iszero, Type::i256); + auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); + auto result = m_builder.CreateZExt(iszero, Type::i256); stack.push(result); break; } @@ -346,7 +343,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = builder.CreateAnd(lhs, rhs); + auto res = m_builder.CreateAnd(lhs, rhs); stack.push(res); break; } @@ -355,7 +352,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = builder.CreateOr(lhs, rhs); + auto res = m_builder.CreateOr(lhs, rhs); stack.push(res); break; } @@ -364,7 +361,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = builder.CreateXor(lhs, rhs); + auto res = m_builder.CreateXor(lhs, rhs); stack.push(res); break; } @@ -386,12 +383,12 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 - auto shbits = builder.CreateShl(byteNum, Constant::get(3)); - value = builder.CreateShl(value, shbits); - value = builder.CreateLShr(value, Constant::get(31 * 8)); + auto shbits = m_builder.CreateShl(byteNum, Constant::get(3)); + value = m_builder.CreateShl(value, shbits); + value = m_builder.CreateLShr(value, Constant::get(31 * 8)); - auto byteNumValid = builder.CreateICmpULT(byteNum, Constant::get(32)); - value = builder.CreateSelect(byteNumValid, value, Constant::get(0)); + auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); + value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); stack.push(value); break; @@ -401,13 +398,13 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto val1 = stack.pop(); auto val2 = stack.pop(); - auto sum = builder.CreateAdd(val1, val2); + auto sum = m_builder.CreateAdd(val1, val2); auto mod = stack.pop(); - auto sum128 = builder.CreateTrunc(sum, Type::lowPrecision); - auto mod128 = builder.CreateTrunc(mod, Type::lowPrecision); - auto res128 = builder.CreateURem(sum128, mod128); - auto res256 = builder.CreateZExt(res128, Type::i256); + auto sum128 = m_builder.CreateTrunc(sum, Type::lowPrecision); + auto mod128 = m_builder.CreateTrunc(mod, Type::lowPrecision); + auto res128 = m_builder.CreateURem(sum128, mod128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); stack.push(res256); break; } @@ -416,13 +413,13 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) { auto val1 = stack.pop(); auto val2 = stack.pop(); - auto prod = builder.CreateMul(val1, val2); + auto prod = m_builder.CreateMul(val1, val2); auto mod = stack.pop(); - auto prod128 = builder.CreateTrunc(prod, Type::lowPrecision); - auto mod128 = builder.CreateTrunc(mod, Type::lowPrecision); - auto res128 = builder.CreateURem(prod128, mod128); - auto res256 = builder.CreateZExt(res128, Type::i256); + auto prod128 = m_builder.CreateTrunc(prod, Type::lowPrecision); + auto mod128 = m_builder.CreateTrunc(mod, Type::lowPrecision); + auto res128 = m_builder.CreateURem(prod128, mod128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); stack.push(res256); break; } @@ -452,7 +449,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) value <<= 8; value |= bytecode[currentPC]; } - auto c = builder.getInt(value); + auto c = m_builder.getInt(value); stack.push(c); break; } @@ -543,13 +540,13 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) // The target address is computed at compile time, // just pop it without looking... stack.pop(); - builder.CreateBr(targetBlock->llvm()); + m_builder.CreateBr(targetBlock->llvm()); } else { // FIXME: this get(0) is a temporary workaround to get some of the jump tests running. stack.get(0); - builder.CreateBr(m_jumpTableBlock->llvm()); + m_builder.CreateBr(m_jumpTableBlock->llvm()); } } else // JUMPI @@ -557,7 +554,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) stack.swap(1); auto val = stack.pop(); auto zero = Constant::get(0); - auto cond = builder.CreateICmpNE(val, zero, "nonzero"); + auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); // Assume the basic blocks are properly ordered: auto nextBBIter = basicBlockPairIt; @@ -568,11 +565,11 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) if (targetBlock) { stack.pop(); - builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm()); + m_builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm()); } else { - builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), followBlock.llvm()); + m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), followBlock.llvm()); } } @@ -780,10 +777,10 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) gasMeter.commitCostBlock(gas); // Require memory for the max of in and out buffers - auto inSizeReq = builder.CreateAdd(inOff, inSize, "inSizeReq"); - auto outSizeReq = builder.CreateAdd(outOff, outSize, "outSizeReq"); - auto cmp = builder.CreateICmpUGT(inSizeReq, outSizeReq); - auto sizeReq = builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); + auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); + auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); + auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); + auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); memory.require(sizeReq); auto receiveAddress = codeAddress; @@ -803,7 +800,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) memory.registerReturnData(index, size); - builder.CreateRet(Constant::get(ReturnCode::Return)); + m_builder.CreateRet(Constant::get(ReturnCode::Return)); break; } @@ -815,7 +812,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) } case Instruction::STOP: { - builder.CreateRet(Constant::get(ReturnCode::Stop)); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); break; } @@ -824,12 +821,12 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) gasMeter.commitCostBlock(); - if (!builder.GetInsertBlock()->getTerminator()) // If block not terminated + if (!m_builder.GetInsertBlock()->getTerminator()) // If block not terminated { if (basicBlock.end() == bytecode.size()) { // Return STOP code - builder.CreateRet(Constant::get(ReturnCode::Stop)); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); } else { @@ -837,7 +834,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) auto iterCopy = basicBlockPairIt; ++iterCopy; auto& next = iterCopy->second; - builder.CreateBr(next); + m_builder.CreateBr(next); } } } @@ -846,19 +843,19 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) // TODO: move to separate function. // Note: Right now the codegen for special blocks depends only on createBasicBlock(), // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). - builder.SetInsertPoint(m_stopBB); - builder.CreateRet(Constant::get(ReturnCode::Stop)); + m_builder.SetInsertPoint(m_stopBB); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - builder.SetInsertPoint(m_badJumpBlock->llvm()); - builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); - builder.SetInsertPoint(m_jumpTableBlock->llvm()); + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) { auto& stack = m_jumpTableBlock->getStack(); auto dest = stack.pop(); - auto switchInstr = builder.CreateSwitch(dest, m_badJumpBlock->llvm(), + auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), m_indirectJumpTargets.size()); for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) { @@ -869,7 +866,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) } else { - builder.CreateBr(m_badJumpBlock->llvm()); + m_builder.CreateBr(m_badJumpBlock->llvm()); } linkBasicBlocks(); diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 44eeebae4..1aa54fa18 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -1,7 +1,7 @@ #pragma once -#include +#include #include @@ -30,6 +30,8 @@ private: void linkBasicBlocks(); + llvm::IRBuilder<> m_builder; + /** * Maps a program counter pc to a basic block that starts at pc (if any). */ From 1367f89b84090361faca05768d2257e7a5072e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 19:27:42 +0200 Subject: [PATCH 134/396] Basic block compilation in separated function --- evmcc/Compiler.cpp | 1200 ++++++++++++++++++++++---------------------- evmcc/Compiler.h | 2 + 2 files changed, 604 insertions(+), 598 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 71ad61493..d5d4e6816 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -172,706 +172,710 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) { auto& basicBlock = basicBlockPairIt->second; - auto& stack = basicBlock.getStack(); - m_builder.SetInsertPoint(basicBlock); + auto iterCopy = basicBlockPairIt; + ++iterCopy; + auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; + compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock); + } + + // Code for special blocks: + // TODO: move to separate function. + // Note: Right now the codegen for special blocks depends only on createBasicBlock(), + // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). + m_builder.SetInsertPoint(m_stopBB); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + if (m_indirectJumpTargets.size() > 0) + { + auto& stack = m_jumpTableBlock->getStack(); + + auto dest = stack.pop(); + auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), + m_indirectJumpTargets.size()); + for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) { - auto inst = static_cast(bytecode[currentPC]); + auto& bb = *it; + auto dest = Constant::get(bb->begin()); + switchInstr->addCase(dest, bb->llvm()); + } + } + else + { + m_builder.CreateBr(m_badJumpBlock->llvm()); + } - gasMeter.count(inst); + linkBasicBlocks(); - switch (inst) - { + return module; +} - case Instruction::ADD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateAdd(lhs, rhs); - stack.push(result); - break; - } - case Instruction::SUB: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateSub(lhs, rhs); - stack.push(result); - break; - } +void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) +{ + auto& stack = basicBlock.getStack(); + m_builder.SetInsertPoint(basicBlock.llvm()); - case Instruction::MUL: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateMul(lhs128, rhs128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); - break; - } + for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) + { + auto inst = static_cast(bytecode[currentPC]); - case Instruction::DIV: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateUDiv(lhs128, rhs128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); - break; - } + gasMeter.count(inst); - case Instruction::SDIV: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateSDiv(lhs128, rhs128); - auto res256 = m_builder.CreateSExt(res128, Type::i256); - stack.push(res256); - break; - } + switch (inst) + { - case Instruction::MOD: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateURem(lhs128, rhs128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); - break; - } + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } - case Instruction::SMOD: - { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateSRem(lhs128, rhs128); - auto res256 = m_builder.CreateSExt(res128, Type::i256); - stack.push(res256); - break; - } + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } - case Instruction::EXP: - { - auto left = stack.pop(); - auto right = stack.pop(); - auto ret = ext.exp(left, right); - stack.push(ret); - break; - } + case Instruction::MUL: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateMul(lhs128, rhs128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); + stack.push(res256); + break; + } - case Instruction::NEG: - { - auto top = stack.pop(); - auto zero = Constant::get(0); - auto res = m_builder.CreateSub(zero, top); - stack.push(res); - break; - } + case Instruction::DIV: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateUDiv(lhs128, rhs128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); + stack.push(res256); + break; + } - case Instruction::LT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpULT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } + case Instruction::SDIV: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateSDiv(lhs128, rhs128); + auto res256 = m_builder.CreateSExt(res128, Type::i256); + stack.push(res256); + break; + } - case Instruction::GT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpUGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } + case Instruction::MOD: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateURem(lhs128, rhs128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); + stack.push(res256); + break; + } - case Instruction::SLT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSLT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } + case Instruction::SMOD: + { + auto lhs256 = stack.pop(); + auto rhs256 = stack.pop(); + auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); + auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); + auto res128 = m_builder.CreateSRem(lhs128, rhs128); + auto res256 = m_builder.CreateSExt(res128, Type::i256); + stack.push(res256); + break; + } - case Instruction::SGT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } + case Instruction::EXP: + { + auto left = stack.pop(); + auto right = stack.pop(); + auto ret = ext.exp(left, right); + stack.push(ret); + break; + } - case Instruction::EQ: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpEQ(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } + case Instruction::NEG: + { + auto top = stack.pop(); + auto zero = Constant::get(0); + auto res = m_builder.CreateSub(zero, top); + stack.push(res); + break; + } - case Instruction::NOT: - { - auto top = stack.pop(); - auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); - auto result = m_builder.CreateZExt(iszero, Type::i256); - stack.push(result); - break; - } + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpULT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } - case Instruction::AND: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateAnd(lhs, rhs); - stack.push(res); - break; - } + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpUGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } - case Instruction::OR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateOr(lhs, rhs); - stack.push(res); - break; - } + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSLT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } - case Instruction::XOR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateXor(lhs, rhs); - stack.push(res); - break; - } + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } - case Instruction::BYTE: - { - const auto byteNum = stack.pop(); - auto value = stack.pop(); + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpEQ(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } - /* - if (byteNum < 32) - use select - { - value <<= byteNum*8 - value >>= 31*8 - push value - } - else push 0 - */ + case Instruction::NOT: + { + auto top = stack.pop(); + auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); + auto result = m_builder.CreateZExt(iszero, Type::i256); + stack.push(result); + break; + } - // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } - auto shbits = m_builder.CreateShl(byteNum, Constant::get(3)); - value = m_builder.CreateShl(value, shbits); - value = m_builder.CreateLShr(value, Constant::get(31 * 8)); + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } - auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); - value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); - stack.push(value); + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } - break; - } + case Instruction::BYTE: + { + const auto byteNum = stack.pop(); + auto value = stack.pop(); - case Instruction::ADDMOD: + /* + if (byteNum < 32) - use select { - auto val1 = stack.pop(); - auto val2 = stack.pop(); - auto sum = m_builder.CreateAdd(val1, val2); - auto mod = stack.pop(); - - auto sum128 = m_builder.CreateTrunc(sum, Type::lowPrecision); - auto mod128 = m_builder.CreateTrunc(mod, Type::lowPrecision); - auto res128 = m_builder.CreateURem(sum128, mod128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); - break; + value <<= byteNum*8 + value >>= 31*8 + push value } + else push 0 + */ - case Instruction::MULMOD: - { - auto val1 = stack.pop(); - auto val2 = stack.pop(); - auto prod = m_builder.CreateMul(val1, val2); - auto mod = stack.pop(); - - auto prod128 = m_builder.CreateTrunc(prod, Type::lowPrecision); - auto mod128 = m_builder.CreateTrunc(mod, Type::lowPrecision); - auto res128 = m_builder.CreateURem(prod128, mod128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); - break; - } + // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 - case Instruction::SHA3: - { - auto inOff = stack.pop(); - auto inSize = stack.pop(); - memory.require(inOff, inSize); - auto hash = ext.sha3(inOff, inSize); - stack.push(hash); - } + auto shbits = m_builder.CreateShl(byteNum, Constant::get(3)); + value = m_builder.CreateShl(value, shbits); + value = m_builder.CreateLShr(value, Constant::get(31 * 8)); - case Instruction::POP: - { - stack.pop(); - break; - } + auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); + value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); + stack.push(value); - case Instruction::ANY_PUSH: - { - auto numBytes = static_cast(inst)-static_cast(Instruction::PUSH1) + 1; - auto value = llvm::APInt(256, 0); - for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator - { - ++currentPC; - value <<= 8; - value |= bytecode[currentPC]; - } - auto c = m_builder.getInt(value); - stack.push(c); - break; - } + break; + } - case Instruction::ANY_DUP: - { - auto index = static_cast(inst)-static_cast(Instruction::DUP1); - stack.dup(index); - break; - } + case Instruction::ADDMOD: + { + auto val1 = stack.pop(); + auto val2 = stack.pop(); + auto sum = m_builder.CreateAdd(val1, val2); + auto mod = stack.pop(); + + auto sum128 = m_builder.CreateTrunc(sum, Type::lowPrecision); + auto mod128 = m_builder.CreateTrunc(mod, Type::lowPrecision); + auto res128 = m_builder.CreateURem(sum128, mod128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); + stack.push(res256); + break; + } - case Instruction::ANY_SWAP: - { - auto index = static_cast(inst)-static_cast(Instruction::SWAP1) + 1; - stack.swap(index); - break; - } + case Instruction::MULMOD: + { + auto val1 = stack.pop(); + auto val2 = stack.pop(); + auto prod = m_builder.CreateMul(val1, val2); + auto mod = stack.pop(); + + auto prod128 = m_builder.CreateTrunc(prod, Type::lowPrecision); + auto mod128 = m_builder.CreateTrunc(mod, Type::lowPrecision); + auto res128 = m_builder.CreateURem(prod128, mod128); + auto res256 = m_builder.CreateZExt(res128, Type::i256); + stack.push(res256); + break; + } - case Instruction::MLOAD: - { - auto addr = stack.pop(); - auto word = memory.loadWord(addr); - stack.push(word); - break; - } + case Instruction::SHA3: + { + auto inOff = stack.pop(); + auto inSize = stack.pop(); + memory.require(inOff, inSize); + auto hash = ext.sha3(inOff, inSize); + stack.push(hash); + } - case Instruction::MSTORE: - { - auto addr = stack.pop(); - auto word = stack.pop(); - memory.storeWord(addr, word); - break; - } + case Instruction::POP: + { + stack.pop(); + break; + } - case Instruction::MSTORE8: + case Instruction::ANY_PUSH: + { + auto numBytes = static_cast(inst)-static_cast(Instruction::PUSH1) + 1; + auto value = llvm::APInt(256, 0); + for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator { - auto addr = stack.pop(); - auto word = stack.pop(); - memory.storeByte(addr, word); - break; + ++currentPC; + value <<= 8; + value |= bytecode[currentPC]; } + auto c = m_builder.getInt(value); + stack.push(c); + break; + } - case Instruction::MSIZE: - { - auto word = memory.getSize(); - stack.push(word); - break; - } + case Instruction::ANY_DUP: + { + auto index = static_cast(inst)-static_cast(Instruction::DUP1); + stack.dup(index); + break; + } - case Instruction::SLOAD: - { - auto index = stack.pop(); - auto value = ext.store(index); - stack.push(value); - break; - } + case Instruction::ANY_SWAP: + { + auto index = static_cast(inst)-static_cast(Instruction::SWAP1) + 1; + stack.swap(index); + break; + } - case Instruction::SSTORE: - { - auto index = stack.pop(); - auto value = stack.pop(); - gasMeter.countSStore(ext, index, value); - ext.setStore(index, value); - break; - } + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = memory.loadWord(addr); + stack.push(word); + break; + } - case Instruction::JUMP: - case Instruction::JUMPI: - { - // Generate direct jump iff: - // 1. this is not the first instruction in the block - // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) - // Otherwise generate a indirect jump (a switch). - BasicBlock* targetBlock = nullptr; - if (currentPC != basicBlock.begin()) - { - auto pairIter = m_directJumpTargets.find(currentPC); - if (pairIter != m_directJumpTargets.end()) - { - targetBlock = pairIter->second; - } - } + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeWord(addr, word); + break; + } - if (inst == Instruction::JUMP) - { - if (targetBlock) - { - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); - m_builder.CreateBr(targetBlock->llvm()); - } - else - { - // FIXME: this get(0) is a temporary workaround to get some of the jump tests running. - stack.get(0); - m_builder.CreateBr(m_jumpTableBlock->llvm()); - } - } - else // JUMPI - { - stack.swap(1); - auto val = stack.pop(); - auto zero = Constant::get(0); - auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - - // Assume the basic blocks are properly ordered: - auto nextBBIter = basicBlockPairIt; - ++nextBBIter; - assert (nextBBIter != basicBlocks.end()); - auto& followBlock = nextBBIter->second; - - if (targetBlock) - { - stack.pop(); - m_builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm()); - } - else - { - m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), followBlock.llvm()); - } - } + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeByte(addr, word); + break; + } - break; - } + case Instruction::MSIZE: + { + auto word = memory.getSize(); + stack.push(word); + break; + } - case Instruction::JUMPDEST: - { - // Extra asserts just in case. - assert(currentPC == basicBlock.begin()); - break; - } + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = ext.store(index); + stack.push(value); + break; + } - case Instruction::PC: - { - auto value = Constant::get(currentPC); - stack.push(value); - break; - } + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + gasMeter.countSStore(ext, index, value); + ext.setStore(index, value); + break; + } - case Instruction::GAS: - { - stack.push(gasMeter.getGas()); - break; + case Instruction::JUMP: + case Instruction::JUMPI: + { + // Generate direct jump iff: + // 1. this is not the first instruction in the block + // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) + // Otherwise generate a indirect jump (a switch). + BasicBlock* targetBlock = nullptr; + if (currentPC != basicBlock.begin()) + { + auto pairIter = m_directJumpTargets.find(currentPC); + if (pairIter != m_directJumpTargets.end()) + { + targetBlock = pairIter->second; + } } - case Instruction::ADDRESS: + if (inst == Instruction::JUMP) { - auto value = ext.address(); - stack.push(value); - break; + if (targetBlock) + { + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + m_builder.CreateBr(targetBlock->llvm()); + } + else + { + // FIXME: this get(0) is a temporary workaround to get some of the jump tests running. + stack.get(0); + m_builder.CreateBr(m_jumpTableBlock->llvm()); + } } - - case Instruction::BALANCE: + else // JUMPI { - auto address = stack.pop(); - auto value = ext.balance(address); - stack.push(value); - break; - } + stack.swap(1); + auto val = stack.pop(); + auto zero = Constant::get(0); + auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - case Instruction::CALLER: - { - auto value = ext.caller(); - stack.push(value); - break; - } + // Assume the basic blocks are properly ordered: + assert(nextBasicBlock); // FIXME: JUMPI can be last instruction - case Instruction::ORIGIN: - { - auto value = ext.origin(); - stack.push(value); - break; + if (targetBlock) + { + stack.pop(); + m_builder.CreateCondBr(cond, targetBlock->llvm(), nextBasicBlock); + } + else + { + m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); + } } - case Instruction::CALLVALUE: - { - auto value = ext.callvalue(); - stack.push(value); - break; - } + break; + } - case Instruction::CALLDATASIZE: - { - auto value = ext.calldatasize(); - stack.push(value); - break; - } + case Instruction::JUMPDEST: + { + // Extra asserts just in case. + assert(currentPC == basicBlock.begin()); + break; + } - case Instruction::CODESIZE: - { - auto value = ext.codesize(); - stack.push(value); - break; - } + case Instruction::PC: + { + auto value = Constant::get(currentPC); + stack.push(value); + break; + } - case Instruction::EXTCODESIZE: - { - auto addr = stack.pop(); - auto value = ext.codesizeAt(addr); - stack.push(value); - break; - } + case Instruction::GAS: + { + stack.push(gasMeter.getGas()); + break; + } - case Instruction::CALLDATACOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); + case Instruction::ADDRESS: + { + auto value = ext.address(); + stack.push(value); + break; + } - auto srcPtr = ext.calldata(); - auto srcSize = ext.calldatasize(); + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = ext.balance(address); + stack.push(value); + break; + } - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } + case Instruction::CALLER: + { + auto value = ext.caller(); + stack.push(value); + break; + } - case Instruction::CODECOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); + case Instruction::ORIGIN: + { + auto value = ext.origin(); + stack.push(value); + break; + } - auto srcPtr = ext.code(); - auto srcSize = ext.codesize(); + case Instruction::CALLVALUE: + { + auto value = ext.callvalue(); + stack.push(value); + break; + } - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } + case Instruction::CALLDATASIZE: + { + auto value = ext.calldatasize(); + stack.push(value); + break; + } - case Instruction::EXTCODECOPY: - { - auto extAddr = stack.pop(); - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); + case Instruction::CODESIZE: + { + auto value = ext.codesize(); + stack.push(value); + break; + } - auto srcPtr = ext.codeAt(extAddr); - auto srcSize = ext.codesizeAt(extAddr); + case Instruction::EXTCODESIZE: + { + auto addr = stack.pop(); + auto value = ext.codesizeAt(addr); + stack.push(value); + break; + } - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } + case Instruction::CALLDATACOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); - case Instruction::CALLDATALOAD: - { - auto index = stack.pop(); - auto value = ext.calldataload(index); - stack.push(value); - break; - } + auto srcPtr = ext.calldata(); + auto srcSize = ext.calldatasize(); - case Instruction::GASPRICE: - { - auto value = ext.gasprice(); - stack.push(value); - break; - } + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } - case Instruction::PREVHASH: - { - auto value = ext.prevhash(); - stack.push(value); - break; - } + case Instruction::CODECOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); - case Instruction::COINBASE: - { - auto value = ext.coinbase(); - stack.push(value); - break; - } + auto srcPtr = ext.code(); + auto srcSize = ext.codesize(); - case Instruction::TIMESTAMP: - { - auto value = ext.timestamp(); - stack.push(value); - break; - } + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } - case Instruction::NUMBER: - { - auto value = ext.number(); - stack.push(value); - break; - } + case Instruction::EXTCODECOPY: + { + auto extAddr = stack.pop(); + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); - case Instruction::DIFFICULTY: - { - auto value = ext.difficulty(); - stack.push(value); - break; - } + auto srcPtr = ext.codeAt(extAddr); + auto srcSize = ext.codesizeAt(extAddr); - case Instruction::GASLIMIT: - { - auto value = ext.gaslimit(); - stack.push(value); - break; - } + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } - case Instruction::CREATE: - { - auto endowment = stack.pop(); - auto initOff = stack.pop(); - auto initSize = stack.pop(); - memory.require(initOff, initSize); + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = ext.calldataload(index); + stack.push(value); + break; + } - auto address = ext.create(endowment, initOff, initSize); - stack.push(address); - break; - } + case Instruction::GASPRICE: + { + auto value = ext.gasprice(); + stack.push(value); + break; + } - case Instruction::CALL: - case Instruction::CALLCODE: - { - auto gas = stack.pop(); - auto codeAddress = stack.pop(); - auto value = stack.pop(); - auto inOff = stack.pop(); - auto inSize = stack.pop(); - auto outOff = stack.pop(); - auto outSize = stack.pop(); - - gasMeter.commitCostBlock(gas); - - // Require memory for the max of in and out buffers - auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); - auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); - auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); - auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); - memory.require(sizeReq); - - auto receiveAddress = codeAddress; - if (inst == Instruction::CALLCODE) - receiveAddress = ext.address(); - - auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - gasMeter.giveBack(gas); - stack.push(ret); - break; - } + case Instruction::PREVHASH: + { + auto value = ext.prevhash(); + stack.push(value); + break; + } - case Instruction::RETURN: - { - auto index = stack.pop(); - auto size = stack.pop(); + case Instruction::COINBASE: + { + auto value = ext.coinbase(); + stack.push(value); + break; + } - memory.registerReturnData(index, size); + case Instruction::TIMESTAMP: + { + auto value = ext.timestamp(); + stack.push(value); + break; + } - m_builder.CreateRet(Constant::get(ReturnCode::Return)); - break; - } + case Instruction::NUMBER: + { + auto value = ext.number(); + stack.push(value); + break; + } - case Instruction::SUICIDE: - { - auto address = stack.pop(); - ext.suicide(address); - // Fall through - } - case Instruction::STOP: - { - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - break; - } + case Instruction::DIFFICULTY: + { + auto value = ext.difficulty(); + stack.push(value); + break; + } - } + case Instruction::GASLIMIT: + { + auto value = ext.gaslimit(); + stack.push(value); + break; } - gasMeter.commitCostBlock(); + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); + memory.require(initOff, initSize); + + auto address = ext.create(endowment, initOff, initSize); + stack.push(address); + break; + } - if (!m_builder.GetInsertBlock()->getTerminator()) // If block not terminated + case Instruction::CALL: + case Instruction::CALLCODE: { - if (basicBlock.end() == bytecode.size()) - { - // Return STOP code - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - } - else - { - // Branch to the next block. - auto iterCopy = basicBlockPairIt; - ++iterCopy; - auto& next = iterCopy->second; - m_builder.CreateBr(next); - } + auto gas = stack.pop(); + auto codeAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + gasMeter.commitCostBlock(gas); + + // Require memory for the max of in and out buffers + auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); + auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); + auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); + auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); + memory.require(sizeReq); + + auto receiveAddress = codeAddress; + if (inst == Instruction::CALLCODE) + receiveAddress = ext.address(); + + auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + gasMeter.giveBack(gas); + stack.push(ret); + break; } - } - // Code for special blocks: - // TODO: move to separate function. - // Note: Right now the codegen for special blocks depends only on createBasicBlock(), - // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). - m_builder.SetInsertPoint(m_stopBB); - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); - m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + memory.registerReturnData(index, size); - m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - if (m_indirectJumpTargets.size() > 0) - { - auto& stack = m_jumpTableBlock->getStack(); + m_builder.CreateRet(Constant::get(ReturnCode::Return)); + break; + } - auto dest = stack.pop(); - auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), - m_indirectJumpTargets.size()); - for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) + case Instruction::SUICIDE: { - auto& bb = *it; - auto dest = Constant::get(bb->begin()); - switchInstr->addCase(dest, bb->llvm()); + auto address = stack.pop(); + ext.suicide(address); + // Fall through + } + case Instruction::STOP: + { + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + break; + } + } - } - else - { - m_builder.CreateBr(m_badJumpBlock->llvm()); } - linkBasicBlocks(); + gasMeter.commitCostBlock(); - return module; + if (!m_builder.GetInsertBlock()->getTerminator()) // If block not terminated + { + if (basicBlock.end() == bytecode.size()) + { + // Return STOP code + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + } + else + { + // Branch to the next block. + assert(nextBasicBlock); + m_builder.CreateBr(nextBasicBlock); + } + } } diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 1aa54fa18..1a0e61ca1 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -28,6 +28,8 @@ private: void createBasicBlocks(const bytes& bytecode); + void compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); + void linkBasicBlocks(); llvm::IRBuilder<> m_builder; From 837f17cea46f338ccafad43ada409e8586795db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 19:34:55 +0200 Subject: [PATCH 135/396] Cleanup block terminator generation --- evmcc/Compiler.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index d5d4e6816..77db366cf 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -862,19 +862,12 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, gasMeter.commitCostBlock(); - if (!m_builder.GetInsertBlock()->getTerminator()) // If block not terminated + if (!basicBlock.llvm()->getTerminator()) // If block not terminated { - if (basicBlock.end() == bytecode.size()) - { - // Return STOP code - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - } + if (nextBasicBlock) + m_builder.CreateBr(nextBasicBlock); // Branch to the next block else - { - // Branch to the next block. - assert(nextBasicBlock); - m_builder.CreateBr(nextBasicBlock); - } + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code } } From 83642fe9ded7d389b8e10607d0f3fa69423d8a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 13:05:51 +0200 Subject: [PATCH 136/396] Introducing CompilerHelper - a base class for... compiler helper classes like Memory, GasMeter, etc. --- evmcc/Compiler.cpp | 2 +- evmcc/CompilerHelper.cpp | 13 +++++++++++++ evmcc/CompilerHelper.h | 34 ++++++++++++++++++++++++++++++++++ evmcc/Ext.cpp | 4 ++-- evmcc/Ext.h | 9 +++------ evmcc/GasMeter.cpp | 2 +- evmcc/GasMeter.h | 11 ++++------- evmcc/Memory.cpp | 2 +- evmcc/Memory.h | 14 ++++---------- windows/evmcc.vcxproj | 6 +++++- windows/evmcc.vcxproj.filters | 2 ++ 11 files changed, 70 insertions(+), 29 deletions(-) create mode 100644 evmcc/CompilerHelper.cpp create mode 100644 evmcc/CompilerHelper.h diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 77db366cf..f48534959 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -714,7 +714,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto srcPtr = ext.code(); + auto srcPtr = ext.code(); // TODO: Code & its size are constants, feature #80814234 auto srcSize = ext.codesize(); memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); diff --git a/evmcc/CompilerHelper.cpp b/evmcc/CompilerHelper.cpp new file mode 100644 index 000000000..a657a443a --- /dev/null +++ b/evmcc/CompilerHelper.cpp @@ -0,0 +1,13 @@ + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +} +} +} diff --git a/evmcc/CompilerHelper.h b/evmcc/CompilerHelper.h new file mode 100644 index 000000000..39cbc7c0d --- /dev/null +++ b/evmcc/CompilerHelper.h @@ -0,0 +1,34 @@ + +#pragma once + +#include + + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class CompilerHelper +{ +protected: + CompilerHelper(llvm::IRBuilder<>& _builder, llvm::Module* _module): + m_builder(_builder), + m_module(_module) + {} + + CompilerHelper(const CompilerHelper&) = delete; + void operator=(CompilerHelper) = delete; + + /// Reference to parent compiler IR builder + llvm::IRBuilder<>& m_builder; + + /// Reference to the IR module being compiled + llvm::Module* m_module; +}; + +} +} +} diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index a300b586c..43b5e9186 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -43,8 +43,8 @@ struct ExtData const byte* code; }; -Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) - : m_builder(_builder) +Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module): + CompilerHelper(_builder, module) { auto&& ctx = _builder.getContext(); diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 227632291..755c8bd16 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -1,10 +1,10 @@ #pragma once -#include - #include +#include "CompilerHelper.h" + namespace dev { namespace eth @@ -12,11 +12,10 @@ namespace eth namespace jit { -class Ext +class Ext : public CompilerHelper { public: Ext(llvm::IRBuilder<>& _builder, llvm::Module* module); - static void init(std::unique_ptr _ext); llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); @@ -54,8 +53,6 @@ private: llvm::Value* bswap(llvm::Value*); private: - llvm::IRBuilder<>& m_builder; - llvm::Value* m_args[2]; llvm::Value* m_arg2; llvm::Value* m_arg3; diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index f57f2b2c8..ef3665bb4 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -81,7 +81,7 @@ bool isCostBlockEnd(Instruction _inst) } GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module) : - m_builder(_builder) + CompilerHelper(_builder, _module) { m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); m_gas->setUnnamedAddr(true); // Address is not important diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 88c952acd..cea4a2b44 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -1,10 +1,10 @@ #pragma once -#include - #include +#include "CompilerHelper.h" + namespace dev { namespace eth @@ -12,14 +12,11 @@ namespace eth namespace jit { -class GasMeter +class GasMeter : public CompilerHelper { public: GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module); - GasMeter(const GasMeter&) = delete; - void operator=(GasMeter) = delete; - /// Count step cost of instruction void count(Instruction _inst); @@ -42,7 +39,7 @@ private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow uint64_t m_blockCost = 0; - llvm::IRBuilder<>& m_builder; + llvm::CallInst* m_checkCall = nullptr; llvm::GlobalVariable* m_gas; llvm::Function* m_gasCheckFunc; diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 7c742eb81..a000816e7 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -23,7 +23,7 @@ namespace jit { Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter): - m_builder(_builder) + CompilerHelper(_builder, _module) { auto i64Ty = m_builder.getInt64Ty(); llvm::Type* argTypes[] = {i64Ty, i64Ty}; diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 24ed81a0c..3d2db56ee 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -1,9 +1,9 @@ #pragma once -#include - #include +#include "CompilerHelper.h" + namespace dev { namespace eth @@ -11,14 +11,10 @@ namespace eth namespace jit { -class GasMeter; - -class Memory +class Memory : public CompilerHelper { public: - Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter); - Memory(const Memory&) = delete; - void operator=(Memory) = delete; + Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, class GasMeter& _gasMeter); llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); @@ -44,8 +40,6 @@ private: llvm::Function* createRequireFunc(llvm::Module* _module, GasMeter& _gasMeter); private: - llvm::IRBuilder<>& m_builder; - llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index dbd9d1b57..efa7a6f20 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -21,6 +21,7 @@ + @@ -33,6 +34,7 @@ + @@ -123,8 +125,9 @@ Disabled WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true - ../ + ../../llvm-3.5.0/include;../../builds/llvm3.5/include;%(AdditionalIncludeDirectories) false + false Console @@ -144,6 +147,7 @@ ../../llvm-3.5.0/include;../../builds/llvm3.5/include;%(AdditionalIncludeDirectories) 4068;4244;4267;4800 false + false Console diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index f84ec6ca3..adfcfaf60 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -11,6 +11,7 @@ + @@ -22,5 +23,6 @@ + \ No newline at end of file From cbab6546789823ab552d9fb0eaa7970dc447b827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 13:16:18 +0200 Subject: [PATCH 137/396] Get IR module from IR builder --- evmcc/Compiler.cpp | 6 +++--- evmcc/CompilerHelper.cpp | 7 +++++++ evmcc/CompilerHelper.h | 5 +---- evmcc/Ext.cpp | 5 +++-- evmcc/Ext.h | 2 +- evmcc/GasMeter.cpp | 12 ++++++------ evmcc/GasMeter.h | 2 +- evmcc/Memory.cpp | 24 ++++++++++++------------ evmcc/Memory.h | 2 +- 9 files changed, 35 insertions(+), 30 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index f48534959..bbd5cf90b 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -163,9 +163,9 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) createBasicBlocks(bytecode); // Init runtime structures. - GasMeter gasMeter(m_builder, module.get()); - Memory memory(m_builder, module.get(), gasMeter); - Ext ext(m_builder, module.get()); + GasMeter gasMeter(m_builder); + Memory memory(m_builder, gasMeter); + Ext ext(m_builder); m_builder.CreateBr(basicBlocks.begin()->second); diff --git a/evmcc/CompilerHelper.cpp b/evmcc/CompilerHelper.cpp index a657a443a..7b29690b7 100644 --- a/evmcc/CompilerHelper.cpp +++ b/evmcc/CompilerHelper.cpp @@ -1,6 +1,8 @@ #include "CompilerHelper.h" +#include + namespace dev { namespace eth @@ -8,6 +10,11 @@ namespace eth namespace jit { +CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_module(_builder.GetInsertBlock()->getParent()->getParent()) +{} + } } } diff --git a/evmcc/CompilerHelper.h b/evmcc/CompilerHelper.h index 39cbc7c0d..e10937277 100644 --- a/evmcc/CompilerHelper.h +++ b/evmcc/CompilerHelper.h @@ -14,10 +14,7 @@ namespace jit class CompilerHelper { protected: - CompilerHelper(llvm::IRBuilder<>& _builder, llvm::Module* _module): - m_builder(_builder), - m_module(_module) - {} + CompilerHelper(llvm::IRBuilder<>& _builder); CompilerHelper(const CompilerHelper&) = delete; void operator=(CompilerHelper) = delete; diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 43b5e9186..f3f7699cd 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -43,10 +43,11 @@ struct ExtData const byte* code; }; -Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module): - CompilerHelper(_builder, module) +Ext::Ext(llvm::IRBuilder<>& _builder): + CompilerHelper(_builder) { auto&& ctx = _builder.getContext(); + auto module = m_module; auto i256Ty = m_builder.getIntNTy(256); auto i256PtrTy = i256Ty->getPointerTo(); diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 755c8bd16..04c17fdac 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -15,7 +15,7 @@ namespace jit class Ext : public CompilerHelper { public: - Ext(llvm::IRBuilder<>& _builder, llvm::Module* module); + Ext(llvm::IRBuilder<>& _builder); llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index ef3665bb4..206e5c805 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -80,13 +80,13 @@ bool isCostBlockEnd(Instruction _inst) } -GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module) : - CompilerHelper(_builder, _module) +GasMeter::GasMeter(llvm::IRBuilder<>& _builder) : + CompilerHelper(_builder) { - m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); + m_gas = new llvm::GlobalVariable(*m_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); m_gas->setUnnamedAddr(true); // Address is not important - 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", m_module); InsertPointGuard guard(m_builder); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); @@ -103,9 +103,9 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module) : m_builder.SetInsertPoint(outOfGasBB); //auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); - auto extJmpBuf = new llvm::GlobalVariable(*_module, Type::BytePtr, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "rt_jmpBuf"); + auto extJmpBuf = new llvm::GlobalVariable(*m_module, Type::BytePtr, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "rt_jmpBuf"); llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; - auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", _module); + auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", m_module); m_builder.CreateCall2(longjmpNative, m_builder.CreateLoad(extJmpBuf), Constant::get(ReturnCode::OutOfGas)); m_builder.CreateUnreachable(); diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index cea4a2b44..521e7080a 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -15,7 +15,7 @@ namespace jit class GasMeter : public CompilerHelper { public: - GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module); + GasMeter(llvm::IRBuilder<>& _builder); /// Count step cost of instruction void count(Instruction _inst); diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index a000816e7..7fde48949 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -22,36 +22,36 @@ namespace eth namespace jit { -Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter): - CompilerHelper(_builder, _module) +Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter): + CompilerHelper(_builder) { auto i64Ty = m_builder.getInt64Ty(); llvm::Type* argTypes[] = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_dump", _module); + "evmccrt_memory_dump", m_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(*m_module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data"); m_data->setUnnamedAddr(true); // Address is not important - m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); + m_size = new llvm::GlobalVariable(*m_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); m_size->setUnnamedAddr(true); // Address is not important - m_returnDataOffset = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset"); + m_returnDataOffset = new llvm::GlobalVariable(*m_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset"); m_returnDataOffset->setUnnamedAddr(true); // Address is not important - m_returnDataSize = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); + m_returnDataSize = new llvm::GlobalVariable(*m_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); m_returnDataSize->setUnnamedAddr(true); // Address is not important - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); + m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", m_module); llvm::AttrBuilder attrBuilder; attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - m_require = createRequireFunc(_module, _gasMeter); - m_loadWord = createFunc(false, Type::i256, _module, _gasMeter); - m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _module, _gasMeter); + m_require = createRequireFunc(m_module, _gasMeter); + m_loadWord = createFunc(false, Type::i256, m_module, _gasMeter); + m_storeWord = createFunc(true, Type::i256, m_module, _gasMeter); + m_storeByte = createFunc(true, Type::Byte, m_module, _gasMeter); } llvm::Function* Memory::createRequireFunc(llvm::Module* _module, GasMeter& _gasMeter) diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 3d2db56ee..489c37439 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -14,7 +14,7 @@ namespace jit class Memory : public CompilerHelper { public: - Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, class GasMeter& _gasMeter); + Memory(llvm::IRBuilder<>& _builder, class GasMeter& _gasMeter); llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); From cc2809c9b6fb628a26226d1947b8a489b6b8bdc1 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 16 Oct 2014 12:22:54 +0100 Subject: [PATCH 138/396] Added dumping of CFG to a .dot file [Delivers #80816506] --- evmcc/Compiler.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++ evmcc/Compiler.h | 4 ++++ evmcc/evmcc.cpp | 18 ++++++++++++++-- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 77db366cf..a7e8ba483 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -929,6 +929,58 @@ void Compiler::linkBasicBlocks() } } +void Compiler::dumpBasicBlockGraph(std::ostream& out) +{ + out << "digraph BB {\n" + << " node [shape=record];\n" + << " entry [share=record, label=\"entry block\"];\n"; + + // std::map blocksByName; + std::vector blocks; + for (auto& pair : this->basicBlocks) + { + blocks.push_back(&pair.second); + } + blocks.push_back(m_jumpTableBlock.get()); + blocks.push_back(m_badJumpBlock.get()); + + // Output nodes + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + // blocksByName.insert(std::pair(blockName, bb)); + + int numOfPhiNodes = 0; + auto firstNonPhiPtr = bb->llvm()->getFirstNonPHI(); + for (auto instrIter = bb->llvm()->begin(); &*instrIter != firstNonPhiPtr; ++instrIter, ++numOfPhiNodes); + + auto endStackSize = bb->getStack().size(); + + out << " \"" << blockName << "\" [shape=record, label=\"" + << std::to_string(numOfPhiNodes) << "|" + << blockName << "|" + << std::to_string(endStackSize) + << "\"];\n"; + } + + out << " entry -> \"Instr.0\";\n"; + + // Output edges + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + auto end = llvm::succ_end(bb->llvm()); + for (llvm::succ_iterator it = llvm::succ_begin(bb->llvm()); it != end; ++it) + { + std::string succName = it->getName(); + out << " \"" << blockName << "\" -> \"" << succName << "\";\n"; + } + } + + out << "}\n"; +} + } } } diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 1a0e61ca1..bda154689 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -24,6 +24,9 @@ public: std::unique_ptr compile(const bytes& bytecode); + void dumpBasicBlockGraph(std::ostream& out); + + private: void createBasicBlocks(const bytes& bytecode); @@ -32,6 +35,7 @@ private: void linkBasicBlocks(); + llvm::IRBuilder<> m_builder; /** diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index d8bf9438b..22ba1db50 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -22,6 +23,7 @@ void show_usage() std::cerr << "usage: evmcc (-b|-c|-d)+ \n"; } + int main(int argc, char** argv) { @@ -30,7 +32,8 @@ int main(int argc, char** argv) bool opt_show_bytes = false; bool opt_compile = false; bool opt_interpret = false; - bool opt_unknown = false; + bool opt_dump_graph = false; + bool opt_unknown = false; for (int i = 1; i < argc; i++) { @@ -43,6 +46,8 @@ int main(int argc, char** argv) opt_dissassemble = true; else if (option == "-i") opt_interpret = true; + else if (option == "-g") + opt_dump_graph = true; else if (option[0] != '-' && input_file.empty()) input_file = option; else @@ -89,9 +94,18 @@ int main(int argc, char** argv) if (opt_compile) { - auto module = eth::jit::Compiler().compile(bytecode); + auto compiler = eth::jit::Compiler(); + auto module = compiler.compile(bytecode); llvm::raw_os_ostream out(std::cout); module->print(out, nullptr); + + if (opt_dump_graph) + { + std::ofstream ofs("blocks.dot"); + compiler.dumpBasicBlockGraph(ofs); + ofs.close(); + std::cout << "Basic blocks graph written to block.dot\n"; + } } if (opt_interpret) From 960380b8e552290f4c7ec6678c60c77669a7108a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 13:27:28 +0200 Subject: [PATCH 139/396] Get IR module from IR builder on demand --- evmcc/CompilerHelper.cpp | 10 ++++++++-- evmcc/CompilerHelper.h | 6 +++--- evmcc/Ext.cpp | 2 +- evmcc/GasMeter.cpp | 9 +++++---- evmcc/Memory.cpp | 29 +++++++++++++++-------------- evmcc/Memory.h | 4 ++-- 6 files changed, 34 insertions(+), 26 deletions(-) diff --git a/evmcc/CompilerHelper.cpp b/evmcc/CompilerHelper.cpp index 7b29690b7..3bdf38641 100644 --- a/evmcc/CompilerHelper.cpp +++ b/evmcc/CompilerHelper.cpp @@ -11,10 +11,16 @@ namespace jit { CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : - m_builder(_builder), - m_module(_builder.GetInsertBlock()->getParent()->getParent()) + m_builder(_builder) {} +llvm::Module* CompilerHelper::getModule() +{ + assert(m_builder.GetInsertBlock()); + assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function + return m_builder.GetInsertBlock()->getParent()->getParent(); +} + } } } diff --git a/evmcc/CompilerHelper.h b/evmcc/CompilerHelper.h index e10937277..7cf2653e5 100644 --- a/evmcc/CompilerHelper.h +++ b/evmcc/CompilerHelper.h @@ -19,11 +19,11 @@ protected: CompilerHelper(const CompilerHelper&) = delete; void operator=(CompilerHelper) = delete; + /// Reference to the IR module being compiled + llvm::Module* getModule(); + /// Reference to parent compiler IR builder llvm::IRBuilder<>& m_builder; - - /// Reference to the IR module being compiled - llvm::Module* m_module; }; } diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index f3f7699cd..5307bc191 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -47,7 +47,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) { auto&& ctx = _builder.getContext(); - auto module = m_module; + auto module = getModule(); auto i256Ty = m_builder.getIntNTy(256); auto i256PtrTy = i256Ty->getPointerTo(); diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 206e5c805..f5e4a224b 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -83,10 +83,11 @@ bool isCostBlockEnd(Instruction _inst) GasMeter::GasMeter(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) { - m_gas = new llvm::GlobalVariable(*m_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); + auto module = getModule(); + m_gas = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); m_gas->setUnnamedAddr(true); // Address is not important - m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", m_module); + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", module); InsertPointGuard guard(m_builder); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); @@ -103,9 +104,9 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder) : m_builder.SetInsertPoint(outOfGasBB); //auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); - auto extJmpBuf = new llvm::GlobalVariable(*m_module, Type::BytePtr, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "rt_jmpBuf"); + auto extJmpBuf = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "rt_jmpBuf"); llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; - auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", m_module); + auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", module); m_builder.CreateCall2(longjmpNative, m_builder.CreateLoad(extJmpBuf), Constant::get(ReturnCode::OutOfGas)); m_builder.CreateUnreachable(); diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 7fde48949..d370a7f72 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -25,38 +25,39 @@ namespace jit Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter): CompilerHelper(_builder) { + auto module = getModule(); auto i64Ty = m_builder.getInt64Ty(); llvm::Type* argTypes[] = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_dump", m_module); + "evmccrt_memory_dump", module); - m_data = new llvm::GlobalVariable(*m_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_size = new llvm::GlobalVariable(*m_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); + m_size = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); m_size->setUnnamedAddr(true); // Address is not important - m_returnDataOffset = new llvm::GlobalVariable(*m_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset"); + m_returnDataOffset = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset"); m_returnDataOffset->setUnnamedAddr(true); // Address is not important - m_returnDataSize = new llvm::GlobalVariable(*m_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); + m_returnDataSize = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); m_returnDataSize->setUnnamedAddr(true); // Address is not important - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", m_module); + m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", module); llvm::AttrBuilder attrBuilder; attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - m_require = createRequireFunc(m_module, _gasMeter); - m_loadWord = createFunc(false, Type::i256, m_module, _gasMeter); - m_storeWord = createFunc(true, Type::i256, m_module, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, m_module, _gasMeter); + m_require = createRequireFunc(_gasMeter); + m_loadWord = createFunc(false, Type::i256, _gasMeter); + m_storeWord = createFunc(true, Type::i256, _gasMeter); + m_storeByte = createFunc(true, Type::Byte, _gasMeter); } -llvm::Function* Memory::createRequireFunc(llvm::Module* _module, GasMeter& _gasMeter) +llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) { - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", _module); + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func); auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func); @@ -91,14 +92,14 @@ llvm::Function* Memory::createRequireFunc(llvm::Module* _module, GasMeter& _gasM return func; } -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::Module* _module, GasMeter& _gasMeter) +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter& _gasMeter) { auto isWord = _valueType == Type::i256; llvm::Type* storeArgs[] = {Type::i256, _valueType}; auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false); - auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, _module); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); InsertPointGuard guard(m_builder); // Restores insert point at function exit diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 489c37439..2ab09c127 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -36,8 +36,8 @@ public: void dump(uint64_t _begin, uint64_t _end = 0); private: - llvm::Function* createFunc(bool _isStore, llvm::Type* _type, llvm::Module* _module, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(llvm::Module* _module, GasMeter& _gasMeter); + llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); + llvm::Function* createRequireFunc(GasMeter& _gasMeter); private: llvm::GlobalVariable* m_data; From 64205161576ad41a484b205ffbf58f12f9a9d0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 13:34:02 +0200 Subject: [PATCH 140/396] InsertPointGuard definition moved to CompilerHelper.h --- evmcc/CompilerHelper.h | 25 +++++++++++++++++++++++++ evmcc/GasMeter.cpp | 1 - evmcc/Utils.h | 22 ---------------------- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/evmcc/CompilerHelper.h b/evmcc/CompilerHelper.h index 7cf2653e5..e284398a3 100644 --- a/evmcc/CompilerHelper.h +++ b/evmcc/CompilerHelper.h @@ -11,6 +11,7 @@ namespace eth namespace jit { +/// Base class for compiler helpers like Memory, GasMeter, etc. class CompilerHelper { protected: @@ -26,6 +27,30 @@ protected: llvm::IRBuilder<>& m_builder; }; + +/// Saves the insert point of the IR builder and restores it when destructed +struct InsertPointGuard +{ + InsertPointGuard(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_insertBB(m_builder.GetInsertBlock()), + m_insertPt(m_builder.GetInsertPoint()) + {} + + InsertPointGuard(const InsertPointGuard&) = delete; + void operator=(InsertPointGuard) = delete; + + ~InsertPointGuard() + { + m_builder.SetInsertPoint(m_insertBB, m_insertPt); + } + +private: + llvm::IRBuilder<>& m_builder; + llvm::BasicBlock* m_insertBB; + llvm::BasicBlock::iterator m_insertPt; +}; + } } } diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index f5e4a224b..9c83ba8db 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -9,7 +9,6 @@ #include #include "Type.h" -#include "Utils.h" #include "Ext.h" namespace dev diff --git a/evmcc/Utils.h b/evmcc/Utils.h index 27189d5d0..1b146b3d2 100644 --- a/evmcc/Utils.h +++ b/evmcc/Utils.h @@ -26,28 +26,6 @@ static_assert(sizeof(i256) == 32, "Wrong i265 size"); u256 llvm2eth(i256); i256 eth2llvm(u256); -struct InsertPointGuard -{ - InsertPointGuard(llvm::IRBuilder<>& _builder) : - m_builder(_builder), - m_insertBB(m_builder.GetInsertBlock()), - m_insertPt(m_builder.GetInsertPoint()) - {} - - ~InsertPointGuard() - { - m_builder.SetInsertPoint(m_insertBB, m_insertPt); - } - -private: - llvm::IRBuilder<>& m_builder; - llvm::BasicBlock* m_insertBB; - llvm::BasicBlock::iterator m_insertPt; - - InsertPointGuard(const InsertPointGuard&) = delete; - void operator=(InsertPointGuard) = delete; -}; - #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ case Instruction::PUSH3: \ From 92cf0b9ab0a64f85b602cc40d5569e860d24540e Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 16 Oct 2014 12:35:51 +0100 Subject: [PATCH 141/396] Dumping CFG to .dot: showing indirect jumps with dashed lines --- evmcc/Compiler.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index a7e8ba483..8acfa7d05 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -935,7 +935,6 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) << " node [shape=record];\n" << " entry [share=record, label=\"entry block\"];\n"; - // std::map blocksByName; std::vector blocks; for (auto& pair : this->basicBlocks) { @@ -948,7 +947,6 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) for (auto bb : blocks) { std::string blockName = bb->llvm()->getName(); - // blocksByName.insert(std::pair(blockName, bb)); int numOfPhiNodes = 0; auto firstNonPhiPtr = bb->llvm()->getFirstNonPHI(); @@ -957,10 +955,8 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) auto endStackSize = bb->getStack().size(); out << " \"" << blockName << "\" [shape=record, label=\"" - << std::to_string(numOfPhiNodes) << "|" - << blockName << "|" - << std::to_string(endStackSize) - << "\"];\n"; + << numOfPhiNodes << "|" << blockName << "|" << endStackSize + << "\"];\n"; } out << " entry -> \"Instr.0\";\n"; @@ -974,7 +970,8 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) for (llvm::succ_iterator it = llvm::succ_begin(bb->llvm()); it != end; ++it) { std::string succName = it->getName(); - out << " \"" << blockName << "\" -> \"" << succName << "\";\n"; + out << " \"" << blockName << "\" -> \"" << succName << "\"" + << ((bb == m_jumpTableBlock.get()) ? " [style = dashed];\n" : "\n"); } } From a6c58c38d89c1da68e4306be0b72087886722450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 15:16:16 +0200 Subject: [PATCH 142/396] Move JIT compiler project to library --- evmcc/evmcc.cpp | 5 +- {evmcc => libevmjit}/BasicBlock.cpp | 0 {evmcc => libevmjit}/BasicBlock.h | 0 {evmcc => libevmjit}/Compiler.cpp | 0 {evmcc => libevmjit}/Compiler.h | 0 {evmcc => libevmjit}/CompilerHelper.cpp | 0 {evmcc => libevmjit}/CompilerHelper.h | 0 {evmcc => libevmjit}/ExecutionEngine.cpp | 0 {evmcc => libevmjit}/ExecutionEngine.h | 0 {evmcc => libevmjit}/Ext.cpp | 0 {evmcc => libevmjit}/Ext.h | 0 {evmcc => libevmjit}/GasMeter.cpp | 0 {evmcc => libevmjit}/GasMeter.h | 0 {evmcc => libevmjit}/Memory.cpp | 0 {evmcc => libevmjit}/Memory.h | 0 {evmcc => libevmjit}/Runtime.cpp | 0 {evmcc => libevmjit}/Runtime.h | 0 {evmcc => libevmjit}/Type.cpp | 0 {evmcc => libevmjit}/Type.h | 0 {evmcc => libevmjit}/Utils.cpp | 0 {evmcc => libevmjit}/Utils.h | 0 windows/Ethereum.sln | 87 ++++++++++++- windows/LLVM.props | 23 ++++ windows/LibEvmJit.vcxproj | 152 +++++++++++++++++++++++ windows/LibEvmJit.vcxproj.filters | 72 +++++++++++ windows/evmcc.vcxproj | 38 ++---- windows/evmcc.vcxproj.filters | 22 ---- 27 files changed, 341 insertions(+), 58 deletions(-) rename {evmcc => libevmjit}/BasicBlock.cpp (100%) rename {evmcc => libevmjit}/BasicBlock.h (100%) rename {evmcc => libevmjit}/Compiler.cpp (100%) rename {evmcc => libevmjit}/Compiler.h (100%) rename {evmcc => libevmjit}/CompilerHelper.cpp (100%) rename {evmcc => libevmjit}/CompilerHelper.h (100%) rename {evmcc => libevmjit}/ExecutionEngine.cpp (100%) rename {evmcc => libevmjit}/ExecutionEngine.h (100%) rename {evmcc => libevmjit}/Ext.cpp (100%) rename {evmcc => libevmjit}/Ext.h (100%) rename {evmcc => libevmjit}/GasMeter.cpp (100%) rename {evmcc => libevmjit}/GasMeter.h (100%) rename {evmcc => libevmjit}/Memory.cpp (100%) rename {evmcc => libevmjit}/Memory.h (100%) rename {evmcc => libevmjit}/Runtime.cpp (100%) rename {evmcc => libevmjit}/Runtime.h (100%) rename {evmcc => libevmjit}/Type.cpp (100%) rename {evmcc => libevmjit}/Type.h (100%) rename {evmcc => libevmjit}/Utils.cpp (100%) rename {evmcc => libevmjit}/Utils.h (100%) create mode 100644 windows/LLVM.props create mode 100644 windows/LibEvmJit.vcxproj create mode 100644 windows/LibEvmJit.vcxproj.filters diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 22ba1db50..8a7ac5384 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -12,9 +12,8 @@ #include #include #include - -#include "Compiler.h" -#include "ExecutionEngine.h" +#include +#include void show_usage() diff --git a/evmcc/BasicBlock.cpp b/libevmjit/BasicBlock.cpp similarity index 100% rename from evmcc/BasicBlock.cpp rename to libevmjit/BasicBlock.cpp diff --git a/evmcc/BasicBlock.h b/libevmjit/BasicBlock.h similarity index 100% rename from evmcc/BasicBlock.h rename to libevmjit/BasicBlock.h diff --git a/evmcc/Compiler.cpp b/libevmjit/Compiler.cpp similarity index 100% rename from evmcc/Compiler.cpp rename to libevmjit/Compiler.cpp diff --git a/evmcc/Compiler.h b/libevmjit/Compiler.h similarity index 100% rename from evmcc/Compiler.h rename to libevmjit/Compiler.h diff --git a/evmcc/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp similarity index 100% rename from evmcc/CompilerHelper.cpp rename to libevmjit/CompilerHelper.cpp diff --git a/evmcc/CompilerHelper.h b/libevmjit/CompilerHelper.h similarity index 100% rename from evmcc/CompilerHelper.h rename to libevmjit/CompilerHelper.h diff --git a/evmcc/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp similarity index 100% rename from evmcc/ExecutionEngine.cpp rename to libevmjit/ExecutionEngine.cpp diff --git a/evmcc/ExecutionEngine.h b/libevmjit/ExecutionEngine.h similarity index 100% rename from evmcc/ExecutionEngine.h rename to libevmjit/ExecutionEngine.h diff --git a/evmcc/Ext.cpp b/libevmjit/Ext.cpp similarity index 100% rename from evmcc/Ext.cpp rename to libevmjit/Ext.cpp diff --git a/evmcc/Ext.h b/libevmjit/Ext.h similarity index 100% rename from evmcc/Ext.h rename to libevmjit/Ext.h diff --git a/evmcc/GasMeter.cpp b/libevmjit/GasMeter.cpp similarity index 100% rename from evmcc/GasMeter.cpp rename to libevmjit/GasMeter.cpp diff --git a/evmcc/GasMeter.h b/libevmjit/GasMeter.h similarity index 100% rename from evmcc/GasMeter.h rename to libevmjit/GasMeter.h diff --git a/evmcc/Memory.cpp b/libevmjit/Memory.cpp similarity index 100% rename from evmcc/Memory.cpp rename to libevmjit/Memory.cpp diff --git a/evmcc/Memory.h b/libevmjit/Memory.h similarity index 100% rename from evmcc/Memory.h rename to libevmjit/Memory.h diff --git a/evmcc/Runtime.cpp b/libevmjit/Runtime.cpp similarity index 100% rename from evmcc/Runtime.cpp rename to libevmjit/Runtime.cpp diff --git a/evmcc/Runtime.h b/libevmjit/Runtime.h similarity index 100% rename from evmcc/Runtime.h rename to libevmjit/Runtime.h diff --git a/evmcc/Type.cpp b/libevmjit/Type.cpp similarity index 100% rename from evmcc/Type.cpp rename to libevmjit/Type.cpp diff --git a/evmcc/Type.h b/libevmjit/Type.h similarity index 100% rename from evmcc/Type.h rename to libevmjit/Type.h diff --git a/evmcc/Utils.cpp b/libevmjit/Utils.cpp similarity index 100% rename from evmcc/Utils.cpp rename to libevmjit/Utils.cpp diff --git a/evmcc/Utils.h b/libevmjit/Utils.h similarity index 100% rename from evmcc/Utils.h rename to libevmjit/Utils.h diff --git a/windows/Ethereum.sln b/windows/Ethereum.sln index c894b8a79..11ced4384 100644 --- a/windows/Ethereum.sln +++ b/windows/Ethereum.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Express 2013 for Windows Desktop -VisualStudioVersion = 12.0.21005.1 +VisualStudioVersion = 12.0.30723.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libs", "Libs", "{988F2383-FA1D-408B-BCF6-C0EE7AB0A560}" EndProject @@ -38,141 +38,221 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lllc", "Lllc.vcxproj", "{255BDC68-B8DB-465F-8220-981E77684189}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "evmcc", "evmcc.vcxproj", "{D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}" + ProjectSection(ProjectDependencies) = postProject + {9C816740-5C11-4377-A3A7-46BE12F35FA0} = {9C816740-5C11-4377-A3A7-46BE12F35FA0} + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F} = {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibEvmJit", "LibEvmJit.vcxproj", "{9C816740-5C11-4377-A3A7-46BE12F35FA0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Mixed Platforms = Debug|Mixed Platforms Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 + Release|Mixed Platforms = Release|Mixed Platforms Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.ActiveCfg = Debug|Win32 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.Build.0 = Debug|Win32 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.ActiveCfg = Debug|x64 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.Build.0 = Debug|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Mixed Platforms.Build.0 = Release|Win32 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.ActiveCfg = Release|Win32 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.Build.0 = Release|Win32 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|x64.ActiveCfg = Release|x64 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|x64.Build.0 = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.ActiveCfg = Debug|Win32 {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.Build.0 = Debug|Win32 {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.ActiveCfg = Debug|x64 {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.Build.0 = Debug|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {27014763-955D-486B-9BA7-69872192E6F4}.Release|Mixed Platforms.Build.0 = Release|Win32 {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.ActiveCfg = Release|Win32 {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.Build.0 = Release|Win32 {27014763-955D-486B-9BA7-69872192E6F4}.Release|x64.ActiveCfg = Release|x64 {27014763-955D-486B-9BA7-69872192E6F4}.Release|x64.Build.0 = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.ActiveCfg = Debug|Win32 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.Build.0 = Debug|Win32 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.ActiveCfg = Debug|x64 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.Build.0 = Debug|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Mixed Platforms.Build.0 = Release|Win32 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.ActiveCfg = Release|Win32 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.Build.0 = Release|Win32 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|x64.ActiveCfg = Release|x64 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|x64.Build.0 = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.ActiveCfg = Debug|Win32 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.Build.0 = Debug|Win32 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.ActiveCfg = Debug|x64 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.Build.0 = Debug|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Mixed Platforms.Build.0 = Release|Win32 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.ActiveCfg = Release|Win32 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.Build.0 = Release|Win32 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|x64.ActiveCfg = Release|x64 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|x64.Build.0 = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.ActiveCfg = Debug|Win32 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.Build.0 = Debug|Win32 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.ActiveCfg = Debug|x64 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.Build.0 = Debug|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Mixed Platforms.Build.0 = Release|Win32 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.ActiveCfg = Release|Win32 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.Build.0 = Release|Win32 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|x64.ActiveCfg = Release|x64 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|x64.Build.0 = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.ActiveCfg = Debug|Win32 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.Build.0 = Debug|Win32 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.ActiveCfg = Debug|x64 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.Build.0 = Debug|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Mixed Platforms.Build.0 = Release|Win32 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.ActiveCfg = Release|Win32 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.Build.0 = Release|Win32 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|x64.ActiveCfg = Release|x64 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|x64.Build.0 = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.ActiveCfg = Debug|Win32 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.Build.0 = Debug|Win32 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.ActiveCfg = Debug|x64 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.Build.0 = Debug|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Mixed Platforms.Build.0 = Release|Win32 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.ActiveCfg = Release|Win32 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.Build.0 = Release|Win32 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|x64.ActiveCfg = Release|x64 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|x64.Build.0 = Release|x64 + {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Debug|Win32.ActiveCfg = Debug|Win32 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Debug|Win32.Build.0 = Debug|Win32 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Debug|x64.ActiveCfg = Debug|x64 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Debug|x64.Build.0 = Debug|x64 + {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|Mixed Platforms.ActiveCfg = Release|Win32 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|Win32.ActiveCfg = Release|Win32 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|Win32.Build.0 = Release|Win32 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|x64.ActiveCfg = Release|x64 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Release|x64.Build.0 = Release|x64 + {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Debug|Win32.ActiveCfg = Debug|Win32 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Debug|Win32.Build.0 = Debug|Win32 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Debug|x64.ActiveCfg = Debug|x64 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Debug|x64.Build.0 = Debug|x64 + {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Release|Mixed Platforms.ActiveCfg = Release|Win32 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Release|Win32.ActiveCfg = Release|Win32 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Release|Win32.Build.0 = Release|Win32 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Release|x64.ActiveCfg = Release|x64 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Release|x64.Build.0 = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.ActiveCfg = Debug|Win32 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.Build.0 = Debug|Win32 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.ActiveCfg = Debug|x64 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.Build.0 = Debug|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Mixed Platforms.Build.0 = Release|Win32 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.ActiveCfg = Release|Win32 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.Build.0 = Release|Win32 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|x64.ActiveCfg = Release|x64 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|x64.Build.0 = Release|x64 + {90C70663-7181-4E99-9079-54188CEB8954}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {90C70663-7181-4E99-9079-54188CEB8954}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {90C70663-7181-4E99-9079-54188CEB8954}.Debug|Win32.ActiveCfg = Debug|Win32 {90C70663-7181-4E99-9079-54188CEB8954}.Debug|Win32.Build.0 = Debug|Win32 {90C70663-7181-4E99-9079-54188CEB8954}.Debug|x64.ActiveCfg = Debug|x64 {90C70663-7181-4E99-9079-54188CEB8954}.Debug|x64.Build.0 = Debug|x64 + {90C70663-7181-4E99-9079-54188CEB8954}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {90C70663-7181-4E99-9079-54188CEB8954}.Release|Mixed Platforms.Build.0 = Release|Win32 {90C70663-7181-4E99-9079-54188CEB8954}.Release|Win32.ActiveCfg = Release|Win32 {90C70663-7181-4E99-9079-54188CEB8954}.Release|Win32.Build.0 = Release|Win32 {90C70663-7181-4E99-9079-54188CEB8954}.Release|x64.ActiveCfg = Release|x64 {90C70663-7181-4E99-9079-54188CEB8954}.Release|x64.Build.0 = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.ActiveCfg = Debug|Win32 {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.Build.0 = Debug|Win32 {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.ActiveCfg = Debug|x64 {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.Build.0 = Debug|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Mixed Platforms.Build.0 = Release|Win32 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.ActiveCfg = Release|Win32 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.Build.0 = Release|Win32 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|x64.ActiveCfg = Release|x64 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|x64.Build.0 = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.ActiveCfg = Debug|Win32 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.Build.0 = Debug|Win32 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.ActiveCfg = Debug|x64 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.Build.0 = Debug|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Mixed Platforms.Build.0 = Release|Win32 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.ActiveCfg = Release|Win32 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.Build.0 = Release|Win32 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|x64.ActiveCfg = Release|x64 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|x64.Build.0 = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.ActiveCfg = Debug|Win32 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.Build.0 = Debug|Win32 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.ActiveCfg = Debug|x64 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.Build.0 = Debug|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Mixed Platforms.Build.0 = Release|Win32 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.ActiveCfg = Release|Win32 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.Build.0 = Release|Win32 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|x64.ActiveCfg = Release|x64 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|x64.Build.0 = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.ActiveCfg = Debug|Win32 {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.Build.0 = Debug|Win32 {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.ActiveCfg = Debug|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.Build.0 = Debug|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {255BDC68-B8DB-465F-8220-981E77684189}.Release|Mixed Platforms.Build.0 = Release|Win32 {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.ActiveCfg = Release|Win32 {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.Build.0 = Release|Win32 {255BDC68-B8DB-465F-8220-981E77684189}.Release|x64.ActiveCfg = Release|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Release|x64.Build.0 = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.ActiveCfg = Debug|Win32 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.Build.0 = Debug|Win32 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|x64.ActiveCfg = Debug|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Mixed Platforms.Build.0 = Release|Win32 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.ActiveCfg = Release|Win32 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.Build.0 = Release|Win32 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|x64.ActiveCfg = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.ActiveCfg = Debug|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.Build.0 = Debug|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.ActiveCfg = Debug|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.Build.0 = Debug|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Mixed Platforms.Build.0 = Release|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.ActiveCfg = Release|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.Build.0 = Release|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|x64.ActiveCfg = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -181,11 +261,12 @@ Global {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} {27014763-955D-486B-9BA7-69872192E6F4} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24} = {6838FA95-01BF-4FF7-914C-FC209B81406E} + {3F3E389B-88DE-41D5-A73B-4F6036E18B36} = {6838FA95-01BF-4FF7-914C-FC209B81406E} {1CC213A4-3482-4211-B47B-172E90DAC7DE} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} {1B1CA20E-39C3-4D9B-AC37-3783048E6672} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} {DF3C5B07-A1A2-4F16-B37F-A27333622CDD} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} {F174E81A-2A66-4693-B917-11BB42D3658C} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24} = {6838FA95-01BF-4FF7-914C-FC209B81406E} - {3F3E389B-88DE-41D5-A73B-4F6036E18B36} = {6838FA95-01BF-4FF7-914C-FC209B81406E} + {9C816740-5C11-4377-A3A7-46BE12F35FA0} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} EndGlobalSection EndGlobal diff --git a/windows/LLVM.props b/windows/LLVM.props new file mode 100644 index 000000000..708ff3085 --- /dev/null +++ b/windows/LLVM.props @@ -0,0 +1,23 @@ + + + + + ..\..\builds\llvm3.5 + ..\..\llvm-3.5.0\include;$(LLVMBuildDir)\include + + + + + $(LLVMIncludeDir);%(AdditionalIncludeDirectories) + 4800;%(DisableSpecificWarnings) + + + + + $(LLVMBuildDir) + + + $(LLVMIncludeDir) + + + \ No newline at end of file diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj new file mode 100644 index 000000000..17832d871 --- /dev/null +++ b/windows/LibEvmJit.vcxproj @@ -0,0 +1,152 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {9C816740-5C11-4377-A3A7-46BE12F35FA0} + LibEvmJit + + + + StaticLibrary + true + v120 + + + StaticLibrary + true + v120 + + + StaticLibrary + false + v120 + true + + + StaticLibrary + false + v120 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters new file mode 100644 index 000000000..e24e4379e --- /dev/null +++ b/windows/LibEvmJit.vcxproj.filters @@ -0,0 +1,72 @@ + + + + + {9bb7d84d-6d6c-48af-a954-60049208b2f1} + + + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + libevmjit + + + \ No newline at end of file diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index efa7a6f20..6c1b72143 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -19,29 +19,7 @@ - - - - - - - - - - - - - - - - - - - - - - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} @@ -132,8 +110,8 @@ Console true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) + LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -152,8 +130,8 @@ Console true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;../../_build/LibSecp256k1/x64_Debug;../../_build/LibCryptoPP/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LibSecp256k1.lib;LibCryptoPP.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;../../_build/LibSecp256k1/x64_Debug;../../_build/LibCryptoPP/x64_Debug;%(AdditionalLibraryDirectories) + LibEthereum.lib;LibEvmJit.lib;LibSecp256k1.lib;LibCryptoPP.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -173,8 +151,8 @@ true true true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) + LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -196,8 +174,8 @@ true true true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) + LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index adfcfaf60..6be5386a1 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -2,27 +2,5 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 9552394cd1112e5b29563428316d3ae91db55614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 18:03:14 +0200 Subject: [PATCH 143/396] VM execution wrapper with similar interface as libevm/VM --- evmcc/evmcc.cpp | 4 ++-- libevmjit/Compiler.cpp | 16 ++++++------- libevmjit/Compiler.h | 6 ++--- libevmjit/ExecutionEngine.cpp | 2 +- libevmjit/ExecutionEngine.h | 2 ++ libevmjit/VM.cpp | 37 +++++++++++++++++++++++++++++++ libevmjit/VM.h | 32 ++++++++++++++++++++++++++ windows/LibEvmJit.vcxproj | 2 ++ windows/LibEvmJit.vcxproj.filters | 6 +++++ 9 files changed, 93 insertions(+), 14 deletions(-) create mode 100644 libevmjit/VM.cpp create mode 100644 libevmjit/VM.h diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 8a7ac5384..600980d44 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -94,7 +94,7 @@ int main(int argc, char** argv) if (opt_compile) { auto compiler = eth::jit::Compiler(); - auto module = compiler.compile(bytecode); + auto module = compiler.compile({bytecode.data(), bytecode.size()}); llvm::raw_os_ostream out(std::cout); module->print(out, nullptr); @@ -110,7 +110,7 @@ int main(int argc, char** argv) if (opt_interpret) { auto engine = eth::jit::ExecutionEngine(); - auto module = eth::jit::Compiler().compile(bytecode); + auto module = eth::jit::Compiler().compile({bytecode.data(), bytecode.size()}); module->dump(); auto result = engine.run(std::move(module)); return result; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 035abf287..cbb6118f4 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -29,7 +29,7 @@ Compiler::Compiler(): Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(const bytes& bytecode) +void Compiler::createBasicBlocks(bytesConstRef bytecode) { std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end splitPoints.insert(0); // First basic block @@ -38,9 +38,9 @@ void Compiler::createBasicBlocks(const bytes& bytecode) std::vector indirectJumpTargets; boost::dynamic_bitset<> validJumpTargets(bytecode.size()); - for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr) + for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) { - ProgramCounter currentPC = curr - bytecode.cbegin(); + ProgramCounter currentPC = curr - bytecode.begin(); validJumpTargets[currentPC] = 1; auto inst = static_cast(*curr); @@ -51,7 +51,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode) { auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; auto next = curr + numBytes + 1; - if (next >= bytecode.cend()) + if (next >= bytecode.end()) break; auto nextInst = static_cast(*next); @@ -72,7 +72,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode) targetPC = bytecode.size(); splitPoints.insert(targetPC); - ProgramCounter jumpPC = (next - bytecode.cbegin()); + ProgramCounter jumpPC = (next - bytecode.begin()); directJumpTargets[jumpPC] = targetPC; } @@ -95,7 +95,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode) case Instruction::SUICIDE: { // Create a basic block starting at the following instruction. - if (curr + 1 < bytecode.cend()) + if (curr + 1 < bytecode.end()) { splitPoints.insert(currentPC + 1); } @@ -149,7 +149,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode) } } -std::unique_ptr Compiler::compile(const bytes& bytecode) +std::unique_ptr Compiler::compile(bytesConstRef bytecode) { auto module = std::make_unique("main", m_builder.getContext()); @@ -214,7 +214,7 @@ std::unique_ptr Compiler::compile(const bytes& bytecode) } -void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) +void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) { auto& stack = basicBlock.getStack(); m_builder.SetInsertPoint(basicBlock.llvm()); diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index bda154689..f708898d6 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -22,16 +22,16 @@ public: Compiler(); - std::unique_ptr compile(const bytes& bytecode); + std::unique_ptr compile(bytesConstRef bytecode); void dumpBasicBlockGraph(std::ostream& out); private: - void createBasicBlocks(const bytes& bytecode); + void createBasicBlocks(bytesConstRef bytecode); - void compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); + void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); void linkBasicBlocks(); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 6a494f42a..bac15a478 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -125,7 +125,7 @@ int ExecutionEngine::run(std::unique_ptr _module) if (returnCode == ReturnCode::Return) { - auto&& returnData = Memory::getReturnData(); // TODO: It might be better to place is in Runtime interface + returnData = Memory::getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface std::cout << "RETURN [ "; for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 158df0283..f6fb49276 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -18,6 +18,8 @@ public: ExecutionEngine(); int run(std::unique_ptr module); + + bytes returnData; }; } diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp new file mode 100644 index 000000000..51cd7c5a3 --- /dev/null +++ b/libevmjit/VM.cpp @@ -0,0 +1,37 @@ + +#include "VM.h" + +#include + +#include "ExecutionEngine.h" +#include "Compiler.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +bytes VM::go(ExtVMFace& _ext) +{ + auto module = Compiler().compile(_ext.code); + module->dump(); + + ExecutionEngine engine; + auto exitCode = engine.run(std::move(module)); + + switch (exitCode) + { + case 101: + BOOST_THROW_EXCEPTION(BadJumpDestination()); + case 102: + BOOST_THROW_EXCEPTION(OutOfGas()); + } + + return std::move(engine.returnData); +} + +} +} +} diff --git a/libevmjit/VM.h b/libevmjit/VM.h new file mode 100644 index 000000000..3e7884b10 --- /dev/null +++ b/libevmjit/VM.h @@ -0,0 +1,32 @@ + +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class VM +{ +public: + /// Construct VM object. + explicit VM(u256 _gas = 0): m_gas(_gas) {} + + void reset(u256 _gas = 0) { m_gas = _gas; } + + bytes go(ExtVMFace& _ext); + + u256 gas() const { return m_gas; } + +private: + u256 m_gas = 0; +}; + +} +} +} diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index 17832d871..1c71bb082 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -133,6 +133,7 @@ + @@ -145,6 +146,7 @@ + diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters index e24e4379e..a2008f971 100644 --- a/windows/LibEvmJit.vcxproj.filters +++ b/windows/LibEvmJit.vcxproj.filters @@ -36,6 +36,9 @@ libevmjit + + libevmjit + @@ -68,5 +71,8 @@ libevmjit + + libevmjit + \ No newline at end of file From 5dbc877b294bf536dc988aa358deeb55a330e38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 18:19:58 +0200 Subject: [PATCH 144/396] test/rlp bugfix: expectedText can be empty --- test/rlp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rlp.cpp b/test/rlp.cpp index 95d40ada7..69360ad66 100644 --- a/test/rlp.cpp +++ b/test/rlp.cpp @@ -79,7 +79,7 @@ namespace dev if ( v.type() == js::str_type ) { const std::string& expectedText = v.get_str(); - if ( expectedText.front() == '#' ) + if ( !expectedText.empty() && expectedText.front() == '#' ) { // Deal with bigint instead of a raw string std::string bigIntStr = expectedText.substr(1,expectedText.length()-1); From 1a18343612a9378591cacce0f76e8270a1ba73d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 18:20:49 +0200 Subject: [PATCH 145/396] Prepare VM test engine for running JIT-ed tests --- test/vm.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index cc87866df..d77906731 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -493,7 +493,6 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_REQUIRE(o.count("pre") > 0); BOOST_REQUIRE(o.count("exec") > 0); - VM vm; dev::test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -508,11 +507,13 @@ void doTests(json_spirit::mValue& v, bool _fillin) fev.code = &fev.thisTxCode; } - vm.reset(fev.gas); bytes output; + u256 gas; try { - output = vm.go(fev).toBytes(); + VM vm(fev.gas); + output = vm.go(fev).toVector(); + gas = vm.gas(); // Get the remaining gas } catch (Exception const& _e) { @@ -549,7 +550,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); - fev.push(o, "gas", vm.gas()); + fev.push(o, "gas", gas); } else { @@ -573,7 +574,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); - BOOST_CHECK(test.toInt(o["gas"]) == vm.gas()); + BOOST_CHECK(test.toInt(o["gas"]) == gas); BOOST_CHECK(test.addresses == fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); } From f8e7689d17acbd19005da8b4ea05961e1e9c2384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 10:51:58 +0200 Subject: [PATCH 146/396] Fix GasMeter not nulling cost call --- libevmjit/GasMeter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 13c27118f..53c1e30e5 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -168,6 +168,7 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost) if (m_blockCost == 0 && !_additionalCost) // Do not check 0 { m_checkCall->eraseFromParent(); // Remove the gas check call + m_checkCall = nullptr; return; } From 05964dccf7917f415197e7e3a4103512573a3357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 10:52:35 +0200 Subject: [PATCH 147/396] Fix not allocated arg8 for CALL --- libevmjit/Ext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 5307bc191..5c4bb7c59 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -61,7 +61,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder): m_arg5 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg5"); m_arg6 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg6"); m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg7"); - m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8"); + m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8"); Type* elements[] = { i256Ty, // i256 address; From 0e56f2609d9cc1759928b657440b6397435670d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 10:58:10 +0200 Subject: [PATCH 148/396] Running vm_tests with JIT --- test/vm.cpp | 17 ++++++++++++++--- windows/Ethereum.sln | 3 +++ windows/TestEthereum.vcxproj | 3 +++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index d77906731..a7b785240 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -22,6 +22,7 @@ #include "vm.h" #include +#include #define FILL_TESTS @@ -511,9 +512,19 @@ void doTests(json_spirit::mValue& v, bool _fillin) u256 gas; try { - VM vm(fev.gas); - output = vm.go(fev).toVector(); - gas = vm.gas(); // Get the remaining gas + auto useJit = true; + if (useJit) + { + jit::VM vm(fev.gas); + output = vm.go(fev); + gas = vm.gas(); + } + else + { + VM vm(fev.gas); + output = vm.go(fev).toVector(); + gas = vm.gas(); // Get the remaining gas + } } catch (Exception const& _e) { diff --git a/windows/Ethereum.sln b/windows/Ethereum.sln index 11ced4384..33167a23b 100644 --- a/windows/Ethereum.sln +++ b/windows/Ethereum.sln @@ -16,6 +16,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestSecp256k1", "TestSecp256k1.vcxproj", "{3BF049F8-AF7E-4E1C-9627-3E94C887AF24}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestEthereum", "TestEthereum.vcxproj", "{3F3E389B-88DE-41D5-A73B-4F6036E18B36}" + ProjectSection(ProjectDependencies) = postProject + {9C816740-5C11-4377-A3A7-46BE12F35FA0} = {9C816740-5C11-4377-A3A7-46BE12F35FA0} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibCryptoPP", "LibCryptoPP.vcxproj", "{1CC213A4-3482-4211-B47B-172E90DAC7DE}" EndProject diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index 172e6be86..b07124581 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -55,6 +55,7 @@ + @@ -107,6 +108,8 @@ Console true + LibEthereum.lib;LibEvmJit.lib;LibSecp256k1.lib;LibCryptoPP.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;../../_build/LibSecp256k1/x64_Debug;../../_build/LibCryptoPP/x64_Debug;%(AdditionalLibraryDirectories) From 138ef80577bce0790654bcfc367ecefcdf91fb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 11:28:16 +0200 Subject: [PATCH 149/396] Tests moved to test/ folder --- evmcc/bytecode/if1.evm | 1 - evmcc/lll/if1.asm | 21 ------------------- evmcc/lll/if1.lll | 5 ----- .../arith/arith1.evm} | 0 .../arith/arith1.lll} | 0 evmcc/{bytecode => test/arith}/fib1.evm | 0 evmcc/{lll => test/arith}/fib1.lll | 0 evmcc/{bytecode => test/ext}/ext_test.evm | 0 evmcc/{lll => test/ext}/ext_test.lll | 0 evmcc/{bytecode => test/ext}/store_test.evm | 0 evmcc/{lll => test/ext}/store_test.lll | 0 evmcc/{bytecode => test/jump}/for1.evm | 0 evmcc/{lll => test/jump}/for1.lll | 0 evmcc/{bytecode => test/jump}/for2.evm | 0 evmcc/{lll => test/jump}/for2.lll | 0 evmcc/{lll => test/jump}/when1.asm | 0 evmcc/{bytecode => test/jump}/when1.evm | 0 evmcc/{lll => test/jump}/when1.lll | 0 evmcc/{bytecode => test}/kv.evm | 0 evmcc/{lll => test}/kv.lll | 0 evmcc/{bytecode => test/mem}/byte.evm | 0 evmcc/{lll => test/mem}/byte.lll | 0 evmcc/{bytecode => test/mem}/mem2.evm | 0 evmcc/{lll => test/mem}/mem2.lll | 0 evmcc/{bytecode => test/mem}/memtest1.evm | 0 evmcc/{lll => test/mem}/memtest1.lll | 0 evmcc/{bytecode => test/ret}/return1.evm | 0 evmcc/{lll => test/ret}/return1.lll | 0 evmcc/{bytecode => test/ret}/return2.evm | 0 evmcc/{lll => test/ret}/return2.lll | 0 evmcc/{bytecode => test/ret}/return_test.evm | 0 evmcc/{lll => test/ret}/return_test.lll | 0 evmcc/{bytecode => test/stack}/push_test.evm | 0 evmcc/{lll => test/stack}/push_test.lll | 0 evmcc/{bytecode => test/stack}/stack_test.evm | 0 evmcc/{lll => test/stack}/stack_test.lll | 0 evmcc/{bytecode => test/stack}/stackjump.evm | 0 evmcc/{lll => test/stack}/stackjump.lll | 0 38 files changed, 27 deletions(-) delete mode 100644 evmcc/bytecode/if1.evm delete mode 100644 evmcc/lll/if1.asm delete mode 100644 evmcc/lll/if1.lll rename evmcc/{bytecode/arithmetic_test.evm => test/arith/arith1.evm} (100%) rename evmcc/{lll/arithmetic_test.lll => test/arith/arith1.lll} (100%) rename evmcc/{bytecode => test/arith}/fib1.evm (100%) rename evmcc/{lll => test/arith}/fib1.lll (100%) rename evmcc/{bytecode => test/ext}/ext_test.evm (100%) rename evmcc/{lll => test/ext}/ext_test.lll (100%) rename evmcc/{bytecode => test/ext}/store_test.evm (100%) rename evmcc/{lll => test/ext}/store_test.lll (100%) rename evmcc/{bytecode => test/jump}/for1.evm (100%) rename evmcc/{lll => test/jump}/for1.lll (100%) rename evmcc/{bytecode => test/jump}/for2.evm (100%) rename evmcc/{lll => test/jump}/for2.lll (100%) rename evmcc/{lll => test/jump}/when1.asm (100%) rename evmcc/{bytecode => test/jump}/when1.evm (100%) rename evmcc/{lll => test/jump}/when1.lll (100%) rename evmcc/{bytecode => test}/kv.evm (100%) rename evmcc/{lll => test}/kv.lll (100%) rename evmcc/{bytecode => test/mem}/byte.evm (100%) rename evmcc/{lll => test/mem}/byte.lll (100%) rename evmcc/{bytecode => test/mem}/mem2.evm (100%) rename evmcc/{lll => test/mem}/mem2.lll (100%) rename evmcc/{bytecode => test/mem}/memtest1.evm (100%) rename evmcc/{lll => test/mem}/memtest1.lll (100%) rename evmcc/{bytecode => test/ret}/return1.evm (100%) rename evmcc/{lll => test/ret}/return1.lll (100%) rename evmcc/{bytecode => test/ret}/return2.evm (100%) rename evmcc/{lll => test/ret}/return2.lll (100%) rename evmcc/{bytecode => test/ret}/return_test.evm (100%) rename evmcc/{lll => test/ret}/return_test.lll (100%) rename evmcc/{bytecode => test/stack}/push_test.evm (100%) rename evmcc/{lll => test/stack}/push_test.lll (100%) rename evmcc/{bytecode => test/stack}/stack_test.evm (100%) rename evmcc/{lll => test/stack}/stack_test.lll (100%) rename evmcc/{bytecode => test/stack}/stackjump.evm (100%) rename evmcc/{lll => test/stack}/stackjump.lll (100%) diff --git a/evmcc/bytecode/if1.evm b/evmcc/bytecode/if1.evm deleted file mode 100644 index ee9009294..000000000 --- a/evmcc/bytecode/if1.evm +++ /dev/null @@ -1 +0,0 @@ -600160805460006080530b6016596003608054601b586002608054 diff --git a/evmcc/lll/if1.asm b/evmcc/lll/if1.asm deleted file mode 100644 index 4a938adce..000000000 --- a/evmcc/lll/if1.asm +++ /dev/null @@ -1,21 +0,0 @@ -.code: - PUSH 1 - PUSH 128 - MSTORE - PUSH 0 - PUSH 128 - MLOAD - GT - PUSH [tag0] - JUMPI - PUSH 3 - PUSH 128 - MSTORE - PUSH [tag1] - JUMP -tag0: - PUSH 2 - PUSH 128 - MSTORE -tag1: - diff --git a/evmcc/lll/if1.lll b/evmcc/lll/if1.lll deleted file mode 100644 index 7984807c1..000000000 --- a/evmcc/lll/if1.lll +++ /dev/null @@ -1,5 +0,0 @@ -{ - [i] 1 - - ( if (> @i 0) [i] 2 [i] 3 ) -} diff --git a/evmcc/bytecode/arithmetic_test.evm b/evmcc/test/arith/arith1.evm similarity index 100% rename from evmcc/bytecode/arithmetic_test.evm rename to evmcc/test/arith/arith1.evm diff --git a/evmcc/lll/arithmetic_test.lll b/evmcc/test/arith/arith1.lll similarity index 100% rename from evmcc/lll/arithmetic_test.lll rename to evmcc/test/arith/arith1.lll diff --git a/evmcc/bytecode/fib1.evm b/evmcc/test/arith/fib1.evm similarity index 100% rename from evmcc/bytecode/fib1.evm rename to evmcc/test/arith/fib1.evm diff --git a/evmcc/lll/fib1.lll b/evmcc/test/arith/fib1.lll similarity index 100% rename from evmcc/lll/fib1.lll rename to evmcc/test/arith/fib1.lll diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/test/ext/ext_test.evm similarity index 100% rename from evmcc/bytecode/ext_test.evm rename to evmcc/test/ext/ext_test.evm diff --git a/evmcc/lll/ext_test.lll b/evmcc/test/ext/ext_test.lll similarity index 100% rename from evmcc/lll/ext_test.lll rename to evmcc/test/ext/ext_test.lll diff --git a/evmcc/bytecode/store_test.evm b/evmcc/test/ext/store_test.evm similarity index 100% rename from evmcc/bytecode/store_test.evm rename to evmcc/test/ext/store_test.evm diff --git a/evmcc/lll/store_test.lll b/evmcc/test/ext/store_test.lll similarity index 100% rename from evmcc/lll/store_test.lll rename to evmcc/test/ext/store_test.lll diff --git a/evmcc/bytecode/for1.evm b/evmcc/test/jump/for1.evm similarity index 100% rename from evmcc/bytecode/for1.evm rename to evmcc/test/jump/for1.evm diff --git a/evmcc/lll/for1.lll b/evmcc/test/jump/for1.lll similarity index 100% rename from evmcc/lll/for1.lll rename to evmcc/test/jump/for1.lll diff --git a/evmcc/bytecode/for2.evm b/evmcc/test/jump/for2.evm similarity index 100% rename from evmcc/bytecode/for2.evm rename to evmcc/test/jump/for2.evm diff --git a/evmcc/lll/for2.lll b/evmcc/test/jump/for2.lll similarity index 100% rename from evmcc/lll/for2.lll rename to evmcc/test/jump/for2.lll diff --git a/evmcc/lll/when1.asm b/evmcc/test/jump/when1.asm similarity index 100% rename from evmcc/lll/when1.asm rename to evmcc/test/jump/when1.asm diff --git a/evmcc/bytecode/when1.evm b/evmcc/test/jump/when1.evm similarity index 100% rename from evmcc/bytecode/when1.evm rename to evmcc/test/jump/when1.evm diff --git a/evmcc/lll/when1.lll b/evmcc/test/jump/when1.lll similarity index 100% rename from evmcc/lll/when1.lll rename to evmcc/test/jump/when1.lll diff --git a/evmcc/bytecode/kv.evm b/evmcc/test/kv.evm similarity index 100% rename from evmcc/bytecode/kv.evm rename to evmcc/test/kv.evm diff --git a/evmcc/lll/kv.lll b/evmcc/test/kv.lll similarity index 100% rename from evmcc/lll/kv.lll rename to evmcc/test/kv.lll diff --git a/evmcc/bytecode/byte.evm b/evmcc/test/mem/byte.evm similarity index 100% rename from evmcc/bytecode/byte.evm rename to evmcc/test/mem/byte.evm diff --git a/evmcc/lll/byte.lll b/evmcc/test/mem/byte.lll similarity index 100% rename from evmcc/lll/byte.lll rename to evmcc/test/mem/byte.lll diff --git a/evmcc/bytecode/mem2.evm b/evmcc/test/mem/mem2.evm similarity index 100% rename from evmcc/bytecode/mem2.evm rename to evmcc/test/mem/mem2.evm diff --git a/evmcc/lll/mem2.lll b/evmcc/test/mem/mem2.lll similarity index 100% rename from evmcc/lll/mem2.lll rename to evmcc/test/mem/mem2.lll diff --git a/evmcc/bytecode/memtest1.evm b/evmcc/test/mem/memtest1.evm similarity index 100% rename from evmcc/bytecode/memtest1.evm rename to evmcc/test/mem/memtest1.evm diff --git a/evmcc/lll/memtest1.lll b/evmcc/test/mem/memtest1.lll similarity index 100% rename from evmcc/lll/memtest1.lll rename to evmcc/test/mem/memtest1.lll diff --git a/evmcc/bytecode/return1.evm b/evmcc/test/ret/return1.evm similarity index 100% rename from evmcc/bytecode/return1.evm rename to evmcc/test/ret/return1.evm diff --git a/evmcc/lll/return1.lll b/evmcc/test/ret/return1.lll similarity index 100% rename from evmcc/lll/return1.lll rename to evmcc/test/ret/return1.lll diff --git a/evmcc/bytecode/return2.evm b/evmcc/test/ret/return2.evm similarity index 100% rename from evmcc/bytecode/return2.evm rename to evmcc/test/ret/return2.evm diff --git a/evmcc/lll/return2.lll b/evmcc/test/ret/return2.lll similarity index 100% rename from evmcc/lll/return2.lll rename to evmcc/test/ret/return2.lll diff --git a/evmcc/bytecode/return_test.evm b/evmcc/test/ret/return_test.evm similarity index 100% rename from evmcc/bytecode/return_test.evm rename to evmcc/test/ret/return_test.evm diff --git a/evmcc/lll/return_test.lll b/evmcc/test/ret/return_test.lll similarity index 100% rename from evmcc/lll/return_test.lll rename to evmcc/test/ret/return_test.lll diff --git a/evmcc/bytecode/push_test.evm b/evmcc/test/stack/push_test.evm similarity index 100% rename from evmcc/bytecode/push_test.evm rename to evmcc/test/stack/push_test.evm diff --git a/evmcc/lll/push_test.lll b/evmcc/test/stack/push_test.lll similarity index 100% rename from evmcc/lll/push_test.lll rename to evmcc/test/stack/push_test.lll diff --git a/evmcc/bytecode/stack_test.evm b/evmcc/test/stack/stack_test.evm similarity index 100% rename from evmcc/bytecode/stack_test.evm rename to evmcc/test/stack/stack_test.evm diff --git a/evmcc/lll/stack_test.lll b/evmcc/test/stack/stack_test.lll similarity index 100% rename from evmcc/lll/stack_test.lll rename to evmcc/test/stack/stack_test.lll diff --git a/evmcc/bytecode/stackjump.evm b/evmcc/test/stack/stackjump.evm similarity index 100% rename from evmcc/bytecode/stackjump.evm rename to evmcc/test/stack/stackjump.evm diff --git a/evmcc/lll/stackjump.lll b/evmcc/test/stack/stackjump.lll similarity index 100% rename from evmcc/lll/stackjump.lll rename to evmcc/test/stack/stackjump.lll From 23c54b6ee463049d5fc6e7c2ad672f21b20598bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 11:29:20 +0200 Subject: [PATCH 150/396] Using ExtVM provided by test engine --- libevmjit/ExecutionEngine.cpp | 39 +++++++++++++++++++---------------- libevmjit/ExecutionEngine.h | 3 ++- libevmjit/Runtime.cpp | 6 +++--- libevmjit/Runtime.h | 4 ++-- libevmjit/VM.cpp | 2 +- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index bac15a478..252cf7aff 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -36,7 +36,7 @@ ExecutionEngine::ExecutionEngine() extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; } -int ExecutionEngine::run(std::unique_ptr _module) +int ExecutionEngine::run(std::unique_ptr _module, ExtVMFace* _ext) { auto module = _module.get(); // Keep ownership of the module in _module @@ -81,26 +81,29 @@ int ExecutionEngine::run(std::unique_ptr _module) exec->finalizeObject(); // Create fake ExtVM interface - auto ext = std::make_unique(); - ext->myAddress = Address(1122334455667788); - ext->caller = Address(0xfacefacefaceface); - ext->origin = Address(101010101010101010); - ext->value = 0xabcd; - ext->gasPrice = 1002; - ext->previousBlock.hash = u256(1003); - ext->currentBlock.coinbaseAddress = Address(1004); - ext->currentBlock.timestamp = 1005; - ext->currentBlock.number = 1006; - ext->currentBlock.difficulty = 1007; - ext->currentBlock.gasLimit = 1008; - std::string calldata = "Hello the Beautiful World of Ethereum!"; - ext->data = calldata; - unsigned char fakecode[] = {0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf}; - ext->code = decltype(ext->code)(fakecode, 8); + if (!_ext) + { + auto _ext = new ExtVMFace; + _ext->myAddress = Address(1122334455667788); + _ext->caller = Address(0xfacefacefaceface); + _ext->origin = Address(101010101010101010); + _ext->value = 0xabcd; + _ext->gasPrice = 1002; + _ext->previousBlock.hash = u256(1003); + _ext->currentBlock.coinbaseAddress = Address(1004); + _ext->currentBlock.timestamp = 1005; + _ext->currentBlock.number = 1006; + _ext->currentBlock.difficulty = 1007; + _ext->currentBlock.gasLimit = 1008; + std::string calldata = "Hello the Beautiful World of Ethereum!"; + _ext->data = calldata; + unsigned char fakecode[] = {0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf}; + _ext->code = decltype(_ext->code)(fakecode, 8); + } // Init runtime uint64_t gas = 100; - Runtime runtime(gas, std::move(ext)); + Runtime runtime(gas, *_ext); auto entryFunc = module->getFunction("main"); if (!entryFunc) diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index f6fb49276..12ca66302 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -4,6 +4,7 @@ #include #include +#include namespace dev { @@ -17,7 +18,7 @@ class ExecutionEngine public: ExecutionEngine(); - int run(std::unique_ptr module); + int run(std::unique_ptr module, ExtVMFace* _ext = nullptr); bytes returnData; }; diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index d85f484b3..448d25f92 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -19,8 +19,8 @@ extern "C" EXPORT i256 gas; } -Runtime::Runtime(u256 _gas, std::unique_ptr _ext): - m_ext(std::move(_ext)) +Runtime::Runtime(u256 _gas, ExtVMFace& _ext): + m_ext(_ext) { assert(!g_runtime); g_runtime = this; @@ -44,7 +44,7 @@ MemoryImpl& Runtime::getMemory() ExtVMFace& Runtime::getExt() { - return *g_runtime->m_ext; + return g_runtime->m_ext; } u256 Runtime::getGas() diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 0312e305b..165f47e06 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -27,7 +27,7 @@ using MemoryImpl = bytes; class Runtime { public: - Runtime(u256 _gas, std::unique_ptr _ext); + Runtime(u256 _gas, ExtVMFace& _ext); ~Runtime(); Runtime(const Runtime&) = delete; @@ -41,7 +41,7 @@ public: private: StackImpl m_stack; MemoryImpl m_memory; - std::unique_ptr m_ext; + ExtVMFace& m_ext; }; } diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 51cd7c5a3..b4139f8bf 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -19,7 +19,7 @@ bytes VM::go(ExtVMFace& _ext) module->dump(); ExecutionEngine engine; - auto exitCode = engine.run(std::move(module)); + auto exitCode = engine.run(std::move(module), &_ext); switch (exitCode) { From 9a3a62cccdb2c88e99b78b2b8e799bff4a0254d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 11:59:12 +0200 Subject: [PATCH 151/396] Using gas provided by test engine and fix for creating fake ExtVMFace. --- evmcc/evmcc.cpp | 3 ++- libevmjit/ExecutionEngine.cpp | 9 ++++----- libevmjit/ExecutionEngine.h | 2 +- libevmjit/VM.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 600980d44..9cf731419 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -112,7 +112,8 @@ int main(int argc, char** argv) auto engine = eth::jit::ExecutionEngine(); auto module = eth::jit::Compiler().compile({bytecode.data(), bytecode.size()}); module->dump(); - auto result = engine.run(std::move(module)); + u256 gas = 10000; + auto result = engine.run(std::move(module), gas); return result; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 252cf7aff..5390d82dd 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -36,7 +36,7 @@ ExecutionEngine::ExecutionEngine() extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; } -int ExecutionEngine::run(std::unique_ptr _module, ExtVMFace* _ext) +int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtVMFace* _ext) { auto module = _module.get(); // Keep ownership of the module in _module @@ -83,7 +83,7 @@ int ExecutionEngine::run(std::unique_ptr _module, ExtVMFace* _ext) // Create fake ExtVM interface if (!_ext) { - auto _ext = new ExtVMFace; + _ext = new ExtVMFace; _ext->myAddress = Address(1122334455667788); _ext->caller = Address(0xfacefacefaceface); _ext->origin = Address(101010101010101010); @@ -102,8 +102,7 @@ int ExecutionEngine::run(std::unique_ptr _module, ExtVMFace* _ext) } // Init runtime - uint64_t gas = 100; - Runtime runtime(gas, *_ext); + Runtime runtime(_gas, *_ext); auto entryFunc = module->getFunction("main"); if (!entryFunc) @@ -124,7 +123,7 @@ int ExecutionEngine::run(std::unique_ptr _module, ExtVMFace* _ext) else returnCode = static_cast(r); - gas = static_cast(Runtime::getGas()); + _gas = Runtime::getGas(); if (returnCode == ReturnCode::Return) { diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 12ca66302..15a4e6ef7 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -18,7 +18,7 @@ class ExecutionEngine public: ExecutionEngine(); - int run(std::unique_ptr module, ExtVMFace* _ext = nullptr); + int run(std::unique_ptr module, u256& _gas, ExtVMFace* _ext = nullptr); bytes returnData; }; diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index b4139f8bf..9e06fb6d0 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -19,7 +19,7 @@ bytes VM::go(ExtVMFace& _ext) module->dump(); ExecutionEngine engine; - auto exitCode = engine.run(std::move(module), &_ext); + auto exitCode = engine.run(std::move(module), m_gas, &_ext); switch (exitCode) { From ac276eaccee8b86df169d9af545e71a63ed18ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 12:30:42 +0200 Subject: [PATCH 152/396] Do not try to add additional cost (call instruction) to cost-block --- libevmjit/GasMeter.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 53c1e30e5..ac7f47d19 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -165,20 +165,21 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost) // If any uncommited block if (m_checkCall) { - if (m_blockCost == 0 && !_additionalCost) // Do not check 0 + if (m_blockCost == 0) // Do not check 0 { m_checkCall->eraseFromParent(); // Remove the gas check call m_checkCall = nullptr; return; } - llvm::Value* cost = Constant::get(m_blockCost); - if (_additionalCost) - cost = m_builder.CreateAdd(cost, _additionalCost); - - m_checkCall->setArgOperand(0, cost); // Update block cost in gas check call + m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block m_blockCost = 0; + + if (_additionalCost) + { + m_builder.CreateCall(m_gasCheckFunc, _additionalCost); + } } assert(m_blockCost == 0); } From a13a660315342f9db821bfc70c387f23ebd72d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 13:12:36 +0200 Subject: [PATCH 153/396] Fix for invalid jump table basic block --- libevmjit/Compiler.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index cbb6118f4..1e76e2fb7 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -927,6 +927,13 @@ void Compiler::linkBasicBlocks() completePhiNodes(*it); } } + + // Remove jump table block if not predecessors + if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } } void Compiler::dumpBasicBlockGraph(std::ostream& out) From 008953a37c24e01f98a2c8296b09d662d9eaa0da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 13:26:53 +0200 Subject: [PATCH 154/396] Limit debug output --- libevmjit/Compiler.cpp | 3 ++- libevmjit/VM.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1e76e2fb7..3d5d7b275 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -923,7 +923,8 @@ void Compiler::linkBasicBlocks() for (auto it = llvm::po_ext_begin(bb.second.llvm(), visitSet), end = llvm::po_ext_end(bb.second.llvm(), visitSet); it != end; ++it) { - std::cerr << it->getName().str() << std::endl; + // TODO: Use logger + //std::cerr << it->getName().str() << std::endl; completePhiNodes(*it); } } diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 9e06fb6d0..6b8b3e38b 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -16,7 +16,6 @@ namespace jit bytes VM::go(ExtVMFace& _ext) { auto module = Compiler().compile(_ext.code); - module->dump(); ExecutionEngine engine; auto exitCode = engine.run(std::move(module), m_gas, &_ext); From bcc6cd7056faf6b49ecbd9baca2f687dbb206780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 13:58:45 +0200 Subject: [PATCH 155/396] Turn on JIT testing with "--jit" command line parameter --- test/vm.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/vm.cpp b/test/vm.cpp index a7b785240..637ee77e9 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -512,7 +512,10 @@ void doTests(json_spirit::mValue& v, bool _fillin) u256 gas; try { - auto useJit = true; + auto argc = boost::unit_test::framework::master_test_suite().argc; + auto argv = boost::unit_test::framework::master_test_suite().argv; + + auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; if (useJit) { jit::VM vm(fev.gas); From 03f4a451aa00d7445b1577f87cd17c4a3c9a1e2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 15:58:20 +0200 Subject: [PATCH 156/396] Add support for direct jump outside the code - terminates with STOP --- libevmjit/Compiler.cpp | 21 +++++++++++++-------- libevmjit/Compiler.h | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 3d5d7b275..63ba83a77 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -67,9 +67,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) } // Create a block for the JUMP target. - ProgramCounter targetPC = val.convert_to(); - if (targetPC > bytecode.size()) - targetPC = bytecode.size(); + ProgramCounter targetPC = val < bytecode.size() ? val.convert_to() : bytecode.size(); splitPoints.insert(targetPC); ProgramCounter jumpPC = (next - bytecode.begin()); @@ -130,16 +128,23 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { + if (it->second >= bytecode.size()) + { + // Jumping out of code means STOP + m_directJumpTargets[it->first] = m_stopBB; + continue; + } + auto blockIter = basicBlocks.find(it->second); if (blockIter != basicBlocks.end()) { - m_directJumpTargets[it->first] = &(blockIter->second); + m_directJumpTargets[it->first] = blockIter->second.llvm(); } else { std::cerr << "Bad JUMP at PC " << it->first << ": " << it->second << " is not a valid PC\n"; - m_directJumpTargets[it->first] = m_badJumpBlock.get(); + m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); } } @@ -567,7 +572,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, // 1. this is not the first instruction in the block // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) // Otherwise generate a indirect jump (a switch). - BasicBlock* targetBlock = nullptr; + llvm::BasicBlock* targetBlock = nullptr; if (currentPC != basicBlock.begin()) { auto pairIter = m_directJumpTargets.find(currentPC); @@ -584,7 +589,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, // The target address is computed at compile time, // just pop it without looking... stack.pop(); - m_builder.CreateBr(targetBlock->llvm()); + m_builder.CreateBr(targetBlock); } else { @@ -606,7 +611,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, if (targetBlock) { stack.pop(); - m_builder.CreateCondBr(cond, targetBlock->llvm(), nextBasicBlock); + m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); } else { diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index f708898d6..8972322ec 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -46,7 +46,7 @@ private: /** * Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. */ - std::map m_directJumpTargets; + std::map m_directJumpTargets; /** * A list of possible blocks to which there may be indirect jumps. From a177ff9b126e2a9b8f7e738a16a77beb0b55d439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 17 Oct 2014 16:07:53 +0200 Subject: [PATCH 157/396] Disable test filling --- test/vm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/vm.cpp b/test/vm.cpp index 637ee77e9..d65b5d3d5 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -24,7 +24,7 @@ #include #include -#define FILL_TESTS +//#define FILL_TESTS using namespace std; using namespace json_spirit; From b8e60e3f42356fb38c381298938e0a54171461d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 16:08:15 +0200 Subject: [PATCH 158/396] Check if pushed item is a word --- libevmjit/BasicBlock.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 02c85165d..736e0a572 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -32,6 +32,7 @@ BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc) : void BasicBlock::Stack::push(llvm::Value* _value) { + assert(_value->getType() == Type::i256); m_backend.push_back(_value); } From 86c42ce1fad36327dfa7cfc5ccf9daac46b9776d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 16:08:59 +0200 Subject: [PATCH 159/396] Endianness handler --- libevmjit/Endianness.cpp | 24 ++++++++++++++++++++++++ libevmjit/Endianness.h | 22 ++++++++++++++++++++++ windows/LibEvmJit.vcxproj | 2 ++ windows/LibEvmJit.vcxproj.filters | 6 ++++++ 4 files changed, 54 insertions(+) create mode 100644 libevmjit/Endianness.cpp create mode 100644 libevmjit/Endianness.h diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp new file mode 100644 index 000000000..7de7b9514 --- /dev/null +++ b/libevmjit/Endianness.cpp @@ -0,0 +1,24 @@ + +#include "Endianness.h" + +#include + +#include "Type.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::Value* Endianness::toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +{ + // TODO: Native is Little Endian + auto bswap = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::i256); + return _builder.CreateCall(bswap, _word); +} + +} +} +} diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h new file mode 100644 index 000000000..7b449b4d8 --- /dev/null +++ b/libevmjit/Endianness.h @@ -0,0 +1,22 @@ + +#pragma once + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Endianness +{ +public: + + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word); +}; + +} +} +} diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index 1c71bb082..f516edf4f 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -126,6 +126,7 @@ + @@ -139,6 +140,7 @@ + diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters index a2008f971..593ce8195 100644 --- a/windows/LibEvmJit.vcxproj.filters +++ b/windows/LibEvmJit.vcxproj.filters @@ -39,6 +39,9 @@ libevmjit + + libevmjit + @@ -74,5 +77,8 @@ libevmjit + + libevmjit + \ No newline at end of file From e34d69aeb0340bf827434138acf4357ab69f24de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 16:14:11 +0200 Subject: [PATCH 160/396] BYTE reimplementation [Delivers #80911670] --- libevmjit/Compiler.cpp | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 63ba83a77..76daca792 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -15,6 +15,7 @@ #include "Ext.h" #include "GasMeter.h" #include "Utils.h" +#include "Endianness.h" namespace dev { @@ -420,21 +421,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, const auto byteNum = stack.pop(); auto value = stack.pop(); - /* - if (byteNum < 32) - use select - { - value <<= byteNum*8 - value >>= 31*8 - push value - } - else push 0 - */ - - // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 - - auto shbits = m_builder.CreateShl(byteNum, Constant::get(3)); - value = m_builder.CreateShl(value, shbits); - value = m_builder.CreateLShr(value, Constant::get(31 * 8)); + // + value = Endianness::toBE(m_builder, value); + auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); + auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); + value = m_builder.CreateZExt(byte, Type::i256); auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); From c2669fe3a87b370cf23f64ccb12f1508984c5152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 16:15:27 +0200 Subject: [PATCH 161/396] Make ExtVMFace polymorphic to give JIT hope for working --- libevm/ExtVMFace.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 1b0f9eaf5..eeae720f3 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -57,37 +57,37 @@ public: ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth); /// Get the code at the given location in code ROM. - byte getCode(u256 _n) const { return _n < code.size() ? code[(unsigned)_n] : 0; } + virtual byte getCode(u256 _n) const { return _n < code.size() ? code[(unsigned)_n] : 0; } /// Read storage location. - u256 store(u256) { return 0; } + virtual u256 store(u256) { return 0; } /// Write a value in storage. - void setStore(u256, u256) {} + virtual void setStore(u256, u256) {} /// Read address's balance. - u256 balance(Address) { return 0; } + virtual u256 balance(Address) { return 0; } /// Read address's code. - bytes const& codeAt(Address) { return NullBytes; } + virtual bytes const& codeAt(Address) { return NullBytes; } /// Subtract amount from account's balance. - void subBalance(u256) {} + virtual void subBalance(u256) {} /// Determine account's TX count. - u256 txCount(Address) { return 0; } + virtual u256 txCount(Address) { return 0; } /// Suicide the associated contract and give proceeds to the given address. - void suicide(Address) { suicides.insert(myAddress); } + virtual void suicide(Address) { suicides.insert(myAddress); } /// Create a new (contract) account. - h160 create(u256, u256*, bytesConstRef, bytesConstRef) { return h160(); } + virtual h160 create(u256, u256*, bytesConstRef, bytesConstRef) { return h160(); } /// Make a new message call. - bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; } + virtual bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; } /// Revert any changes made (by any of the other calls). - void revert() {} + virtual void revert() {} Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be). Address caller; ///< Address which sent the message (either equal to origin or a contract). From 40f23fceb364c0578f3fbd5550298ac2b26d8b28 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 20 Oct 2014 16:07:29 +0100 Subject: [PATCH 162/396] Defined dev::eth::FeeStructure::c_memoryGas and two other declared in FeeStructure. --- libevm/VM.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index e47237d5a..b2f7fea22 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -25,6 +25,10 @@ using namespace std; using namespace dev; using namespace dev::eth; +uint32_t const dev::eth::FeeStructure::c_memoryGas; +uint32_t const dev::eth::FeeStructure::c_txDataGas; +uint32_t const dev::eth::FeeStructure::c_txGas; + void VM::reset(u256 _gas) { m_gas = _gas; From 0abe8ab42e8ea8c9b0a2e9164352b7786887f40a Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 20 Oct 2014 16:12:00 +0100 Subject: [PATCH 163/396] Updated cmake files after moving the jit compiler to a lib. --- CMakeLists.txt | 1 + evmcc/CMakeLists.txt | 1 + test/CMakeLists.txt | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d055587c..150fb865c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,6 +157,7 @@ if (NOT LANGUAGES) endif() if (EVMCC) + add_subdirectory(libevmjit) add_subdirectory(evmcc) endif() diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index f09c327b8..ae9162162 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmjit) if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2e5366079..7dc226fb5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,6 +5,8 @@ aux_source_directory(. SRC_LIST) include_directories(..) link_directories(../libethcore) link_directories(../libethereum) +link_directories(../libevm) +link_directories(../libevmjit) file(GLOB HEADERS "*.h") add_executable(testeth ${SRC_LIST} ${HEADERS}) @@ -14,6 +16,8 @@ target_link_libraries(testeth ethcore) target_link_libraries(testeth secp256k1) target_link_libraries(testeth gmp) target_link_libraries(testeth ${CRYPTOPP_LS}) +target_link_libraries(testeth evm) +target_link_libraries(testeth evmjit) if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") From d173447b97787046edef5ced44400cae08b8e5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 17:36:26 +0200 Subject: [PATCH 164/396] Another round of fixing ExtVM interface --- libevm/ExtVMFace.h | 2 +- test/vm.cpp | 19 +++++++++++++++---- test/vm.h | 18 +++++++++--------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index eeae720f3..481b11eff 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -81,7 +81,7 @@ public: virtual void suicide(Address) { suicides.insert(myAddress); } /// Create a new (contract) account. - virtual h160 create(u256, u256*, bytesConstRef, bytesConstRef) { return h160(); } + virtual h160 create(u256, u256*, bytesConstRef, OnOpFunc const&) { return h160(); } /// Make a new message call. virtual bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; } diff --git a/test/vm.cpp b/test/vm.cpp index d65b5d3d5..80185f659 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -35,7 +35,7 @@ using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _depth) {} -h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc) +h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&) { Transaction t; t.value = _endowment; @@ -45,7 +45,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun m_s.noteSending(myAddress); m_ms.internal.resize(m_ms.internal.size() + 1); - auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); + auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); @@ -61,7 +61,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun return ret; } -bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc, Address _myAddressOverride = Address(), Address _codeAddressOverride = Address()) +bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride = Address(), Address _codeAddressOverride = Address()) { u256 contractgas = 0xffff; @@ -91,7 +91,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, if (!m_s.addresses().count(myAddress)) { m_ms.internal.resize(m_ms.internal.size() + 1); - auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); + auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); if (na != myAddress) @@ -588,6 +588,17 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); + //auto a = fev.addresses.at(fev.myAddress); + //auto b = test.addresses.at(fev.myAddress); + + //auto t = a == b; + //auto t0 = get<0>(a) == get<0>(b); + //auto t1 = get<1>(a) == get<1>(b); + //auto t2 = get<2>(a) == get<2>(b); + //auto t3 = get<3>(a) == get<3>(b); + + //BOOST_CHECK_EQUAL(get<0>(a), get<0>(b)); + BOOST_CHECK(test.toInt(o["gas"]) == gas); BOOST_CHECK(test.addresses == fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); diff --git a/test/vm.h b/test/vm.h index 34e0e855a..a9897bee3 100644 --- a/test/vm.h +++ b/test/vm.h @@ -53,15 +53,15 @@ public: FakeExtVM() {} FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth = 0); - u256 store(u256 _n) { return std::get<2>(addresses[myAddress])[_n]; } - void setStore(u256 _n, u256 _v) { std::get<2>(addresses[myAddress])[_n] = _v; } - u256 balance(Address _a) { return std::get<0>(addresses[_a]); } - void subBalance(u256 _a) { std::get<0>(addresses[myAddress]) -= _a; } - u256 txCount(Address _a) { return std::get<1>(addresses[_a]); } - void suicide(Address _a) { std::get<0>(addresses[_a]) += std::get<0>(addresses[myAddress]); addresses.erase(myAddress); } - bytes const& codeAt(Address _a) { return std::get<3>(addresses[_a]); } - h160 create(u256 _endowment, u256* _gas, bytesConstRef _init, eth::OnOpFunc); - bool call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, eth::OnOpFunc, Address, Address); + u256 store(u256 _n) override { return std::get<2>(addresses[myAddress])[_n]; } + void setStore(u256 _n, u256 _v) override { std::get<2>(addresses[myAddress])[_n] = _v; } + u256 balance(Address _a) override { return std::get<0>(addresses[_a]); } + void subBalance(u256 _a) override { std::get<0>(addresses[myAddress]) -= _a; } + u256 txCount(Address _a) override { return std::get<1>(addresses[_a]); } + void suicide(Address _a) override { std::get<0>(addresses[_a]) += std::get<0>(addresses[myAddress]); addresses.erase(myAddress); } + bytes const& codeAt(Address _a) override { return std::get<3>(addresses[_a]); } + h160 create(u256 _endowment, u256* _gas, bytesConstRef _init, eth::OnOpFunc const&) override; + bool call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, eth::OnOpFunc const&, Address, Address) override; void setTransaction(Address _caller, u256 _value, u256 _gasPrice, bytes const& _data); void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, std::map const& _storage, bytes const& _code); void set(Address _a, u256 _myBalance, u256 _myNonce, std::map const& _storage, bytes const& _code); From e193d2d0817e600924c1508b6ce356717e781ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 17:37:42 +0200 Subject: [PATCH 165/396] Another round of fixing ExtVM interface --- libevmjit/Ext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 5c4bb7c59..26ed962b2 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -310,7 +310,7 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* auto initOff = static_cast(llvm2eth(*_initOff)); auto initSize = static_cast(llvm2eth(*_initSize)); auto&& initRef = bytesConstRef(Runtime::getMemory().data() + initOff, initSize); - auto&& onOp = bytesConstRef(); // TODO: Handle that thing + OnOpFunc onOp{}; // TODO: Handle that thing h256 address = ext.create(endowment, &gas, initRef, onOp); *_address = address; } From 448e3141f67c4931a5c2246ca21f7fc11c4b21b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 17:49:09 +0200 Subject: [PATCH 166/396] Fixing Visual Studio compilation - these FeeStructure constants are weird --- libevm/FeeStructure.cpp | 6 ++++++ libevm/VM.cpp | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index aeeb19e27..b04dc113b 100644 --- a/libevm/FeeStructure.cpp +++ b/libevm/FeeStructure.cpp @@ -31,6 +31,12 @@ namespace dev namespace eth { +#ifndef _MSC_VER +uint32_t const FeeStructure::c_memoryGas; +uint32_t const FeeStructure::c_txDataGas; +uint32_t const FeeStructure::c_txGas; +#endif + uint32_t FeeStructure::getInstructionFee(Instruction _inst) { switch (_inst) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index b2f7fea22..e47237d5a 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -25,10 +25,6 @@ using namespace std; using namespace dev; using namespace dev::eth; -uint32_t const dev::eth::FeeStructure::c_memoryGas; -uint32_t const dev::eth::FeeStructure::c_txDataGas; -uint32_t const dev::eth::FeeStructure::c_txGas; - void VM::reset(u256 _gas) { m_gas = _gas; From 340a84fbf451716a348dd8131252dbe9abe2077f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 18:38:39 +0200 Subject: [PATCH 167/396] Throw exception if EVM program is not jitable instead of terminating to make tests going --- libevmjit/Compiler.cpp | 5 +---- libevmjit/ExecutionEngine.cpp | 13 ++----------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 34970c602..65f75c20f 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -901,10 +901,7 @@ void Compiler::linkBasicBlocks() // TODO: In case entry block is reached - report error auto predBB = findBasicBlock(*predIt); if (!predBB) - { - std::cerr << "Stack too small in " << _llbb->getName().str() << std::endl; - std::exit(1); - } + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Unsupported dynamic stack")); auto value = predBB->getStack().get(valueIdx); phi->addIncoming(value, predBB->llvm()); } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 5390d82dd..9ff4bed99 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -70,13 +70,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV auto exec = std::unique_ptr(builder.create()); if (!exec) - { - if (!errorMsg.empty()) - std::cerr << "error creating EE: " << errorMsg << std::endl; - else - std::cerr << "unknown error creating llvm::ExecutionEngine" << std::endl; - exit(1); - } + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment(errorMsg)); _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module exec->finalizeObject(); @@ -106,10 +100,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV auto entryFunc = module->getFunction("main"); if (!entryFunc) - { - std::cerr << "main function not found\n"; - exit(1); - } + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found")); ReturnCode returnCode; std::jmp_buf buf; From 79f93faa7de7f1e20a1730ae30d987430d06185e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 20 Oct 2014 18:57:06 +0200 Subject: [PATCH 168/396] Fix compiling empty bytecode --- libevmjit/Compiler.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 65f75c20f..19c90e244 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -33,16 +33,18 @@ Compiler::Compiler(): void Compiler::createBasicBlocks(bytesConstRef bytecode) { std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end - splitPoints.insert(0); // First basic block std::map directJumpTargets; std::vector indirectJumpTargets; - boost::dynamic_bitset<> validJumpTargets(bytecode.size()); + boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); + + splitPoints.insert(0); // First basic block + validJumpTargets[0] = true; for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) { ProgramCounter currentPC = curr - bytecode.begin(); - validJumpTargets[currentPC] = 1; + validJumpTargets[currentPC] = true; auto inst = static_cast(*curr); switch (inst) From 399ba5a855ecfa0547627f24b967e10d7f0a551a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 00:41:34 +0200 Subject: [PATCH 169/396] Updating Visual Studio project files --- windows/Ethereum.sln | 1 - windows/LLVM.props | 12 ++++++++++-- windows/LibEvmJit.vcxproj | 5 +++++ windows/TestEthereum.vcxproj | 11 +++++------ windows/evmcc.vcxproj | 15 ++++++++++----- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/windows/Ethereum.sln b/windows/Ethereum.sln index 33167a23b..c4ac205a7 100644 --- a/windows/Ethereum.sln +++ b/windows/Ethereum.sln @@ -43,7 +43,6 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "evmcc", "evmcc.vcxproj", "{D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}" ProjectSection(ProjectDependencies) = postProject {9C816740-5C11-4377-A3A7-46BE12F35FA0} = {9C816740-5C11-4377-A3A7-46BE12F35FA0} - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F} = {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibEvmJit", "LibEvmJit.vcxproj", "{9C816740-5C11-4377-A3A7-46BE12F35FA0}" diff --git a/windows/LLVM.props b/windows/LLVM.props index 708ff3085..3290a4f64 100644 --- a/windows/LLVM.props +++ b/windows/LLVM.props @@ -2,8 +2,9 @@ - ..\..\builds\llvm3.5 - ..\..\llvm-3.5.0\include;$(LLVMBuildDir)\include + ..\..\_build\llvm\$(Platform) + ..\..\llvm\include;$(LLVMBuildDir)\include + $(LLVMBuildDir)\$(Configuration)\lib @@ -11,6 +12,10 @@ $(LLVMIncludeDir);%(AdditionalIncludeDirectories) 4800;%(DisableSpecificWarnings) + + $(LLVMLibDir);%(AdditionalLibraryDirectories) + LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + @@ -19,5 +24,8 @@ $(LLVMIncludeDir) + + $(LLVMLibDir) + \ No newline at end of file diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index f516edf4f..3a62813c0 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -150,6 +150,11 @@ + + + {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} + + diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index b07124581..be475a949 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -108,7 +108,6 @@ Console true - LibEthereum.lib;LibEvmJit.lib;LibSecp256k1.lib;LibCryptoPP.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;../../_build/LibSecp256k1/x64_Debug;../../_build/LibCryptoPP/x64_Debug;%(AdditionalLibraryDirectories) @@ -155,11 +154,6 @@ true - - - {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} - - @@ -191,6 +185,11 @@ + + + {9c816740-5c11-4377-a3a7-46be12f35fa0} + + diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 6c1b72143..a93635e6b 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -21,6 +21,11 @@ + + + {9c816740-5c11-4377-a3a7-46be12f35fa0} + + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} Win32Proj @@ -58,21 +63,25 @@ + + + + @@ -110,7 +119,6 @@ Console true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -130,8 +138,7 @@ Console true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;../../_build/LibSecp256k1/x64_Debug;../../_build/LibCryptoPP/x64_Debug;%(AdditionalLibraryDirectories) - LibEthereum.lib;LibEvmJit.lib;LibSecp256k1.lib;LibCryptoPP.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + %(AdditionalDependencies) @@ -151,7 +158,6 @@ true true true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -174,7 +180,6 @@ true true true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;%(AdditionalLibraryDirectories) LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) From 9e8e9af60381c0e4e21d68b47686fe25c4c52280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 11:51:45 +0200 Subject: [PATCH 170/396] Remove dead code --- test/vm.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 80185f659..5cb2a7b7f 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -588,17 +588,6 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); - //auto a = fev.addresses.at(fev.myAddress); - //auto b = test.addresses.at(fev.myAddress); - - //auto t = a == b; - //auto t0 = get<0>(a) == get<0>(b); - //auto t1 = get<1>(a) == get<1>(b); - //auto t2 = get<2>(a) == get<2>(b); - //auto t3 = get<3>(a) == get<3>(b); - - //BOOST_CHECK_EQUAL(get<0>(a), get<0>(b)); - BOOST_CHECK(test.toInt(o["gas"]) == gas); BOOST_CHECK(test.addresses == fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); From 270cddef8b6b3490959d9a7428f6b1567abad3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 11:54:54 +0200 Subject: [PATCH 171/396] Enhance VM tests reports --- test/vm.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 5cb2a7b7f..91bb17c0c 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -588,8 +588,44 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); - BOOST_CHECK(test.toInt(o["gas"]) == gas); - BOOST_CHECK(test.addresses == fev.addresses); + BOOST_CHECK_EQUAL(test.toInt(o["gas"]), gas); + + auto& expectedAddrs = test.addresses; + auto& resultAddrs = fev.addresses; + for (auto&& expectedPair : expectedAddrs) + { + auto& expectedAddr = expectedPair.first; + auto resultAddrIt = resultAddrs.find(expectedAddr); + if (resultAddrIt == resultAddrs.end()) + BOOST_ERROR("Missing expected address " << expectedAddr); + else + { + auto& expectedState = expectedPair.second; + auto& resultState = resultAddrIt->second; + BOOST_CHECK_MESSAGE(std::get<0>(expectedState) == std::get<0>(resultState), expectedAddr << ": incorrect balance " << std::get<0>(resultState) << ", expected " << std::get<0>(expectedState)); + BOOST_CHECK_MESSAGE(std::get<1>(expectedState) == std::get<1>(resultState), expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState)); + BOOST_CHECK_MESSAGE(std::get<3>(expectedState) == std::get<3>(resultState), expectedAddr << ": incorrect code"); + + auto&& expectedStore = std::get<2>(expectedState); + auto&& resultStore = std::get<2>(resultState); + + for (auto&& expectedStorePair : expectedStore) + { + auto& expectedStoreKey = expectedStorePair.first; + auto resultStoreIt = resultStore.find(expectedStoreKey); + if (resultStoreIt == resultStore.end()) + BOOST_ERROR(expectedAddr << ": missing store key " << expectedStoreKey); + else + { + auto& expectedStoreValue = expectedStorePair.second; + auto& resultStoreValue = resultStoreIt->second; + BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); + } + } + } + } + + BOOST_CHECK(test.addresses == fev.addresses); // Just to make sure nothing missed BOOST_CHECK(test.callcreates == fev.callcreates); } } From 0a84ed39d8ab3c8fb9c107885f6e271d5a846ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 12:52:46 +0200 Subject: [PATCH 172/396] Handle endianness of MSTORE & MLOAD [#79877740] --- evmcc/test/mem/mstore1.evm | 1 + evmcc/test/mem/mstore1.lll | 6 ++++++ libevmjit/Endianness.cpp | 3 ++- libevmjit/Endianness.h | 7 ++++++- libevmjit/Memory.cpp | 6 +++++- 5 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 evmcc/test/mem/mstore1.evm create mode 100644 evmcc/test/mem/mstore1.lll diff --git a/evmcc/test/mem/mstore1.evm b/evmcc/test/mem/mstore1.evm new file mode 100644 index 000000000..ba6141ab1 --- /dev/null +++ b/evmcc/test/mem/mstore1.evm @@ -0,0 +1 @@ +6001600054 diff --git a/evmcc/test/mem/mstore1.lll b/evmcc/test/mem/mstore1.lll new file mode 100644 index 000000000..2d2ca32b5 --- /dev/null +++ b/evmcc/test/mem/mstore1.lll @@ -0,0 +1,6 @@ + +(asm ;; [] +1 +0 +MSTORE ;; [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] +) \ No newline at end of file diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index 7de7b9514..f0da5f9d4 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -12,9 +12,10 @@ namespace eth namespace jit { -llvm::Value* Endianness::toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +llvm::Value* Endianness::bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word) { // TODO: Native is Little Endian + assert(_word->getType() == Type::i256); auto bswap = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::i256); return _builder.CreateCall(bswap, _word); } diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h index 7b449b4d8..9234961c1 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -14,7 +14,12 @@ class Endianness { public: - static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word); + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswap(_builder, _word); } + + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswap(_builder, _word); } + +private: + static llvm::Value* bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word); }; } diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index d370a7f72..23d027ba4 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -14,6 +14,7 @@ #include "Type.h" #include "Runtime.h" #include "GasMeter.h" +#include "Endianness.h" namespace dev { @@ -117,12 +118,15 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet { llvm::Value* value = ++func->arg_begin(); value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); m_builder.CreateStore(value, ptr); m_builder.CreateRetVoid(); } else { - auto ret = m_builder.CreateLoad(ptr); + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); m_builder.CreateRet(ret); } From b283a07f76913e9eb0d6a29fd303fa15e2ace966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 14:23:19 +0200 Subject: [PATCH 173/396] Fix SHA3 instruction :) --- libevmjit/Compiler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 19c90e244..ab98b27d0 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -473,6 +473,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, memory.require(inOff, inSize); auto hash = ext.sha3(inOff, inSize); stack.push(hash); + break; } case Instruction::POP: From 71ccd3f353bdc12a3b528c6fd6e917f76f9290e4 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 14:29:27 +0100 Subject: [PATCH 174/396] Propagation of values between basic blocks (and the stack): initial implementation (probably buggy, but simple cases work). [#80895676] --- libevmjit/BasicBlock.cpp | 11 ++-- libevmjit/BasicBlock.h | 22 ++++--- libevmjit/Compiler.cpp | 134 +++++++++++++++++++++++++++------------ libevmjit/Compiler.h | 2 +- libevmjit/Stack.cpp | 69 ++++++++++++++++++++ libevmjit/Stack.h | 35 ++++++++++ 6 files changed, 218 insertions(+), 55 deletions(-) create mode 100644 libevmjit/Stack.cpp create mode 100644 libevmjit/Stack.h diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 736e0a572..927f1180b 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -30,20 +30,20 @@ BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc) : {} -void BasicBlock::Stack::push(llvm::Value* _value) +void BasicBlock::LocalStack::push(llvm::Value* _value) { assert(_value->getType() == Type::i256); m_backend.push_back(_value); } -llvm::Value* BasicBlock::Stack::pop() +llvm::Value* BasicBlock::LocalStack::pop() { auto top = get(0); m_backend.pop_back(); return top; } -llvm::Value* BasicBlock::Stack::get(size_t _index) +llvm::Value* BasicBlock::LocalStack::get(size_t _index) { if (_index >= m_backend.size()) { @@ -55,18 +55,19 @@ llvm::Value* BasicBlock::Stack::get(size_t _index) m_backend[i] = m_llvmBB->empty() ? llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB) : llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI()); + m_numRequiredStackItems += 1; } } return *(m_backend.rbegin() + _index); } -void BasicBlock::Stack::dup(size_t _index) +void BasicBlock::LocalStack::dup(size_t _index) { m_backend.push_back(get(_index)); } -void BasicBlock::Stack::swap(size_t _index) +void BasicBlock::LocalStack::swap(size_t _index) { assert(_index != 0); get(_index); // Create PHI nodes diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 71d8aa355..51a48c6e0 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -15,7 +15,7 @@ using ProgramCounter = uint64_t; // TODO: Rename class BasicBlock { public: - class Stack + class LocalStack { public: /// Pushes value on stack @@ -37,17 +37,23 @@ public: /// Size of the stack size_t size() const { return m_backend.size(); } + size_t initialSize() const { return m_numRequiredStackItems; } + private: - Stack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB) {} - Stack(const Stack&) = delete; - void operator=(const Stack&) = delete; + // LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB) {} + LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB), m_numRequiredStackItems(0) {} + LocalStack(LocalStack const&) = delete; + void operator=(LocalStack const&) = delete; friend BasicBlock; private: std::vector m_backend; - /// LLVM Basic Block where phi nodes are inserted - llvm::BasicBlock* const m_llvmBB; + /** Basic block into which phi nodes are inserted */ + llvm::BasicBlock* m_llvmBB; + + /** Number of items required on the EVM stack at the beginning of the block */ + size_t m_numRequiredStackItems; }; /// Basic block name prefix. The rest is beging instruction index. @@ -62,7 +68,7 @@ public: operator llvm::BasicBlock*() { return m_llvmBB; } llvm::BasicBlock* llvm() { return m_llvmBB; } - Stack& getStack() { return m_stack; } + LocalStack& getStack() { return m_stack; } ProgramCounter begin() { return m_beginInstIdx; } ProgramCounter end() { return m_endInstIdx; } @@ -74,7 +80,7 @@ private: /// Basic black state vector (stack) - current/end values and their positions on stack /// @internal Must be AFTER m_llvmBB - Stack m_stack; + LocalStack m_stack; }; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 34970c602..35e88f045 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -12,6 +12,7 @@ #include "Type.h" #include "Memory.h" +#include "Stack.h" #include "Ext.h" #include "GasMeter.h" #include "Utils.h" @@ -172,6 +173,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) GasMeter gasMeter(m_builder); Memory memory(m_builder, gasMeter); Ext ext(m_builder); + Stack stack(m_builder); m_builder.CreateBr(basicBlocks.begin()->second); @@ -214,7 +216,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) m_builder.CreateBr(m_badJumpBlock->llvm()); } - linkBasicBlocks(); + linkBasicBlocks(stack); return module; } @@ -868,61 +870,111 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } -void Compiler::linkBasicBlocks() +void Compiler::linkBasicBlocks(Stack& stack) { - /// Helper function that finds basic block given LLVM basic block pointer - auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock* + struct BBInfo { - // TODO: Fix for finding jumpTableBlock - if (_llbb == this->m_jumpTableBlock->llvm()) - return this->m_jumpTableBlock.get(); - - for (auto&& bb : this->basicBlocks) - if (_llbb == bb.second.llvm()) - return &bb.second; - return nullptr; - - // Name is used to get basic block index (index of first instruction) - // TODO: If basicBlocs are still a map - multikey map can be used - //auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2); - //auto idx = std::stoul(idxStr); - //return basicBlocks.find(idx)->second; + BasicBlock& bblock; + std::vector predecessors; + size_t inputItems; + size_t outputItems; + + BBInfo(BasicBlock& _bblock) + : bblock(_bblock), + predecessors(), + inputItems(_bblock.getStack().initialSize()), + outputItems(_bblock.getStack().size()) + {} }; - auto completePhiNodes = [findBasicBlock](llvm::BasicBlock* _llbb) -> void + std::map cfg; + + // Create nodes in cfg + for (auto& pair : this->basicBlocks) + { + auto& bb = pair.second; + cfg.emplace(std::piecewise_construct, + std::forward_as_tuple(bb.llvm()), + std::forward_as_tuple(bb)); + } + + auto& entryBlock = m_mainFunc->getEntryBlock(); + + // Create edges in cfg + for (auto& pair : cfg) + { + auto bbPtr = pair.first; + auto& bbInfo = pair.second; + + for (auto predIt = llvm::pred_begin(bbPtr); predIt != llvm::pred_end(bbPtr); ++predIt) + { + if (*predIt != &entryBlock) + bbInfo.predecessors.push_back(&cfg.find(*predIt)->second); + } + } + + // Iteratively compute inputs and outputs of each block, until reaching fixpoint. + bool valuesChanged = true; + while (valuesChanged) { - size_t valueIdx = 0; - auto firstNonPhi = _llbb->getFirstNonPHI(); - for (auto instIt = _llbb->begin(); &*instIt != firstNonPhi; ++instIt, ++valueIdx) + valuesChanged = false; + for (auto& pair : cfg) { - auto phi = llvm::cast(instIt); - for (auto predIt = llvm::pred_begin(_llbb); predIt != llvm::pred_end(_llbb); ++predIt) + auto& bbInfo = pair.second; + + for (auto predInfo : bbInfo.predecessors) { - // TODO: In case entry block is reached - report error - auto predBB = findBasicBlock(*predIt); - if (!predBB) + if (predInfo->outputItems < bbInfo.inputItems) + { + bbInfo.inputItems = predInfo->outputItems; + valuesChanged = true; + } + else if (predInfo->outputItems > bbInfo.inputItems) { - std::cerr << "Stack too small in " << _llbb->getName().str() << std::endl; - std::exit(1); + predInfo->outputItems = bbInfo.inputItems; + valuesChanged = true; } - auto value = predBB->getStack().get(valueIdx); - phi->addIncoming(value, predBB->llvm()); } } - }; + } - - // TODO: It is crappy visiting of basic blocks. - llvm::SmallPtrSet visitSet; - for (auto&& bb : basicBlocks) // TODO: External loop is to visit unreable blocks that can also have phi nodes + // Propagate values between blocks. + for (auto& pair : cfg) { - for (auto it = llvm::po_ext_begin(bb.second.llvm(), visitSet), - end = llvm::po_ext_end(bb.second.llvm(), visitSet); it != end; ++it) + auto llbb = pair.first; + auto& bbInfo = pair.second; + auto& bblock = bbInfo.bblock; + + // Complete phi nodes for the top bbInfo.inputItems placeholder values + auto instrIter = llbb->begin(); + for (size_t valueIdx = 0; valueIdx < bbInfo.inputItems; ++instrIter, ++valueIdx) { - // TODO: Use logger - //std::cerr << it->getName().str() << std::endl; - completePhiNodes(*it); + auto phi = llvm::cast(instrIter); + for (auto predIt : bbInfo.predecessors) + { + assert(valueIdx < predIt->bblock.getStack().size()); + auto value = predIt->bblock.getStack().get(valueIdx); + phi->addIncoming(value, predIt->bblock.llvm()); + } + } + + // Turn the remaining phi nodes into stack.pop's. + m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI())); + for (; llvm::isa(*instrIter); ) + { + auto phi = llvm::cast(instrIter); + auto value = stack.popWord(); + phi->replaceAllUsesWith(value); + ++ instrIter; + phi->eraseFromParent(); } + + // Emit stack push's at the end of the block, just before the terminator; + m_builder.SetInsertPoint(llbb, -- llbb->end()); + auto localStackSize = bblock.getStack().size(); + assert(localStackSize >= bbInfo.outputItems); + for (size_t i = 0; i < localStackSize - bbInfo.outputItems; ++i) + stack.pushWord(bblock.getStack().get(localStackSize - 1 - i)); } // Remove jump table block if not predecessors diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 8972322ec..ac6277e7b 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -33,7 +33,7 @@ private: void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); - void linkBasicBlocks(); + void linkBasicBlocks(class Stack& stack); llvm::IRBuilder<> m_builder; diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp new file mode 100644 index 000000000..772e6255b --- /dev/null +++ b/libevmjit/Stack.cpp @@ -0,0 +1,69 @@ +#include "Stack.h" +#include "Runtime.h" + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Stack::Stack(llvm::IRBuilder<>& _builder) + : CompilerHelper(_builder) +{ + auto i256Ty = m_builder.getIntNTy(256); + auto i256PtrTy = i256Ty->getPointerTo(); + + m_arg = m_builder.CreateAlloca(i256Ty, nullptr, "stack.retVal"); + + using namespace llvm; + using Linkage = GlobalValue::LinkageTypes; + + auto module = getModule(); + m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_push", module); + m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_pop", module); +} + +Stack::~Stack() +{} + +llvm::Instruction* Stack::popWord() +{ + m_builder.CreateCall(m_pop, m_arg); + return m_builder.CreateLoad(m_arg); +} + +void Stack::pushWord(llvm::Value* _word) +{ + m_builder.CreateStore(_word, m_arg); + m_builder.CreateCall(m_push, m_arg); +} + +} +} +} + +extern "C" +{ + +using namespace dev::eth::jit; + +EXPORT void stack_pop(i256* _ret) +{ + auto& stack = Runtime::getStack(); + assert(stack.size() > 0); + *_ret = stack.back(); + stack.pop_back(); +} + +EXPORT void stack_push(i256* _word) +{ + auto& stack = Runtime::getStack(); + stack.push_back(*_word); +} + +} // extern "C" + diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h new file mode 100644 index 000000000..5e1ac0f39 --- /dev/null +++ b/libevmjit/Stack.h @@ -0,0 +1,35 @@ +#pragma once + +#include "CompilerHelper.h" + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder); + virtual ~Stack(); + + void pushWord(llvm::Value* _word); + llvm::Instruction* popWord(); + +private: + llvm::Function* m_push; + llvm::Function* m_pop; + + llvm::Value* m_arg; +}; + + +} +} +} + + From ceb6d86fa35bcdbaa64b33aa5685bfe63c48e244 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 14:52:43 +0100 Subject: [PATCH 175/396] added missing CMakeLists.txt --- libevmjit/CMakeLists.txt | 60 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 libevmjit/CMakeLists.txt diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt new file mode 100644 index 000000000..f461c16cf --- /dev/null +++ b/libevmjit/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_policy(SET CMP0015 NEW) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") + +aux_source_directory(. SRC_LIST) + +set(EXECUTABLE evmjit) + +file(GLOB HEADERS "*.h") +if (EVMJIT_STATIC) + add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) +else() + add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) +endif() + +include_directories(..) + +target_link_libraries(${EXECUTABLE} devcore) +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) + target_link_libraries(${EXECUTABLE} gdi32) + target_link_libraries(${EXECUTABLE} ws2_32) + target_link_libraries(${EXECUTABLE} mswsock) + target_link_libraries(${EXECUTABLE} shlwapi) + 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 + +find_package(LLVM REQUIRED CONFIG) + +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +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(evmjit ${llvm_libs}) + +# end of LLVM specific commands + + + +install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + +cmake_policy(SET CMP0015 NEW) From ca016033888ce10df246ce6a8ec6235913210416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 15:55:29 +0200 Subject: [PATCH 176/396] Remove unreachable basic blocks before "linking" --- libevmjit/Compiler.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index ab98b27d0..fe720b811 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -911,7 +911,26 @@ void Compiler::linkBasicBlocks() } }; - + // Remove dead basic blocks + auto sthErased = false; + do + { + sthErased = false; + for (auto it = basicBlocks.begin(); it != basicBlocks.end();) + { + auto llvmBB = it->second.llvm(); + if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) + { + llvmBB->eraseFromParent(); + basicBlocks.erase(it++); + sthErased = true; + } + else + ++it; + } + } + while (sthErased); + // TODO: It is crappy visiting of basic blocks. llvm::SmallPtrSet visitSet; for (auto&& bb : basicBlocks) // TODO: External loop is to visit unreable blocks that can also have phi nodes From 6c702a178d7eb2b3bb12983d266ed687a203d74f Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 15:00:09 +0100 Subject: [PATCH 177/396] cmake: added dependency on libevmjit to target createRandomTest --- test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 962d82ca5..bb3dd9ead 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,6 +25,7 @@ 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 ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") From 9a257917d322b59e8ef93e00eff3517f6057af36 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 15:00:43 +0100 Subject: [PATCH 178/396] minor changes in the compiler driver --- evmcc/evmcc.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 9cf731419..3cd06d5a8 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -91,12 +91,12 @@ int main(int argc, char** argv) std::cout << assembly << std::endl; } - if (opt_compile) + if (opt_compile || opt_interpret) { auto compiler = eth::jit::Compiler(); auto module = compiler.compile({bytecode.data(), bytecode.size()}); - llvm::raw_os_ostream out(std::cout); - module->print(out, nullptr); + + module->dump(); if (opt_dump_graph) { @@ -105,17 +105,15 @@ int main(int argc, char** argv) ofs.close(); std::cout << "Basic blocks graph written to block.dot\n"; } - } - if (opt_interpret) - { - auto engine = eth::jit::ExecutionEngine(); - auto module = eth::jit::Compiler().compile({bytecode.data(), bytecode.size()}); - module->dump(); - u256 gas = 10000; - auto result = engine.run(std::move(module), gas); - return result; - } + if (opt_interpret) + { + auto engine = eth::jit::ExecutionEngine(); + u256 gas = 10000; + auto result = engine.run(std::move(module), gas); + return result; + } + } return 0; } From 5eeb082ae0918b1e2c52607058c95818fe27e7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 16:06:30 +0200 Subject: [PATCH 179/396] Remove unreachable basic blocks before "linking" --- libevmjit/Compiler.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index a88797413..ef8eb2f2d 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -875,6 +875,25 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, void Compiler::linkBasicBlocks(Stack& stack) { + // Remove dead basic blocks + auto sthErased = false; + do + { + sthErased = false; + for (auto it = basicBlocks.begin(); it != basicBlocks.end();) + { + auto llvmBB = it->second.llvm(); + if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) + { + llvmBB->eraseFromParent(); + basicBlocks.erase(it++); + sthErased = true; + } + else + ++it; + } + } while (sthErased); + struct BBInfo { BasicBlock& bblock; From baf935b31c644c663c0d7b1701d1e44d5bca3620 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 15:53:51 +0100 Subject: [PATCH 180/396] Handling pop() from the empty EVM stack. [#80895676] --- libevmjit/Compiler.cpp | 11 +++++++---- libevmjit/Stack.cpp | 8 ++++++++ libevmjit/Type.h | 1 + libevmjit/VM.cpp | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index a88797413..640561ad9 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -925,6 +925,9 @@ void Compiler::linkBasicBlocks(Stack& stack) { auto& bbInfo = pair.second; + if (bbInfo.predecessors.empty()) + bbInfo.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false + for (auto predInfo : bbInfo.predecessors) { if (predInfo->outputItems < bbInfo.inputItems) @@ -996,11 +999,11 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) std::vector blocks; for (auto& pair : this->basicBlocks) - { blocks.push_back(&pair.second); - } - blocks.push_back(m_jumpTableBlock.get()); - blocks.push_back(m_badJumpBlock.get()); + if (m_jumpTableBlock.get()) + blocks.push_back(m_jumpTableBlock.get()); + if (m_badJumpBlock.get()) + blocks.push_back(m_badJumpBlock.get()); // Output nodes for (auto bb : blocks) diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 772e6255b..ce7d09471 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -1,5 +1,8 @@ #include "Stack.h" #include "Runtime.h" +#include "Type.h" + +#include #include #include @@ -51,9 +54,14 @@ extern "C" using namespace dev::eth::jit; +extern std::jmp_buf* rt_jmpBuf; + EXPORT void stack_pop(i256* _ret) { auto& stack = Runtime::getStack(); + if (stack.size() == 0) + longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + assert(stack.size() > 0); *_ret = stack.back(); stack.pop_back(); diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 06907b7df..a03bfac38 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -39,6 +39,7 @@ enum class ReturnCode BadJumpDestination = 101, OutOfGas = 102, + StackTooSmall = 103 }; struct Constant diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 6b8b3e38b..16011241e 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -26,6 +26,8 @@ bytes VM::go(ExtVMFace& _ext) BOOST_THROW_EXCEPTION(BadJumpDestination()); case 102: BOOST_THROW_EXCEPTION(OutOfGas()); + case 103: + BOOST_THROW_EXCEPTION(StackTooSmall(1,0)); } return std::move(engine.returnData); From 12ccd5d44ff094b1baf3e4d50193dfd3c03d1038 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 16:24:53 +0100 Subject: [PATCH 181/396] added assert in linkBasicBlocks() --- libevmjit/Compiler.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index f6093b374..bf77901cd 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -892,7 +892,16 @@ void Compiler::linkBasicBlocks(Stack& stack) else ++it; } - } while (sthErased); + } + while (sthErased); + + // Remove jump table block if no predecessors + if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } + struct BBInfo { @@ -931,7 +940,11 @@ void Compiler::linkBasicBlocks(Stack& stack) for (auto predIt = llvm::pred_begin(bbPtr); predIt != llvm::pred_end(bbPtr); ++predIt) { if (*predIt != &entryBlock) - bbInfo.predecessors.push_back(&cfg.find(*predIt)->second); + { + auto predInfoEntry = cfg.find(*predIt); + assert(predInfoEntry != cfg.end()); + bbInfo.predecessors.push_back(&predInfoEntry->second); + } } } @@ -1001,13 +1014,6 @@ void Compiler::linkBasicBlocks(Stack& stack) for (size_t i = 0; i < localStackSize - bbInfo.outputItems; ++i) stack.pushWord(bblock.getStack().get(localStackSize - 1 - i)); } - - // Remove jump table block if not predecessors - if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) - { - m_jumpTableBlock->llvm()->eraseFromParent(); - m_jumpTableBlock.reset(); - } } void Compiler::dumpBasicBlockGraph(std::ostream& out) From 52bc5c6ca92338cdbac0652c75a2d97fde4a277a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 17:35:18 +0200 Subject: [PATCH 182/396] Handle endianness for CALLDATALOAD correctly [#79877740] --- libevmjit/Ext.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 26ed962b2..ca0a83307 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -8,6 +8,7 @@ #include #include "Runtime.h" +#include "Endianness.h" using namespace llvm; @@ -145,7 +146,8 @@ Value* Ext::calldataload(Value* _index) { m_builder.CreateStore(_index, m_args[0]); m_builder.CreateCall(m_calldataload, m_args); - return m_builder.CreateLoad(m_args[1]); + auto ret = m_builder.CreateLoad(m_args[1]); + return Endianness::toNative(m_builder, ret); } Value* Ext::bswap(Value* _value) @@ -282,8 +284,8 @@ EXPORT void ext_calldataload(i256* _index, i256* _value) auto index = static_cast(llvm2eth(*_index)); assert(index + 31 > index); // TODO: Handle large index auto b = reinterpret_cast(_value); - for (size_t i = index, j = 31; i <= index + 31; ++i, --j) - b[j] = i < Runtime::getExt().data.size() ? Runtime::getExt().data[i] : 0; + for (size_t i = index, j = 0; i <= index + 31; ++i, ++j) + b[j] = i < Runtime::getExt().data.size() ? Runtime::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 } From f778b4eba710d133692963d3b8378bc59820837c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 17:44:48 +0200 Subject: [PATCH 183/396] Comment: storage uses native endianness [#79877740] --- libevmjit/Ext.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index ca0a83307..98cb791e0 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -109,7 +109,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder): llvm::Value* Ext::store(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateCall(m_store, m_args); + m_builder.CreateCall(m_store, m_args); // Uses native endianness return m_builder.CreateLoad(m_args[1]); } @@ -117,7 +117,7 @@ void Ext::setStore(llvm::Value* _index, llvm::Value* _value) { m_builder.CreateStore(_index, m_args[0]); m_builder.CreateStore(_value, m_args[1]); - m_builder.CreateCall(m_setStore, m_args); + m_builder.CreateCall(m_setStore, m_args); // Uses native endianness } Value* Ext::getDataElem(unsigned _index, const Twine& _name) @@ -268,7 +268,7 @@ EXPORT void ext_init(ExtData* _extData) EXPORT void ext_store(i256* _index, i256* _value) { auto index = llvm2eth(*_index); - auto value = Runtime::getExt().store(index); + auto value = Runtime::getExt().store(index); // Interface uses native endianness *_value = eth2llvm(value); } @@ -276,7 +276,7 @@ EXPORT void ext_setStore(i256* _index, i256* _value) { auto index = llvm2eth(*_index); auto value = llvm2eth(*_value); - Runtime::getExt().setStore(index, value); + Runtime::getExt().setStore(index, value); // Interface uses native endianness } EXPORT void ext_calldataload(i256* _index, i256* _value) From 847d5f98645e031b377fbba398712d45dbb99cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 17:50:34 +0200 Subject: [PATCH 184/396] Use Endianness in Ext [#79877740] --- libevmjit/Ext.cpp | 21 ++++++++------------- libevmjit/Ext.h | 2 -- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 98cb791e0..045d25b62 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -150,14 +150,9 @@ Value* Ext::calldataload(Value* _index) return Endianness::toNative(m_builder, ret); } -Value* Ext::bswap(Value* _value) -{ - return m_builder.CreateCall(m_bswap, _value); -} - Value* Ext::balance(Value* _address) { - auto address = bswap(_address); // to BE + auto address = Endianness::toBE(m_builder, _address); m_builder.CreateStore(address, m_args[0]); m_builder.CreateCall(m_balance, m_args); return m_builder.CreateLoad(m_args[1]); @@ -165,7 +160,7 @@ Value* Ext::balance(Value* _address) void Ext::suicide(Value* _address) { - auto address = bswap(_address); // to BE + auto address = Endianness::toBE(m_builder, _address); m_builder.CreateStore(address, m_args[0]); m_builder.CreateCall(m_suicide, m_args[0]); } @@ -178,21 +173,21 @@ Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* Value* args[] = {m_args[0], m_arg2, m_arg3, m_args[1]}; m_builder.CreateCall(m_create, args); Value* address = m_builder.CreateLoad(m_args[1]); - address = bswap(address); // to LE + address = Endianness::toNative(m_builder, address); return address; } llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) { m_builder.CreateStore(_gas, m_args[0]); - auto receiveAddress = bswap(_receiveAddress); // to BE + auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); m_builder.CreateStore(receiveAddress, m_arg2); m_builder.CreateStore(_value, m_arg3); m_builder.CreateStore(_inOff, m_arg4); m_builder.CreateStore(_inSize, m_arg5); m_builder.CreateStore(_outOff, m_arg6); m_builder.CreateStore(_outSize, m_arg7); - auto codeAddress = bswap(_codeAddress); // toBE + auto codeAddress = Endianness::toBE(m_builder, _codeAddress); m_builder.CreateStore(codeAddress, m_arg8); llvm::Value* args[] = {m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]}; @@ -208,7 +203,7 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) llvm::Value* args[] = {m_args[0], m_arg2, m_args[1]}; m_builder.CreateCall(m_sha3, args); Value* hash = m_builder.CreateLoad(m_args[1]); - hash = bswap(hash); // to LE + hash = Endianness::toNative(m_builder, hash); return hash; } @@ -223,14 +218,14 @@ llvm::Value* Ext::exp(llvm::Value* _left, llvm::Value* _right) llvm::Value* Ext::codeAt(llvm::Value* _addr) { - auto addr = bswap(_addr); + auto addr = Endianness::toBE(m_builder, _addr); m_builder.CreateStore(addr, m_args[0]); return m_builder.CreateCall(m_codeAt, m_args[0]); } llvm::Value* Ext::codesizeAt(llvm::Value* _addr) { - auto addr = bswap(_addr); + auto addr = Endianness::toBE(m_builder, _addr); m_builder.CreateStore(addr, m_args[0]); llvm::Value* args[] = {m_args[0], m_args[1]}; m_builder.CreateCall(m_codesizeAt, args); diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 04c17fdac..361b6e47e 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -50,8 +50,6 @@ public: private: llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); - llvm::Value* bswap(llvm::Value*); - private: llvm::Value* m_args[2]; llvm::Value* m_arg2; From 17a3006633c16aad1ef3751f999f36463a3d5f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 18:16:57 +0200 Subject: [PATCH 185/396] Add support for Big Endian architectures [Delivers #79877740] --- libevmjit/Endianness.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h index 9234961c1..951904358 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -1,6 +1,8 @@ #pragma once +#include + #include namespace dev @@ -10,14 +12,19 @@ namespace eth namespace jit { -class Endianness +struct Endianness { -public: +#if defined(BOOST_LITTLE_ENDIAN) static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswap(_builder, _word); } - static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswap(_builder, _word); } +#elif defined(BOOST_BIG_ENDIAN) + static llvm::Value* toBE(llvm::IRBuilder<>&, llvm::Value* _word) { return _word; } + static llvm::Value* toNative(llvm::IRBuilder<>&, llvm::Value* _word) { return _word; } + +#endif // Add support for PDP endianness if needed + private: static llvm::Value* bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word); }; From 57a8935d876253e7f7866818c987042ce8fb8371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 19:42:24 +0200 Subject: [PATCH 186/396] Fix remaining gas testing [#81118624] --- test/vm.cpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 784515c1a..cd40a5ee3 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -512,37 +512,35 @@ void doTests(json_spirit::mValue& v, bool _fillin) fev.code = &fev.thisTxCode; } + + auto argc = boost::unit_test::framework::master_test_suite().argc; + auto argv = boost::unit_test::framework::master_test_suite().argv; + auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; + + jit::VM jit(fev.gas); + VM interpreter(fev.gas); bytes output; - u256 gas; + auto outOfGas = false; try { - auto argc = boost::unit_test::framework::master_test_suite().argc; - auto argv = boost::unit_test::framework::master_test_suite().argv; - - auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; if (useJit) - { - jit::VM vm(fev.gas); - output = vm.go(fev); - gas = vm.gas(); - } + output = jit.go(fev); else - { - VM vm(fev.gas); - output = vm.go(fev).toVector(); - gas = vm.gas(); // Get the remaining gas + output = interpreter.go(fev).toVector(); } + catch (OutOfGas const&) + { + outOfGas = true; } catch (Exception const& _e) { cnote << "VM did throw an exception: " << diagnostic_information(_e); - //BOOST_ERROR("Failed VM Test with Exception: " << e.what()); } catch (std::exception const& _e) { cnote << "VM did throw an exception: " << _e.what(); - //BOOST_ERROR("Failed VM Test with Exception: " << e.what()); } + auto gas = useJit ? jit.gas() : interpreter.gas(); // delete null entries in storage for the sake of comparison @@ -593,6 +591,9 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_CHECK(output == fromHex(o["out"].get_str())); BOOST_CHECK_EQUAL(test.toInt(o["gas"]), gas); + + if (outOfGas) + BOOST_CHECK_MESSAGE(gas == 0, "Remaining gas not 0 in out-of-gas state"); auto& expectedAddrs = test.addresses; auto& resultAddrs = fev.addresses; From daf7d16670ef670ae6cbf4514e518bbe9bdee5ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 19:52:08 +0200 Subject: [PATCH 187/396] Null gas in case of out-of-gas exception [Delivers #81118624] --- libevmjit/ExecutionEngine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 9ff4bed99..4bcaf2c50 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -114,7 +114,8 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV else returnCode = static_cast(r); - _gas = Runtime::getGas(); + // Return remaining gas + _gas = returnCode == ReturnCode::OutOfGas ? 0 : Runtime::getGas(); if (returnCode == ReturnCode::Return) { From 15499e68b87c3caa8f9e7bf480f97d0da5fb25c3 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 21:52:18 +0100 Subject: [PATCH 188/396] Fixed bug in phi node rewriting [#80895676] --- libevmjit/Compiler.cpp | 47 +++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index bf77901cd..71661bde9 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -924,11 +924,13 @@ void Compiler::linkBasicBlocks(Stack& stack) for (auto& pair : this->basicBlocks) { auto& bb = pair.second; - cfg.emplace(std::piecewise_construct, - std::forward_as_tuple(bb.llvm()), - std::forward_as_tuple(bb)); + cfg.emplace(bb.llvm(), bb); } + // Insert jump table block into cfg + if (m_jumpTableBlock) + cfg.emplace(m_jumpTableBlock->llvm(), *m_jumpTableBlock); + auto& entryBlock = m_mainFunc->getEntryBlock(); // Create edges in cfg @@ -976,6 +978,8 @@ void Compiler::linkBasicBlocks(Stack& stack) } } + std::map phiReplacements; + // Propagate values between blocks. for (auto& pair : cfg) { @@ -998,13 +1002,12 @@ void Compiler::linkBasicBlocks(Stack& stack) // Turn the remaining phi nodes into stack.pop's. m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI())); - for (; llvm::isa(*instrIter); ) + for (; llvm::isa(*instrIter); ++instrIter) { auto phi = llvm::cast(instrIter); auto value = stack.popWord(); - phi->replaceAllUsesWith(value); - ++ instrIter; - phi->eraseFromParent(); + // Don't delete the phi node yet. It may still be stored in a local stack of some block. + phiReplacements[phi] = value; } // Emit stack push's at the end of the block, just before the terminator; @@ -1014,6 +1017,12 @@ void Compiler::linkBasicBlocks(Stack& stack) for (size_t i = 0; i < localStackSize - bbInfo.outputItems; ++i) stack.pushWord(bblock.getStack().get(localStackSize - 1 - i)); } + + for (auto& entry : phiReplacements) + { + entry.first->replaceAllUsesWith(entry.second); + entry.first->eraseFromParent(); + } } void Compiler::dumpBasicBlockGraph(std::ostream& out) @@ -1025,11 +1034,13 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) std::vector blocks; for (auto& pair : this->basicBlocks) blocks.push_back(&pair.second); - if (m_jumpTableBlock.get()) + if (m_jumpTableBlock) blocks.push_back(m_jumpTableBlock.get()); - if (m_badJumpBlock.get()) + if (m_badJumpBlock) blocks.push_back(m_badJumpBlock.get()); + std::map phiNodesPerBlock; + // Output nodes for (auto bb : blocks) { @@ -1038,27 +1049,29 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) int numOfPhiNodes = 0; auto firstNonPhiPtr = bb->llvm()->getFirstNonPHI(); for (auto instrIter = bb->llvm()->begin(); &*instrIter != firstNonPhiPtr; ++instrIter, ++numOfPhiNodes); + phiNodesPerBlock[bb] = numOfPhiNodes; + auto initStackSize = bb->getStack().initialSize(); auto endStackSize = bb->getStack().size(); out << " \"" << blockName << "\" [shape=record, label=\"" - << numOfPhiNodes << "|" << blockName << "|" << endStackSize + << initStackSize << "|" << blockName << "|" << endStackSize << "\"];\n"; } - out << " entry -> \"Instr.0\";\n"; - // Output edges for (auto bb : blocks) { std::string blockName = bb->llvm()->getName(); - auto end = llvm::succ_end(bb->llvm()); - for (llvm::succ_iterator it = llvm::succ_begin(bb->llvm()); it != end; ++it) + auto end = llvm::pred_end(bb->llvm()); + for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) { - std::string succName = it->getName(); - out << " \"" << blockName << "\" -> \"" << succName << "\"" - << ((bb == m_jumpTableBlock.get()) ? " [style = dashed];\n" : "\n"); + out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" + << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") + << "label = \"" + << phiNodesPerBlock[bb] + << "\"];\n"; } } From 472f9c749fb87eefbb45811d1c1d9a30b1493aab Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 22 Oct 2014 10:01:56 +0100 Subject: [PATCH 189/396] Fixed the order in which phi nodes are created (was incorrect) [#80895676] --- evmcc/test/jump/fib1.ethel | 3 ++- evmcc/test/jump/fib1.evm | 2 +- evmcc/test/jump/rec1.ethel | 4 ++++ evmcc/test/jump/rec1.evm | 1 + libevmjit/BasicBlock.cpp | 2 +- 5 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 evmcc/test/jump/rec1.ethel create mode 100644 evmcc/test/jump/rec1.evm diff --git a/evmcc/test/jump/fib1.ethel b/evmcc/test/jump/fib1.ethel index 6efd4ed2d..81b869f41 100644 --- a/evmcc/test/jump/fib1.ethel +++ b/evmcc/test/jump/fib1.ethel @@ -2,4 +2,5 @@ let fib n = if n < 3 then 1 else fib (n-1) + fib (n-2) -return fib 5 +return fib 10 + diff --git a/evmcc/test/jump/fib1.evm b/evmcc/test/jump/fib1.evm index b5b5bf9c6..5042a192f 100644 --- a/evmcc/test/jump/fib1.evm +++ b/evmcc/test/jump/fib1.evm @@ -1 +1 @@ -630000000d60056300000016585d60005460206000f28060030a630000004759630000002f816001036300000016585d630000003f836002036300000016585d0163000000495860019350505058 \ No newline at end of file +6007600a6010585d60005460206000f26003810a602f596020600282036010585d602a600183036010585d01603158600190509058 \ No newline at end of file diff --git a/evmcc/test/jump/rec1.ethel b/evmcc/test/jump/rec1.ethel new file mode 100644 index 000000000..f83c8e81e --- /dev/null +++ b/evmcc/test/jump/rec1.ethel @@ -0,0 +1,4 @@ +let f n = + if n == 0 then 2 else f (n-1) + +return f 10 diff --git a/evmcc/test/jump/rec1.evm b/evmcc/test/jump/rec1.evm new file mode 100644 index 000000000..2ae62aff6 --- /dev/null +++ b/evmcc/test/jump/rec1.evm @@ -0,0 +1 @@ +6007600a6010585d60005460206000f26000810e6024596020600182036010585d602658600290509058 \ No newline at end of file diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 927f1180b..2c5ea7285 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -52,7 +52,7 @@ llvm::Value* BasicBlock::LocalStack::get(size_t _index) m_backend.insert(m_backend.begin(), nMissingVals, nullptr); for (decltype(nMissingVals) i = 0; i < nMissingVals; ++i) { - m_backend[i] = m_llvmBB->empty() ? + m_backend[nMissingVals - 1 - i] = m_llvmBB->empty() ? llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB) : llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI()); m_numRequiredStackItems += 1; From 71426520a1fb387cfc8bdd6c63d9b1fa3123c1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 22 Oct 2014 15:12:27 +0200 Subject: [PATCH 190/396] Add LLVMEnable user macro in LLVM.props (VS property sheet) to allow easily disabling LLVM dependency --- windows/Eth.vcxproj | 4 ++++ windows/LLVM.props | 17 +++++++++++++++-- windows/TestEthereum.vcxproj | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/windows/Eth.vcxproj b/windows/Eth.vcxproj index 9b2d47727..3af0a0bce 100644 --- a/windows/Eth.vcxproj +++ b/windows/Eth.vcxproj @@ -52,21 +52,25 @@ + + + + diff --git a/windows/LLVM.props b/windows/LLVM.props index 3290a4f64..42be9a170 100644 --- a/windows/LLVM.props +++ b/windows/LLVM.props @@ -2,22 +2,32 @@ + 1 + ..\..\llvm ..\..\_build\llvm\$(Platform) - ..\..\llvm\include;$(LLVMBuildDir)\include + $(LLVMSrcDir)\include;$(LLVMBuildDir)\include $(LLVMBuildDir)\$(Configuration)\lib + LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib $(LLVMIncludeDir);%(AdditionalIncludeDirectories) 4800;%(DisableSpecificWarnings) + ETH_JIT=$(LLVMEnabled);%(PreprocessorDefinitions) $(LLVMLibDir);%(AdditionalLibraryDirectories) - LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) + $(LLVMLibs);%(AdditionalDependencies) + + $(LLVMEnabled) + + + $(LLVMSrcDir) + $(LLVMBuildDir) @@ -27,5 +37,8 @@ $(LLVMLibDir) + + $(LLVMLibs) + \ No newline at end of file diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index be475a949..277a38a3d 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -51,6 +51,7 @@ + @@ -60,10 +61,12 @@ + + From 4f69964b2a5ceee327d3f1c18a7f5d18ba87c8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 22 Oct 2014 16:23:25 +0200 Subject: [PATCH 191/396] Extract interface of VM into new VMFace class --- libevm/VM.cpp | 12 ++++- libevm/VM.h | 38 +++------------ libevm/VMFace.cpp | 19 ++++++++ libevm/VMFace.h | 75 +++++++++++++++++++++++++++++ windows/LibEthereum.vcxproj | 2 + windows/LibEthereum.vcxproj.filters | 6 +++ 6 files changed, 120 insertions(+), 32 deletions(-) create mode 100644 libevm/VMFace.cpp create mode 100644 libevm/VMFace.h diff --git a/libevm/VM.cpp b/libevm/VM.cpp index e47237d5a..4afd75659 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -20,13 +20,21 @@ */ #include "VM.h" +#include -using namespace std; using namespace dev; using namespace dev::eth; void VM::reset(u256 _gas) { - m_gas = _gas; + VMFace::reset(_gas); m_curPC = 0; } + +bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +{ + if (auto defaultExt = dynamic_cast(&_ext)) + return go(*defaultExt, _onOp, _steps); + else + return go(_ext, _onOp, _steps); +} diff --git a/libevm/VM.h b/libevm/VM.h index e092bdfed..9f47afe4a 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -27,6 +27,7 @@ #include #include #include +#include "VMFace.h" #include "FeeStructure.h" #include "ExtVMFace.h" @@ -35,52 +36,29 @@ namespace dev namespace eth { -struct VMException: virtual Exception {}; -struct StepsDone: virtual VMException {}; -struct BreakPointHit: virtual VMException {}; -struct BadInstruction: virtual VMException {}; -struct BadJumpDestination: virtual VMException {}; -struct OutOfGas: virtual VMException {}; -class StackTooSmall: virtual public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; - -// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. -// Currently we just pull out the right (low-order in BE) 160-bits. -inline Address asAddress(u256 _item) -{ - return right160(h256(_item)); -} - -inline u256 fromAddress(Address _a) -{ - return (u160)_a; -// h256 ret; -// memcpy(&ret, &_a, sizeof(_a)); -// return ret; -} - /** */ -class VM +class VM : public VMFace { public: /// Construct VM object. - explicit VM(u256 _gas = 0) { reset(_gas); } + explicit VM(u256 _gas = 0): VMFace(_gas) {} - void reset(u256 _gas = 0); + virtual void reset(u256 _gas = 0) override final; - template - bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp = OnOpFunc(), uint64_t _steps = (uint64_t)-1); + virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall(_n, m_stack.size())); } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } - u256 gas() const { return m_gas; } u256 curPC() const { return m_curPC; } bytes const& memory() const { return m_temp; } u256s const& stack() const { return m_stack; } private: - u256 m_gas = 0; + template + bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp, uint64_t _steps); + u256 m_curPC = 0; bytes m_temp; u256s m_stack; diff --git a/libevm/VMFace.cpp b/libevm/VMFace.cpp new file mode 100644 index 000000000..22f13d5a6 --- /dev/null +++ b/libevm/VMFace.cpp @@ -0,0 +1,19 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ + +#include "VM.h" + diff --git a/libevm/VMFace.h b/libevm/VMFace.h new file mode 100644 index 000000000..f10068700 --- /dev/null +++ b/libevm/VMFace.h @@ -0,0 +1,75 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ + +#pragma once + +#include +#include "ExtVMFace.h" + +namespace dev +{ +namespace eth +{ + +struct VMException: virtual Exception {}; +struct StepsDone: virtual VMException {}; +struct BreakPointHit: virtual VMException {}; +struct BadInstruction: virtual VMException {}; +struct BadJumpDestination: virtual VMException {}; +struct OutOfGas: virtual VMException {}; +class StackTooSmall: virtual public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; + +// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. +// Currently we just pull out the right (low-order in BE) 160-bits. +inline Address asAddress(u256 _item) +{ + return right160(h256(_item)); +} + +inline u256 fromAddress(Address _a) +{ + return (u160)_a; + // h256 ret; + // memcpy(&ret, &_a, sizeof(_a)); + // return ret; +} + +/** + */ +class VMFace +{ +public: + /// Construct VM object. + explicit VMFace(u256 _gas = 0): m_gas(_gas) {} + + virtual ~VMFace() = default; + + VMFace(VMFace const&) = delete; + void operator=(VMFace const&) = delete; + + virtual void reset(u256 _gas = 0) { m_gas = _gas; } + + virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; + + u256 gas() const { return m_gas; } + +protected: + u256 m_gas = 0; +}; + +} +} diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 8c08091ec..b5305c322 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -141,6 +141,7 @@ true true + @@ -360,6 +361,7 @@ true true + diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index 7d743d82d..e86c30c00 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -193,6 +193,9 @@ libethcore + + libevm + @@ -417,6 +420,9 @@ libwebthree + + libevm + From dfb283097ca5e1bccc07c33d8a997612afe084f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 22 Oct 2014 16:40:05 +0200 Subject: [PATCH 192/396] Implement VMFace with jit::VM --- libevmjit/VM.cpp | 7 ++++--- libevmjit/VM.h | 14 +++++--------- test/vm.cpp | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 16011241e..c6364eadb 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -1,7 +1,7 @@ #include "VM.h" -#include +#include #include "ExecutionEngine.h" #include "Compiler.h" @@ -13,7 +13,7 @@ namespace eth namespace jit { -bytes VM::go(ExtVMFace& _ext) +bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { auto module = Compiler().compile(_ext.code); @@ -30,7 +30,8 @@ bytes VM::go(ExtVMFace& _ext) BOOST_THROW_EXCEPTION(StackTooSmall(1,0)); } - return std::move(engine.returnData); + m_output = std::move(engine.returnData); + return {m_output.data(), m_output.size()}; // TODO: This all bytesConstRef stuff sucks } } diff --git a/libevmjit/VM.h b/libevmjit/VM.h index 3e7884b10..934e16ed0 100644 --- a/libevmjit/VM.h +++ b/libevmjit/VM.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include namespace dev @@ -11,20 +12,15 @@ namespace eth namespace jit { -class VM +class VM: public VMFace { public: - /// Construct VM object. - explicit VM(u256 _gas = 0): m_gas(_gas) {} + explicit VM(u256 _gas = 0): VMFace(_gas) {} - void reset(u256 _gas = 0) { m_gas = _gas; } - - bytes go(ExtVMFace& _ext); - - u256 gas() const { return m_gas; } + virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) final; private: - u256 m_gas = 0; + bytes m_output; }; } diff --git a/test/vm.cpp b/test/vm.cpp index cd40a5ee3..179a47b91 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -524,7 +524,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) try { if (useJit) - output = jit.go(fev); + output = jit.go(fev).toVector(); else output = interpreter.go(fev).toVector(); } From f49612f10c522622d67f212df71250c3d0bbb441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 22 Oct 2014 16:52:47 +0200 Subject: [PATCH 193/396] Update VM test engine to use VMFace interface --- test/vm.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 179a47b91..4671a92b6 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -517,16 +517,13 @@ void doTests(json_spirit::mValue& v, bool _fillin) auto argv = boost::unit_test::framework::master_test_suite().argv; auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; - jit::VM jit(fev.gas); - VM interpreter(fev.gas); + auto vm = useJit ? std::unique_ptr(new jit::VM) : std::unique_ptr(new VM); + vm->reset(fev.gas); bytes output; auto outOfGas = false; try { - if (useJit) - output = jit.go(fev).toVector(); - else - output = interpreter.go(fev).toVector(); + output = vm->go(fev).toVector(); } catch (OutOfGas const&) { @@ -540,7 +537,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) { cnote << "VM did throw an exception: " << _e.what(); } - auto gas = useJit ? jit.gas() : interpreter.gas(); + auto gas = vm->gas(); // delete null entries in storage for the sake of comparison From 08cae3947ead23e5cde92bc0ec6c1b1f48d63487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 22 Oct 2014 17:27:27 +0200 Subject: [PATCH 194/396] Try not to use JIT in any interactive mode --- libevmjit/VM.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index c6364eadb..f1c1ad0a7 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -15,6 +15,9 @@ namespace jit bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { + assert(_onOp == nullptr); // Parameter ignored + assert(_steps == (uint64_t)-1); // Parameter ignored + auto module = Compiler().compile(_ext.code); ExecutionEngine engine; From a7dabc897e42318b9f1be7c40036058b4183f906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 22 Oct 2014 17:30:02 +0200 Subject: [PATCH 195/396] Use VMFace in some places in Executive --- libethereum/Executive.cpp | 2 +- libethereum/Executive.h | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index fe5b21761..c46b8c39b 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -147,7 +147,7 @@ OnOpFunc Executive::simpleTrace() return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt) { ExtVM const& ext = *(ExtVM const*)voidExt; - VM& vm = *(VM*)voidVM; + VM& vm = *(VM*)voidVM; // TODO: Ok for now, because only interpeter/VM supports OnOp callback, but safer solution would be nice ostringstream o; o << endl << " STACK" << endl; diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 82b7df7e9..f7c056252 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -25,7 +25,6 @@ #include #include #include -#include #include "Transaction.h" #include "Manifest.h" @@ -34,7 +33,7 @@ namespace dev namespace eth { -class VM; +class VMFace; class ExtVM; class State; @@ -62,14 +61,14 @@ public: bytesConstRef out() const { return m_out; } h160 newAddress() const { return m_newAddress; } - VM const& vm() const { return *m_vm; } + VMFace const& vm() const { return *m_vm; } State const& state() const { return m_s; } ExtVM const& ext() const { return *m_ext; } private: State& m_s; ExtVM* m_ext = nullptr; // TODO: make safe. - VM* m_vm = nullptr; + VMFace* m_vm = nullptr; Manifest* m_ms = nullptr; bytesConstRef m_out; Address m_newAddress; From 6ca44a9ada482608221237c571533a5590de9dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 22 Oct 2014 17:35:33 +0200 Subject: [PATCH 196/396] Better assert condition --- libevmjit/VM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index f1c1ad0a7..9a76c5bcb 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -15,7 +15,7 @@ namespace jit bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { - assert(_onOp == nullptr); // Parameter ignored + assert(!_onOp); // Parameter ignored assert(_steps == (uint64_t)-1); // Parameter ignored auto module = Compiler().compile(_ext.code); From 900fd04f1edab3f86e789d629c7350d17a6a0f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 22 Oct 2014 18:48:14 +0200 Subject: [PATCH 197/396] Change the way VMs are created (mostly for tracking where are created) --- libethereum/Executive.cpp | 4 ++-- libethereum/State.cpp | 6 ++++-- libevm/VM.h | 8 ++++---- libevm/VMFace.cpp | 11 +++++++++++ libevm/VMFace.h | 7 ++++++- libevmjit/VM.h | 8 ++++---- test/vm.cpp | 7 ++++--- windows/Eth.vcxproj | 3 +++ 8 files changed, 38 insertions(+), 16 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index c46b8c39b..30986928e 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -118,7 +118,7 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu if (m_s.addressHasCode(_receiveAddress)) { - m_vm = new VM(_gas); + m_vm = VMFace::create(VMFace::Interpreter, _gas).release(); bytes const& c = m_s.code(_receiveAddress); m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms); } @@ -137,7 +137,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g m_s.m_cache[m_newAddress] = AddressState(0, m_s.balance(m_newAddress) + _endowment, h256(), h256()); // Execute _init. - m_vm = new VM(_gas); + m_vm = VMFace::create(VMFace::JIT, _gas).release(); m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms); return _init.empty(); } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 931ee2cf6..b51224e32 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1146,7 +1146,8 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA } else if (addressHasCode(_codeAddress)) { - VM vm(*_gas); + auto vmObj = VMFace::create(VMFace::Interpreter, *_gas); + VMFace& vm = *vmObj; ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level); bool revert = false; @@ -1208,7 +1209,8 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, m_cache[newAddress] = AddressState(0, balance(newAddress) + _endowment, h256(), h256()); // Execute init code. - VM vm(*_gas); + auto vmObj = VMFace::create(VMFace::Interpreter, *_gas); + VMFace& vm = *vmObj; ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); bool revert = false; bytesConstRef out; diff --git a/libevm/VM.h b/libevm/VM.h index 9f47afe4a..2ddf16bb6 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -41,10 +41,7 @@ namespace eth class VM : public VMFace { public: - /// Construct VM object. - explicit VM(u256 _gas = 0): VMFace(_gas) {} - - virtual void reset(u256 _gas = 0) override final; + virtual void reset(u256 _gas = 0) noexcept override final; virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; @@ -56,6 +53,9 @@ public: u256s const& stack() const { return m_stack; } private: + friend VMFace; + explicit VM(u256 _gas = 0): VMFace(_gas) {} + template bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp, uint64_t _steps); diff --git a/libevm/VMFace.cpp b/libevm/VMFace.cpp index 22f13d5a6..2553f3004 100644 --- a/libevm/VMFace.cpp +++ b/libevm/VMFace.cpp @@ -15,5 +15,16 @@ along with cpp-ethereum. If not, see . */ +#include "VMFace.h" #include "VM.h" +#include +using namespace dev; +using namespace dev::eth; + +std::unique_ptr VMFace::create(VMFace::Kind _kind, u256 _gas) +{ + std::unique_ptr vm(_kind == Kind::JIT ? static_cast(new jit::VM) : new VM); + vm->reset(_gas); + return vm; +} diff --git a/libevm/VMFace.h b/libevm/VMFace.h index f10068700..508a39bc0 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include "ExtVMFace.h" @@ -61,12 +62,16 @@ public: VMFace(VMFace const&) = delete; void operator=(VMFace const&) = delete; - virtual void reset(u256 _gas = 0) { m_gas = _gas; } + virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; } virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; u256 gas() const { return m_gas; } + enum Kind: bool { Interpreter, JIT }; + + static std::unique_ptr create(Kind, u256 _gas = 0); + protected: u256 m_gas = 0; }; diff --git a/libevmjit/VM.h b/libevmjit/VM.h index 934e16ed0..93b359cd7 100644 --- a/libevmjit/VM.h +++ b/libevmjit/VM.h @@ -14,12 +14,12 @@ namespace jit class VM: public VMFace { -public: - explicit VM(u256 _gas = 0): VMFace(_gas) {} - - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) final; + virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; private: + friend VMFace; + explicit VM(u256 _gas = 0): VMFace(_gas) {} + bytes m_output; }; diff --git a/test/vm.cpp b/test/vm.cpp index 4671a92b6..d62329af4 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -436,7 +436,8 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end m_cache[_newAddress] = AddressState(0, balance(_newAddress) + _endowment, h256(), h256()); // Execute init code. - VM vm(*_gas); + auto vmObj = VMFace::create(VMFace::Interpreter, *_gas); + VMFace& vm = *vmObj; ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); bool revert = false; bytesConstRef out; @@ -517,8 +518,8 @@ void doTests(json_spirit::mValue& v, bool _fillin) auto argv = boost::unit_test::framework::master_test_suite().argv; auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; - auto vm = useJit ? std::unique_ptr(new jit::VM) : std::unique_ptr(new VM); - vm->reset(fev.gas); + auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; + auto vm = VMFace::create(vmKind, fev.gas); bytes output; auto outOfGas = false; try diff --git a/windows/Eth.vcxproj b/windows/Eth.vcxproj index 3af0a0bce..d67d964f8 100644 --- a/windows/Eth.vcxproj +++ b/windows/Eth.vcxproj @@ -155,6 +155,9 @@ {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} + + {9c816740-5c11-4377-a3a7-46be12f35fa0} + From 0ff7da1c9d84f80990b3e7c540227b6be35768ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 22 Oct 2014 19:27:10 +0200 Subject: [PATCH 198/396] Do not skip evmcc build in Visual Studio solution --- windows/Ethereum.sln | 280 ++++++++++++++++++++++--------------------- 1 file changed, 141 insertions(+), 139 deletions(-) diff --git a/windows/Ethereum.sln b/windows/Ethereum.sln index c4ac205a7..df5916e63 100644 --- a/windows/Ethereum.sln +++ b/windows/Ethereum.sln @@ -57,88 +57,88 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.ActiveCfg = Debug|Win32 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.Build.0 = Debug|Win32 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.ActiveCfg = Debug|x64 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.Build.0 = Debug|x64 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Mixed Platforms.Build.0 = Release|Win32 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.ActiveCfg = Release|Win32 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.Build.0 = Release|Win32 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Mixed Platforms.Build.0 = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.ActiveCfg = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.Build.0 = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.ActiveCfg = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.Build.0 = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Mixed Platforms.Build.0 = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.ActiveCfg = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.Build.0 = Release|x64 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|x64.ActiveCfg = Release|x64 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|x64.Build.0 = Release|x64 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.ActiveCfg = Debug|Win32 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.Build.0 = Debug|Win32 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.ActiveCfg = Debug|x64 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.Build.0 = Debug|x64 - {27014763-955D-486B-9BA7-69872192E6F4}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {27014763-955D-486B-9BA7-69872192E6F4}.Release|Mixed Platforms.Build.0 = Release|Win32 - {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.ActiveCfg = Release|Win32 - {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.Build.0 = Release|Win32 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Mixed Platforms.Build.0 = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.ActiveCfg = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.Build.0 = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.ActiveCfg = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.Build.0 = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Release|Mixed Platforms.Build.0 = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.ActiveCfg = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.Build.0 = Release|x64 {27014763-955D-486B-9BA7-69872192E6F4}.Release|x64.ActiveCfg = Release|x64 {27014763-955D-486B-9BA7-69872192E6F4}.Release|x64.Build.0 = Release|x64 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.ActiveCfg = Debug|Win32 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.Build.0 = Debug|Win32 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.ActiveCfg = Debug|x64 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.Build.0 = Debug|x64 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Mixed Platforms.Build.0 = Release|Win32 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.ActiveCfg = Release|Win32 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.Build.0 = Release|Win32 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Mixed Platforms.Build.0 = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.ActiveCfg = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.Build.0 = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.ActiveCfg = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.Build.0 = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Mixed Platforms.Build.0 = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.ActiveCfg = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.Build.0 = Release|x64 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|x64.ActiveCfg = Release|x64 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|x64.Build.0 = Release|x64 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.ActiveCfg = Debug|Win32 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.Build.0 = Debug|Win32 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.ActiveCfg = Debug|x64 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.Build.0 = Debug|x64 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Mixed Platforms.Build.0 = Release|Win32 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.ActiveCfg = Release|Win32 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.Build.0 = Release|Win32 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Mixed Platforms.Build.0 = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.ActiveCfg = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.Build.0 = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.ActiveCfg = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.Build.0 = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Mixed Platforms.Build.0 = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.ActiveCfg = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.Build.0 = Release|x64 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|x64.ActiveCfg = Release|x64 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|x64.Build.0 = Release|x64 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.ActiveCfg = Debug|Win32 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.Build.0 = Debug|Win32 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.ActiveCfg = Debug|x64 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.Build.0 = Debug|x64 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Mixed Platforms.Build.0 = Release|Win32 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.ActiveCfg = Release|Win32 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.Build.0 = Release|Win32 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Mixed Platforms.Build.0 = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.ActiveCfg = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.Build.0 = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.ActiveCfg = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.Build.0 = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Mixed Platforms.Build.0 = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.ActiveCfg = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.Build.0 = Release|x64 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|x64.ActiveCfg = Release|x64 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|x64.Build.0 = Release|x64 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.ActiveCfg = Debug|Win32 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.Build.0 = Debug|Win32 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.ActiveCfg = Debug|x64 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.Build.0 = Debug|x64 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Mixed Platforms.Build.0 = Release|Win32 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.ActiveCfg = Release|Win32 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.Build.0 = Release|Win32 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Mixed Platforms.Build.0 = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.ActiveCfg = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.Build.0 = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.ActiveCfg = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.Build.0 = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Mixed Platforms.Build.0 = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.ActiveCfg = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.Build.0 = Release|x64 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|x64.ActiveCfg = Release|x64 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|x64.Build.0 = Release|x64 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.ActiveCfg = Debug|Win32 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.Build.0 = Debug|Win32 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.ActiveCfg = Debug|x64 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.Build.0 = Debug|x64 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Mixed Platforms.Build.0 = Release|Win32 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.ActiveCfg = Release|Win32 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.Build.0 = Release|Win32 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Mixed Platforms.Build.0 = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.ActiveCfg = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.Build.0 = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.ActiveCfg = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.Build.0 = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Mixed Platforms.Build.0 = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.ActiveCfg = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.Build.0 = Release|x64 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|x64.ActiveCfg = Release|x64 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|x64.Build.0 = Release|x64 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 @@ -161,16 +161,16 @@ Global {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Release|Win32.Build.0 = Release|Win32 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Release|x64.ActiveCfg = Release|x64 {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Release|x64.Build.0 = Release|x64 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.ActiveCfg = Debug|Win32 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.Build.0 = Debug|Win32 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.ActiveCfg = Debug|x64 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.Build.0 = Debug|x64 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Mixed Platforms.Build.0 = Release|Win32 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.ActiveCfg = Release|Win32 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.Build.0 = Release|Win32 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Mixed Platforms.Build.0 = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.ActiveCfg = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.Build.0 = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.ActiveCfg = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.Build.0 = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Mixed Platforms.Build.0 = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.ActiveCfg = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.Build.0 = Release|x64 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|x64.ActiveCfg = Release|x64 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|x64.Build.0 = Release|x64 {90C70663-7181-4E99-9079-54188CEB8954}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 @@ -185,74 +185,76 @@ Global {90C70663-7181-4E99-9079-54188CEB8954}.Release|Win32.Build.0 = Release|Win32 {90C70663-7181-4E99-9079-54188CEB8954}.Release|x64.ActiveCfg = Release|x64 {90C70663-7181-4E99-9079-54188CEB8954}.Release|x64.Build.0 = Release|x64 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.ActiveCfg = Debug|Win32 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.Build.0 = Debug|Win32 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.ActiveCfg = Debug|x64 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.Build.0 = Debug|x64 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Mixed Platforms.Build.0 = Release|Win32 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.ActiveCfg = Release|Win32 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.Build.0 = Release|Win32 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Mixed Platforms.Build.0 = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.ActiveCfg = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.Build.0 = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.ActiveCfg = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.Build.0 = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Mixed Platforms.Build.0 = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.ActiveCfg = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.Build.0 = Release|x64 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|x64.ActiveCfg = Release|x64 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|x64.Build.0 = Release|x64 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.ActiveCfg = Debug|Win32 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.Build.0 = Debug|Win32 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.ActiveCfg = Debug|x64 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.Build.0 = Debug|x64 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Mixed Platforms.Build.0 = Release|Win32 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.ActiveCfg = Release|Win32 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.Build.0 = Release|Win32 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Mixed Platforms.Build.0 = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.ActiveCfg = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.Build.0 = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.ActiveCfg = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.Build.0 = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Mixed Platforms.Build.0 = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.ActiveCfg = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.Build.0 = Release|x64 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|x64.ActiveCfg = Release|x64 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|x64.Build.0 = Release|x64 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.ActiveCfg = Debug|Win32 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.Build.0 = Debug|Win32 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.ActiveCfg = Debug|x64 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.Build.0 = Debug|x64 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Mixed Platforms.Build.0 = Release|Win32 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.ActiveCfg = Release|Win32 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.Build.0 = Release|Win32 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Mixed Platforms.Build.0 = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.ActiveCfg = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.Build.0 = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.ActiveCfg = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.Build.0 = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Mixed Platforms.Build.0 = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.ActiveCfg = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.Build.0 = Release|x64 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|x64.ActiveCfg = Release|x64 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|x64.Build.0 = Release|x64 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.ActiveCfg = Debug|Win32 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.Build.0 = Debug|Win32 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.ActiveCfg = Debug|x64 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.Build.0 = Debug|x64 - {255BDC68-B8DB-465F-8220-981E77684189}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {255BDC68-B8DB-465F-8220-981E77684189}.Release|Mixed Platforms.Build.0 = Release|Win32 - {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.ActiveCfg = Release|Win32 - {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.Build.0 = Release|Win32 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Mixed Platforms.Build.0 = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.ActiveCfg = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.Build.0 = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.ActiveCfg = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.Build.0 = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Release|Mixed Platforms.Build.0 = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.ActiveCfg = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.Build.0 = Release|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Release|x64.ActiveCfg = Release|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Release|x64.Build.0 = Release|x64 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.ActiveCfg = Debug|Win32 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.Build.0 = Debug|Win32 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|x64.ActiveCfg = Debug|x64 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Mixed Platforms.Build.0 = Release|Win32 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.ActiveCfg = Release|Win32 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.Build.0 = Release|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Mixed Platforms.Build.0 = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.ActiveCfg = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.Build.0 = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|x64.ActiveCfg = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|x64.Build.0 = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Mixed Platforms.Build.0 = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.ActiveCfg = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.Build.0 = Release|x64 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|x64.ActiveCfg = Release|x64 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.ActiveCfg = Debug|Win32 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.Build.0 = Debug|Win32 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.ActiveCfg = Debug|x64 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.Build.0 = Debug|x64 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Mixed Platforms.Build.0 = Release|Win32 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.ActiveCfg = Release|Win32 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.Build.0 = Release|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|x64.Build.0 = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Mixed Platforms.ActiveCfg = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Mixed Platforms.Build.0 = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.ActiveCfg = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.Build.0 = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.ActiveCfg = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.Build.0 = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Mixed Platforms.Build.0 = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.ActiveCfg = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.Build.0 = Release|x64 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|x64.ActiveCfg = Release|x64 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|x64.Build.0 = Release|x64 EndGlobalSection From fa494bc6a9005363f09249e5e83a654283836bca Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 22 Oct 2014 23:17:04 +0100 Subject: [PATCH 199/396] update some CMakeLists.txt --- eth/CMakeLists.txt | 5 +++++ exp/CMakeLists.txt | 4 ++++ neth/CMakeLists.txt | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index 087c5314a..274700ee7 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -14,6 +14,11 @@ add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} gmp) + +if(EVMCC) + target_link_libraries(${EXECUTABLE} evmjit) +endif() + if(MINIUPNPC_LS) target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) endif() diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index da6775798..c671f240f 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -17,6 +17,10 @@ target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) endif() target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) +if(EVMCC) + target_link_libraries(${EXECUTABLE} evmjit) +endif() + if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") target_link_libraries(${EXECUTABLE} gcc) diff --git a/neth/CMakeLists.txt b/neth/CMakeLists.txt index 2b3f92947..184fc7104 100644 --- a/neth/CMakeLists.txt +++ b/neth/CMakeLists.txt @@ -24,6 +24,10 @@ if(JSONRPC_LS) target_link_libraries(${EXECUTABLE} ${JSONRPC_LS}) endif() +if(EVMCC) + target_link_libraries(${EXECUTABLE} evmjit) +endif() + if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") target_link_libraries(${EXECUTABLE} gcc) From 69b36f01f6ab2f8e0a4adb7994d8c3870d4a43f6 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 22 Oct 2014 23:17:48 +0100 Subject: [PATCH 200/396] added option to set initial gas --- evmcc/evmcc.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 3cd06d5a8..abaf3e511 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -25,7 +25,6 @@ void show_usage() int main(int argc, char** argv) { - std::string input_file; bool opt_dissassemble = false; bool opt_show_bytes = false; @@ -33,6 +32,7 @@ int main(int argc, char** argv) bool opt_interpret = false; bool opt_dump_graph = false; bool opt_unknown = false; + size_t initialGas = 10000; for (int i = 1; i < argc; i++) { @@ -47,6 +47,12 @@ int main(int argc, char** argv) opt_interpret = true; else if (option == "-g") opt_dump_graph = true; + else if (option == "-G" && i + 1 < argc) + { + std::string gasValue = argv[++i]; + initialGas = boost::lexical_cast(gasValue); + std::cerr << "Initial gas set to " << initialGas << "\n"; + } else if (option[0] != '-' && input_file.empty()) input_file = option; else @@ -109,7 +115,7 @@ int main(int argc, char** argv) if (opt_interpret) { auto engine = eth::jit::ExecutionEngine(); - u256 gas = 10000; + u256 gas = initialGas; auto result = engine.run(std::move(module), gas); return result; } From 77e18420db7dab4b85e4a42af36541726c83b9f4 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 22 Oct 2014 23:24:02 +0100 Subject: [PATCH 201/396] fixes for compiling libevm/VM.cpp with gcc --- libevm/VM.cpp | 2 +- libevm/VM.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 4afd75659..4504fa302 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -25,7 +25,7 @@ using namespace dev; using namespace dev::eth; -void VM::reset(u256 _gas) +void VM::reset(u256 _gas) noexcept { VMFace::reset(_gas); m_curPC = 0; diff --git a/libevm/VM.h b/libevm/VM.h index 2ddf16bb6..344764d87 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -52,10 +52,11 @@ public: bytes const& memory() const { return m_temp; } u256s const& stack() const { return m_stack; } -private: friend VMFace; explicit VM(u256 _gas = 0): VMFace(_gas) {} +private: + template bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp, uint64_t _steps); From 055097bc1f56f9f8f29fde0933c58727df2cef58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Oct 2014 10:33:11 +0200 Subject: [PATCH 202/396] Add createRandomTest.cpp to TestEhereum Visual Studio project --- windows/TestEthereum.vcxproj | 1 + windows/TestEthereum.vcxproj.filters | 1 + 2 files changed, 2 insertions(+) diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index 277a38a3d..1ef821380 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -159,6 +159,7 @@ + diff --git a/windows/TestEthereum.vcxproj.filters b/windows/TestEthereum.vcxproj.filters index 4be707aec..f86265ab8 100644 --- a/windows/TestEthereum.vcxproj.filters +++ b/windows/TestEthereum.vcxproj.filters @@ -20,6 +20,7 @@ + From c4de0745e2eed27ef7c358a8eb8eff54c17a366d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Oct 2014 12:37:48 +0200 Subject: [PATCH 203/396] Fix Visual Studio solution bad build configuration --- windows/Ethereum.sln | 168 +++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/windows/Ethereum.sln b/windows/Ethereum.sln index df5916e63..4d2c7a3b4 100644 --- a/windows/Ethereum.sln +++ b/windows/Ethereum.sln @@ -59,86 +59,86 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Mixed Platforms.Build.0 = Release|x64 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.ActiveCfg = Release|x64 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.Build.0 = Release|x64 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.ActiveCfg = Release|x64 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.Build.0 = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.ActiveCfg = Debug|Win32 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|Win32.Build.0 = Debug|Win32 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.ActiveCfg = Debug|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Debug|x64.Build.0 = Debug|x64 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Mixed Platforms.ActiveCfg = Release|x64 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Mixed Platforms.Build.0 = Release|x64 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.ActiveCfg = Release|x64 - {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.Build.0 = Release|x64 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.ActiveCfg = Release|Win32 + {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|Win32.Build.0 = Release|Win32 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|x64.ActiveCfg = Release|x64 {826E68CB-D3EE-4A8A-B540-59A8C3F38D4F}.Release|x64.Build.0 = Release|x64 {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Mixed Platforms.Build.0 = Release|x64 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.ActiveCfg = Release|x64 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.Build.0 = Release|x64 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.ActiveCfg = Release|x64 - {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.Build.0 = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.ActiveCfg = Debug|Win32 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|Win32.Build.0 = Debug|Win32 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.ActiveCfg = Debug|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Debug|x64.Build.0 = Debug|x64 {27014763-955D-486B-9BA7-69872192E6F4}.Release|Mixed Platforms.ActiveCfg = Release|x64 {27014763-955D-486B-9BA7-69872192E6F4}.Release|Mixed Platforms.Build.0 = Release|x64 - {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.ActiveCfg = Release|x64 - {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.Build.0 = Release|x64 + {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.ActiveCfg = Release|Win32 + {27014763-955D-486B-9BA7-69872192E6F4}.Release|Win32.Build.0 = Release|Win32 {27014763-955D-486B-9BA7-69872192E6F4}.Release|x64.ActiveCfg = Release|x64 {27014763-955D-486B-9BA7-69872192E6F4}.Release|x64.Build.0 = Release|x64 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Mixed Platforms.Build.0 = Release|x64 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.ActiveCfg = Release|x64 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.Build.0 = Release|x64 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.ActiveCfg = Release|x64 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.Build.0 = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.ActiveCfg = Debug|Win32 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|Win32.Build.0 = Debug|Win32 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.ActiveCfg = Debug|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Debug|x64.Build.0 = Debug|x64 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Mixed Platforms.ActiveCfg = Release|x64 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Mixed Platforms.Build.0 = Release|x64 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.ActiveCfg = Release|x64 - {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.Build.0 = Release|x64 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.ActiveCfg = Release|Win32 + {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|Win32.Build.0 = Release|Win32 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|x64.ActiveCfg = Release|x64 {1E1175BB-C4A9-41D8-B2D1-9022F71D3CEA}.Release|x64.Build.0 = Release|x64 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Mixed Platforms.Build.0 = Release|x64 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.ActiveCfg = Release|x64 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.Build.0 = Release|x64 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.ActiveCfg = Release|x64 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.Build.0 = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.ActiveCfg = Debug|Win32 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|Win32.Build.0 = Debug|Win32 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.ActiveCfg = Debug|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Debug|x64.Build.0 = Debug|x64 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Mixed Platforms.ActiveCfg = Release|x64 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Mixed Platforms.Build.0 = Release|x64 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.ActiveCfg = Release|x64 - {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.Build.0 = Release|x64 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.ActiveCfg = Release|Win32 + {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|Win32.Build.0 = Release|Win32 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|x64.ActiveCfg = Release|x64 {3BF049F8-AF7E-4E1C-9627-3E94C887AF24}.Release|x64.Build.0 = Release|x64 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Mixed Platforms.Build.0 = Release|x64 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.ActiveCfg = Release|x64 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.Build.0 = Release|x64 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.ActiveCfg = Release|x64 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.Build.0 = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.ActiveCfg = Debug|Win32 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|Win32.Build.0 = Debug|Win32 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.ActiveCfg = Debug|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Debug|x64.Build.0 = Debug|x64 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Mixed Platforms.ActiveCfg = Release|x64 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Mixed Platforms.Build.0 = Release|x64 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.ActiveCfg = Release|x64 - {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.Build.0 = Release|x64 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.ActiveCfg = Release|Win32 + {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|Win32.Build.0 = Release|Win32 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|x64.ActiveCfg = Release|x64 {3F3E389B-88DE-41D5-A73B-4F6036E18B36}.Release|x64.Build.0 = Release|x64 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Mixed Platforms.Build.0 = Release|x64 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.ActiveCfg = Release|x64 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.Build.0 = Release|x64 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.ActiveCfg = Release|x64 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.Build.0 = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.ActiveCfg = Debug|Win32 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|Win32.Build.0 = Debug|Win32 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.ActiveCfg = Debug|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Debug|x64.Build.0 = Debug|x64 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Mixed Platforms.ActiveCfg = Release|x64 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Mixed Platforms.Build.0 = Release|x64 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.ActiveCfg = Release|x64 - {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.Build.0 = Release|x64 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.ActiveCfg = Release|Win32 + {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|Win32.Build.0 = Release|Win32 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|x64.ActiveCfg = Release|x64 {1CC213A4-3482-4211-B47B-172E90DAC7DE}.Release|x64.Build.0 = Release|x64 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Mixed Platforms.Build.0 = Release|x64 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.ActiveCfg = Release|x64 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.Build.0 = Release|x64 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.ActiveCfg = Release|x64 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.Build.0 = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.ActiveCfg = Debug|Win32 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|Win32.Build.0 = Debug|Win32 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.ActiveCfg = Debug|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Debug|x64.Build.0 = Debug|x64 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Mixed Platforms.ActiveCfg = Release|x64 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Mixed Platforms.Build.0 = Release|x64 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.ActiveCfg = Release|x64 - {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.Build.0 = Release|x64 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.ActiveCfg = Release|Win32 + {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|Win32.Build.0 = Release|Win32 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|x64.ActiveCfg = Release|x64 {1B1CA20E-39C3-4D9B-AC37-3783048E6672}.Release|x64.Build.0 = Release|x64 {BFCFFC46-78A3-4350-9938-0EA3A2B1CCCD}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 @@ -163,14 +163,14 @@ Global {DF3C5B07-A1A2-4F16-B37F-A27333622CDD}.Release|x64.Build.0 = Release|x64 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Mixed Platforms.Build.0 = Release|x64 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.ActiveCfg = Release|x64 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.Build.0 = Release|x64 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.ActiveCfg = Release|x64 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.Build.0 = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.ActiveCfg = Debug|Win32 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|Win32.Build.0 = Debug|Win32 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.ActiveCfg = Debug|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Debug|x64.Build.0 = Debug|x64 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Mixed Platforms.ActiveCfg = Release|x64 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Mixed Platforms.Build.0 = Release|x64 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.ActiveCfg = Release|x64 - {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.Build.0 = Release|x64 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.ActiveCfg = Release|Win32 + {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|Win32.Build.0 = Release|Win32 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|x64.ActiveCfg = Release|x64 {C60C065C-2135-4B2B-AFD4-35FD7AC56B40}.Release|x64.Build.0 = Release|x64 {90C70663-7181-4E99-9079-54188CEB8954}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 @@ -187,74 +187,74 @@ Global {90C70663-7181-4E99-9079-54188CEB8954}.Release|x64.Build.0 = Release|x64 {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Mixed Platforms.Build.0 = Release|x64 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.ActiveCfg = Release|x64 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.Build.0 = Release|x64 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.ActiveCfg = Release|x64 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.Build.0 = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.ActiveCfg = Debug|Win32 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|Win32.Build.0 = Debug|Win32 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.ActiveCfg = Debug|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Debug|x64.Build.0 = Debug|x64 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Mixed Platforms.ActiveCfg = Release|x64 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Mixed Platforms.Build.0 = Release|x64 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.ActiveCfg = Release|x64 - {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.Build.0 = Release|x64 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.ActiveCfg = Release|Win32 + {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|Win32.Build.0 = Release|Win32 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|x64.ActiveCfg = Release|x64 {F174E81A-2A66-4693-B917-11BB42D3658C}.Release|x64.Build.0 = Release|x64 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Mixed Platforms.Build.0 = Release|x64 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.ActiveCfg = Release|x64 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.Build.0 = Release|x64 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.ActiveCfg = Release|x64 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.Build.0 = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.ActiveCfg = Debug|Win32 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|Win32.Build.0 = Debug|Win32 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.ActiveCfg = Debug|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Debug|x64.Build.0 = Debug|x64 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Mixed Platforms.ActiveCfg = Release|x64 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Mixed Platforms.Build.0 = Release|x64 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.ActiveCfg = Release|x64 - {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.Build.0 = Release|x64 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.ActiveCfg = Release|Win32 + {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|Win32.Build.0 = Release|Win32 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|x64.ActiveCfg = Release|x64 {9AA5CF66-1150-4A02-B40E-3B89740DADB8}.Release|x64.Build.0 = Release|x64 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Mixed Platforms.Build.0 = Release|x64 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.ActiveCfg = Release|x64 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.Build.0 = Release|x64 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.ActiveCfg = Release|x64 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.Build.0 = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.ActiveCfg = Debug|Win32 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|Win32.Build.0 = Debug|Win32 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.ActiveCfg = Debug|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Debug|x64.Build.0 = Debug|x64 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Mixed Platforms.ActiveCfg = Release|x64 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Mixed Platforms.Build.0 = Release|x64 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.ActiveCfg = Release|x64 - {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.Build.0 = Release|x64 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.ActiveCfg = Release|Win32 + {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|Win32.Build.0 = Release|Win32 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|x64.ActiveCfg = Release|x64 {90068D1B-070E-4C41-88B0-1E243E1E5BFF}.Release|x64.Build.0 = Release|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Mixed Platforms.Build.0 = Release|x64 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.ActiveCfg = Release|x64 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.Build.0 = Release|x64 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.ActiveCfg = Release|x64 - {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.Build.0 = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.ActiveCfg = Debug|Win32 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|Win32.Build.0 = Debug|Win32 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.ActiveCfg = Debug|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Debug|x64.Build.0 = Debug|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Release|Mixed Platforms.ActiveCfg = Release|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Release|Mixed Platforms.Build.0 = Release|x64 - {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.ActiveCfg = Release|x64 - {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.Build.0 = Release|x64 + {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.ActiveCfg = Release|Win32 + {255BDC68-B8DB-465F-8220-981E77684189}.Release|Win32.Build.0 = Release|Win32 {255BDC68-B8DB-465F-8220-981E77684189}.Release|x64.ActiveCfg = Release|x64 {255BDC68-B8DB-465F-8220-981E77684189}.Release|x64.Build.0 = Release|x64 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Mixed Platforms.Build.0 = Release|x64 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.ActiveCfg = Release|x64 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.Build.0 = Release|x64 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|x64.ActiveCfg = Release|x64 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|x64.Build.0 = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.ActiveCfg = Debug|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|Win32.Build.0 = Debug|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|x64.ActiveCfg = Debug|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Debug|x64.Build.0 = Debug|x64 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Mixed Platforms.ActiveCfg = Release|x64 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Mixed Platforms.Build.0 = Release|x64 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.ActiveCfg = Release|x64 - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.Build.0 = Release|x64 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.ActiveCfg = Release|Win32 + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|Win32.Build.0 = Release|Win32 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|x64.ActiveCfg = Release|x64 {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D}.Release|x64.Build.0 = Release|x64 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Mixed Platforms.ActiveCfg = Release|x64 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Mixed Platforms.Build.0 = Release|x64 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.ActiveCfg = Release|x64 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.Build.0 = Release|x64 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.ActiveCfg = Release|x64 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.Build.0 = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.ActiveCfg = Debug|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|Win32.Build.0 = Debug|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.ActiveCfg = Debug|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Debug|x64.Build.0 = Debug|x64 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Mixed Platforms.ActiveCfg = Release|x64 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Mixed Platforms.Build.0 = Release|x64 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.ActiveCfg = Release|x64 - {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.Build.0 = Release|x64 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.ActiveCfg = Release|Win32 + {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.Build.0 = Release|Win32 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|x64.ActiveCfg = Release|x64 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|x64.Build.0 = Release|x64 EndGlobalSection From eb347cb24c5e9151758bc157e7638cdd13117789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Oct 2014 12:38:45 +0200 Subject: [PATCH 204/396] Update createRandomTest.cpp to use new VM construction method --- libevm/VM.h | 3 +-- test/createRandomTest.cpp | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 344764d87..2ddf16bb6 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -52,11 +52,10 @@ public: bytes const& memory() const { return m_temp; } u256s const& stack() const { return m_stack; } +private: friend VMFace; explicit VM(u256 _gas = 0): VMFace(_gas) {} -private: - template bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp, uint64_t _steps); diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 874869a5c..dbe50851a 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -97,7 +97,9 @@ void doMyTests(json_spirit::mValue& v) assert(o.count("pre") > 0); assert(o.count("exec") > 0); - eth::VM vm; + + auto vmObj = eth::VMFace::create(eth::VMFace::Interpreter); + auto& vm = *vmObj; test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); From 0a14243ca1f38cc8558457296b6bcea6daea1355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Oct 2014 12:39:20 +0200 Subject: [PATCH 205/396] Change directory separator in LLVM.props (Visual Studio) --- windows/LLVM.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/LLVM.props b/windows/LLVM.props index 42be9a170..a5c6c4dc5 100644 --- a/windows/LLVM.props +++ b/windows/LLVM.props @@ -3,8 +3,8 @@ 1 - ..\..\llvm - ..\..\_build\llvm\$(Platform) + ../../llvm + ../../_build/llvm/$(Platform) $(LLVMSrcDir)\include;$(LLVMBuildDir)\include $(LLVMBuildDir)\$(Configuration)\lib LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib From 4d601dc9554f75c45a0a335edf920abcda31e954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Oct 2014 12:40:18 +0200 Subject: [PATCH 206/396] Remove createRandomTest.cpp from TestEthereum project (Visual Studio) --- windows/TestEthereum.vcxproj | 2 -- windows/TestEthereum.vcxproj.filters | 1 - 2 files changed, 3 deletions(-) diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index 1ef821380..557a899b3 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -111,7 +111,6 @@ Console true - ../../builds/llvm3.5/Debug/lib;../../_build/LibEvmJit/x64_Debug;../../_build/LibEthereum/x64_Debug;../../_build/LibSecp256k1/x64_Debug;../../_build/LibCryptoPP/x64_Debug;%(AdditionalLibraryDirectories) @@ -159,7 +158,6 @@ - diff --git a/windows/TestEthereum.vcxproj.filters b/windows/TestEthereum.vcxproj.filters index f86265ab8..4be707aec 100644 --- a/windows/TestEthereum.vcxproj.filters +++ b/windows/TestEthereum.vcxproj.filters @@ -20,7 +20,6 @@ - From b2f0fddeadeab9f0dcdcc6de858cfe56ac91b5d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Oct 2014 14:37:01 +0200 Subject: [PATCH 207/396] Add vm.h file to TestEthereum project (Visual Studio) --- windows/TestEthereum.vcxproj | 1 + windows/TestEthereum.vcxproj.filters | 1 + 2 files changed, 2 insertions(+) diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index 557a899b3..94667fa16 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -185,6 +185,7 @@ + diff --git a/windows/TestEthereum.vcxproj.filters b/windows/TestEthereum.vcxproj.filters index 4be707aec..bd2253c5e 100644 --- a/windows/TestEthereum.vcxproj.filters +++ b/windows/TestEthereum.vcxproj.filters @@ -34,5 +34,6 @@ + \ No newline at end of file From 7aa2b25220dc2fa7c56bcf41310759344eafe5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Oct 2014 15:27:18 +0200 Subject: [PATCH 208/396] Add option to set VM kind in State. Interpreter by default. --- libethereum/State.cpp | 12 +++++++----- libethereum/State.h | 9 +++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index b51224e32..3099530b2 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -166,7 +166,8 @@ State::State(State const& _s): m_previousBlock(_s.m_previousBlock), m_currentBlock(_s.m_currentBlock), m_ourAddress(_s.m_ourAddress), - m_blockReward(_s.m_blockReward) + m_blockReward(_s.m_blockReward), + m_vmKind(_s.m_vmKind) { paranoia("after state cloning (copy cons).", true); } @@ -199,6 +200,7 @@ State& State::operator=(State const& _s) m_ourAddress = _s.m_ourAddress; m_blockReward = _s.m_blockReward; m_lastTx = _s.m_lastTx; + m_vmKind = _s.m_vmKind; paranoia("after state cloning (assignment op)", true); return *this; } @@ -1146,8 +1148,8 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA } else if (addressHasCode(_codeAddress)) { - auto vmObj = VMFace::create(VMFace::Interpreter, *_gas); - VMFace& vm = *vmObj; + auto vmObj = VMFace::create(getVMKind(), *_gas); + auto& vm = *vmObj; ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level); bool revert = false; @@ -1209,8 +1211,8 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, m_cache[newAddress] = AddressState(0, balance(newAddress) + _endowment, h256(), h256()); // Execute init code. - auto vmObj = VMFace::create(VMFace::Interpreter, *_gas); - VMFace& vm = *vmObj; + auto vmObj = VMFace::create(getVMKind(), *_gas); + auto& vm = *vmObj; ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); bool revert = false; bytesConstRef out; diff --git a/libethereum/State.h b/libethereum/State.h index dd6043c73..a3641a3cb 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -32,6 +32,7 @@ #include #include #include +#include #include "TransactionQueue.h" #include "AddressState.h" #include "Transaction.h" @@ -264,6 +265,12 @@ public: /// the block since all state changes are ultimately reversed. void cleanup(bool _fullCommit); + /// Sets VM kind to be used by the state + void setVMKind(VMFace::Kind _kind) { m_vmKind = _kind; } + + /// Get the kind of VM used by the state + VMFace::Kind getVMKind() const { return m_vmKind; } + private: /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -330,6 +337,8 @@ private: u256 m_blockReward; + VMFace::Kind m_vmKind = VMFace::Interpreter; ///< The kind of VM used by the state + static std::string c_defaultPath; static const std::map c_precompiled; From 2d0557e2ee236b73546d6dd9f3ed7d19ec852a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Oct 2014 15:28:08 +0200 Subject: [PATCH 209/396] Expose VM kind setting of State in FakeExtVM --- test/vm.cpp | 19 ++++++++++--------- test/vm.h | 2 ++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index d62329af4..d68a30c6b 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -436,8 +436,8 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end m_cache[_newAddress] = AddressState(0, balance(_newAddress) + _endowment, h256(), h256()); // Execute init code. - auto vmObj = VMFace::create(VMFace::Interpreter, *_gas); - VMFace& vm = *vmObj; + auto vmObj = VMFace::create(getVMKind(), *_gas); + auto& vm = *vmObj; ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); bool revert = false; bytesConstRef out; @@ -499,7 +499,14 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_REQUIRE(o.count("pre") > 0); BOOST_REQUIRE(o.count("exec") > 0); + auto argc = boost::unit_test::framework::master_test_suite().argc; + auto argv = boost::unit_test::framework::master_test_suite().argv; + auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; + auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; + dev::test::FakeExtVM fev; + fev.setVMKind(vmKind); + fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -512,14 +519,8 @@ void doTests(json_spirit::mValue& v, bool _fillin) fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); fev.code = &fev.thisTxCode; } - - - auto argc = boost::unit_test::framework::master_test_suite().argc; - auto argv = boost::unit_test::framework::master_test_suite().argv; - auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; - auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; - auto vm = VMFace::create(vmKind, fev.gas); + auto vm = VMFace::create(fev.getVMKind(), fev.gas); bytes output; auto outOfGas = false; try diff --git a/test/vm.h b/test/vm.h index a9897bee3..2069cad3d 100644 --- a/test/vm.h +++ b/test/vm.h @@ -79,6 +79,8 @@ public: void importExec(json_spirit::mObject& _o); json_spirit::mArray exportCallCreates(); void importCallCreates(json_spirit::mArray& _callcreates); + void setVMKind(eth::VMFace::Kind _kind) { m_s.setVMKind(_kind); } + eth::VMFace::Kind getVMKind() const { return m_s.getVMKind(); } std::map, bytes>> addresses; eth::Transactions callcreates; From 6ad065bb3e30b5e67283f70e84ac55368e843e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 23 Oct 2014 15:49:12 +0200 Subject: [PATCH 210/396] Revert "Expose VM kind setting of State in FakeExtVM" This reverts commit 2d0557e2ee236b73546d6dd9f3ed7d19ec852a0f. --- test/vm.cpp | 19 +++++++++---------- test/vm.h | 2 -- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index d68a30c6b..d62329af4 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -436,8 +436,8 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end m_cache[_newAddress] = AddressState(0, balance(_newAddress) + _endowment, h256(), h256()); // Execute init code. - auto vmObj = VMFace::create(getVMKind(), *_gas); - auto& vm = *vmObj; + auto vmObj = VMFace::create(VMFace::Interpreter, *_gas); + VMFace& vm = *vmObj; ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); bool revert = false; bytesConstRef out; @@ -499,14 +499,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_REQUIRE(o.count("pre") > 0); BOOST_REQUIRE(o.count("exec") > 0); - auto argc = boost::unit_test::framework::master_test_suite().argc; - auto argv = boost::unit_test::framework::master_test_suite().argv; - auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; - auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; - dev::test::FakeExtVM fev; - fev.setVMKind(vmKind); - fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -519,8 +512,14 @@ void doTests(json_spirit::mValue& v, bool _fillin) fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); fev.code = &fev.thisTxCode; } + + + auto argc = boost::unit_test::framework::master_test_suite().argc; + auto argv = boost::unit_test::framework::master_test_suite().argv; + auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; - auto vm = VMFace::create(fev.getVMKind(), fev.gas); + auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; + auto vm = VMFace::create(vmKind, fev.gas); bytes output; auto outOfGas = false; try diff --git a/test/vm.h b/test/vm.h index 2069cad3d..a9897bee3 100644 --- a/test/vm.h +++ b/test/vm.h @@ -79,8 +79,6 @@ public: void importExec(json_spirit::mObject& _o); json_spirit::mArray exportCallCreates(); void importCallCreates(json_spirit::mArray& _callcreates); - void setVMKind(eth::VMFace::Kind _kind) { m_s.setVMKind(_kind); } - eth::VMFace::Kind getVMKind() const { return m_s.getVMKind(); } std::map, bytes>> addresses; eth::Transactions callcreates; From cdb49404ddb7237f7b705d4c3ccf16a646e6eae6 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 23 Oct 2014 23:56:56 +0100 Subject: [PATCH 211/396] Refactored local stack [#81180320] --- libevmjit/BasicBlock.cpp | 201 +++++++++++++++++++++++++++++----- libevmjit/BasicBlock.h | 70 ++++++++---- libevmjit/Compiler.cpp | 66 +++++++---- libevmjit/Compiler.h | 2 +- libevmjit/ExecutionEngine.cpp | 5 +- libevmjit/Stack.cpp | 65 ++++++++--- libevmjit/Stack.h | 12 +- libevmjit/Type.cpp | 3 + libevmjit/Type.h | 2 + 9 files changed, 342 insertions(+), 84 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 2c5ea7285..13d66140f 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -1,8 +1,11 @@ #include "BasicBlock.h" +#include + #include #include +#include #include "Type.h" @@ -15,65 +18,211 @@ namespace jit const char* BasicBlock::NamePrefix = "Instr."; -BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc) : +BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : m_beginInstIdx(_beginInstIdx), m_endInstIdx(_endInstIdx), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)), - m_stack(m_llvmBB) + m_stack(_builder) {} -BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc) : +BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : m_beginInstIdx(0), m_endInstIdx(0), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), - m_stack(m_llvmBB) + m_stack(_builder) {} +BasicBlock::LocalStack::LocalStack(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_initialStack(), + m_currentStack(), + m_tosOffset(0) +{} void BasicBlock::LocalStack::push(llvm::Value* _value) { - assert(_value->getType() == Type::i256); - m_backend.push_back(_value); + m_currentStack.push_back(_value); + m_tosOffset += 1; } llvm::Value* BasicBlock::LocalStack::pop() { - auto top = get(0); - m_backend.pop_back(); - return top; + auto result = get(0); + + if (m_currentStack.size() > 0) + m_currentStack.pop_back(); + + m_tosOffset -= 1; + return result; +} + +/** + * Pushes a copy of _index-th element (tos is 0-th elem). + */ +void BasicBlock::LocalStack::dup(size_t _index) +{ + auto val = get(_index); + push(val); +} + +/** + * Swaps tos with _index-th element (tos is 0-th elem). + * _index must be > 0. + */ +void BasicBlock::LocalStack::swap(size_t _index) +{ + assert(_index > 0); + auto val = get(_index); + auto tos = get(0); + set(_index, tos); + set(0, val); +} + +void BasicBlock::LocalStack::synchronize(Stack& _evmStack) +{ + auto blockTerminator = m_builder.GetInsertBlock()->getTerminator(); + assert(blockTerminator != nullptr); + m_builder.SetInsertPoint(blockTerminator); + + auto currIter = m_currentStack.begin(); + auto endIter = m_currentStack.end(); + + // Update (emit set()) changed values + for (int idx = m_currentStack.size() - 1 - m_tosOffset; + currIter < endIter && idx >= 0; + ++currIter, --idx) + { + assert(static_cast(idx) < m_initialStack.size()); + if (*currIter != m_initialStack[idx]) // value needs update + _evmStack.set(static_cast(idx), *currIter); + } + + if (m_tosOffset < 0) + { + // Pop values + _evmStack.pop(static_cast(-m_tosOffset)); + } + + // Push new values + for ( ; currIter < endIter; ++currIter) + { + assert(*currIter != nullptr); + _evmStack.push(*currIter); + } + + // Emit get() for all (used) values from the initial stack + for (size_t idx = 0; idx < m_initialStack.size(); ++idx) + { + auto val = m_initialStack[idx]; + if (val == nullptr) + continue; + + assert(llvm::isa(val)); + llvm::PHINode* phi = llvm::cast(val); + if (! phi->use_empty()) + { + // Insert call to get() just before the PHI node and replace + // the uses of PHI with the uses of this new instruction. + m_builder.SetInsertPoint(phi); + auto newVal = _evmStack.get(idx); + phi->replaceAllUsesWith(newVal); + } + phi->eraseFromParent(); + } + + // Reset the stack + m_initialStack.erase(m_initialStack.begin(), m_initialStack.end()); + m_currentStack.erase(m_currentStack.begin(), m_currentStack.end()); + m_tosOffset = 0; +} + +std::vector::iterator BasicBlock::LocalStack::getItemIterator(size_t _index) +{ + if (_index < m_currentStack.size()) + return m_currentStack.end() - _index - 1; + + // Need to map more elements from the EVM stack + auto nNewItems = 1 + _index - m_currentStack.size(); + m_currentStack.insert(m_currentStack.begin(), nNewItems, nullptr); + + return m_currentStack.end() - _index - 1; } llvm::Value* BasicBlock::LocalStack::get(size_t _index) -{ - if (_index >= m_backend.size()) +{ + auto itemIter = getItemIterator(_index); + + if (*itemIter == nullptr) { - // Create PHI node for missing values - auto nMissingVals = _index - m_backend.size() + 1; - m_backend.insert(m_backend.begin(), nMissingVals, nullptr); - for (decltype(nMissingVals) i = 0; i < nMissingVals; ++i) + // Need to fetch a new item from the EVM stack + assert(static_cast(_index) >= m_tosOffset); + size_t initialIdx = _index - m_tosOffset; + if (initialIdx >= m_initialStack.size()) { - m_backend[nMissingVals - 1 - i] = m_llvmBB->empty() ? - llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB) : - llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI()); - m_numRequiredStackItems += 1; + auto nNewItems = 1 + initialIdx - m_initialStack.size(); + m_initialStack.insert(m_initialStack.end(), nNewItems, nullptr); } + + assert(m_initialStack[initialIdx] == nullptr); + // Create a dummy value. + std::string name = "get_" + boost::lexical_cast(_index); + m_initialStack[initialIdx] = m_builder.CreatePHI(Type::i256, 0, name); + *itemIter = m_initialStack[initialIdx]; } - return *(m_backend.rbegin() + _index); + return *itemIter; } -void BasicBlock::LocalStack::dup(size_t _index) +void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word) { - m_backend.push_back(get(_index)); + auto itemIter = getItemIterator(_index); + *itemIter = _word; } -void BasicBlock::LocalStack::swap(size_t _index) + +void BasicBlock::dump() { - assert(_index != 0); - get(_index); // Create PHI nodes - std::swap(*m_backend.rbegin(), *(m_backend.rbegin() + _index)); + std::cerr << "Initial stack:\n"; + for (auto val : m_stack.m_initialStack) + { + if (val == nullptr) + std::cerr << " ?\n"; + else if (llvm::isa(val)) + val->dump(); + else + { + std::cerr << " "; + val->dump(); + } + } + std::cerr << " ...\n"; + + std::cerr << "Instructions:\n"; + for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) + ins->dump(); + + std::cerr << "Current stack (offset = " + << m_stack.m_tosOffset << "):\n"; + + for (auto val = m_stack.m_currentStack.rbegin(); val != m_stack.m_currentStack.rend(); ++val) + { + if (*val == nullptr) + std::cerr << " ?\n"; + else if (llvm::isa(*val)) + (*val)->dump(); + else + { + std::cerr << " "; + (*val)->dump(); + } + + } + std::cerr << " ...\n----------------------------------------\n"; } + + + } } } diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 51a48c6e0..2723cf919 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -1,8 +1,11 @@ +#pragma once #include #include +#include "Stack.h" + namespace dev { namespace eth @@ -18,49 +21,72 @@ public: class LocalStack { public: + /// Pushes value on stack void push(llvm::Value* _value); /// Pops and returns top value llvm::Value* pop(); - /// Gets _index'th value from top (counting from 0) - llvm::Value* get(size_t _index); - - /// Duplicates _index'th value on stack. + /// Duplicates _index'th value on stack void dup(size_t _index); /// Swaps _index'th value on stack with a value on stack top. - /// @param _index Index of value to be swaped. Cannot be 0. + /// @param _index Index of value to be swaped. Must be > 0. void swap(size_t _index); - /// Size of the stack - size_t size() const { return m_backend.size(); } - - size_t initialSize() const { return m_numRequiredStackItems; } + /// Synchronize current local stack with the EVM stack. + void synchronize(Stack& _evmStack); private: - // LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB) {} - LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB), m_numRequiredStackItems(0) {} + + LocalStack(llvm::IRBuilder<>& _builder); LocalStack(LocalStack const&) = delete; void operator=(LocalStack const&) = delete; friend BasicBlock; + /// Gets _index'th value from top (counting from 0) + llvm::Value* get(size_t _index); + + /// Sets _index'th value from top (counting from 0) + void set(size_t _index, llvm::Value* _value); + + std::vector::iterator getItemIterator(size_t _index); + private: - std::vector m_backend; - /** Basic block into which phi nodes are inserted */ - llvm::BasicBlock* m_llvmBB; + llvm::IRBuilder<>& m_builder; + + /** + * This stack contains LLVM values that correspond to items found at + * the EVM stack when the current basic block starts executing. + * Location 0 corresponds to the top of the EVM stack, location 1 is + * the item below the top and so on. The stack grows as the code + * accesses more items on the EVM stack but once a value is put on + * the stack, it will never be replaced. + */ + std::vector m_initialStack; + + /** + * This stack tracks the contents of the EVM stack as the current basic + * block executes. It may grow on both sides, as the code pushes items on + * top of the stack or changes existing items. + */ + std::vector m_currentStack; + + /** + * How many items higher is the current stack than the initial one. + * May be negative. + */ + int m_tosOffset; - /** Number of items required on the EVM stack at the beginning of the block */ - size_t m_numRequiredStackItems; }; /// Basic block name prefix. The rest is beging instruction index. static const char* NamePrefix; - explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc); - explicit BasicBlock(std::string _name, llvm::Function* _mainFunc); + explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); + explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); BasicBlock(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete; @@ -68,11 +94,15 @@ public: operator llvm::BasicBlock*() { return m_llvmBB; } llvm::BasicBlock* llvm() { return m_llvmBB; } - LocalStack& getStack() { return m_stack; } - ProgramCounter begin() { return m_beginInstIdx; } ProgramCounter end() { return m_endInstIdx; } + LocalStack& localStack() { return m_stack; } + + /// Prints local stack and block instructions to stderr. + /// Useful for calling in a debugger session. + void dump(); + private: ProgramCounter const m_beginInstIdx; ProgramCounter const m_endInstIdx; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 71661bde9..1b408d6fe 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -123,12 +123,12 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) auto beginInstIdx = *it; ++it; auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size(); - basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc)); + basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); } m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc); - m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc); + m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc, m_builder); + m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc, m_builder); for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { @@ -186,6 +186,9 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) ++iterCopy; auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock); + if (getenv("EVMCC_DEBUG_BLOCKS")) + basicBlock.dump(); + basicBlock.localStack().synchronize(stack); } // Code for special blocks: @@ -201,9 +204,9 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) { - auto& stack = m_jumpTableBlock->getStack(); + // auto& stack = m_jumpTableBlock->getStack(); - auto dest = stack.pop(); + auto dest = m_jumpTableBlock->localStack().pop(); //m_jumpTableBlock->localGet(0); // stack.pop(); auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), m_indirectJumpTargets.size()); for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) @@ -218,7 +221,8 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) m_builder.CreateBr(m_badJumpBlock->llvm()); } - linkBasicBlocks(stack); + m_jumpTableBlock->localStack().synchronize(stack); + linkBasicBlocks(); return module; } @@ -226,8 +230,8 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) { - auto& stack = basicBlock.getStack(); m_builder.SetInsertPoint(basicBlock.llvm()); + auto& stack = basicBlock.localStack(); for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) { @@ -589,8 +593,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } else { - // FIXME: this get(0) is a temporary workaround to get some of the jump tests running. - stack.get(0); m_builder.CreateBr(m_jumpTableBlock->llvm()); } } @@ -873,7 +875,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } -void Compiler::linkBasicBlocks(Stack& stack) +void Compiler::linkBasicBlocks() // Stack& stack) { // Remove dead basic blocks auto sthErased = false; @@ -902,13 +904,14 @@ void Compiler::linkBasicBlocks(Stack& stack) m_jumpTableBlock.reset(); } - +/* struct BBInfo { BasicBlock& bblock; std::vector predecessors; size_t inputItems; size_t outputItems; + std::vector phisToRewrite; BBInfo(BasicBlock& _bblock) : bblock(_bblock), @@ -978,7 +981,8 @@ void Compiler::linkBasicBlocks(Stack& stack) } } - std::map phiReplacements; + // std::map phiReplacements; + // std::vector phiNodesToRewrite; // Propagate values between blocks. for (auto& pair : cfg) @@ -1001,13 +1005,14 @@ void Compiler::linkBasicBlocks(Stack& stack) } // Turn the remaining phi nodes into stack.pop's. - m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI())); + // m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI())); for (; llvm::isa(*instrIter); ++instrIter) { auto phi = llvm::cast(instrIter); - auto value = stack.popWord(); + // auto value = stack.popWord(); // Don't delete the phi node yet. It may still be stored in a local stack of some block. - phiReplacements[phi] = value; + // phiReplacements[phi] = value; + bbInfo.phisToRewrite.push_back(phi); } // Emit stack push's at the end of the block, just before the terminator; @@ -1018,11 +1023,33 @@ void Compiler::linkBasicBlocks(Stack& stack) stack.pushWord(bblock.getStack().get(localStackSize - 1 - i)); } - for (auto& entry : phiReplacements) + for (auto& entry : cfg) { - entry.first->replaceAllUsesWith(entry.second); - entry.first->eraseFromParent(); + // Where was the last stack.pop() inserted + auto lastPopIt = entry.first->begin(); + + for (auto phi : entry.second.phisToRewrite) + { + // Insert stack.pop() before the first use of phi, + // then replace all uses of phi with the popped val. + + if (phi->use_begin() == phi->use_end()) + { + // For a phi with no uses, insert pop just after the previous one + } + std::cout << "*** PHI node " << phi->getName().str() << " has no uses!\n"; + } + else + { + assert(llvm::isa(phi->use_begin()->getUser())); + + m_builder.SetInsertPoint(*phi->use_begin()); + auto popVal = stack.popWord(); + phi->replaceAllUsesWith(popVal); + phi->eraseFromParent(); + } } + */ } void Compiler::dumpBasicBlockGraph(std::ostream& out) @@ -1030,7 +1057,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) out << "digraph BB {\n" << " node [shape=record];\n" << " entry [share=record, label=\"entry block\"];\n"; - +/* std::vector blocks; for (auto& pair : this->basicBlocks) blocks.push_back(&pair.second); @@ -1076,6 +1103,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) } out << "}\n"; + */ } } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index ac6277e7b..9d7b37fbc 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -33,7 +33,7 @@ private: void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); - void linkBasicBlocks(class Stack& stack); + void linkBasicBlocks(); //class Stack& stack); llvm::IRBuilder<> m_builder; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 4bcaf2c50..af5f96ac7 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,7 @@ #include "Runtime.h" #include "Memory.h" +#include "Stack.h" #include "Type.h" namespace dev @@ -35,7 +36,6 @@ ExecutionEngine::ExecutionEngine() extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; } - int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtVMFace* _ext) { auto module = _module.get(); // Keep ownership of the module in _module @@ -117,6 +117,8 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV // Return remaining gas _gas = returnCode == ReturnCode::OutOfGas ? 0 : Runtime::getGas(); + std::cout << "Max stack size: " << Stack::maxStackSize << std::endl; + if (returnCode == ReturnCode::Return) { returnData = Memory::getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface @@ -128,6 +130,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV } std::cout << "RETURN CODE: " << (int)returnCode << std::endl; + return static_cast(returnCode); } diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index ce7d09471..89044bea8 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -17,34 +17,48 @@ namespace jit Stack::Stack(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) { - auto i256Ty = m_builder.getIntNTy(256); - auto i256PtrTy = i256Ty->getPointerTo(); - - m_arg = m_builder.CreateAlloca(i256Ty, nullptr, "stack.retVal"); + m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg"); using namespace llvm; using Linkage = GlobalValue::LinkageTypes; auto module = getModule(); - m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_push", module); - m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_pop", module); + m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::WordPtr, false), Linkage::ExternalLinkage, "stack_push", module); + m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::Size, false), Linkage::ExternalLinkage, "stack_pop", module); + llvm::Type* getSetArgTypes[] = {Type::Size, Type::WordPtr}; + m_get = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_get", module); + m_set = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_set", module); } Stack::~Stack() {} -llvm::Instruction* Stack::popWord() +llvm::Value* Stack::get(size_t _index) { - m_builder.CreateCall(m_pop, m_arg); + m_builder.CreateCall2(m_get, llvm::ConstantInt::get(Type::Size, _index, false), m_arg); return m_builder.CreateLoad(m_arg); } -void Stack::pushWord(llvm::Value* _word) +void Stack::set(size_t _index, llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_arg); + m_builder.CreateCall2(m_set, llvm::ConstantInt::get(Type::Size, _index, false), m_arg); +} + +void Stack::pop(size_t _count) { - m_builder.CreateStore(_word, m_arg); + m_builder.CreateCall(m_pop, llvm::ConstantInt::get(Type::Size, _count, false)); +} + +void Stack::push(llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_arg); m_builder.CreateCall(m_push, m_arg); } + +size_t Stack::maxStackSize = 0; + } } } @@ -56,21 +70,42 @@ using namespace dev::eth::jit; extern std::jmp_buf* rt_jmpBuf; -EXPORT void stack_pop(i256* _ret) +EXPORT void stack_pop(uint64_t _count) { auto& stack = Runtime::getStack(); - if (stack.size() == 0) + if (stack.size() < _count) longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); - assert(stack.size() > 0); - *_ret = stack.back(); - stack.pop_back(); + stack.erase(stack.end() - _count, stack.end()); } EXPORT void stack_push(i256* _word) { auto& stack = Runtime::getStack(); stack.push_back(*_word); + + if (stack.size() > Stack::maxStackSize) + Stack::maxStackSize = stack.size(); +} + +EXPORT void stack_get(uint64_t _index, i256* _ret) +{ + auto& stack = Runtime::getStack(); + // TODO: encode _index and stack size in the return code + if (stack.size() <= _index) + longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + + *_ret = *(stack.rbegin() + _index); +} + +EXPORT void stack_set(uint64_t _index, i256* _word) +{ + auto& stack = Runtime::getStack(); + // TODO: encode _index and stack size in the return code + if (stack.size() <= _index) + longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + + *(stack.rbegin() + _index) = *_word; } } // extern "C" diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index 5e1ac0f39..2380b2a15 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -14,15 +14,23 @@ namespace jit class Stack : public CompilerHelper { public: + Stack(llvm::IRBuilder<>& builder); virtual ~Stack(); - void pushWord(llvm::Value* _word); - llvm::Instruction* popWord(); + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; private: + llvm::Function* m_push; llvm::Function* m_pop; + llvm::Function* m_get; + llvm::Function* m_set; llvm::Value* m_arg; }; diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 3ef339a1b..baf458dbd 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -13,6 +13,7 @@ namespace jit llvm::IntegerType* Type::i256; llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; +llvm::IntegerType* Type::Size; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -23,6 +24,8 @@ void Type::init(llvm::LLVMContext& _context) i256 = llvm::Type::getIntNTy(_context, 256); WordPtr = i256->getPointerTo(); lowPrecision = llvm::Type::getInt64Ty(_context); + // TODO: Size should be architecture-dependent + Size = llvm::Type::getInt64Ty(_context); Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); diff --git a/libevmjit/Type.h b/libevmjit/Type.h index a03bfac38..16a13c373 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -20,6 +20,8 @@ struct Type /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required static llvm::IntegerType* lowPrecision; + static llvm::IntegerType* Size; + static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; From 9ec5ffd7d7f79c005c081e2ce186ca5d07cb40ac Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 24 Oct 2014 00:00:25 +0100 Subject: [PATCH 212/396] new test cases --- evmcc/test/jump/ackermann.ethel | 7 +++++++ evmcc/test/jump/ackermann.evm | 1 + evmcc/test/jump/fac.ethel | 5 +++++ evmcc/test/jump/fac.evm | 1 + evmcc/test/jump/fac_tail.ethel | 5 +++++ evmcc/test/jump/fac_tail.evm | 1 + evmcc/test/stack/oos.evm | 1 + evmcc/test/stack/oos.lll | 11 +++++++++++ evmcc/test/stack/swap.evm | 1 + evmcc/test/stack/swap.lll | 25 +++++++++++++++++++++++++ evmcc/test/stack/swapswap.evm | 1 + evmcc/test/stack/swapswap.lll | 26 ++++++++++++++++++++++++++ evmcc/test/stack/test.evm | 1 + 13 files changed, 86 insertions(+) create mode 100644 evmcc/test/jump/ackermann.ethel create mode 100644 evmcc/test/jump/ackermann.evm create mode 100644 evmcc/test/jump/fac.ethel create mode 100644 evmcc/test/jump/fac.evm create mode 100644 evmcc/test/jump/fac_tail.ethel create mode 100644 evmcc/test/jump/fac_tail.evm create mode 100644 evmcc/test/stack/oos.evm create mode 100644 evmcc/test/stack/oos.lll create mode 100644 evmcc/test/stack/swap.evm create mode 100644 evmcc/test/stack/swap.lll create mode 100644 evmcc/test/stack/swapswap.evm create mode 100644 evmcc/test/stack/swapswap.lll create mode 100644 evmcc/test/stack/test.evm diff --git a/evmcc/test/jump/ackermann.ethel b/evmcc/test/jump/ackermann.ethel new file mode 100644 index 000000000..971fd2b8d --- /dev/null +++ b/evmcc/test/jump/ackermann.ethel @@ -0,0 +1,7 @@ +let A m n = + if m == 0 then n+1 + else if n == 0 then A (m-1) 1 + else A (m-1) (A (m) (n-1)) + +return A 3 8 + diff --git a/evmcc/test/jump/ackermann.evm b/evmcc/test/jump/ackermann.evm new file mode 100644 index 000000000..964844045 --- /dev/null +++ b/evmcc/test/jump/ackermann.evm @@ -0,0 +1 @@ +6009600360086012585d60005460206000f26000820e6047596000810e603859603460018303603084600185036012585d6012585d60445860436001830360016012585d604b5860018101905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/fac.ethel b/evmcc/test/jump/fac.ethel new file mode 100644 index 000000000..8bfe94dd6 --- /dev/null +++ b/evmcc/test/jump/fac.ethel @@ -0,0 +1,5 @@ +let fac n = + if n == 0 then 1 + else n * fac (n-1) + +return fac 60 \ No newline at end of file diff --git a/evmcc/test/jump/fac.evm b/evmcc/test/jump/fac.evm new file mode 100644 index 000000000..04cd3e4f4 --- /dev/null +++ b/evmcc/test/jump/fac.evm @@ -0,0 +1 @@ +6007603c6010585d60005460206000f26000810e6026596020600182036010585d8102602858600190509058 \ No newline at end of file diff --git a/evmcc/test/jump/fac_tail.ethel b/evmcc/test/jump/fac_tail.ethel new file mode 100644 index 000000000..9ce5ecac7 --- /dev/null +++ b/evmcc/test/jump/fac_tail.ethel @@ -0,0 +1,5 @@ +let fac a n = + if n == 0 then a + else fac (a*n) (n-1) + +return fac 1 60 \ No newline at end of file diff --git a/evmcc/test/jump/fac_tail.evm b/evmcc/test/jump/fac_tail.evm new file mode 100644 index 000000000..8384d94e4 --- /dev/null +++ b/evmcc/test/jump/fac_tail.evm @@ -0,0 +1 @@ +60096001603c6012585d60005460206000f26000810e6029596025818302600183036012585d602a5881905090509058 \ No newline at end of file diff --git a/evmcc/test/stack/oos.evm b/evmcc/test/stack/oos.evm new file mode 100644 index 000000000..ea2f1c890 --- /dev/null +++ b/evmcc/test/stack/oos.evm @@ -0,0 +1 @@ +60018194505050509150 diff --git a/evmcc/test/stack/oos.lll b/evmcc/test/stack/oos.lll new file mode 100644 index 000000000..5394b06ba --- /dev/null +++ b/evmcc/test/stack/oos.lll @@ -0,0 +1,11 @@ +(asm ;; x . v y z +1 ;; 1 x . v y z +DUP2 ;; x 1 x . v y z +SWAP5 ;; y 1 x . v x z +POP ;; 1 x . v x z +POP ;; x . v x z +POP ;; . v x z +POP ;; v x z +SWAP2 ;; z x v +POP ;; x v +) diff --git a/evmcc/test/stack/swap.evm b/evmcc/test/stack/swap.evm new file mode 100644 index 000000000..27914aa55 --- /dev/null +++ b/evmcc/test/stack/swap.evm @@ -0,0 +1 @@ +600160026001600a590090600160115900016000546001601ff2 diff --git a/evmcc/test/stack/swap.lll b/evmcc/test/stack/swap.lll new file mode 100644 index 000000000..e9ac214bd --- /dev/null +++ b/evmcc/test/stack/swap.lll @@ -0,0 +1,25 @@ +(asm +1 ;; 0 +2 ;; 2 +1 ;; 4 +10 ;; 6 +JUMPI ;; 8 +STOP ;; 9 + +;; stack = 2,1 +SWAP1 ;; 10 +1 ;; 11 +17 ;; 13 +JUMPI ;; 15 +STOP ;; 16 + +;; stack = 1,2 +ADD ;; 17 +0 +MSTORE +1 +31 +RETURN ;; returns 03 +) + + diff --git a/evmcc/test/stack/swapswap.evm b/evmcc/test/stack/swapswap.evm new file mode 100644 index 000000000..f0081f238 --- /dev/null +++ b/evmcc/test/stack/swapswap.evm @@ -0,0 +1 @@ +600160026001600a59009090600160125900016000546001601ff2 diff --git a/evmcc/test/stack/swapswap.lll b/evmcc/test/stack/swapswap.lll new file mode 100644 index 000000000..67fe75941 --- /dev/null +++ b/evmcc/test/stack/swapswap.lll @@ -0,0 +1,26 @@ +(asm +1 ;; 0 +2 ;; 2 +1 ;; 4 +10 ;; 6 +JUMPI ;; 8 +STOP ;; 9 + +;; stack = 2,1 +SWAP1 ;; 10 +SWAP1 ;; 11 +1 ;; 12 +18 ;; 14 +JUMPI ;; 16 +STOP ;; 17 + +;; stack = 2,1 +ADD ;; 18 +0 +MSTORE +1 +31 +RETURN ;; returns 03 +) + + diff --git a/evmcc/test/stack/test.evm b/evmcc/test/stack/test.evm new file mode 100644 index 000000000..ea2f1c890 --- /dev/null +++ b/evmcc/test/stack/test.evm @@ -0,0 +1 @@ +60018194505050509150 From 9fa2958d3951d989adfa772819ba0a58bec76782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 24 Oct 2014 11:48:18 +0200 Subject: [PATCH 213/396] Visual Studio build fix --- libevmjit/BasicBlock.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 13d66140f..cc0efc11a 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -1,6 +1,8 @@ #include "BasicBlock.h" +#include + #include #include From 8b4709452948607b8e087f1fee95ce942ee79628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 24 Oct 2014 15:19:32 +0200 Subject: [PATCH 214/396] Introducing RuntimeData struct - a data that will be provided to running program --- libevmjit/Compiler.cpp | 5 ++++- libevmjit/ExecutionEngine.cpp | 2 +- libevmjit/Runtime.cpp | 9 +++++++++ libevmjit/Runtime.h | 12 ++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1b408d6fe..0128c76d5 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -17,6 +17,7 @@ #include "GasMeter.h" #include "Utils.h" #include "Endianness.h" +#include "Runtime.h" namespace dev { @@ -163,7 +164,9 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto module = std::make_unique("main", m_builder.getContext()); // Create main function - m_mainFunc = llvm::Function::Create(llvm::FunctionType::get(Type::MainReturn, false), llvm::Function::ExternalLinkage, "main", module.get()); + llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), RuntimeData::getType()->getPointerTo()}; // 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()); // Create the basic blocks. auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index af5f96ac7..e537d0517 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -108,7 +108,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV if (r == 0) { rt_jmpBuf = &buf; - auto result = exec->runFunction(entryFunc, {}); + auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(runtime.getDataPtr())}); returnCode = static_cast(result.IntVal.getZExtValue()); } else diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 448d25f92..900b109fa 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -12,6 +12,15 @@ namespace eth namespace jit { +llvm::StructType* RuntimeData::getType() +{ + llvm::Type* elems[] = + { + Type::i256, + }; + return llvm::StructType::create(elems, "RuntimeData"); +} + static Runtime* g_runtime; extern "C" diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 165f47e06..8cee63fa1 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -21,6 +21,13 @@ namespace eth namespace jit { +struct RuntimeData +{ + static llvm::StructType* getType(); + + i256 gas; +}; + using StackImpl = std::vector; using MemoryImpl = bytes; @@ -33,12 +40,17 @@ public: Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; + RuntimeData* getDataPtr() { return &m_data; } + static StackImpl& getStack(); static MemoryImpl& getMemory(); static ExtVMFace& getExt(); static u256 getGas(); private: + + /// @internal Must be the first element to asure Runtime* === RuntimeData* + RuntimeData m_data; StackImpl m_stack; MemoryImpl m_memory; ExtVMFace& m_ext; From 3fbe03a45670c9ba29178e97a39e9166878cb5f2 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 24 Oct 2014 15:08:33 +0100 Subject: [PATCH 215/396] Propagation of values between basic blocks' local stacks [#80895676] --- evmcc/test/stack/swap.evm | 2 +- evmcc/test/stack/swap.lll | 24 ++-- evmcc/test/stack/swapswap.evm | 2 +- evmcc/test/stack/swapswap.lll | 28 ++-- libevmjit/BasicBlock.cpp | 197 +++++++++++++++++++++++---- libevmjit/BasicBlock.h | 9 +- libevmjit/Compiler.cpp | 246 ++++++++++------------------------ libevmjit/Compiler.h | 4 +- 8 files changed, 288 insertions(+), 224 deletions(-) diff --git a/evmcc/test/stack/swap.evm b/evmcc/test/stack/swap.evm index 27914aa55..d17f0ee09 100644 --- a/evmcc/test/stack/swap.evm +++ b/evmcc/test/stack/swap.evm @@ -1 +1 @@ -600160026001600a590090600160115900016000546001601ff2 +600560026001600c59505000906001601559505000036000546001601ff2 diff --git a/evmcc/test/stack/swap.lll b/evmcc/test/stack/swap.lll index e9ac214bd..90dee585d 100644 --- a/evmcc/test/stack/swap.lll +++ b/evmcc/test/stack/swap.lll @@ -1,20 +1,26 @@ (asm -1 ;; 0 +5 ;; 0 2 ;; 2 1 ;; 4 -10 ;; 6 +12 ;; 6 JUMPI ;; 8 -STOP ;; 9 + +POP ;; 9 +POP ;; 10 +STOP ;; 11 ;; stack = 2,1 -SWAP1 ;; 10 -1 ;; 11 -17 ;; 13 -JUMPI ;; 15 -STOP ;; 16 +SWAP1 ;; 12 +1 ;; 13 +21 ;; 15 +JUMPI ;; 17 + +POP ;; 18 +POP ;; 19 +STOP ;; 20 ;; stack = 1,2 -ADD ;; 17 +SUB ;; 21 0 MSTORE 1 diff --git a/evmcc/test/stack/swapswap.evm b/evmcc/test/stack/swapswap.evm index f0081f238..fb4f1bf75 100644 --- a/evmcc/test/stack/swapswap.evm +++ b/evmcc/test/stack/swapswap.evm @@ -1 +1 @@ -600160026001600a59009090600160125900016000546001601ff2 +600260056001600c5950500090906001601659505000036000546001601ff2 diff --git a/evmcc/test/stack/swapswap.lll b/evmcc/test/stack/swapswap.lll index 67fe75941..1fedf726e 100644 --- a/evmcc/test/stack/swapswap.lll +++ b/evmcc/test/stack/swapswap.lll @@ -1,21 +1,27 @@ (asm -1 ;; 0 -2 ;; 2 +2 ;; 0 +5 ;; 2 1 ;; 4 -10 ;; 6 +12 ;; 6 JUMPI ;; 8 -STOP ;; 9 + +POP ;; 9 +POP ;; 10 +STOP ;; 11 ;; stack = 2,1 -SWAP1 ;; 10 -SWAP1 ;; 11 -1 ;; 12 -18 ;; 14 -JUMPI ;; 16 -STOP ;; 17 +SWAP1 ;; 12 +SWAP1 ;; 13 +1 ;; 14 +22 ;; 16 +JUMPI ;; 18 + +POP ;; 19 +POP ;; 20 +STOP ;; 21 ;; stack = 2,1 -ADD ;; 18 +SUB ;; 22 0 MSTORE 1 diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 13d66140f..3fffb2148 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -3,9 +3,11 @@ #include +#include #include #include #include +#include #include "Type.h" @@ -22,17 +24,18 @@ BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, m_beginInstIdx(_beginInstIdx), m_endInstIdx(_endInstIdx), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)), - m_stack(_builder) + m_stack(_builder, m_llvmBB) {} BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : m_beginInstIdx(0), m_endInstIdx(0), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), - m_stack(_builder) + m_stack(_builder, m_llvmBB) {} -BasicBlock::LocalStack::LocalStack(llvm::IRBuilder<>& _builder) : +BasicBlock::LocalStack::LocalStack(llvm::IRBuilder<>& _builder, llvm::BasicBlock* _llvmBB) : + m_llvmBB(_llvmBB), m_builder(_builder), m_initialStack(), m_currentStack(), @@ -80,7 +83,7 @@ void BasicBlock::LocalStack::swap(size_t _index) void BasicBlock::LocalStack::synchronize(Stack& _evmStack) { - auto blockTerminator = m_builder.GetInsertBlock()->getTerminator(); + auto blockTerminator = m_llvmBB->getTerminator(); assert(blockTerminator != nullptr); m_builder.SetInsertPoint(blockTerminator); @@ -180,44 +183,190 @@ void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word) } + +void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRBuilder<>& _builder) +{ + struct BBInfo + { + BasicBlock& bblock; + std::vector predecessors; + size_t inputItems; + size_t outputItems; + std::vector phisToRewrite; + + BBInfo(BasicBlock& _bblock) : + bblock(_bblock), + predecessors(), + inputItems(0), + outputItems(0) + { + auto& initialStack = bblock.localStack().m_initialStack; + for (auto it = initialStack.begin(); + it != initialStack.end() && *it != nullptr; + ++it, ++inputItems); + + //if (bblock.localStack().m_tosOffset > 0) + // outputItems = bblock.localStack().m_tosOffset; + auto& exitStack = bblock.localStack().m_currentStack; + for (auto it = exitStack.rbegin(); + it != exitStack.rend() && *it != nullptr; + ++it, ++outputItems); + } + }; + + std::map cfg; + + // Create nodes in cfg + for (auto bb : basicBlocks) + cfg.emplace(bb->llvm(), *bb); + + // Create edges in cfg: for each bb info fill the list + // of predecessor infos. + for (auto& pair : cfg) + { + auto bb = pair.first; + auto& info = pair.second; + + for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt) + { + auto predInfoEntry = cfg.find(*predIt); + if (predInfoEntry != cfg.end()) + info.predecessors.push_back(&predInfoEntry->second); + } + } + + // Iteratively compute inputs and outputs of each block, until reaching fixpoint. + bool valuesChanged = true; + while (valuesChanged) + { + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + for (auto& pair: cfg) + std::cerr << pair.second.bblock.llvm()->getName().str() + << ": in " << pair.second.inputItems + << ", out " << pair.second.outputItems + << "\n"; + } + + valuesChanged = false; + for (auto& pair : cfg) + { + auto& info = pair.second; + + if (info.predecessors.empty()) + info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false + + for (auto predInfo : info.predecessors) + { + if (predInfo->outputItems < info.inputItems) + { + info.inputItems = predInfo->outputItems; + valuesChanged = true; + } + else if (predInfo->outputItems > info.inputItems) + { + predInfo->outputItems = info.inputItems; + valuesChanged = true; + } + } + } + } + + // Propagate values between blocks. + for (auto& entry : cfg) + { + auto& info = entry.second; + auto& bblock = info.bblock; + + llvm::BasicBlock::iterator fstNonPhi(bblock.llvm()->getFirstNonPHI()); + auto phiIter = bblock.localStack().m_initialStack.begin(); + for (size_t index = 0; index < info.inputItems; ++index, ++phiIter) + { + assert(llvm::isa(*phiIter)); + auto phi = llvm::cast(*phiIter); + + for (auto predIt : info.predecessors) + { + auto& predExitStack = predIt->bblock.localStack().m_currentStack; + auto value = *(predExitStack.end() - 1 - index); + phi->addIncoming(value, predIt->bblock.llvm()); + } + + // Move phi to the front + if (llvm::BasicBlock::iterator(phi) != bblock.llvm()->begin()) + { + phi->removeFromParent(); + _builder.SetInsertPoint(bblock.llvm(), bblock.llvm()->begin()); + _builder.Insert(phi); + } + } + + // The items pulled directly from predecessors block must be removed + // from the list of items that has to be popped from the initial stack. + auto& initialStack = bblock.localStack().m_initialStack; + initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); + // Initial stack shrinks, so the size difference grows: + bblock.localStack().m_tosOffset += info.inputItems; + } + + // We must account for the items that were pushed directly to successor + // blocks and thus should not be on the list of items to be pushed onto + // to EVM stack + for (auto& entry : cfg) + { + auto& info = entry.second; + auto& bblock = info.bblock; + + auto& exitStack = bblock.localStack().m_currentStack; + exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); + bblock.localStack().m_tosOffset -= info.outputItems; + } +} + void BasicBlock::dump() { - std::cerr << "Initial stack:\n"; + dump(std::cerr, false); +} + +void BasicBlock::dump(std::ostream& _out, bool _dotOutput) +{ + llvm::raw_os_ostream out(_out); + + out << (_dotOutput ? "" : "Initial stack:\n"); for (auto val : m_stack.m_initialStack) { if (val == nullptr) - std::cerr << " ?\n"; + out << " ?"; else if (llvm::isa(val)) - val->dump(); + out << *val; else - { - std::cerr << " "; - val->dump(); - } + out << " " << *val; + + out << (_dotOutput ? "\\l" : "\n"); } - std::cerr << " ...\n"; - std::cerr << "Instructions:\n"; + out << (_dotOutput ? "| " : "Instructions:\n"); for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) - ins->dump(); + out << *ins << (_dotOutput ? "\\l" : "\n"); - std::cerr << "Current stack (offset = " - << m_stack.m_tosOffset << "):\n"; + if (! _dotOutput) + out << "Current stack (offset = " << m_stack.m_tosOffset << "):\n"; + else + out << "|"; for (auto val = m_stack.m_currentStack.rbegin(); val != m_stack.m_currentStack.rend(); ++val) { if (*val == nullptr) - std::cerr << " ?\n"; + out << " ?"; else if (llvm::isa(*val)) - (*val)->dump(); + out << **val; else - { - std::cerr << " "; - (*val)->dump(); - } - + out << " " << **val; + out << (_dotOutput ? "\\l" : "\n"); } - std::cerr << " ...\n----------------------------------------\n"; + + if (! _dotOutput) + out << " ...\n----------------------------------------\n"; } diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 2723cf919..65044eb2a 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -40,7 +40,7 @@ public: private: - LocalStack(llvm::IRBuilder<>& _builder); + LocalStack(llvm::IRBuilder<>& _builder, llvm::BasicBlock* _llvmBB); LocalStack(LocalStack const&) = delete; void operator=(LocalStack const&) = delete; friend BasicBlock; @@ -55,6 +55,8 @@ public: private: + llvm::BasicBlock* m_llvmBB; + llvm::IRBuilder<>& m_builder; /** @@ -99,9 +101,14 @@ public: LocalStack& localStack() { return m_stack; } + /// Optimization: propagates values between local stacks in basic blocks + /// to avoid excessive pushing/popping on the EVM stack. + static void linkLocalStacks(std::vector _basicBlocks, llvm::IRBuilder<>& _builder); + /// Prints local stack and block instructions to stderr. /// Useful for calling in a debugger session. void dump(); + void dump(std::ostream& os, bool _dotOutput = false); private: ProgramCounter const m_beginInstIdx; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1b408d6fe..9632f5194 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -1,11 +1,13 @@ #include "Compiler.h" +#include + #include -#include -#include #include +#include +#include #include #include @@ -186,9 +188,6 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) ++iterCopy; auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock); - if (getenv("EVMCC_DEBUG_BLOCKS")) - basicBlock.dump(); - basicBlock.localStack().synchronize(stack); } // Code for special blocks: @@ -204,9 +203,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) { - // auto& stack = m_jumpTableBlock->getStack(); - - auto dest = m_jumpTableBlock->localStack().pop(); //m_jumpTableBlock->localGet(0); // stack.pop(); + auto dest = m_jumpTableBlock->localStack().pop(); auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), m_indirectJumpTargets.size()); for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) @@ -221,8 +218,51 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) m_builder.CreateBr(m_badJumpBlock->llvm()); } - m_jumpTableBlock->localStack().synchronize(stack); - linkBasicBlocks(); + removeDeadBlocks(); + + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + std::ofstream ofs("blocks-init.dot"); + dumpBasicBlockGraph(ofs); + ofs.close(); + std::cerr << "\n\nAfter dead block elimination \n\n"; + dump(); + } + + if (getenv("EVMCC_OPTIMIZE_STACK")) + { + std::vector blockList; + for (auto& entry : basicBlocks) + blockList.push_back(&entry.second); + + if (m_jumpTableBlock != nullptr) + blockList.push_back(m_jumpTableBlock.get()); + + BasicBlock::linkLocalStacks(blockList, m_builder); + + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + std::ofstream ofs("blocks-opt.dot"); + dumpBasicBlockGraph(ofs); + ofs.close(); + std::cerr << "\n\nAfter stack optimization \n\n"; + dump(); + } + } + + for (auto& entry : basicBlocks) + entry.second.localStack().synchronize(stack); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->localStack().synchronize(stack); + + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + std::ofstream ofs("blocks-sync.dot"); + dumpBasicBlockGraph(ofs); + ofs.close(); + std::cerr << "\n\nAfter stack synchronization \n\n"; + dump(); + } return module; } @@ -875,7 +915,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } -void Compiler::linkBasicBlocks() // Stack& stack) + +void Compiler::removeDeadBlocks() { // Remove dead basic blocks auto sthErased = false; @@ -903,187 +944,33 @@ void Compiler::linkBasicBlocks() // Stack& stack) m_jumpTableBlock->llvm()->eraseFromParent(); m_jumpTableBlock.reset(); } - -/* - struct BBInfo - { - BasicBlock& bblock; - std::vector predecessors; - size_t inputItems; - size_t outputItems; - std::vector phisToRewrite; - - BBInfo(BasicBlock& _bblock) - : bblock(_bblock), - predecessors(), - inputItems(_bblock.getStack().initialSize()), - outputItems(_bblock.getStack().size()) - {} - }; - - std::map cfg; - - // Create nodes in cfg - for (auto& pair : this->basicBlocks) - { - auto& bb = pair.second; - cfg.emplace(bb.llvm(), bb); - } - - // Insert jump table block into cfg - if (m_jumpTableBlock) - cfg.emplace(m_jumpTableBlock->llvm(), *m_jumpTableBlock); - - auto& entryBlock = m_mainFunc->getEntryBlock(); - - // Create edges in cfg - for (auto& pair : cfg) - { - auto bbPtr = pair.first; - auto& bbInfo = pair.second; - - for (auto predIt = llvm::pred_begin(bbPtr); predIt != llvm::pred_end(bbPtr); ++predIt) - { - if (*predIt != &entryBlock) - { - auto predInfoEntry = cfg.find(*predIt); - assert(predInfoEntry != cfg.end()); - bbInfo.predecessors.push_back(&predInfoEntry->second); - } - } - } - - // Iteratively compute inputs and outputs of each block, until reaching fixpoint. - bool valuesChanged = true; - while (valuesChanged) - { - valuesChanged = false; - for (auto& pair : cfg) - { - auto& bbInfo = pair.second; - - if (bbInfo.predecessors.empty()) - bbInfo.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false - - for (auto predInfo : bbInfo.predecessors) - { - if (predInfo->outputItems < bbInfo.inputItems) - { - bbInfo.inputItems = predInfo->outputItems; - valuesChanged = true; - } - else if (predInfo->outputItems > bbInfo.inputItems) - { - predInfo->outputItems = bbInfo.inputItems; - valuesChanged = true; - } - } - } - } - - // std::map phiReplacements; - // std::vector phiNodesToRewrite; - - // Propagate values between blocks. - for (auto& pair : cfg) - { - auto llbb = pair.first; - auto& bbInfo = pair.second; - auto& bblock = bbInfo.bblock; - - // Complete phi nodes for the top bbInfo.inputItems placeholder values - auto instrIter = llbb->begin(); - for (size_t valueIdx = 0; valueIdx < bbInfo.inputItems; ++instrIter, ++valueIdx) - { - auto phi = llvm::cast(instrIter); - for (auto predIt : bbInfo.predecessors) - { - assert(valueIdx < predIt->bblock.getStack().size()); - auto value = predIt->bblock.getStack().get(valueIdx); - phi->addIncoming(value, predIt->bblock.llvm()); - } - } - - // Turn the remaining phi nodes into stack.pop's. - // m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI())); - for (; llvm::isa(*instrIter); ++instrIter) - { - auto phi = llvm::cast(instrIter); - // auto value = stack.popWord(); - // Don't delete the phi node yet. It may still be stored in a local stack of some block. - // phiReplacements[phi] = value; - bbInfo.phisToRewrite.push_back(phi); - } - - // Emit stack push's at the end of the block, just before the terminator; - m_builder.SetInsertPoint(llbb, -- llbb->end()); - auto localStackSize = bblock.getStack().size(); - assert(localStackSize >= bbInfo.outputItems); - for (size_t i = 0; i < localStackSize - bbInfo.outputItems; ++i) - stack.pushWord(bblock.getStack().get(localStackSize - 1 - i)); - } - - for (auto& entry : cfg) - { - // Where was the last stack.pop() inserted - auto lastPopIt = entry.first->begin(); - - for (auto phi : entry.second.phisToRewrite) - { - // Insert stack.pop() before the first use of phi, - // then replace all uses of phi with the popped val. - - if (phi->use_begin() == phi->use_end()) - { - // For a phi with no uses, insert pop just after the previous one - } - std::cout << "*** PHI node " << phi->getName().str() << " has no uses!\n"; - } - else - { - assert(llvm::isa(phi->use_begin()->getUser())); - - m_builder.SetInsertPoint(*phi->use_begin()); - auto popVal = stack.popWord(); - phi->replaceAllUsesWith(popVal); - phi->eraseFromParent(); - } - } - */ } void Compiler::dumpBasicBlockGraph(std::ostream& out) { out << "digraph BB {\n" - << " node [shape=record];\n" + << " node [shape=record, fontname=Courier, fontsize=10];\n" << " entry [share=record, label=\"entry block\"];\n"; -/* + std::vector blocks; - for (auto& pair : this->basicBlocks) + for (auto& pair : basicBlocks) blocks.push_back(&pair.second); if (m_jumpTableBlock) blocks.push_back(m_jumpTableBlock.get()); if (m_badJumpBlock) blocks.push_back(m_badJumpBlock.get()); - std::map phiNodesPerBlock; + // std::map phiNodesPerBlock; // Output nodes for (auto bb : blocks) { std::string blockName = bb->llvm()->getName(); - int numOfPhiNodes = 0; - auto firstNonPhiPtr = bb->llvm()->getFirstNonPHI(); - for (auto instrIter = bb->llvm()->begin(); &*instrIter != firstNonPhiPtr; ++instrIter, ++numOfPhiNodes); - phiNodesPerBlock[bb] = numOfPhiNodes; - - auto initStackSize = bb->getStack().initialSize(); - auto endStackSize = bb->getStack().size(); + std::ostringstream oss; + bb->dump(oss, true); - out << " \"" << blockName << "\" [shape=record, label=\"" - << initStackSize << "|" << blockName << "|" << endStackSize - << "\"];\n"; + out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; } // Output edges @@ -1096,14 +983,21 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) { out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") - << "label = \"" - << phiNodesPerBlock[bb] - << "\"];\n"; + //<< "label = \"" + //<< phiNodesPerBlock[bb] + << "];\n"; } } out << "}\n"; - */ +} + +void Compiler::dump() +{ + for (auto& entry : basicBlocks) + entry.second.dump(); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->dump(); } } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 9d7b37fbc..afd5aef72 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -33,8 +33,10 @@ private: void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); - void linkBasicBlocks(); //class Stack& stack); + void removeDeadBlocks(); + /// Dump all basic blocks to stderr. Useful in a debugging session. + void dump(); llvm::IRBuilder<> m_builder; From c87717aa781f9fd05258dea49876afd8e14229d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 24 Oct 2014 16:20:29 +0200 Subject: [PATCH 216/396] Export runtime data to global variable in main function --- libevmjit/Compiler.cpp | 1 + libevmjit/CompilerHelper.cpp | 8 ++++++++ libevmjit/CompilerHelper.h | 3 +++ libevmjit/Runtime.cpp | 28 ++++++++++++++++++++++++---- libevmjit/Runtime.h | 12 ++++++++++++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 0128c76d5..14952163f 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -175,6 +175,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) createBasicBlocks(bytecode); // Init runtime structures. + RuntimeManager runtimeManager(m_builder); GasMeter gasMeter(m_builder); Memory memory(m_builder, gasMeter); Ext ext(m_builder); diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index 3bdf38641..b919043f2 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -21,6 +21,14 @@ llvm::Module* CompilerHelper::getModule() return m_builder.GetInsertBlock()->getParent()->getParent(); } +llvm::Function* CompilerHelper::getMainFunction() +{ + assert(m_builder.GetInsertBlock()); + auto mainFunc = m_builder.GetInsertBlock()->getParent(); + assert(mainFunc && mainFunc->getName() == "main"); + return mainFunc; +} + } } } diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index e284398a3..23bbcbd11 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -23,6 +23,9 @@ protected: /// Reference to the IR module being compiled llvm::Module* getModule(); + /// Reference to the main module function + llvm::Function* getMainFunction(); + /// Reference to parent compiler IR builder llvm::IRBuilder<>& m_builder; }; diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 900b109fa..4d800535c 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -1,6 +1,9 @@ #include "Runtime.h" +#include +#include + #include #include "Type.h" @@ -14,11 +17,16 @@ namespace jit llvm::StructType* RuntimeData::getType() { - llvm::Type* elems[] = + static llvm::StructType* type = nullptr; + if (!type) { - Type::i256, - }; - return llvm::StructType::create(elems, "RuntimeData"); + llvm::Type* elems[] = + { + Type::i256, + }; + type = llvm::StructType::create(elems, "RuntimeData"); + } + return type; } static Runtime* g_runtime; @@ -61,6 +69,18 @@ u256 Runtime::getGas() return llvm2eth(gas); } + +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) +{ + auto dataPtrType = RuntimeData::getType()->getPointerTo(); + m_dataPtr = new llvm::GlobalVariable(*getModule(), dataPtrType, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(dataPtrType), "rt"); + + // Export data + auto mainFunc = getMainFunction(); + llvm::Value* dataPtr = &mainFunc->getArgumentList().back(); + m_builder.CreateStore(dataPtr, m_dataPtr); +} + } } } diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 8cee63fa1..d9984966e 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -5,6 +5,7 @@ #include +#include "CompilerHelper.h" #include "Utils.h" @@ -56,6 +57,17 @@ private: ExtVMFace& m_ext; }; +class RuntimeManager: public CompilerHelper +{ +public: + RuntimeManager(llvm::IRBuilder<>& _builder); + + llvm::Value* getGas(); + +private: + llvm::GlobalVariable* m_dataPtr; +}; + } } } From fcf5400c3ab76f427dd04f1a2807bdd8d3efd1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 10:35:44 +0100 Subject: [PATCH 217/396] Place current gas counter value in RuntimeData --- libevmjit/Compiler.cpp | 8 ++++---- libevmjit/Compiler.h | 2 +- libevmjit/ExecutionEngine.cpp | 2 +- libevmjit/GasMeter.cpp | 21 +++++++-------------- libevmjit/GasMeter.h | 8 ++++---- libevmjit/Runtime.cpp | 25 ++++++++++++++++++------- libevmjit/Runtime.h | 3 ++- 7 files changed, 37 insertions(+), 32 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 339f73959..ddfe2497e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -178,7 +178,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) // Init runtime structures. RuntimeManager runtimeManager(m_builder); - GasMeter gasMeter(m_builder); + GasMeter gasMeter(m_builder, runtimeManager); Memory memory(m_builder, gasMeter); Ext ext(m_builder); Stack stack(m_builder); @@ -191,7 +191,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, bytecode, runtimeManager, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: @@ -272,7 +272,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) } -void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) +void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) { m_builder.SetInsertPoint(basicBlock.llvm()); auto& stack = basicBlock.localStack(); @@ -680,7 +680,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::GAS: { - stack.push(gasMeter.getGas()); + stack.push(_runtimeManager.getGas()); break; } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index afd5aef72..d543b9b1d 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -31,7 +31,7 @@ private: void createBasicBlocks(bytesConstRef bytecode); - void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); + void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class RuntimeManager& _runtimeManager, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); void removeDeadBlocks(); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index e537d0517..5d5af553e 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -115,7 +115,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV returnCode = static_cast(r); // Return remaining gas - _gas = returnCode == ReturnCode::OutOfGas ? 0 : Runtime::getGas(); + _gas = returnCode == ReturnCode::OutOfGas ? 0 : runtime.getGas(); std::cout << "Max stack size: " << Stack::maxStackSize << std::endl; diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 6eb8eb6eb..317b204fc 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -10,6 +10,7 @@ #include "Type.h" #include "Ext.h" +#include "Runtime.h" namespace dev { @@ -79,12 +80,11 @@ bool isCostBlockEnd(Instruction _inst) } -GasMeter::GasMeter(llvm::IRBuilder<>& _builder) : - CompilerHelper(_builder) +GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) : + CompilerHelper(_builder), + m_runtimeManager(_runtimeManager) { auto module = getModule(); - m_gas = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); - m_gas->setUnnamedAddr(true); // Address is not important m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", module); InsertPointGuard guard(m_builder); @@ -96,7 +96,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder) : m_builder.SetInsertPoint(checkBB); llvm::Value* cost = m_gasCheckFunc->arg_begin(); cost->setName("cost"); - llvm::Value* gas = m_builder.CreateLoad(m_gas, "gas"); + auto gas = m_runtimeManager.getGas(); auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); @@ -111,7 +111,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder) : m_builder.SetInsertPoint(updateBB); gas = m_builder.CreateSub(gas, cost); - m_builder.CreateStore(gas, m_gas); + m_runtimeManager.setGas(gas); m_builder.CreateRetVoid(); } @@ -153,9 +153,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu void GasMeter::giveBack(llvm::Value* _gas) { - llvm::Value* gasCounter = m_builder.CreateLoad(m_gas, "gas"); - gasCounter = m_builder.CreateAdd(gasCounter, _gas); - m_builder.CreateStore(gasCounter, m_gas); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); } void GasMeter::commitCostBlock(llvm::Value* _additionalCost) @@ -191,11 +189,6 @@ void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilde _builder.CreateCall(m_gasCheckFunc, cost); } -llvm::Value* GasMeter::getGas() -{ - return m_builder.CreateLoad(m_gas, "gas"); -} - } } } diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 521e7080a..82007fc00 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -11,11 +11,12 @@ namespace eth { namespace jit { +class RuntimeManager; class GasMeter : public CompilerHelper { public: - GasMeter(llvm::IRBuilder<>& _builder); + GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager); /// Count step cost of instruction void count(Instruction _inst); @@ -33,16 +34,15 @@ public: /// Generate code that checks the cost of additional memory used by program void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); - llvm::Value* getGas(); - private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow uint64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; - llvm::GlobalVariable* m_gas; llvm::Function* m_gasCheckFunc; + + RuntimeManager& m_runtimeManager; }; } diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 4d800535c..e37729e5b 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -31,17 +31,12 @@ llvm::StructType* RuntimeData::getType() static Runtime* g_runtime; -extern "C" -{ -EXPORT i256 gas; -} - Runtime::Runtime(u256 _gas, ExtVMFace& _ext): m_ext(_ext) { assert(!g_runtime); g_runtime = this; - gas = eth2llvm(_gas); + m_data.gas = eth2llvm(_gas); } Runtime::~Runtime() @@ -66,7 +61,7 @@ ExtVMFace& Runtime::getExt() u256 Runtime::getGas() { - return llvm2eth(gas); + return llvm2eth(m_data.gas); } @@ -81,6 +76,22 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui m_builder.CreateStore(dataPtr, m_dataPtr); } +llvm::Value* RuntimeManager::getGas() +{ + //auto gasPtr = m_builder.CreateConstGEP2_64(m_dataPtr, 0, 0); + auto rt = m_builder.CreateLoad(m_dataPtr); + auto gasPtr = m_builder.CreateStructGEP(rt, 0); + return m_builder.CreateLoad(gasPtr, "gas"); +} + +void RuntimeManager::setGas(llvm::Value* _gas) +{ + //auto gasPtr = m_builder.CreateStructGEP(m_dataPtr, 0); + auto rt = m_builder.CreateLoad(m_dataPtr); + auto gasPtr = m_builder.CreateStructGEP(rt, 0); + m_builder.CreateStore(_gas, gasPtr); +} + } } } diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index d9984966e..418555c04 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -46,7 +46,7 @@ public: static StackImpl& getStack(); static MemoryImpl& getMemory(); static ExtVMFace& getExt(); - static u256 getGas(); + u256 getGas(); private: @@ -63,6 +63,7 @@ public: RuntimeManager(llvm::IRBuilder<>& _builder); llvm::Value* getGas(); + void setGas(llvm::Value* _gas); private: llvm::GlobalVariable* m_dataPtr; From 9ec1ea526ac13e24853fedb2b969e473ddaa06f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 11:45:07 +0100 Subject: [PATCH 218/396] Access memory structure through runtime structure [#81470252] --- libevmjit/Compiler.cpp | 2 +- libevmjit/ExecutionEngine.cpp | 2 +- libevmjit/Ext.cpp | 9 ++--- libevmjit/Memory.cpp | 68 +++++++++++++++-------------------- libevmjit/Memory.h | 7 ++-- libevmjit/Runtime.cpp | 34 +++++++++++------- libevmjit/Runtime.h | 5 ++- 7 files changed, 66 insertions(+), 61 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index ddfe2497e..c3c09384b 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -179,7 +179,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) // Init runtime structures. RuntimeManager runtimeManager(m_builder); GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(m_builder, gasMeter); + Memory memory(m_builder, gasMeter, runtimeManager); Ext ext(m_builder); Stack stack(m_builder); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 5d5af553e..f7f30614c 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -121,7 +121,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV if (returnCode == ReturnCode::Return) { - returnData = Memory::getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface + returnData = runtime.getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface std::cout << "RETURN [ "; for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 045d25b62..07023c674 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -306,7 +306,8 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* u256 gas; // TODO: Handle gas auto initOff = static_cast(llvm2eth(*_initOff)); auto initSize = static_cast(llvm2eth(*_initSize)); - auto&& initRef = bytesConstRef(Runtime::getMemory().data() + initOff, initSize); + //auto&& initRef = bytesConstRef(Runtime::getMemory().data() + initOff, initSize); + bytesConstRef initRef; OnOpFunc onOp{}; // TODO: Handle that thing h256 address = ext.create(endowment, &gas, initRef, onOp); *_address = address; @@ -332,8 +333,8 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO auto inSize = static_cast(llvm2eth(*_inSize)); auto outOff = static_cast(llvm2eth(*_outOff)); auto outSize = static_cast(llvm2eth(*_outSize)); - auto&& inRef = bytesConstRef(Runtime::getMemory().data() + inOff, inSize); - auto&& outRef = bytesConstRef(Runtime::getMemory().data() + outOff, outSize); + auto&& inRef = bytesConstRef(); //Runtime::getMemory().data() + inOff, inSize); + auto&& outRef = bytesConstRef(); // Runtime::getMemory().data() + outOff, outSize); OnOpFunc onOp{}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); @@ -347,7 +348,7 @@ EXPORT void ext_sha3(i256* _inOff, i256* _inSize, i256* _ret) { auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); - auto dataRef = bytesConstRef(Runtime::getMemory().data() + inOff, inSize); + auto dataRef = bytesConstRef(); // Runtime::getMemory().data() + inOff, inSize); auto hash = sha3(dataRef); *_ret = *reinterpret_cast(&hash); } diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 23d027ba4..8d7674885 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -15,6 +15,7 @@ #include "Runtime.h" #include "GasMeter.h" #include "Endianness.h" +#include "Runtime.h" namespace dev { @@ -23,7 +24,7 @@ namespace eth namespace jit { -Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter): +Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter, RuntimeManager& _runtimeManager): CompilerHelper(_builder) { auto module = getModule(); @@ -45,18 +46,19 @@ Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter): m_returnDataSize = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); m_returnDataSize->setUnnamedAddr(true); // Address is not important - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", module); + llvm::Type* resizeArgs[] = {RuntimeData::getType()->getPointerTo(), Type::WordPtr}; + m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module); llvm::AttrBuilder attrBuilder; attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - m_require = createRequireFunc(_gasMeter); + m_require = createRequireFunc(_gasMeter, _runtimeManager); m_loadWord = createFunc(false, Type::i256, _gasMeter); m_storeWord = createFunc(true, Type::i256, _gasMeter); m_storeByte = createFunc(true, Type::Byte, _gasMeter); } -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager) { auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); @@ -83,7 +85,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) _gasMeter.checkMemory(newWords, m_builder); // Resize m_builder.CreateStore(sizeRequired, m_size); - auto newData = m_builder.CreateCall(m_resize, m_size, "newData"); + auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData"); m_builder.CreateStore(newData, m_data); m_builder.CreateBr(returnBB); @@ -232,48 +234,36 @@ extern "C" using namespace dev::eth::jit; -EXPORT i256 mem_returnDataOffset; -EXPORT i256 mem_returnDataSize; - -EXPORT uint8_t* mem_resize(i256* _size) +EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size) { auto size = _size->a; // Trunc to 64-bit - auto& memory = Runtime::getMemory(); + 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 - << 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(b) << ' '; - } - std::cerr << std::endl; + //if (_end == 0) + // _end = Runtime::getMemory().size(); + + //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(b) << ' '; + //} + //std::cerr << std::endl; } } // extern "C" - -dev::bytesConstRef dev::eth::jit::Memory::getReturnData() -{ - // TODO: Handle large indexes - auto offset = static_cast(llvm2eth(mem_returnDataOffset)); - auto size = static_cast(llvm2eth(mem_returnDataSize)); - auto& memory = Runtime::getMemory(); - return {memory.data() + offset, size}; -} diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index 2ab09c127..d92538247 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -10,11 +10,12 @@ namespace eth { namespace jit { +class RuntimeManager; class Memory : public CompilerHelper { public: - Memory(llvm::IRBuilder<>& _builder, class GasMeter& _gasMeter); + Memory(llvm::IRBuilder<>& _builder, class GasMeter& _gasMeter, RuntimeManager& _runtimeManager); llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); @@ -31,13 +32,13 @@ public: void require(llvm::Value* _offset, llvm::Value* _size); void registerReturnData(llvm::Value* _index, llvm::Value* _size); - static bytesConstRef getReturnData(); + bytesConstRef getReturnData(); void dump(uint64_t _begin, uint64_t _end = 0); private: llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter); + llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager); private: llvm::GlobalVariable* m_data; diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index e37729e5b..37e414b17 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -29,7 +29,7 @@ llvm::StructType* RuntimeData::getType() return type; } -static Runtime* g_runtime; +static Runtime* g_runtime; // FIXME: Remove Runtime::Runtime(u256 _gas, ExtVMFace& _ext): m_ext(_ext) @@ -49,11 +49,6 @@ StackImpl& Runtime::getStack() return g_runtime->m_stack; } -MemoryImpl& Runtime::getMemory() -{ - return g_runtime->m_memory; -} - ExtVMFace& Runtime::getExt() { return g_runtime->m_ext; @@ -64,6 +59,19 @@ u256 Runtime::getGas() return llvm2eth(m_data.gas); } +extern "C" { + EXPORT i256 mem_returnDataOffset; // FIXME: Dis-globalize + EXPORT i256 mem_returnDataSize; +} + +bytesConstRef Runtime::getReturnData() +{ + // TODO: Handle large indexes + auto offset = static_cast(llvm2eth(mem_returnDataOffset)); + auto size = static_cast(llvm2eth(mem_returnDataSize)); + return{getMemory().data() + offset, size}; +} + RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) { @@ -76,19 +84,21 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui m_builder.CreateStore(dataPtr, m_dataPtr); } +llvm::Value* RuntimeManager::getRuntimePtr() +{ + // TODO: If in main function - get it from param + return m_builder.CreateLoad(m_dataPtr); +} + llvm::Value* RuntimeManager::getGas() { - //auto gasPtr = m_builder.CreateConstGEP2_64(m_dataPtr, 0, 0); - auto rt = m_builder.CreateLoad(m_dataPtr); - auto gasPtr = m_builder.CreateStructGEP(rt, 0); + auto gasPtr = m_builder.CreateStructGEP(getRuntimePtr(), 0); return m_builder.CreateLoad(gasPtr, "gas"); } void RuntimeManager::setGas(llvm::Value* _gas) { - //auto gasPtr = m_builder.CreateStructGEP(m_dataPtr, 0); - auto rt = m_builder.CreateLoad(m_dataPtr); - auto gasPtr = m_builder.CreateStructGEP(rt, 0); + auto gasPtr = m_builder.CreateStructGEP(getRuntimePtr(), 0); m_builder.CreateStore(_gas, gasPtr); } diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 418555c04..87f43f786 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -44,9 +44,10 @@ public: RuntimeData* getDataPtr() { return &m_data; } static StackImpl& getStack(); - static MemoryImpl& getMemory(); + MemoryImpl& getMemory() { return m_memory; } static ExtVMFace& getExt(); u256 getGas(); + bytesConstRef getReturnData(); private: @@ -62,6 +63,8 @@ class RuntimeManager: public CompilerHelper public: RuntimeManager(llvm::IRBuilder<>& _builder); + llvm::Value* getRuntimePtr(); + llvm::Value* getGas(); void setGas(llvm::Value* _gas); From f81971bae852f5aea0b3dfda60a9357b96a9622d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 12:16:33 +0100 Subject: [PATCH 219/396] Add Type::RuntimePtr predefined LLVM type --- libevmjit/Type.cpp | 4 ++++ libevmjit/Type.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index baf458dbd..5021473ff 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -3,6 +3,8 @@ #include +#include "Runtime.h" + namespace dev { namespace eth @@ -18,6 +20,7 @@ llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; llvm::IntegerType* Type::MainReturn; +llvm::PointerType* Type::RuntimePtr; void Type::init(llvm::LLVMContext& _context) { @@ -30,6 +33,7 @@ void Type::init(llvm::LLVMContext& _context) BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); MainReturn = llvm::Type::getInt32Ty(_context); + RuntimePtr = RuntimeData::getType()->getPointerTo(); } llvm::ConstantInt* Constant::get(uint64_t _n) diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 16a13c373..86915cd9e 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -30,6 +30,8 @@ struct Type /// Main function return type static llvm::IntegerType* MainReturn; + static llvm::PointerType* RuntimePtr; + static void init(llvm::LLVMContext& _context); }; From 0d4ca779ff7f4ad455d08fc0820d4a2552cf0dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 12:17:04 +0100 Subject: [PATCH 220/396] Access stack structure through runtime structure [#81470252] --- libevmjit/Compiler.cpp | 2 +- libevmjit/Runtime.cpp | 4 ---- libevmjit/Runtime.h | 2 +- libevmjit/Stack.cpp | 44 ++++++++++++++++++++++++------------------ libevmjit/Stack.h | 4 +++- 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index c3c09384b..b20d5ae9c 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -181,7 +181,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) GasMeter gasMeter(m_builder, runtimeManager); Memory memory(m_builder, gasMeter, runtimeManager); Ext ext(m_builder); - Stack stack(m_builder); + Stack stack(m_builder, runtimeManager); m_builder.CreateBr(basicBlocks.begin()->second); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 37e414b17..a41d5e296 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -44,10 +44,6 @@ Runtime::~Runtime() g_runtime = nullptr; } -StackImpl& Runtime::getStack() -{ - return g_runtime->m_stack; -} ExtVMFace& Runtime::getExt() { diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 87f43f786..dc617b777 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -43,7 +43,7 @@ public: RuntimeData* getDataPtr() { return &m_data; } - static StackImpl& getStack(); + StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } static ExtVMFace& getExt(); u256 getGas(); diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 89044bea8..6c287dc6a 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -14,8 +14,9 @@ namespace eth namespace jit { -Stack::Stack(llvm::IRBuilder<>& _builder) - : CompilerHelper(_builder) +Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) + : CompilerHelper(_builder), + m_runtimeManager(_runtimeManager) { m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg"); @@ -23,11 +24,16 @@ Stack::Stack(llvm::IRBuilder<>& _builder) using Linkage = GlobalValue::LinkageTypes; auto module = getModule(); - m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::WordPtr, false), Linkage::ExternalLinkage, "stack_push", module); - m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::Size, false), Linkage::ExternalLinkage, "stack_pop", module); - llvm::Type* getSetArgTypes[] = {Type::Size, Type::WordPtr}; - m_get = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_get", module); - m_set = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_set", module); + + llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; + m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); + + llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; + m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); + + llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; + m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); + m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); } Stack::~Stack() @@ -35,25 +41,25 @@ Stack::~Stack() llvm::Value* Stack::get(size_t _index) { - m_builder.CreateCall2(m_get, 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); return m_builder.CreateLoad(m_arg); } void Stack::set(size_t _index, llvm::Value* _value) { m_builder.CreateStore(_value, m_arg); - m_builder.CreateCall2(m_set, llvm::ConstantInt::get(Type::Size, _index, false), m_arg); + m_builder.CreateCall3(m_set, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); } void Stack::pop(size_t _count) { - m_builder.CreateCall(m_pop, llvm::ConstantInt::get(Type::Size, _count, false)); + m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); } void Stack::push(llvm::Value* _value) { m_builder.CreateStore(_value, m_arg); - m_builder.CreateCall(m_push, m_arg); + m_builder.CreateCall2(m_push, m_runtimeManager.getRuntimePtr(), m_arg); } @@ -70,27 +76,27 @@ using namespace dev::eth::jit; extern std::jmp_buf* rt_jmpBuf; -EXPORT void stack_pop(uint64_t _count) +EXPORT void stack_pop(Runtime* _rt, uint64_t _count) { - auto& stack = Runtime::getStack(); + auto& stack = _rt->getStack(); if (stack.size() < _count) longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); stack.erase(stack.end() - _count, stack.end()); } -EXPORT void stack_push(i256* _word) +EXPORT void stack_push(Runtime* _rt, i256* _word) { - auto& stack = Runtime::getStack(); + auto& stack = _rt->getStack(); stack.push_back(*_word); if (stack.size() > Stack::maxStackSize) Stack::maxStackSize = stack.size(); } -EXPORT void stack_get(uint64_t _index, i256* _ret) +EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* _ret) { - auto& stack = Runtime::getStack(); + auto& stack = _rt->getStack(); // TODO: encode _index and stack size in the return code if (stack.size() <= _index) longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); @@ -98,9 +104,9 @@ EXPORT void stack_get(uint64_t _index, i256* _ret) *_ret = *(stack.rbegin() + _index); } -EXPORT void stack_set(uint64_t _index, i256* _word) +EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256* _word) { - auto& stack = Runtime::getStack(); + auto& stack = _rt->getStack(); // TODO: encode _index and stack size in the return code if (stack.size() <= _index) longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index 2380b2a15..db9032ec4 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -10,12 +10,13 @@ namespace eth { namespace jit { +class RuntimeManager; class Stack : public CompilerHelper { public: - Stack(llvm::IRBuilder<>& builder); + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); virtual ~Stack(); llvm::Value* get(size_t _index); @@ -26,6 +27,7 @@ public: static size_t maxStackSize; private: + RuntimeManager& m_runtimeManager; llvm::Function* m_push; llvm::Function* m_pop; From 5d3afa175606067fae4c37e441b80a295386a99d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 12:19:02 +0100 Subject: [PATCH 221/396] Use Type::RuntimePtr instead of RuntimeData::getType->getPointerTo() --- libevmjit/Compiler.cpp | 2 +- libevmjit/Memory.cpp | 2 +- libevmjit/Runtime.cpp | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index b20d5ae9c..5061dabb0 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -166,7 +166,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto module = std::make_unique("main", m_builder.getContext()); // Create main function - llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), RuntimeData::getType()->getPointerTo()}; // 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()); diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 8d7674885..fa5a2b0dd 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -46,7 +46,7 @@ Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter, RuntimeManager& m_returnDataSize = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); m_returnDataSize->setUnnamedAddr(true); // Address is not important - llvm::Type* resizeArgs[] = {RuntimeData::getType()->getPointerTo(), Type::WordPtr}; + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module); llvm::AttrBuilder attrBuilder; attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index a41d5e296..e09db52c9 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -71,8 +71,7 @@ bytesConstRef Runtime::getReturnData() RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) { - auto dataPtrType = RuntimeData::getType()->getPointerTo(); - m_dataPtr = new llvm::GlobalVariable(*getModule(), dataPtrType, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(dataPtrType), "rt"); + m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt"); // Export data auto mainFunc = getMainFunction(); From 7ec7977fc457952f9a8ec8b4f50542ca7619f154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 12:42:32 +0100 Subject: [PATCH 222/396] Introducing RuntimeHelper - a compiler helper that depends on runtime data [#81470252] --- libevmjit/CompilerHelper.cpp | 8 ++++++++ libevmjit/CompilerHelper.h | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index b919043f2..c2d612c66 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -3,6 +3,8 @@ #include +#include "Runtime.h" + namespace dev { namespace eth @@ -29,6 +31,12 @@ llvm::Function* CompilerHelper::getMainFunction() return mainFunc; } + +RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): + CompilerHelper(_runtimeManager.getBuilder()), + m_runtimeManager(_runtimeManager) +{} + } } } diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index 23bbcbd11..cf83d70cd 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -10,6 +10,7 @@ namespace eth { namespace jit { +class RuntimeManager; /// Base class for compiler helpers like Memory, GasMeter, etc. class CompilerHelper @@ -28,6 +29,22 @@ protected: /// Reference to parent compiler IR builder llvm::IRBuilder<>& m_builder; + llvm::IRBuilder<>& getBuilder() { return m_builder; } + + friend class RuntimeHelper; +}; + + +/// Compiler helper that depends on runtime data +class RuntimeHelper : public CompilerHelper +{ +protected: + RuntimeHelper(RuntimeManager& _runtimeManager); + + RuntimeManager& getRuntimeManager() { return m_runtimeManager; } + +private: + RuntimeManager& m_runtimeManager; }; From c7ccf546fcc75360d30b710f4c5f2bce66fd5bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 14:18:39 +0100 Subject: [PATCH 223/396] Moving ADDRESS data from Ext to Runtime [#81470252] --- libevmjit/Compiler.cpp | 6 +++--- libevmjit/Ext.cpp | 8 +++----- libevmjit/Ext.h | 5 ++--- libevmjit/Runtime.cpp | 33 +++++++++++++++++++++++---------- libevmjit/Runtime.h | 19 +++++++++++++++---- 5 files changed, 46 insertions(+), 25 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 5061dabb0..26d5c6f19 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -180,7 +180,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) RuntimeManager runtimeManager(m_builder); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(m_builder, gasMeter, runtimeManager); - Ext ext(m_builder); + Ext ext(runtimeManager); Stack stack(m_builder, runtimeManager); m_builder.CreateBr(basicBlocks.begin()->second); @@ -686,7 +686,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ADDRESS: { - auto value = ext.address(); + auto value = _runtimeManager.get(RuntimeData::Address); stack.push(value); break; } @@ -873,7 +873,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto receiveAddress = codeAddress; if (inst == Instruction::CALLCODE) - receiveAddress = ext.address(); + receiveAddress = _runtimeManager.get(RuntimeData::Address); auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); gasMeter.giveBack(gas); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 07023c674..2e38aef27 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -44,10 +44,10 @@ struct ExtData const byte* code; }; -Ext::Ext(llvm::IRBuilder<>& _builder): - CompilerHelper(_builder) +Ext::Ext(RuntimeManager& _runtimeManager): + RuntimeHelper(_runtimeManager) { - auto&& ctx = _builder.getContext(); + auto&& ctx = m_builder.getContext(); auto module = getModule(); auto i256Ty = m_builder.getIntNTy(256); @@ -126,7 +126,6 @@ Value* Ext::getDataElem(unsigned _index, const Twine& _name) return m_builder.CreateLoad(valuePtr); } -Value* Ext::address() { return getDataElem(0, "address"); } Value* Ext::caller() { return getDataElem(1, "caller"); } Value* Ext::origin() { return getDataElem(2, "origin"); } Value* Ext::callvalue() { return getDataElem(3, "callvalue"); } @@ -243,7 +242,6 @@ using namespace dev::eth::jit; EXPORT void ext_init(ExtData* _extData) { auto&& ext = Runtime::getExt(); - _extData->address = eth2llvm(fromAddress(ext.myAddress)); _extData->caller = eth2llvm(fromAddress(ext.caller)); _extData->origin = eth2llvm(fromAddress(ext.origin)); _extData->callvalue = eth2llvm(ext.value); diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 361b6e47e..6d8501d29 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -12,15 +12,14 @@ namespace eth namespace jit { -class Ext : public CompilerHelper +class Ext : public RuntimeHelper { public: - Ext(llvm::IRBuilder<>& _builder); + Ext(RuntimeManager& _runtimeManager); llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); - llvm::Value* address(); llvm::Value* caller(); llvm::Value* origin(); llvm::Value* callvalue(); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index e09db52c9..bf231cc10 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -22,7 +22,7 @@ llvm::StructType* RuntimeData::getType() { llvm::Type* elems[] = { - Type::i256, + llvm::ArrayType::get(Type::i256, _size) }; type = llvm::StructType::create(elems, "RuntimeData"); } @@ -36,7 +36,8 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext): { assert(!g_runtime); g_runtime = this; - m_data.gas = eth2llvm(_gas); + set(RuntimeData::Gas, _gas); + set(RuntimeData::Address, fromAddress(_ext.myAddress)); } Runtime::~Runtime() @@ -44,15 +45,20 @@ Runtime::~Runtime() g_runtime = nullptr; } +void Runtime::set(RuntimeData::Index _index, u256 _value) +{ + m_data.elems[_index] = eth2llvm(_value); +} + ExtVMFace& Runtime::getExt() { return g_runtime->m_ext; } -u256 Runtime::getGas() +u256 Runtime::getGas() const { - return llvm2eth(m_data.gas); + return llvm2eth(m_data.elems[RuntimeData::Gas]); } extern "C" { @@ -60,12 +66,12 @@ extern "C" { EXPORT i256 mem_returnDataSize; } -bytesConstRef Runtime::getReturnData() +bytesConstRef Runtime::getReturnData() const { // TODO: Handle large indexes auto offset = static_cast(llvm2eth(mem_returnDataOffset)); auto size = static_cast(llvm2eth(mem_returnDataSize)); - return{getMemory().data() + offset, size}; + return {m_memory.data() + offset, size}; } @@ -85,16 +91,23 @@ llvm::Value* RuntimeManager::getRuntimePtr() return m_builder.CreateLoad(m_dataPtr); } +llvm::Value* RuntimeManager::get(RuntimeData::Index _index) +{ + llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)}; + auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, "dataElemPtr"); + return m_builder.CreateLoad(ptr); +} + llvm::Value* RuntimeManager::getGas() { - auto gasPtr = m_builder.CreateStructGEP(getRuntimePtr(), 0); - return m_builder.CreateLoad(gasPtr, "gas"); + return get(RuntimeData::Gas); } void RuntimeManager::setGas(llvm::Value* _gas) { - auto gasPtr = m_builder.CreateStructGEP(getRuntimePtr(), 0); - m_builder.CreateStore(_gas, gasPtr); + llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(RuntimeData::Gas)}; + auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, "gasPtr"); + m_builder.CreateStore(_gas, ptr); } } diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index dc617b777..8b2efe8ed 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -24,9 +24,17 @@ namespace jit struct RuntimeData { - static llvm::StructType* getType(); + enum Index: unsigned + { + Gas, + Address, + + _size + }; + + i256 elems[_size]; - i256 gas; + static llvm::StructType* getType(); }; using StackImpl = std::vector; @@ -46,10 +54,12 @@ public: StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } static ExtVMFace& getExt(); - u256 getGas(); - bytesConstRef getReturnData(); + + u256 getGas() const; + bytesConstRef getReturnData() const; private: + void set(RuntimeData::Index _index, u256 _value); /// @internal Must be the first element to asure Runtime* === RuntimeData* RuntimeData m_data; @@ -65,6 +75,7 @@ public: llvm::Value* getRuntimePtr(); + llvm::Value* get(RuntimeData::Index _index); llvm::Value* getGas(); void setGas(llvm::Value* _gas); From 669612cdcf3b6e5e833564a473b60468b65d71a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 14:30:36 +0100 Subject: [PATCH 224/396] Add name to data indices [#81470252] --- libevmjit/Runtime.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index bf231cc10..779ffe8a9 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -29,6 +29,19 @@ llvm::StructType* RuntimeData::getType() return type; } +namespace +{ +llvm::Twine getName(RuntimeData::Index _index) +{ + switch (_index) + { + default: return "data"; + case RuntimeData::Gas: return "gas"; + case RuntimeData::Address: return "address"; + } +} +} + static Runtime* g_runtime; // FIXME: Remove Runtime::Runtime(u256 _gas, ExtVMFace& _ext): @@ -94,8 +107,8 @@ llvm::Value* RuntimeManager::getRuntimePtr() llvm::Value* RuntimeManager::get(RuntimeData::Index _index) { llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)}; - auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, "dataElemPtr"); - return m_builder.CreateLoad(ptr); + auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr"); + return m_builder.CreateLoad(ptr, getName(_index)); } llvm::Value* RuntimeManager::getGas() From ae89279c1af56ee01b7b76eff7691cc73ff4fc50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 14:42:47 +0100 Subject: [PATCH 225/396] Moving ORIGIN, CALLER & CALLVALUE data from Ext to Runtime [#81470252] --- libevmjit/Compiler.cpp | 6 +++--- libevmjit/Ext.cpp | 36 +++++++++++------------------------- libevmjit/Ext.h | 3 --- libevmjit/Runtime.cpp | 12 +++++++++--- libevmjit/Runtime.h | 3 +++ 5 files changed, 26 insertions(+), 34 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 26d5c6f19..ccdc21e39 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -701,21 +701,21 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::CALLER: { - auto value = ext.caller(); + auto value = _runtimeManager.get(RuntimeData::Caller); stack.push(value); break; } case Instruction::ORIGIN: { - auto value = ext.origin(); + auto value = _runtimeManager.get(RuntimeData::Origin); stack.push(value); break; } case Instruction::CALLVALUE: { - auto value = ext.callvalue(); + auto value = _runtimeManager.get(RuntimeData::CallValue); stack.push(value); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 2e38aef27..741bd9993 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -27,10 +27,6 @@ inline u256 fromAddress(Address _a) struct ExtData { - i256 address; - i256 caller; - i256 origin; - i256 callvalue; i256 calldatasize; i256 gasprice; i256 prevhash; @@ -65,10 +61,6 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8"); Type* elements[] = { - i256Ty, // i256 address; - i256Ty, // i256 caller; - i256Ty, // i256 origin; - i256Ty, // i256 callvalue; i256Ty, // i256 calldatasize; i256Ty, // i256 gasprice; i256Ty, // i256 prevhash; @@ -126,20 +118,17 @@ Value* Ext::getDataElem(unsigned _index, const Twine& _name) return m_builder.CreateLoad(valuePtr); } -Value* Ext::caller() { return getDataElem(1, "caller"); } -Value* Ext::origin() { return getDataElem(2, "origin"); } -Value* Ext::callvalue() { return getDataElem(3, "callvalue"); } -Value* Ext::calldatasize() { return getDataElem(4, "calldatasize"); } -Value* Ext::gasprice() { return getDataElem(5, "gasprice"); } -Value* Ext::prevhash() { return getDataElem(6, "prevhash"); } -Value* Ext::coinbase() { return getDataElem(7, "coinbase"); } -Value* Ext::timestamp() { return getDataElem(8, "timestamp"); } -Value* Ext::number() { return getDataElem(9, "number"); } -Value* Ext::difficulty() { return getDataElem(10, "difficulty"); } -Value* Ext::gaslimit() { return getDataElem(11, "gaslimit"); } -Value* Ext::codesize() { return getDataElem(12, "codesize"); } -Value* Ext::calldata() { return getDataElem(13, "calldata"); } -Value* Ext::code() { return getDataElem(14, "code"); } +Value* Ext::calldatasize() { return getDataElem(0, "calldatasize"); } +Value* Ext::gasprice() { return getDataElem(1, "gasprice"); } +Value* Ext::prevhash() { return getDataElem(2, "prevhash"); } +Value* Ext::coinbase() { return getDataElem(3, "coinbase"); } +Value* Ext::timestamp() { return getDataElem(4, "timestamp"); } +Value* Ext::number() { return getDataElem(5, "number"); } +Value* Ext::difficulty() { return getDataElem(6, "difficulty"); } +Value* Ext::gaslimit() { return getDataElem(7, "gaslimit"); } +Value* Ext::codesize() { return getDataElem(8, "codesize"); } +Value* Ext::calldata() { return getDataElem(9, "calldata"); } +Value* Ext::code() { return getDataElem(10, "code"); } Value* Ext::calldataload(Value* _index) { @@ -242,9 +231,6 @@ using namespace dev::eth::jit; EXPORT void ext_init(ExtData* _extData) { auto&& ext = Runtime::getExt(); - _extData->caller = eth2llvm(fromAddress(ext.caller)); - _extData->origin = eth2llvm(fromAddress(ext.origin)); - _extData->callvalue = eth2llvm(ext.value); _extData->gasprice = eth2llvm(ext.gasPrice); _extData->calldatasize = eth2llvm(ext.data.size()); _extData->prevhash = eth2llvm(ext.previousBlock.hash); diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 6d8501d29..5585f9d05 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -20,9 +20,6 @@ public: llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); - llvm::Value* caller(); - llvm::Value* origin(); - llvm::Value* callvalue(); llvm::Value* calldatasize(); llvm::Value* gasprice(); llvm::Value* prevhash(); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 779ffe8a9..374398b69 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -35,9 +35,12 @@ llvm::Twine getName(RuntimeData::Index _index) { switch (_index) { - default: return "data"; - case RuntimeData::Gas: return "gas"; - case RuntimeData::Address: return "address"; + default: return "data"; + case RuntimeData::Gas: return "gas"; + case RuntimeData::Address: return "address"; + case RuntimeData::Caller: return "caller"; + case RuntimeData::Origin: return "origin"; + case RuntimeData::CallValue: return "callvalue"; } } } @@ -51,6 +54,9 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext): g_runtime = this; set(RuntimeData::Gas, _gas); set(RuntimeData::Address, fromAddress(_ext.myAddress)); + set(RuntimeData::Caller, fromAddress(_ext.caller)); + set(RuntimeData::Origin, fromAddress(_ext.origin)); + set(RuntimeData::CallValue, _ext.value); } Runtime::~Runtime() diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 8b2efe8ed..3300b4106 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -28,6 +28,9 @@ struct RuntimeData { Gas, Address, + Caller, + Origin, + CallValue, _size }; From 6facdd0df6ba67c0ee0b48ec2905a06ce644aac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 15:05:21 +0100 Subject: [PATCH 226/396] Moving the rest word-size data from Ext to Runtime [#81470252] --- libevmjit/Compiler.cpp | 24 ++++++++++++------------ libevmjit/Ext.cpp | 40 ++-------------------------------------- libevmjit/Ext.h | 9 --------- libevmjit/Runtime.cpp | 18 ++++++++++++++++++ libevmjit/Runtime.h | 9 +++++++++ 5 files changed, 41 insertions(+), 59 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index ccdc21e39..e711fe706 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -722,14 +722,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::CALLDATASIZE: { - auto value = ext.calldatasize(); + auto value = _runtimeManager.get(RuntimeData::CallDataSize); stack.push(value); break; } case Instruction::CODESIZE: { - auto value = ext.codesize(); + auto value = _runtimeManager.get(RuntimeData::CodeSize); stack.push(value); break; } @@ -749,7 +749,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto reqBytes = stack.pop(); auto srcPtr = ext.calldata(); - auto srcSize = ext.calldatasize(); + auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); break; @@ -762,7 +762,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto reqBytes = stack.pop(); auto srcPtr = ext.code(); // TODO: Code & its size are constants, feature #80814234 - auto srcSize = ext.codesize(); + auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); break; @@ -791,50 +791,50 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } case Instruction::GASPRICE: - { - auto value = ext.gasprice(); + { + auto value = _runtimeManager.get(RuntimeData::GasPrice); stack.push(value); break; } case Instruction::PREVHASH: { - auto value = ext.prevhash(); + auto value = _runtimeManager.get(RuntimeData::PrevHash); stack.push(value); break; } case Instruction::COINBASE: { - auto value = ext.coinbase(); + auto value = _runtimeManager.get(RuntimeData::CoinBase); stack.push(value); break; } case Instruction::TIMESTAMP: { - auto value = ext.timestamp(); + auto value = _runtimeManager.get(RuntimeData::TimeStamp); stack.push(value); break; } case Instruction::NUMBER: { - auto value = ext.number(); + auto value = _runtimeManager.get(RuntimeData::Number); stack.push(value); break; } case Instruction::DIFFICULTY: { - auto value = ext.difficulty(); + auto value = _runtimeManager.get(RuntimeData::Difficulty); stack.push(value); break; } case Instruction::GASLIMIT: { - auto value = ext.gaslimit(); + auto value = _runtimeManager.get(RuntimeData::GasLimit); stack.push(value); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 741bd9993..1adaf741c 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -27,15 +27,6 @@ inline u256 fromAddress(Address _a) struct ExtData { - i256 calldatasize; - i256 gasprice; - i256 prevhash; - i256 coinbase; - i256 timestamp; - i256 number; - i256 difficulty; - i256 gaslimit; - i256 codesize; const byte* calldata; const byte* code; }; @@ -61,15 +52,6 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8"); Type* elements[] = { - i256Ty, // i256 calldatasize; - i256Ty, // i256 gasprice; - i256Ty, // i256 prevhash; - i256Ty, // i256 coinbase; - i256Ty, // i256 timestamp; - i256Ty, // i256 number; - i256Ty, // i256 difficulty; - i256Ty, // i256 gaslimit; - i256Ty, // i256 codesize i8PtrTy, // byte* calldata i8PtrTy, // byte* code @@ -118,17 +100,8 @@ Value* Ext::getDataElem(unsigned _index, const Twine& _name) return m_builder.CreateLoad(valuePtr); } -Value* Ext::calldatasize() { return getDataElem(0, "calldatasize"); } -Value* Ext::gasprice() { return getDataElem(1, "gasprice"); } -Value* Ext::prevhash() { return getDataElem(2, "prevhash"); } -Value* Ext::coinbase() { return getDataElem(3, "coinbase"); } -Value* Ext::timestamp() { return getDataElem(4, "timestamp"); } -Value* Ext::number() { return getDataElem(5, "number"); } -Value* Ext::difficulty() { return getDataElem(6, "difficulty"); } -Value* Ext::gaslimit() { return getDataElem(7, "gaslimit"); } -Value* Ext::codesize() { return getDataElem(8, "codesize"); } -Value* Ext::calldata() { return getDataElem(9, "calldata"); } -Value* Ext::code() { return getDataElem(10, "code"); } +Value* Ext::calldata() { return getDataElem(0, "calldata"); } +Value* Ext::code() { return getDataElem(1, "code"); } Value* Ext::calldataload(Value* _index) { @@ -231,15 +204,6 @@ using namespace dev::eth::jit; EXPORT void ext_init(ExtData* _extData) { auto&& ext = Runtime::getExt(); - _extData->gasprice = eth2llvm(ext.gasPrice); - _extData->calldatasize = eth2llvm(ext.data.size()); - _extData->prevhash = eth2llvm(ext.previousBlock.hash); - _extData->coinbase = eth2llvm(fromAddress(ext.currentBlock.coinbaseAddress)); - _extData->timestamp = eth2llvm(ext.currentBlock.timestamp); - _extData->number = eth2llvm(ext.currentBlock.number); - _extData->difficulty = eth2llvm(ext.currentBlock.difficulty); - _extData->gaslimit = eth2llvm(ext.currentBlock.gasLimit); - _extData->codesize = eth2llvm(ext.code.size()); _extData->calldata = ext.data.data(); _extData->code = ext.code.data(); } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 5585f9d05..62938f3cb 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -20,15 +20,6 @@ public: llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); - llvm::Value* calldatasize(); - llvm::Value* gasprice(); - llvm::Value* prevhash(); - llvm::Value* coinbase(); - llvm::Value* timestamp(); - llvm::Value* number(); - llvm::Value* difficulty(); - llvm::Value* gaslimit(); - llvm::Value* codesize(); llvm::Value* calldata(); llvm::Value* code(); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 374398b69..42d2fe52f 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -41,6 +41,15 @@ llvm::Twine getName(RuntimeData::Index _index) case RuntimeData::Caller: return "caller"; case RuntimeData::Origin: return "origin"; case RuntimeData::CallValue: return "callvalue"; + case RuntimeData::CallDataSize: return "calldatasize"; + case RuntimeData::GasPrice: return "gasprice"; + case RuntimeData::PrevHash: return "prevhash"; + case RuntimeData::CoinBase: return "coinbase"; + case RuntimeData::TimeStamp: return "timestamp"; + case RuntimeData::Number: return "number"; + case RuntimeData::Difficulty: return "difficulty"; + case RuntimeData::GasLimit: return "gaslimit"; + case RuntimeData::CodeSize: return "codesize"; } } } @@ -57,6 +66,15 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext): set(RuntimeData::Caller, fromAddress(_ext.caller)); set(RuntimeData::Origin, fromAddress(_ext.origin)); set(RuntimeData::CallValue, _ext.value); + set(RuntimeData::CallDataSize, _ext.data.size()); + set(RuntimeData::GasPrice, _ext.gasPrice); + set(RuntimeData::PrevHash, _ext.previousBlock.hash); + set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress)); + set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp); + 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 } Runtime::~Runtime() diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 3300b4106..478c212b1 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -31,6 +31,15 @@ struct RuntimeData Caller, Origin, CallValue, + CallDataSize, + GasPrice, + PrevHash, + CoinBase, + TimeStamp, + Number, + Difficulty, + GasLimit, + CodeSize, _size }; From 356f6609d58cdd52fe6ac04fcbb1603c7169016c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 15:21:47 +0100 Subject: [PATCH 227/396] Group instructions that access runtime data [#81470252] --- libevmjit/Compiler.cpp | 103 ++++++----------------------------------- libevmjit/Runtime.cpp | 22 +++++++++ libevmjit/Runtime.h | 1 + 3 files changed, 36 insertions(+), 90 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index e711fe706..7f6aba051 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -679,57 +679,29 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } case Instruction::GAS: - { - stack.push(_runtimeManager.getGas()); - break; - } - case Instruction::ADDRESS: - { - auto value = _runtimeManager.get(RuntimeData::Address); - stack.push(value); - break; - } - - case Instruction::BALANCE: - { - auto address = stack.pop(); - auto value = ext.balance(address); - stack.push(value); - break; - } - case Instruction::CALLER: - { - auto value = _runtimeManager.get(RuntimeData::Caller); - stack.push(value); - break; - } - case Instruction::ORIGIN: - { - auto value = _runtimeManager.get(RuntimeData::Origin); - stack.push(value); - break; - } - case Instruction::CALLVALUE: - { - auto value = _runtimeManager.get(RuntimeData::CallValue); - stack.push(value); - break; - } - case Instruction::CALLDATASIZE: + case Instruction::CODESIZE: + case Instruction::GASPRICE: + case Instruction::PREVHASH: + case Instruction::COINBASE: + case Instruction::TIMESTAMP: + case Instruction::NUMBER: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: { - auto value = _runtimeManager.get(RuntimeData::CallDataSize); - stack.push(value); + // Pushes an element of runtime data on stack + stack.push(_runtimeManager.get(inst)); break; } - case Instruction::CODESIZE: + case Instruction::BALANCE: { - auto value = _runtimeManager.get(RuntimeData::CodeSize); + auto address = stack.pop(); + auto value = ext.balance(address); stack.push(value); break; } @@ -790,55 +762,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, break; } - case Instruction::GASPRICE: - { - auto value = _runtimeManager.get(RuntimeData::GasPrice); - stack.push(value); - break; - } - - case Instruction::PREVHASH: - { - auto value = _runtimeManager.get(RuntimeData::PrevHash); - stack.push(value); - break; - } - - case Instruction::COINBASE: - { - auto value = _runtimeManager.get(RuntimeData::CoinBase); - stack.push(value); - break; - } - - case Instruction::TIMESTAMP: - { - auto value = _runtimeManager.get(RuntimeData::TimeStamp); - stack.push(value); - break; - } - - case Instruction::NUMBER: - { - auto value = _runtimeManager.get(RuntimeData::Number); - stack.push(value); - break; - } - - case Instruction::DIFFICULTY: - { - auto value = _runtimeManager.get(RuntimeData::Difficulty); - stack.push(value); - break; - } - - case Instruction::GASLIMIT: - { - auto value = _runtimeManager.get(RuntimeData::GasLimit); - stack.push(value); - break; - } - case Instruction::CREATE: { auto endowment = stack.pop(); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 42d2fe52f..21fcfaddb 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -135,6 +135,28 @@ llvm::Value* RuntimeManager::get(RuntimeData::Index _index) return m_builder.CreateLoad(ptr, getName(_index)); } +llvm::Value* RuntimeManager::get(Instruction _inst) +{ + switch (_inst) + { + default: assert(false); return nullptr; + case Instruction::GAS: return get(RuntimeData::Gas); + case Instruction::ADDRESS: return get(RuntimeData::Address); + case Instruction::CALLER: return get(RuntimeData::Caller); + case Instruction::ORIGIN: return get(RuntimeData::Origin); + case Instruction::CALLVALUE: return get(RuntimeData::CallValue); + case Instruction::CALLDATASIZE: return get(RuntimeData::CallDataSize); + case Instruction::GASPRICE: return get(RuntimeData::GasPrice); + case Instruction::PREVHASH: return get(RuntimeData::PrevHash); + case Instruction::COINBASE: return get(RuntimeData::CoinBase); + case Instruction::TIMESTAMP: return get(RuntimeData::TimeStamp); + case Instruction::NUMBER: return get(RuntimeData::Number); + case Instruction::DIFFICULTY: return get(RuntimeData::Difficulty); + case Instruction::GASLIMIT: return get(RuntimeData::GasLimit); + case Instruction::CODESIZE: return get(RuntimeData::CodeSize); + } +} + llvm::Value* RuntimeManager::getGas() { return get(RuntimeData::Gas); diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 478c212b1..a4bb89427 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -88,6 +88,7 @@ public: llvm::Value* getRuntimePtr(); llvm::Value* get(RuntimeData::Index _index); + llvm::Value* get(Instruction _inst); llvm::Value* getGas(); void setGas(llvm::Value* _gas); From f12620d6d8d0a3e9d91432267dc23e88f1c052df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 16:00:41 +0100 Subject: [PATCH 228/396] Moving CALLDATA data from Ext to Runtime [#81470252] --- libevmjit/Compiler.cpp | 2 +- libevmjit/Ext.cpp | 4 +--- libevmjit/Ext.h | 1 - libevmjit/Runtime.cpp | 10 +++++++++- libevmjit/Runtime.h | 4 +++- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 7f6aba051..a872a0097 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -720,7 +720,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto srcPtr = ext.calldata(); + auto srcPtr = _runtimeManager.getCallData(); auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 1adaf741c..b75cd3195 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -52,7 +52,6 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8"); Type* elements[] = { - i8PtrTy, // byte* calldata i8PtrTy, // byte* code }; @@ -100,8 +99,7 @@ Value* Ext::getDataElem(unsigned _index, const Twine& _name) return m_builder.CreateLoad(valuePtr); } -Value* Ext::calldata() { return getDataElem(0, "calldata"); } -Value* Ext::code() { return getDataElem(1, "code"); } +Value* Ext::code() { return getDataElem(0, "code"); } Value* Ext::calldataload(Value* _index) { diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 62938f3cb..f798ec549 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -20,7 +20,6 @@ public: llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); - llvm::Value* calldata(); llvm::Value* code(); llvm::Value* balance(llvm::Value* _address); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 21fcfaddb..523d5ea90 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -22,7 +22,8 @@ llvm::StructType* RuntimeData::getType() { llvm::Type* elems[] = { - llvm::ArrayType::get(Type::i256, _size) + llvm::ArrayType::get(Type::i256, _size), + Type::BytePtr }; type = llvm::StructType::create(elems, "RuntimeData"); } @@ -75,6 +76,7 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext): set(RuntimeData::Difficulty, _ext.currentBlock.difficulty); set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); set(RuntimeData::CodeSize, _ext.code.size()); // TODO: Use constant + m_data.callData = _ext.data.data(); } Runtime::~Runtime() @@ -157,6 +159,12 @@ llvm::Value* RuntimeManager::get(Instruction _inst) } } +llvm::Value* RuntimeManager::getCallData() +{ + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 1, "calldataPtr"); + return getBuilder().CreateLoad(ptr, "calldata"); +} + llvm::Value* RuntimeManager::getGas() { return get(RuntimeData::Gas); diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index a4bb89427..d8f1a2624 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -45,6 +45,7 @@ struct RuntimeData }; i256 elems[_size]; + byte const* callData; static llvm::StructType* getType(); }; @@ -89,7 +90,8 @@ public: llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); - llvm::Value* getGas(); + llvm::Value* getGas(); // TODO: Remove + llvm::Value* getCallData(); void setGas(llvm::Value* _gas); private: From 13fb431c54a1790a7f0ceef2f35a0734aa1eec02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 16:13:38 +0100 Subject: [PATCH 229/396] Moving CODE data from Ext to Runtime [#81470252] --- libevmjit/Compiler.cpp | 2 +- libevmjit/Ext.cpp | 19 ------------------- libevmjit/Ext.h | 5 ----- libevmjit/Runtime.cpp | 8 ++++++++ libevmjit/Runtime.h | 2 ++ 5 files changed, 11 insertions(+), 25 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index a872a0097..600551c29 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -733,7 +733,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto srcPtr = ext.code(); // 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); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index b75cd3195..6659425ea 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -51,17 +51,8 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg7"); m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8"); - Type* elements[] = { - i8PtrTy, // byte* code - - }; - auto extDataTy = StructType::create(elements, "ext.Data"); - - m_data = m_builder.CreateAlloca(extDataTy, nullptr, "ext.data"); - using llvm::types::i; using Linkage = llvm::GlobalValue::LinkageTypes; - m_init = Function::Create(FunctionType::get(m_builder.getVoidTy(), extDataTy->getPointerTo(), false), Linkage::ExternalLinkage, "ext_init", module); m_store = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); m_setStore = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); m_calldataload = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_calldataload", module); @@ -75,8 +66,6 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_exp = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_exp", module); m_codeAt = Function::Create(TypeBuilder*(i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codeAt", module); m_codesizeAt = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codesizeAt", module); - - m_builder.CreateCall(m_init, m_data); } llvm::Value* Ext::store(llvm::Value* _index) @@ -93,14 +82,6 @@ void Ext::setStore(llvm::Value* _index, llvm::Value* _value) m_builder.CreateCall(m_setStore, m_args); // Uses native endianness } -Value* Ext::getDataElem(unsigned _index, const Twine& _name) -{ - auto valuePtr = m_builder.CreateStructGEP(m_data, _index, _name); - return m_builder.CreateLoad(valuePtr); -} - -Value* Ext::code() { return getDataElem(0, "code"); } - Value* Ext::calldataload(Value* _index) { m_builder.CreateStore(_index, m_args[0]); diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index f798ec549..e7200e95a 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -20,8 +20,6 @@ public: llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); - llvm::Value* code(); - llvm::Value* balance(llvm::Value* _address); void suicide(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); @@ -33,8 +31,6 @@ public: llvm::Value* codeAt(llvm::Value* _addr); llvm::Value* codesizeAt(llvm::Value* _addr); -private: - llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = ""); private: llvm::Value* m_args[2]; @@ -46,7 +42,6 @@ private: llvm::Value* m_arg7; llvm::Value* m_arg8; llvm::Value* m_data; - llvm::Function* m_init; llvm::Function* m_store; llvm::Function* m_setStore; llvm::Function* m_calldataload; diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 523d5ea90..489034a17 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -23,6 +23,7 @@ llvm::StructType* RuntimeData::getType() llvm::Type* elems[] = { llvm::ArrayType::get(Type::i256, _size), + Type::BytePtr, Type::BytePtr }; type = llvm::StructType::create(elems, "RuntimeData"); @@ -77,6 +78,7 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext): set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); set(RuntimeData::CodeSize, _ext.code.size()); // TODO: Use constant m_data.callData = _ext.data.data(); + m_data.code = _ext.code.data(); } Runtime::~Runtime() @@ -165,6 +167,12 @@ llvm::Value* RuntimeManager::getCallData() return getBuilder().CreateLoad(ptr, "calldata"); } +llvm::Value* RuntimeManager::getCode() +{ + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "codePtr"); + return getBuilder().CreateLoad(ptr, "code"); +} + llvm::Value* RuntimeManager::getGas() { return get(RuntimeData::Gas); diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index d8f1a2624..7eb7c2d38 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -46,6 +46,7 @@ struct RuntimeData i256 elems[_size]; byte const* callData; + byte const* code; static llvm::StructType* getType(); }; @@ -92,6 +93,7 @@ public: llvm::Value* get(Instruction _inst); llvm::Value* getGas(); // TODO: Remove llvm::Value* getCallData(); + llvm::Value* getCode(); void setGas(llvm::Value* _gas); private: From df144a7e2e911c3fe3fc53c18dcd88a4c1785992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 16:16:02 +0100 Subject: [PATCH 230/396] Old bswap intrinsic removed --- libevmjit/Ext.cpp | 1 - libevmjit/Ext.h | 1 - 2 files changed, 2 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 6659425ea..853b8cd94 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -61,7 +61,6 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_create = Function::Create(TypeBuilder*, i<256>*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_create", module); Type* args[] = {i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy}; m_call = Function::Create(FunctionType::get(m_builder.getVoidTy(), args, false), Linkage::ExternalLinkage, "ext_call", module); - m_bswap = Intrinsic::getDeclaration(module, Intrinsic::bswap, i256Ty); m_sha3 = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_sha3", module); m_exp = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_exp", module); m_codeAt = Function::Create(TypeBuilder*(i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codeAt", module); diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index e7200e95a..fe62f43c6 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -49,7 +49,6 @@ private: llvm::Function* m_suicide; llvm::Function* m_create; llvm::Function* m_call; - llvm::Function* m_bswap; llvm::Function* m_sha3; llvm::Function* m_exp; llvm::Function* m_codeAt; From 18ccc108a0a91bb8f920b5ea742f65814e0c4805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Oct 2014 16:46:53 +0100 Subject: [PATCH 231/396] Using RuntimeData pointer in ext functions [#81470252] --- libevmjit/Ext.cpp | 111 ++++++++++++++++++++---------------------- libevmjit/Runtime.cpp | 6 --- libevmjit/Runtime.h | 2 +- 3 files changed, 53 insertions(+), 66 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 853b8cd94..170086dae 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -8,10 +8,9 @@ #include #include "Runtime.h" +#include "Type.h" #include "Endianness.h" -using namespace llvm; - namespace dev { namespace eth @@ -51,26 +50,27 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg7"); m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8"); - using llvm::types::i; using Linkage = llvm::GlobalValue::LinkageTypes; - m_store = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module); - m_setStore = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module); - m_calldataload = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_calldataload", module); - m_balance = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_balance", module); - m_suicide = Function::Create(TypeBuilder*), true>::get(ctx), Linkage::ExternalLinkage, "ext_suicide", module); - m_create = Function::Create(TypeBuilder*, i<256>*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_create", module); - Type* args[] = {i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy}; - m_call = Function::Create(FunctionType::get(m_builder.getVoidTy(), args, false), Linkage::ExternalLinkage, "ext_call", module); - m_sha3 = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_sha3", module); - m_exp = Function::Create(TypeBuilder*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_exp", module); - m_codeAt = Function::Create(TypeBuilder*(i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codeAt", module); - m_codesizeAt = Function::Create(TypeBuilder*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codesizeAt", module); + + llvm::Type* argsTypes[] = {Type::RuntimePtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; + + m_store = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_store", module); + m_setStore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_setStore", module); + m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_calldataload", module); + m_balance = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_balance", module); + m_suicide = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_suicide", module); + m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 5}, false), Linkage::ExternalLinkage, "ext_create", module); + m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), Linkage::ExternalLinkage, "ext_call", module); + m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_sha3", module); + m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module); + m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), Linkage::ExternalLinkage, "ext_codeAt", module); + m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module); } llvm::Value* Ext::store(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateCall(m_store, m_args); // Uses native endianness + m_builder.CreateCall3(m_store, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); // Uses native endianness return m_builder.CreateLoad(m_args[1]); } @@ -78,40 +78,40 @@ void Ext::setStore(llvm::Value* _index, llvm::Value* _value) { m_builder.CreateStore(_index, m_args[0]); m_builder.CreateStore(_value, m_args[1]); - m_builder.CreateCall(m_setStore, m_args); // Uses native endianness + m_builder.CreateCall3(m_setStore, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); // Uses native endianness } -Value* Ext::calldataload(Value* _index) +llvm::Value* Ext::calldataload(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateCall(m_calldataload, m_args); + m_builder.CreateCall3(m_calldataload, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); auto ret = m_builder.CreateLoad(m_args[1]); return Endianness::toNative(m_builder, ret); } -Value* Ext::balance(Value* _address) +llvm::Value* Ext::balance(llvm::Value* _address) { auto address = Endianness::toBE(m_builder, _address); m_builder.CreateStore(address, m_args[0]); - m_builder.CreateCall(m_balance, m_args); + m_builder.CreateCall3(m_balance, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); return m_builder.CreateLoad(m_args[1]); } -void Ext::suicide(Value* _address) +void Ext::suicide(llvm::Value* _address) { auto address = Endianness::toBE(m_builder, _address); m_builder.CreateStore(address, m_args[0]); - m_builder.CreateCall(m_suicide, m_args[0]); + m_builder.CreateCall2(m_suicide, getRuntimeManager().getRuntimePtr(), m_args[0]); } -Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { m_builder.CreateStore(_endowment, m_args[0]); m_builder.CreateStore(_initOff, m_arg2); m_builder.CreateStore(_initSize, m_arg3); - Value* args[] = {m_args[0], m_arg2, m_arg3, m_args[1]}; + llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_args[1]}; m_builder.CreateCall(m_create, args); - Value* address = m_builder.CreateLoad(m_args[1]); + llvm::Value* address = m_builder.CreateLoad(m_args[1]); address = Endianness::toNative(m_builder, address); return address; } @@ -129,7 +129,7 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V auto codeAddress = Endianness::toBE(m_builder, _codeAddress); m_builder.CreateStore(codeAddress, m_arg8); - llvm::Value* args[] = {m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]}; + llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]}; m_builder.CreateCall(m_call, args); _gas = m_builder.CreateLoad(m_args[0]); // Return gas return m_builder.CreateLoad(m_args[1]); @@ -139,9 +139,9 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) { m_builder.CreateStore(_inOff, m_args[0]); m_builder.CreateStore(_inSize, m_arg2); - llvm::Value* args[] = {m_args[0], m_arg2, m_args[1]}; + llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]}; m_builder.CreateCall(m_sha3, args); - Value* hash = m_builder.CreateLoad(m_args[1]); + llvm::Value* hash = m_builder.CreateLoad(m_args[1]); hash = Endianness::toNative(m_builder, hash); return hash; } @@ -150,7 +150,7 @@ llvm::Value* Ext::exp(llvm::Value* _left, llvm::Value* _right) { m_builder.CreateStore(_left, m_args[0]); m_builder.CreateStore(_right, m_arg2); - llvm::Value* args[] = {m_args[0], m_arg2, m_args[1]}; + llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]}; m_builder.CreateCall(m_exp, args); return m_builder.CreateLoad(m_args[1]); } @@ -159,14 +159,14 @@ llvm::Value* Ext::codeAt(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); m_builder.CreateStore(addr, m_args[0]); - return m_builder.CreateCall(m_codeAt, m_args[0]); + return m_builder.CreateCall2(m_codeAt, getRuntimeManager().getRuntimePtr(), m_args[0]); } llvm::Value* Ext::codesizeAt(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); m_builder.CreateStore(addr, m_args[0]); - llvm::Value* args[] = {m_args[0], m_args[1]}; + llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]}; m_builder.CreateCall(m_codesizeAt, args); return m_builder.CreateLoad(m_args[1]); } @@ -179,51 +179,44 @@ extern "C" using namespace dev::eth::jit; -EXPORT void ext_init(ExtData* _extData) -{ - auto&& ext = Runtime::getExt(); - _extData->calldata = ext.data.data(); - _extData->code = ext.code.data(); -} - -EXPORT void ext_store(i256* _index, i256* _value) +EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value) { auto index = llvm2eth(*_index); - auto value = Runtime::getExt().store(index); // Interface uses native endianness + auto value = _rt->getExt().store(index); // Interface uses native endianness *_value = eth2llvm(value); } -EXPORT void ext_setStore(i256* _index, i256* _value) +EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value) { auto index = llvm2eth(*_index); auto value = llvm2eth(*_value); - Runtime::getExt().setStore(index, value); // Interface uses native endianness + _rt->getExt().setStore(index, value); // Interface uses native endianness } -EXPORT void ext_calldataload(i256* _index, i256* _value) +EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value) { auto index = static_cast(llvm2eth(*_index)); assert(index + 31 > index); // TODO: Handle large index auto b = reinterpret_cast(_value); for (size_t i = index, j = 0; i <= index + 31; ++i, ++j) - b[j] = i < Runtime::getExt().data.size() ? Runtime::getExt().data[i] : 0; // Keep Big Endian + 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(h256* _address, i256* _value) +EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* _value) { - auto u = Runtime::getExt().balance(right160(*_address)); + auto u = _rt->getExt().balance(right160(*_address)); *_value = eth2llvm(u); } -EXPORT void ext_suicide(h256* _address) +EXPORT void ext_suicide(Runtime* _rt, h256* _address) { - Runtime::getExt().suicide(right160(*_address)); + _rt->getExt().suicide(right160(*_address)); } -EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) +EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) { - auto&& ext = Runtime::getExt(); + auto&& ext = _rt->getExt(); auto endowment = llvm2eth(*_endowment); if (ext.balance(ext.myAddress) >= endowment) @@ -244,9 +237,9 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* -EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* _ret) +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 = Runtime::getExt(); + auto&& ext = _rt->getExt(); auto value = llvm2eth(*_value); auto ret = false; @@ -270,7 +263,7 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO _ret->a = ret ? 1 : 0; } -EXPORT void ext_sha3(i256* _inOff, i256* _inSize, i256* _ret) +EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret) { auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); @@ -279,7 +272,7 @@ EXPORT void ext_sha3(i256* _inOff, i256* _inSize, i256* _ret) *_ret = *reinterpret_cast(&hash); } -EXPORT void ext_exp(i256* _left, i256* _right, i256* _ret) +EXPORT void ext_exp(Runtime* _rt, i256* _left, i256* _right, i256* _ret) { bigint left = llvm2eth(*_left); bigint right = llvm2eth(*_right); @@ -287,17 +280,17 @@ EXPORT void ext_exp(i256* _left, i256* _right, i256* _ret) *_ret = eth2llvm(ret); } -EXPORT unsigned char* ext_codeAt(h256* _addr256) +EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) //FIXME: Check endianess { - auto&& ext = Runtime::getExt(); + auto&& ext = _rt->getExt(); auto addr = right160(*_addr256); auto& code = ext.codeAt(addr); return const_cast(code.data()); } -EXPORT void ext_codesizeAt(h256* _addr256, i256* _ret) +EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret) //FIXME: Check endianess { - auto&& ext = Runtime::getExt(); + auto&& ext = _rt->getExt(); auto addr = right160(*_addr256); auto& code = ext.codeAt(addr); *_ret = eth2llvm(u256(code.size())); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 489034a17..4b9464293 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -91,12 +91,6 @@ void Runtime::set(RuntimeData::Index _index, u256 _value) m_data.elems[_index] = eth2llvm(_value); } - -ExtVMFace& Runtime::getExt() -{ - return g_runtime->m_ext; -} - u256 Runtime::getGas() const { return llvm2eth(m_data.elems[RuntimeData::Gas]); diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 7eb7c2d38..ec912849a 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -67,7 +67,7 @@ public: StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } - static ExtVMFace& getExt(); + ExtVMFace& getExt() { return m_ext; } u256 getGas() const; bytesConstRef getReturnData() const; From 2fec309a55e06f059d25393fb3c3ff842388f546 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 27 Oct 2014 21:35:58 +0000 Subject: [PATCH 232/396] Print compilation/execution times --- libevmjit/Compiler.cpp | 8 ++++++++ libevmjit/ExecutionEngine.cpp | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 9632f5194..09314452f 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -10,6 +10,9 @@ #include #include +#include +#include + #include #include "Type.h" @@ -264,6 +267,11 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) dump(); } + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); + return module; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index af5f96ac7..6363f6d72 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -2,6 +2,7 @@ #include "ExecutionEngine.h" #include +#include #include #include @@ -72,7 +73,13 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV if (!exec) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment(errorMsg)); _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(); + std::cerr << "*** Module finalization time: " + << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count() + << std::endl; // Create fake ExtVM interface if (!_ext) @@ -107,9 +114,17 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV auto r = setjmp(buf); if (r == 0) { + auto executionStartTime = std::chrono::high_resolution_clock::now(); + rt_jmpBuf = &buf; auto result = exec->runFunction(entryFunc, {}); returnCode = static_cast(result.IntVal.getZExtValue()); + + auto executionEndTime = std::chrono::high_resolution_clock::now(); + std::cerr << "*** Execution time: " + << std::chrono::duration_cast(executionEndTime - executionStartTime).count() + << std::endl; + } else returnCode = static_cast(r); From 0b2c3c0e00ec3eeb662add094d03dcec59901462 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 27 Oct 2014 23:12:07 +0000 Subject: [PATCH 233/396] 256-bit arithmetic implemented via calls to boost::multiprecision library. [#79450108] --- evmcc/test/arith/div.evm | 1 + evmcc/test/arith/div.lll | 10 ++++ evmcc/test/arith/mul.evm | 1 + evmcc/test/arith/mul.lll | 13 +++++ libevmjit/Arith256.cpp | 118 +++++++++++++++++++++++++++++++++++++++ libevmjit/Arith256.h | 41 ++++++++++++++ 6 files changed, 184 insertions(+) create mode 100644 evmcc/test/arith/div.evm create mode 100644 evmcc/test/arith/div.lll create mode 100644 evmcc/test/arith/mul.evm create mode 100644 evmcc/test/arith/mul.lll create mode 100644 libevmjit/Arith256.cpp create mode 100644 libevmjit/Arith256.h diff --git a/evmcc/test/arith/div.evm b/evmcc/test/arith/div.evm new file mode 100644 index 000000000..b68d5d202 --- /dev/null +++ b/evmcc/test/arith/div.evm @@ -0,0 +1 @@ +60027ffedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432100460005460206000f2 diff --git a/evmcc/test/arith/div.lll b/evmcc/test/arith/div.lll new file mode 100644 index 000000000..72c22bfdc --- /dev/null +++ b/evmcc/test/arith/div.lll @@ -0,0 +1,10 @@ +(asm +0x2 +0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 +DIV +0 +MSTORE +32 +0 +RETURN +) diff --git a/evmcc/test/arith/mul.evm b/evmcc/test/arith/mul.evm new file mode 100644 index 000000000..7e8afd268 --- /dev/null +++ b/evmcc/test/arith/mul.evm @@ -0,0 +1 @@ +7001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba0987654321020260005460206000f2 diff --git a/evmcc/test/arith/mul.lll b/evmcc/test/arith/mul.lll new file mode 100644 index 000000000..b0fa343bb --- /dev/null +++ b/evmcc/test/arith/mul.lll @@ -0,0 +1,13 @@ +(asm +0x1234567890abcdef0fedcba0987654321 +0x1234567890abcdef0fedcba0987654321 +0x1234567890abcdef0fedcba0987654321 +MUL +MUL +0 +MSTORE +32 +0 +RETURN +;; 47d0817e4167b1eb4f9fc722b133ef9d7d9a6fb4c2c1c442d000107a5e419561 +) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp new file mode 100644 index 000000000..094ad2ea5 --- /dev/null +++ b/libevmjit/Arith256.cpp @@ -0,0 +1,118 @@ +#include "Arith256.h" +#include "Runtime.h" +#include "Type.h" + +#include + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Arith256::Arith256(llvm::IRBuilder<>& _builder) : + CompilerHelper(_builder) +{ + using namespace llvm; + + m_result = m_builder.CreateAlloca(Type::i256, nullptr, "arith.result"); + m_arg1 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg1"); + m_arg2 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg2"); + + using Linkage = GlobalValue::LinkageTypes; + + llvm::Type* argTypes[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; + m_mul = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_mul", getModule()); + m_div = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_div", getModule()); + m_mod = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_mod", getModule()); + m_sdiv = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_sdiv", getModule()); + m_smod = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_smod", getModule()); +} + +Arith256::~Arith256() +{} + +llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) +{ + m_builder.CreateStore(_arg1, m_arg1); + m_builder.CreateStore(_arg2, m_arg2); + m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); + return m_builder.CreateLoad(m_result); +} + +llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_mul, _arg1, _arg2); +} + +llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_div, _arg1, _arg2); +} + +llvm::Value* Arith256::mod(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_mod, _arg1, _arg2); +} + +llvm::Value* Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_sdiv, _arg1, _arg2); +} + +llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_smod, _arg1, _arg2); +} + +} +} +} + + +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))); +} + +} + + diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h new file mode 100644 index 000000000..32afae8a7 --- /dev/null +++ b/libevmjit/Arith256.h @@ -0,0 +1,41 @@ +#pragma once + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Arith256 : public CompilerHelper +{ +public: + Arith256(llvm::IRBuilder<>& _builder); + virtual ~Arith256(); + + llvm::Value* mul(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* div(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* mod(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* sdiv(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* smod(llvm::Value* _arg1, llvm::Value* _arg2); + +private: + llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); + + llvm::Function* m_mul; + llvm::Function* m_div; + llvm::Function* m_mod; + llvm::Function* m_sdiv; + llvm::Function* m_smod; + + llvm::Value* m_arg1; + llvm::Value* m_arg2; + llvm::Value* m_result; +}; + + +} +} +} From 07a909188ad32c7a327bfc6b6a5f2fcbb5938dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 09:23:28 +0100 Subject: [PATCH 234/396] Move jmpbuf to Runtime [#81470252] --- libevmjit/ExecutionEngine.cpp | 8 ++------ libevmjit/GasMeter.cpp | 3 +-- libevmjit/Runtime.cpp | 10 +++++++++- libevmjit/Runtime.h | 8 +++++++- libevmjit/Stack.cpp | 8 +++----- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 068237af6..efa039f2b 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -35,8 +35,6 @@ ExecutionEngine::ExecutionEngine() } -extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; } - int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtVMFace* _ext) { auto module = _module.get(); // Keep ownership of the module in _module @@ -102,21 +100,19 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV _ext->code = decltype(_ext->code)(fakecode, 8); } - // Init runtime - Runtime runtime(_gas, *_ext); - auto entryFunc = module->getFunction("main"); if (!entryFunc) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found")); ReturnCode returnCode; std::jmp_buf buf; + Runtime runtime(_gas, *_ext, buf); auto r = setjmp(buf); if (r == 0) { + auto executionStartTime = std::chrono::high_resolution_clock::now(); - rt_jmpBuf = &buf; auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(runtime.getDataPtr())}); returnCode = static_cast(result.IntVal.getZExtValue()); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 317b204fc..897044cbe 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -103,10 +103,9 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.SetInsertPoint(outOfGasBB); //auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); - auto extJmpBuf = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "rt_jmpBuf"); llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", module); - m_builder.CreateCall2(longjmpNative, m_builder.CreateLoad(extJmpBuf), Constant::get(ReturnCode::OutOfGas)); + m_builder.CreateCall2(longjmpNative, m_runtimeManager.getJmpBuf(), Constant::get(ReturnCode::OutOfGas)); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 4b9464293..0be5a5b70 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -24,6 +24,7 @@ llvm::StructType* RuntimeData::getType() { llvm::ArrayType::get(Type::i256, _size), Type::BytePtr, + Type::BytePtr, Type::BytePtr }; type = llvm::StructType::create(elems, "RuntimeData"); @@ -58,7 +59,7 @@ llvm::Twine getName(RuntimeData::Index _index) static Runtime* g_runtime; // FIXME: Remove -Runtime::Runtime(u256 _gas, ExtVMFace& _ext): +Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf): m_ext(_ext) { assert(!g_runtime); @@ -79,6 +80,7 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext): 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; } Runtime::~Runtime() @@ -167,6 +169,12 @@ llvm::Value* RuntimeManager::getCode() return getBuilder().CreateLoad(ptr, "code"); } +llvm::Value* RuntimeManager::getJmpBuf() +{ + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 3, "jmpbufPtr"); + return getBuilder().CreateLoad(ptr, "jmpbuf"); +} + llvm::Value* RuntimeManager::getGas() { return get(RuntimeData::Gas); diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index ec912849a..43fafb4d9 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -41,12 +41,16 @@ struct RuntimeData GasLimit, CodeSize, + ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference + ReturnDataSize = CallDataSize, + _size }; i256 elems[_size]; byte const* callData; byte const* code; + decltype(&jmp_buf{}[0]) jmpBuf; static llvm::StructType* getType(); }; @@ -57,7 +61,7 @@ using MemoryImpl = bytes; class Runtime { public: - Runtime(u256 _gas, ExtVMFace& _ext); + Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf); ~Runtime(); Runtime(const Runtime&) = delete; @@ -71,6 +75,7 @@ public: u256 getGas() const; bytesConstRef getReturnData() const; + decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; } private: void set(RuntimeData::Index _index, u256 _value); @@ -94,6 +99,7 @@ public: llvm::Value* getGas(); // TODO: Remove llvm::Value* getCallData(); llvm::Value* getCode(); + llvm::Value* getJmpBuf(); void setGas(llvm::Value* _gas); private: diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 6c287dc6a..144cd5d54 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -74,13 +74,11 @@ extern "C" using namespace dev::eth::jit; -extern std::jmp_buf* rt_jmpBuf; - EXPORT void stack_pop(Runtime* _rt, uint64_t _count) { auto& stack = _rt->getStack(); if (stack.size() < _count) - longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); stack.erase(stack.end() - _count, stack.end()); } @@ -99,7 +97,7 @@ 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_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); *_ret = *(stack.rbegin() + _index); } @@ -109,7 +107,7 @@ 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_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); *(stack.rbegin() + _index) = *_word; } From d86d6c689b17212a05d5c7a4e589c14ab074ba9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 10:21:50 +0100 Subject: [PATCH 235/396] Fix ReturnData::Index::_size --- libevmjit/Runtime.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 43fafb4d9..c2b21e4ca 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -41,10 +41,10 @@ struct RuntimeData GasLimit, CodeSize, - ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference - ReturnDataSize = CallDataSize, + _size, - _size + ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference + ReturnDataSize = CallDataSize }; i256 elems[_size]; From 33246126f22a0d65837f5aedecef2dbcdbe0f937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 10:27:41 +0100 Subject: [PATCH 236/396] Move return data reference to Runtime [#81470252] --- libevmjit/Compiler.cpp | 5 +++-- libevmjit/Memory.cpp | 18 ++---------------- libevmjit/Memory.h | 12 ++---------- libevmjit/Runtime.cpp | 33 +++++++++++++++++++++++---------- libevmjit/Runtime.h | 5 +++++ 5 files changed, 35 insertions(+), 38 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index dd73ff1e5..3aac68cd8 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -182,7 +182,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) // Init runtime structures. RuntimeManager runtimeManager(m_builder); GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(m_builder, gasMeter, runtimeManager); + Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager); Stack stack(m_builder, runtimeManager); @@ -817,7 +817,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto index = stack.pop(); auto size = stack.pop(); - memory.registerReturnData(index, size); + memory.require(index, size); + _runtimeManager.registerReturnData(index, size); m_builder.CreateRet(Constant::get(ReturnCode::Return)); break; diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index fa5a2b0dd..b7b3d8497 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -24,8 +24,8 @@ namespace eth namespace jit { -Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter, RuntimeManager& _runtimeManager): - CompilerHelper(_builder) +Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): + RuntimeHelper(_runtimeManager) { auto module = getModule(); auto i64Ty = m_builder.getInt64Ty(); @@ -40,12 +40,6 @@ Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter, RuntimeManager& m_size = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); m_size->setUnnamedAddr(true); // Address is not important - m_returnDataOffset = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset"); - m_returnDataOffset->setUnnamedAddr(true); // Address is not important - - m_returnDataSize = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); - m_returnDataSize->setUnnamedAddr(true); // Address is not important - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module); llvm::AttrBuilder attrBuilder; @@ -180,14 +174,6 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) require(sizeRequired); } -void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) -{ - require(_index, _size); // Make sure that memory is allocated and count gas - - m_builder.CreateStore(_index, m_returnDataOffset); - m_builder.CreateStore(_size, m_returnDataSize); -} - void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, llvm::Value* _destMemIdx, llvm::Value* _reqBytes) { diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index d92538247..d8c1e4b72 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -10,12 +10,11 @@ namespace eth { namespace jit { -class RuntimeManager; -class Memory : public CompilerHelper +class Memory : public RuntimeHelper { public: - Memory(llvm::IRBuilder<>& _builder, class GasMeter& _gasMeter, RuntimeManager& _runtimeManager); + Memory(RuntimeManager& _runtimeManager, class GasMeter& _gasMeter); llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); @@ -31,9 +30,6 @@ public: /// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory. void require(llvm::Value* _offset, llvm::Value* _size); - void registerReturnData(llvm::Value* _index, llvm::Value* _size); - bytesConstRef getReturnData(); - void dump(uint64_t _begin, uint64_t _end = 0); private: @@ -44,10 +40,6 @@ private: llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; - /// @TODO: m_data and m_size could be used - llvm::GlobalVariable* m_returnDataOffset; - llvm::GlobalVariable* m_returnDataSize; - llvm::Function* m_resize; llvm::Function* m_require; llvm::Function* m_loadWord; diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 0be5a5b70..b9dd63ea2 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -98,16 +98,14 @@ u256 Runtime::getGas() const return llvm2eth(m_data.elems[RuntimeData::Gas]); } -extern "C" { - EXPORT i256 mem_returnDataOffset; // FIXME: Dis-globalize - EXPORT i256 mem_returnDataSize; -} - bytesConstRef Runtime::getReturnData() const { // TODO: Handle large indexes - auto offset = static_cast(llvm2eth(mem_returnDataOffset)); - auto size = static_cast(llvm2eth(mem_returnDataSize)); + auto offset = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset])); + auto size = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataSize])); + + assert(offset + size <= m_memory.size()); + // TODO: Handle invalid data access by returning empty ref return {m_memory.data() + offset, size}; } @@ -128,11 +126,26 @@ llvm::Value* RuntimeManager::getRuntimePtr() return m_builder.CreateLoad(m_dataPtr); } -llvm::Value* RuntimeManager::get(RuntimeData::Index _index) +llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) { llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)}; - auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr"); - return m_builder.CreateLoad(ptr, getName(_index)); + return m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr"); +} + +llvm::Value* RuntimeManager::get(RuntimeData::Index _index) +{ + return m_builder.CreateLoad(getPtr(_index), getName(_index)); +} + +void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value) +{ + m_builder.CreateStore(_value, getPtr(_index)); +} + +void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size) +{ + set(RuntimeData::ReturnDataOffset, _offset); + set(RuntimeData::ReturnDataSize, _size); } llvm::Value* RuntimeManager::get(Instruction _inst) diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index c2b21e4ca..f516912eb 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -102,7 +102,12 @@ public: llvm::Value* getJmpBuf(); void setGas(llvm::Value* _gas); + void registerReturnData(llvm::Value* _index, llvm::Value* _size); + private: + llvm::Value* getPtr(RuntimeData::Index _index); + void set(RuntimeData::Index _index, llvm::Value* _value); + llvm::GlobalVariable* m_dataPtr; }; From 66a7834e95337f12834f90635a77cff357c4b30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 10:32:10 +0100 Subject: [PATCH 237/396] Change some runtime names --- libevmjit/Compiler.cpp | 1 + libevmjit/Runtime.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 3aac68cd8..cfa9349c6 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -172,6 +172,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) 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"); // Create the basic blocks. auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index b9dd63ea2..233ce2a39 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -27,7 +27,7 @@ llvm::StructType* RuntimeData::getType() Type::BytePtr, Type::BytePtr }; - type = llvm::StructType::create(elems, "RuntimeData"); + type = llvm::StructType::create(elems, "Runtime"); } return type; } From bb67c7587dadf78f3e694c4a0f6cd6f9a4f4faa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 10:43:18 +0100 Subject: [PATCH 238/396] Get Runtime pointer from main function argument if available --- libevmjit/CompilerHelper.cpp | 6 ++++-- libevmjit/Runtime.cpp | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index c2d612c66..c4835c32e 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -27,8 +27,10 @@ llvm::Function* CompilerHelper::getMainFunction() { assert(m_builder.GetInsertBlock()); auto mainFunc = m_builder.GetInsertBlock()->getParent(); - assert(mainFunc && mainFunc->getName() == "main"); - return mainFunc; + assert(mainFunc); + if (mainFunc->getName() == "main") + return mainFunc; + return nullptr; } diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 233ce2a39..86966e2b1 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -122,8 +122,9 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui llvm::Value* RuntimeManager::getRuntimePtr() { - // TODO: If in main function - get it from param - return m_builder.CreateLoad(m_dataPtr); + if (auto mainFunc = getMainFunction()) + return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function + return m_builder.CreateLoad(m_dataPtr, "rt"); } llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) From 2eedd8dfdbaed08d8274bb429374413c60e9084b Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 28 Oct 2014 09:50:42 +0000 Subject: [PATCH 239/396] Added missing changes [#79450108] --- libevmjit/Compiler.cpp | 89 ++++++++++++++++-------------------------- libevmjit/Compiler.h | 2 +- 2 files changed, 35 insertions(+), 56 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index dd73ff1e5..a03543d91 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -22,6 +22,7 @@ #include "GasMeter.h" #include "Utils.h" #include "Endianness.h" +#include "Arith256.h" #include "Runtime.h" namespace dev @@ -185,6 +186,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) Memory memory(m_builder, gasMeter, runtimeManager); Ext ext(runtimeManager); Stack stack(m_builder, runtimeManager); + Arith256 arith(m_builder); m_builder.CreateBr(basicBlocks.begin()->second); @@ -194,7 +196,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, bytecode, runtimeManager, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: @@ -280,7 +282,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) } -void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) +void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Arith256& arith, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) { m_builder.SetInsertPoint(basicBlock.llvm()); auto& stack = basicBlock.localStack(); @@ -314,61 +316,46 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::MUL: { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateMul(lhs128, rhs128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.mul(lhs, rhs); + stack.push(res); break; } case Instruction::DIV: { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateUDiv(lhs128, rhs128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.div(lhs, rhs); + stack.push(res); break; } case Instruction::SDIV: { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateSDiv(lhs128, rhs128); - auto res256 = m_builder.CreateSExt(res128, Type::i256); - stack.push(res256); + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.sdiv(lhs, rhs); + stack.push(res); break; } case Instruction::MOD: { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateURem(lhs128, rhs128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.mod(lhs, rhs); + stack.push(res); break; } case Instruction::SMOD: { - auto lhs256 = stack.pop(); - auto rhs256 = stack.pop(); - auto lhs128 = m_builder.CreateTrunc(lhs256, Type::lowPrecision); - auto rhs128 = m_builder.CreateTrunc(rhs256, Type::lowPrecision); - auto res128 = m_builder.CreateSRem(lhs128, rhs128); - auto res256 = m_builder.CreateSExt(res128, Type::i256); - stack.push(res256); + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.smod(lhs, rhs); + stack.push(res); break; } @@ -496,31 +483,23 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ADDMOD: { - auto val1 = stack.pop(); - auto val2 = stack.pop(); - auto sum = m_builder.CreateAdd(val1, val2); + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto sum = m_builder.CreateAdd(lhs, rhs); auto mod = stack.pop(); - - auto sum128 = m_builder.CreateTrunc(sum, Type::lowPrecision); - auto mod128 = m_builder.CreateTrunc(mod, Type::lowPrecision); - auto res128 = m_builder.CreateURem(sum128, mod128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); + auto res = arith.mod(sum, mod); + stack.push(res); break; } case Instruction::MULMOD: { - auto val1 = stack.pop(); - auto val2 = stack.pop(); - auto prod = m_builder.CreateMul(val1, val2); + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto prod = m_builder.CreateMul(lhs, rhs); auto mod = stack.pop(); - - auto prod128 = m_builder.CreateTrunc(prod, Type::lowPrecision); - auto mod128 = m_builder.CreateTrunc(mod, Type::lowPrecision); - auto res128 = m_builder.CreateURem(prod128, mod128); - auto res256 = m_builder.CreateZExt(res128, Type::i256); - stack.push(res256); + auto res = arith.mod(prod, mod); + stack.push(res); break; } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index d543b9b1d..d58745a06 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -31,7 +31,7 @@ private: void createBasicBlocks(bytesConstRef bytecode); - void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class RuntimeManager& _runtimeManager, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); + void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class RuntimeManager& _runtimeManager, class Arith256& arith, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); void removeDeadBlocks(); From 686e894b26de378e82484e7670439adb122fdd05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 11:17:00 +0100 Subject: [PATCH 240/396] Add Arith256.* files to Visual Studio project --- windows/LibEvmJit.vcxproj | 2 ++ windows/LibEvmJit.vcxproj.filters | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index 1fdc62392..a9288a212 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -123,6 +123,7 @@ + @@ -138,6 +139,7 @@ + diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters index b8e592036..ae89fe550 100644 --- a/windows/LibEvmJit.vcxproj.filters +++ b/windows/LibEvmJit.vcxproj.filters @@ -45,6 +45,9 @@ libevmjit + + libevmjit + @@ -86,5 +89,8 @@ libevmjit + + libevmjit + \ No newline at end of file From d74ce85d4a9ee03157d3624764a9e8f60586313e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 11:24:50 +0100 Subject: [PATCH 241/396] Restore correct memory access in Ext functions --- libevmjit/Ext.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 170086dae..bf7947408 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -225,8 +225,7 @@ EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _in u256 gas; // TODO: Handle gas auto initOff = static_cast(llvm2eth(*_initOff)); auto initSize = static_cast(llvm2eth(*_initSize)); - //auto&& initRef = bytesConstRef(Runtime::getMemory().data() + initOff, initSize); - bytesConstRef initRef; + auto&& initRef = bytesConstRef(_rt->getMemory().data() + initOff, initSize); OnOpFunc onOp{}; // TODO: Handle that thing h256 address = ext.create(endowment, &gas, initRef, onOp); *_address = address; @@ -252,8 +251,8 @@ EXPORT void ext_call(Runtime* _rt, i256* _gas, h256* _receiveAddress, i256* _val auto inSize = static_cast(llvm2eth(*_inSize)); auto outOff = static_cast(llvm2eth(*_outOff)); auto outSize = static_cast(llvm2eth(*_outSize)); - auto&& inRef = bytesConstRef(); //Runtime::getMemory().data() + inOff, inSize); - auto&& outRef = bytesConstRef(); // Runtime::getMemory().data() + outOff, 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); @@ -267,7 +266,7 @@ EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret) { auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); - auto dataRef = bytesConstRef(); // Runtime::getMemory().data() + inOff, inSize); + auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); auto hash = sha3(dataRef); *_ret = *reinterpret_cast(&hash); } From a0204f8e50178e463a76e25e21d58872a0586877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 11:37:15 +0100 Subject: [PATCH 242/396] Fix EXTCODECOPY --- libevmjit/Ext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index bf7947408..003b0ae08 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -63,7 +63,7 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), Linkage::ExternalLinkage, "ext_call", module); m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_sha3", module); m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module); - m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), Linkage::ExternalLinkage, "ext_codeAt", module); + m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_codeAt", module); m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module); } From df4267e6f8251e3998a68356e86dcba8ef1ef6af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 12:28:23 +0100 Subject: [PATCH 243/396] Ignore opOp callback silently --- libevmjit/VM.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 9a76c5bcb..56121941e 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -13,9 +13,8 @@ namespace eth namespace jit { -bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) { - assert(!_onOp); // Parameter ignored assert(_steps == (uint64_t)-1); // Parameter ignored auto module = Compiler().compile(_ext.code); From f1451174e30583c3ae02dc95b4b03bd8f70b9417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 12:30:05 +0100 Subject: [PATCH 244/396] Ignore opOp callback silently --- libevmjit/VM.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 56121941e..dd54dd0e5 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -15,8 +15,6 @@ namespace jit bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) { - assert(_steps == (uint64_t)-1); // Parameter ignored - auto module = Compiler().compile(_ext.code); ExecutionEngine engine; From 23440c642a533b291000383ad218734648073f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 14:28:23 +0100 Subject: [PATCH 245/396] Return jit::VM only if ETH_JIT macro is on --- libevm/VMFace.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libevm/VMFace.cpp b/libevm/VMFace.cpp index 2553f3004..03f228ad0 100644 --- a/libevm/VMFace.cpp +++ b/libevm/VMFace.cpp @@ -24,7 +24,12 @@ using namespace dev::eth; std::unique_ptr VMFace::create(VMFace::Kind _kind, u256 _gas) { - std::unique_ptr vm(_kind == Kind::JIT ? static_cast(new jit::VM) : new VM); + std::unique_ptr vm; +#if ETH_JIT + vm.reset(_kind == Kind::JIT ? static_cast(new jit::VM) : new VM); +#else + vm.reset(new VM); +#endif vm->reset(_gas); return vm; } From 8cec0751fda1021e3ed55e1049670c9da23987b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 15:37:24 +0100 Subject: [PATCH 246/396] Add missing Visual Studio projects dependencies --- windows/LibEthereum.vcxproj | 4 ++++ windows/TestEthereum.vcxproj | 3 +++ 2 files changed, 7 insertions(+) diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index d19bbc175..956252979 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -479,21 +479,25 @@ + + + + diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index 94667fa16..d81fe613a 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -189,6 +189,9 @@ + + {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} + {9c816740-5c11-4377-a3a7-46be12f35fa0} From 5707ac924ab3428832f5713689a0d105f2fc1e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 16:08:19 +0100 Subject: [PATCH 247/396] Disable LLVM dependency --- windows/Eth.vcxproj | 3 --- windows/LLVM.props | 2 +- windows/TestEthereum.vcxproj | 3 --- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/windows/Eth.vcxproj b/windows/Eth.vcxproj index d67d964f8..3af0a0bce 100644 --- a/windows/Eth.vcxproj +++ b/windows/Eth.vcxproj @@ -155,9 +155,6 @@ {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} - - {9c816740-5c11-4377-a3a7-46be12f35fa0} - diff --git a/windows/LLVM.props b/windows/LLVM.props index a5c6c4dc5..72fd53a85 100644 --- a/windows/LLVM.props +++ b/windows/LLVM.props @@ -2,7 +2,7 @@ - 1 + 0 ../../llvm ../../_build/llvm/$(Platform) $(LLVMSrcDir)\include;$(LLVMBuildDir)\include diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index d81fe613a..57542f0b4 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -192,9 +192,6 @@ {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} - - {9c816740-5c11-4377-a3a7-46be12f35fa0} - From acc50285e7f6bd38b48e779bf0370e9b1bd2c292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 17:41:38 +0100 Subject: [PATCH 248/396] Fix compile on Visual Studio --- libevm/VM.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index d5db792f5..6e9819ccd 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -427,12 +427,12 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::SIGNEXTEND: { - unsigned k = m_stack.back(); + unsigned k = m_stack.back().convert_to(); m_stack.pop_back(); auto& b = m_stack.back(); if (k <= 31) if ((b >> (k * 8)) & 0x80) - for (int i = 31; i > k; --i) + for (unsigned i = 31; i > k; --i) b |= (u256(0xff) << i); break; } From 6541b0db8a87e9102a2346d3caf8200ea54bdece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 18:04:01 +0100 Subject: [PATCH 249/396] Add raiseException helper to RuntimeManager [#81563132] --- libevmjit/GasMeter.cpp | 6 +----- libevmjit/GasMeter.h | 2 +- libevmjit/Runtime.cpp | 7 +++++++ libevmjit/Runtime.h | 8 ++++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index b71fd8286..7294fa2f7 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -101,11 +101,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - - //auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); - llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; - auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", module); - m_builder.CreateCall2(longjmpNative, m_runtimeManager.getJmpBuf(), Constant::get(ReturnCode::OutOfGas)); + _runtimeManager.raiseException(ReturnCode::OutOfGas); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 82007fc00..dcfde92a3 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -13,7 +13,7 @@ namespace jit { class RuntimeManager; -class GasMeter : public CompilerHelper +class GasMeter : public CompilerHelper // TODO: Use RuntimeHelper { public: GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 86966e2b1..a93f191a9 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -113,6 +113,8 @@ bytesConstRef Runtime::getReturnData() const RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) { m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt"); + llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; + m_longjmp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", getModule()); // Export data auto mainFunc = getMainFunction(); @@ -149,6 +151,11 @@ void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size set(RuntimeData::ReturnDataSize, _size); } +void RuntimeManager::raiseException(ReturnCode _returnCode) +{ + m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); +} + llvm::Value* RuntimeManager::get(Instruction _inst) { switch (_inst) diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index f516912eb..ad2002674 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -7,6 +7,7 @@ #include "CompilerHelper.h" #include "Utils.h" +#include "Type.h" #ifdef _MSC_VER @@ -99,16 +100,19 @@ public: llvm::Value* getGas(); // TODO: Remove llvm::Value* getCallData(); llvm::Value* getCode(); - llvm::Value* getJmpBuf(); void setGas(llvm::Value* _gas); void registerReturnData(llvm::Value* _index, llvm::Value* _size); + void raiseException(ReturnCode _returnCode); + private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); + llvm::Value* getJmpBuf(); - llvm::GlobalVariable* m_dataPtr; + llvm::GlobalVariable* m_dataPtr = nullptr; + llvm::Function* m_longjmp = nullptr; }; } From 6ae263f9867cab8c1192d56d295fcbbb32c5fc16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 18:15:58 +0100 Subject: [PATCH 250/396] Handle bad instructions (BadInstruction exception) [#81563132] --- evmcc/test/except/badinst1.evm | 1 + libevmjit/Compiler.cpp | 5 +++++ libevmjit/Type.h | 3 ++- libevmjit/VM.cpp | 11 +++++++---- 4 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 evmcc/test/except/badinst1.evm diff --git a/evmcc/test/except/badinst1.evm b/evmcc/test/except/badinst1.evm new file mode 100644 index 000000000..69aadac5e --- /dev/null +++ b/evmcc/test/except/badinst1.evm @@ -0,0 +1 @@ +4a diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 0b9fb5b7b..02c8db715 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -816,6 +816,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, break; } + default: // Invalid instruction - runtime exception + { + _runtimeManager.raiseException(ReturnCode::BadInstruction); + } + } } diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 86915cd9e..b432f0813 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -43,7 +43,8 @@ enum class ReturnCode BadJumpDestination = 101, OutOfGas = 102, - StackTooSmall = 103 + StackTooSmall = 103, + BadInstruction = 104, }; struct Constant diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index dd54dd0e5..0907682d2 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -5,6 +5,7 @@ #include "ExecutionEngine.h" #include "Compiler.h" +#include "Type.h" namespace dev { @@ -20,14 +21,16 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) ExecutionEngine engine; auto exitCode = engine.run(std::move(module), m_gas, &_ext); - switch (exitCode) + switch (static_cast(exitCode)) { - case 101: + case ReturnCode::BadJumpDestination: BOOST_THROW_EXCEPTION(BadJumpDestination()); - case 102: + case ReturnCode::OutOfGas: BOOST_THROW_EXCEPTION(OutOfGas()); - case 103: + case ReturnCode::StackTooSmall: BOOST_THROW_EXCEPTION(StackTooSmall(1,0)); + case ReturnCode::BadInstruction: + BOOST_THROW_EXCEPTION(BadInstruction()); } m_output = std::move(engine.returnData); From 1b2e51432abad75a1a4ab9e111b5a9f4f8771725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 20:20:21 +0100 Subject: [PATCH 251/396] Call helper --- libevmjit/CompilerHelper.h | 7 +++++++ libevmjit/GasMeter.cpp | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index cf83d70cd..c2257bf51 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -31,6 +31,13 @@ protected: llvm::IRBuilder<>& m_builder; llvm::IRBuilder<>& getBuilder() { return m_builder; } + template + llvm::CallInst* call(llvm::Function* _func, _Args*... _args) + { + llvm::Value* args[] = {_args...}; + return m_builder.CreateCall(_func, args); + } + friend class RuntimeHelper; }; diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 7294fa2f7..20ee30e9a 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -143,7 +143,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu 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"); - m_builder.CreateCall(m_gasCheckFunc, cost); + call(m_gasCheckFunc, cost); } void GasMeter::giveBack(llvm::Value* _gas) From 2ae0fa25d6f21f048729c210144fa5ad43789e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 20:36:03 +0100 Subject: [PATCH 252/396] Using call helper --- libevmjit/CompilerHelper.h | 4 ++-- libevmjit/Ext.cpp | 17 ++++++----------- libevmjit/GasMeter.cpp | 2 +- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index c2257bf51..19315fe4a 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -32,10 +32,10 @@ protected: llvm::IRBuilder<>& getBuilder() { return m_builder; } template - llvm::CallInst* call(llvm::Function* _func, _Args*... _args) + llvm::CallInst* createCall(llvm::Function* _func, _Args*... _args) { llvm::Value* args[] = {_args...}; - return m_builder.CreateCall(_func, args); + return getBuilder().CreateCall(_func, args); } friend class RuntimeHelper; diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 34c1ebf5e..0da9c8809 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -109,8 +109,7 @@ llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::V m_builder.CreateStore(_endowment, m_args[0]); m_builder.CreateStore(_initOff, m_arg2); m_builder.CreateStore(_initSize, m_arg3); - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_args[1]}; - m_builder.CreateCall(m_create, args); + createCall(m_create, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_args[1]); llvm::Value* address = m_builder.CreateLoad(m_args[1]); address = Endianness::toNative(m_builder, address); return address; @@ -128,9 +127,7 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V m_builder.CreateStore(_outSize, m_arg7); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); m_builder.CreateStore(codeAddress, m_arg8); - - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]}; - m_builder.CreateCall(m_call, args); + createCall(m_call, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]); _gas = m_builder.CreateLoad(m_args[0]); // Return gas return m_builder.CreateLoad(m_args[1]); } @@ -139,8 +136,7 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) { m_builder.CreateStore(_inOff, m_args[0]); m_builder.CreateStore(_inSize, m_arg2); - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]}; - m_builder.CreateCall(m_sha3, args); + createCall(m_sha3, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]); llvm::Value* hash = m_builder.CreateLoad(m_args[1]); hash = Endianness::toNative(m_builder, hash); return hash; @@ -148,10 +144,10 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) llvm::Value* Ext::exp(llvm::Value* _left, llvm::Value* _right) { + // TODO: Move ext to Arith256 m_builder.CreateStore(_left, m_args[0]); m_builder.CreateStore(_right, m_arg2); - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]}; - m_builder.CreateCall(m_exp, args); + createCall(m_exp, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]); return m_builder.CreateLoad(m_args[1]); } @@ -166,8 +162,7 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); m_builder.CreateStore(addr, m_args[0]); - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]}; - m_builder.CreateCall(m_codesizeAt, args); + createCall(m_codesizeAt, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); return m_builder.CreateLoad(m_args[1]); } diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 20ee30e9a..149944f28 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -143,7 +143,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu 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"); - call(m_gasCheckFunc, cost); + createCall(m_gasCheckFunc, cost); } void GasMeter::giveBack(llvm::Value* _gas) From f4202d9144057642846a05501329cd4969301b3c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 28 Oct 2014 22:25:08 +0000 Subject: [PATCH 253/396] 1. Indenting spaces converted to tabs 2. Options changed: -G --> -g --- evmcc/evmcc.cpp | 125 ++++++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 56 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index abaf3e511..1e0b7e1cd 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -1,4 +1,5 @@ +#include #include #include #include @@ -18,92 +19,104 @@ void show_usage() { - // FIXME: Use arg[0] as program name? - std::cerr << "usage: evmcc (-b|-c|-d)+ \n"; + // FIXME: Use arg[0] as program name? + std::cerr << "usage: evmcc (-b|-c|-d)+ \n"; } int main(int argc, char** argv) { - std::string input_file; - bool opt_dissassemble = false; - bool opt_show_bytes = false; + std::string input_file; + bool opt_dissassemble = false; + bool opt_show_bytes = false; bool opt_compile = false; bool opt_interpret = false; bool opt_dump_graph = false; bool opt_unknown = false; + bool opt_verbose = false; size_t initialGas = 10000; - for (int i = 1; i < argc; i++) - { - std::string option = argv[i]; - if (option == "-b") - opt_show_bytes = true; - else if (option == "-c") - opt_compile = true; - else if (option == "-d") + for (int i = 1; i < argc; i++) + { + std::string option = argv[i]; + if (option == "-b") + opt_show_bytes = true; + else if (option == "-c") + opt_compile = true; + else if (option == "-d") opt_dissassemble = true; else if (option == "-i") opt_interpret = true; - else if (option == "-g") + else if (option == "--dump-cfg") opt_dump_graph = true; - else if (option == "-G" && i + 1 < argc) + else if (option == "-g" && i + 1 < argc) { std::string gasValue = argv[++i]; initialGas = boost::lexical_cast(gasValue); std::cerr << "Initial gas set to " << initialGas << "\n"; } + else if (option == "-v") + opt_verbose = true; else if (option[0] != '-' && input_file.empty()) input_file = option; - else - { - opt_unknown = true; - break; - } - } - - if (opt_unknown || - input_file.empty() || - (!opt_show_bytes && !opt_compile && !opt_dissassemble && !opt_interpret)) - { - show_usage(); - exit(1); - } - - std::ifstream ifs(input_file); - if (!ifs.is_open()) - { - std::cerr << "cannot open file " << input_file << std::endl; - exit(1); - } - - std::string src((std::istreambuf_iterator(ifs)), - (std::istreambuf_iterator())); - - boost::algorithm::trim(src); + else + { + opt_unknown = true; + break; + } + } + + if (opt_unknown || + input_file.empty() || + (!opt_show_bytes && !opt_compile && !opt_dissassemble && !opt_interpret)) + { + show_usage(); + exit(1); + } + + std::ifstream ifs(input_file); + if (!ifs.is_open()) + { + std::cerr << "cannot open file " << input_file << std::endl; + exit(1); + } + + std::string src((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + + boost::algorithm::trim(src); using namespace dev; - bytes bytecode = fromHex(src); + bytes bytecode = fromHex(src); - if (opt_show_bytes) - { - std::cout << memDump(bytecode) << std::endl; - } + if (opt_show_bytes) + std::cout << memDump(bytecode) << std::endl; - if (opt_dissassemble) - { - std::string assembly = eth::disassemble(bytecode); - std::cout << assembly << std::endl; - } + if (opt_dissassemble) + { + std::string assembly = eth::disassemble(bytecode); + std::cout << assembly << std::endl; + } - if (opt_compile || opt_interpret) - { - auto compiler = eth::jit::Compiler(); + if (opt_compile || opt_interpret) + { + auto compilationStartTime = std::chrono::high_resolution_clock::now(); + + auto compiler = eth::jit::Compiler(); auto module = compiler.compile({bytecode.data(), bytecode.size()}); + auto compilationEndTime = std::chrono::high_resolution_clock::now(); + module->dump(); + if (opt_verbose) + { + std::cerr << "*** Compilation time: " + << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count() + << std::endl; + } + if (opt_dump_graph) { std::ofstream ofs("blocks.dot"); @@ -119,7 +132,7 @@ int main(int argc, char** argv) auto result = engine.run(std::move(module), gas); return result; } - } + } - return 0; + return 0; } From 017bfd9d7a706ee750a88e1dc2a47e9bc81b1e31 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 28 Oct 2014 22:29:00 +0000 Subject: [PATCH 254/396] Changed semantics of JUMPDEST so that *the next* instruction is a jump destination --- libevmjit/Compiler.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index a03543d91..cd680d927 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -91,9 +91,12 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) case Instruction::JUMPDEST: { - // A basic block starts here. - splitPoints.insert(currentPC); - indirectJumpTargets.push_back(currentPC); + // A basic block starts at the next instruction. + if (currentPC + 1 < bytecode.size()) + { + splitPoints.insert(currentPC + 1); + indirectJumpTargets.push_back(currentPC + 1); + } break; } @@ -653,8 +656,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::JUMPDEST: { - // Extra asserts just in case. - assert(currentPC == basicBlock.begin()); + // Nothing to do break; } From f48c0d7e9603ae32f42ee5a28237ecb9e04e214f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 10:21:59 +0100 Subject: [PATCH 255/396] Expose VM kind setting of State in FakeExtVM This reverts commit 6ad065bb3e30b5e67283f70e84ac55368e843e6a. --- test/vm.cpp | 19 ++++++++++--------- test/vm.h | 2 ++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index d03a4a278..a8e1ea727 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -441,8 +441,8 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end m_cache[_newAddress] = AddressState(0, balance(_newAddress) + _endowment, h256(), h256()); // Execute init code. - auto vmObj = VMFace::create(VMFace::Interpreter, *_gas); - VMFace& vm = *vmObj; + auto vmObj = VMFace::create(getVMKind(), *_gas); + auto& vm = *vmObj; ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); bool revert = false; bytesConstRef out; @@ -500,7 +500,14 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_REQUIRE(o.count("pre") > 0); BOOST_REQUIRE(o.count("exec") > 0); + auto argc = boost::unit_test::framework::master_test_suite().argc; + auto argv = boost::unit_test::framework::master_test_suite().argv; + auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; + auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; + dev::test::FakeExtVM fev; + fev.setVMKind(vmKind); + fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -513,14 +520,8 @@ void doTests(json_spirit::mValue& v, bool _fillin) fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); fev.code = &fev.thisTxCode; } - - - auto argc = boost::unit_test::framework::master_test_suite().argc; - auto argv = boost::unit_test::framework::master_test_suite().argv; - auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; - auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; - auto vm = VMFace::create(vmKind, fev.gas); + auto vm = VMFace::create(fev.getVMKind(), fev.gas); bytes output; auto outOfGas = false; try diff --git a/test/vm.h b/test/vm.h index f3aae694a..e51fe3f89 100644 --- a/test/vm.h +++ b/test/vm.h @@ -80,6 +80,8 @@ public: void importExec(json_spirit::mObject& _o); json_spirit::mArray exportCallCreates(); void importCallCreates(json_spirit::mArray& _callcreates); + void setVMKind(eth::VMFace::Kind _kind) { m_s.setVMKind(_kind); } + eth::VMFace::Kind getVMKind() const { return m_s.getVMKind(); } template eth::OnOpFunc simpleTrace(); From 57fd3e14587a5639bed1b6b5d5b054611de25ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 10:30:00 +0100 Subject: [PATCH 256/396] Remove global Runtime pointer --- libevmjit/Runtime.cpp | 9 --------- libevmjit/Runtime.h | 1 - 2 files changed, 10 deletions(-) diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index a93f191a9..3efd78a26 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -57,13 +57,9 @@ llvm::Twine getName(RuntimeData::Index _index) } } -static Runtime* g_runtime; // FIXME: Remove - Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf): m_ext(_ext) { - assert(!g_runtime); - g_runtime = this; set(RuntimeData::Gas, _gas); set(RuntimeData::Address, fromAddress(_ext.myAddress)); set(RuntimeData::Caller, fromAddress(_ext.caller)); @@ -83,11 +79,6 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf): m_data.jmpBuf = _jmpBuf; } -Runtime::~Runtime() -{ - g_runtime = nullptr; -} - void Runtime::set(RuntimeData::Index _index, u256 _value) { m_data.elems[_index] = eth2llvm(_value); diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index ad2002674..418652c40 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -63,7 +63,6 @@ class Runtime { public: Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf); - ~Runtime(); Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; From 732c40b57a667f04c790e17d2fa31f56c4b42c2e Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 10:29:34 +0000 Subject: [PATCH 257/396] MULMOD/ADDMOD implemented in separate functions [FIXES #80566276] --- libevmjit/Arith256.cpp | 53 +++++++++++++++++++++++++++++++++++++----- libevmjit/Arith256.h | 6 +++++ libevmjit/Compiler.cpp | 6 ++--- test/vm.cpp | 26 +++++++++++++++++++-- 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 094ad2ea5..caf7bf3d0 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -21,15 +21,20 @@ Arith256::Arith256(llvm::IRBuilder<>& _builder) : m_result = m_builder.CreateAlloca(Type::i256, nullptr, "arith.result"); m_arg1 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg1"); m_arg2 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg2"); + m_arg3 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg3"); using Linkage = GlobalValue::LinkageTypes; - llvm::Type* argTypes[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; - m_mul = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_mul", getModule()); - m_div = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_div", getModule()); - m_mod = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_mod", getModule()); - m_sdiv = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_sdiv", getModule()); - m_smod = Function::Create(FunctionType::get(Type::Void, argTypes, false), Linkage::ExternalLinkage, "arith_smod", getModule()); + llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; + llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; + + m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); + m_div = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_div", getModule()); + m_mod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mod", getModule()); + m_sdiv = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule()); + m_smod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_smod", getModule()); + m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule()); + m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule()); } Arith256::~Arith256() @@ -43,6 +48,15 @@ llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::V return m_builder.CreateLoad(m_result); } +llvm::Value* Arith256::ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + m_builder.CreateStore(_arg1, m_arg1); + m_builder.CreateStore(_arg2, m_arg2); + m_builder.CreateStore(_arg3, m_arg3); + m_builder.CreateCall4(_op, m_arg1, m_arg2, m_arg3, m_result); + return m_builder.CreateLoad(m_result); +} + llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { return binaryOp(m_mul, _arg1, _arg2); @@ -68,6 +82,17 @@ llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2) return binaryOp(m_smod, _arg1, _arg2); } +llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + return ternaryOp(m_addmod, _arg1, _arg2, _arg3); +} + +llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + return ternaryOp(m_mulmod, _arg1, _arg2, _arg3); +} + + } } } @@ -113,6 +138,22 @@ EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* _result) *_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)); +} + } diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 32afae8a7..2268d5076 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -20,18 +20,24 @@ public: llvm::Value* mod(llvm::Value* _arg1, llvm::Value* _arg2); llvm::Value* sdiv(llvm::Value* _arg1, llvm::Value* _arg2); llvm::Value* smod(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); + llvm::Value* addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); private: llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); llvm::Function* m_mul; llvm::Function* m_div; llvm::Function* m_mod; llvm::Function* m_sdiv; llvm::Function* m_smod; + llvm::Function* m_mulmod; + llvm::Function* m_addmod; llvm::Value* m_arg1; llvm::Value* m_arg2; + llvm::Value* m_arg3; llvm::Value* m_result; }; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index cd680d927..d36ee5009 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -488,9 +488,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto sum = m_builder.CreateAdd(lhs, rhs); auto mod = stack.pop(); - auto res = arith.mod(sum, mod); + auto res = arith.addmod(lhs, rhs, mod); stack.push(res); break; } @@ -499,9 +498,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto prod = m_builder.CreateMul(lhs, rhs); auto mod = stack.pop(); - auto res = arith.mod(prod, mod); + auto res = arith.mulmod(lhs, rhs, mod); stack.push(res); break; } diff --git a/test/vm.cpp b/test/vm.cpp index d62329af4..c056abf5b 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -24,7 +24,7 @@ #include #include #include - +#include //#define FILL_TESTS using namespace std; @@ -357,7 +357,7 @@ void FakeExtVM::importExec(mObject& _o) thisTxCode.clear(); code = &thisTxCode; if (_o["code"].type() == str_type) - if (_o["code"].get_str().find_first_of("0x") == 0) + if (_o["code"].get_str().find_first_of("0x") != 0) thisTxCode = compileLLL(_o["code"].get_str()); else thisTxCode = fromHex(_o["code"].get_str().substr(2)); @@ -518,10 +518,16 @@ void doTests(json_spirit::mValue& v, bool _fillin) auto argv = boost::unit_test::framework::master_test_suite().argv; auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; + auto showTimes = false; + for (auto i = 0; i < argc; ++i) + showTimes |= std::string(argv[i]) == "--show-times"; + auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; auto vm = VMFace::create(vmKind, fev.gas); bytes output; auto outOfGas = false; + + auto startTime = std::chrono::high_resolution_clock::now(); try { output = vm->go(fev).toVector(); @@ -538,6 +544,16 @@ void doTests(json_spirit::mValue& v, bool _fillin) { cnote << "VM did throw an exception: " << _e.what(); } + + auto endTime = std::chrono::high_resolution_clock::now(); + if (showTimes) + { + auto testDuration = endTime - startTime; + cnote << "Execution time: " + << std::chrono::duration_cast(testDuration).count() + << " ms"; + } + auto gas = vm->gas(); // delete null entries in storage for the sake of comparison @@ -760,8 +776,14 @@ BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) dev::test::executeTests("vmPushDupSwapTest"); } +BOOST_AUTO_TEST_CASE(vmPerformanceTest) +{ + dev::test::executeTests("vmPerformanceTest"); +} + BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) { dev::test::executeTests("vmSystemOperationsTest"); } + From 4c7fddd3e81fe5ca7adc9643d5dec7fa038a721d Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 11:03:41 +0000 Subject: [PATCH 258/396] added dependency on libethereum to evmcc --- evmcc/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index ae9162162..52ce6ec38 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ethcore) +target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmjit) From 0432706b2fa1391bf4bac7f3aeff0e6a93a52d90 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 11:05:01 +0000 Subject: [PATCH 259/396] added inlcude of setjmp.h required for jmp_buf type --- libevmjit/Runtime.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 418652c40..e71b646cf 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,6 +1,8 @@ #pragma once + +#include #include #include From a34259ec66d0bdb7a5707e8c592c8369cf83aab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 12:14:05 +0100 Subject: [PATCH 260/396] Fix bad .filters file --- windows/LibEthereum.vcxproj.filters | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index d34e63e27..d96ee47a5 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -195,6 +195,7 @@ libevm + libdevcrypto From be6a02a446c7652751df4c8369261d46d4af7757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 12:14:24 +0100 Subject: [PATCH 261/396] Use clog for JIT logs --- libevmjit/Compiler.cpp | 4 ++-- libevmjit/ExecutionEngine.cpp | 23 +++++++++++------------ libevmjit/Utils.h | 3 +++ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 02c8db715..2ee776387 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -153,8 +153,8 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) } else { - std::cerr << "Bad JUMP at PC " << it->first - << ": " << it->second << " is not a valid PC\n"; + clog(JIT) << "Bad JUMP at PC " << it->first + << ": " << it->second << " is not a valid PC"; m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); } } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index efa039f2b..c6e623d0e 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -75,9 +75,8 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV auto finalizationStartTime = std::chrono::high_resolution_clock::now(); exec->finalizeObject(); auto finalizationEndTime = std::chrono::high_resolution_clock::now(); - std::cerr << "*** Module finalization time: " - << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count() - << std::endl; + clog(JIT) << "Module finalization time: " + << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); // Create fake ExtVM interface if (!_ext) @@ -117,9 +116,8 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV returnCode = static_cast(result.IntVal.getZExtValue()); auto executionEndTime = std::chrono::high_resolution_clock::now(); - std::cerr << "*** Execution time: " - << std::chrono::duration_cast(executionEndTime - executionStartTime).count() - << std::endl; + clog(JIT) << "Execution time : " + << std::chrono::duration_cast(executionEndTime - executionStartTime).count(); } else @@ -128,19 +126,20 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV // Return remaining gas _gas = returnCode == ReturnCode::OutOfGas ? 0 : runtime.getGas(); - std::cout << "Max stack size: " << Stack::maxStackSize << std::endl; + clog(JIT) << "Max stack size: " << Stack::maxStackSize; if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface - std::cout << "RETURN [ "; + auto&& log = clog(JIT); + log << "RETURN [ "; for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) - std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; - std::cout << "]\n"; + log << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; + log << "]"; } - - std::cout << "RETURN CODE: " << (int)returnCode << std::endl; + else + cslog(JIT) << "RETURN " << (int)returnCode; return static_cast(returnCode); } diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 1b146b3d2..7a3afda64 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -4,6 +4,7 @@ #include #include +#include namespace dev { @@ -12,6 +13,8 @@ namespace eth namespace jit { +struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; + /// Representation of 256-bit value binary compatible with LLVM i256 // TODO: Replace with h256 struct i256 From 9a82a78b889eb38395f60abf06a44134682fdfcc Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 11:52:11 +0000 Subject: [PATCH 262/396] json test file for performance testing --- evmcc/test/vmtests/vmPerformanceTest.json | 169 ++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 evmcc/test/vmtests/vmPerformanceTest.json diff --git a/evmcc/test/vmtests/vmPerformanceTest.json b/evmcc/test/vmtests/vmPerformanceTest.json new file mode 100644 index 000000000..1bcc2ec15 --- /dev/null +++ b/evmcc/test/vmtests/vmPerformanceTest.json @@ -0,0 +1,169 @@ +{ + "for100000" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620186a06080545d60006080530b0f60295960a0536080530160a0546001608053036080546008585d", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "7799983", + "out" : "0x0", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a06080545d60006080530b0f60295960a0536080530160a0546001608053036080546008585d", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a06080545d60006080530b0f60295960a0536080530160a0546001608053036080546008585d", + "nonce" : "0", + "storage" : { } + } + } + }, + + "recloop" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x600c6204000060006015585d60005460206000f25d6000820e602e59602a60018303600183016015585d6030585d805d905090509058", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "4232808", + "out" : "0x0000000000000000000000000000000000000000000000000000000000040000", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600c6204000060006015585d60005460206000f25d6000820e602e59602a60018303600183016015585d6030585d805d905090509058", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600c6204000060006015585d60005460206000f25d6000820e602e59602a60018303600183016015585d6030585d805d905090509058", + "nonce" : "0", + "storage" : { } + } + } + }, + + "fib25" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x600860196011585d60005460206000f25d6003810a6031596022600282036011585d602c600183036011585d016034585d60015d90509058", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "7374139", + "out" : "0x0000000000000000000000000000000000000000000000000000000000012511", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600860196011585d60005460206000f25d6003810a6031596022600282036011585d602c600183036011585d016034585d60015d90509058", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600860196011585d60005460206000f25d6003810a6031596022600282036011585d602c600183036011585d016034585d60015d90509058", + "nonce" : "0", + "storage" : { + } + } + } + }, + + "ackermann36" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x600a600360066013585d60005460206000f25d6000820e604b596000810e603a59603660018303603284600185036013585d6013585d6047585d60466001830360016013585d5d6050585d600181015d905090509058", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "5865402", + "out" : "0x00000000000000000000000000000000000000000000000000000000000001fd", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a600360066013585d60005460206000f25d6000820e604b596000810e603a59603660018303603284600185036013585d6013585d6047585d60466001830360016013585d5d6050585d600181015d905090509058", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a600360066013585d60005460206000f25d6000820e604b596000810e603a59603660018303603284600185036013585d6013585d6047585d60466001830360016013585d5d6050585d600181015d905090509058", + "nonce" : "0", + "storage" : { + } + } + } + }, +} From 865cfe4a72a497065ad0cb37f4c16e3224300986 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 11:54:02 +0000 Subject: [PATCH 263/396] turned on stack optimization by default in jit compiler --- libevmjit/Compiler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 99172fbe9..0ba31db95 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -242,8 +242,8 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) dump(); } - if (getenv("EVMCC_OPTIMIZE_STACK")) - { + //if (getenv("EVMCC_OPTIMIZE_STACK")) + //{ std::vector blockList; for (auto& entry : basicBlocks) blockList.push_back(&entry.second); @@ -261,7 +261,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) std::cerr << "\n\nAfter stack optimization \n\n"; dump(); } - } + //} for (auto& entry : basicBlocks) entry.second.localStack().synchronize(stack); From b009ad1b88688b427220891b9cec7db36fa4619b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 14:29:21 +0100 Subject: [PATCH 264/396] Fix emcc Visual Studio project for Release configuration --- windows/evmcc.vcxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index a93635e6b..1448bb5a8 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -171,7 +171,6 @@ true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true - ../../llvm-3.5.0/include;../../builds/llvm3.5/include;%(AdditionalIncludeDirectories) 4068;4244;4267;4800 false @@ -180,7 +179,6 @@ true true true - LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) From 68829e87b946f969dc6bbdaa90aac0ef94b6b07c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 14:53:09 +0100 Subject: [PATCH 265/396] Remove done FIXME tasks --- libevmjit/Ext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 0da9c8809..f7b10cfa2 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -274,7 +274,7 @@ EXPORT void ext_exp(Runtime* _rt, i256* _left, i256* _right, i256* _ret) *_ret = eth2llvm(ret); } -EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) //FIXME: Check endianess +EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) { auto&& ext = _rt->getExt(); auto addr = right160(*_addr256); @@ -282,7 +282,7 @@ EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) //FIXME: Check en return const_cast(code.data()); } -EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret) //FIXME: Check endianess +EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret) { auto&& ext = _rt->getExt(); auto addr = right160(*_addr256); From 16868c7222759e77989455c58345ab3702e659be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:19:13 +0100 Subject: [PATCH 266/396] Improve Stack code formatting --- libevmjit/Stack.cpp | 86 +++++++++++++++++++++------------------------ libevmjit/Stack.h | 2 -- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 144cd5d54..d6538a22d 100644 --- a/libevmjit/Stack.cpp +++ b/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(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(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(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(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(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(ReturnCode::StackTooSmall)); + + *(stack.rbegin() + _index) = *_word; + } } // extern "C" diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index db9032ec4..3e8881e4f 100644 --- a/libevmjit/Stack.h +++ b/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); From de76284186a457e0b7baeb39cd164b3c0827e322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:19:32 +0100 Subject: [PATCH 267/396] Change #include setjmp --- libevmjit/Runtime.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index e71b646cf..8c784b394 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,9 +1,8 @@ #pragma once - -#include #include +#include #include From 57c6eb8ba3ea0a722d471136887b1781bde0048c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:21:21 +0100 Subject: [PATCH 268/396] Improve Arith256 code formatting --- libevmjit/Arith256.cpp | 104 ++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index caf7bf3d0..61b0ba35e 100644 --- a/libevmjit/Arith256.cpp +++ b/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)); + } } From 31ccf59bd086047893bfb1ded8e50253784dc74e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:38:18 +0100 Subject: [PATCH 269/396] Improve code formatting --- libevmjit/BasicBlock.h | 2 +- libevmjit/Ext.h | 2 +- libevmjit/Memory.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 65044eb2a..ffa9ca109 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -14,7 +14,7 @@ namespace jit { using ProgramCounter = uint64_t; // TODO: Rename - + class BasicBlock { public: diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index fe62f43c6..8e70af7d0 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -54,7 +54,7 @@ private: llvm::Function* m_codeAt; llvm::Function* m_codesizeAt; }; - + } } diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index d8c1e4b72..f315b9295 100644 --- a/libevmjit/Memory.h +++ b/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); From 3216898b49cc6919f2ad98cf95a07372bfacbd0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:39:28 +0100 Subject: [PATCH 270/396] Improve Memory code formatting --- libevmjit/Memory.cpp | 72 +++++++++++++++++++++---------------------- libevmjit/Runtime.cpp | 4 +-- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index b7b3d8497..63e97efc6 100644 --- a/libevmjit/Memory.cpp +++ b/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(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 @@ -103,7 +103,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 +175,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 +218,38 @@ 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(); - - //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; + using namespace dev::eth::jit; - //_begin = _begin / 16 * 16; - //for (size_t i = _begin; i < _end; i++) - //{ - // if ((i - _begin) % 16 == 0) - // std::cerr << '\n' << std::dec << i << ": "; + 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(); + } - // auto b = Runtime::getMemory()[i]; - // std::cerr << std::hex << std::setw(2) << static_cast(b) << ' '; - //} - //std::cerr << std::endl; -} + 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 + // << 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(b) << ' '; + //} + //std::cerr << std::endl; + } -} // extern "C" +} // extern "C" diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 3efd78a26..361089ba1 100644 --- a/libevmjit/Runtime.cpp +++ b/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"); } From 3e948d963b73686657841ea3c4a4f23e7a9555ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:41:00 +0100 Subject: [PATCH 271/396] Improve BasicBlock code formatting --- libevmjit/BasicBlock.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 1756971be..a35462cbe 100644 --- a/libevmjit/BasicBlock.cpp +++ b/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 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"); From 1f6d12a55c73fbacadc657d12a73b25e8e1cb6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:42:04 +0100 Subject: [PATCH 272/396] Improve ExecutionEngine code formatting --- libevmjit/ExecutionEngine.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index c6e623d0e..c8ab85150 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -64,19 +64,19 @@ int ExecutionEngine::run(std::unique_ptr _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(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(finalizationEndTime - finalizationStartTime).count(); + << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); // Create fake ExtVM interface if (!_ext) @@ -117,7 +117,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV auto executionEndTime = std::chrono::high_resolution_clock::now(); clog(JIT) << "Execution time : " - << std::chrono::duration_cast(executionEndTime - executionStartTime).count(); + << std::chrono::duration_cast(executionEndTime - executionStartTime).count(); } else From 715c60000d48d2b0f74765002ab9bc43f342f66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:42:22 +0100 Subject: [PATCH 273/396] Improve GasMeter code formatting --- libevmjit/GasMeter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 149944f28..82b587dd8 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -31,7 +31,7 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure return 0; case Instruction::SSTORE: - return static_cast(c_sstoreResetGas); // FIXME: Check store gas + return static_cast(c_sstoreResetGas); // FIXME: Check store gas case Instruction::SLOAD: return static_cast(c_sloadGas); @@ -87,7 +87,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,7 +117,7 @@ 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); @@ -129,7 +129,7 @@ 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(c_sstoreResetGas); // FIXME: Check store gas + static const auto sstoreCost = static_cast(c_sstoreResetGas); // FIXME: Check store gas // [ADD] if oldValue == 0 and newValue != 0 => 2*cost // [DEL] if oldValue != 0 and newValue == 0 => 0 From d9ce724f55155c1be5b156b893c7f1d30a4e517d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:43:02 +0100 Subject: [PATCH 274/396] Improve Ext code formatting --- libevmjit/Ext.cpp | 198 +++++++++++++++++++++++----------------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index f7b10cfa2..ef2681803 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -24,7 +24,7 @@ inline u256 fromAddress(Address _a) return (u160)_a; } -struct ExtData +struct ExtData { const byte* calldata; const byte* code; @@ -172,123 +172,123 @@ 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_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_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_calldataload(Runtime* _rt, i256* _index, i256* _value) -{ - auto index = static_cast(llvm2eth(*_index)); - assert(index + 31 > index); // TODO: Handle large index - auto b = reinterpret_cast(_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_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_balance(Runtime* _rt, h256* _address, i256* _value) -{ - auto u = _rt->getExt().balance(right160(*_address)); - *_value = eth2llvm(u); -} + EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value) + { + auto index = static_cast(llvm2eth(*_index)); + assert(index + 31 > index); // TODO: Handle large index + auto b = reinterpret_cast(_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_suicide(Runtime* _rt, h256* _address) -{ - _rt->getExt().suicide(right160(*_address)); -} + EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* _value) + { + auto u = _rt->getExt().balance(right160(*_address)); + *_value = eth2llvm(u); + } -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_suicide(Runtime* _rt, h256* _address) + { + _rt->getExt().suicide(right160(*_address)); + } - if (ext.balance(ext.myAddress) >= endowment) + EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) { - ext.subBalance(endowment); - u256 gas; // TODO: Handle gas - auto initOff = static_cast(llvm2eth(*_initOff)); - auto initSize = static_cast(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; + 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(llvm2eth(*_initOff)); + auto initSize = static_cast(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 = {}; } - 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); + 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(llvm2eth(*_inOff)); + auto inSize = static_cast(llvm2eth(*_inSize)); + auto outOff = static_cast(llvm2eth(*_outOff)); + auto outSize = static_cast(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; + } - auto ret = false; - auto gas = llvm2eth(*_gas); - if (ext.balance(ext.myAddress) >= value) + EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret) { - ext.subBalance(value); - auto receiveAddress = right160(*_receiveAddress); auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); - auto outOff = static_cast(llvm2eth(*_outOff)); - auto outSize = static_cast(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(&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(llvm2eth(*_inOff)); - auto inSize = static_cast(llvm2eth(*_inSize)); - auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); - auto hash = sha3(dataRef); - *_ret = *reinterpret_cast(&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(boost::multiprecision::powm(left, right, bigint(2) << 256)); - *_ret = eth2llvm(ret); -} + EXPORT void ext_exp(Runtime* _rt, i256* _left, i256* _right, i256* _ret) + { + bigint left = llvm2eth(*_left); + bigint right = llvm2eth(*_right); + auto ret = static_cast(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(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(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())); + } } } From fd351c84fbc3f95005fa135108e888f55fa0f287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:43:38 +0100 Subject: [PATCH 275/396] Improve VM code formatting --- libevmjit/VM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 0907682d2..c0a8c8605 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -28,13 +28,13 @@ 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()); } 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 } } From 91dd7122c2b9fd4ddc04c3bf57f4acf966f793d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 16:45:35 +0100 Subject: [PATCH 276/396] Improve Compiler code formatting --- libevmjit/Compiler.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index bed0aaaab..8dc19e84c 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -46,7 +46,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) std::vector 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 +120,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 +128,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; @@ -173,7 +173,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto module = std::make_unique("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 +217,8 @@ std::unique_ptr 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; @@ -523,9 +523,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ANY_PUSH: { - auto numBytes = static_cast(inst)-static_cast(Instruction::PUSH1) + 1; + auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; auto value = llvm::APInt(256, 0); - for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator + for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator { ++currentPC; value <<= 8; @@ -538,14 +538,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ANY_DUP: { - auto index = static_cast(inst)-static_cast(Instruction::DUP1); + auto index = static_cast(inst) - static_cast(Instruction::DUP1); stack.dup(index); break; } case Instruction::ANY_SWAP: { - auto index = static_cast(inst)-static_cast(Instruction::SWAP1) + 1; + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; stack.swap(index); break; } @@ -721,7 +721,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 +826,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 +870,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 blocks; for (auto& pair : basicBlocks) @@ -903,10 +903,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"; } } From 76719fb4f49a3a50f09c586990b189e988a67553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 20:03:32 +0100 Subject: [PATCH 277/396] Update astyle options: - "delete-empty-lines" removed as it removes single empty lines also - "keep-one-line-blocks" added to keep one-line inline methods implementations - "close-templates" added - places template angle bracket together --- astylerc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astylerc b/astylerc index 0b407b9fe..d4e1188eb 100644 --- a/astylerc +++ b/astylerc @@ -6,6 +6,6 @@ min-conditional-indent=1 pad-oper pad-header unpad-paren -delete-empty-lines align-pointer=type - +keep-one-line-blocks +close-templates From decf4105159a29597a99e4e3d8cb7c08c9390448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 20:49:28 +0100 Subject: [PATCH 278/396] Update gas counting for SSTORE, no refunding yet [#81575908] --- libevmjit/GasMeter.cpp | 21 ++++++++------------- libevmjit/Type.h | 2 +- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 82b587dd8..d3f6c10f3 100644 --- a/libevmjit/GasMeter.cpp +++ b/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(c_sstoreResetGas); // FIXME: Check store gas - case Instruction::SLOAD: return static_cast(c_sloadGas); @@ -118,8 +116,7 @@ void GasMeter::count(Instruction _inst) 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,18 @@ 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(c_sstoreResetGas); // FIXME: Check store gas - - // [ADD] if oldValue == 0 and newValue != 0 => 2*cost - // [DEL] if oldValue != 0 and newValue == 0 => 0 + static const auto updateCost = static_cast(c_sstoreResetGas); // TODO: Discuss naming (DB names look better) + static const auto insertCost = static_cast(c_sstoreSetGas); 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(insertCost), Constant::get(updateCost), "cost"); + cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); createCall(m_gasCheckFunc, cost); } diff --git a/libevmjit/Type.h b/libevmjit/Type.h index b432f0813..21c41efc0 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -50,7 +50,7 @@ enum class ReturnCode struct Constant { /// Returns word-size constant - static llvm::ConstantInt* get(uint64_t _n); + static llvm::ConstantInt* get(uint64_t _n); // TODO: add overload with u256 static llvm::ConstantInt* get(ReturnCode _returnCode); }; From 56bd2c3411d5e94df0fd03e840cca38f8373b2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 21:23:16 +0100 Subject: [PATCH 279/396] Allow creating LLVM constants directly from u256 --- libevmjit/GasMeter.cpp | 5 +---- libevmjit/Type.cpp | 8 ++++++++ libevmjit/Type.h | 4 +++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index d3f6c10f3..5f6f81e72 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -126,9 +126,6 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu { assert(!m_checkCall); // Everything should've been commited before - static const auto updateCost = static_cast(c_sstoreResetGas); // TODO: Discuss naming (DB names look better) - static const auto insertCost = static_cast(c_sstoreSetGas); - 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"); @@ -136,7 +133,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); - auto cost = m_builder.CreateSelect(isInsert, Constant::get(insertCost), Constant::get(updateCost), "cost"); + 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); } diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 5021473ff..33d571087 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -41,6 +41,14 @@ llvm::ConstantInt* Constant::get(uint64_t _n) return llvm::ConstantInt::get(Type::i256, _n); } +llvm::ConstantInt* Constant::get(u256 _n) +{ + auto limbs = _n.backend().limbs(); + auto words = reinterpret_cast(limbs); + llvm::APInt n(256, 4, words); + return static_cast(llvm::ConstantInt::get(Type::i256, n)); +} + llvm::ConstantInt* Constant::get(ReturnCode _returnCode) { return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 21c41efc0..c80e46777 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -3,6 +3,7 @@ #include #include +#include namespace dev { @@ -50,7 +51,8 @@ enum class ReturnCode struct Constant { /// Returns word-size constant - static llvm::ConstantInt* get(uint64_t _n); // TODO: add overload with u256 + static llvm::ConstantInt* get(uint64_t _n); + static llvm::ConstantInt* get(u256 _n); static llvm::ConstantInt* get(ReturnCode _returnCode); }; From 3f50913d95752663e5289672f6d6b06697b96bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Oct 2014 21:56:12 +0100 Subject: [PATCH 280/396] Fix u256 to APInt conversion --- libevmjit/Type.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 33d571087..447da6a4b 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -43,9 +43,11 @@ llvm::ConstantInt* Constant::get(uint64_t _n) llvm::ConstantInt* Constant::get(u256 _n) { - auto limbs = _n.backend().limbs(); - auto words = reinterpret_cast(limbs); - llvm::APInt n(256, 4, words); + auto& backend = _n.backend(); + auto words = reinterpret_cast(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::get(Type::i256, n)); } From 236361044cadda0ecda7edd5445c386415b047a5 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 22:13:25 +0000 Subject: [PATCH 281/396] Got rid of some gcc warnings --- libevmjit/Ext.cpp | 7 +++---- libevmjit/Memory.cpp | 26 +------------------------- libevmjit/VM.cpp | 2 ++ 3 files changed, 6 insertions(+), 29 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index ef2681803..9484d9b26 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -31,14 +31,13 @@ struct ExtData }; 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"); @@ -266,7 +265,7 @@ extern "C" *_ret = *reinterpret_cast(&hash); } - EXPORT void ext_exp(Runtime* _rt, i256* _left, i256* _right, i256* _ret) + EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* _ret) { bigint left = llvm2eth(*_left); bigint right = llvm2eth(*_right); diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 63e97efc6..86c6e8e07 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -89,7 +89,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; @@ -228,28 +228,4 @@ extern "C" 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 - // << 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(b) << ' '; - //} - //std::cerr << std::endl; - } - } // extern "C" diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index c0a8c8605..b42b09499 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -31,6 +31,8 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) BOOST_THROW_EXCEPTION(StackTooSmall(1, 0)); case ReturnCode::BadInstruction: BOOST_THROW_EXCEPTION(BadInstruction()); + default: + break; } m_output = std::move(engine.returnData); From 4f5959ed641a1736c07b493f3a243ba63e5c598c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 10:39:45 +0100 Subject: [PATCH 282/396] Remove old code --- libevmjit/Ext.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index ef2681803..bee65c564 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -24,12 +24,6 @@ inline u256 fromAddress(Address _a) return (u160)_a; } -struct ExtData -{ - const byte* calldata; - const byte* code; -}; - Ext::Ext(RuntimeManager& _runtimeManager): RuntimeHelper(_runtimeManager) { From e3ccbf8d49f358ec86e6b1c702d8810907ad08b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 11:12:18 +0100 Subject: [PATCH 283/396] Increase refund counter if deleting a storage item [Delivers #81575908] --- evmcc/test/ext/store_delete.evm | 1 + evmcc/test/ext/store_delete.lll | 9 +++++++++ libevmjit/Ext.cpp | 8 +++++++- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 evmcc/test/ext/store_delete.evm create mode 100644 evmcc/test/ext/store_delete.lll diff --git a/evmcc/test/ext/store_delete.evm b/evmcc/test/ext/store_delete.evm new file mode 100644 index 000000000..d6acae03d --- /dev/null +++ b/evmcc/test/ext/store_delete.evm @@ -0,0 +1 @@ +6104d26063576000606357 diff --git a/evmcc/test/ext/store_delete.lll b/evmcc/test/ext/store_delete.lll new file mode 100644 index 000000000..3d8f0f23a --- /dev/null +++ b/evmcc/test/ext/store_delete.lll @@ -0,0 +1,9 @@ + +(asm +1234 +99 +SSTORE +0 +99 +SSTORE +) \ No newline at end of file diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index bee65c564..09b350763 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "Runtime.h" #include "Type.h" @@ -179,7 +180,12 @@ extern "C" { auto index = llvm2eth(*_index); auto value = llvm2eth(*_value); - _rt->getExt().setStore(index, value); // Interface uses native endianness + auto& ext = _rt->getExt(); + + if (value == 0 && ext.store(index) != 0) // If delete + ext.sub.refunds += c_sstoreRefundGas; // Increase refund counter + + ext.setStore(index, value); // Interface uses native endianness } EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value) From 8cfe2ee454334876926b30ca53b34c27e49cf056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 11:44:31 +0100 Subject: [PATCH 284/396] BNOT instruction [Delivers #81700198] --- evmcc/test/arith/arith_bnot.evm | 1 + evmcc/test/arith/arith_bnot.lll | 14 ++++++++++++++ libevmjit/Compiler.cpp | 11 ++++------- 3 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 evmcc/test/arith/arith_bnot.evm create mode 100644 evmcc/test/arith/arith_bnot.lll diff --git a/evmcc/test/arith/arith_bnot.evm b/evmcc/test/arith/arith_bnot.evm new file mode 100644 index 000000000..4cfaf8f55 --- /dev/null +++ b/evmcc/test/arith/arith_bnot.evm @@ -0,0 +1 @@ +6201e2406000546000530960005460206000f2 diff --git a/evmcc/test/arith/arith_bnot.lll b/evmcc/test/arith/arith_bnot.lll new file mode 100644 index 000000000..a83b05a9a --- /dev/null +++ b/evmcc/test/arith/arith_bnot.lll @@ -0,0 +1,14 @@ + +(asm +123456 +0 +MSTORE +0 +MLOAD +BNOT +0 +MSTORE +32 +0 +RETURN +) \ No newline at end of file diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 8dc19e84c..6b8f094e3 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -372,14 +372,11 @@ 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); - break; - }*/ + auto value = stack.pop(); + auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot"); + } case Instruction::LT: { From 4c27c26af9ab1cdcb1009af9e27a59136a18b9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 12:22:59 +0100 Subject: [PATCH 285/396] Fix BNOT instruction [Delivers #81700198] --- libevmjit/Compiler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 6b8f094e3..ab0f7efe7 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -376,6 +376,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto value = stack.pop(); auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot"); + stack.push(ret); + break; } case Instruction::LT: From f8feca9dfc9dbd1966cf3d258c01f71a24590843 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 12:56:52 +0000 Subject: [PATCH 286/396] SIGEXTEND: first try [#81700414] --- libevmjit/Compiler.cpp | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 8dc19e84c..ea74d1051 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -372,14 +372,14 @@ 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); + auto allones = llvm::ConstantInt::get(Type::i256, llvm::APInt::getAllOnesValue(256)); + auto res = m_builder.CreateXor(top, allones); stack.push(res); break; - }*/ + } case Instruction::LT: { @@ -505,6 +505,35 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, break; } + case Instruction::SIGNEXTEND: + { + auto k = stack.pop(); + auto b = stack.pop(); + auto k32 = m_builder.CreateTrunc(k, m_builder.getIntNTy(5), "k_32"); + auto k32ext = m_builder.CreateZExt(k32, Type::i256); + auto k32x8 = m_builder.CreateMul(k32ext, Constant::get(8), "kx8"); + + // test for b >> (k * 8 + 7) + auto val = m_builder.CreateAdd(k32x8, llvm::ConstantInt::get(Type::i256, 7)); + auto tmp = m_builder.CreateAShr(b, val); + auto bitset = m_builder.CreateTrunc(tmp, m_builder.getInt1Ty()); + + // shift left by (31 - k) * 8 = (248 - k*8), then do arithmetic shr by the same amount. + auto shiftSize = m_builder.CreateSub(llvm::ConstantInt::get(Type::i256, 31 * 8), k32x8); + auto bshl = m_builder.CreateShl(b, shiftSize); + auto bshr = m_builder.CreateAShr(bshl, shiftSize); + + // bshr is our final value if 0 <= k <= 30 and bitset is true, + // otherwise we push back b unchanged + auto kInRange = m_builder.CreateICmpULE(k, llvm::ConstantInt::get(Type::i256, 30)); + auto cond = m_builder.CreateAnd(kInRange, bitset); + + auto result = m_builder.CreateSelect(cond, bshr, b); + stack.push(result); + + break; + } + case Instruction::SHA3: { auto inOff = stack.pop(); From c32e1e05b3e1c6a4535909650c8bc6a32388ba2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 15:50:44 +0100 Subject: [PATCH 287/396] Fix case where JUMPI is the last instruction --- evmcc/test/jump/jumpi_at_the_end.evm | 1 + evmcc/test/jump/jumpi_at_the_end.lll | 1 + evmcc/test/vmtests/vm_jump.json | 41 ++++++++++++++++++++++++++++ libevmjit/Compiler.cpp | 11 ++------ 4 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 evmcc/test/jump/jumpi_at_the_end.evm create mode 100644 evmcc/test/jump/jumpi_at_the_end.lll create mode 100644 evmcc/test/vmtests/vm_jump.json diff --git a/evmcc/test/jump/jumpi_at_the_end.evm b/evmcc/test/jump/jumpi_at_the_end.evm new file mode 100644 index 000000000..2d7411761 --- /dev/null +++ b/evmcc/test/jump/jumpi_at_the_end.evm @@ -0,0 +1 @@ +600a6000545d6000536001900380600054600659 diff --git a/evmcc/test/jump/jumpi_at_the_end.lll b/evmcc/test/jump/jumpi_at_the_end.lll new file mode 100644 index 000000000..263ada6a7 --- /dev/null +++ b/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) \ No newline at end of file diff --git a/evmcc/test/vmtests/vm_jump.json b/evmcc/test/vmtests/vm_jump.json new file mode 100644 index 000000000..6b63edeae --- /dev/null +++ b/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" : {} + } + } + } +} diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index ab0f7efe7..593820b8c 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -609,9 +609,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) @@ -624,9 +622,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, m_builder.CreateBr(targetBlock); } else - { m_builder.CreateBr(m_jumpTableBlock->llvm()); - } } else // JUMPI { @@ -635,8 +631,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) { @@ -644,9 +641,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); } else - { m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); - } } break; From c11867553240f36245f88067dcaafc12063905bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 16:29:14 +0100 Subject: [PATCH 288/396] Improve PUSH compilation --- libevmjit/Compiler.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 939c4a275..c104ec092 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -552,16 +552,15 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ANY_PUSH: { - auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; + const auto numBytes = static_cast(inst) - static_cast(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; } From 1dc5bece058979a229cfccca3c45a3e468914897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 17:32:20 +0100 Subject: [PATCH 289/396] Fix MSIZE and memory resize step [Delivers #81777708] --- libevmjit/Memory.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 86c6e8e07..84aa105fe 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -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 From 250374180385fd36351d733c0363b073989be243 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:42:44 +0000 Subject: [PATCH 290/396] CMakeLists updated, should now build without LLVM when EVMJIT is not enabled [#81588646] --- CMakeLists.txt | 17 +++++++++++++---- eth/CMakeLists.txt | 2 +- evmcc/CMakeLists.txt | 7 ++----- exp/CMakeLists.txt | 2 +- libevmjit/CMakeLists.txt | 7 +++---- neth/CMakeLists.txt | 2 +- test/CMakeLists.txt | 9 ++++++--- 7 files changed, 27 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53fe2684b..4c1cf55c0 100644 --- a/CMakeLists.txt +++ b/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() diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index 274700ee7..d04cac504 100644 --- a/eth/CMakeLists.txt +++ b/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() diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index 52ce6ec38..230013aef 100644 --- a/evmcc/CMakeLists.txt +++ b/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) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index c671f240f..fce739007 100644 --- a/exp/CMakeLists.txt +++ b/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() diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index f461c16cf..cc63e72db 100644 --- a/libevmjit/CMakeLists.txt +++ b/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 diff --git a/neth/CMakeLists.txt b/neth/CMakeLists.txt index 184fc7104..d1b3fb441 100644 --- a/neth/CMakeLists.txt +++ b/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() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 16eb0f40e..17dda74d2 100644 --- a/test/CMakeLists.txt +++ b/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++") From feaa976c884644f00c4b865b1e725ea657d0d2ed Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:46:01 +0000 Subject: [PATCH 291/396] Cleaning up warnings and build dependencies [#81588646] --- evmcc/evmcc.cpp | 2 - libevm/VMFace.cpp | 3 +- libevmjit/Compiler.cpp | 12 +- libevmjit/Compiler.cpp.orig | 962 ++++++++++++++++++++++++++++++++++ libevmjit/ExecutionEngine.cpp | 7 +- windows/LLVM.props | 2 +- 6 files changed, 978 insertions(+), 10 deletions(-) create mode 100644 libevmjit/Compiler.cpp.orig diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 1e0b7e1cd..047fdf252 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -8,8 +8,6 @@ #include -#include - #include #include #include diff --git a/libevm/VMFace.cpp b/libevm/VMFace.cpp index 03f228ad0..3313ee926 100644 --- a/libevm/VMFace.cpp +++ b/libevm/VMFace.cpp @@ -25,9 +25,10 @@ using namespace dev::eth; std::unique_ptr VMFace::create(VMFace::Kind _kind, u256 _gas) { std::unique_ptr vm; -#if ETH_JIT +#if ETH_EVMJIT vm.reset(_kind == Kind::JIT ? static_cast(new jit::VM) : new VM); #else + (void) _kind; // suppress unused var warning vm.reset(new VM); #endif vm->reset(_gas); diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index d7a87b508..befb843e2 100644 --- a/libevmjit/Compiler.cpp +++ b/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()); } @@ -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("BadJumpBlock", m_mainFunc, m_builder); - m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc, m_builder); + m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); + m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { @@ -170,7 +172,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) std::unique_ptr Compiler::compile(bytesConstRef bytecode) { - auto module = std::make_unique("main", m_builder.getContext()); + auto module = std::unique_ptr(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 @@ -513,7 +515,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto k32 = m_builder.CreateZExt(k32_, Type::i256); auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8"); - // test for b >> (k * 8 + 7) + // 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"); diff --git a/libevmjit/Compiler.cpp.orig b/libevmjit/Compiler.cpp.orig new file mode 100644 index 000000000..a7d2b116c --- /dev/null +++ b/libevmjit/Compiler.cpp.orig @@ -0,0 +1,962 @@ + +#include "Compiler.h" + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "Type.h" +#include "Memory.h" +#include "Stack.h" +#include "Ext.h" +#include "GasMeter.h" +#include "Utils.h" +#include "Endianness.h" +#include "Arith256.h" +#include "Runtime.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Compiler::Compiler(): + m_builder(llvm::getGlobalContext()) +{ + Type::init(m_builder.getContext()); +} + +void Compiler::createBasicBlocks(bytesConstRef bytecode) +{ + std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end + + std::map directJumpTargets; + std::vector indirectJumpTargets; + boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); + + splitPoints.insert(0); // First basic block + validJumpTargets[0] = true; + + for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) + { + ProgramCounter currentPC = curr - bytecode.begin(); + validJumpTargets[currentPC] = true; + + auto inst = static_cast(*curr); + switch (inst) + { + + case Instruction::ANY_PUSH: + { + auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; + auto next = curr + numBytes + 1; + if (next >= bytecode.end()) + break; + + auto nextInst = static_cast(*next); + + if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) + { + // Compute target PC of the jump. + u256 val = 0; + for (auto iter = curr + 1; iter < next; ++iter) + { + val <<= 8; + val |= *iter; + } + + // Create a block for the JUMP target. + ProgramCounter targetPC = val < bytecode.size() ? val.convert_to() : bytecode.size(); + splitPoints.insert(targetPC); + + ProgramCounter jumpPC = (next - bytecode.begin()); + directJumpTargets[jumpPC] = targetPC; + } + + curr += numBytes; + break; + } + + case Instruction::JUMPDEST: + { + // A basic block starts at the next instruction. + if (currentPC + 1 < bytecode.size()) + { + splitPoints.insert(currentPC + 1); + indirectJumpTargets.push_back(currentPC + 1); + } + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::RETURN: + case Instruction::STOP: + case Instruction::SUICIDE: + { + // Create a basic block starting at the following instruction. + if (curr + 1 < bytecode.end()) + { + splitPoints.insert(currentPC + 1); + } + break; + } + + default: + break; + } + } + + // Remove split points generated from jumps out of code or into data. + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + if (*it > bytecode.size() || !validJumpTargets[*it]) + it = splitPoints.erase(it); + else + ++it; + } + + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + auto beginInstIdx = *it; + ++it; + auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size(); + basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); + } + + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc, m_builder); + m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc, m_builder); + + for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) + { + if (it->second >= bytecode.size()) + { + // Jumping out of code means STOP + m_directJumpTargets[it->first] = m_stopBB; + continue; + } + + auto blockIter = basicBlocks.find(it->second); + if (blockIter != basicBlocks.end()) + { + m_directJumpTargets[it->first] = blockIter->second.llvm(); + } + else + { + clog(JIT) << "Bad JUMP at PC " << it->first + << ": " << it->second << " is not a valid PC"; + m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); + } + } + + for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) + { + m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); + } +} + +std::unique_ptr Compiler::compile(bytesConstRef bytecode) +{ + auto module = std::make_unique("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 + 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"); + + // Create the basic blocks. + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + m_builder.SetInsertPoint(entryBlock); + + createBasicBlocks(bytecode); + + // Init runtime structures. + RuntimeManager runtimeManager(m_builder); + GasMeter gasMeter(m_builder, runtimeManager); + Memory memory(runtimeManager, gasMeter); + Ext ext(runtimeManager); + Stack stack(m_builder, runtimeManager); + Arith256 arith(m_builder); + + m_builder.CreateBr(basicBlocks.begin()->second); + + for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) + { + auto& basicBlock = basicBlockPairIt->second; + auto iterCopy = basicBlockPairIt; + ++iterCopy; + auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; + compileBasicBlock(basicBlock, bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + } + + // Code for special blocks: + // TODO: move to separate function. + // Note: Right now the codegen for special blocks depends only on createBasicBlock(), + // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). + m_builder.SetInsertPoint(m_stopBB); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + if (m_indirectJumpTargets.size() > 0) + { + auto dest = m_jumpTableBlock->localStack().pop(); + 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; + auto dest = Constant::get(bb->begin()); + switchInstr->addCase(dest, bb->llvm()); + } + } + else + { + m_builder.CreateBr(m_badJumpBlock->llvm()); + } + + removeDeadBlocks(); + + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + std::ofstream ofs("blocks-init.dot"); + dumpBasicBlockGraph(ofs); + ofs.close(); + std::cerr << "\n\nAfter dead block elimination \n\n"; + dump(); + } + + //if (getenv("EVMCC_OPTIMIZE_STACK")) + //{ + std::vector blockList; + for (auto& entry : basicBlocks) + blockList.push_back(&entry.second); + + if (m_jumpTableBlock != nullptr) + blockList.push_back(m_jumpTableBlock.get()); + + BasicBlock::linkLocalStacks(blockList, m_builder); + + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + std::ofstream ofs("blocks-opt.dot"); + dumpBasicBlockGraph(ofs); + ofs.close(); + std::cerr << "\n\nAfter stack optimization \n\n"; + dump(); + } + //} + + for (auto& entry : basicBlocks) + entry.second.localStack().synchronize(stack); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->localStack().synchronize(stack); + + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + std::ofstream ofs("blocks-sync.dot"); + dumpBasicBlockGraph(ofs); + ofs.close(); + std::cerr << "\n\nAfter stack synchronization \n\n"; + dump(); + } + + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); + + return module; +} + + +void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Arith256& arith, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) +{ + m_builder.SetInsertPoint(basicBlock.llvm()); + auto& stack = basicBlock.localStack(); + + for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) + { + auto inst = static_cast(bytecode[currentPC]); + + gasMeter.count(inst); + + switch (inst) + { + + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::MUL: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.mul(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::DIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.div(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SDIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.sdiv(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::MOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.mod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = arith.smod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::EXP: + { + auto left = stack.pop(); + auto right = stack.pop(); + auto ret = ext.exp(left, right); + stack.push(ret); + break; + } + + case Instruction::BNOT: + { +<<<<<<< HEAD + auto top = stack.pop(); + auto allones = llvm::ConstantInt::get(Type::i256, llvm::APInt::getAllOnesValue(256)); + auto res = m_builder.CreateXor(top, allones); + stack.push(res); +======= + auto value = stack.pop(); + auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot"); + stack.push(ret); +>>>>>>> cd8727a1e4786caaccf7fbbffd178edcc7aa3c35 + break; + } + + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpULT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpUGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSLT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpEQ(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::NOT: + { + auto top = stack.pop(); + auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); + auto result = m_builder.CreateZExt(iszero, Type::i256); + stack.push(result); + break; + } + + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::BYTE: + { + const auto byteNum = stack.pop(); + auto value = stack.pop(); + + // + value = Endianness::toBE(m_builder, value); + auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); + auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); + value = m_builder.CreateZExt(byte, Type::i256); + + auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); + value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); + stack.push(value); + + break; + } + + case Instruction::ADDMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = arith.addmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::MULMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = arith.mulmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::SIGNEXTEND: + { + auto k = stack.pop(); + auto b = stack.pop(); + auto k32 = m_builder.CreateTrunc(k, m_builder.getIntNTy(5), "k_32"); + auto k32ext = m_builder.CreateZExt(k32, Type::i256); + auto k32x8 = m_builder.CreateMul(k32ext, Constant::get(8), "kx8"); + + // test for b >> (k * 8 + 7) + auto val = m_builder.CreateAdd(k32x8, llvm::ConstantInt::get(Type::i256, 7)); + auto tmp = m_builder.CreateAShr(b, val); + auto bitset = m_builder.CreateTrunc(tmp, m_builder.getInt1Ty()); + + // shift left by (31 - k) * 8 = (248 - k*8), then do arithmetic shr by the same amount. + auto shiftSize = m_builder.CreateSub(llvm::ConstantInt::get(Type::i256, 31 * 8), k32x8); + auto bshl = m_builder.CreateShl(b, shiftSize); + auto bshr = m_builder.CreateAShr(bshl, shiftSize); + + // bshr is our final value if 0 <= k <= 30 and bitset is true, + // otherwise we push back b unchanged + auto kInRange = m_builder.CreateICmpULE(k, llvm::ConstantInt::get(Type::i256, 30)); + auto cond = m_builder.CreateAnd(kInRange, bitset); + + auto result = m_builder.CreateSelect(cond, bshr, b); + stack.push(result); + + break; + } + + case Instruction::SHA3: + { + auto inOff = stack.pop(); + auto inSize = stack.pop(); + memory.require(inOff, inSize); + auto hash = ext.sha3(inOff, inSize); + stack.push(hash); + break; + } + + case Instruction::POP: + { + stack.pop(); + break; + } + + case Instruction::ANY_PUSH: + { + auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; + auto value = llvm::APInt(256, 0); + for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator + { + ++currentPC; + value <<= 8; + value |= bytecode[currentPC]; + } + auto c = m_builder.getInt(value); + stack.push(c); + break; + } + + case Instruction::ANY_DUP: + { + auto index = static_cast(inst) - static_cast(Instruction::DUP1); + stack.dup(index); + break; + } + + case Instruction::ANY_SWAP: + { + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; + stack.swap(index); + break; + } + + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = memory.loadWord(addr); + stack.push(word); + break; + } + + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeWord(addr, word); + break; + } + + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + memory.storeByte(addr, word); + break; + } + + case Instruction::MSIZE: + { + auto word = memory.getSize(); + stack.push(word); + break; + } + + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = ext.store(index); + stack.push(value); + break; + } + + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + gasMeter.countSStore(ext, index, value); + ext.setStore(index, value); + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + { + // Generate direct jump iff: + // 1. this is not the first instruction in the block + // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) + // Otherwise generate a indirect jump (a switch). + llvm::BasicBlock* targetBlock = nullptr; + if (currentPC != basicBlock.begin()) + { + auto pairIter = m_directJumpTargets.find(currentPC); + if (pairIter != m_directJumpTargets.end()) + { + targetBlock = pairIter->second; + } + } + + if (inst == Instruction::JUMP) + { + if (targetBlock) + { + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + m_builder.CreateBr(targetBlock); + } + else + { + m_builder.CreateBr(m_jumpTableBlock->llvm()); + } + } + else // JUMPI + { + stack.swap(1); + auto val = stack.pop(); + 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 (targetBlock) + { + stack.pop(); + m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); + } + else + { + m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); + } + } + + break; + } + + case Instruction::JUMPDEST: + { + // Nothing to do + break; + } + + case Instruction::PC: + { + auto value = Constant::get(currentPC); + stack.push(value); + break; + } + + case Instruction::GAS: + case Instruction::ADDRESS: + case Instruction::CALLER: + case Instruction::ORIGIN: + case Instruction::CALLVALUE: + case Instruction::CALLDATASIZE: + case Instruction::CODESIZE: + case Instruction::GASPRICE: + case Instruction::PREVHASH: + case Instruction::COINBASE: + case Instruction::TIMESTAMP: + case Instruction::NUMBER: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + { + // Pushes an element of runtime data on stack + stack.push(_runtimeManager.get(inst)); + break; + } + + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = ext.balance(address); + stack.push(value); + break; + } + + case Instruction::EXTCODESIZE: + { + auto addr = stack.pop(); + auto value = ext.codesizeAt(addr); + stack.push(value); + break; + } + + case Instruction::CALLDATACOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCallData(); + auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); + + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CODECOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + 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); + break; + } + + case Instruction::EXTCODECOPY: + { + auto extAddr = stack.pop(); + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = ext.codeAt(extAddr); + auto srcSize = ext.codesizeAt(extAddr); + + memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = ext.calldataload(index); + stack.push(value); + break; + } + + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); + memory.require(initOff, initSize); + + auto address = ext.create(endowment, initOff, initSize); + stack.push(address); + break; + } + + case Instruction::CALL: + case Instruction::CALLCODE: + { + auto gas = stack.pop(); + auto codeAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + gasMeter.commitCostBlock(gas); + + // Require memory for the max of in and out buffers + auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); + auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); + auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); + auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); + memory.require(sizeReq); + + auto receiveAddress = codeAddress; + if (inst == Instruction::CALLCODE) + receiveAddress = _runtimeManager.get(RuntimeData::Address); + + auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + gasMeter.giveBack(gas); + stack.push(ret); + break; + } + + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); + + memory.require(index, size); + _runtimeManager.registerReturnData(index, size); + + m_builder.CreateRet(Constant::get(ReturnCode::Return)); + break; + } + + case Instruction::SUICIDE: + { + auto address = stack.pop(); + ext.suicide(address); + // Fall through + } + case Instruction::STOP: + { + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + break; + } + + default: // Invalid instruction - runtime exception + { + _runtimeManager.raiseException(ReturnCode::BadInstruction); + } + + } + } + + gasMeter.commitCostBlock(); + + if (!basicBlock.llvm()->getTerminator()) // If block not terminated + { + if (nextBasicBlock) + m_builder.CreateBr(nextBasicBlock); // Branch to the next block + else + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code + } +} + + + +void Compiler::removeDeadBlocks() +{ + // Remove dead basic blocks + auto sthErased = false; + do + { + sthErased = false; + for (auto it = basicBlocks.begin(); it != basicBlocks.end();) + { + auto llvmBB = it->second.llvm(); + if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) + { + llvmBB->eraseFromParent(); + basicBlocks.erase(it++); + sthErased = true; + } + else + ++it; + } + } + while (sthErased); + + // Remove jump table block if no predecessors + if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } +} + +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"; + + std::vector blocks; + for (auto& pair : basicBlocks) + blocks.push_back(&pair.second); + if (m_jumpTableBlock) + blocks.push_back(m_jumpTableBlock.get()); + if (m_badJumpBlock) + blocks.push_back(m_badJumpBlock.get()); + + // std::map phiNodesPerBlock; + + // Output nodes + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + std::ostringstream oss; + bb->dump(oss, true); + + out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; + } + + // Output edges + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + auto end = llvm::pred_end(bb->llvm()); + 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"; + } + } + + out << "}\n"; +} + +void Compiler::dump() +{ + for (auto& entry : basicBlocks) + entry.second.dump(); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->dump(); +} + +} +} +} + diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index c8ab85150..4c617d9ea 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,9 +1,11 @@ - #include "ExecutionEngine.h" #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + #include #include #include @@ -16,6 +18,9 @@ #include #include +#pragma GCC diagnostic pop + + #include #include "Runtime.h" diff --git a/windows/LLVM.props b/windows/LLVM.props index a5c6c4dc5..7a779144b 100644 --- a/windows/LLVM.props +++ b/windows/LLVM.props @@ -14,7 +14,7 @@ $(LLVMIncludeDir);%(AdditionalIncludeDirectories) 4800;%(DisableSpecificWarnings) - ETH_JIT=$(LLVMEnabled);%(PreprocessorDefinitions) + ETH_EVMJIT=$(LLVMEnabled);%(PreprocessorDefinitions) $(LLVMLibDir);%(AdditionalLibraryDirectories) From de7f0ac7b3e15418b34cc46163aa39b0219174fc Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:47:43 +0000 Subject: [PATCH 292/396] New performance tests [Delivers #81578852] --- evmcc/test/vmtests/vmPerformanceTest.json | 90 ++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/evmcc/test/vmtests/vmPerformanceTest.json b/evmcc/test/vmtests/vmPerformanceTest.json index 1bcc2ec15..07baa6709 100644 --- a/evmcc/test/vmtests/vmPerformanceTest.json +++ b/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" : { + } + } + } + }, + } From 46fc1a396ecddfe23f7082404b9bcb739b7e0868 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:51:04 +0000 Subject: [PATCH 293/396] removed accidentally added *.orig file --- libevmjit/Compiler.cpp.orig | 962 ------------------------------------ 1 file changed, 962 deletions(-) delete mode 100644 libevmjit/Compiler.cpp.orig diff --git a/libevmjit/Compiler.cpp.orig b/libevmjit/Compiler.cpp.orig deleted file mode 100644 index a7d2b116c..000000000 --- a/libevmjit/Compiler.cpp.orig +++ /dev/null @@ -1,962 +0,0 @@ - -#include "Compiler.h" - -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include "Type.h" -#include "Memory.h" -#include "Stack.h" -#include "Ext.h" -#include "GasMeter.h" -#include "Utils.h" -#include "Endianness.h" -#include "Arith256.h" -#include "Runtime.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Compiler::Compiler(): - m_builder(llvm::getGlobalContext()) -{ - Type::init(m_builder.getContext()); -} - -void Compiler::createBasicBlocks(bytesConstRef bytecode) -{ - std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end - - std::map directJumpTargets; - std::vector indirectJumpTargets; - boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); - - splitPoints.insert(0); // First basic block - validJumpTargets[0] = true; - - for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) - { - ProgramCounter currentPC = curr - bytecode.begin(); - validJumpTargets[currentPC] = true; - - auto inst = static_cast(*curr); - switch (inst) - { - - case Instruction::ANY_PUSH: - { - auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; - auto next = curr + numBytes + 1; - if (next >= bytecode.end()) - break; - - auto nextInst = static_cast(*next); - - if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) - { - // Compute target PC of the jump. - u256 val = 0; - for (auto iter = curr + 1; iter < next; ++iter) - { - val <<= 8; - val |= *iter; - } - - // Create a block for the JUMP target. - ProgramCounter targetPC = val < bytecode.size() ? val.convert_to() : bytecode.size(); - splitPoints.insert(targetPC); - - ProgramCounter jumpPC = (next - bytecode.begin()); - directJumpTargets[jumpPC] = targetPC; - } - - curr += numBytes; - break; - } - - case Instruction::JUMPDEST: - { - // A basic block starts at the next instruction. - if (currentPC + 1 < bytecode.size()) - { - splitPoints.insert(currentPC + 1); - indirectJumpTargets.push_back(currentPC + 1); - } - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - case Instruction::RETURN: - case Instruction::STOP: - case Instruction::SUICIDE: - { - // Create a basic block starting at the following instruction. - if (curr + 1 < bytecode.end()) - { - splitPoints.insert(currentPC + 1); - } - break; - } - - default: - break; - } - } - - // Remove split points generated from jumps out of code or into data. - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - if (*it > bytecode.size() || !validJumpTargets[*it]) - it = splitPoints.erase(it); - else - ++it; - } - - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - auto beginInstIdx = *it; - ++it; - auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size(); - basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); - } - - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc, m_builder); - m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc, m_builder); - - for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) - { - if (it->second >= bytecode.size()) - { - // Jumping out of code means STOP - m_directJumpTargets[it->first] = m_stopBB; - continue; - } - - auto blockIter = basicBlocks.find(it->second); - if (blockIter != basicBlocks.end()) - { - m_directJumpTargets[it->first] = blockIter->second.llvm(); - } - else - { - clog(JIT) << "Bad JUMP at PC " << it->first - << ": " << it->second << " is not a valid PC"; - m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); - } - } - - for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - { - m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); - } -} - -std::unique_ptr Compiler::compile(bytesConstRef bytecode) -{ - auto module = std::make_unique("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 - 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"); - - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); - m_builder.SetInsertPoint(entryBlock); - - createBasicBlocks(bytecode); - - // Init runtime structures. - RuntimeManager runtimeManager(m_builder); - GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(runtimeManager, gasMeter); - Ext ext(runtimeManager); - Stack stack(m_builder, runtimeManager); - Arith256 arith(m_builder); - - m_builder.CreateBr(basicBlocks.begin()->second); - - for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) - { - auto& basicBlock = basicBlockPairIt->second; - auto iterCopy = basicBlockPairIt; - ++iterCopy; - auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); - } - - // Code for special blocks: - // TODO: move to separate function. - // Note: Right now the codegen for special blocks depends only on createBasicBlock(), - // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). - m_builder.SetInsertPoint(m_stopBB); - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - - m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); - - m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - if (m_indirectJumpTargets.size() > 0) - { - auto dest = m_jumpTableBlock->localStack().pop(); - 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; - auto dest = Constant::get(bb->begin()); - switchInstr->addCase(dest, bb->llvm()); - } - } - else - { - m_builder.CreateBr(m_badJumpBlock->llvm()); - } - - removeDeadBlocks(); - - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-init.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter dead block elimination \n\n"; - dump(); - } - - //if (getenv("EVMCC_OPTIMIZE_STACK")) - //{ - std::vector blockList; - for (auto& entry : basicBlocks) - blockList.push_back(&entry.second); - - if (m_jumpTableBlock != nullptr) - blockList.push_back(m_jumpTableBlock.get()); - - BasicBlock::linkLocalStacks(blockList, m_builder); - - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-opt.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter stack optimization \n\n"; - dump(); - } - //} - - for (auto& entry : basicBlocks) - entry.second.localStack().synchronize(stack); - if (m_jumpTableBlock != nullptr) - m_jumpTableBlock->localStack().synchronize(stack); - - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-sync.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter stack synchronization \n\n"; - dump(); - } - - llvm::FunctionPassManager fpManager(module.get()); - fpManager.add(llvm::createLowerSwitchPass()); - fpManager.doInitialization(); - fpManager.run(*m_mainFunc); - - return module; -} - - -void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Arith256& arith, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) -{ - m_builder.SetInsertPoint(basicBlock.llvm()); - auto& stack = basicBlock.localStack(); - - for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) - { - auto inst = static_cast(bytecode[currentPC]); - - gasMeter.count(inst); - - switch (inst) - { - - case Instruction::ADD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateAdd(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::SUB: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateSub(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::MUL: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.mul(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::DIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.div(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SDIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.sdiv(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::MOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.mod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = arith.smod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::EXP: - { - auto left = stack.pop(); - auto right = stack.pop(); - auto ret = ext.exp(left, right); - stack.push(ret); - break; - } - - case Instruction::BNOT: - { -<<<<<<< HEAD - auto top = stack.pop(); - auto allones = llvm::ConstantInt::get(Type::i256, llvm::APInt::getAllOnesValue(256)); - auto res = m_builder.CreateXor(top, allones); - stack.push(res); -======= - auto value = stack.pop(); - auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot"); - stack.push(ret); ->>>>>>> cd8727a1e4786caaccf7fbbffd178edcc7aa3c35 - break; - } - - case Instruction::LT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpULT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::GT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpUGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::SLT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSLT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::SGT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::EQ: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpEQ(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::NOT: - { - auto top = stack.pop(); - auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); - auto result = m_builder.CreateZExt(iszero, Type::i256); - stack.push(result); - break; - } - - case Instruction::AND: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateAnd(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::OR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateOr(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::XOR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateXor(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::BYTE: - { - const auto byteNum = stack.pop(); - auto value = stack.pop(); - - // - value = Endianness::toBE(m_builder, value); - auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); - auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); - value = m_builder.CreateZExt(byte, Type::i256); - - auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); - value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); - stack.push(value); - - break; - } - - case Instruction::ADDMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = arith.addmod(lhs, rhs, mod); - stack.push(res); - break; - } - - case Instruction::MULMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = arith.mulmod(lhs, rhs, mod); - stack.push(res); - break; - } - - case Instruction::SIGNEXTEND: - { - auto k = stack.pop(); - auto b = stack.pop(); - auto k32 = m_builder.CreateTrunc(k, m_builder.getIntNTy(5), "k_32"); - auto k32ext = m_builder.CreateZExt(k32, Type::i256); - auto k32x8 = m_builder.CreateMul(k32ext, Constant::get(8), "kx8"); - - // test for b >> (k * 8 + 7) - auto val = m_builder.CreateAdd(k32x8, llvm::ConstantInt::get(Type::i256, 7)); - auto tmp = m_builder.CreateAShr(b, val); - auto bitset = m_builder.CreateTrunc(tmp, m_builder.getInt1Ty()); - - // shift left by (31 - k) * 8 = (248 - k*8), then do arithmetic shr by the same amount. - auto shiftSize = m_builder.CreateSub(llvm::ConstantInt::get(Type::i256, 31 * 8), k32x8); - auto bshl = m_builder.CreateShl(b, shiftSize); - auto bshr = m_builder.CreateAShr(bshl, shiftSize); - - // bshr is our final value if 0 <= k <= 30 and bitset is true, - // otherwise we push back b unchanged - auto kInRange = m_builder.CreateICmpULE(k, llvm::ConstantInt::get(Type::i256, 30)); - auto cond = m_builder.CreateAnd(kInRange, bitset); - - auto result = m_builder.CreateSelect(cond, bshr, b); - stack.push(result); - - break; - } - - case Instruction::SHA3: - { - auto inOff = stack.pop(); - auto inSize = stack.pop(); - memory.require(inOff, inSize); - auto hash = ext.sha3(inOff, inSize); - stack.push(hash); - break; - } - - case Instruction::POP: - { - stack.pop(); - break; - } - - case Instruction::ANY_PUSH: - { - auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; - auto value = llvm::APInt(256, 0); - for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator - { - ++currentPC; - value <<= 8; - value |= bytecode[currentPC]; - } - auto c = m_builder.getInt(value); - stack.push(c); - break; - } - - case Instruction::ANY_DUP: - { - auto index = static_cast(inst) - static_cast(Instruction::DUP1); - stack.dup(index); - break; - } - - case Instruction::ANY_SWAP: - { - auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; - stack.swap(index); - break; - } - - case Instruction::MLOAD: - { - auto addr = stack.pop(); - auto word = memory.loadWord(addr); - stack.push(word); - break; - } - - case Instruction::MSTORE: - { - auto addr = stack.pop(); - auto word = stack.pop(); - memory.storeWord(addr, word); - break; - } - - case Instruction::MSTORE8: - { - auto addr = stack.pop(); - auto word = stack.pop(); - memory.storeByte(addr, word); - break; - } - - case Instruction::MSIZE: - { - auto word = memory.getSize(); - stack.push(word); - break; - } - - case Instruction::SLOAD: - { - auto index = stack.pop(); - auto value = ext.store(index); - stack.push(value); - break; - } - - case Instruction::SSTORE: - { - auto index = stack.pop(); - auto value = stack.pop(); - gasMeter.countSStore(ext, index, value); - ext.setStore(index, value); - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - { - // Generate direct jump iff: - // 1. this is not the first instruction in the block - // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) - // Otherwise generate a indirect jump (a switch). - llvm::BasicBlock* targetBlock = nullptr; - if (currentPC != basicBlock.begin()) - { - auto pairIter = m_directJumpTargets.find(currentPC); - if (pairIter != m_directJumpTargets.end()) - { - targetBlock = pairIter->second; - } - } - - if (inst == Instruction::JUMP) - { - if (targetBlock) - { - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); - m_builder.CreateBr(targetBlock); - } - else - { - m_builder.CreateBr(m_jumpTableBlock->llvm()); - } - } - else // JUMPI - { - stack.swap(1); - auto val = stack.pop(); - 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 (targetBlock) - { - stack.pop(); - m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); - } - else - { - m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); - } - } - - break; - } - - case Instruction::JUMPDEST: - { - // Nothing to do - break; - } - - case Instruction::PC: - { - auto value = Constant::get(currentPC); - stack.push(value); - break; - } - - case Instruction::GAS: - case Instruction::ADDRESS: - case Instruction::CALLER: - case Instruction::ORIGIN: - case Instruction::CALLVALUE: - case Instruction::CALLDATASIZE: - case Instruction::CODESIZE: - case Instruction::GASPRICE: - case Instruction::PREVHASH: - case Instruction::COINBASE: - case Instruction::TIMESTAMP: - case Instruction::NUMBER: - case Instruction::DIFFICULTY: - case Instruction::GASLIMIT: - { - // Pushes an element of runtime data on stack - stack.push(_runtimeManager.get(inst)); - break; - } - - case Instruction::BALANCE: - { - auto address = stack.pop(); - auto value = ext.balance(address); - stack.push(value); - break; - } - - case Instruction::EXTCODESIZE: - { - auto addr = stack.pop(); - auto value = ext.codesizeAt(addr); - stack.push(value); - break; - } - - case Instruction::CALLDATACOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _runtimeManager.getCallData(); - auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); - - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CODECOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - 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); - break; - } - - case Instruction::EXTCODECOPY: - { - auto extAddr = stack.pop(); - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = ext.codeAt(extAddr); - auto srcSize = ext.codesizeAt(extAddr); - - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CALLDATALOAD: - { - auto index = stack.pop(); - auto value = ext.calldataload(index); - stack.push(value); - break; - } - - case Instruction::CREATE: - { - auto endowment = stack.pop(); - auto initOff = stack.pop(); - auto initSize = stack.pop(); - memory.require(initOff, initSize); - - auto address = ext.create(endowment, initOff, initSize); - stack.push(address); - break; - } - - case Instruction::CALL: - case Instruction::CALLCODE: - { - auto gas = stack.pop(); - auto codeAddress = stack.pop(); - auto value = stack.pop(); - auto inOff = stack.pop(); - auto inSize = stack.pop(); - auto outOff = stack.pop(); - auto outSize = stack.pop(); - - gasMeter.commitCostBlock(gas); - - // Require memory for the max of in and out buffers - auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); - auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); - auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); - auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); - memory.require(sizeReq); - - auto receiveAddress = codeAddress; - if (inst == Instruction::CALLCODE) - receiveAddress = _runtimeManager.get(RuntimeData::Address); - - auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - gasMeter.giveBack(gas); - stack.push(ret); - break; - } - - case Instruction::RETURN: - { - auto index = stack.pop(); - auto size = stack.pop(); - - memory.require(index, size); - _runtimeManager.registerReturnData(index, size); - - m_builder.CreateRet(Constant::get(ReturnCode::Return)); - break; - } - - case Instruction::SUICIDE: - { - auto address = stack.pop(); - ext.suicide(address); - // Fall through - } - case Instruction::STOP: - { - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - break; - } - - default: // Invalid instruction - runtime exception - { - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - - } - } - - gasMeter.commitCostBlock(); - - if (!basicBlock.llvm()->getTerminator()) // If block not terminated - { - if (nextBasicBlock) - m_builder.CreateBr(nextBasicBlock); // Branch to the next block - else - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code - } -} - - - -void Compiler::removeDeadBlocks() -{ - // Remove dead basic blocks - auto sthErased = false; - do - { - sthErased = false; - for (auto it = basicBlocks.begin(); it != basicBlocks.end();) - { - auto llvmBB = it->second.llvm(); - if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) - { - llvmBB->eraseFromParent(); - basicBlocks.erase(it++); - sthErased = true; - } - else - ++it; - } - } - while (sthErased); - - // Remove jump table block if no predecessors - if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) - { - m_jumpTableBlock->llvm()->eraseFromParent(); - m_jumpTableBlock.reset(); - } -} - -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"; - - std::vector blocks; - for (auto& pair : basicBlocks) - blocks.push_back(&pair.second); - if (m_jumpTableBlock) - blocks.push_back(m_jumpTableBlock.get()); - if (m_badJumpBlock) - blocks.push_back(m_badJumpBlock.get()); - - // std::map phiNodesPerBlock; - - // Output nodes - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - std::ostringstream oss; - bb->dump(oss, true); - - out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; - } - - // Output edges - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - auto end = llvm::pred_end(bb->llvm()); - 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"; - } - } - - out << "}\n"; -} - -void Compiler::dump() -{ - for (auto& entry : basicBlocks) - entry.second.dump(); - if (m_jumpTableBlock != nullptr) - m_jumpTableBlock->dump(); -} - -} -} -} - From c376cda830506d995d332efdd78e40dd34f85b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 19:17:19 +0100 Subject: [PATCH 294/396] Fix u256 to APInt conversion --- libevmjit/Type.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 447da6a4b..ec11acef5 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -43,10 +43,7 @@ llvm::ConstantInt* Constant::get(uint64_t _n) llvm::ConstantInt* Constant::get(u256 _n) { - auto& backend = _n.backend(); - auto words = reinterpret_cast(backend.limbs()); - auto nWords = backend.limb_bits == 64 ? backend.size() : (backend.size() + 1) / 2; - llvm::APInt n(256, nWords, words); + llvm::APInt n(256, _n.str(0, std::ios_base::hex), 16); assert(n.toString(10, false) == _n.str()); return static_cast(llvm::ConstantInt::get(Type::i256, n)); } From 20277e8b0beee7f3d148b9f290942db9250e42a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 19:17:55 +0100 Subject: [PATCH 295/396] Create dedicated function for pushdata reading --- libevmjit/Utils.cpp | 17 +++++++++++++++++ libevmjit/Utils.h | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 0fd9c0e41..966dc69bd 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -35,6 +35,23 @@ i256 eth2llvm(u256 _u) return i; } +u256 readPushData(const byte*& _curr, const byte* _end) +{ + auto pushInst = *_curr; + assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); + auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1; + u256 value; + ++_curr; // Point the data + for (decltype(numBytes) i = 0; i < numBytes; ++i) + { + byte b = (_curr != _end) ? *_curr++ : 0; + value <<= 8; + value |= b; + } + --_curr; // Point the last real byte read + return value; +} + } } } diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 7a3afda64..9fa9f050e 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -5,6 +5,7 @@ #include #include +#include namespace dev { @@ -29,6 +30,11 @@ static_assert(sizeof(i256) == 32, "Wrong i265 size"); u256 llvm2eth(i256); i256 eth2llvm(u256); +/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it +/// Reading out of bytecode means reading 0 +/// @param _curr is updates and points the last real byte read +u256 readPushData(const byte*& _curr, const byte* _end); + #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ case Instruction::PUSH3: \ From 01b6974a18ad93924bdace7e25161a9ff3c529bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 19:22:01 +0100 Subject: [PATCH 296/396] Use readPushData() in instruction compilation --- libevmjit/Compiler.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index c63418753..92357e8d8 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -554,15 +554,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ANY_PUSH: { - const auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; - auto value = llvm::APInt(256, 0); - for (auto lastPC = currentPC + numBytes; currentPC < lastPC;) - { - value <<= 8; - value |= bytecode[++currentPC]; - } + auto curr = bytecode.begin() + currentPC; // TODO: replace currentPC with iterator + auto value = readPushData(curr, bytecode.end()); + currentPC = curr - bytecode.begin(); - stack.push(m_builder.getInt(value)); + stack.push(Constant::get(value)); break; } From 1728f58cbaae9fe508b85e4030c0074b4598bcf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 30 Oct 2014 19:28:10 +0100 Subject: [PATCH 297/396] Use readPushData() in basic block analysis --- libevmjit/Compiler.cpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 92357e8d8..1e394eba0 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -56,29 +56,20 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) ProgramCounter currentPC = curr - bytecode.begin(); validJumpTargets[currentPC] = true; - auto inst = static_cast(*curr); + auto inst = Instruction(*curr); switch (inst) { case Instruction::ANY_PUSH: { - auto numBytes = static_cast(inst) - static_cast(Instruction::PUSH1) + 1; - auto next = curr + numBytes + 1; - if (next >= bytecode.end()) + auto val = readPushData(curr, bytecode.end()); + auto next = curr + 1; + if (next == bytecode.end()) break; - auto nextInst = static_cast(*next); - + auto nextInst = Instruction(*next); if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) { - // Compute target PC of the jump. - u256 val = 0; - for (auto iter = curr + 1; iter < next; ++iter) - { - val <<= 8; - val |= *iter; - } - // Create a block for the JUMP target. ProgramCounter targetPC = val < bytecode.size() ? val.convert_to() : bytecode.size(); splitPoints.insert(targetPC); @@ -86,8 +77,6 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) ProgramCounter jumpPC = (next - bytecode.begin()); directJumpTargets[jumpPC] = targetPC; } - - curr += numBytes; break; } From 41648959356322398eb0262d9805e5436f04f13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 08:26:41 +0100 Subject: [PATCH 298/396] Deprecate Memory::require(size) function. Risk of unsigned integer overflow. --- libevmjit/Compiler.cpp | 9 +++------ libevmjit/Memory.cpp | 2 +- libevmjit/Memory.h | 7 +++---- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1e394eba0..0c955ab3b 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -785,12 +785,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, gasMeter.commitCostBlock(gas); - // Require memory for the max of in and out buffers - auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); - auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); - auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); - auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); - memory.require(sizeReq); + // Require memory for in and out buffers + memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one + memory.require(inOff, inSize); auto receiveAddress = codeAddress; if (inst == Instruction::CALLCODE) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 84aa105fe..8528bd9d2 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -171,7 +171,7 @@ void Memory::require(llvm::Value* _size) void Memory::require(llvm::Value* _offset, llvm::Value* _size) { - auto sizeRequired = m_builder.CreateAdd(_offset, _size, "sizeRequired"); + auto sizeRequired = m_builder.CreateNUWAdd(_offset, _size, "sizeRequired"); require(sizeRequired); } diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index f315b9295..90c60c5fd 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -24,9 +24,6 @@ public: void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex, llvm::Value* _destMemIdx, llvm::Value* _byteCount); - /// Requires this amount of memory. And counts gas fee for that memory. - void require(llvm::Value* _size); - /// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory. void require(llvm::Value* _offset, llvm::Value* _size); @@ -36,7 +33,9 @@ private: llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager); -private: + /// Requires this amount of memory. And counts gas fee for that memory. + void require(llvm::Value* _size); + llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; From cfb98606f563bb5c079374d656462438c4ee87bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 08:50:25 +0100 Subject: [PATCH 299/396] Remove Memory::require(size) interface [#81773288] --- libevmjit/Memory.cpp | 32 ++++++++++++++------------------ libevmjit/Memory.h | 3 --- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 8528bd9d2..309fb2964 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -28,8 +28,7 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager) { auto module = getModule(); - auto i64Ty = m_builder.getInt64Ty(); - llvm::Type* argTypes[] = {i64Ty, i64Ty}; + llvm::Type* argTypes[] = {Type::i256, Type::i256}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_memory_dump", module); @@ -54,19 +53,23 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager) { - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + llvm::Type* argTypes[] = {Type::i256, Type::i256}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto offset = func->arg_begin(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func); - auto returnBB = llvm::BasicBlock::Create(func->getContext(), "return", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); InsertPointGuard guard(m_builder); // Restores insert point at function exit // BB "check" m_builder.SetInsertPoint(checkBB); - llvm::Value* sizeRequired = func->arg_begin(); - sizeRequired->setName("sizeRequired"); - auto size = m_builder.CreateLoad(m_size, "size"); + auto sizeRequired = m_builder.CreateNUWAdd(offset, size, "sizeRequired"); + auto currSize = m_builder.CreateLoad(m_size, "currSize"); auto resizeNeeded = m_builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? @@ -164,15 +167,9 @@ llvm::Value* Memory::getSize() return m_builder.CreateLoad(m_size); } -void Memory::require(llvm::Value* _size) -{ - m_builder.CreateCall(m_require, _size); -} - void Memory::require(llvm::Value* _offset, llvm::Value* _size) { - auto sizeRequired = m_builder.CreateNUWAdd(_offset, _size, "sizeRequired"); - require(sizeRequired); + m_builder.CreateCall2(m_require, _offset, _size); } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, @@ -180,8 +177,7 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* { auto zero256 = llvm::ConstantInt::get(Type::i256, 0); - auto reqMemSize = m_builder.CreateAdd(_destMemIdx, _reqBytes, "req_mem_size"); - require(reqMemSize); + require(_destMemIdx, _reqBytes); auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx"); diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index 90c60c5fd..37bfb15f5 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -33,9 +33,6 @@ private: llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager); - /// Requires this amount of memory. And counts gas fee for that memory. - void require(llvm::Value* _size); - llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; From 340d9ea6782e474271c0990e0f34414dd7e0d646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 11:09:53 +0100 Subject: [PATCH 300/396] Change Constant::get to support negative values --- libevmjit/Compiler.cpp | 2 +- libevmjit/Type.cpp | 4 ++-- libevmjit/Type.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 0c955ab3b..8a38e257f 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -366,7 +366,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::BNOT: { auto value = stack.pop(); - auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot"); + auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); stack.push(ret); break; } diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index ec11acef5..37757dfdf 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -36,9 +36,9 @@ void Type::init(llvm::LLVMContext& _context) RuntimePtr = RuntimeData::getType()->getPointerTo(); } -llvm::ConstantInt* Constant::get(uint64_t _n) +llvm::ConstantInt* Constant::get(int64_t _n) { - return llvm::ConstantInt::get(Type::i256, _n); + return llvm::ConstantInt::getSigned(Type::i256, _n); } llvm::ConstantInt* Constant::get(u256 _n) diff --git a/libevmjit/Type.h b/libevmjit/Type.h index c80e46777..4658f94bb 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -51,7 +51,7 @@ enum class ReturnCode struct Constant { /// Returns word-size constant - static llvm::ConstantInt* get(uint64_t _n); + static llvm::ConstantInt* get(int64_t _n); static llvm::ConstantInt* get(u256 _n); static llvm::ConstantInt* get(ReturnCode _returnCode); From d555d4af8fe08c34361bbc098aed76e1fc9c52b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 11:14:25 +0100 Subject: [PATCH 301/396] Handle unsigned integer overflow in Memory::require() [Delivers #81773288] --- libevmjit/Memory.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 309fb2964..322c53ee3 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -8,6 +8,7 @@ #include #include +#include #include @@ -68,17 +69,26 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ // BB "check" m_builder.SetInsertPoint(checkBB); - auto sizeRequired = m_builder.CreateNUWAdd(offset, size, "sizeRequired"); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::i256); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); auto currSize = m_builder.CreateLoad(m_size, "currSize"); - auto resizeNeeded = m_builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); + auto tooSmall = m_builder.CreateICmpULE(size, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? // BB "resize" m_builder.SetInsertPoint(resizeBB); // Check gas first - auto wordsRequired = m_builder.CreateUDiv(m_builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeRequired"); - auto words = m_builder.CreateUDiv(size, Constant::get(32), "words"); // size is always 32*k + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); _gasMeter.checkMemory(newWords, m_builder); // Resize From ec07859aedd18ebfd9b40cfa2a182e49c5b3f30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 12:44:43 +0100 Subject: [PATCH 302/396] Update Visual Studio project file for LibEthereum --- windows/LibEthereum.vcxproj | 4 ++-- windows/LibEthereum.vcxproj.filters | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 956252979..9faae62c3 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -103,8 +103,8 @@ true + - @@ -319,8 +319,8 @@ true true + - diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index d96ee47a5..5e1497b86 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -4,9 +4,6 @@ Windows - - libethereum - libethereum @@ -205,14 +202,14 @@ libdevcrypto + + libethereum + Windows - - libethereum - libethereum @@ -441,6 +438,9 @@ libdevcrypto + + libethereum + From 5dc0a266c4f24f1aabc1a9e4203877af02b23462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:16:34 +0100 Subject: [PATCH 303/396] Empty lines removal --- libevmjit/Compiler.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 8a38e257f..121ae37d5 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -462,7 +462,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, const auto byteNum = stack.pop(); auto value = stack.pop(); - // value = Endianness::toBE(m_builder, value); auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); @@ -471,7 +470,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); stack.push(value); - break; } @@ -521,7 +519,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, m_builder.CreateSelect(bittest, val1, val0), word); stack.push(result); - break; } From b039d7ee8e98aa22e9693e52d5ad3090b25000f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:17:03 +0100 Subject: [PATCH 304/396] Use common builder in GasMeter and Memory --- libevmjit/GasMeter.cpp | 7 +++---- libevmjit/GasMeter.h | 4 ++-- libevmjit/Memory.cpp | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 5f6f81e72..a0656ace4 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -169,11 +169,10 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost) assert(m_blockCost == 0); } -void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder) +void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords) { - // Memory uses other builder, but that can be changes later - auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); - _builder.CreateCall(m_gasCheckFunc, cost); + auto cost = m_builder.CreateNUWMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); + m_builder.CreateCall(m_gasCheckFunc, cost); } } diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index dcfde92a3..3de227651 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -32,7 +32,7 @@ public: void giveBack(llvm::Value* _gas); /// Generate code that checks the cost of additional memory used by program - void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); + void checkMemory(llvm::Value* _additionalMemoryInWords); private: /// Cumulative gas cost of a block of instructions @@ -40,7 +40,7 @@ private: uint64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; - llvm::Function* m_gasCheckFunc; + llvm::Function* m_gasCheckFunc = nullptr; RuntimeManager& m_runtimeManager; }; diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 322c53ee3..beedd9cb9 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -90,7 +90,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.checkMemory(newWords, m_builder); + _gasMeter.checkMemory(newWords); // Resize m_builder.CreateStore(sizeRequired, m_size); auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData"); From 23c7da66fa406dab7df9e8a7151bc3e597cf56a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:28:27 +0100 Subject: [PATCH 305/396] Rename Type::i256 -> Type::Word --- libevmjit/Arith256.cpp | 8 ++++---- libevmjit/BasicBlock.cpp | 2 +- libevmjit/Compiler.cpp | 20 ++++++++++---------- libevmjit/Endianness.cpp | 4 ++-- libevmjit/GasMeter.cpp | 4 ++-- libevmjit/Memory.cpp | 26 +++++++++++++------------- libevmjit/Runtime.cpp | 2 +- libevmjit/Stack.cpp | 2 +- libevmjit/Type.cpp | 10 +++++----- libevmjit/Type.h | 2 +- 10 files changed, 40 insertions(+), 40 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 61b0ba35e..82e31e61d 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -18,10 +18,10 @@ Arith256::Arith256(llvm::IRBuilder<>& _builder) : { using namespace llvm; - m_result = m_builder.CreateAlloca(Type::i256, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::i256, nullptr, "arith.arg3"); + m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); + m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); + m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); + m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); using Linkage = GlobalValue::LinkageTypes; diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index a35462cbe..0c604f1b3 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -171,7 +171,7 @@ llvm::Value* BasicBlock::LocalStack::get(size_t _index) assert(m_initialStack[initialIdx] == nullptr); // Create a dummy value. std::string name = "get_" + boost::lexical_cast(_index); - m_initialStack[initialIdx] = m_builder.CreatePHI(Type::i256, 0, name); + m_initialStack[initialIdx] = m_builder.CreatePHI(Type::Word, 0, name); *itemIter = m_initialStack[initialIdx]; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 121ae37d5..537a0082b 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -376,7 +376,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpULT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -386,7 +386,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpUGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -396,7 +396,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpSLT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -406,7 +406,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpSGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -416,7 +416,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto res1 = m_builder.CreateICmpEQ(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); + auto res256 = m_builder.CreateZExt(res1, Type::Word); stack.push(res256); break; } @@ -425,7 +425,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto top = stack.pop(); auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); - auto result = m_builder.CreateZExt(iszero, Type::i256); + auto result = m_builder.CreateZExt(iszero, Type::Word); stack.push(result); break; } @@ -465,7 +465,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, value = Endianness::toBE(m_builder, value); auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); - value = m_builder.CreateZExt(byte, Type::i256); + value = m_builder.CreateZExt(byte, Type::Word); auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); @@ -499,7 +499,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, 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 k32 = m_builder.CreateZExt(k32_, Type::Word); auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8"); // test for word >> (k * 8 + 7) @@ -510,11 +510,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, 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 negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::Word), "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 kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::Word, 30)); auto result = m_builder.CreateSelect(kInRange, m_builder.CreateSelect(bittest, val1, val0), word); diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index f0da5f9d4..e062fb77e 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -15,8 +15,8 @@ namespace jit llvm::Value* Endianness::bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word) { // TODO: Native is Little Endian - assert(_word->getType() == Type::i256); - auto bswap = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::i256); + assert(_word->getType() == Type::Word); + auto bswap = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); return _builder.CreateCall(bswap, _word); } diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index a0656ace4..7a6a0ebd2 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -84,7 +84,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); + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::Word, false), llvm::Function::PrivateLinkage, "gas.check", module); InsertPointGuard guard(m_builder); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); @@ -113,7 +113,7 @@ void GasMeter::count(Instruction _inst) if (!m_checkCall) { // 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::Word)); } m_blockCost += getStepCost(_inst); diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index beedd9cb9..c06b22637 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -29,7 +29,7 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager) { auto module = getModule(); - llvm::Type* argTypes[] = {Type::i256, Type::i256}; + llvm::Type* argTypes[] = {Type::Word, Type::Word}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_memory_dump", module); @@ -37,7 +37,7 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): 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_size = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); + m_size = new llvm::GlobalVariable(*module, Type::Word, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); m_size->setUnnamedAddr(true); // Address is not important llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; @@ -47,14 +47,14 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); m_require = createRequireFunc(_gasMeter, _runtimeManager); - m_loadWord = createFunc(false, Type::i256, _gasMeter); - m_storeWord = createFunc(true, Type::i256, _gasMeter); + m_loadWord = createFunc(false, Type::Word, _gasMeter); + m_storeWord = createFunc(true, Type::Word, _gasMeter); m_storeByte = createFunc(true, Type::Byte, _gasMeter); } llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager) { - llvm::Type* argTypes[] = {Type::i256, Type::i256}; + llvm::Type* argTypes[] = {Type::Word, Type::Word}; auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); auto offset = func->arg_begin(); offset->setName("offset"); @@ -67,9 +67,9 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ InsertPointGuard guard(m_builder); // Restores insert point at function exit - // BB "check" + // BB "Check" m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::i256); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); @@ -78,7 +78,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - // BB "resize" + // BB "Resize" m_builder.SetInsertPoint(resizeBB); // Check gas first uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); @@ -97,7 +97,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ m_builder.CreateStore(newData, m_data); m_builder.CreateBr(returnBB); - // BB "return" + // BB "Return" m_builder.SetInsertPoint(returnBB); m_builder.CreateRetVoid(); return func; @@ -105,11 +105,11 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) { - auto isWord = _valueType == Type::i256; + auto isWord = _valueType == Type::Word; - llvm::Type* storeArgs[] = {Type::i256, _valueType}; + llvm::Type* storeArgs[] = {Type::Word, _valueType}; auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; - auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false); + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, Type::Word, false); auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); InsertPointGuard guard(m_builder); // Restores insert point at function exit @@ -185,7 +185,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) { - auto zero256 = llvm::ConstantInt::get(Type::i256, 0); + auto zero256 = llvm::ConstantInt::get(Type::Word, 0); require(_destMemIdx, _reqBytes); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 361089ba1..292eb02bd 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -22,7 +22,7 @@ llvm::StructType* RuntimeData::getType() { llvm::Type* elems[] = { - llvm::ArrayType::get(Type::i256, _size), + llvm::ArrayType::get(Type::Word, _size), Type::BytePtr, Type::BytePtr, Type::BytePtr diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index d6538a22d..bb157b847 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -18,7 +18,7 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): CompilerHelper(_builder), m_runtimeManager(_runtimeManager) { - m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg"); + m_arg = m_builder.CreateAlloca(Type::Word, nullptr, "stack.arg"); using namespace llvm; using Linkage = GlobalValue::LinkageTypes; diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 37757dfdf..a72ec0eda 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -12,7 +12,7 @@ namespace eth namespace jit { -llvm::IntegerType* Type::i256; +llvm::IntegerType* Type::Word; llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Size; @@ -24,8 +24,8 @@ llvm::PointerType* Type::RuntimePtr; void Type::init(llvm::LLVMContext& _context) { - i256 = llvm::Type::getIntNTy(_context, 256); - WordPtr = i256->getPointerTo(); + Word = llvm::Type::getIntNTy(_context, 256); + WordPtr = Word->getPointerTo(); lowPrecision = llvm::Type::getInt64Ty(_context); // TODO: Size should be architecture-dependent Size = llvm::Type::getInt64Ty(_context); @@ -38,14 +38,14 @@ void Type::init(llvm::LLVMContext& _context) llvm::ConstantInt* Constant::get(int64_t _n) { - return llvm::ConstantInt::getSigned(Type::i256, _n); + return llvm::ConstantInt::getSigned(Type::Word, _n); } llvm::ConstantInt* Constant::get(u256 _n) { llvm::APInt n(256, _n.str(0, std::ios_base::hex), 16); assert(n.toString(10, false) == _n.str()); - return static_cast(llvm::ConstantInt::get(Type::i256, n)); + return static_cast(llvm::ConstantInt::get(Type::Word, n)); } llvm::ConstantInt* Constant::get(ReturnCode _returnCode) diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 4658f94bb..0d8c6c530 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -14,7 +14,7 @@ namespace jit struct Type { - static llvm::IntegerType* i256; + static llvm::IntegerType* Word; static llvm::PointerType* WordPtr; /// Type for doing low precision arithmetics where 256-bit precision is not supported by native target From aa3ae144220d9255c158c5012118bac2c8c1109d Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 14:46:32 +0000 Subject: [PATCH 306/396] code cleanup & coding-standardization --- libevmjit/Compiler.cpp | 243 +++++++++++++++++++---------------------- 1 file changed, 112 insertions(+), 131 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1e394eba0..cdb9a6448 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -32,28 +32,27 @@ namespace eth namespace jit { -Compiler::Compiler(): - m_builder(llvm::getGlobalContext()), - m_jumpTableBlock(), - m_badJumpBlock() +Compiler::Compiler(Options const& _options): + m_options(_options), + m_builder(llvm::getGlobalContext()) { Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(bytesConstRef bytecode) +void Compiler::createBasicBlocks(bytesConstRef _bytecode) { std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end std::map directJumpTargets; std::vector 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 validJumpTargets[0] = true; - for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) + for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) { - ProgramCounter currentPC = curr - bytecode.begin(); + ProgramCounter currentPC = curr - _bytecode.begin(); validJumpTargets[currentPC] = true; auto inst = Instruction(*curr); @@ -62,19 +61,19 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) case Instruction::ANY_PUSH: { - auto val = readPushData(curr, bytecode.end()); + auto val = readPushData(curr, _bytecode.end()); auto next = curr + 1; - if (next == bytecode.end()) + if (next == _bytecode.end()) break; auto nextInst = Instruction(*next); if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) { // Create a block for the JUMP target. - ProgramCounter targetPC = val < bytecode.size() ? val.convert_to() : bytecode.size(); + ProgramCounter targetPC = val < _bytecode.size() ? val.convert_to() : _bytecode.size(); splitPoints.insert(targetPC); - ProgramCounter jumpPC = (next - bytecode.begin()); + ProgramCounter jumpPC = (next - _bytecode.begin()); directJumpTargets[jumpPC] = targetPC; } break; @@ -83,7 +82,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) case Instruction::JUMPDEST: { // A basic block starts at the next instruction. - if (currentPC + 1 < bytecode.size()) + if (currentPC + 1 < _bytecode.size()) { splitPoints.insert(currentPC + 1); indirectJumpTargets.push_back(currentPC + 1); @@ -98,7 +97,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) case Instruction::SUICIDE: { // Create a basic block starting at the following instruction. - if (curr + 1 < bytecode.end()) + if (curr + 1 < _bytecode.end()) { splitPoints.insert(currentPC + 1); } @@ -113,7 +112,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();) { - if (*it > bytecode.size() || !validJumpTargets[*it]) + if (*it > _bytecode.size() || !validJumpTargets[*it]) it = splitPoints.erase(it); else ++it; @@ -123,7 +122,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) { auto beginInstIdx = *it; ++it; - auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size(); + auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); } @@ -133,7 +132,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { - if (it->second >= bytecode.size()) + if (it->second >= _bytecode.size()) { // Jumping out of code means STOP m_directJumpTargets[it->first] = m_stopBB; @@ -154,12 +153,10 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) } for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - { m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); - } } -std::unique_ptr Compiler::compile(bytesConstRef bytecode) +std::unique_ptr Compiler::compile(bytesConstRef _bytecode) { auto module = std::unique_ptr(new llvm::Module("main", m_builder.getContext())); @@ -173,7 +170,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - createBasicBlocks(bytecode); + createBasicBlocks(_bytecode); // Init runtime structures. RuntimeManager runtimeManager(m_builder); @@ -191,13 +188,11 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: // TODO: move to separate function. - // Note: Right now the codegen for special blocks depends only on createBasicBlock(), - // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). m_builder.SetInsertPoint(m_stopBB); m_builder.CreateRet(Constant::get(ReturnCode::Stop)); @@ -218,75 +213,59 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) } } else - { m_builder.CreateBr(m_badJumpBlock->llvm()); - } removeDeadBlocks(); - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-init.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter dead block elimination \n\n"; - dump(); - } + dumpCFGifRequired("blocks-init.dot"); - //if (getenv("EVMCC_OPTIMIZE_STACK")) - //{ + if (m_options.optimizeStack) + { std::vector blockList; for (auto& entry : basicBlocks) blockList.push_back(&entry.second); - if (m_jumpTableBlock != nullptr) + if (m_jumpTableBlock) blockList.push_back(m_jumpTableBlock.get()); BasicBlock::linkLocalStacks(blockList, m_builder); - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - std::ofstream ofs("blocks-opt.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter stack optimization \n\n"; - dump(); - } - //} + dumpCFGifRequired("blocks-opt.dot"); + } for (auto& entry : basicBlocks) entry.second.localStack().synchronize(stack); - if (m_jumpTableBlock != nullptr) + if (m_jumpTableBlock) m_jumpTableBlock->localStack().synchronize(stack); - if (getenv("EVMCC_DEBUG_BLOCKS")) + dumpCFGifRequired("blocks-sync.dot"); + + if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) { - std::ofstream ofs("blocks-sync.dot"); - dumpBasicBlockGraph(ofs); - ofs.close(); - std::cerr << "\n\nAfter stack synchronization \n\n"; - dump(); + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); } - llvm::FunctionPassManager fpManager(module.get()); - fpManager.add(llvm::createLowerSwitchPass()); - fpManager.doInitialization(); - fpManager.run(*m_mainFunc); - return module; } -void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Arith256& arith, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, RuntimeManager& _runtimeManager, + Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) { - m_builder.SetInsertPoint(basicBlock.llvm()); - auto& stack = basicBlock.localStack(); + if (!_nextBasicBlock) // this is the last block in the code + _nextBasicBlock = m_stopBB; + + m_builder.SetInsertPoint(_basicBlock.llvm()); + auto& stack = _basicBlock.localStack(); - for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) + for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) { - auto inst = static_cast(bytecode[currentPC]); + auto inst = static_cast(_bytecode[currentPC]); - gasMeter.count(inst); + _gasMeter.count(inst); switch (inst) { @@ -313,7 +292,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.mul(lhs, rhs); + auto res = _arith.mul(lhs, rhs); stack.push(res); break; } @@ -322,7 +301,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.div(lhs, rhs); + auto res = _arith.div(lhs, rhs); stack.push(res); break; } @@ -331,7 +310,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.sdiv(lhs, rhs); + auto res = _arith.sdiv(lhs, rhs); stack.push(res); break; } @@ -340,7 +319,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.mod(lhs, rhs); + auto res = _arith.mod(lhs, rhs); stack.push(res); break; } @@ -349,7 +328,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto lhs = stack.pop(); auto rhs = stack.pop(); - auto res = arith.smod(lhs, rhs); + auto res = _arith.smod(lhs, rhs); stack.push(res); break; } @@ -358,7 +337,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto left = stack.pop(); auto right = stack.pop(); - auto ret = ext.exp(left, right); + auto ret = _ext.exp(left, right); stack.push(ret); break; } @@ -480,7 +459,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto mod = stack.pop(); - auto res = arith.addmod(lhs, rhs, mod); + auto res = _arith.addmod(lhs, rhs, mod); stack.push(res); break; } @@ -490,7 +469,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto lhs = stack.pop(); auto rhs = stack.pop(); auto mod = stack.pop(); - auto res = arith.mulmod(lhs, rhs, mod); + auto res = _arith.mulmod(lhs, rhs, mod); stack.push(res); break; } @@ -529,8 +508,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto inOff = stack.pop(); auto inSize = stack.pop(); - memory.require(inOff, inSize); - auto hash = ext.sha3(inOff, inSize); + _memory.require(inOff, inSize); + auto hash = _ext.sha3(inOff, inSize); stack.push(hash); break; } @@ -543,9 +522,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::ANY_PUSH: { - auto curr = bytecode.begin() + currentPC; // TODO: replace currentPC with iterator - auto value = readPushData(curr, bytecode.end()); - currentPC = curr - bytecode.begin(); + auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator + auto value = readPushData(curr, _bytecode.end()); + currentPC = curr - _bytecode.begin(); stack.push(Constant::get(value)); break; @@ -568,7 +547,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::MLOAD: { auto addr = stack.pop(); - auto word = memory.loadWord(addr); + auto word = _memory.loadWord(addr); stack.push(word); break; } @@ -577,7 +556,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto addr = stack.pop(); auto word = stack.pop(); - memory.storeWord(addr, word); + _memory.storeWord(addr, word); break; } @@ -585,13 +564,13 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto addr = stack.pop(); auto word = stack.pop(); - memory.storeByte(addr, word); + _memory.storeByte(addr, word); break; } case Instruction::MSIZE: { - auto word = memory.getSize(); + auto word = _memory.getSize(); stack.push(word); break; } @@ -599,7 +578,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::SLOAD: { auto index = stack.pop(); - auto value = ext.store(index); + auto value = _ext.store(index); stack.push(value); break; } @@ -608,8 +587,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, { auto index = stack.pop(); auto value = stack.pop(); - gasMeter.countSStore(ext, index, value); - ext.setStore(index, value); + _gasMeter.countSStore(_ext, index, value); + _ext.setStore(index, value); break; } @@ -621,7 +600,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) // Otherwise generate a indirect jump (a switch). llvm::BasicBlock* targetBlock = nullptr; - if (currentPC != basicBlock.begin()) + if (currentPC != _basicBlock.begin()) { auto pairIter = m_directJumpTargets.find(currentPC); if (pairIter != m_directJumpTargets.end()) @@ -647,17 +626,13 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto zero = Constant::get(0); auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - - if (!nextBasicBlock) // In case JUMPI is the last instruction - nextBasicBlock = m_stopBB; - if (targetBlock) { stack.pop(); - m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); + m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); } else - m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); + m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); } break; @@ -699,7 +674,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::BALANCE: { auto address = stack.pop(); - auto value = ext.balance(address); + auto value = _ext.balance(address); stack.push(value); break; } @@ -707,7 +682,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, case Instruction::EXTCODESIZE: { auto addr = stack.pop(); - auto value = ext.codesizeAt(addr); + auto value = _ext.codesizeAt(addr); stack.push(value); break; } @@ -721,7 +696,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto srcPtr = _runtimeManager.getCallData(); auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); break; } @@ -734,7 +709,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, 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); + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); break; } @@ -745,17 +720,17 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto srcPtr = ext.codeAt(extAddr); - auto srcSize = ext.codesizeAt(extAddr); + auto srcPtr = _ext.codeAt(extAddr); + auto srcSize = _ext.codesizeAt(extAddr); - memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); break; } case Instruction::CALLDATALOAD: { auto index = stack.pop(); - auto value = ext.calldataload(index); + auto value = _ext.calldataload(index); stack.push(value); break; } @@ -765,9 +740,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto endowment = stack.pop(); auto initOff = stack.pop(); auto initSize = stack.pop(); - memory.require(initOff, initSize); + _memory.require(initOff, initSize); - auto address = ext.create(endowment, initOff, initSize); + auto address = _ext.create(endowment, initOff, initSize); stack.push(address); break; } @@ -783,21 +758,21 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto outOff = stack.pop(); auto outSize = stack.pop(); - gasMeter.commitCostBlock(gas); + _gasMeter.commitCostBlock(gas); - // Require memory for the max of in and out buffers + // Require _memory for the max of in and out buffers auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); - memory.require(sizeReq); + _memory.require(sizeReq); auto receiveAddress = codeAddress; if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); - auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - gasMeter.giveBack(gas); + auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gas); stack.push(ret); break; } @@ -807,7 +782,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto index = stack.pop(); auto size = stack.pop(); - memory.require(index, size); + _memory.require(index, size); _runtimeManager.registerReturnData(index, size); m_builder.CreateRet(Constant::get(ReturnCode::Return)); @@ -815,13 +790,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } case Instruction::SUICIDE: - { - auto address = stack.pop(); - ext.suicide(address); - // Fall through - } case Instruction::STOP: { + if (inst == Instruction::SUICIDE) + { + auto address = stack.pop(); + _ext.suicide(address); + } + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); break; } @@ -834,15 +810,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } } - gasMeter.commitCostBlock(); + _gasMeter.commitCostBlock(); - if (!basicBlock.llvm()->getTerminator()) // If block not terminated - { - if (nextBasicBlock) - m_builder.CreateBr(nextBasicBlock); // Branch to the next block - else - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code - } + // Block may have no terminator if the next instruction is a jump destination. + if (!_basicBlock.llvm()->getTerminator()) + m_builder.CreateBr(_nextBasicBlock); } @@ -877,11 +849,22 @@ void Compiler::removeDeadBlocks() } } -void Compiler::dumpBasicBlockGraph(std::ostream& out) +void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) +{ + if (! m_options.dumpCFG) + return; + + // TODO: handle i/o failures + std::ofstream ofs(_dotfilePath); + dumpCFGtoStream(ofs); + ofs.close(); +} + +void Compiler::dumpCFGtoStream(std::ostream& _out) { - out << "digraph BB {\n" - << " node [shape=record, fontname=Courier, fontsize=10];\n" - << " entry [share=record, label=\"entry block\"];\n"; + _out << "digraph BB {\n" + << " node [shape=record, fontname=Courier, fontsize=10];\n" + << " entry [share=record, label=\"entry block\"];\n"; std::vector blocks; for (auto& pair : basicBlocks) @@ -901,7 +884,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) std::ostringstream oss; bb->dump(oss, true); - out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; + _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; } // Output edges @@ -912,15 +895,13 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) auto end = llvm::pred_end(bb->llvm()); 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"; + _out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" + << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") + << "];\n"; } } - out << "}\n"; + _out << "}\n"; } void Compiler::dump() From bb4c21e5f3add80b537b222fa0ceeb2a8561d48a Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 14:47:16 +0000 Subject: [PATCH 307/396] allow --jit as non first argument --- test/vm.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 102de7c4f..3fe12dc1f 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -535,7 +535,9 @@ void doTests(json_spirit::mValue& v, bool _fillin) auto argc = boost::unit_test::framework::master_test_suite().argc; auto argv = boost::unit_test::framework::master_test_suite().argv; - auto useJit = argc >= 2 && std::string(argv[1]) == "--jit"; + auto useJit = false; + for (auto i = 0; i < argc && !useJit; ++i) + useJit |= std::string(argv[i]) == "--jit"; auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; dev::test::FakeExtVM fev; @@ -585,8 +587,8 @@ void doTests(json_spirit::mValue& v, bool _fillin) cnote << "Execution time: " << std::chrono::duration_cast(testDuration).count() << " ms"; + break; } - break; } auto gas = vm->gas(); @@ -826,7 +828,7 @@ BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) BOOST_AUTO_TEST_CASE(userDefinedFile) { - if (boost::unit_test::framework::master_test_suite().argc == 2) + if (boost::unit_test::framework::master_test_suite().argc >= 2) { string filename = boost::unit_test::framework::master_test_suite().argv[1]; int currentVerbosity = g_logVerbosity; From a19f3df3b39515bbc84599a4cfe925c254323af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:50:03 +0100 Subject: [PATCH 308/396] Coding style: use "o_" prefix for output function arguments --- libevmjit/Arith256.cpp | 28 ++++++++++++++-------------- libevmjit/Ext.cpp | 40 ++++++++++++++++++++-------------------- libevmjit/Memory.cpp | 4 +--- libevmjit/Stack.cpp | 8 ++++---- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 82e31e61d..79a8fe79c 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -103,55 +103,55 @@ extern "C" using namespace dev::eth::jit; - EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* _result) + EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg1 * arg2); + *o_result = eth2llvm(arg1 * arg2); } - EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* _result) + EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); + *o_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* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); + *o_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* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2))); + *o_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* o_result) { dev::u256 arg1 = llvm2eth(*_arg1); dev::u256 arg2 = llvm2eth(*_arg2); - *_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) % dev::u2s(arg2))); + *o_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* o_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)); + *o_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* o_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)); + *o_result = eth2llvm(dev::u256((dev::bigint(arg1) + dev::bigint(arg2)) % arg3)); } } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 0fe795a1f..f39ab5755 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -168,11 +168,11 @@ extern "C" using namespace dev::eth::jit; - EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value) + EXPORT void ext_store(Runtime* _rt, i256* _index, i256* o_value) { auto index = llvm2eth(*_index); auto value = _rt->getExt().store(index); // Interface uses native endianness - *_value = eth2llvm(value); + *o_value = eth2llvm(value); } EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value) @@ -187,28 +187,28 @@ extern "C" ext.setStore(index, value); // Interface uses native endianness } - EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value) + EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* o_value) { auto index = static_cast(llvm2eth(*_index)); assert(index + 31 > index); // TODO: Handle large index - auto b = reinterpret_cast(_value); + auto b = reinterpret_cast(o_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) + EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* o_value) { auto u = _rt->getExt().balance(right160(*_address)); - *_value = eth2llvm(u); + *o_value = eth2llvm(u); } - EXPORT void ext_suicide(Runtime* _rt, h256* _address) + EXPORT void ext_suicide(Runtime* _rt, h256 const* _address) { _rt->getExt().suicide(right160(*_address)); } - EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* _address) + EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* o_address) { auto&& ext = _rt->getExt(); auto endowment = llvm2eth(*_endowment); @@ -222,21 +222,21 @@ extern "C" 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; + *o_address = address; } else - *_address = {}; + *o_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) + EXPORT void ext_call(Runtime* _rt, i256* io_gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* o_ret) { auto&& ext = _rt->getExt(); auto value = llvm2eth(*_value); auto ret = false; - auto gas = llvm2eth(*_gas); + auto gas = llvm2eth(*io_gas); if (ext.balance(ext.myAddress) >= value) { ext.subBalance(value); @@ -252,25 +252,25 @@ extern "C" ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); } - *_gas = eth2llvm(gas); - _ret->a = ret ? 1 : 0; + *io_gas = eth2llvm(gas); + o_ret->a = ret ? 1 : 0; } - EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret) + EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* o_ret) { auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); auto hash = sha3(dataRef); - *_ret = *reinterpret_cast(&hash); + *o_ret = *reinterpret_cast(&hash); } - EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* _ret) + EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* o_ret) { bigint left = llvm2eth(*_left); bigint right = llvm2eth(*_right); auto ret = static_cast(boost::multiprecision::powm(left, right, bigint(2) << 256)); - *_ret = eth2llvm(ret); + *o_ret = eth2llvm(ret); } EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) @@ -281,12 +281,12 @@ extern "C" return const_cast(code.data()); } - EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret) + EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* o_ret) { auto&& ext = _rt->getExt(); auto addr = right160(*_addr256); auto& code = ext.codeAt(addr); - *_ret = eth2llvm(u256(code.size())); + *o_ret = eth2llvm(u256(code.size())); } } diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c06b22637..c3e904ef8 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -224,7 +224,6 @@ 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) @@ -234,5 +233,4 @@ extern "C" memory.resize(size); return memory.data(); } - -} // extern "C" +} diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index bb157b847..494750b43 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -79,7 +79,7 @@ extern "C" stack.erase(stack.end() - _count, stack.end()); } - EXPORT void stack_push(Runtime* _rt, i256* _word) + EXPORT void stack_push(Runtime* _rt, i256 const* _word) { auto& stack = _rt->getStack(); stack.push_back(*_word); @@ -88,17 +88,17 @@ extern "C" 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* o_ret) { auto& stack = _rt->getStack(); // TODO: encode _index and stack size in the return code if (stack.size() <= _index) longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - *_ret = *(stack.rbegin() + _index); + *o_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 const* _word) { auto& stack = _rt->getStack(); // TODO: encode _index and stack size in the return code From c52fd78fb66d63bb292123f7e617845201b92625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 15:57:54 +0100 Subject: [PATCH 309/396] Use llvm.longjmp intrinsic for longjmp [Delivers #81792986] --- libevmjit/Runtime.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 292eb02bd..96a5f75a3 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -105,7 +106,7 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui { m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt"); llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; - m_longjmp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", getModule()); + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); // Export data auto mainFunc = getMainFunction(); From 44a9ea0fb850378bfd8e7d0ea843892762a410a9 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 15:46:05 +0000 Subject: [PATCH 310/396] code cleanup and coding-standardization --- libevmjit/Compiler.cpp | 4 +- libevmjit/Compiler.cpp.orig | 924 ++++++++++++++++++++++++++++++++++++ libevmjit/Compiler.h | 69 +-- libevmjit/VM.cpp | 3 +- 4 files changed, 970 insertions(+), 30 deletions(-) create mode 100644 libevmjit/Compiler.cpp.orig diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 6b0d5f2e1..928baee22 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -761,8 +761,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod _gasMeter.commitCostBlock(gas); // Require memory for in and out buffers - memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one - memory.require(inOff, inSize); + _memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one + _memory.require(inOff, inSize); auto receiveAddress = codeAddress; if (inst == Instruction::CALLCODE) diff --git a/libevmjit/Compiler.cpp.orig b/libevmjit/Compiler.cpp.orig new file mode 100644 index 000000000..9c6043ff2 --- /dev/null +++ b/libevmjit/Compiler.cpp.orig @@ -0,0 +1,924 @@ + +#include "Compiler.h" + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "Type.h" +#include "Memory.h" +#include "Stack.h" +#include "Ext.h" +#include "GasMeter.h" +#include "Utils.h" +#include "Endianness.h" +#include "Arith256.h" +#include "Runtime.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Compiler::Compiler(Options const& _options): + m_options(_options), + m_builder(llvm::getGlobalContext()) +{ + Type::init(m_builder.getContext()); +} + +void Compiler::createBasicBlocks(bytesConstRef _bytecode) +{ + std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end + + std::map directJumpTargets; + std::vector indirectJumpTargets; + boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1))); + + splitPoints.insert(0); // First basic block + validJumpTargets[0] = true; + + for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) + { + ProgramCounter currentPC = curr - _bytecode.begin(); + validJumpTargets[currentPC] = true; + + auto inst = Instruction(*curr); + switch (inst) + { + + case Instruction::ANY_PUSH: + { + auto val = readPushData(curr, _bytecode.end()); + auto next = curr + 1; + if (next == _bytecode.end()) + break; + + auto nextInst = Instruction(*next); + if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) + { + // Create a block for the JUMP target. + ProgramCounter targetPC = val < _bytecode.size() ? val.convert_to() : _bytecode.size(); + splitPoints.insert(targetPC); + + ProgramCounter jumpPC = (next - _bytecode.begin()); + directJumpTargets[jumpPC] = targetPC; + } + break; + } + + case Instruction::JUMPDEST: + { + // A basic block starts at the next instruction. + if (currentPC + 1 < _bytecode.size()) + { + splitPoints.insert(currentPC + 1); + indirectJumpTargets.push_back(currentPC + 1); + } + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::RETURN: + case Instruction::STOP: + case Instruction::SUICIDE: + { + // Create a basic block starting at the following instruction. + if (curr + 1 < _bytecode.end()) + { + splitPoints.insert(currentPC + 1); + } + break; + } + + default: + break; + } + } + + // Remove split points generated from jumps out of code or into data. + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + if (*it > _bytecode.size() || !validJumpTargets[*it]) + it = splitPoints.erase(it); + else + ++it; + } + + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + auto beginInstIdx = *it; + ++it; + auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); + basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); + } + + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); + m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); + + for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) + { + if (it->second >= _bytecode.size()) + { + // Jumping out of code means STOP + m_directJumpTargets[it->first] = m_stopBB; + continue; + } + + auto blockIter = basicBlocks.find(it->second); + if (blockIter != basicBlocks.end()) + { + m_directJumpTargets[it->first] = blockIter->second.llvm(); + } + else + { + clog(JIT) << "Bad JUMP at PC " << it->first + << ": " << it->second << " is not a valid PC"; + m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); + } + } + + for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) + m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); +} + +std::unique_ptr Compiler::compile(bytesConstRef _bytecode) +{ + auto module = std::unique_ptr(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 + 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"); + + // Create the basic blocks. + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + m_builder.SetInsertPoint(entryBlock); + + createBasicBlocks(_bytecode); + + // Init runtime structures. + RuntimeManager runtimeManager(m_builder); + GasMeter gasMeter(m_builder, runtimeManager); + Memory memory(runtimeManager, gasMeter); + Ext ext(runtimeManager); + Stack stack(m_builder, runtimeManager); + Arith256 arith(m_builder); + + m_builder.CreateBr(basicBlocks.begin()->second); + + for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) + { + auto& basicBlock = basicBlockPairIt->second; + auto iterCopy = basicBlockPairIt; + ++iterCopy; + auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; + compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + } + + // Code for special blocks: + // TODO: move to separate function. + m_builder.SetInsertPoint(m_stopBB); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + if (m_indirectJumpTargets.size() > 0) + { + auto dest = m_jumpTableBlock->localStack().pop(); + 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; + auto dest = Constant::get(bb->begin()); + switchInstr->addCase(dest, bb->llvm()); + } + } + else + m_builder.CreateBr(m_badJumpBlock->llvm()); + + removeDeadBlocks(); + + dumpCFGifRequired("blocks-init.dot"); + + if (m_options.optimizeStack) + { + std::vector blockList; + for (auto& entry : basicBlocks) + blockList.push_back(&entry.second); + + if (m_jumpTableBlock) + blockList.push_back(m_jumpTableBlock.get()); + + BasicBlock::linkLocalStacks(blockList, m_builder); + + dumpCFGifRequired("blocks-opt.dot"); + } + + for (auto& entry : basicBlocks) + entry.second.localStack().synchronize(stack); + if (m_jumpTableBlock) + m_jumpTableBlock->localStack().synchronize(stack); + + dumpCFGifRequired("blocks-sync.dot"); + + if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) + { + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); + } + + return module; +} + + +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, RuntimeManager& _runtimeManager, + Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) +{ + if (!_nextBasicBlock) // this is the last block in the code + _nextBasicBlock = m_stopBB; + + m_builder.SetInsertPoint(_basicBlock.llvm()); + auto& stack = _basicBlock.localStack(); + + for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) + { + auto inst = static_cast(_bytecode[currentPC]); + + _gasMeter.count(inst); + + switch (inst) + { + + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::MUL: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.mul(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::DIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.div(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SDIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.sdiv(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::MOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.mod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.smod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::EXP: + { + auto left = stack.pop(); + auto right = stack.pop(); + auto ret = _ext.exp(left, right); + stack.push(ret); + break; + } + + case Instruction::BNOT: + { + auto value = stack.pop(); + auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); + stack.push(ret); + break; + } + + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpULT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpUGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSLT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpEQ(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::i256); + stack.push(res256); + break; + } + + case Instruction::NOT: + { + auto top = stack.pop(); + auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); + auto result = m_builder.CreateZExt(iszero, Type::i256); + stack.push(result); + break; + } + + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::BYTE: + { + const auto byteNum = stack.pop(); + auto value = stack.pop(); + + // + value = Endianness::toBE(m_builder, value); + auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); + auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); + value = m_builder.CreateZExt(byte, Type::i256); + + auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); + value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); + stack.push(value); + + break; + } + + case Instruction::ADDMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.addmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::MULMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.mulmod(lhs, rhs, mod); + stack.push(res); + 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(); + auto inSize = stack.pop(); + _memory.require(inOff, inSize); + auto hash = _ext.sha3(inOff, inSize); + stack.push(hash); + break; + } + + case Instruction::POP: + { + stack.pop(); + break; + } + + case Instruction::ANY_PUSH: + { + auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator + auto value = readPushData(curr, _bytecode.end()); + currentPC = curr - _bytecode.begin(); + + stack.push(Constant::get(value)); + break; + } + + case Instruction::ANY_DUP: + { + auto index = static_cast(inst) - static_cast(Instruction::DUP1); + stack.dup(index); + break; + } + + case Instruction::ANY_SWAP: + { + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; + stack.swap(index); + break; + } + + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = _memory.loadWord(addr); + stack.push(word); + break; + } + + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeWord(addr, word); + break; + } + + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeByte(addr, word); + break; + } + + case Instruction::MSIZE: + { + auto word = _memory.getSize(); + stack.push(word); + break; + } + + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = _ext.store(index); + stack.push(value); + break; + } + + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + _gasMeter.countSStore(_ext, index, value); + _ext.setStore(index, value); + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + { + // Generate direct jump iff: + // 1. this is not the first instruction in the block + // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) + // Otherwise generate a indirect jump (a switch). + llvm::BasicBlock* targetBlock = nullptr; + if (currentPC != _basicBlock.begin()) + { + auto pairIter = m_directJumpTargets.find(currentPC); + if (pairIter != m_directJumpTargets.end()) + targetBlock = pairIter->second; + } + + if (inst == Instruction::JUMP) + { + if (targetBlock) + { + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + m_builder.CreateBr(targetBlock); + } + else + m_builder.CreateBr(m_jumpTableBlock->llvm()); + } + else // JUMPI + { + stack.swap(1); + auto val = stack.pop(); + auto zero = Constant::get(0); + auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); + + if (targetBlock) + { + stack.pop(); + m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); + } + else + m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); + } + + break; + } + + case Instruction::JUMPDEST: + { + // Nothing to do + break; + } + + case Instruction::PC: + { + auto value = Constant::get(currentPC); + stack.push(value); + break; + } + + case Instruction::GAS: + case Instruction::ADDRESS: + case Instruction::CALLER: + case Instruction::ORIGIN: + case Instruction::CALLVALUE: + case Instruction::CALLDATASIZE: + case Instruction::CODESIZE: + case Instruction::GASPRICE: + case Instruction::PREVHASH: + case Instruction::COINBASE: + case Instruction::TIMESTAMP: + case Instruction::NUMBER: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + { + // Pushes an element of runtime data on stack + stack.push(_runtimeManager.get(inst)); + break; + } + + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = _ext.balance(address); + stack.push(value); + break; + } + + case Instruction::EXTCODESIZE: + { + auto addr = stack.pop(); + auto value = _ext.codesizeAt(addr); + stack.push(value); + break; + } + + case Instruction::CALLDATACOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCallData(); + auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CODECOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + 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); + break; + } + + case Instruction::EXTCODECOPY: + { + auto extAddr = stack.pop(); + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _ext.codeAt(extAddr); + auto srcSize = _ext.codesizeAt(extAddr); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = _ext.calldataload(index); + stack.push(value); + break; + } + + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); + _memory.require(initOff, initSize); + + auto address = _ext.create(endowment, initOff, initSize); + stack.push(address); + break; + } + + case Instruction::CALL: + case Instruction::CALLCODE: + { + auto gas = stack.pop(); + auto codeAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + _gasMeter.commitCostBlock(gas); + +<<<<<<< HEAD + // Require _memory for the max of in and out buffers + auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); + auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); + auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); + auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); + _memory.require(sizeReq); +======= + // Require memory for in and out buffers + memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one + memory.require(inOff, inSize); +>>>>>>> ec07859aedd18ebfd9b40cfa2a182e49c5b3f30a + + auto receiveAddress = codeAddress; + if (inst == Instruction::CALLCODE) + receiveAddress = _runtimeManager.get(RuntimeData::Address); + + auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gas); + stack.push(ret); + break; + } + + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); + + _memory.require(index, size); + _runtimeManager.registerReturnData(index, size); + + m_builder.CreateRet(Constant::get(ReturnCode::Return)); + break; + } + + case Instruction::SUICIDE: + case Instruction::STOP: + { + if (inst == Instruction::SUICIDE) + { + auto address = stack.pop(); + _ext.suicide(address); + } + + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + break; + } + + default: // Invalid instruction - runtime exception + { + _runtimeManager.raiseException(ReturnCode::BadInstruction); + } + + } + } + + _gasMeter.commitCostBlock(); + + // Block may have no terminator if the next instruction is a jump destination. + if (!_basicBlock.llvm()->getTerminator()) + m_builder.CreateBr(_nextBasicBlock); +} + + + +void Compiler::removeDeadBlocks() +{ + // Remove dead basic blocks + auto sthErased = false; + do + { + sthErased = false; + for (auto it = basicBlocks.begin(); it != basicBlocks.end();) + { + auto llvmBB = it->second.llvm(); + if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) + { + llvmBB->eraseFromParent(); + basicBlocks.erase(it++); + sthErased = true; + } + else + ++it; + } + } + while (sthErased); + + // Remove jump table block if no predecessors + if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } +} + +void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) +{ + if (! m_options.dumpCFG) + return; + + // TODO: handle i/o failures + std::ofstream ofs(_dotfilePath); + dumpCFGtoStream(ofs); + ofs.close(); +} + +void Compiler::dumpCFGtoStream(std::ostream& _out) +{ + _out << "digraph BB {\n" + << " node [shape=record, fontname=Courier, fontsize=10];\n" + << " entry [share=record, label=\"entry block\"];\n"; + + std::vector blocks; + for (auto& pair : basicBlocks) + blocks.push_back(&pair.second); + if (m_jumpTableBlock) + blocks.push_back(m_jumpTableBlock.get()); + if (m_badJumpBlock) + blocks.push_back(m_badJumpBlock.get()); + + // std::map phiNodesPerBlock; + + // Output nodes + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + std::ostringstream oss; + bb->dump(oss, true); + + _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; + } + + // Output edges + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + auto end = llvm::pred_end(bb->llvm()); + 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, " : "") + << "];\n"; + } + } + + _out << "}\n"; +} + +void Compiler::dump() +{ + for (auto& entry : basicBlocks) + entry.second.dump(); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->dump(); +} + +} +} +} + diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index d58745a06..12b7f6e0e 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -18,55 +18,70 @@ class Compiler { public: - using ProgramCounter = uint64_t; + struct Options + { + /// Optimize stack operations between basic blocks + bool optimizeStack; + + /// Rewrite switch instructions to sequences of branches + bool rewriteSwitchToBranches; - Compiler(); + /// Dump CFG as a .dot file for graphviz + bool dumpCFG; - std::unique_ptr compile(bytesConstRef bytecode); + Options(): + optimizeStack(true), + rewriteSwitchToBranches(true), + dumpCFG(false) + {} + }; + + using ProgramCounter = uint64_t; - void dumpBasicBlockGraph(std::ostream& out); + Compiler(Options const& _options); + std::unique_ptr compile(bytesConstRef _bytecode); private: - void createBasicBlocks(bytesConstRef bytecode); + void createBasicBlocks(bytesConstRef _bytecode); - void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class RuntimeManager& _runtimeManager, class Arith256& arith, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); + void compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); void removeDeadBlocks(); - /// Dump all basic blocks to stderr. Useful in a debugging session. + /// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled. + void dumpCFGifRequired(std::string const& _dotfilePath); + + /// Dumps basic block graph in graphviz format to a stream. + void dumpCFGtoStream(std::ostream& _out); + + /// Dumps all basic blocks to stderr. Useful in a debugging session. void dump(); + /// Compiler options + Options const& m_options; + + /// Helper class for generating IR llvm::IRBuilder<> m_builder; - /** - * Maps a program counter pc to a basic block that starts at pc (if any). - */ - std::map basicBlocks; + /// Maps a program counter pc to a basic block that starts at pc (if any). + std::map basicBlocks = {}; - /** - * Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. - */ - std::map m_directJumpTargets; + /// Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. + std::map m_directJumpTargets = {}; - /** - * A list of possible blocks to which there may be indirect jumps. - */ - std::vector m_indirectJumpTargets; + /// A list of possible blocks to which there may be indirect jumps. + std::vector m_indirectJumpTargets = {}; /// Stop basic block - terminates execution with STOP code (0) llvm::BasicBlock* m_stopBB = nullptr; - /** - * Block with a jump table. - */ - std::unique_ptr m_jumpTableBlock; + /// Block with a jump table. + std::unique_ptr m_jumpTableBlock = nullptr; - /** - * Default destination for indirect jumps. - */ - std::unique_ptr m_badJumpBlock; + /// Default destination for indirect jumps. + std::unique_ptr m_badJumpBlock = nullptr; /// Main program function llvm::Function* m_mainFunc = nullptr; diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index b42b09499..f60dbe783 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -16,7 +16,8 @@ namespace jit bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) { - auto module = Compiler().compile(_ext.code); + Compiler::Options defaultOptions; + auto module = Compiler(defaultOptions).compile(_ext.code); ExecutionEngine engine; auto exitCode = engine.run(std::move(module), m_gas, &_ext); From 11d78d44b13c34c8121cd5e9e48052cca24944cf Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 15:46:44 +0000 Subject: [PATCH 311/396] removed *.orig file --- libevmjit/Compiler.cpp.orig | 924 ------------------------------------ 1 file changed, 924 deletions(-) delete mode 100644 libevmjit/Compiler.cpp.orig diff --git a/libevmjit/Compiler.cpp.orig b/libevmjit/Compiler.cpp.orig deleted file mode 100644 index 9c6043ff2..000000000 --- a/libevmjit/Compiler.cpp.orig +++ /dev/null @@ -1,924 +0,0 @@ - -#include "Compiler.h" - -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include "Type.h" -#include "Memory.h" -#include "Stack.h" -#include "Ext.h" -#include "GasMeter.h" -#include "Utils.h" -#include "Endianness.h" -#include "Arith256.h" -#include "Runtime.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Compiler::Compiler(Options const& _options): - m_options(_options), - m_builder(llvm::getGlobalContext()) -{ - Type::init(m_builder.getContext()); -} - -void Compiler::createBasicBlocks(bytesConstRef _bytecode) -{ - std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end - - std::map directJumpTargets; - std::vector indirectJumpTargets; - boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1))); - - splitPoints.insert(0); // First basic block - validJumpTargets[0] = true; - - for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) - { - ProgramCounter currentPC = curr - _bytecode.begin(); - validJumpTargets[currentPC] = true; - - auto inst = Instruction(*curr); - switch (inst) - { - - case Instruction::ANY_PUSH: - { - auto val = readPushData(curr, _bytecode.end()); - auto next = curr + 1; - if (next == _bytecode.end()) - break; - - auto nextInst = Instruction(*next); - if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) - { - // Create a block for the JUMP target. - ProgramCounter targetPC = val < _bytecode.size() ? val.convert_to() : _bytecode.size(); - splitPoints.insert(targetPC); - - ProgramCounter jumpPC = (next - _bytecode.begin()); - directJumpTargets[jumpPC] = targetPC; - } - break; - } - - case Instruction::JUMPDEST: - { - // A basic block starts at the next instruction. - if (currentPC + 1 < _bytecode.size()) - { - splitPoints.insert(currentPC + 1); - indirectJumpTargets.push_back(currentPC + 1); - } - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - case Instruction::RETURN: - case Instruction::STOP: - case Instruction::SUICIDE: - { - // Create a basic block starting at the following instruction. - if (curr + 1 < _bytecode.end()) - { - splitPoints.insert(currentPC + 1); - } - break; - } - - default: - break; - } - } - - // Remove split points generated from jumps out of code or into data. - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - if (*it > _bytecode.size() || !validJumpTargets[*it]) - it = splitPoints.erase(it); - else - ++it; - } - - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - auto beginInstIdx = *it; - ++it; - auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); - basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); - } - - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); - m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); - - for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) - { - if (it->second >= _bytecode.size()) - { - // Jumping out of code means STOP - m_directJumpTargets[it->first] = m_stopBB; - continue; - } - - auto blockIter = basicBlocks.find(it->second); - if (blockIter != basicBlocks.end()) - { - m_directJumpTargets[it->first] = blockIter->second.llvm(); - } - else - { - clog(JIT) << "Bad JUMP at PC " << it->first - << ": " << it->second << " is not a valid PC"; - m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); - } - } - - for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); -} - -std::unique_ptr Compiler::compile(bytesConstRef _bytecode) -{ - auto module = std::unique_ptr(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 - 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"); - - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); - m_builder.SetInsertPoint(entryBlock); - - createBasicBlocks(_bytecode); - - // Init runtime structures. - RuntimeManager runtimeManager(m_builder); - GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(runtimeManager, gasMeter); - Ext ext(runtimeManager); - Stack stack(m_builder, runtimeManager); - Arith256 arith(m_builder); - - m_builder.CreateBr(basicBlocks.begin()->second); - - for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) - { - auto& basicBlock = basicBlockPairIt->second; - auto iterCopy = basicBlockPairIt; - ++iterCopy; - auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); - } - - // Code for special blocks: - // TODO: move to separate function. - m_builder.SetInsertPoint(m_stopBB); - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - - m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); - - m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - if (m_indirectJumpTargets.size() > 0) - { - auto dest = m_jumpTableBlock->localStack().pop(); - 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; - auto dest = Constant::get(bb->begin()); - switchInstr->addCase(dest, bb->llvm()); - } - } - else - m_builder.CreateBr(m_badJumpBlock->llvm()); - - removeDeadBlocks(); - - dumpCFGifRequired("blocks-init.dot"); - - if (m_options.optimizeStack) - { - std::vector blockList; - for (auto& entry : basicBlocks) - blockList.push_back(&entry.second); - - if (m_jumpTableBlock) - blockList.push_back(m_jumpTableBlock.get()); - - BasicBlock::linkLocalStacks(blockList, m_builder); - - dumpCFGifRequired("blocks-opt.dot"); - } - - for (auto& entry : basicBlocks) - entry.second.localStack().synchronize(stack); - if (m_jumpTableBlock) - m_jumpTableBlock->localStack().synchronize(stack); - - dumpCFGifRequired("blocks-sync.dot"); - - if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) - { - llvm::FunctionPassManager fpManager(module.get()); - fpManager.add(llvm::createLowerSwitchPass()); - fpManager.doInitialization(); - fpManager.run(*m_mainFunc); - } - - return module; -} - - -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, RuntimeManager& _runtimeManager, - Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) -{ - if (!_nextBasicBlock) // this is the last block in the code - _nextBasicBlock = m_stopBB; - - m_builder.SetInsertPoint(_basicBlock.llvm()); - auto& stack = _basicBlock.localStack(); - - for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) - { - auto inst = static_cast(_bytecode[currentPC]); - - _gasMeter.count(inst); - - switch (inst) - { - - case Instruction::ADD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateAdd(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::SUB: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateSub(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::MUL: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.mul(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::DIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.div(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SDIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.sdiv(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::MOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.mod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.smod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::EXP: - { - auto left = stack.pop(); - auto right = stack.pop(); - auto ret = _ext.exp(left, right); - stack.push(ret); - break; - } - - case Instruction::BNOT: - { - auto value = stack.pop(); - auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); - stack.push(ret); - break; - } - - case Instruction::LT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpULT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::GT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpUGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::SLT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSLT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::SGT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::EQ: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpEQ(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::i256); - stack.push(res256); - break; - } - - case Instruction::NOT: - { - auto top = stack.pop(); - auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); - auto result = m_builder.CreateZExt(iszero, Type::i256); - stack.push(result); - break; - } - - case Instruction::AND: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateAnd(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::OR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateOr(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::XOR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateXor(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::BYTE: - { - const auto byteNum = stack.pop(); - auto value = stack.pop(); - - // - value = Endianness::toBE(m_builder, value); - auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); - auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); - value = m_builder.CreateZExt(byte, Type::i256); - - auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); - value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); - stack.push(value); - - break; - } - - case Instruction::ADDMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = _arith.addmod(lhs, rhs, mod); - stack.push(res); - break; - } - - case Instruction::MULMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = _arith.mulmod(lhs, rhs, mod); - stack.push(res); - 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(); - auto inSize = stack.pop(); - _memory.require(inOff, inSize); - auto hash = _ext.sha3(inOff, inSize); - stack.push(hash); - break; - } - - case Instruction::POP: - { - stack.pop(); - break; - } - - case Instruction::ANY_PUSH: - { - auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator - auto value = readPushData(curr, _bytecode.end()); - currentPC = curr - _bytecode.begin(); - - stack.push(Constant::get(value)); - break; - } - - case Instruction::ANY_DUP: - { - auto index = static_cast(inst) - static_cast(Instruction::DUP1); - stack.dup(index); - break; - } - - case Instruction::ANY_SWAP: - { - auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; - stack.swap(index); - break; - } - - case Instruction::MLOAD: - { - auto addr = stack.pop(); - auto word = _memory.loadWord(addr); - stack.push(word); - break; - } - - case Instruction::MSTORE: - { - auto addr = stack.pop(); - auto word = stack.pop(); - _memory.storeWord(addr, word); - break; - } - - case Instruction::MSTORE8: - { - auto addr = stack.pop(); - auto word = stack.pop(); - _memory.storeByte(addr, word); - break; - } - - case Instruction::MSIZE: - { - auto word = _memory.getSize(); - stack.push(word); - break; - } - - case Instruction::SLOAD: - { - auto index = stack.pop(); - auto value = _ext.store(index); - stack.push(value); - break; - } - - case Instruction::SSTORE: - { - auto index = stack.pop(); - auto value = stack.pop(); - _gasMeter.countSStore(_ext, index, value); - _ext.setStore(index, value); - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - { - // Generate direct jump iff: - // 1. this is not the first instruction in the block - // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) - // Otherwise generate a indirect jump (a switch). - llvm::BasicBlock* targetBlock = nullptr; - if (currentPC != _basicBlock.begin()) - { - auto pairIter = m_directJumpTargets.find(currentPC); - if (pairIter != m_directJumpTargets.end()) - targetBlock = pairIter->second; - } - - if (inst == Instruction::JUMP) - { - if (targetBlock) - { - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); - m_builder.CreateBr(targetBlock); - } - else - m_builder.CreateBr(m_jumpTableBlock->llvm()); - } - else // JUMPI - { - stack.swap(1); - auto val = stack.pop(); - auto zero = Constant::get(0); - auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - - if (targetBlock) - { - stack.pop(); - m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); - } - else - m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); - } - - break; - } - - case Instruction::JUMPDEST: - { - // Nothing to do - break; - } - - case Instruction::PC: - { - auto value = Constant::get(currentPC); - stack.push(value); - break; - } - - case Instruction::GAS: - case Instruction::ADDRESS: - case Instruction::CALLER: - case Instruction::ORIGIN: - case Instruction::CALLVALUE: - case Instruction::CALLDATASIZE: - case Instruction::CODESIZE: - case Instruction::GASPRICE: - case Instruction::PREVHASH: - case Instruction::COINBASE: - case Instruction::TIMESTAMP: - case Instruction::NUMBER: - case Instruction::DIFFICULTY: - case Instruction::GASLIMIT: - { - // Pushes an element of runtime data on stack - stack.push(_runtimeManager.get(inst)); - break; - } - - case Instruction::BALANCE: - { - auto address = stack.pop(); - auto value = _ext.balance(address); - stack.push(value); - break; - } - - case Instruction::EXTCODESIZE: - { - auto addr = stack.pop(); - auto value = _ext.codesizeAt(addr); - stack.push(value); - break; - } - - case Instruction::CALLDATACOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _runtimeManager.getCallData(); - auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); - - _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CODECOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - 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); - break; - } - - case Instruction::EXTCODECOPY: - { - auto extAddr = stack.pop(); - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _ext.codeAt(extAddr); - auto srcSize = _ext.codesizeAt(extAddr); - - _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CALLDATALOAD: - { - auto index = stack.pop(); - auto value = _ext.calldataload(index); - stack.push(value); - break; - } - - case Instruction::CREATE: - { - auto endowment = stack.pop(); - auto initOff = stack.pop(); - auto initSize = stack.pop(); - _memory.require(initOff, initSize); - - auto address = _ext.create(endowment, initOff, initSize); - stack.push(address); - break; - } - - case Instruction::CALL: - case Instruction::CALLCODE: - { - auto gas = stack.pop(); - auto codeAddress = stack.pop(); - auto value = stack.pop(); - auto inOff = stack.pop(); - auto inSize = stack.pop(); - auto outOff = stack.pop(); - auto outSize = stack.pop(); - - _gasMeter.commitCostBlock(gas); - -<<<<<<< HEAD - // Require _memory for the max of in and out buffers - auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq"); - auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq"); - auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq); - auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq"); - _memory.require(sizeReq); -======= - // Require memory for in and out buffers - memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one - memory.require(inOff, inSize); ->>>>>>> ec07859aedd18ebfd9b40cfa2a182e49c5b3f30a - - auto receiveAddress = codeAddress; - if (inst == Instruction::CALLCODE) - receiveAddress = _runtimeManager.get(RuntimeData::Address); - - auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gas); - stack.push(ret); - break; - } - - case Instruction::RETURN: - { - auto index = stack.pop(); - auto size = stack.pop(); - - _memory.require(index, size); - _runtimeManager.registerReturnData(index, size); - - m_builder.CreateRet(Constant::get(ReturnCode::Return)); - break; - } - - case Instruction::SUICIDE: - case Instruction::STOP: - { - if (inst == Instruction::SUICIDE) - { - auto address = stack.pop(); - _ext.suicide(address); - } - - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - break; - } - - default: // Invalid instruction - runtime exception - { - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - - } - } - - _gasMeter.commitCostBlock(); - - // Block may have no terminator if the next instruction is a jump destination. - if (!_basicBlock.llvm()->getTerminator()) - m_builder.CreateBr(_nextBasicBlock); -} - - - -void Compiler::removeDeadBlocks() -{ - // Remove dead basic blocks - auto sthErased = false; - do - { - sthErased = false; - for (auto it = basicBlocks.begin(); it != basicBlocks.end();) - { - auto llvmBB = it->second.llvm(); - if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) - { - llvmBB->eraseFromParent(); - basicBlocks.erase(it++); - sthErased = true; - } - else - ++it; - } - } - while (sthErased); - - // Remove jump table block if no predecessors - if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) - { - m_jumpTableBlock->llvm()->eraseFromParent(); - m_jumpTableBlock.reset(); - } -} - -void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) -{ - if (! m_options.dumpCFG) - return; - - // TODO: handle i/o failures - std::ofstream ofs(_dotfilePath); - dumpCFGtoStream(ofs); - ofs.close(); -} - -void Compiler::dumpCFGtoStream(std::ostream& _out) -{ - _out << "digraph BB {\n" - << " node [shape=record, fontname=Courier, fontsize=10];\n" - << " entry [share=record, label=\"entry block\"];\n"; - - std::vector blocks; - for (auto& pair : basicBlocks) - blocks.push_back(&pair.second); - if (m_jumpTableBlock) - blocks.push_back(m_jumpTableBlock.get()); - if (m_badJumpBlock) - blocks.push_back(m_badJumpBlock.get()); - - // std::map phiNodesPerBlock; - - // Output nodes - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - std::ostringstream oss; - bb->dump(oss, true); - - _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; - } - - // Output edges - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - auto end = llvm::pred_end(bb->llvm()); - 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, " : "") - << "];\n"; - } - } - - _out << "}\n"; -} - -void Compiler::dump() -{ - for (auto& entry : basicBlocks) - entry.second.dump(); - if (m_jumpTableBlock != nullptr) - m_jumpTableBlock->dump(); -} - -} -} -} - From 683f956a2e6d08e4e99560766704acd7f118b249 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 15:47:36 +0000 Subject: [PATCH 312/396] added struct for compiler options --- evmcc/evmcc.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 047fdf252..191b87dcf 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -101,7 +101,10 @@ int main(int argc, char** argv) { auto compilationStartTime = std::chrono::high_resolution_clock::now(); - auto compiler = eth::jit::Compiler(); + eth::jit::Compiler::Options options; + options.dumpCFG = opt_dump_graph; + + auto compiler = eth::jit::Compiler(options); auto module = compiler.compile({bytecode.data(), bytecode.size()}); auto compilationEndTime = std::chrono::high_resolution_clock::now(); @@ -115,14 +118,6 @@ int main(int argc, char** argv) << std::endl; } - if (opt_dump_graph) - { - std::ofstream ofs("blocks.dot"); - compiler.dumpBasicBlockGraph(ofs); - ofs.close(); - std::cout << "Basic blocks graph written to block.dot\n"; - } - if (opt_interpret) { auto engine = eth::jit::ExecutionEngine(); From e756b4ae1e7921960c0b3592a878403953558e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 31 Oct 2014 16:59:21 +0100 Subject: [PATCH 313/396] Rename BNOT -> NOT, NOT -> ISZERO --- libevmjit/Compiler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 39c9edc7c..51b1ee403 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -342,7 +342,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod break; } - case Instruction::BNOT: + case Instruction::NOT: { auto value = stack.pop(); auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); @@ -400,7 +400,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod break; } - case Instruction::NOT: + case Instruction::ISZERO: { auto top = stack.pop(); auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); From 1c9fb4acb726a851106b1a471e9e7136218470af Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 3 Nov 2014 10:31:09 +0000 Subject: [PATCH 314/396] 1) JUMP/I semantics updated. 2) Members of BasicBlock::LocalStack pulled out to BasicBlock --- libevmjit/BasicBlock.cpp | 142 ++++++++++++++++++++------------------- libevmjit/BasicBlock.h | 59 +++++++--------- libevmjit/Compiler.cpp | 15 ++--- 3 files changed, 102 insertions(+), 114 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 0c604f1b3..1cc0e13fd 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -26,38 +26,36 @@ BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, m_beginInstIdx(_beginInstIdx), m_endInstIdx(_endInstIdx), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)), - m_stack(_builder, m_llvmBB) + m_stack(*this), + m_builder(_builder) {} BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : m_beginInstIdx(0), m_endInstIdx(0), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), - m_stack(_builder, m_llvmBB) + m_stack(*this), + m_builder(_builder) {} -BasicBlock::LocalStack::LocalStack(llvm::IRBuilder<>& _builder, llvm::BasicBlock* _llvmBB) : - m_llvmBB(_llvmBB), - m_builder(_builder), - m_initialStack(), - m_currentStack(), - m_tosOffset(0) +BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : + m_bblock(_owner) {} void BasicBlock::LocalStack::push(llvm::Value* _value) { - m_currentStack.push_back(_value); - m_tosOffset += 1; + m_bblock.m_currentStack.push_back(_value); + m_bblock.m_tosOffset += 1; } llvm::Value* BasicBlock::LocalStack::pop() { auto result = get(0); - if (m_currentStack.size() > 0) - m_currentStack.pop_back(); + if (m_bblock.m_currentStack.size() > 0) + m_bblock.m_currentStack.pop_back(); - m_tosOffset -= 1; + m_bblock.m_tosOffset -= 1; return result; } @@ -83,7 +81,56 @@ void BasicBlock::LocalStack::swap(size_t _index) set(0, val); } -void BasicBlock::LocalStack::synchronize(Stack& _evmStack) +std::vector::iterator BasicBlock::LocalStack::getItemIterator(size_t _index) +{ + auto& currentStack = m_bblock.m_currentStack; + if (_index < currentStack.size()) + return currentStack.end() - _index - 1; + + // Need to map more elements from the EVM stack + auto nNewItems = 1 + _index - currentStack.size(); + currentStack.insert(currentStack.begin(), nNewItems, nullptr); + + return currentStack.end() - _index - 1; +} + +llvm::Value* BasicBlock::LocalStack::get(size_t _index) +{ + auto& initialStack = m_bblock.m_initialStack; + auto itemIter = getItemIterator(_index); + + if (*itemIter == nullptr) + { + // Need to fetch a new item from the EVM stack + assert(static_cast(_index) >= m_bblock.m_tosOffset); + size_t initialIdx = _index - m_bblock.m_tosOffset; + if (initialIdx >= initialStack.size()) + { + auto nNewItems = 1 + initialIdx - initialStack.size(); + initialStack.insert(initialStack.end(), nNewItems, nullptr); + } + + assert(initialStack[initialIdx] == nullptr); + // Create a dummy value. + std::string name = "get_" + boost::lexical_cast(_index); + initialStack[initialIdx] = m_bblock.m_builder.CreatePHI(Type::Word, 0, name); + *itemIter = initialStack[initialIdx]; + } + + return *itemIter; +} + +void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word) +{ + auto itemIter = getItemIterator(_index); + *itemIter = _word; +} + + + + + +void BasicBlock::synchronizeLocalStack(Stack& _evmStack) { auto blockTerminator = m_llvmBB->getTerminator(); assert(blockTerminator != nullptr); @@ -141,51 +188,6 @@ void BasicBlock::LocalStack::synchronize(Stack& _evmStack) m_tosOffset = 0; } -std::vector::iterator BasicBlock::LocalStack::getItemIterator(size_t _index) -{ - if (_index < m_currentStack.size()) - return m_currentStack.end() - _index - 1; - - // Need to map more elements from the EVM stack - auto nNewItems = 1 + _index - m_currentStack.size(); - m_currentStack.insert(m_currentStack.begin(), nNewItems, nullptr); - - return m_currentStack.end() - _index - 1; -} - -llvm::Value* BasicBlock::LocalStack::get(size_t _index) -{ - auto itemIter = getItemIterator(_index); - - if (*itemIter == nullptr) - { - // Need to fetch a new item from the EVM stack - assert(static_cast(_index) >= m_tosOffset); - size_t initialIdx = _index - m_tosOffset; - if (initialIdx >= m_initialStack.size()) - { - auto nNewItems = 1 + initialIdx - m_initialStack.size(); - m_initialStack.insert(m_initialStack.end(), nNewItems, nullptr); - } - - assert(m_initialStack[initialIdx] == nullptr); - // Create a dummy value. - std::string name = "get_" + boost::lexical_cast(_index); - m_initialStack[initialIdx] = m_builder.CreatePHI(Type::Word, 0, name); - *itemIter = m_initialStack[initialIdx]; - } - - return *itemIter; -} - -void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word) -{ - auto itemIter = getItemIterator(_index); - *itemIter = _word; -} - - - void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRBuilder<>& _builder) { struct BBInfo @@ -202,14 +204,14 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB inputItems(0), outputItems(0) { - auto& initialStack = bblock.localStack().m_initialStack; + auto& initialStack = bblock.m_initialStack; for (auto it = initialStack.begin(); it != initialStack.end() && *it != nullptr; ++it, ++inputItems); //if (bblock.localStack().m_tosOffset > 0) // outputItems = bblock.localStack().m_tosOffset; - auto& exitStack = bblock.localStack().m_currentStack; + auto& exitStack = bblock.m_currentStack; for (auto it = exitStack.rbegin(); it != exitStack.rend() && *it != nullptr; ++it, ++outputItems); @@ -281,7 +283,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& bblock = info.bblock; llvm::BasicBlock::iterator fstNonPhi(bblock.llvm()->getFirstNonPHI()); - auto phiIter = bblock.localStack().m_initialStack.begin(); + auto phiIter = bblock.m_initialStack.begin(); for (size_t index = 0; index < info.inputItems; ++index, ++phiIter) { assert(llvm::isa(*phiIter)); @@ -289,7 +291,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB for (auto predIt : info.predecessors) { - auto& predExitStack = predIt->bblock.localStack().m_currentStack; + auto& predExitStack = predIt->bblock.m_currentStack; auto value = *(predExitStack.end() - 1 - index); phi->addIncoming(value, predIt->bblock.llvm()); } @@ -305,10 +307,10 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB // The items pulled directly from predecessors block must be removed // from the list of items that has to be popped from the initial stack. - auto& initialStack = bblock.localStack().m_initialStack; + auto& initialStack = bblock.m_initialStack; initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); // Initial stack shrinks, so the size difference grows: - bblock.localStack().m_tosOffset += info.inputItems; + bblock.m_tosOffset += info.inputItems; } // We must account for the items that were pushed directly to successor @@ -319,9 +321,9 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& info = entry.second; auto& bblock = info.bblock; - auto& exitStack = bblock.localStack().m_currentStack; + auto& exitStack = bblock.m_currentStack; exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); - bblock.localStack().m_tosOffset -= info.outputItems; + bblock.m_tosOffset -= info.outputItems; } } @@ -335,7 +337,7 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput) llvm::raw_os_ostream out(_out); out << (_dotOutput ? "" : "Initial stack:\n"); - for (auto val : m_stack.m_initialStack) + for (auto val : m_initialStack) { if (val == nullptr) out << " ?"; @@ -352,11 +354,11 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput) out << *ins << (_dotOutput ? "\\l" : "\n"); if (! _dotOutput) - out << "Current stack (offset = " << m_stack.m_tosOffset << "):\n"; + out << "Current stack (offset = " << m_tosOffset << "):\n"; else out << "|"; - for (auto val = m_stack.m_currentStack.rbegin(); val != m_stack.m_currentStack.rend(); ++val) + for (auto val = m_currentStack.rbegin(); val != m_currentStack.rend(); ++val) { if (*val == nullptr) out << " ?"; diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index ffa9ca109..f0643f342 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -21,7 +21,6 @@ public: class LocalStack { public: - /// Pushes value on stack void push(llvm::Value* _value); @@ -35,12 +34,8 @@ public: /// @param _index Index of value to be swaped. Must be > 0. void swap(size_t _index); - /// Synchronize current local stack with the EVM stack. - void synchronize(Stack& _evmStack); - private: - - LocalStack(llvm::IRBuilder<>& _builder, llvm::BasicBlock* _llvmBB); + LocalStack(BasicBlock& _owner); LocalStack(LocalStack const&) = delete; void operator=(LocalStack const&) = delete; friend BasicBlock; @@ -54,34 +49,7 @@ public: std::vector::iterator getItemIterator(size_t _index); private: - - llvm::BasicBlock* m_llvmBB; - - llvm::IRBuilder<>& m_builder; - - /** - * This stack contains LLVM values that correspond to items found at - * the EVM stack when the current basic block starts executing. - * Location 0 corresponds to the top of the EVM stack, location 1 is - * the item below the top and so on. The stack grows as the code - * accesses more items on the EVM stack but once a value is put on - * the stack, it will never be replaced. - */ - std::vector m_initialStack; - - /** - * This stack tracks the contents of the EVM stack as the current basic - * block executes. It may grow on both sides, as the code pushes items on - * top of the stack or changes existing items. - */ - std::vector m_currentStack; - - /** - * How many items higher is the current stack than the initial one. - * May be negative. - */ - int m_tosOffset; - + BasicBlock& m_bblock; }; /// Basic block name prefix. The rest is beging instruction index. @@ -105,6 +73,9 @@ public: /// to avoid excessive pushing/popping on the EVM stack. static void linkLocalStacks(std::vector _basicBlocks, llvm::IRBuilder<>& _builder); + /// Synchronize current local stack with the EVM stack. + void synchronizeLocalStack(Stack& _evmStack); + /// Prints local stack and block instructions to stderr. /// Useful for calling in a debugger session. void dump(); @@ -113,11 +84,31 @@ public: private: ProgramCounter const m_beginInstIdx; ProgramCounter const m_endInstIdx; + llvm::BasicBlock* const m_llvmBB; /// Basic black state vector (stack) - current/end values and their positions on stack /// @internal Must be AFTER m_llvmBB LocalStack m_stack; + + llvm::IRBuilder<>& m_builder; + + /// This stack contains LLVM values that correspond to items found at + /// the EVM stack when the current basic block starts executing. + /// Location 0 corresponds to the top of the EVM stack, location 1 is + /// the item below the top and so on. The stack grows as the code + /// accesses more items on the EVM stack but once a value is put on + /// the stack, it will never be replaced. + std::vector m_initialStack = {}; + + /// This stack tracks the contents of the EVM stack as the basic block + /// executes. It may grow on both sides, as the code pushes items on + /// top of the stack or changes existing items. + std::vector m_currentStack = {}; + + /// How many items higher is the current stack than the initial one. + /// May be negative. + int m_tosOffset = 0; }; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 51b1ee403..295f3a131 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -81,12 +81,9 @@ void Compiler::createBasicBlocks(bytesConstRef _bytecode) case Instruction::JUMPDEST: { - // A basic block starts at the next instruction. - if (currentPC + 1 < _bytecode.size()) - { - splitPoints.insert(currentPC + 1); - indirectJumpTargets.push_back(currentPC + 1); - } + // A basic block starts here. + splitPoints.insert(currentPC); + indirectJumpTargets.push_back(currentPC); break; } @@ -98,9 +95,7 @@ void Compiler::createBasicBlocks(bytesConstRef _bytecode) { // Create a basic block starting at the following instruction. if (curr + 1 < _bytecode.end()) - { splitPoints.insert(currentPC + 1); - } break; } @@ -234,9 +229,9 @@ std::unique_ptr Compiler::compile(bytesConstRef _bytecode) } for (auto& entry : basicBlocks) - entry.second.localStack().synchronize(stack); + entry.second.synchronizeLocalStack(stack); if (m_jumpTableBlock) - m_jumpTableBlock->localStack().synchronize(stack); + m_jumpTableBlock->synchronizeLocalStack(stack); dumpCFGifRequired("blocks-sync.dot"); From f8a577989140f69518b34e50f442f8dbdac65496 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 3 Nov 2014 10:31:34 +0000 Subject: [PATCH 315/396] unused var removed --- libevmjit/Runtime.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 96a5f75a3..982dd9f36 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -105,7 +105,6 @@ bytesConstRef Runtime::getReturnData() const RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) { m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt"); - llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); // Export data From fe303b4013790e65f9618b406a3b877cdccddd08 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 3 Nov 2014 16:04:31 +0000 Subject: [PATCH 316/396] (1) Handling evmcc options with boost::program_options. (2) Writing out .ll and .bc files --- evmcc/CMakeLists.txt | 5 +- evmcc/evmcc.cpp | 166 +++++++++++++++++++++++++++---------------- 2 files changed, 109 insertions(+), 62 deletions(-) diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index 230013aef..488893509 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -8,6 +8,7 @@ set(EXECUTABLE evmcc) add_executable(${EXECUTABLE} ${SRC_LIST}) +target_link_libraries(${EXECUTABLE} boost_program_options) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethereum) @@ -40,8 +41,8 @@ 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 bitwriter) +target_link_libraries(evmcc ${llvm_libs}) # end of LLVM specific commands diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 191b87dcf..535a9aed9 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -7,6 +7,10 @@ #include #include +#include + +#include +#include #include #include @@ -15,67 +19,76 @@ #include -void show_usage() +void parseProgramOptions(int _argc, char** _argv, boost::program_options::variables_map& _varMap) { - // FIXME: Use arg[0] as program name? - std::cerr << "usage: evmcc (-b|-c|-d)+ \n"; -} + namespace opt = boost::program_options; + + opt::options_description explicitOpts("Allowed options"); + explicitOpts.add_options() + ("help,h", "show usage information") + ("compile,c", "compile the code to LLVM IR") + ("interpret,i", "compile the code to LLVM IR and execute") + ("gas,g", opt::value(), "set initial gas for execution") + ("disassemble,d", "dissassemble the code") + ("dump-cfg", "dump control flow graph to graphviz file") + ("optimize-stack,os", "optimize stack use between basic blocks") + ("output-ll", opt::value(), "dump generated LLVM IR to file") + ("output-bc", opt::value(), "dump generated LLVM bitcode to file") + ("verbose,V", "enable verbose output"); + + opt::options_description implicitOpts("Input files"); + implicitOpts.add_options() + ("input-file", opt::value(), "input file"); + + opt::options_description allOpts(""); + allOpts.add(explicitOpts).add(implicitOpts); + + opt::positional_options_description inputOpts; + inputOpts.add("input-file", 1); + + const char* errorMsg = nullptr; + try + { + auto parser = opt::command_line_parser(_argc, _argv).options(allOpts).positional(inputOpts); + opt::store(parser.run(), _varMap); + opt::notify(_varMap); + } + catch (boost::program_options::error& err) + { + errorMsg = err.what(); + } + if (!errorMsg && _varMap.count("input-file") == 0) + errorMsg = "missing input file name"; -int main(int argc, char** argv) -{ - std::string input_file; - bool opt_dissassemble = false; - bool opt_show_bytes = false; - bool opt_compile = false; - bool opt_interpret = false; - bool opt_dump_graph = false; - bool opt_unknown = false; - bool opt_verbose = false; - size_t initialGas = 10000; - - for (int i = 1; i < argc; i++) + if (_varMap.count("disassemble") == 0 + && _varMap.count("compile") == 0 + && _varMap.count("interpret") == 0) { - std::string option = argv[i]; - if (option == "-b") - opt_show_bytes = true; - else if (option == "-c") - opt_compile = true; - else if (option == "-d") - opt_dissassemble = true; - else if (option == "-i") - opt_interpret = true; - else if (option == "--dump-cfg") - opt_dump_graph = true; - else if (option == "-g" && i + 1 < argc) - { - std::string gasValue = argv[++i]; - initialGas = boost::lexical_cast(gasValue); - std::cerr << "Initial gas set to " << initialGas << "\n"; - } - else if (option == "-v") - opt_verbose = true; - else if (option[0] != '-' && input_file.empty()) - input_file = option; - else - { - opt_unknown = true; - break; - } + errorMsg = "at least one of -c, -i, -d is required"; } - if (opt_unknown || - input_file.empty() || - (!opt_show_bytes && !opt_compile && !opt_dissassemble && !opt_interpret)) + if (errorMsg || _varMap.count("help")) { - show_usage(); - exit(1); + if (errorMsg) + std::cerr << "Error: " << errorMsg << std::endl; + + std::cout << "Usage: " << _argv[0] << " input-file " << std::endl + << explicitOpts << std::endl; + std::exit(errorMsg ? 1 : 0); } +} + +int main(int argc, char** argv) +{ + boost::program_options::variables_map options; + parseProgramOptions(argc, argv, options); - std::ifstream ifs(input_file); + auto inputFile = options["input-file"].as(); + std::ifstream ifs(inputFile); if (!ifs.is_open()) { - std::cerr << "cannot open file " << input_file << std::endl; + std::cerr << "cannot open input file " << inputFile << std::endl; exit(1); } @@ -88,37 +101,70 @@ int main(int argc, char** argv) bytes bytecode = fromHex(src); - if (opt_show_bytes) - std::cout << memDump(bytecode) << std::endl; - - if (opt_dissassemble) + if (options.count("disassemble")) { std::string assembly = eth::disassemble(bytecode); std::cout << assembly << std::endl; } - if (opt_compile || opt_interpret) + if (options.count("compile") || options.count("interpret")) { + size_t initialGas = 10000; + + if (options.count("gas")) + initialGas = options["gas"].as(); + auto compilationStartTime = std::chrono::high_resolution_clock::now(); - eth::jit::Compiler::Options options; - options.dumpCFG = opt_dump_graph; + eth::jit::Compiler::Options compilerOptions; + compilerOptions.dumpCFG = options.count("dump-cfg") > 0; + compilerOptions.optimizeStack = options.count("optimize-stack") > 0; - auto compiler = eth::jit::Compiler(options); + auto compiler = eth::jit::Compiler(compilerOptions); auto module = compiler.compile({bytecode.data(), bytecode.size()}); auto compilationEndTime = std::chrono::high_resolution_clock::now(); module->dump(); - if (opt_verbose) + if (options.count("output-ll")) + { + auto outputFile = options["output-ll"].as(); + std::ofstream ofs(outputFile); + if (!ofs.is_open()) + { + std::cerr << "cannot open output file " << outputFile << std::endl; + exit(1); + } + llvm::raw_os_ostream ros(ofs); + module->print(ros, nullptr); + ofs.close(); + } + + if (options.count("output-bc")) + { + auto outputFile = options["output-bc"].as(); + std::ofstream ofs(outputFile); + if (!ofs.is_open()) + { + std::cerr << "cannot open output file " << outputFile << std::endl; + exit(1); + } + llvm::raw_os_ostream ros(ofs); + llvm::WriteBitcodeToFile(module.get(), ros); + ros.flush(); + ofs.close(); + } + + + if (options.count("verbose")) { std::cerr << "*** Compilation time: " << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count() << std::endl; } - if (opt_interpret) + if (options.count("interpret")) { auto engine = eth::jit::ExecutionEngine(); u256 gas = initialGas; From 99abfb03e08269d3e7594ed861d55c95e0fa8ec8 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 4 Nov 2014 22:02:11 +0000 Subject: [PATCH 317/396] fixed bug in llvm ir computing required memory size --- libevmjit/Memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c3e904ef8..89cef4d48 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -74,7 +74,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); auto currSize = m_builder.CreateLoad(m_size, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(size, sizeRequired, "tooSmall"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? From 54f4710bba7b632b03c32cb3738130d473a609d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 5 Nov 2014 12:37:37 +0100 Subject: [PATCH 318/396] Add LLVMBitWriter.lib to dependencies on Visual Studio --- windows/LLVM.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/LLVM.props b/windows/LLVM.props index 7a779144b..a4e6f2c0f 100644 --- a/windows/LLVM.props +++ b/windows/LLVM.props @@ -7,7 +7,7 @@ ../../_build/llvm/$(Platform) $(LLVMSrcDir)\include;$(LLVMBuildDir)\include $(LLVMBuildDir)\$(Configuration)\lib - LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib + LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMBitWriter.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib From ba26796dbe45a971aeb235043ddc50bab59a0793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 5 Nov 2014 12:38:30 +0100 Subject: [PATCH 319/396] Build boost/program_options on Windows --- windows/bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/bootstrap.sh b/windows/bootstrap.sh index 642c3f5c8..cd8e84086 100644 --- a/windows/bootstrap.sh +++ b/windows/bootstrap.sh @@ -152,7 +152,7 @@ compile_boost() fi if [ ! -d "stage/$platform" ]; then - targets="--with-filesystem --with-system --with-thread --with-date_time --with-regex --with-test" + targets="--with-filesystem --with-system --with-thread --with-date_time --with-regex --with-test --with-program_options" (set -x; ./b2 -j4 --build-type=complete link=static runtime-link=shared variant=debug,release threading=multi $addressModel $targets stage) (set -x; mv stage/lib stage/$platform) fi From 2a0aa9cd5a0b1571ccb10c95f2ceecadc2c3105d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 5 Nov 2014 12:38:51 +0100 Subject: [PATCH 320/396] Clean up evmcc.vcxproj --- windows/evmcc.vcxproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index 1448bb5a8..e7bf633fa 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -119,7 +119,6 @@ Console true - LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) @@ -138,7 +137,6 @@ Console true - %(AdditionalDependencies) @@ -158,7 +156,6 @@ true true true - LibEthereum.lib;LibEvmJit.lib;LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib;%(AdditionalDependencies) From 2bd09c250a737294fdf1679adce1c539b03de6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 6 Nov 2014 17:58:37 +0100 Subject: [PATCH 321/396] Fix compilation with Visual Studio --- libdevcrypto/EC.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index af6d0e65e..7bc17ab99 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -134,7 +134,7 @@ bool crypto::verify(Signature const& _signature, bytesConstRef _message) bool crypto::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed) { - static size_t derMaxEncodingLength = 72; + static const size_t derMaxEncodingLength = 72; if (_hashed) { assert(_message.size() == 32); @@ -155,8 +155,9 @@ Public crypto::recover(Signature _signature, bytesConstRef _message) { secp256k1_start(); - int pubkeylen = 65; - byte pubkey[pubkeylen]; + static const int c_pubkeylen = 65; + auto pubkeylen = c_pubkeylen; + byte pubkey[c_pubkeylen]; if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &pubkeylen, 0, (int)_signature[64])) return Public(); @@ -180,8 +181,9 @@ bool crypto::verifySecret(Secret const& _s, Public const& _p) if (!ok) return false; - int pubkeylen = 65; - byte pubkey[pubkeylen]; + static const int c_pubkeylen = 65; + auto pubkeylen = c_pubkeylen; + byte pubkey[c_pubkeylen]; ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _s.data(), 0); if (!ok || pubkeylen != 65) return false; From b43f66ab01142e2a2177ce25206f30c9ca8a2311 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 13 Nov 2014 16:57:01 +0100 Subject: [PATCH 322/396] removed references to Memory::dump() --- libevmjit/Memory.cpp | 18 ------------------ libevmjit/Memory.h | 2 -- 2 files changed, 20 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 89cef4d48..53cccf92b 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -147,24 +147,18 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet llvm::Value* Memory::loadWord(llvm::Value* _addr) { auto value = m_builder.CreateCall(m_loadWord, _addr); - - dump(0); return value; } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { m_builder.CreateCall2(m_storeWord, _addr, _word); - - dump(0); } void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); m_builder.CreateCall2(m_storeByte, _addr, byte); - - dump(0); } llvm::Value* Memory::getData() @@ -205,18 +199,6 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* m_builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); } -void Memory::dump(uint64_t _begin, uint64_t _end) -{ - if (getenv("EVMCC_DEBUG_MEMORY") == nullptr) - return; - - auto beginVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _begin); - auto endVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _end); - - std::vector args = {beginVal, endVal}; - m_builder.CreateCall(m_memDump, llvm::ArrayRef(args)); -} - } } } diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index 37bfb15f5..c6ba02a54 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -27,8 +27,6 @@ public: /// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory. void require(llvm::Value* _offset, llvm::Value* _size); - void dump(uint64_t _begin, uint64_t _end = 0); - private: llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager); From a09c3a404d3f944e03178fee30a3e8e86a8b3fe3 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 13 Nov 2014 17:03:39 +0100 Subject: [PATCH 323/396] codegen for LOG instructions [Delivers #81700490] --- evmcc/evmcc.cpp | 12 ++-- libevmjit/Compiler.cpp | 25 ++++++- libevmjit/ExecutionEngine.cpp | 5 +- libevmjit/ExecutionEngine.h | 2 +- libevmjit/Ext.cpp | 125 ++++++++++++++++++++++++++++++++++ libevmjit/Ext.h | 7 ++ libevmjit/Runtime.cpp | 10 ++- libevmjit/Runtime.h | 4 +- 8 files changed, 178 insertions(+), 12 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 535a9aed9..48d883fd7 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -31,9 +31,12 @@ void parseProgramOptions(int _argc, char** _argv, boost::program_options::variab ("gas,g", opt::value(), "set initial gas for execution") ("disassemble,d", "dissassemble the code") ("dump-cfg", "dump control flow graph to graphviz file") - ("optimize-stack,os", "optimize stack use between basic blocks") + ("dont-optimize", "turn off optimizations") + ("optimize-stack", "optimize stack use between basic blocks (default: on)") + ("rewrite-switch", "rewrite LLVM switch to branches (default: on)") ("output-ll", opt::value(), "dump generated LLVM IR to file") ("output-bc", opt::value(), "dump generated LLVM bitcode to file") + ("show-logs", "output LOG statements to stderr") ("verbose,V", "enable verbose output"); opt::options_description implicitOpts("Input files"); @@ -118,7 +121,9 @@ int main(int argc, char** argv) eth::jit::Compiler::Options compilerOptions; compilerOptions.dumpCFG = options.count("dump-cfg") > 0; - compilerOptions.optimizeStack = options.count("optimize-stack") > 0; + bool optimize = options.count("dont-optimize") == 0; + compilerOptions.optimizeStack = optimize || options.count("optimize-stack") > 0; + compilerOptions.rewriteSwitchToBranches = optimize || options.count("rewrite-switch") > 0; auto compiler = eth::jit::Compiler(compilerOptions); auto module = compiler.compile({bytecode.data(), bytecode.size()}); @@ -156,7 +161,6 @@ int main(int argc, char** argv) ofs.close(); } - if (options.count("verbose")) { std::cerr << "*** Compilation time: " @@ -168,7 +172,7 @@ int main(int argc, char** argv) { auto engine = eth::jit::ExecutionEngine(); u256 gas = initialGas; - auto result = engine.run(std::move(module), gas); + auto result = engine.run(std::move(module), gas, options.count("show-logs") > 0); return result; } } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 295f3a131..8ce490040 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -508,7 +508,11 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod case Instruction::POP: { - stack.pop(); + auto val = stack.pop(); + static_cast(val); + // Generate a dummy use of val to make sure that a get(0) will be emitted at this point, + // so that StackTooSmall will be thrown + // m_builder.CreateICmpEQ(val, val, "dummy"); break; } @@ -791,6 +795,25 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod break; } + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + auto beginIdx = stack.pop(); + auto numBytes = stack.pop(); + _memory.require(beginIdx, numBytes); + + std::array topics; + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + for (size_t i = 0; i < numTopics; ++i) + topics[i] = stack.pop(); + + _ext.log(beginIdx, numBytes, numTopics, topics); + break; + } + default: // Invalid instruction - runtime exception { _runtimeManager.raiseException(ReturnCode::BadInstruction); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 4c617d9ea..9f2149524 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -37,10 +37,9 @@ namespace jit ExecutionEngine::ExecutionEngine() { - } -int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtVMFace* _ext) +int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool _outputLogs, ExtVMFace* _ext) { auto module = _module.get(); // Keep ownership of the module in _module @@ -110,7 +109,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV ReturnCode returnCode; std::jmp_buf buf; - Runtime runtime(_gas, *_ext, buf); + Runtime runtime(_gas, *_ext, buf, _outputLogs); auto r = setjmp(buf); if (r == 0) { diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 15a4e6ef7..0c425e415 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -18,7 +18,7 @@ class ExecutionEngine public: ExecutionEngine(); - int run(std::unique_ptr module, u256& _gas, ExtVMFace* _ext = nullptr); + int run(std::unique_ptr module, u256& _gas, bool _outputLogs, ExtVMFace* _ext = nullptr); bytes returnData; }; diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index f39ab5755..17cbf5dc4 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -59,6 +59,11 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module); m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_codeAt", module); m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module); + m_log0 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_log0", module); + m_log1 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_log1", module); + m_log2 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 5}, false), Linkage::ExternalLinkage, "ext_log2", module); + m_log3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 6}, false), Linkage::ExternalLinkage, "ext_log3", module); + m_log4 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 7}, false), Linkage::ExternalLinkage, "ext_log4", module); } llvm::Value* Ext::store(llvm::Value* _index) @@ -160,6 +165,21 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr) return m_builder.CreateLoad(m_args[1]); } +void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array const& _topics) +{ + static llvm::Value* args[] = {nullptr, m_args[0], m_args[1], m_arg2, m_arg3, m_arg4, m_arg5}; + static llvm::Value* funcs[] = {m_log0, m_log1, m_log2, m_log3, m_log4}; + + args[0] = getRuntimeManager().getRuntimePtr(); + m_builder.CreateStore(_memIdx, m_args[0]); + m_builder.CreateStore(_numBytes, m_args[1]); + + for (size_t i = 0; i < _numTopics; ++i) + m_builder.CreateStore(_topics[i], args[i + 3]); + + m_builder.CreateCall(funcs[_numTopics], llvm::ArrayRef(args, _numTopics + 3)); +} + } @@ -289,6 +309,111 @@ extern "C" *o_ret = eth2llvm(u256(code.size())); } + void ext_show_bytes(bytesConstRef _bytes) + { + for (auto b : _bytes) + std::cerr << std::hex << std::setw(2) << std::setfill('0') << static_cast(b) << " "; + std::cerr << std::endl; + } + + EXPORT void ext_log0(Runtime* _rt, i256* _memIdx, i256* _numBytes) + { + auto&& ext = _rt->getExt(); + + auto memIdx = static_cast(llvm2eth(*_memIdx)); + auto numBytes = static_cast(llvm2eth(*_numBytes)); + + auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + ext.log({}, dataRef); + + if (_rt->outputLogs()) + { + std::cerr << "LOG: "; + ext_show_bytes(dataRef); + } + } + + EXPORT void ext_log1(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1) + { + auto&& ext = _rt->getExt(); + + auto memIdx = static_cast(llvm2eth(*_memIdx)); + auto numBytes = static_cast(llvm2eth(*_numBytes)); + + auto topic1 = llvm2eth(*_topic1); + + auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + ext.log({topic1}, dataRef); + + if (_rt->outputLogs()) + { + std::cerr << "LOG [" << topic1 << "]: "; + ext_show_bytes(dataRef); + } + } + + EXPORT void ext_log2(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2) + { + auto&& ext = _rt->getExt(); + + auto memIdx = static_cast(llvm2eth(*_memIdx)); + auto numBytes = static_cast(llvm2eth(*_numBytes)); + + auto topic1 = llvm2eth(*_topic1); + auto topic2 = llvm2eth(*_topic2); + + auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + ext.log({topic1, topic2}, dataRef); + + if (_rt->outputLogs()) + { + std::cerr << "LOG [" << topic1 << "][" << topic2 << "]: "; + ext_show_bytes(dataRef); + } + } + + EXPORT void ext_log3(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3) + { + auto&& ext = _rt->getExt(); + + auto memIdx = static_cast(llvm2eth(*_memIdx)); + auto numBytes = static_cast(llvm2eth(*_numBytes)); + + auto topic1 = llvm2eth(*_topic1); + auto topic2 = llvm2eth(*_topic2); + auto topic3 = llvm2eth(*_topic3); + + auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + ext.log({topic1, topic2, topic3}, dataRef); + + if (_rt->outputLogs()) + { + std::cerr << "LOG [" << topic1 << "][" << topic2 << "][" << topic3 << "]: "; + ext_show_bytes(dataRef); + } + } + + EXPORT void ext_log4(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3, i256* _topic4) + { + auto&& ext = _rt->getExt(); + + auto memIdx = static_cast(llvm2eth(*_memIdx)); + auto numBytes = static_cast(llvm2eth(*_numBytes)); + + auto topic1 = llvm2eth(*_topic1); + auto topic2 = llvm2eth(*_topic2); + auto topic3 = llvm2eth(*_topic3); + auto topic4 = llvm2eth(*_topic4); + + auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + ext.log({topic1, topic2, topic3, topic4}, dataRef); + + if (_rt->outputLogs()) + { + std::cerr << "LOG [" << topic1 << "][" << topic2 << "][" << topic3 << "][" << topic4 << "]: "; + ext_show_bytes(dataRef); + } + } } } } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 8e70af7d0..54380dda6 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -31,8 +31,10 @@ public: llvm::Value* codeAt(llvm::Value* _addr); llvm::Value* codesizeAt(llvm::Value* _addr); + void log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array const& _topics); private: + llvm::Value* m_args[2]; llvm::Value* m_arg2; llvm::Value* m_arg3; @@ -53,6 +55,11 @@ private: llvm::Function* m_exp; llvm::Function* m_codeAt; llvm::Function* m_codesizeAt; + llvm::Function* m_log0; + llvm::Function* m_log1; + llvm::Function* m_log2; + llvm::Function* m_log3; + llvm::Function* m_log4; }; diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 982dd9f36..8e52b648a 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -58,8 +58,9 @@ llvm::Twine getName(RuntimeData::Index _index) } } -Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf): - m_ext(_ext) +Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf, bool _outputLogs): + m_ext(_ext), + m_outputLogs(_outputLogs) { set(RuntimeData::Gas, _gas); set(RuntimeData::Address, fromAddress(_ext.myAddress)); @@ -101,6 +102,11 @@ bytesConstRef Runtime::getReturnData() const return {m_memory.data() + offset, size}; } +bool Runtime::outputLogs() const +{ + return m_outputLogs; +} + RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) { diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 8c784b394..8f485794a 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -63,7 +63,7 @@ using MemoryImpl = bytes; class Runtime { public: - Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf); + Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf, bool _outputLogs); Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; @@ -77,6 +77,7 @@ public: u256 getGas() const; bytesConstRef getReturnData() const; decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; } + bool outputLogs() const; private: void set(RuntimeData::Index _index, u256 _value); @@ -86,6 +87,7 @@ private: StackImpl m_stack; MemoryImpl m_memory; ExtVMFace& m_ext; + bool m_outputLogs; ///< write LOG statements to console }; class RuntimeManager: public CompilerHelper From bb243c4a284b685d96b46d57d160149feb11e1df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 14 Nov 2014 10:50:22 +0100 Subject: [PATCH 324/396] Fix VC proj --- windows/LibEthereum.vcxproj | 7 ++++--- windows/LibEthereum.vcxproj.filters | 15 +++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 92fdfe8ca..be1940b8e 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -125,6 +125,7 @@ + true @@ -146,7 +147,6 @@ - @@ -342,6 +342,7 @@ + true @@ -369,7 +370,7 @@ - + @@ -573,4 +574,4 @@ - + \ No newline at end of file diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index cc39c8eaa..09770f5ed 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -40,9 +40,6 @@ libevmcore - - liblll - liblll @@ -205,6 +202,9 @@ libethereum + + libevmcore + @@ -252,8 +252,8 @@ liblll - - libevmcore + + libevmcore liblll @@ -441,6 +441,9 @@ libethereum + + libevmcore + @@ -477,4 +480,4 @@ {d838fece-fc20-42f6-bff5-97c236159b80} - + \ No newline at end of file From bb6d39f7cc7cd09bdbf7acf03fda52c78e47b07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 14 Nov 2014 10:51:47 +0100 Subject: [PATCH 325/396] Update Instruction.h location --- evmcc/evmcc.cpp | 2 +- libevmjit/Compiler.cpp | 2 +- libevmjit/GasMeter.cpp | 2 +- libevmjit/GasMeter.h | 2 +- libevmjit/Utils.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 535a9aed9..81824f010 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 295f3a131..2b970586e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include "Type.h" #include "Memory.h" diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 7a6a0ebd2..734931c32 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include "Type.h" diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 3de227651..4be6c1a02 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -1,7 +1,7 @@ #pragma once -#include +#include #include "CompilerHelper.h" diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 9fa9f050e..c3ed53a70 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -5,7 +5,7 @@ #include #include -#include +#include namespace dev { From 078b208b040d3e94f1fd71e6dddd0a803b587e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 14 Nov 2014 11:07:05 +0100 Subject: [PATCH 326/396] Handle bytecode as bytes --- evmcc/evmcc.cpp | 2 +- libevmjit/Compiler.cpp | 6 +++--- libevmjit/Compiler.h | 6 +++--- libevmjit/ExecutionEngine.cpp | 3 +-- libevmjit/Utils.cpp | 2 +- libevmjit/Utils.h | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 81824f010..a04956fab 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -121,7 +121,7 @@ int main(int argc, char** argv) compilerOptions.optimizeStack = options.count("optimize-stack") > 0; auto compiler = eth::jit::Compiler(compilerOptions); - auto module = compiler.compile({bytecode.data(), bytecode.size()}); + auto module = compiler.compile(bytecode); auto compilationEndTime = std::chrono::high_resolution_clock::now(); diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 2b970586e..717ecff22 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -39,7 +39,7 @@ Compiler::Compiler(Options const& _options): Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(bytesConstRef _bytecode) +void Compiler::createBasicBlocks(bytes const& _bytecode) { std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end @@ -151,7 +151,7 @@ void Compiler::createBasicBlocks(bytesConstRef _bytecode) m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); } -std::unique_ptr Compiler::compile(bytesConstRef _bytecode) +std::unique_ptr Compiler::compile(bytes const& _bytecode) { auto module = std::unique_ptr(new llvm::Module("main", m_builder.getContext())); @@ -247,7 +247,7 @@ std::unique_ptr Compiler::compile(bytesConstRef _bytecode) } -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, RuntimeManager& _runtimeManager, +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) { if (!_nextBasicBlock) // this is the last block in the code diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 12b7f6e0e..a618f41a3 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -40,13 +40,13 @@ public: Compiler(Options const& _options); - std::unique_ptr compile(bytesConstRef _bytecode); + std::unique_ptr compile(bytes const& _bytecode); private: - void createBasicBlocks(bytesConstRef _bytecode); + void createBasicBlocks(bytes const& _bytecode); - void compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); void removeDeadBlocks(); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 4c617d9ea..f3e4132e9 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -100,8 +100,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV _ext->currentBlock.gasLimit = 1008; std::string calldata = "Hello the Beautiful World of Ethereum!"; _ext->data = calldata; - unsigned char fakecode[] = {0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf}; - _ext->code = decltype(_ext->code)(fakecode, 8); + _ext->code = { 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf }; } auto entryFunc = module->getFunction("main"); diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 966dc69bd..548ee0e1f 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -35,7 +35,7 @@ i256 eth2llvm(u256 _u) return i; } -u256 readPushData(const byte*& _curr, const byte* _end) +u256 readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index c3ed53a70..54291f3e0 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -33,7 +33,7 @@ i256 eth2llvm(u256); /// Reads PUSH data from pointed fragment of bytecode and constructs number out of it /// Reading out of bytecode means reading 0 /// @param _curr is updates and points the last real byte read -u256 readPushData(const byte*& _curr, const byte* _end); +u256 readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ From ec4301014bf53814f9ff5de09913460e26d3ddb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 14 Nov 2014 11:07:14 +0100 Subject: [PATCH 327/396] Fix VM tester --- test/vm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/vm.cpp b/test/vm.cpp index 1c6022f50..67f088376 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -313,7 +313,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) try { output = vm->go(fev, fev.simpleTrace()).toVector(); - gas = vm.gas(); + gas = vm->gas(); } catch (OutOfGas const&) { From d4f18b45bc967bc1e5530852a4e8b1158a65ada8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 14 Nov 2014 11:44:51 +0100 Subject: [PATCH 328/396] Test unexpected storage entries --- test/TestHelper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index c1a141abb..be05ef7fc 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -287,6 +287,12 @@ void checkStorage(map _expectedStore, map _resultStore, BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, _expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); } } + + for (auto&& resultStorePair : _resultStore) + { + if (!_expectedStore.count(resultStorePair.first)) + BOOST_ERROR("unexpected result store key " << resultStorePair.first); + } } std::string getTestPath() From 3d501db9dacbe7a4dc2eb961186d3b22a4a32b34 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 14 Nov 2014 14:39:06 +0100 Subject: [PATCH 329/396] libevmface -> libevmcore: updated cmake files --- evmcc/CMakeLists.txt | 2 +- libevmjit/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index 488893509..26a586271 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -13,7 +13,7 @@ target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} evm) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} evmjit) if ("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index cc63e72db..b06316dd2 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -18,7 +18,7 @@ include_directories(..) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} evm) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) if ("${TARGET_PLATFORM}" STREQUAL "w64") From d088957f088b6a43ea820e67345f053ec9875101 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 14 Nov 2014 14:40:34 +0100 Subject: [PATCH 330/396] made _ext a mandatory arg of Runtime::run() --- evmcc/evmcc.cpp | 2 +- libevmjit/ExecutionEngine.h | 2 +- libevmjit/VM.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index e3f7e9c8e..f8e2b12f0 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -172,7 +172,7 @@ int main(int argc, char** argv) { auto engine = eth::jit::ExecutionEngine(); u256 gas = initialGas; - auto result = engine.run(std::move(module), gas, options.count("show-logs") > 0); + auto result = engine.run(std::move(module), gas, options.count("show-logs") > 0, nullptr); return result; } } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 0c425e415..c47562981 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -18,7 +18,7 @@ class ExecutionEngine public: ExecutionEngine(); - int run(std::unique_ptr module, u256& _gas, bool _outputLogs, ExtVMFace* _ext = nullptr); + int run(std::unique_ptr module, u256& _gas, bool _outputLogs, ExtVMFace* _ext); bytes returnData; }; diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 0c89587e9..e19156d6e 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -20,7 +20,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) auto module = Compiler(defaultOptions).compile(_ext.code); ExecutionEngine engine; - auto exitCode = engine.run(std::move(module), m_gas, &_ext); + auto exitCode = engine.run(std::move(module), m_gas, false, &_ext); switch (static_cast(exitCode)) { From 0389030674f3f95c99c899564c363246a09c51e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 14 Nov 2014 15:06:38 +0100 Subject: [PATCH 331/396] Move mock of ExtVMFace to evmcc tool --- evmcc/evmcc.cpp | 20 +++++++++++++++++++- libevmjit/ExecutionEngine.cpp | 24 ++---------------------- libevmjit/ExecutionEngine.h | 2 +- libevmjit/VM.cpp | 2 +- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index f8e2b12f0..16ab23e9b 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -172,7 +173,24 @@ int main(int argc, char** argv) { auto engine = eth::jit::ExecutionEngine(); u256 gas = initialGas; - auto result = engine.run(std::move(module), gas, options.count("show-logs") > 0, nullptr); + + // Create fake ExtVM interface + eth::ExtVMFace ext; + ext.myAddress = Address(1122334455667788); + ext.caller = Address(0xfacefacefaceface); + ext.origin = Address(101010101010101010); + ext.value = 0xabcd; + ext.gasPrice = 1002; + ext.previousBlock.hash = u256(1003); + ext.currentBlock.coinbaseAddress = Address(1004); + ext.currentBlock.timestamp = 1005; + ext.currentBlock.number = 1006; + ext.currentBlock.difficulty = 1007; + ext.currentBlock.gasLimit = 1008; + ext.data = std::string("Hello the Beautiful World of Ethereum!"); + ext.code = { 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf }; + + auto result = engine.run(std::move(module), gas, options.count("show-logs") > 0, ext); return result; } } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index bdc107630..02b12d373 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -39,7 +39,7 @@ ExecutionEngine::ExecutionEngine() { } -int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool _outputLogs, ExtVMFace* _ext) +int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool _outputLogs, ExtVMFace& _ext) { auto module = _module.get(); // Keep ownership of the module in _module @@ -82,33 +82,13 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool clog(JIT) << "Module finalization time: " << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); - // Create fake ExtVM interface - if (!_ext) - { - _ext = new ExtVMFace; - _ext->myAddress = Address(1122334455667788); - _ext->caller = Address(0xfacefacefaceface); - _ext->origin = Address(101010101010101010); - _ext->value = 0xabcd; - _ext->gasPrice = 1002; - _ext->previousBlock.hash = u256(1003); - _ext->currentBlock.coinbaseAddress = Address(1004); - _ext->currentBlock.timestamp = 1005; - _ext->currentBlock.number = 1006; - _ext->currentBlock.difficulty = 1007; - _ext->currentBlock.gasLimit = 1008; - std::string calldata = "Hello the Beautiful World of Ethereum!"; - _ext->data = calldata; - _ext->code = { 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf }; - } - auto entryFunc = module->getFunction("main"); if (!entryFunc) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found")); ReturnCode returnCode; std::jmp_buf buf; - Runtime runtime(_gas, *_ext, buf, _outputLogs); + Runtime runtime(_gas, _ext, buf, _outputLogs); auto r = setjmp(buf); if (r == 0) { diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index c47562981..8cf1ec746 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -18,7 +18,7 @@ class ExecutionEngine public: ExecutionEngine(); - int run(std::unique_ptr module, u256& _gas, bool _outputLogs, ExtVMFace* _ext); + int run(std::unique_ptr module, u256& _gas, bool _outputLogs, ExtVMFace& _ext); bytes returnData; }; diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index e19156d6e..9b60fccf1 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -20,7 +20,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) auto module = Compiler(defaultOptions).compile(_ext.code); ExecutionEngine engine; - auto exitCode = engine.run(std::move(module), m_gas, false, &_ext); + auto exitCode = engine.run(std::move(module), m_gas, false, _ext); switch (static_cast(exitCode)) { From f56e2edcd2e5fcedbcd83697c0de7a83765bde25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 14 Nov 2014 15:40:07 +0100 Subject: [PATCH 332/396] After merge changes --- windows/LibEthereum.vcxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 1b63f2872..77b8f7e1a 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -480,21 +480,25 @@ + + + + From 63c8a8384cb2e97b25ad6ba4035b66641ae88661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Mon, 17 Nov 2014 18:10:54 +0100 Subject: [PATCH 333/396] fixed libevmjit dependencies in cmake files --- eth/CMakeLists.txt | 1 + evmcc/CMakeLists.txt | 5 ++--- libevmjit/CMakeLists.txt | 1 - neth/CMakeLists.txt | 1 + test/CMakeLists.txt | 2 ++ 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index 70ed25f5e..9239e79ac 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -14,6 +14,7 @@ target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} gmp) if(EVMJIT) + target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evmjit) endif() diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index 26a586271..a087539dc 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -11,10 +11,9 @@ add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} boost_program_options) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} evm) -target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} evmjit) +target_link_libraries(${EXECUTABLE} evm) +target_link_libraries(${EXECUTABLE} ethereum) if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index b06316dd2..0b3226e14 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -17,7 +17,6 @@ include_directories(..) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evmcore) diff --git a/neth/CMakeLists.txt b/neth/CMakeLists.txt index 8d8bf2ab5..c3d14c983 100644 --- a/neth/CMakeLists.txt +++ b/neth/CMakeLists.txt @@ -23,6 +23,7 @@ target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() if(EVMJIT) + target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evmjit) endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 951db2c99..8d8430b5c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,6 +21,7 @@ if(JSONRPC_LS) target_link_libraries(testeth web3jsonrpc) endif() if (EVMJIT) + target_link_libraries(testeth evm) target_link_libraries(testeth evmjit) endif() @@ -29,6 +30,7 @@ target_link_libraries(createRandomTest ethcore) target_link_libraries(createRandomTest boost_chrono) target_link_libraries(createRandomTest boost_unit_test_framework) if (EVMJIT) + target_link_libraries(createRandomTest evm) target_link_libraries(createRandomTest evmjit) endif() From 7a121c38b818449d4bb664277dfc15cdbf168b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 20 Nov 2014 20:13:28 +0100 Subject: [PATCH 334/396] Do not catch OutOfGas exception in tests separately --- test/vm.cpp | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 03e03566c..3f8e0a233 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -306,7 +306,6 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) auto vm = VMFace::create(vmKind, fev.gas); bytes output; - auto outOfGas = false; auto startTime = std::chrono::high_resolution_clock::now(); u256 gas; @@ -316,11 +315,6 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) output = vm->go(fev, fev.simpleTrace()).toVector(); gas = vm->gas(); } - catch (OutOfGas const&) - { - outOfGas = true; - gas = 0; - } catch (VMException const& _e) { cnote << "VM did throw an exception: " << diagnostic_information(_e); @@ -373,11 +367,11 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) o["exec"] = mValue(fev.exportExec()); if (!vmExceptionOccured) { - o["post"] = mValue(fev.exportState()); - o["callcreates"] = fev.exportCallCreates(); - o["out"] = "0x" + toHex(output); - fev.push(o, "gas", gas); - } + o["post"] = mValue(fev.exportState()); + o["callcreates"] = fev.exportCallCreates(); + o["out"] = "0x" + toHex(output); + fev.push(o, "gas", gas); + } } else { @@ -397,10 +391,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) checkOutput(output, o); BOOST_CHECK_EQUAL(toInt(o["gas"]), gas); - - if (outOfGas) - BOOST_CHECK_MESSAGE(gas == 0, "Remaining gas not 0 in out-of-gas state"); - + auto& expectedAddrs = test.addresses; auto& resultAddrs = fev.addresses; for (auto&& expectedPair : expectedAddrs) From 3918a50dbb741dc5d7f7ea29786f84ba181b633f Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 24 Nov 2014 22:42:50 +0100 Subject: [PATCH 335/396] EVM code updated in vmPerformanceTests --- evmcc/test/vmtests/vmPerformanceTest.json | 71 +++++------------------ 1 file changed, 15 insertions(+), 56 deletions(-) diff --git a/evmcc/test/vmtests/vmPerformanceTest.json b/evmcc/test/vmtests/vmPerformanceTest.json index 07baa6709..b3e47ae16 100644 --- a/evmcc/test/vmtests/vmPerformanceTest.json +++ b/evmcc/test/vmtests/vmPerformanceTest.json @@ -12,7 +12,7 @@ "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x60015d68010000000000000000908060010115600358", + "code" : "0x60015b68010000000000000000908060010109600356", "data" : "0x", "gas" : "1000000", "gasPrice" : "100000000000000", @@ -24,7 +24,7 @@ "post" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x60015d68010000000000000000908060010115600358", + "code" : "0x60015b68010000000000000000908060010109600356", "nonce" : "0", "storage" : { } @@ -33,7 +33,7 @@ "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x60015d68010000000000000000908060010115600358", + "code" : "0x60015b68010000000000000000908060010109600356", "nonce" : "0", "storage" : { } } @@ -54,7 +54,7 @@ "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x620186a06080545d60006080530b0f60295960a0536080530160a0546001608053036080546008585d", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", "data" : "0x", "gas" : "10000000", "gasPrice" : "100000000000000", @@ -66,7 +66,7 @@ "post" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x620186a06080545d60006080530b0f60295960a0536080530160a0546001608053036080546008585d", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", "nonce" : "0", "storage" : { } @@ -75,48 +75,7 @@ "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x620186a06080545d60006080530b0f60295960a0536080530160a0546001608053036080546008585d", - "nonce" : "0", - "storage" : { } - } - } - }, - - "recloop0x40000" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x600c6204000060006015585d60005460206000f25d6000820e602e59602a60018303600183016015585d6030585d805d905090509058", - "data" : "0x", - "gas" : "10000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "4232808", - "out" : "0x0000000000000000000000000000000000000000000000000000000000040000", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x600c6204000060006015585d60005460206000f25d6000820e602e59602a60018303600183016015585d6030585d805d905090509058", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x600c6204000060006015585d60005460206000f25d6000820e602e59602a60018303600183016015585d6030585d805d905090509058", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", "nonce" : "0", "storage" : { } } @@ -137,7 +96,7 @@ "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x600860196011585d60005460206000f25d6003810a6031596022600282036011585d602c600183036011585d016034585d60015d90509058", + "code" : "0x600760196010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", "data" : "0x", "gas" : "10000000", "gasPrice" : "100000000000000", @@ -149,7 +108,7 @@ "post" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x600860196011585d60005460206000f25d6003810a6031596022600282036011585d602c600183036011585d016034585d60015d90509058", + "code" : "0x600760196010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", "nonce" : "0", "storage" : { } @@ -158,7 +117,7 @@ "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x600860196011585d60005460206000f25d6003810a6031596022600282036011585d602c600183036011585d016034585d60015d90509058", + "code" : "0x600760196010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", "nonce" : "0", "storage" : { } @@ -180,7 +139,7 @@ "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x600a600360066013585d60005460206000f25d6000820e604b596000810e603a59603660018303603284600185036013585d6013585d6047585d60466001830360016013585d5d6050585d600181015d905090509058", + "code" : "0x6009600360066012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", "data" : "0x", "gas" : "10000000", "gasPrice" : "100000000000000", @@ -192,7 +151,7 @@ "post" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x600a600360066013585d60005460206000f25d6000820e604b596000810e603a59603660018303603284600185036013585d6013585d6047585d60466001830360016013585d5d6050585d600181015d905090509058", + "code" : "0x6009600360066012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", "nonce" : "0", "storage" : { } @@ -201,7 +160,7 @@ "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x600a600360066013585d60005460206000f25d6000820e604b596000810e603a59603660018303603284600185036013585d6013585d6047585d60466001830360016013585d5d6050585d600181015d905090509058", + "code" : "0x6009600360066012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", "nonce" : "0", "storage" : { } @@ -223,7 +182,7 @@ "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6127105d600190038060000e6104615961001b600160005458005d610026600260005458005d610031600360005458005d61003c600460005458005d610047600560005458005d610052600660005458005d61005d600760005458005d610068600860005458005d610073600960005458005d61007e600a60005458005d610089600b60005458005d610094600c60005458005d61009f600d60005458005d6100aa600e60005458005d6100b5600f60005458005d6100c0601060005458005d6100cb601160005458005d6100d6601260005458005d6100e1601360005458005d6100ec601460005458005d6100f7601560005458005d610102601660005458005d61010d601760005458005d610118601860005458005d610123601960005458005d61012e601a60005458005d610139601b60005458005d610144601c60005458005d61014f601d60005458005d61015a601e60005458005d610165601f60005458005d610170602060005458005d61017b602160005458005d610186602260005458005d610191602360005458005d61019c602460005458005d6101a7602560005458005d6101b2602660005458005d6101bd602760005458005d6101c8602860005458005d6101d3602960005458005d6101de602a60005458005d6101e9602b60005458005d6101f4602c60005458005d6101ff602d60005458005d61020a602e60005458005d610215602f60005458005d610220603060005458005d61022b603160005458005d610236603260005458005d610241603360005458005d61024c603460005458005d610257603560005458005d610262603660005458005d61026d603760005458005d610278603860005458005d610283603960005458005d61028e603a60005458005d610299603b60005458005d6102a4603c60005458005d6102af603d60005458005d6102ba603e60005458005d6102c5603f60005458005d6102d0604060005458005d6102db604160005458005d6102e6604260005458005d6102f1604360005458005d6102fc604460005458005d610307604560005458005d610312604660005458005d61031d604760005458005d610328604860005458005d610333604960005458005d61033e604a60005458005d610349604b60005458005d610354604c60005458005d61035f604d60005458005d61036a604e60005458005d610375604f60005458005d610380605060005458005d61038b605160005458005d610396605260005458005d6103a1605360005458005d6103ac605460005458005d6103b7605560005458005d6103c2605660005458005d6103cd605760005458005d6103d8605860005458005d6103e3605960005458005d6103ee605a60005458005d6103f9605b60005458005d610404605c60005458005d61040f605d60005458005d61041a605e60005458005d610425605f60005458005d610430606060005458005d61043b606160005458005d610446606260005458005d610451606360005458005d61045c606460005458005d610004585d60206000f2", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", "data" : "0x", "gas" : "10000000", "gasPrice" : "100000000000000", @@ -235,7 +194,7 @@ "post" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x6127105d600190038060000e6104615961001b600160005458005d610026600260005458005d610031600360005458005d61003c600460005458005d610047600560005458005d610052600660005458005d61005d600760005458005d610068600860005458005d610073600960005458005d61007e600a60005458005d610089600b60005458005d610094600c60005458005d61009f600d60005458005d6100aa600e60005458005d6100b5600f60005458005d6100c0601060005458005d6100cb601160005458005d6100d6601260005458005d6100e1601360005458005d6100ec601460005458005d6100f7601560005458005d610102601660005458005d61010d601760005458005d610118601860005458005d610123601960005458005d61012e601a60005458005d610139601b60005458005d610144601c60005458005d61014f601d60005458005d61015a601e60005458005d610165601f60005458005d610170602060005458005d61017b602160005458005d610186602260005458005d610191602360005458005d61019c602460005458005d6101a7602560005458005d6101b2602660005458005d6101bd602760005458005d6101c8602860005458005d6101d3602960005458005d6101de602a60005458005d6101e9602b60005458005d6101f4602c60005458005d6101ff602d60005458005d61020a602e60005458005d610215602f60005458005d610220603060005458005d61022b603160005458005d610236603260005458005d610241603360005458005d61024c603460005458005d610257603560005458005d610262603660005458005d61026d603760005458005d610278603860005458005d610283603960005458005d61028e603a60005458005d610299603b60005458005d6102a4603c60005458005d6102af603d60005458005d6102ba603e60005458005d6102c5603f60005458005d6102d0604060005458005d6102db604160005458005d6102e6604260005458005d6102f1604360005458005d6102fc604460005458005d610307604560005458005d610312604660005458005d61031d604760005458005d610328604860005458005d610333604960005458005d61033e604a60005458005d610349604b60005458005d610354604c60005458005d61035f604d60005458005d61036a604e60005458005d610375604f60005458005d610380605060005458005d61038b605160005458005d610396605260005458005d6103a1605360005458005d6103ac605460005458005d6103b7605560005458005d6103c2605660005458005d6103cd605760005458005d6103d8605860005458005d6103e3605960005458005d6103ee605a60005458005d6103f9605b60005458005d610404605c60005458005d61040f605d60005458005d61041a605e60005458005d610425605f60005458005d610430606060005458005d61043b606160005458005d610446606260005458005d610451606360005458005d61045c606460005458005d610004585d60206000f2", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", "nonce" : "0", "storage" : { } @@ -244,7 +203,7 @@ "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x6127105d600190038060000e6104615961001b600160005458005d610026600260005458005d610031600360005458005d61003c600460005458005d610047600560005458005d610052600660005458005d61005d600760005458005d610068600860005458005d610073600960005458005d61007e600a60005458005d610089600b60005458005d610094600c60005458005d61009f600d60005458005d6100aa600e60005458005d6100b5600f60005458005d6100c0601060005458005d6100cb601160005458005d6100d6601260005458005d6100e1601360005458005d6100ec601460005458005d6100f7601560005458005d610102601660005458005d61010d601760005458005d610118601860005458005d610123601960005458005d61012e601a60005458005d610139601b60005458005d610144601c60005458005d61014f601d60005458005d61015a601e60005458005d610165601f60005458005d610170602060005458005d61017b602160005458005d610186602260005458005d610191602360005458005d61019c602460005458005d6101a7602560005458005d6101b2602660005458005d6101bd602760005458005d6101c8602860005458005d6101d3602960005458005d6101de602a60005458005d6101e9602b60005458005d6101f4602c60005458005d6101ff602d60005458005d61020a602e60005458005d610215602f60005458005d610220603060005458005d61022b603160005458005d610236603260005458005d610241603360005458005d61024c603460005458005d610257603560005458005d610262603660005458005d61026d603760005458005d610278603860005458005d610283603960005458005d61028e603a60005458005d610299603b60005458005d6102a4603c60005458005d6102af603d60005458005d6102ba603e60005458005d6102c5603f60005458005d6102d0604060005458005d6102db604160005458005d6102e6604260005458005d6102f1604360005458005d6102fc604460005458005d610307604560005458005d610312604660005458005d61031d604760005458005d610328604860005458005d610333604960005458005d61033e604a60005458005d610349604b60005458005d610354604c60005458005d61035f604d60005458005d61036a604e60005458005d610375604f60005458005d610380605060005458005d61038b605160005458005d610396605260005458005d6103a1605360005458005d6103ac605460005458005d6103b7605560005458005d6103c2605660005458005d6103cd605760005458005d6103d8605860005458005d6103e3605960005458005d6103ee605a60005458005d6103f9605b60005458005d610404605c60005458005d61040f605d60005458005d61041a605e60005458005d610425605f60005458005d610430606060005458005d61043b606160005458005d610446606260005458005d610451606360005458005d61045c606460005458005d610004585d60206000f2", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", "nonce" : "0", "storage" : { } From 8b8a67c7b6e67edcb2126fcf9c2bb80f69689e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Tue, 25 Nov 2014 00:42:07 +0100 Subject: [PATCH 336/396] output gas updated in vmPerformanceTest.json --- evmcc/test/vmtests/vmPerformanceTest.json | 46 +++++++++++------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/evmcc/test/vmtests/vmPerformanceTest.json b/evmcc/test/vmtests/vmPerformanceTest.json index b3e47ae16..604e45993 100644 --- a/evmcc/test/vmtests/vmPerformanceTest.json +++ b/evmcc/test/vmtests/vmPerformanceTest.json @@ -4,7 +4,7 @@ "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentDifficulty" : "256", - "currentGasLimit" : "1000000", + "currentGasLimit" : "10000000", "currentNumber" : "0", "currentTimestamp" : "1", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" @@ -14,7 +14,7 @@ "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", "code" : "0x60015b68010000000000000000908060010109600356", "data" : "0x", - "gas" : "1000000", + "gas" : "10000000", "gasPrice" : "100000000000000", "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000" @@ -46,7 +46,7 @@ "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentDifficulty" : "256", - "currentGasLimit" : "10000000", + "currentGasLimit" : "100000000", "currentNumber" : "0", "currentTimestamp" : "1", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" @@ -56,13 +56,13 @@ "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", "data" : "0x", - "gas" : "10000000", + "gas" : "30000000", "gasPrice" : "100000000000000", "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000" }, - "gas" : "7799983", - "out" : "0x0", + "gas" : "6999982", + "out" : "0x00", "post" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", @@ -88,7 +88,7 @@ "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentDifficulty" : "256", - "currentGasLimit" : "10000000", + "currentGasLimit" : "100000000", "currentNumber" : "0", "currentTimestamp" : "1", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" @@ -96,19 +96,19 @@ "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x600760196010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", "data" : "0x", - "gas" : "10000000", + "gas" : "40000000", "gasPrice" : "100000000000000", "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000" }, - "gas" : "7374139", - "out" : "0x0000000000000000000000000000000000000000000000000000000000012511", + "gas" : "5886377", + "out" : "0x00000000000000000000000000000000000000000000000000000000000cb228", "post" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x600760196010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", "nonce" : "0", "storage" : { } @@ -117,7 +117,7 @@ "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x600760196010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", "nonce" : "0", "storage" : { } @@ -125,13 +125,13 @@ } }, - "ackermann36" : { + "ackermann37" : { "callcreates" : [ ], "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentDifficulty" : "256", - "currentGasLimit" : "10000000", + "currentGasLimit" : "20000000", "currentNumber" : "0", "currentTimestamp" : "1", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" @@ -139,19 +139,19 @@ "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6009600360066012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", "data" : "0x", - "gas" : "10000000", + "gas" : "20000000", "gasPrice" : "100000000000000", "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000" }, - "gas" : "5865402", - "out" : "0x00000000000000000000000000000000000000000000000000000000000001fd", + "gas" : "913456", + "out" : "0x00000000000000000000000000000000000000000000000000000000000003fd", "post" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x6009600360066012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", "nonce" : "0", "storage" : { } @@ -160,7 +160,7 @@ "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", - "code" : "0x6009600360066012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", "nonce" : "0", "storage" : { } @@ -184,12 +184,12 @@ "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", "data" : "0x", - "gas" : "10000000", + "gas" : "1000000", "gasPrice" : "100000000000000", "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000" }, - "gas" : "4900496", + "gas" : "389596", "out" : "0x0000000000000000000000000000000000000000000000000000000000000064", "post" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { From bcee6e6921662b46c3a445da9d52aac9f7b3cb6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 26 Nov 2014 21:37:40 +0100 Subject: [PATCH 337/396] I don't know what I was thinking: always use interpreter in Executive (for now) --- libethereum/Executive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index f7cbcf3e3..f609c9c14 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -137,7 +137,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception); // Execute _init. - m_vm = VMFace::create(VMFace::JIT, _gas).release(); + m_vm = VMFace::create(VMFace::Interpreter, _gas).release(); m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms); return _init.empty(); } From 312e05ab49fb300c1f66a416873cc93abfb19253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Fri, 28 Nov 2014 00:37:24 +0100 Subject: [PATCH 338/396] resolved circular dependency between libevm and libevmjit --- exp/CMakeLists.txt | 1 + libethereum/CMakeLists.txt | 3 +++ libethereum/Executive.cpp | 4 ++-- libethereum/State.cpp | 4 ++-- libethereum/State.h | 8 +++++--- libevm/VM.h | 4 +++- libevm/VMFace.cpp | 12 ++---------- libevm/VMFace.h | 6 +----- libevmjit/VM.cpp | 1 + libevmjit/VM.h | 8 +++++++- test/createRandomTest.cpp | 3 ++- test/vm.cpp | 10 +++++++--- 12 files changed, 36 insertions(+), 28 deletions(-) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index fce739007..156de203f 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,6 +18,7 @@ endif() target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) if(EVMJIT) + target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evmjit) endif() diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index cb2049886..6088525fb 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -28,6 +28,9 @@ endif() target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS}) target_link_libraries(${EXECUTABLE} gmp) +if (EVMJIT) + target_link_libraries(${EXECUTABLE} evmjit) +endif() if("${TARGET_PLATFORM}" STREQUAL "w64") target_link_libraries(${EXECUTABLE} boost_system-mt-s) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index f609c9c14..87e675e15 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -118,7 +118,7 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu if (m_s.addressHasCode(_receiveAddress)) { - m_vm = VMFace::create(VMFace::Interpreter, _gas).release(); + m_vm = VMFactory::create(VMFactory::Interpreter, _gas).release(); bytes const& c = m_s.code(_receiveAddress); m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms); } @@ -137,7 +137,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception); // Execute _init. - m_vm = VMFace::create(VMFace::Interpreter, _gas).release(); + m_vm = VMFactory::create(VMFactory::Interpreter, _gas).release(); m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms); return _init.empty(); } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 4e5f5226c..2f8f4063f 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1214,7 +1214,7 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA } else if (addressHasCode(_codeAddress)) { - auto vmObj = VMFace::create(getVMKind(), *_gas); + auto vmObj = VMFactory::create(getVMKind(), *_gas); auto& vm = *vmObj; ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level); bool revert = false; @@ -1274,7 +1274,7 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, m_cache[newAddress] = Account(balance(newAddress) + _endowment, Account::ContractConception); // Execute init code. - auto vmObj = VMFace::create(getVMKind(), *_gas); + auto vmObj = VMFactory::create(getVMKind(), *_gas); auto& vm = *vmObj; ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); bool revert = false; diff --git a/libethereum/State.h b/libethereum/State.h index 96d53bc9e..f7bc0d119 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include "TransactionReceipt.h" #include "Executive.h" #include "AccountDiff.h" +#include "VMFactory.h" namespace dev { @@ -261,10 +263,10 @@ public: void cleanup(bool _fullCommit); /// Sets VM kind to be used by the state - void setVMKind(VMFace::Kind _kind) { m_vmKind = _kind; } + void setVMKind(VMFactory::Kind _kind) { m_vmKind = _kind; } /// Get the kind of VM used by the state - VMFace::Kind getVMKind() const { return m_vmKind; } + VMFactory::Kind getVMKind() const { return m_vmKind; } private: /// Undo the changes to the state for committing to mine. @@ -333,7 +335,7 @@ private: u256 m_blockReward; - VMFace::Kind m_vmKind = VMFace::Interpreter; ///< The kind of VM used by the state + VMFactory::Kind m_vmKind = VMFactory::Interpreter; ///< The kind of VM used by the state static std::string c_defaultPath; diff --git a/libevm/VM.h b/libevm/VM.h index b7a98d262..f39bc9d4f 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -36,6 +36,8 @@ namespace dev namespace eth { +class VMFactory; + /** */ class VM : public VMFace @@ -53,7 +55,7 @@ public: u256s const& stack() const { return m_stack; } private: - friend VMFace; + friend VMFactory; explicit VM(u256 _gas = 0): VMFace(_gas) {} template diff --git a/libevm/VMFace.cpp b/libevm/VMFace.cpp index 3313ee926..9f8c6549c 100644 --- a/libevm/VMFace.cpp +++ b/libevm/VMFace.cpp @@ -22,15 +22,7 @@ using namespace dev; using namespace dev::eth; -std::unique_ptr VMFace::create(VMFace::Kind _kind, u256 _gas) +void VMFace::reset(u256 _gas) noexcept { - std::unique_ptr vm; -#if ETH_EVMJIT - vm.reset(_kind == Kind::JIT ? static_cast(new jit::VM) : new VM); -#else - (void) _kind; // suppress unused var warning - vm.reset(new VM); -#endif - vm->reset(_gas); - return vm; + m_gas = _gas; } diff --git a/libevm/VMFace.h b/libevm/VMFace.h index 76dc8a219..6617db1da 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -62,16 +62,12 @@ public: VMFace(VMFace const&) = delete; void operator=(VMFace const&) = delete; - virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; } + virtual void reset(u256 _gas = 0) noexcept; virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; u256 gas() const { return m_gas; } - enum Kind: bool { Interpreter, JIT }; - - static std::unique_ptr create(Kind, u256 _gas = 0); - protected: u256 m_gas = 0; }; diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 9b60fccf1..b968008aa 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -2,6 +2,7 @@ #include "VM.h" #include +#include #include "ExecutionEngine.h" #include "Compiler.h" diff --git a/libevmjit/VM.h b/libevmjit/VM.h index 93b359cd7..1c6c71181 100644 --- a/libevmjit/VM.h +++ b/libevmjit/VM.h @@ -9,6 +9,9 @@ namespace dev { namespace eth { + +class VMFactory; + namespace jit { @@ -16,8 +19,11 @@ class VM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + enum Kind: bool { Interpreter, JIT }; + static std::unique_ptr create(Kind, u256 _gas = 0); + private: - friend VMFace; + friend VMFactory; explicit VM(u256 _gas = 0): VMFace(_gas) {} bytes m_output; diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index f22e5c0aa..87bb13846 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include "vm.h" @@ -128,7 +129,7 @@ void doMyTests(json_spirit::mValue& v) assert(o.count("exec") > 0); - auto vmObj = eth::VMFace::create(eth::VMFace::Interpreter); + auto vmObj = eth::VMFactory::create(eth::VMFactory::Interpreter); auto& vm = *vmObj; test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); diff --git a/test/vm.cpp b/test/vm.cpp index b34dc1829..ce0fe0808 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "vm.h" using namespace std; using namespace json_spirit; @@ -322,8 +323,11 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) auto useJit = false; for (auto i = 0; i < argc && !useJit; ++i) useJit |= std::string(argv[i]) == "--jit"; - auto vmKind = useJit ? VMFace::JIT : VMFace::Interpreter; - +#if ETH_EVMJIT + auto vmKind = useJit ? VMFactory::JIT : VMFactory::Interpreter; +#else + auto vmKind == VMFactory::Interpreter; +#endif dev::test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); @@ -339,7 +343,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) fev.code = fev.thisTxCode; } - auto vm = VMFace::create(vmKind, fev.gas); + auto vm = VMFactory::create(vmKind, fev.gas); bytes output; auto startTime = std::chrono::high_resolution_clock::now(); From 5a173029ad555bd452c3a1b6f618b65b6bf51a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Fri, 28 Nov 2014 01:23:40 +0100 Subject: [PATCH 339/396] forgot to add new source files --- libethereum/VMFactory.cpp | 28 ++++++++++++++++++++++++++++ libethereum/VMFactory.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 libethereum/VMFactory.cpp create mode 100644 libethereum/VMFactory.h diff --git a/libethereum/VMFactory.cpp b/libethereum/VMFactory.cpp new file mode 100644 index 000000000..1c8de319b --- /dev/null +++ b/libethereum/VMFactory.cpp @@ -0,0 +1,28 @@ +#include + +#if ETH_EVMJIT + #include +#endif + +#include "VMFactory.h" + +namespace dev +{ +namespace eth +{ + +std::unique_ptr VMFactory::create(VMFactory::Kind _kind, u256 _gas) +{ +#if ETH_EVMJIT + auto vm = _kind == Kind::JIT ? static_cast(new jit::VM) + : static_cast(new VM); +#else + VMFace* vm = new VM; +#endif + + vm->reset(_gas); + return std::unique_ptr(vm); +} + +} +} diff --git a/libethereum/VMFactory.h b/libethereum/VMFactory.h new file mode 100644 index 000000000..5d8edc391 --- /dev/null +++ b/libethereum/VMFactory.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace dev +{ +namespace eth +{ + +/** + */ + +class VMFactory +{ +public: + enum Kind: bool { + Interpreter, +#if ETH_EVMJIT + JIT +#endif + }; + + static std::unique_ptr create(Kind, u256 _gas = 0); +}; + + +} +} From ce0fe1dfccc101f3a166f58c07a0dbc3a9879663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Fri, 28 Nov 2014 01:32:57 +0100 Subject: [PATCH 340/396] added reference to libevmjit to alethzero's CMakeLists.txt --- alethzero/CMakeLists.txt | 3 +++ exp/CMakeLists.txt | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 01dfb88dc..721ab79ba 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -54,6 +54,9 @@ endif () qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmcore devcore web3jsonrpc jsqrc) +if (EVMJIT) + target_link_libraries(${EXECUTEABLE} evmjit) +endif() if (APPLE) # First have qt5 install plugins and frameworks diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index 156de203f..fce739007 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,7 +18,6 @@ endif() target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) if(EVMJIT) - target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evmjit) endif() From 0a8fb84ce7c212c61bd39ba64ad21c4e5c8bf832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Fri, 28 Nov 2014 11:56:50 +0100 Subject: [PATCH 341/396] fixed bug in implementation of LOG --- libevmjit/Ext.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 17cbf5dc4..6eb35acda 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -167,8 +167,8 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr) void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array const& _topics) { - static llvm::Value* args[] = {nullptr, m_args[0], m_args[1], m_arg2, m_arg3, m_arg4, m_arg5}; - static llvm::Value* funcs[] = {m_log0, m_log1, m_log2, m_log3, m_log4}; + llvm::Value* args[] = {nullptr, m_args[0], m_args[1], m_arg2, m_arg3, m_arg4, m_arg5}; + llvm::Value* funcs[] = {m_log0, m_log1, m_log2, m_log3, m_log4}; args[0] = getRuntimeManager().getRuntimePtr(); m_builder.CreateStore(_memIdx, m_args[0]); @@ -320,8 +320,8 @@ extern "C" { auto&& ext = _rt->getExt(); - auto memIdx = static_cast(llvm2eth(*_memIdx)); - auto numBytes = static_cast(llvm2eth(*_numBytes)); + auto memIdx = llvm2eth(*_memIdx).convert_to(); + auto numBytes = llvm2eth(*_numBytes).convert_to(); auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); ext.log({}, dataRef); From 72b9da57123222b3e0f5347835e02c3e2b6ad96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Fri, 28 Nov 2014 15:25:41 +0100 Subject: [PATCH 342/396] correct calculation of LOG cost --- libevmjit/Compiler.cpp | 3 +++ libevmjit/GasMeter.cpp | 18 ++++++++++++++++++ libevmjit/GasMeter.h | 3 +++ 3 files changed, 24 insertions(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 94e1450cd..1cc86d8aa 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -805,6 +805,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto numBytes = stack.pop(); _memory.require(beginIdx, numBytes); + // This will commit the current cost block + _gasMeter.countLogData(numBytes); + std::array topics; auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); for (size_t i = 0; i < numTopics; ++i) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 734931c32..48499259a 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -47,6 +47,16 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure case Instruction::CREATE: return static_cast(c_createGas); + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + return static_cast(c_logGas) + numTopics * static_cast(c_logTopicGas); + } + default: // Assumes instruction code is valid return static_cast(c_stepGas); } @@ -138,6 +148,14 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu createCall(m_gasCheckFunc, cost); } +void GasMeter::countLogData(llvm::Value* _dataLength) +{ + assert(m_checkCall); + assert(m_blockCost > 0); // LOGn instruction is already counted + auto cost = m_builder.CreateMul(_dataLength, Constant::get(c_logDataGas), "logdata_cost"); + commitCostBlock(cost); +} + void GasMeter::giveBack(llvm::Value* _gas) { m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 4be6c1a02..dfb4fb548 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -24,6 +24,9 @@ public: /// Calculate & count gas cost for SSTORE instruction void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); + /// Count gas cost of LOG data + void countLogData(llvm::Value* _dataLength); + /// Finalize cost-block by checking gas needed for the block before the block /// @param _additionalCost adds additional cost to cost-block before commit void commitCostBlock(llvm::Value* _additionalCost = nullptr); From 965af120d6fd51a09b007c92921855a0d715014b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 1 Dec 2014 15:58:49 +0100 Subject: [PATCH 343/396] C Interface draft 1 --- libevmjit/interface.c | 30 ++++++++++++++++++++++++++++++ windows/LibEvmJit.vcxproj | 1 + windows/LibEvmJit.vcxproj.filters | 3 +++ 3 files changed, 34 insertions(+) create mode 100644 libevmjit/interface.c diff --git a/libevmjit/interface.c b/libevmjit/interface.c new file mode 100644 index 000000000..47589578b --- /dev/null +++ b/libevmjit/interface.c @@ -0,0 +1,30 @@ +#include + +// JIT object opaque type +typedef struct evm_jit evm_jit; + +// Contract execution return code +typedef int evm_jit_return_code; + +// Host-endian 256-bit integer type +typedef struct i256 i256; + +// Big-endian right aligned 256-bit hash +typedef struct h256 h256; + +// Runtime data struct - must be provided by external language (Go, C++, Python) +typedef struct evm_jit_rt evm_jit_rt; + +// Runtime callback functions - implementations must be provided by external language (Go, C++, Python) +void evm_jit_rt_sload(evm_jit_rt* _rt, i256* _index, i256* _ret); +void evm_jit_rt_sstore(evm_jit_rt* _rt, i256* _index, i256* _value); +void evm_jit_rt_balance(evm_jit_rt* _rt, h256* _address, i256* _ret); +// And so on... + +evm_jit* evm_jit_create(evm_jit_rt* _runtime_data); + +evm_jit_return_code evm_jit_execute(evm_jit* _jit); + +void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); + +void evm_jit_destroy(evm_jit* _jit); diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index a9288a212..50824fb2d 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -131,6 +131,7 @@ + diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters index ae89fe550..1a0d86e56 100644 --- a/windows/LibEvmJit.vcxproj.filters +++ b/windows/LibEvmJit.vcxproj.filters @@ -48,6 +48,9 @@ libevmjit + + libevmjit + From 428468e2d221f5ab86acc06180b09ab905a456f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 1 Dec 2014 18:17:44 +0100 Subject: [PATCH 344/396] MSVS update --- windows/LibEthereum.vcxproj | 4 +++- windows/LibEthereum.vcxproj.filters | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 4ae5d5bf8..66efe7dc2 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -125,6 +125,7 @@ + @@ -342,6 +343,7 @@ + @@ -574,4 +576,4 @@ - + \ No newline at end of file diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index fd03dd451..85f1fdedc 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -190,12 +190,6 @@ libdevcrypto - - libdevcrypto - - - libdevcrypto - libethereum @@ -205,6 +199,11 @@ libevm + + + + libethereum + @@ -444,6 +443,9 @@ libevm + + libethereum + @@ -480,4 +482,4 @@ {d838fece-fc20-42f6-bff5-97c236159b80} - + \ No newline at end of file From 1ff8b68e91244417899ec2f4df9bbb0fd1e5323b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 16:50:00 +0100 Subject: [PATCH 345/396] Add evmjit submodule --- .gitmodules | 4 ++++ evmjit | 1 + 2 files changed, 5 insertions(+) create mode 100644 .gitmodules create mode 160000 evmjit diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d7fb4f437 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "evmjit"] + path = evmjit + url = ../evmjit + branch = develop diff --git a/evmjit b/evmjit new file mode 160000 index 000000000..49b82cdba --- /dev/null +++ b/evmjit @@ -0,0 +1 @@ +Subproject commit 49b82cdbac09c3c2058e0b4326645e5da37f7133 From 8ab7030ebc86a2444eadcb7a8734014ce1acd8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Thu, 4 Dec 2014 12:43:10 +0100 Subject: [PATCH 346/396] added some more VM performance tests --- .../test/vmtests/vmArithPerformanceTest.json | 260 ++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 evmcc/test/vmtests/vmArithPerformanceTest.json diff --git a/evmcc/test/vmtests/vmArithPerformanceTest.json b/evmcc/test/vmtests/vmArithPerformanceTest.json new file mode 100644 index 000000000..d9017517f --- /dev/null +++ b/evmcc/test/vmtests/vmArithPerformanceTest.json @@ -0,0 +1,260 @@ +{ + "arith-1" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "999538", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-2" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "995488", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-3" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "954988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-4" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "549988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { } + } + } + } + + + , + + + "arith-5" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "5499988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { } + } + } + } + +, + + "arith-6" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "data" : "0x", + "gas" : "100000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "54999988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { } + } + } + } + +} From e087c5afcfbe7a997b34e6096cca0540d89056d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 16:55:04 +0100 Subject: [PATCH 347/396] Windows configuration for evmjit submodule --- evmjit | 2 +- windows/Eth.vcxproj | 4 +- windows/Ethereum.sln | 19 +++- windows/LibEvmJit.vcxproj | 70 +++++++------ windows/LibEvmJit.vcxproj.filters | 123 +++++++---------------- windows/LibEvmJitCpp.vcxproj | 143 +++++++++++++++++++++++++++ windows/LibEvmJitCpp.vcxproj.filters | 13 +++ windows/TestEthereum.vcxproj | 9 +- windows/evmcc.vcxproj | 4 +- 9 files changed, 252 insertions(+), 135 deletions(-) create mode 100644 windows/LibEvmJitCpp.vcxproj create mode 100644 windows/LibEvmJitCpp.vcxproj.filters diff --git a/evmjit b/evmjit index 49b82cdba..6f84f3d1a 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 49b82cdbac09c3c2058e0b4326645e5da37f7133 +Subproject commit 6f84f3d1ade42bcacc99533d4807b9b759a5938b diff --git a/windows/Eth.vcxproj b/windows/Eth.vcxproj index d67d964f8..6736e0f12 100644 --- a/windows/Eth.vcxproj +++ b/windows/Eth.vcxproj @@ -155,8 +155,8 @@ {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} - - {9c816740-5c11-4377-a3a7-46be12f35fa0} + + {a5d8764c-fd17-4364-afcf-5baf78777569} diff --git a/windows/Ethereum.sln b/windows/Ethereum.sln index 4d2c7a3b4..ba804b16c 100644 --- a/windows/Ethereum.sln +++ b/windows/Ethereum.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Express 2013 for Windows Desktop -VisualStudioVersion = 12.0.30723.0 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libs", "Libs", "{988F2383-FA1D-408B-BCF6-C0EE7AB0A560}" EndProject @@ -47,6 +47,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "evmcc", "evmcc.vcxproj", "{ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibEvmJit", "LibEvmJit.vcxproj", "{9C816740-5C11-4377-A3A7-46BE12F35FA0}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibEvmJitCpp", "LibEvmJitCpp.vcxproj", "{A5D8764C-FD17-4364-AFCF-5BAF78777569}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Mixed Platforms = Debug|Mixed Platforms @@ -257,6 +259,18 @@ Global {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|Win32.Build.0 = Release|Win32 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|x64.ActiveCfg = Release|x64 {9C816740-5C11-4377-A3A7-46BE12F35FA0}.Release|x64.Build.0 = Release|x64 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Debug|Win32.ActiveCfg = Debug|Win32 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Debug|Win32.Build.0 = Debug|Win32 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Debug|x64.ActiveCfg = Debug|x64 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Debug|x64.Build.0 = Debug|x64 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Release|Mixed Platforms.Build.0 = Release|Win32 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Release|Win32.ActiveCfg = Release|Win32 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Release|Win32.Build.0 = Release|Win32 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Release|x64.ActiveCfg = Release|x64 + {A5D8764C-FD17-4364-AFCF-5BAF78777569}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -272,5 +286,6 @@ Global {DF3C5B07-A1A2-4F16-B37F-A27333622CDD} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} {F174E81A-2A66-4693-B917-11BB42D3658C} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} {9C816740-5C11-4377-A3A7-46BE12F35FA0} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} + {A5D8764C-FD17-4364-AFCF-5BAF78777569} = {988F2383-FA1D-408B-BCF6-C0EE7AB0A560} EndGlobalSection EndGlobal diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index 50824fb2d..077757aab 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -123,42 +123,48 @@ - - - - - - - - - - - - - - - + + {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} - + + + + + + + + + + + + + + + + + + + + diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters index 1a0d86e56..06f1ed308 100644 --- a/windows/LibEvmJit.vcxproj.filters +++ b/windows/LibEvmJit.vcxproj.filters @@ -1,99 +1,42 @@  - - {9bb7d84d-6d6c-48af-a954-60049208b2f1} - + + + + + + + + + + + + + + + - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - + + + + + + + + + + + + + + + + + - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - - - libevmjit - + \ No newline at end of file diff --git a/windows/LibEvmJitCpp.vcxproj b/windows/LibEvmJitCpp.vcxproj new file mode 100644 index 000000000..a5094e49c --- /dev/null +++ b/windows/LibEvmJitCpp.vcxproj @@ -0,0 +1,143 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {A5D8764C-FD17-4364-AFCF-5BAF78777569} + LibEvmJitCpp + + + + StaticLibrary + true + v120 + + + StaticLibrary + true + v120 + + + StaticLibrary + false + v120 + true + + + StaticLibrary + false + v120 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + + + + + + + + + + + {9c816740-5c11-4377-a3a7-46be12f35fa0} + + + + + + \ No newline at end of file diff --git a/windows/LibEvmJitCpp.vcxproj.filters b/windows/LibEvmJitCpp.vcxproj.filters new file mode 100644 index 000000000..0c37264b0 --- /dev/null +++ b/windows/LibEvmJitCpp.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index d81fe613a..93bb98e23 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -73,7 +73,7 @@ true - true + false false @@ -189,11 +189,8 @@ - - {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} - - - {9c816740-5c11-4377-a3a7-46be12f35fa0} + + {a5d8764c-fd17-4364-afcf-5baf78777569} diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index e7bf633fa..a0e64ad6f 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -22,8 +22,8 @@ - - {9c816740-5c11-4377-a3a7-46be12f35fa0} + + {a5d8764c-fd17-4364-afcf-5baf78777569} From abe5c5c37dcd5e1f389918316d9c1a3960e0a619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 08:49:30 +0100 Subject: [PATCH 348/396] MSVS evmcc project updated --- windows/evmcc.vcxproj | 9 ++++++--- windows/evmcc.vcxproj.filters | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj index a0e64ad6f..6cd0ece89 100644 --- a/windows/evmcc.vcxproj +++ b/windows/evmcc.vcxproj @@ -18,14 +18,17 @@ x64 - - - {a5d8764c-fd17-4364-afcf-5baf78777569} + + + + + + {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} Win32Proj diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters index 6be5386a1..f70c861ba 100644 --- a/windows/evmcc.vcxproj.filters +++ b/windows/evmcc.vcxproj.filters @@ -1,6 +1,9 @@  - + + + + \ No newline at end of file From 68662deed6bbe09963c32d9a69557ad185e768d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 08:50:54 +0100 Subject: [PATCH 349/396] C++ emvjit connector header includes updated --- libethereum/VMFactory.cpp | 2 +- libevm/VMFace.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libethereum/VMFactory.cpp b/libethereum/VMFactory.cpp index 1c8de319b..a5910ed15 100644 --- a/libethereum/VMFactory.cpp +++ b/libethereum/VMFactory.cpp @@ -1,7 +1,7 @@ #include #if ETH_EVMJIT - #include + #include #endif #include "VMFactory.h" diff --git a/libevm/VMFace.cpp b/libevm/VMFace.cpp index 9f8c6549c..136bd5223 100644 --- a/libevm/VMFace.cpp +++ b/libevm/VMFace.cpp @@ -17,7 +17,6 @@ #include "VMFace.h" #include "VM.h" -#include using namespace dev; using namespace dev::eth; From 51f4383287f9b03ad085376cbb5dc87dc50ebc8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 09:12:28 +0100 Subject: [PATCH 350/396] Removing moved evmjit code --- evmcc/CMakeLists.txt | 51 - evmcc/evmcc.cpp | 199 ---- evmcc/test/arith/addmod.evm | 1 - evmcc/test/arith/addmod.lll | 12 - evmcc/test/arith/arith1.evm | 1 - evmcc/test/arith/arith1.lll | 37 - evmcc/test/arith/arith_bnot.evm | 1 - evmcc/test/arith/arith_bnot.lll | 14 - evmcc/test/arith/div.evm | 1 - evmcc/test/arith/div.lll | 10 - evmcc/test/arith/fib1.evm | 1 - evmcc/test/arith/fib1.lll | 57 -- evmcc/test/arith/mul.evm | 1 - evmcc/test/arith/mul.lll | 13 - evmcc/test/arith/mulmod.evm | 1 - evmcc/test/arith/mulmod.lll | 12 - evmcc/test/except/badinst1.evm | 1 - evmcc/test/ext/calldatacopy1.evm | 1 - evmcc/test/ext/calldatacopy1.lll | 13 - evmcc/test/ext/calldatacopy2.evm | 1 - evmcc/test/ext/calldatacopy2.lll | 13 - evmcc/test/ext/codecopy1.evm | 1 - evmcc/test/ext/codecopy1.lll | 13 - evmcc/test/ext/codecopy2.evm | 1 - evmcc/test/ext/codecopy2.lll | 13 - evmcc/test/ext/codecopy3.evm | 1 - evmcc/test/ext/codecopy3.lll | 13 - evmcc/test/ext/ext_test.evm | 1 - evmcc/test/ext/ext_test.lll | 55 -- evmcc/test/ext/extcodecopy1.evm | 1 - evmcc/test/ext/extcodecopy1.lll | 11 - evmcc/test/ext/store_delete.evm | 1 - evmcc/test/ext/store_delete.lll | 9 - evmcc/test/ext/store_test.evm | 1 - evmcc/test/ext/store_test.lll | 14 - evmcc/test/jump/ackermann.ethel | 7 - evmcc/test/jump/ackermann.evm | 1 - evmcc/test/jump/badindirect1.evm | 1 - evmcc/test/jump/badindirect1.lll | 9 - evmcc/test/jump/badindirect2.evm | 1 - evmcc/test/jump/badindirect2.lll | 12 - evmcc/test/jump/badjump1.evm | 1 - evmcc/test/jump/badjump1.lll | 6 - evmcc/test/jump/badjump2.evm | 1 - evmcc/test/jump/badjump2.lll | 9 - evmcc/test/jump/call1.ethel | 5 - evmcc/test/jump/call1.evm | 1 - evmcc/test/jump/call2.ethel | 5 - evmcc/test/jump/call2.evm | 1 - evmcc/test/jump/fac.ethel | 5 - evmcc/test/jump/fac.evm | 1 - evmcc/test/jump/fac_tail.ethel | 5 - evmcc/test/jump/fac_tail.evm | 1 - evmcc/test/jump/fib1.ethel | 6 - evmcc/test/jump/fib1.evm | 1 - evmcc/test/jump/for1.evm | 1 - evmcc/test/jump/for1.lll | 3 - evmcc/test/jump/for2.evm | 1 - evmcc/test/jump/for2.lll | 3 - evmcc/test/jump/if1.ethel | 1 - evmcc/test/jump/if1.evm | 1 - evmcc/test/jump/if2.ethel | 1 - evmcc/test/jump/if2.evm | 1 - evmcc/test/jump/indirect1.evm | 1 - evmcc/test/jump/indirect1.lll | 13 - evmcc/test/jump/indirect2.evm | 1 - evmcc/test/jump/indirect2.lll | 19 - evmcc/test/jump/indirect3.evm | 1 - evmcc/test/jump/indirect3.lll | 14 - evmcc/test/jump/indirect4.evm | 1 - evmcc/test/jump/indirect4.lll | 15 - evmcc/test/jump/jump1.evm | 1 - evmcc/test/jump/jump1.lll | 11 - evmcc/test/jump/jump2.evm | 1 - evmcc/test/jump/jump2.lll | 10 - evmcc/test/jump/jump3.evm | 1 - evmcc/test/jump/jump3.lll | 10 - evmcc/test/jump/jump4.evm | 1 - evmcc/test/jump/jump4.lll | 17 - evmcc/test/jump/jump5.evm | 1 - evmcc/test/jump/jump5.lll | 16 - evmcc/test/jump/jump6.evm | 1 - evmcc/test/jump/jump6.lll | 32 - evmcc/test/jump/jumpi_at_the_end.evm | 1 - evmcc/test/jump/jumpi_at_the_end.lll | 1 - evmcc/test/jump/loop1.evm | 1 - evmcc/test/jump/loop1.lll | 27 - evmcc/test/jump/loop2.evm | 1 - evmcc/test/jump/loop2.lll | 28 - evmcc/test/jump/rec1.ethel | 4 - evmcc/test/jump/rec1.evm | 1 - evmcc/test/jump/when1.asm | 10 - evmcc/test/jump/when1.evm | 1 - evmcc/test/jump/when1.lll | 2 - evmcc/test/kv.evm | 1 - evmcc/test/kv.lll | 10 - evmcc/test/mem/byte.evm | 1 - evmcc/test/mem/byte.lll | 105 -- evmcc/test/mem/mem2.evm | 1 - evmcc/test/mem/mem2.lll | 15 - evmcc/test/mem/memtest1.evm | 1 - evmcc/test/mem/memtest1.lll | 18 - evmcc/test/mem/mstore1.evm | 1 - evmcc/test/mem/mstore1.lll | 6 - evmcc/test/ret/return1.evm | 1 - evmcc/test/ret/return1.lll | 6 - evmcc/test/ret/return2.evm | 1 - evmcc/test/ret/return2.lll | 6 - evmcc/test/ret/return_test.evm | 1 - evmcc/test/ret/return_test.lll | 15 - evmcc/test/stack/oos.evm | 1 - evmcc/test/stack/oos.lll | 11 - evmcc/test/stack/push_test.evm | 1 - evmcc/test/stack/push_test.lll | 35 - evmcc/test/stack/stack_test.evm | 1 - evmcc/test/stack/stack_test.lll | 8 - evmcc/test/stack/stackjump.evm | 1 - evmcc/test/stack/stackjump.lll | 3 - evmcc/test/stack/swap.evm | 1 - evmcc/test/stack/swap.lll | 31 - evmcc/test/stack/swapswap.evm | 1 - evmcc/test/stack/swapswap.lll | 32 - evmcc/test/stack/test.evm | 1 - .../test/vmtests/vmArithPerformanceTest.json | 260 ----- evmcc/test/vmtests/vmPerformanceTest.json | 214 ---- evmcc/test/vmtests/vm_jump.json | 41 - libevmjit/Arith256.cpp | 159 --- libevmjit/Arith256.h | 47 - libevmjit/BasicBlock.cpp | 382 ------- libevmjit/BasicBlock.h | 117 --- libevmjit/CMakeLists.txt | 58 -- libevmjit/Compiler.cpp | 933 ------------------ libevmjit/Compiler.h | 92 -- libevmjit/CompilerHelper.cpp | 44 - libevmjit/CompilerHelper.h | 83 -- libevmjit/Endianness.cpp | 25 - libevmjit/Endianness.h | 34 - libevmjit/ExecutionEngine.cpp | 132 --- libevmjit/ExecutionEngine.h | 28 - libevmjit/Ext.cpp | 420 -------- libevmjit/Ext.h | 69 -- libevmjit/GasMeter.cpp | 199 ---- libevmjit/GasMeter.h | 54 - libevmjit/Memory.cpp | 218 ---- libevmjit/Memory.h | 49 - libevmjit/Runtime.cpp | 210 ---- libevmjit/Runtime.h | 122 --- libevmjit/Stack.cpp | 112 --- libevmjit/Stack.h | 43 - libevmjit/Type.cpp | 59 -- libevmjit/Type.h | 63 -- libevmjit/Utils.cpp | 57 -- libevmjit/Utils.h | 107 -- libevmjit/VM.cpp | 46 - libevmjit/VM.h | 34 - libevmjit/interface.c | 30 - 156 files changed, 5768 deletions(-) delete mode 100644 evmcc/CMakeLists.txt delete mode 100644 evmcc/evmcc.cpp delete mode 100644 evmcc/test/arith/addmod.evm delete mode 100644 evmcc/test/arith/addmod.lll delete mode 100644 evmcc/test/arith/arith1.evm delete mode 100644 evmcc/test/arith/arith1.lll delete mode 100644 evmcc/test/arith/arith_bnot.evm delete mode 100644 evmcc/test/arith/arith_bnot.lll delete mode 100644 evmcc/test/arith/div.evm delete mode 100644 evmcc/test/arith/div.lll delete mode 100644 evmcc/test/arith/fib1.evm delete mode 100644 evmcc/test/arith/fib1.lll delete mode 100644 evmcc/test/arith/mul.evm delete mode 100644 evmcc/test/arith/mul.lll delete mode 100644 evmcc/test/arith/mulmod.evm delete mode 100644 evmcc/test/arith/mulmod.lll delete mode 100644 evmcc/test/except/badinst1.evm delete mode 100644 evmcc/test/ext/calldatacopy1.evm delete mode 100644 evmcc/test/ext/calldatacopy1.lll delete mode 100644 evmcc/test/ext/calldatacopy2.evm delete mode 100644 evmcc/test/ext/calldatacopy2.lll delete mode 100644 evmcc/test/ext/codecopy1.evm delete mode 100644 evmcc/test/ext/codecopy1.lll delete mode 100644 evmcc/test/ext/codecopy2.evm delete mode 100644 evmcc/test/ext/codecopy2.lll delete mode 100644 evmcc/test/ext/codecopy3.evm delete mode 100644 evmcc/test/ext/codecopy3.lll delete mode 100644 evmcc/test/ext/ext_test.evm delete mode 100644 evmcc/test/ext/ext_test.lll delete mode 100644 evmcc/test/ext/extcodecopy1.evm delete mode 100644 evmcc/test/ext/extcodecopy1.lll delete mode 100644 evmcc/test/ext/store_delete.evm delete mode 100644 evmcc/test/ext/store_delete.lll delete mode 100644 evmcc/test/ext/store_test.evm delete mode 100644 evmcc/test/ext/store_test.lll delete mode 100644 evmcc/test/jump/ackermann.ethel delete mode 100644 evmcc/test/jump/ackermann.evm delete mode 100644 evmcc/test/jump/badindirect1.evm delete mode 100644 evmcc/test/jump/badindirect1.lll delete mode 100644 evmcc/test/jump/badindirect2.evm delete mode 100644 evmcc/test/jump/badindirect2.lll delete mode 100644 evmcc/test/jump/badjump1.evm delete mode 100644 evmcc/test/jump/badjump1.lll delete mode 100644 evmcc/test/jump/badjump2.evm delete mode 100644 evmcc/test/jump/badjump2.lll delete mode 100644 evmcc/test/jump/call1.ethel delete mode 100644 evmcc/test/jump/call1.evm delete mode 100644 evmcc/test/jump/call2.ethel delete mode 100644 evmcc/test/jump/call2.evm delete mode 100644 evmcc/test/jump/fac.ethel delete mode 100644 evmcc/test/jump/fac.evm delete mode 100644 evmcc/test/jump/fac_tail.ethel delete mode 100644 evmcc/test/jump/fac_tail.evm delete mode 100644 evmcc/test/jump/fib1.ethel delete mode 100644 evmcc/test/jump/fib1.evm delete mode 100644 evmcc/test/jump/for1.evm delete mode 100644 evmcc/test/jump/for1.lll delete mode 100644 evmcc/test/jump/for2.evm delete mode 100644 evmcc/test/jump/for2.lll delete mode 100644 evmcc/test/jump/if1.ethel delete mode 100644 evmcc/test/jump/if1.evm delete mode 100644 evmcc/test/jump/if2.ethel delete mode 100644 evmcc/test/jump/if2.evm delete mode 100644 evmcc/test/jump/indirect1.evm delete mode 100644 evmcc/test/jump/indirect1.lll delete mode 100644 evmcc/test/jump/indirect2.evm delete mode 100644 evmcc/test/jump/indirect2.lll delete mode 100644 evmcc/test/jump/indirect3.evm delete mode 100644 evmcc/test/jump/indirect3.lll delete mode 100644 evmcc/test/jump/indirect4.evm delete mode 100644 evmcc/test/jump/indirect4.lll delete mode 100644 evmcc/test/jump/jump1.evm delete mode 100644 evmcc/test/jump/jump1.lll delete mode 100644 evmcc/test/jump/jump2.evm delete mode 100644 evmcc/test/jump/jump2.lll delete mode 100644 evmcc/test/jump/jump3.evm delete mode 100644 evmcc/test/jump/jump3.lll delete mode 100644 evmcc/test/jump/jump4.evm delete mode 100644 evmcc/test/jump/jump4.lll delete mode 100644 evmcc/test/jump/jump5.evm delete mode 100644 evmcc/test/jump/jump5.lll delete mode 100644 evmcc/test/jump/jump6.evm delete mode 100644 evmcc/test/jump/jump6.lll delete mode 100644 evmcc/test/jump/jumpi_at_the_end.evm delete mode 100644 evmcc/test/jump/jumpi_at_the_end.lll delete mode 100644 evmcc/test/jump/loop1.evm delete mode 100644 evmcc/test/jump/loop1.lll delete mode 100644 evmcc/test/jump/loop2.evm delete mode 100644 evmcc/test/jump/loop2.lll delete mode 100644 evmcc/test/jump/rec1.ethel delete mode 100644 evmcc/test/jump/rec1.evm delete mode 100644 evmcc/test/jump/when1.asm delete mode 100644 evmcc/test/jump/when1.evm delete mode 100644 evmcc/test/jump/when1.lll delete mode 100644 evmcc/test/kv.evm delete mode 100644 evmcc/test/kv.lll delete mode 100644 evmcc/test/mem/byte.evm delete mode 100644 evmcc/test/mem/byte.lll delete mode 100644 evmcc/test/mem/mem2.evm delete mode 100644 evmcc/test/mem/mem2.lll delete mode 100644 evmcc/test/mem/memtest1.evm delete mode 100644 evmcc/test/mem/memtest1.lll delete mode 100644 evmcc/test/mem/mstore1.evm delete mode 100644 evmcc/test/mem/mstore1.lll delete mode 100644 evmcc/test/ret/return1.evm delete mode 100644 evmcc/test/ret/return1.lll delete mode 100644 evmcc/test/ret/return2.evm delete mode 100644 evmcc/test/ret/return2.lll delete mode 100644 evmcc/test/ret/return_test.evm delete mode 100644 evmcc/test/ret/return_test.lll delete mode 100644 evmcc/test/stack/oos.evm delete mode 100644 evmcc/test/stack/oos.lll delete mode 100644 evmcc/test/stack/push_test.evm delete mode 100644 evmcc/test/stack/push_test.lll delete mode 100644 evmcc/test/stack/stack_test.evm delete mode 100644 evmcc/test/stack/stack_test.lll delete mode 100644 evmcc/test/stack/stackjump.evm delete mode 100644 evmcc/test/stack/stackjump.lll delete mode 100644 evmcc/test/stack/swap.evm delete mode 100644 evmcc/test/stack/swap.lll delete mode 100644 evmcc/test/stack/swapswap.evm delete mode 100644 evmcc/test/stack/swapswap.lll delete mode 100644 evmcc/test/stack/test.evm delete mode 100644 evmcc/test/vmtests/vmArithPerformanceTest.json delete mode 100644 evmcc/test/vmtests/vmPerformanceTest.json delete mode 100644 evmcc/test/vmtests/vm_jump.json delete mode 100644 libevmjit/Arith256.cpp delete mode 100644 libevmjit/Arith256.h delete mode 100644 libevmjit/BasicBlock.cpp delete mode 100644 libevmjit/BasicBlock.h delete mode 100644 libevmjit/CMakeLists.txt delete mode 100644 libevmjit/Compiler.cpp delete mode 100644 libevmjit/Compiler.h delete mode 100644 libevmjit/CompilerHelper.cpp delete mode 100644 libevmjit/CompilerHelper.h delete mode 100644 libevmjit/Endianness.cpp delete mode 100644 libevmjit/Endianness.h delete mode 100644 libevmjit/ExecutionEngine.cpp delete mode 100644 libevmjit/ExecutionEngine.h delete mode 100644 libevmjit/Ext.cpp delete mode 100644 libevmjit/Ext.h delete mode 100644 libevmjit/GasMeter.cpp delete mode 100644 libevmjit/GasMeter.h delete mode 100644 libevmjit/Memory.cpp delete mode 100644 libevmjit/Memory.h delete mode 100644 libevmjit/Runtime.cpp delete mode 100644 libevmjit/Runtime.h delete mode 100644 libevmjit/Stack.cpp delete mode 100644 libevmjit/Stack.h delete mode 100644 libevmjit/Type.cpp delete mode 100644 libevmjit/Type.h delete mode 100644 libevmjit/Utils.cpp delete mode 100644 libevmjit/Utils.h delete mode 100644 libevmjit/VM.cpp delete mode 100644 libevmjit/VM.h delete mode 100644 libevmjit/interface.c diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt deleted file mode 100644 index a087539dc..000000000 --- a/evmcc/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -cmake_policy(SET CMP0015 NEW) - -aux_source_directory(. SRC_LIST) - -include_directories(..) - -set(EXECUTABLE evmcc) - -add_executable(${EXECUTABLE} ${SRC_LIST}) - -target_link_libraries(${EXECUTABLE} boost_program_options) -target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} evmjit) -target_link_libraries(${EXECUTABLE} evm) -target_link_libraries(${EXECUTABLE} ethereum) - -if ("${TARGET_PLATFORM}" STREQUAL "w64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") - target_link_libraries(${EXECUTABLE} gcc) - target_link_libraries(${EXECUTABLE} gdi32) - target_link_libraries(${EXECUTABLE} ws2_32) - target_link_libraries(${EXECUTABLE} mswsock) - target_link_libraries(${EXECUTABLE} shlwapi) - target_link_libraries(${EXECUTABLE} iphlpapi) - target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) - set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) -else () - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -endif () - -# LLVM specific commands - -find_package(LLVM REQUIRED CONFIG) - -message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") -message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - -include_directories(${LLVM_INCLUDE_DIRS}) -add_definitions(${LLVM_DEFINITIONS}) - -llvm_map_components_to_libnames(llvm_libs bitwriter) -target_link_libraries(evmcc ${llvm_libs}) - -# end of LLVM specific commands - - -install( TARGETS ${EXECUTABLE} DESTINATION bin ) - -cmake_policy(SET CMP0015 NEW) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp deleted file mode 100644 index 16ab23e9b..000000000 --- a/evmcc/evmcc.cpp +++ /dev/null @@ -1,199 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - - -void parseProgramOptions(int _argc, char** _argv, boost::program_options::variables_map& _varMap) -{ - namespace opt = boost::program_options; - - opt::options_description explicitOpts("Allowed options"); - explicitOpts.add_options() - ("help,h", "show usage information") - ("compile,c", "compile the code to LLVM IR") - ("interpret,i", "compile the code to LLVM IR and execute") - ("gas,g", opt::value(), "set initial gas for execution") - ("disassemble,d", "dissassemble the code") - ("dump-cfg", "dump control flow graph to graphviz file") - ("dont-optimize", "turn off optimizations") - ("optimize-stack", "optimize stack use between basic blocks (default: on)") - ("rewrite-switch", "rewrite LLVM switch to branches (default: on)") - ("output-ll", opt::value(), "dump generated LLVM IR to file") - ("output-bc", opt::value(), "dump generated LLVM bitcode to file") - ("show-logs", "output LOG statements to stderr") - ("verbose,V", "enable verbose output"); - - opt::options_description implicitOpts("Input files"); - implicitOpts.add_options() - ("input-file", opt::value(), "input file"); - - opt::options_description allOpts(""); - allOpts.add(explicitOpts).add(implicitOpts); - - opt::positional_options_description inputOpts; - inputOpts.add("input-file", 1); - - const char* errorMsg = nullptr; - try - { - auto parser = opt::command_line_parser(_argc, _argv).options(allOpts).positional(inputOpts); - opt::store(parser.run(), _varMap); - opt::notify(_varMap); - } - catch (boost::program_options::error& err) - { - errorMsg = err.what(); - } - - if (!errorMsg && _varMap.count("input-file") == 0) - errorMsg = "missing input file name"; - - if (_varMap.count("disassemble") == 0 - && _varMap.count("compile") == 0 - && _varMap.count("interpret") == 0) - { - errorMsg = "at least one of -c, -i, -d is required"; - } - - if (errorMsg || _varMap.count("help")) - { - if (errorMsg) - std::cerr << "Error: " << errorMsg << std::endl; - - std::cout << "Usage: " << _argv[0] << " input-file " << std::endl - << explicitOpts << std::endl; - std::exit(errorMsg ? 1 : 0); - } -} - -int main(int argc, char** argv) -{ - boost::program_options::variables_map options; - parseProgramOptions(argc, argv, options); - - auto inputFile = options["input-file"].as(); - std::ifstream ifs(inputFile); - if (!ifs.is_open()) - { - std::cerr << "cannot open input file " << inputFile << std::endl; - exit(1); - } - - std::string src((std::istreambuf_iterator(ifs)), - (std::istreambuf_iterator())); - - boost::algorithm::trim(src); - - using namespace dev; - - bytes bytecode = fromHex(src); - - if (options.count("disassemble")) - { - std::string assembly = eth::disassemble(bytecode); - std::cout << assembly << std::endl; - } - - if (options.count("compile") || options.count("interpret")) - { - size_t initialGas = 10000; - - if (options.count("gas")) - initialGas = options["gas"].as(); - - auto compilationStartTime = std::chrono::high_resolution_clock::now(); - - eth::jit::Compiler::Options compilerOptions; - compilerOptions.dumpCFG = options.count("dump-cfg") > 0; - bool optimize = options.count("dont-optimize") == 0; - compilerOptions.optimizeStack = optimize || options.count("optimize-stack") > 0; - compilerOptions.rewriteSwitchToBranches = optimize || options.count("rewrite-switch") > 0; - - auto compiler = eth::jit::Compiler(compilerOptions); - auto module = compiler.compile(bytecode); - - auto compilationEndTime = std::chrono::high_resolution_clock::now(); - - module->dump(); - - if (options.count("output-ll")) - { - auto outputFile = options["output-ll"].as(); - std::ofstream ofs(outputFile); - if (!ofs.is_open()) - { - std::cerr << "cannot open output file " << outputFile << std::endl; - exit(1); - } - llvm::raw_os_ostream ros(ofs); - module->print(ros, nullptr); - ofs.close(); - } - - if (options.count("output-bc")) - { - auto outputFile = options["output-bc"].as(); - std::ofstream ofs(outputFile); - if (!ofs.is_open()) - { - std::cerr << "cannot open output file " << outputFile << std::endl; - exit(1); - } - llvm::raw_os_ostream ros(ofs); - llvm::WriteBitcodeToFile(module.get(), ros); - ros.flush(); - ofs.close(); - } - - if (options.count("verbose")) - { - std::cerr << "*** Compilation time: " - << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count() - << std::endl; - } - - if (options.count("interpret")) - { - auto engine = eth::jit::ExecutionEngine(); - u256 gas = initialGas; - - // Create fake ExtVM interface - eth::ExtVMFace ext; - ext.myAddress = Address(1122334455667788); - ext.caller = Address(0xfacefacefaceface); - ext.origin = Address(101010101010101010); - ext.value = 0xabcd; - ext.gasPrice = 1002; - ext.previousBlock.hash = u256(1003); - ext.currentBlock.coinbaseAddress = Address(1004); - ext.currentBlock.timestamp = 1005; - ext.currentBlock.number = 1006; - ext.currentBlock.difficulty = 1007; - ext.currentBlock.gasLimit = 1008; - ext.data = std::string("Hello the Beautiful World of Ethereum!"); - ext.code = { 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf }; - - auto result = engine.run(std::move(module), gas, options.count("show-logs") > 0, ext); - return result; - } - } - - return 0; -} diff --git a/evmcc/test/arith/addmod.evm b/evmcc/test/arith/addmod.evm deleted file mode 100644 index 4ca71e065..000000000 --- a/evmcc/test/arith/addmod.evm +++ /dev/null @@ -1 +0,0 @@ -60646107b760271460005560006001f2 diff --git a/evmcc/test/arith/addmod.lll b/evmcc/test/arith/addmod.lll deleted file mode 100644 index 11a6b2cb9..000000000 --- a/evmcc/test/arith/addmod.lll +++ /dev/null @@ -1,12 +0,0 @@ -;; Should return (1975 + 39) `mod` 100 = 14 = 0x0e -(asm -100 -1975 -39 -ADDMOD -0 -MSTORE8 -0 -1 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/arith/arith1.evm b/evmcc/test/arith/arith1.evm deleted file mode 100644 index c7a029f52..000000000 --- a/evmcc/test/arith/arith1.evm +++ /dev/null @@ -1 +0,0 @@ -60016001900160070260050160029004600490066021900560150160030260059007600303600960110860005460086000f2 diff --git a/evmcc/test/arith/arith1.lll b/evmcc/test/arith/arith1.lll deleted file mode 100644 index 4757a7420..000000000 --- a/evmcc/test/arith/arith1.lll +++ /dev/null @@ -1,37 +0,0 @@ - -(asm -1 -1 -SWAP1 -ADD ;; 2 -7 -MUL ;; 14 -5 -ADD ;; 19 -2 -SWAP1 -DIV ;; 9 -4 -SWAP1 -MOD ;; 1 -33 -SWAP1 -SDIV;; 0 -21 -ADD ;; 21 -3 -MUL ;; 63 -5 -SWAP1 -SMOD;; 3 -3 -SUB ;; 0 -9 -17 -EXP ;; 17^9 -0 -MSTORE -8 -0 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/arith/arith_bnot.evm b/evmcc/test/arith/arith_bnot.evm deleted file mode 100644 index 4cfaf8f55..000000000 --- a/evmcc/test/arith/arith_bnot.evm +++ /dev/null @@ -1 +0,0 @@ -6201e2406000546000530960005460206000f2 diff --git a/evmcc/test/arith/arith_bnot.lll b/evmcc/test/arith/arith_bnot.lll deleted file mode 100644 index a83b05a9a..000000000 --- a/evmcc/test/arith/arith_bnot.lll +++ /dev/null @@ -1,14 +0,0 @@ - -(asm -123456 -0 -MSTORE -0 -MLOAD -BNOT -0 -MSTORE -32 -0 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/arith/div.evm b/evmcc/test/arith/div.evm deleted file mode 100644 index b68d5d202..000000000 --- a/evmcc/test/arith/div.evm +++ /dev/null @@ -1 +0,0 @@ -60027ffedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432100460005460206000f2 diff --git a/evmcc/test/arith/div.lll b/evmcc/test/arith/div.lll deleted file mode 100644 index 72c22bfdc..000000000 --- a/evmcc/test/arith/div.lll +++ /dev/null @@ -1,10 +0,0 @@ -(asm -0x2 -0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 -DIV -0 -MSTORE -32 -0 -RETURN -) diff --git a/evmcc/test/arith/fib1.evm b/evmcc/test/arith/fib1.evm deleted file mode 100644 index 4c141314e..000000000 --- a/evmcc/test/arith/fib1.evm +++ /dev/null @@ -1 +0,0 @@ -60016001818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101 diff --git a/evmcc/test/arith/fib1.lll b/evmcc/test/arith/fib1.lll deleted file mode 100644 index 286bed275..000000000 --- a/evmcc/test/arith/fib1.lll +++ /dev/null @@ -1,57 +0,0 @@ -;; Fibbonacci unrolled - -(asm -1 -1 -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -) \ No newline at end of file diff --git a/evmcc/test/arith/mul.evm b/evmcc/test/arith/mul.evm deleted file mode 100644 index 7e8afd268..000000000 --- a/evmcc/test/arith/mul.evm +++ /dev/null @@ -1 +0,0 @@ -7001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba0987654321020260005460206000f2 diff --git a/evmcc/test/arith/mul.lll b/evmcc/test/arith/mul.lll deleted file mode 100644 index b0fa343bb..000000000 --- a/evmcc/test/arith/mul.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -0x1234567890abcdef0fedcba0987654321 -0x1234567890abcdef0fedcba0987654321 -0x1234567890abcdef0fedcba0987654321 -MUL -MUL -0 -MSTORE -32 -0 -RETURN -;; 47d0817e4167b1eb4f9fc722b133ef9d7d9a6fb4c2c1c442d000107a5e419561 -) diff --git a/evmcc/test/arith/mulmod.evm b/evmcc/test/arith/mulmod.evm deleted file mode 100644 index e34a06154..000000000 --- a/evmcc/test/arith/mulmod.evm +++ /dev/null @@ -1 +0,0 @@ -6064601b60251560005560006001f2 diff --git a/evmcc/test/arith/mulmod.lll b/evmcc/test/arith/mulmod.lll deleted file mode 100644 index 5e87f0843..000000000 --- a/evmcc/test/arith/mulmod.lll +++ /dev/null @@ -1,12 +0,0 @@ -;; Should return (27 * 37) `mod` 100 = 99 = 0x63 -(asm -100 -27 -37 -MULMOD -0 -MSTORE8 -0 -1 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/except/badinst1.evm b/evmcc/test/except/badinst1.evm deleted file mode 100644 index 69aadac5e..000000000 --- a/evmcc/test/except/badinst1.evm +++ /dev/null @@ -1 +0,0 @@ -4a diff --git a/evmcc/test/ext/calldatacopy1.evm b/evmcc/test/ext/calldatacopy1.evm deleted file mode 100644 index f20019651..000000000 --- a/evmcc/test/ext/calldatacopy1.evm +++ /dev/null @@ -1 +0,0 @@ -60326000600a37600053600a6014f2 diff --git a/evmcc/test/ext/calldatacopy1.lll b/evmcc/test/ext/calldatacopy1.lll deleted file mode 100644 index 3d2ae0a78..000000000 --- a/evmcc/test/ext/calldatacopy1.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -50 ;; byte count -0 ;; source index in calldata array -10 ;; dest index in memory -CALLDATACOPY - -0 -MLOAD ;; to dump memory - -10 -20 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/calldatacopy2.evm b/evmcc/test/ext/calldatacopy2.evm deleted file mode 100644 index e8eea8da7..000000000 --- a/evmcc/test/ext/calldatacopy2.evm +++ /dev/null @@ -1 +0,0 @@ -606464e8d4a510006000376000536000600af2 diff --git a/evmcc/test/ext/calldatacopy2.lll b/evmcc/test/ext/calldatacopy2.lll deleted file mode 100644 index 6bbea48d8..000000000 --- a/evmcc/test/ext/calldatacopy2.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -100 ;; byte count -1000000000000 ;; source index in calldata array -0 ;; dest index in memory -CALLDATACOPY - -0 -MLOAD ;; to dump memory - -0 -10 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy1.evm b/evmcc/test/ext/codecopy1.evm deleted file mode 100644 index d286f9232..000000000 --- a/evmcc/test/ext/codecopy1.evm +++ /dev/null @@ -1 +0,0 @@ -60146000600a39600053600a6014f2 diff --git a/evmcc/test/ext/codecopy1.lll b/evmcc/test/ext/codecopy1.lll deleted file mode 100644 index 85a02b5d7..000000000 --- a/evmcc/test/ext/codecopy1.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -20 ;; byte count -0 ;; source index in code array -10 ;; dest index in memory -CODECOPY - -0 -MLOAD ;; to dump memory - -10 -20 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy2.evm b/evmcc/test/ext/codecopy2.evm deleted file mode 100644 index 71cd92525..000000000 --- a/evmcc/test/ext/codecopy2.evm +++ /dev/null @@ -1 +0,0 @@ -606464e8d4a510006000396000536000600af2 diff --git a/evmcc/test/ext/codecopy2.lll b/evmcc/test/ext/codecopy2.lll deleted file mode 100644 index dcbbcaa46..000000000 --- a/evmcc/test/ext/codecopy2.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -100 ;; byte count -1000000000000 ;; source index in code array -0 ;; dest index in memory -CODECOPY - -0 -MLOAD ;; to dump memory - -0 -10 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy3.evm b/evmcc/test/ext/codecopy3.evm deleted file mode 100644 index e4b6a9253..000000000 --- a/evmcc/test/ext/codecopy3.evm +++ /dev/null @@ -1 +0,0 @@ -3860006000396000536000600af2 diff --git a/evmcc/test/ext/codecopy3.lll b/evmcc/test/ext/codecopy3.lll deleted file mode 100644 index 80d9982c6..000000000 --- a/evmcc/test/ext/codecopy3.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -CODESIZE ;; byte count -0 ;; source index in code array -0 ;; dest index in memory -CODECOPY - -0 -MLOAD ;; to dump memory - -0 -10 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/ext_test.evm b/evmcc/test/ext/ext_test.evm deleted file mode 100644 index 580bd9675..000000000 --- a/evmcc/test/ext/ext_test.evm +++ /dev/null @@ -1 +0,0 @@ -5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f1600053611000545b60200260002030ff60016002f2 diff --git a/evmcc/test/ext/ext_test.lll b/evmcc/test/ext/ext_test.lll deleted file mode 100644 index 3287ae95f..000000000 --- a/evmcc/test/ext/ext_test.lll +++ /dev/null @@ -1,55 +0,0 @@ - -(asm -PC -ADDRESS -BALANCE -CALLER -ORIGIN -CALLVALUE -CALLDATASIZE -GASPRICE -PREVHASH -COINBASE -TIMESTAMP -NUMBER -DIFFICULTY -GASLIMIT -PC -CALLDATASIZE -0 -CALLDATALOAD -38 -CALLDATALOAD -19 -CALLDATALOAD -CODESIZE -0x1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff -0 -MSTORE -32 -0 -0 -CREATE -32 -0 -32 -0 -0 -ADDRESS -3000 -CALL -0 -MLOAD -4096 -MSTORE -MSIZE -32 -MUL -0 -SHA3 -ADDRESS -SUICIDE -1 -2 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/extcodecopy1.evm b/evmcc/test/ext/extcodecopy1.evm deleted file mode 100644 index 6132b52d8..000000000 --- a/evmcc/test/ext/extcodecopy1.evm +++ /dev/null @@ -1 +0,0 @@ -60c86000600a303c60005360006020f2 diff --git a/evmcc/test/ext/extcodecopy1.lll b/evmcc/test/ext/extcodecopy1.lll deleted file mode 100644 index c37054574..000000000 --- a/evmcc/test/ext/extcodecopy1.lll +++ /dev/null @@ -1,11 +0,0 @@ -(asm -200 ;; byte count -0 ;; source index in code array -10 ;; dest index in memory -ADDRESS -EXTCODECOPY - -0 MLOAD ;; to dump memory - -0 32 RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/store_delete.evm b/evmcc/test/ext/store_delete.evm deleted file mode 100644 index d6acae03d..000000000 --- a/evmcc/test/ext/store_delete.evm +++ /dev/null @@ -1 +0,0 @@ -6104d26063576000606357 diff --git a/evmcc/test/ext/store_delete.lll b/evmcc/test/ext/store_delete.lll deleted file mode 100644 index 3d8f0f23a..000000000 --- a/evmcc/test/ext/store_delete.lll +++ /dev/null @@ -1,9 +0,0 @@ - -(asm -1234 -99 -SSTORE -0 -99 -SSTORE -) \ No newline at end of file diff --git a/evmcc/test/ext/store_test.evm b/evmcc/test/ext/store_test.evm deleted file mode 100644 index 54c9419b5..000000000 --- a/evmcc/test/ext/store_test.evm +++ /dev/null @@ -1 +0,0 @@ -607b607c60015760005760015660005603 diff --git a/evmcc/test/ext/store_test.lll b/evmcc/test/ext/store_test.lll deleted file mode 100644 index c40471c40..000000000 --- a/evmcc/test/ext/store_test.lll +++ /dev/null @@ -1,14 +0,0 @@ - -(asm -123 -124 -1 -SSTORE -0 -SSTORE -1 -SLOAD -0 -SLOAD -SUB -) \ No newline at end of file diff --git a/evmcc/test/jump/ackermann.ethel b/evmcc/test/jump/ackermann.ethel deleted file mode 100644 index 971fd2b8d..000000000 --- a/evmcc/test/jump/ackermann.ethel +++ /dev/null @@ -1,7 +0,0 @@ -let A m n = - if m == 0 then n+1 - else if n == 0 then A (m-1) 1 - else A (m-1) (A (m) (n-1)) - -return A 3 8 - diff --git a/evmcc/test/jump/ackermann.evm b/evmcc/test/jump/ackermann.evm deleted file mode 100644 index 964844045..000000000 --- a/evmcc/test/jump/ackermann.evm +++ /dev/null @@ -1 +0,0 @@ -6009600360086012585d60005460206000f26000820e6047596000810e603859603460018303603084600185036012585d6012585d60445860436001830360016012585d604b5860018101905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/badindirect1.evm b/evmcc/test/jump/badindirect1.evm deleted file mode 100644 index b2a8aad67..000000000 --- a/evmcc/test/jump/badindirect1.evm +++ /dev/null @@ -1 +0,0 @@ -601b602502585d diff --git a/evmcc/test/jump/badindirect1.lll b/evmcc/test/jump/badindirect1.lll deleted file mode 100644 index d6291be68..000000000 --- a/evmcc/test/jump/badindirect1.lll +++ /dev/null @@ -1,9 +0,0 @@ -;; Indirect jump out of code - -(asm -27 -37 -MUL -JUMP -JUMPDEST -) \ No newline at end of file diff --git a/evmcc/test/jump/badindirect2.evm b/evmcc/test/jump/badindirect2.evm deleted file mode 100644 index 22217523d..000000000 --- a/evmcc/test/jump/badindirect2.evm +++ /dev/null @@ -1 +0,0 @@ -60016003600302596000600058 diff --git a/evmcc/test/jump/badindirect2.lll b/evmcc/test/jump/badindirect2.lll deleted file mode 100644 index 53a6294f7..000000000 --- a/evmcc/test/jump/badindirect2.lll +++ /dev/null @@ -1,12 +0,0 @@ -;; Indirect jump into data - -(asm -1 ;; 0 -3 -3 -MUL ;; 6 -JUMPI ;; 7 -0 ;; 8 -0 -JUMP -) \ No newline at end of file diff --git a/evmcc/test/jump/badjump1.evm b/evmcc/test/jump/badjump1.evm deleted file mode 100644 index 5c11a8661..000000000 --- a/evmcc/test/jump/badjump1.evm +++ /dev/null @@ -1 +0,0 @@ -6103e758 diff --git a/evmcc/test/jump/badjump1.lll b/evmcc/test/jump/badjump1.lll deleted file mode 100644 index 1834a62ef..000000000 --- a/evmcc/test/jump/badjump1.lll +++ /dev/null @@ -1,6 +0,0 @@ -;; Direct jump out of code. - -(asm -999 -JUMP -) \ No newline at end of file diff --git a/evmcc/test/jump/badjump2.evm b/evmcc/test/jump/badjump2.evm deleted file mode 100644 index 900a1c15a..000000000 --- a/evmcc/test/jump/badjump2.evm +++ /dev/null @@ -1 +0,0 @@ -6004586000600058 diff --git a/evmcc/test/jump/badjump2.lll b/evmcc/test/jump/badjump2.lll deleted file mode 100644 index ce61276d7..000000000 --- a/evmcc/test/jump/badjump2.lll +++ /dev/null @@ -1,9 +0,0 @@ -;; Direct jump into data - -(asm -4 ;; 0 0-3 -JUMP ;; 2 -0 ;; 3 3-4 -0 ;; 5 4-7 -JUMP ;; 6 -) \ No newline at end of file diff --git a/evmcc/test/jump/call1.ethel b/evmcc/test/jump/call1.ethel deleted file mode 100644 index 414ad0124..000000000 --- a/evmcc/test/jump/call1.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let f n = n + 1 - -return f 2 - - diff --git a/evmcc/test/jump/call1.evm b/evmcc/test/jump/call1.evm deleted file mode 100644 index 252aaf778..000000000 --- a/evmcc/test/jump/call1.evm +++ /dev/null @@ -1 +0,0 @@ -600760026010585d60005460206000f28060010190509058 \ No newline at end of file diff --git a/evmcc/test/jump/call2.ethel b/evmcc/test/jump/call2.ethel deleted file mode 100644 index bdeb9b734..000000000 --- a/evmcc/test/jump/call2.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let f a b = a + b - -return f 2 3 - - diff --git a/evmcc/test/jump/call2.evm b/evmcc/test/jump/call2.evm deleted file mode 100644 index 6832e044d..000000000 --- a/evmcc/test/jump/call2.evm +++ /dev/null @@ -1 +0,0 @@ -6009600260036012585d60005460206000f2818101905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/fac.ethel b/evmcc/test/jump/fac.ethel deleted file mode 100644 index 8bfe94dd6..000000000 --- a/evmcc/test/jump/fac.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let fac n = - if n == 0 then 1 - else n * fac (n-1) - -return fac 60 \ No newline at end of file diff --git a/evmcc/test/jump/fac.evm b/evmcc/test/jump/fac.evm deleted file mode 100644 index 04cd3e4f4..000000000 --- a/evmcc/test/jump/fac.evm +++ /dev/null @@ -1 +0,0 @@ -6007603c6010585d60005460206000f26000810e6026596020600182036010585d8102602858600190509058 \ No newline at end of file diff --git a/evmcc/test/jump/fac_tail.ethel b/evmcc/test/jump/fac_tail.ethel deleted file mode 100644 index 9ce5ecac7..000000000 --- a/evmcc/test/jump/fac_tail.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let fac a n = - if n == 0 then a - else fac (a*n) (n-1) - -return fac 1 60 \ No newline at end of file diff --git a/evmcc/test/jump/fac_tail.evm b/evmcc/test/jump/fac_tail.evm deleted file mode 100644 index 8384d94e4..000000000 --- a/evmcc/test/jump/fac_tail.evm +++ /dev/null @@ -1 +0,0 @@ -60096001603c6012585d60005460206000f26000810e6029596025818302600183036012585d602a5881905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/fib1.ethel b/evmcc/test/jump/fib1.ethel deleted file mode 100644 index 81b869f41..000000000 --- a/evmcc/test/jump/fib1.ethel +++ /dev/null @@ -1,6 +0,0 @@ -let fib n = - if n < 3 then 1 - else fib (n-1) + fib (n-2) - -return fib 10 - diff --git a/evmcc/test/jump/fib1.evm b/evmcc/test/jump/fib1.evm deleted file mode 100644 index 5042a192f..000000000 --- a/evmcc/test/jump/fib1.evm +++ /dev/null @@ -1 +0,0 @@ -6007600a6010585d60005460206000f26003810a602f596020600282036010585d602a600183036010585d01603158600190509058 \ No newline at end of file diff --git a/evmcc/test/jump/for1.evm b/evmcc/test/jump/for1.evm deleted file mode 100644 index f8e65cbf2..000000000 --- a/evmcc/test/jump/for1.evm +++ /dev/null @@ -1 +0,0 @@ -600a60805460006080530b0f60255960a0536080530160a054600160805303608054600558 diff --git a/evmcc/test/jump/for1.lll b/evmcc/test/jump/for1.lll deleted file mode 100644 index 419fc9b54..000000000 --- a/evmcc/test/jump/for1.lll +++ /dev/null @@ -1,3 +0,0 @@ -(for [i]:10 (> @i 0) [i](- @i 1) - [j](+ @i @j) -) diff --git a/evmcc/test/jump/for2.evm b/evmcc/test/jump/for2.evm deleted file mode 100644 index 628297778..000000000 --- a/evmcc/test/jump/for2.evm +++ /dev/null @@ -1 +0,0 @@ -6000608054600a6080530a0f60255960a0536080530160a054600160805301608054600558 diff --git a/evmcc/test/jump/for2.lll b/evmcc/test/jump/for2.lll deleted file mode 100644 index de17d65ac..000000000 --- a/evmcc/test/jump/for2.lll +++ /dev/null @@ -1,3 +0,0 @@ -(for [i]:0 (< @i 10) [i](+ @i 1) - [j](+ @i @j) -) diff --git a/evmcc/test/jump/if1.ethel b/evmcc/test/jump/if1.ethel deleted file mode 100644 index 85c3e126b..000000000 --- a/evmcc/test/jump/if1.ethel +++ /dev/null @@ -1 +0,0 @@ -return if 0 then 1 else 2 \ No newline at end of file diff --git a/evmcc/test/jump/if1.evm b/evmcc/test/jump/if1.evm deleted file mode 100644 index 51fbe04bd..000000000 --- a/evmcc/test/jump/if1.evm +++ /dev/null @@ -1 +0,0 @@ -60006300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmcc/test/jump/if2.ethel b/evmcc/test/jump/if2.ethel deleted file mode 100644 index 2a58d6365..000000000 --- a/evmcc/test/jump/if2.ethel +++ /dev/null @@ -1 +0,0 @@ -return if 1 then 1 else 2 \ No newline at end of file diff --git a/evmcc/test/jump/if2.evm b/evmcc/test/jump/if2.evm deleted file mode 100644 index 6d823b374..000000000 --- a/evmcc/test/jump/if2.evm +++ /dev/null @@ -1 +0,0 @@ -60016300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmcc/test/jump/indirect1.evm b/evmcc/test/jump/indirect1.evm deleted file mode 100644 index ab6928304..000000000 --- a/evmcc/test/jump/indirect1.evm +++ /dev/null @@ -1 +0,0 @@ -600460030158005d6001600054 diff --git a/evmcc/test/jump/indirect1.lll b/evmcc/test/jump/indirect1.lll deleted file mode 100644 index 1ee7dc347..000000000 --- a/evmcc/test/jump/indirect1.lll +++ /dev/null @@ -1,13 +0,0 @@ -;; Indirect JUMP - -(asm -4 ;; 0 -3 ;; 2 -ADD ;; 4 -JUMP ;; 5 -STOP ;; 6 -JUMPDEST ;; 7 -1 -0 -MSTORE -) \ No newline at end of file diff --git a/evmcc/test/jump/indirect2.evm b/evmcc/test/jump/indirect2.evm deleted file mode 100644 index e9697eaa1..000000000 --- a/evmcc/test/jump/indirect2.evm +++ /dev/null @@ -1 +0,0 @@ -600860060158005d6001600054005d600260005400 diff --git a/evmcc/test/jump/indirect2.lll b/evmcc/test/jump/indirect2.lll deleted file mode 100644 index f2f068630..000000000 --- a/evmcc/test/jump/indirect2.lll +++ /dev/null @@ -1,19 +0,0 @@ -;; Indirect JUMP - -(asm -8 ;; 0 -6 ;; 2 -ADD ;; 4 -JUMP ;; 5 --> 14 -STOP ;; 6 -JUMPDEST ;; 7 -1 ;; 8 -0 ;; 10 -MSTORE ;; 12 -STOP ;; 13 -JUMPDEST ;; 14 -2 -0 -MSTORE -STOP -) \ No newline at end of file diff --git a/evmcc/test/jump/indirect3.evm b/evmcc/test/jump/indirect3.evm deleted file mode 100644 index 1fb0a356c..000000000 --- a/evmcc/test/jump/indirect3.evm +++ /dev/null @@ -1 +0,0 @@ -6001600460050159005d6001600054 diff --git a/evmcc/test/jump/indirect3.lll b/evmcc/test/jump/indirect3.lll deleted file mode 100644 index d6a679f9a..000000000 --- a/evmcc/test/jump/indirect3.lll +++ /dev/null @@ -1,14 +0,0 @@ -;; Indirect JUMP - -(asm -1 ;; 0 -4 ;; 2 -5 ;; 4 -ADD ;; 6 -JUMPI ;; 7 -STOP ;; 8 -JUMPDEST ;; 9 -1 -0 -MSTORE -) \ No newline at end of file diff --git a/evmcc/test/jump/indirect4.evm b/evmcc/test/jump/indirect4.evm deleted file mode 100644 index f0e31a8f4..000000000 --- a/evmcc/test/jump/indirect4.evm +++ /dev/null @@ -1 +0,0 @@ -60006007600501596001600054005d00 diff --git a/evmcc/test/jump/indirect4.lll b/evmcc/test/jump/indirect4.lll deleted file mode 100644 index 7fbe0b833..000000000 --- a/evmcc/test/jump/indirect4.lll +++ /dev/null @@ -1,15 +0,0 @@ -;; Indirect JUMP - -(asm -0 ;; 0 -7 ;; 2 -5 ;; 4 -ADD ;; 6 -JUMPI ;; 7 -1 ;; 8 -0 ;; 9 -MSTORE ;; 10 -STOP ;; 11 -JUMPDEST ;; 12 -STOP -) \ No newline at end of file diff --git a/evmcc/test/jump/jump1.evm b/evmcc/test/jump/jump1.evm deleted file mode 100644 index 0df9b4036..000000000 --- a/evmcc/test/jump/jump1.evm +++ /dev/null @@ -1 +0,0 @@ -600458006001600154 diff --git a/evmcc/test/jump/jump1.lll b/evmcc/test/jump/jump1.lll deleted file mode 100644 index 33119edb3..000000000 --- a/evmcc/test/jump/jump1.lll +++ /dev/null @@ -1,11 +0,0 @@ -;; Direct JUMP. -;; output: memory[1] == 1 - -(asm -4 ;; 0 -JUMP ;; 2 -STOP ;; 3 -1 ;; 4 -1 ;; 6 -MSTORE ;; 8 -) \ No newline at end of file diff --git a/evmcc/test/jump/jump2.evm b/evmcc/test/jump/jump2.evm deleted file mode 100644 index 35d75941d..000000000 --- a/evmcc/test/jump/jump2.evm +++ /dev/null @@ -1 +0,0 @@ -6008586001600154 diff --git a/evmcc/test/jump/jump2.lll b/evmcc/test/jump/jump2.lll deleted file mode 100644 index a70d50ecb..000000000 --- a/evmcc/test/jump/jump2.lll +++ /dev/null @@ -1,10 +0,0 @@ -;; Direct JUMP to the end of code. -;; output: memory should have size 0. - -(asm -8 ;; 0 -JUMP ;; 2 -1 ;; 3 -1 ;; 5 -MSTORE ;; 7 -) \ No newline at end of file diff --git a/evmcc/test/jump/jump3.evm b/evmcc/test/jump/jump3.evm deleted file mode 100644 index 599d4a764..000000000 --- a/evmcc/test/jump/jump3.evm +++ /dev/null @@ -1 +0,0 @@ -602a586001600154 diff --git a/evmcc/test/jump/jump3.lll b/evmcc/test/jump/jump3.lll deleted file mode 100644 index bc897e30c..000000000 --- a/evmcc/test/jump/jump3.lll +++ /dev/null @@ -1,10 +0,0 @@ -;; Direct JUMP past the end of code. -;; output: memory should have size 0. - -(asm -42 -JUMP -1 -1 -MSTORE -) \ No newline at end of file diff --git a/evmcc/test/jump/jump4.evm b/evmcc/test/jump/jump4.evm deleted file mode 100644 index 41713f43e..000000000 --- a/evmcc/test/jump/jump4.evm +++ /dev/null @@ -1 +0,0 @@ -600b6009580000600558005d6001600154 diff --git a/evmcc/test/jump/jump4.lll b/evmcc/test/jump/jump4.lll deleted file mode 100644 index 131baee2d..000000000 --- a/evmcc/test/jump/jump4.lll +++ /dev/null @@ -1,17 +0,0 @@ -;; Direct JUMP. -;; output: memory[1] = 1 - -(asm -11 ;; 0 -9 ;; 2 -JUMP ;; 4 --> 9 -STOP ;; 5 -STOP ;; 6 -5 ;; 7 -JUMP ;; 9 --> 11 -STOP ;; 10 -JUMPDEST -1 ;; 11 -1 -MSTORE -) \ No newline at end of file diff --git a/evmcc/test/jump/jump5.evm b/evmcc/test/jump/jump5.evm deleted file mode 100644 index c36d9615b..000000000 --- a/evmcc/test/jump/jump5.evm +++ /dev/null @@ -1 +0,0 @@ -6005600e585d600160015400600f5800 diff --git a/evmcc/test/jump/jump5.lll b/evmcc/test/jump/jump5.lll deleted file mode 100644 index d28b7d4ac..000000000 --- a/evmcc/test/jump/jump5.lll +++ /dev/null @@ -1,16 +0,0 @@ -;; Direct JUMP. -;; output: memory[1] = 1 - -(asm -5 ;; 0 -14 ;; 2 -JUMP ;; 4 --> 14 -JUMPDEST ;; 5 -1 ;; 6 -1 ;; 8 -MSTORE ;; 10 -STOP ;; 11 -15 ;; 12 -JUMP ;; 14 --> 5 -STOP ;; 15 -) \ No newline at end of file diff --git a/evmcc/test/jump/jump6.evm b/evmcc/test/jump/jump6.evm deleted file mode 100644 index 029db7191..000000000 --- a/evmcc/test/jump/jump6.evm +++ /dev/null @@ -1 +0,0 @@ -600358600f600d58006014600758005d6001600154005d600260025400 diff --git a/evmcc/test/jump/jump6.lll b/evmcc/test/jump/jump6.lll deleted file mode 100644 index 1116aa663..000000000 --- a/evmcc/test/jump/jump6.lll +++ /dev/null @@ -1,32 +0,0 @@ -;; Direct JUMP. -;; output: memory[1] = 1 - -;; 0, 2 --> 3 .. 7 --> 13 -*-> 15 .. 19 - -(asm -3 ;; 0 -JUMP ;; 2 - -15 ;; 3 <- start -13 ;; 5 -JUMP ;; 7 <- b -STOP ;; 8 - -20 ;; 9 -7 ;; 11 - -JUMP ;; 13 <- a -STOP ;; 14 - -JUMPDEST ;; 15 <- c -1 ;; 16 -1 ;; 18 -MSTORE ;; 19 -STOP ;; 20 - -JUMPDEST ;; 21 <- d -2 ;; 22 -2 ;; 24 -MSTORE ;; 26 -STOP ;; 27 -) \ No newline at end of file diff --git a/evmcc/test/jump/jumpi_at_the_end.evm b/evmcc/test/jump/jumpi_at_the_end.evm deleted file mode 100644 index 2d7411761..000000000 --- a/evmcc/test/jump/jumpi_at_the_end.evm +++ /dev/null @@ -1 +0,0 @@ -600a6000545d6000536001900380600054600659 diff --git a/evmcc/test/jump/jumpi_at_the_end.lll b/evmcc/test/jump/jumpi_at_the_end.lll deleted file mode 100644 index 263ada6a7..000000000 --- a/evmcc/test/jump/jumpi_at_the_end.lll +++ /dev/null @@ -1 +0,0 @@ -(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI) \ No newline at end of file diff --git a/evmcc/test/jump/loop1.evm b/evmcc/test/jump/loop1.evm deleted file mode 100644 index 7724d6308..000000000 --- a/evmcc/test/jump/loop1.evm +++ /dev/null @@ -1 +0,0 @@ -600a600181038060025960005460015460025400 diff --git a/evmcc/test/jump/loop1.lll b/evmcc/test/jump/loop1.lll deleted file mode 100644 index 0044ec1fb..000000000 --- a/evmcc/test/jump/loop1.lll +++ /dev/null @@ -1,27 +0,0 @@ -;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits - -(asm -10 - -;; 2 -1 -DUP2 -SUB -DUP1 -2 -JUMPI - -;; stack = 1 2 3 4 5 6 7 8 9 10 -0 -MSTORE -1 -MSTORE -2 -MSTORE -;;3 -;;MSTORE - -STOP -) - - diff --git a/evmcc/test/jump/loop2.evm b/evmcc/test/jump/loop2.evm deleted file mode 100644 index faffa4e5b..000000000 --- a/evmcc/test/jump/loop2.evm +++ /dev/null @@ -1 +0,0 @@ -600a80600190038060025960005460015460025400 diff --git a/evmcc/test/jump/loop2.lll b/evmcc/test/jump/loop2.lll deleted file mode 100644 index 9996c52ba..000000000 --- a/evmcc/test/jump/loop2.lll +++ /dev/null @@ -1,28 +0,0 @@ -;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits - -(asm -10 - -;; 2 -DUP1 -1 -SWAP1 -SUB -DUP1 -2 -JUMPI - -;; stack = 1 2 3 4 5 6 7 8 9 10 -0 -MSTORE -1 -MSTORE -2 -MSTORE -;;3 -;;MSTORE - -STOP -) - - diff --git a/evmcc/test/jump/rec1.ethel b/evmcc/test/jump/rec1.ethel deleted file mode 100644 index f83c8e81e..000000000 --- a/evmcc/test/jump/rec1.ethel +++ /dev/null @@ -1,4 +0,0 @@ -let f n = - if n == 0 then 2 else f (n-1) - -return f 10 diff --git a/evmcc/test/jump/rec1.evm b/evmcc/test/jump/rec1.evm deleted file mode 100644 index 2ae62aff6..000000000 --- a/evmcc/test/jump/rec1.evm +++ /dev/null @@ -1 +0,0 @@ -6007600a6010585d60005460206000f26000810e6024596020600182036010585d602658600290509058 \ No newline at end of file diff --git a/evmcc/test/jump/when1.asm b/evmcc/test/jump/when1.asm deleted file mode 100644 index 01d41c266..000000000 --- a/evmcc/test/jump/when1.asm +++ /dev/null @@ -1,10 +0,0 @@ -.code: - PUSH 1 - NOT - PUSH [tag0] - JUMPI - PUSH 13 - PUSH 128 - MSTORE -tag0: - diff --git a/evmcc/test/jump/when1.evm b/evmcc/test/jump/when1.evm deleted file mode 100644 index 303b02623..000000000 --- a/evmcc/test/jump/when1.evm +++ /dev/null @@ -1 +0,0 @@ -60010f600b59600d608054 diff --git a/evmcc/test/jump/when1.lll b/evmcc/test/jump/when1.lll deleted file mode 100644 index 990a6e64a..000000000 --- a/evmcc/test/jump/when1.lll +++ /dev/null @@ -1,2 +0,0 @@ -(when (> 1 0) [i] 13) - \ No newline at end of file diff --git a/evmcc/test/kv.evm b/evmcc/test/kv.evm deleted file mode 100644 index 55141ea59..000000000 --- a/evmcc/test/kv.evm +++ /dev/null @@ -1 +0,0 @@ -33604557602a8060106000396000f200604556330e0f602a59366080530a0f602a59602060805301356080533557604060805301608054600958 diff --git a/evmcc/test/kv.lll b/evmcc/test/kv.lll deleted file mode 100644 index c62d9fa70..000000000 --- a/evmcc/test/kv.lll +++ /dev/null @@ -1,10 +0,0 @@ -{ - [[69]] (caller) - (return 0 (lll - (when (= (caller) @@69) - (for {} (< @i (calldatasize)) [i](+ @i 64) - [[ (calldataload @i) ]] (calldataload (+ @i 32)) - ) - ) - 0)) -} diff --git a/evmcc/test/mem/byte.evm b/evmcc/test/mem/byte.evm deleted file mode 100644 index ab63431ee..000000000 --- a/evmcc/test/mem/byte.evm +++ /dev/null @@ -1 +0,0 @@ -7f112233445566778899001122334455667788990011223344556677889900aabb6000137f112233445566778899001122334455667788990011223344556677889900aabb6001137f112233445566778899001122334455667788990011223344556677889900aabb6002137f112233445566778899001122334455667788990011223344556677889900aabb6003137f112233445566778899001122334455667788990011223344556677889900aabb6004137f112233445566778899001122334455667788990011223344556677889900aabb6005137f112233445566778899001122334455667788990011223344556677889900aabb6006137f112233445566778899001122334455667788990011223344556677889900aabb6007137f112233445566778899001122334455667788990011223344556677889900aabb6008137f112233445566778899001122334455667788990011223344556677889900aabb6009137f112233445566778899001122334455667788990011223344556677889900aabb600a137f112233445566778899001122334455667788990011223344556677889900aabb600b137f112233445566778899001122334455667788990011223344556677889900aabb600c137f112233445566778899001122334455667788990011223344556677889900aabb600d137f112233445566778899001122334455667788990011223344556677889900aabb600e137f112233445566778899001122334455667788990011223344556677889900aabb600f137f112233445566778899001122334455667788990011223344556677889900aabb6010137f112233445566778899001122334455667788990011223344556677889900aabb6011137f112233445566778899001122334455667788990011223344556677889900aabb6012137f112233445566778899001122334455667788990011223344556677889900aabb6013137f112233445566778899001122334455667788990011223344556677889900aabb6014137f112233445566778899001122334455667788990011223344556677889900aabb6015137f112233445566778899001122334455667788990011223344556677889900aabb6016137f112233445566778899001122334455667788990011223344556677889900aabb6017137f112233445566778899001122334455667788990011223344556677889900aabb6018137f112233445566778899001122334455667788990011223344556677889900aabb6019137f112233445566778899001122334455667788990011223344556677889900aabb601a137f112233445566778899001122334455667788990011223344556677889900aabb601b137f112233445566778899001122334455667788990011223344556677889900aabb601c137f112233445566778899001122334455667788990011223344556677889900aabb601d137f112233445566778899001122334455667788990011223344556677889900aabb601e137f112233445566778899001122334455667788990011223344556677889900aabb601f137f112233445566778899001122334455667788990011223344556677889900aabb6020137f112233445566778899001122334455667788990011223344556677889900aabb6107de13 diff --git a/evmcc/test/mem/byte.lll b/evmcc/test/mem/byte.lll deleted file mode 100644 index 95b0f99dc..000000000 --- a/evmcc/test/mem/byte.lll +++ /dev/null @@ -1,105 +0,0 @@ - -(asm -0x112233445566778899001122334455667788990011223344556677889900aabb -0 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -1 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -2 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -3 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -4 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -5 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -6 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -7 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -8 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -9 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -10 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -11 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -12 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -13 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -14 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -15 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -16 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -17 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -18 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -19 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -20 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -21 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -22 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -23 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -24 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -25 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -26 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -27 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -28 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -29 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -30 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -31 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -32 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -2014 -BYTE -) \ No newline at end of file diff --git a/evmcc/test/mem/mem2.evm b/evmcc/test/mem/mem2.evm deleted file mode 100644 index 49cc6e8b1..000000000 --- a/evmcc/test/mem/mem2.evm +++ /dev/null @@ -1 +0,0 @@ -6001610d805b01556504409585d6df620493e05462061a80535b01 diff --git a/evmcc/test/mem/mem2.lll b/evmcc/test/mem/mem2.lll deleted file mode 100644 index 5345ee47c..000000000 --- a/evmcc/test/mem/mem2.lll +++ /dev/null @@ -1,15 +0,0 @@ - -(asm ;; [] -1 -3456 -MSIZE -ADD -MSTORE8 ;; [02] -4675432994527 -300000 -MSTORE -400000 -MLOAD -MSIZE -ADD -) \ No newline at end of file diff --git a/evmcc/test/mem/memtest1.evm b/evmcc/test/mem/memtest1.evm deleted file mode 100644 index 0506bf928..000000000 --- a/evmcc/test/mem/memtest1.evm +++ /dev/null @@ -1 +0,0 @@ -6002600055600360015560005360015301600254 diff --git a/evmcc/test/mem/memtest1.lll b/evmcc/test/mem/memtest1.lll deleted file mode 100644 index 4b4389ad8..000000000 --- a/evmcc/test/mem/memtest1.lll +++ /dev/null @@ -1,18 +0,0 @@ - -(asm ;; [] -2 -0 -MSTORE8 ;; [02] -3 -1 -MSTORE8 ;; [02 03] -0 -MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] -1 -MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] -ADD -2 -MSTORE ;; [2 3 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] -) \ No newline at end of file diff --git a/evmcc/test/mem/mstore1.evm b/evmcc/test/mem/mstore1.evm deleted file mode 100644 index ba6141ab1..000000000 --- a/evmcc/test/mem/mstore1.evm +++ /dev/null @@ -1 +0,0 @@ -6001600054 diff --git a/evmcc/test/mem/mstore1.lll b/evmcc/test/mem/mstore1.lll deleted file mode 100644 index 2d2ca32b5..000000000 --- a/evmcc/test/mem/mstore1.lll +++ /dev/null @@ -1,6 +0,0 @@ - -(asm ;; [] -1 -0 -MSTORE ;; [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] -) \ No newline at end of file diff --git a/evmcc/test/ret/return1.evm b/evmcc/test/ret/return1.evm deleted file mode 100644 index 8092cb007..000000000 --- a/evmcc/test/ret/return1.evm +++ /dev/null @@ -1 +0,0 @@ -600160805460006080530b601b59600160005460206000f2602a58602760005460206000f26002608054 diff --git a/evmcc/test/ret/return1.lll b/evmcc/test/ret/return1.lll deleted file mode 100644 index 159d15ca3..000000000 --- a/evmcc/test/ret/return1.lll +++ /dev/null @@ -1,6 +0,0 @@ -;; code should return 39 -;; i should remain 1 -{ - [i] 1 - ( if (> @i 0) { (return 39) [i] 2 } (return 1) ) -} \ No newline at end of file diff --git a/evmcc/test/ret/return2.evm b/evmcc/test/ret/return2.evm deleted file mode 100644 index e29da7664..000000000 --- a/evmcc/test/ret/return2.evm +++ /dev/null @@ -1 +0,0 @@ -6001620f4240f2 diff --git a/evmcc/test/ret/return2.lll b/evmcc/test/ret/return2.lll deleted file mode 100644 index f5ee68f6e..000000000 --- a/evmcc/test/ret/return2.lll +++ /dev/null @@ -1,6 +0,0 @@ - -(asm -1 -1000000 -RETURN ;; return 1 byte from index 1M -) \ No newline at end of file diff --git a/evmcc/test/ret/return_test.evm b/evmcc/test/ret/return_test.evm deleted file mode 100644 index 977cf7c19..000000000 --- a/evmcc/test/ret/return_test.evm +++ /dev/null @@ -1 +0,0 @@ -60016064546002608454600360a45460606064f2 diff --git a/evmcc/test/ret/return_test.lll b/evmcc/test/ret/return_test.lll deleted file mode 100644 index c87a2d812..000000000 --- a/evmcc/test/ret/return_test.lll +++ /dev/null @@ -1,15 +0,0 @@ - -(asm -1 -100 -MSTORE -2 -132 -MSTORE -3 -164 -MSTORE -96 -100 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/stack/oos.evm b/evmcc/test/stack/oos.evm deleted file mode 100644 index ea2f1c890..000000000 --- a/evmcc/test/stack/oos.evm +++ /dev/null @@ -1 +0,0 @@ -60018194505050509150 diff --git a/evmcc/test/stack/oos.lll b/evmcc/test/stack/oos.lll deleted file mode 100644 index 5394b06ba..000000000 --- a/evmcc/test/stack/oos.lll +++ /dev/null @@ -1,11 +0,0 @@ -(asm ;; x . v y z -1 ;; 1 x . v y z -DUP2 ;; x 1 x . v y z -SWAP5 ;; y 1 x . v x z -POP ;; 1 x . v x z -POP ;; x . v x z -POP ;; . v x z -POP ;; v x z -SWAP2 ;; z x v -POP ;; x v -) diff --git a/evmcc/test/stack/push_test.evm b/evmcc/test/stack/push_test.evm deleted file mode 100644 index d624cee1d..000000000 --- a/evmcc/test/stack/push_test.evm +++ /dev/null @@ -1 +0,0 @@ -60656107d26204a0c763026921f4640bc5588eb165372d0f1dca6e661ba1d901961c71670c55f7bc23038e3868056bc75e2d630fffff69021e19e0c9bab24000016a085d1c6e8050f0ea1c71bd6b0688be36543f3c36e638e37a6c03d41f73d55d0d482ae55555376dc76810d0fe03c91964d31c71c6f46e615dd0360c07d931663b14e38e38b16f2da3f99955a3adcf27ebb1caaaaaaa6e7014ccba6a8bb1ed35bd86bf065c71c71c2b7109491c5d4781b79c9009de6bfb8e38e38de8720414a0f6fdec81304d4c563e740bffffffffa573118427b3b4a05bc8a8a4de8459868000000000017406eb15e7331e727940d4ac54b7cdca1c71c71c71bd750567a91c9fefc96ebaa626a22f98c5e638e38e38e37a76032abd16c5b68006e15d5aa307e383f4e55555555555377701a6427bdc4f0d58eab5f48a3ec67f64e21c71c71c71c6f478080dd0a0c9b9ff2c2a0c740b06853a0a980ee38e38e38e38b17903c679cb5e8f2f9cb3b5d6652b0e7334f746faaaaaaaaaaaaa6e7a01b873815917ebb2bf3b890a1af495d6235bae3c71c71c71c71c2b7b07ae4cca96e1a55dfa49c85ad3c3e60e426b92fb8e38e38e38e38de87c036018bf074e292bcc7d6c8bea0f9699443046178bffffffffffffffa57d0e7d34c64a9c85d4460dbbca87196b61618a4bd2168000000000000000017e05b901f48a5b994d6572502bc4ea43140486666416aa1c71c71c71c71c71bd7f047889870c178fc477414ea231d70467a388fffe31b4e638e38e38e38e38e37a diff --git a/evmcc/test/stack/push_test.lll b/evmcc/test/stack/push_test.lll deleted file mode 100644 index 832daaec1..000000000 --- a/evmcc/test/stack/push_test.lll +++ /dev/null @@ -1,35 +0,0 @@ - -(asm -101 ;; PUSH1 -2002 ;; PUSH2 -303303 ;; PUSH3 -40444404 ;; PUSH4 -50555555505 ;; PUSH5 -60666666666606 -7777777777777777 -888888888888888888 -99999999999999999999 -10000000000000000000001 -10111111111111111111111101 -2022222222222222222222222202 -303333333333333333333333333303 -4044444444444444444444444444444404 -505555555555555555555555555555555505 -60666666666666666666666666666666666606 -7077777777777777777777777777777777777707 -808888888888888888888888888888888888888808 -90999999999999999999999999999999999999999909 -100000000000000000000000000000000000000000000001 -10111111111111111111111111111111111111111111111101 -2022222222222222222222222222222222222222222222222202 -303333333333333333333333333333333333333333333333333303 -40444444444444444444444444444444444444444444444444444404 -50555555555555555555555555555555555555555555555555555555505 -6066666666666666666666666666666666666666666666666666666666606 -707777777777777777777777777777777777777777777777777777777777707 -808888888888888888888888888888888888888888888888888888888888888808 -90999999999999999999999999999999999999999999999999999999999999999909 -100000000000000000000000000000000000000000000000000000000000000000000001 -10111111111111111111111111111111111111111111111111111111111111111111111101 -2022222222222222222222222222222222222222222222222222222222222222222222222202 ;; PUSH32 -) \ No newline at end of file diff --git a/evmcc/test/stack/stack_test.evm b/evmcc/test/stack/stack_test.evm deleted file mode 100644 index 02417c967..000000000 --- a/evmcc/test/stack/stack_test.evm +++ /dev/null @@ -1 +0,0 @@ -65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae81819290 diff --git a/evmcc/test/stack/stack_test.lll b/evmcc/test/stack/stack_test.lll deleted file mode 100644 index fdf83594c..000000000 --- a/evmcc/test/stack/stack_test.lll +++ /dev/null @@ -1,8 +0,0 @@ - -(asm -123 -SSTORE -SLOAD -123 -SUB -) \ No newline at end of file diff --git a/evmcc/test/stack/stackjump.evm b/evmcc/test/stack/stackjump.evm deleted file mode 100644 index baddec42e..000000000 --- a/evmcc/test/stack/stackjump.evm +++ /dev/null @@ -1 +0,0 @@ -600460066009601358600a036000545b6000f260005401600958 \ No newline at end of file diff --git a/evmcc/test/stack/stackjump.lll b/evmcc/test/stack/stackjump.lll deleted file mode 100644 index f5da5e733..000000000 --- a/evmcc/test/stack/stackjump.lll +++ /dev/null @@ -1,3 +0,0 @@ -(asm -0x4 0x6 0x9 0x13 JUMP 0xa SUB 0x0 MSTORE MSIZE 0x0 RETURN 0x0 MSTORE ADD 0x9 JUMP -) diff --git a/evmcc/test/stack/swap.evm b/evmcc/test/stack/swap.evm deleted file mode 100644 index d17f0ee09..000000000 --- a/evmcc/test/stack/swap.evm +++ /dev/null @@ -1 +0,0 @@ -600560026001600c59505000906001601559505000036000546001601ff2 diff --git a/evmcc/test/stack/swap.lll b/evmcc/test/stack/swap.lll deleted file mode 100644 index 90dee585d..000000000 --- a/evmcc/test/stack/swap.lll +++ /dev/null @@ -1,31 +0,0 @@ -(asm -5 ;; 0 -2 ;; 2 -1 ;; 4 -12 ;; 6 -JUMPI ;; 8 - -POP ;; 9 -POP ;; 10 -STOP ;; 11 - -;; stack = 2,1 -SWAP1 ;; 12 -1 ;; 13 -21 ;; 15 -JUMPI ;; 17 - -POP ;; 18 -POP ;; 19 -STOP ;; 20 - -;; stack = 1,2 -SUB ;; 21 -0 -MSTORE -1 -31 -RETURN ;; returns 03 -) - - diff --git a/evmcc/test/stack/swapswap.evm b/evmcc/test/stack/swapswap.evm deleted file mode 100644 index fb4f1bf75..000000000 --- a/evmcc/test/stack/swapswap.evm +++ /dev/null @@ -1 +0,0 @@ -600260056001600c5950500090906001601659505000036000546001601ff2 diff --git a/evmcc/test/stack/swapswap.lll b/evmcc/test/stack/swapswap.lll deleted file mode 100644 index 1fedf726e..000000000 --- a/evmcc/test/stack/swapswap.lll +++ /dev/null @@ -1,32 +0,0 @@ -(asm -2 ;; 0 -5 ;; 2 -1 ;; 4 -12 ;; 6 -JUMPI ;; 8 - -POP ;; 9 -POP ;; 10 -STOP ;; 11 - -;; stack = 2,1 -SWAP1 ;; 12 -SWAP1 ;; 13 -1 ;; 14 -22 ;; 16 -JUMPI ;; 18 - -POP ;; 19 -POP ;; 20 -STOP ;; 21 - -;; stack = 2,1 -SUB ;; 22 -0 -MSTORE -1 -31 -RETURN ;; returns 03 -) - - diff --git a/evmcc/test/stack/test.evm b/evmcc/test/stack/test.evm deleted file mode 100644 index ea2f1c890..000000000 --- a/evmcc/test/stack/test.evm +++ /dev/null @@ -1 +0,0 @@ -60018194505050509150 diff --git a/evmcc/test/vmtests/vmArithPerformanceTest.json b/evmcc/test/vmtests/vmArithPerformanceTest.json deleted file mode 100644 index d9017517f..000000000 --- a/evmcc/test/vmtests/vmArithPerformanceTest.json +++ /dev/null @@ -1,260 +0,0 @@ -{ - "arith-1" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "999538", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "nonce" : "0", - "storage" : { } - } - } - } - - , - - "arith-2" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "995488", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "nonce" : "0", - "storage" : { } - } - } - } - - , - - "arith-3" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "954988", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "nonce" : "0", - "storage" : { } - } - } - } - - , - - "arith-4" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "549988", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "nonce" : "0", - "storage" : { } - } - } - } - - - , - - - "arith-5" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "data" : "0x", - "gas" : "10000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "5499988", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "nonce" : "0", - "storage" : { } - } - } - } - -, - - "arith-6" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "100000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "data" : "0x", - "gas" : "100000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "54999988", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "nonce" : "0", - "storage" : { } - } - } - } - -} diff --git a/evmcc/test/vmtests/vmPerformanceTest.json b/evmcc/test/vmtests/vmPerformanceTest.json deleted file mode 100644 index 604e45993..000000000 --- a/evmcc/test/vmtests/vmPerformanceTest.json +++ /dev/null @@ -1,214 +0,0 @@ -{ - "mulmodloop" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x60015b68010000000000000000908060010109600356", - "data" : "0x", - "gas" : "10000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "0", - "out" : "0x0", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x60015b68010000000000000000908060010109600356", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x60015b68010000000000000000908060010109600356", - "nonce" : "0", - "storage" : { } - } - } - }, - - - "for-1e06" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "100000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", - "data" : "0x", - "gas" : "30000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "6999982", - "out" : "0x00", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", - "nonce" : "0", - "storage" : { } - } - } - }, - - "fib25" : { - "callcreates" : [ - ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "100000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", - "data" : "0x", - "gas" : "40000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "5886377", - "out" : "0x00000000000000000000000000000000000000000000000000000000000cb228", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", - "nonce" : "0", - "storage" : { - } - } - } - }, - - "ackermann37" : { - "callcreates" : [ - ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "20000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", - "data" : "0x", - "gas" : "20000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "913456", - "out" : "0x00000000000000000000000000000000000000000000000000000000000003fd", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", - "nonce" : "0", - "storage" : { - } - } - } - }, - - "jumptable100" : { - "callcreates" : [ - ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "389596", - "out" : "0x0000000000000000000000000000000000000000000000000000000000000064", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", - "nonce" : "0", - "storage" : { - } - } - } - }, - -} diff --git a/evmcc/test/vmtests/vm_jump.json b/evmcc/test/vmtests/vm_jump.json deleted file mode 100644 index 6b63edeae..000000000 --- a/evmcc/test/vmtests/vm_jump.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "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" : {} - } - } - } -} diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp deleted file mode 100644 index 79a8fe79c..000000000 --- a/libevmjit/Arith256.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "Arith256.h" -#include "Runtime.h" -#include "Type.h" - -#include - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Arith256::Arith256(llvm::IRBuilder<>& _builder) : - CompilerHelper(_builder) -{ - using namespace llvm; - - m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); - - using Linkage = GlobalValue::LinkageTypes; - - llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; - llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; - - m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); - m_div = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_div", getModule()); - m_mod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mod", getModule()); - m_sdiv = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule()); - m_smod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_smod", getModule()); - m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule()); - m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule()); -} - -Arith256::~Arith256() -{} - -llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); - return m_builder.CreateLoad(m_result); -} - -llvm::Value* Arith256::ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateStore(_arg3, m_arg3); - m_builder.CreateCall4(_op, m_arg1, m_arg2, m_arg3, m_result); - return m_builder.CreateLoad(m_result); -} - -llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) -{ - return binaryOp(m_mul, _arg1, _arg2); -} - -llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) -{ - return binaryOp(m_div, _arg1, _arg2); -} - -llvm::Value* Arith256::mod(llvm::Value* _arg1, llvm::Value* _arg2) -{ - return binaryOp(m_mod, _arg1, _arg2); -} - -llvm::Value* Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2) -{ - return binaryOp(m_sdiv, _arg1, _arg2); -} - -llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2) -{ - return binaryOp(m_smod, _arg1, _arg2); -} - -llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) -{ - return ternaryOp(m_addmod, _arg1, _arg2, _arg3); -} - -llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) -{ - return ternaryOp(m_mulmod, _arg1, _arg2, _arg3); -} - - -} -} -} - - -extern "C" -{ - - using namespace dev::eth::jit; - - EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result) - { - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg1 * arg2); - } - - EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result) - { - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); - } - - EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result) - { - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); - } - - EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result) - { - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) / dev::u2s(arg2))); - } - - EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result) - { - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : dev::s2u(dev::u2s(arg1) % dev::u2s(arg2))); - } - - EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) - { - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - dev::u256 arg3 = llvm2eth(*_arg3); - *o_result = eth2llvm(dev::u256((dev::bigint(arg1) * dev::bigint(arg2)) % arg3)); - } - - EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) - { - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); - dev::u256 arg3 = llvm2eth(*_arg3); - *o_result = eth2llvm(dev::u256((dev::bigint(arg1) + dev::bigint(arg2)) % arg3)); - } - -} - - diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h deleted file mode 100644 index 2268d5076..000000000 --- a/libevmjit/Arith256.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class Arith256 : public CompilerHelper -{ -public: - Arith256(llvm::IRBuilder<>& _builder); - virtual ~Arith256(); - - llvm::Value* mul(llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* div(llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* mod(llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* sdiv(llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* smod(llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); - llvm::Value* addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); - -private: - llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); - llvm::Value* ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); - - llvm::Function* m_mul; - llvm::Function* m_div; - llvm::Function* m_mod; - llvm::Function* m_sdiv; - llvm::Function* m_smod; - llvm::Function* m_mulmod; - llvm::Function* m_addmod; - - llvm::Value* m_arg1; - llvm::Value* m_arg2; - llvm::Value* m_arg3; - llvm::Value* m_result; -}; - - -} -} -} diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp deleted file mode 100644 index 1cc0e13fd..000000000 --- a/libevmjit/BasicBlock.cpp +++ /dev/null @@ -1,382 +0,0 @@ - -#include "BasicBlock.h" - -#include - -#include - -#include -#include -#include -#include -#include - -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -const char* BasicBlock::NamePrefix = "Instr."; - -BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : - m_beginInstIdx(_beginInstIdx), - m_endInstIdx(_endInstIdx), - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)), - m_stack(*this), - m_builder(_builder) -{} - -BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : - m_beginInstIdx(0), - m_endInstIdx(0), - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), - m_stack(*this), - m_builder(_builder) -{} - -BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : - m_bblock(_owner) -{} - -void BasicBlock::LocalStack::push(llvm::Value* _value) -{ - m_bblock.m_currentStack.push_back(_value); - m_bblock.m_tosOffset += 1; -} - -llvm::Value* BasicBlock::LocalStack::pop() -{ - auto result = get(0); - - if (m_bblock.m_currentStack.size() > 0) - m_bblock.m_currentStack.pop_back(); - - m_bblock.m_tosOffset -= 1; - return result; -} - -/** - * Pushes a copy of _index-th element (tos is 0-th elem). - */ -void BasicBlock::LocalStack::dup(size_t _index) -{ - auto val = get(_index); - push(val); -} - -/** - * Swaps tos with _index-th element (tos is 0-th elem). - * _index must be > 0. - */ -void BasicBlock::LocalStack::swap(size_t _index) -{ - assert(_index > 0); - auto val = get(_index); - auto tos = get(0); - set(_index, tos); - set(0, val); -} - -std::vector::iterator BasicBlock::LocalStack::getItemIterator(size_t _index) -{ - auto& currentStack = m_bblock.m_currentStack; - if (_index < currentStack.size()) - return currentStack.end() - _index - 1; - - // Need to map more elements from the EVM stack - auto nNewItems = 1 + _index - currentStack.size(); - currentStack.insert(currentStack.begin(), nNewItems, nullptr); - - return currentStack.end() - _index - 1; -} - -llvm::Value* BasicBlock::LocalStack::get(size_t _index) -{ - auto& initialStack = m_bblock.m_initialStack; - auto itemIter = getItemIterator(_index); - - if (*itemIter == nullptr) - { - // Need to fetch a new item from the EVM stack - assert(static_cast(_index) >= m_bblock.m_tosOffset); - size_t initialIdx = _index - m_bblock.m_tosOffset; - if (initialIdx >= initialStack.size()) - { - auto nNewItems = 1 + initialIdx - initialStack.size(); - initialStack.insert(initialStack.end(), nNewItems, nullptr); - } - - assert(initialStack[initialIdx] == nullptr); - // Create a dummy value. - std::string name = "get_" + boost::lexical_cast(_index); - initialStack[initialIdx] = m_bblock.m_builder.CreatePHI(Type::Word, 0, name); - *itemIter = initialStack[initialIdx]; - } - - return *itemIter; -} - -void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word) -{ - auto itemIter = getItemIterator(_index); - *itemIter = _word; -} - - - - - -void BasicBlock::synchronizeLocalStack(Stack& _evmStack) -{ - auto blockTerminator = m_llvmBB->getTerminator(); - assert(blockTerminator != nullptr); - m_builder.SetInsertPoint(blockTerminator); - - auto currIter = m_currentStack.begin(); - auto endIter = m_currentStack.end(); - - // Update (emit set()) changed values - for (int idx = m_currentStack.size() - 1 - m_tosOffset; - currIter < endIter && idx >= 0; - ++currIter, --idx) - { - assert(static_cast(idx) < m_initialStack.size()); - if (*currIter != m_initialStack[idx]) // value needs update - _evmStack.set(static_cast(idx), *currIter); - } - - if (m_tosOffset < 0) - { - // Pop values - _evmStack.pop(static_cast(-m_tosOffset)); - } - - // Push new values - for (; currIter < endIter; ++currIter) - { - assert(*currIter != nullptr); - _evmStack.push(*currIter); - } - - // Emit get() for all (used) values from the initial stack - for (size_t idx = 0; idx < m_initialStack.size(); ++idx) - { - auto val = m_initialStack[idx]; - if (val == nullptr) - continue; - - assert(llvm::isa(val)); - llvm::PHINode* phi = llvm::cast(val); - if (! phi->use_empty()) - { - // Insert call to get() just before the PHI node and replace - // the uses of PHI with the uses of this new instruction. - m_builder.SetInsertPoint(phi); - auto newVal = _evmStack.get(idx); - phi->replaceAllUsesWith(newVal); - } - phi->eraseFromParent(); - } - - // Reset the stack - m_initialStack.erase(m_initialStack.begin(), m_initialStack.end()); - m_currentStack.erase(m_currentStack.begin(), m_currentStack.end()); - m_tosOffset = 0; -} - -void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRBuilder<>& _builder) -{ - struct BBInfo - { - BasicBlock& bblock; - std::vector predecessors; - size_t inputItems; - size_t outputItems; - std::vector phisToRewrite; - - BBInfo(BasicBlock& _bblock) : - bblock(_bblock), - predecessors(), - inputItems(0), - outputItems(0) - { - auto& initialStack = bblock.m_initialStack; - for (auto it = initialStack.begin(); - it != initialStack.end() && *it != nullptr; - ++it, ++inputItems); - - //if (bblock.localStack().m_tosOffset > 0) - // outputItems = bblock.localStack().m_tosOffset; - auto& exitStack = bblock.m_currentStack; - for (auto it = exitStack.rbegin(); - it != exitStack.rend() && *it != nullptr; - ++it, ++outputItems); - } - }; - - std::map cfg; - - // Create nodes in cfg - for (auto bb : basicBlocks) - cfg.emplace(bb->llvm(), *bb); - - // Create edges in cfg: for each bb info fill the list - // of predecessor infos. - for (auto& pair : cfg) - { - auto bb = pair.first; - auto& info = pair.second; - - for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt) - { - auto predInfoEntry = cfg.find(*predIt); - if (predInfoEntry != cfg.end()) - info.predecessors.push_back(&predInfoEntry->second); - } - } - - // Iteratively compute inputs and outputs of each block, until reaching fixpoint. - bool valuesChanged = true; - while (valuesChanged) - { - if (getenv("EVMCC_DEBUG_BLOCKS")) - { - for (auto& pair : cfg) - std::cerr << pair.second.bblock.llvm()->getName().str() - << ": in " << pair.second.inputItems - << ", out " << pair.second.outputItems - << "\n"; - } - - valuesChanged = false; - for (auto& pair : cfg) - { - auto& info = pair.second; - - if (info.predecessors.empty()) - info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false - - for (auto predInfo : info.predecessors) - { - if (predInfo->outputItems < info.inputItems) - { - info.inputItems = predInfo->outputItems; - valuesChanged = true; - } - else if (predInfo->outputItems > info.inputItems) - { - predInfo->outputItems = info.inputItems; - valuesChanged = true; - } - } - } - } - - // Propagate values between blocks. - for (auto& entry : cfg) - { - auto& info = entry.second; - auto& bblock = info.bblock; - - llvm::BasicBlock::iterator fstNonPhi(bblock.llvm()->getFirstNonPHI()); - auto phiIter = bblock.m_initialStack.begin(); - for (size_t index = 0; index < info.inputItems; ++index, ++phiIter) - { - assert(llvm::isa(*phiIter)); - auto phi = llvm::cast(*phiIter); - - for (auto predIt : info.predecessors) - { - auto& predExitStack = predIt->bblock.m_currentStack; - auto value = *(predExitStack.end() - 1 - index); - phi->addIncoming(value, predIt->bblock.llvm()); - } - - // Move phi to the front - if (llvm::BasicBlock::iterator(phi) != bblock.llvm()->begin()) - { - phi->removeFromParent(); - _builder.SetInsertPoint(bblock.llvm(), bblock.llvm()->begin()); - _builder.Insert(phi); - } - } - - // The items pulled directly from predecessors block must be removed - // from the list of items that has to be popped from the initial stack. - auto& initialStack = bblock.m_initialStack; - initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); - // Initial stack shrinks, so the size difference grows: - bblock.m_tosOffset += info.inputItems; - } - - // We must account for the items that were pushed directly to successor - // blocks and thus should not be on the list of items to be pushed onto - // to EVM stack - for (auto& entry : cfg) - { - auto& info = entry.second; - auto& bblock = info.bblock; - - auto& exitStack = bblock.m_currentStack; - exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); - bblock.m_tosOffset -= info.outputItems; - } -} - -void BasicBlock::dump() -{ - dump(std::cerr, false); -} - -void BasicBlock::dump(std::ostream& _out, bool _dotOutput) -{ - llvm::raw_os_ostream out(_out); - - out << (_dotOutput ? "" : "Initial stack:\n"); - for (auto val : m_initialStack) - { - if (val == nullptr) - out << " ?"; - else if (llvm::isa(val)) - out << *val; - else - out << " " << *val; - - out << (_dotOutput ? "\\l" : "\n"); - } - - out << (_dotOutput ? "| " : "Instructions:\n"); - for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) - out << *ins << (_dotOutput ? "\\l" : "\n"); - - if (! _dotOutput) - out << "Current stack (offset = " << m_tosOffset << "):\n"; - else - out << "|"; - - for (auto val = m_currentStack.rbegin(); val != m_currentStack.rend(); ++val) - { - if (*val == nullptr) - out << " ?"; - else if (llvm::isa(*val)) - out << **val; - else - out << " " << **val; - out << (_dotOutput ? "\\l" : "\n"); - } - - if (! _dotOutput) - out << " ...\n----------------------------------------\n"; -} - - - - -} -} -} - diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h deleted file mode 100644 index f0643f342..000000000 --- a/libevmjit/BasicBlock.h +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once - -#include - -#include - -#include "Stack.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -using ProgramCounter = uint64_t; // TODO: Rename - -class BasicBlock -{ -public: - class LocalStack - { - public: - /// Pushes value on stack - void push(llvm::Value* _value); - - /// Pops and returns top value - llvm::Value* pop(); - - /// Duplicates _index'th value on stack - void dup(size_t _index); - - /// Swaps _index'th value on stack with a value on stack top. - /// @param _index Index of value to be swaped. Must be > 0. - void swap(size_t _index); - - private: - LocalStack(BasicBlock& _owner); - LocalStack(LocalStack const&) = delete; - void operator=(LocalStack const&) = delete; - friend BasicBlock; - - /// Gets _index'th value from top (counting from 0) - llvm::Value* get(size_t _index); - - /// Sets _index'th value from top (counting from 0) - void set(size_t _index, llvm::Value* _value); - - std::vector::iterator getItemIterator(size_t _index); - - private: - BasicBlock& m_bblock; - }; - - /// Basic block name prefix. The rest is beging instruction index. - static const char* NamePrefix; - - explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); - explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); - - BasicBlock(const BasicBlock&) = delete; - void operator=(const BasicBlock&) = delete; - - operator llvm::BasicBlock*() { return m_llvmBB; } - llvm::BasicBlock* llvm() { return m_llvmBB; } - - ProgramCounter begin() { return m_beginInstIdx; } - ProgramCounter end() { return m_endInstIdx; } - - LocalStack& localStack() { return m_stack; } - - /// Optimization: propagates values between local stacks in basic blocks - /// to avoid excessive pushing/popping on the EVM stack. - static void linkLocalStacks(std::vector _basicBlocks, llvm::IRBuilder<>& _builder); - - /// Synchronize current local stack with the EVM stack. - void synchronizeLocalStack(Stack& _evmStack); - - /// Prints local stack and block instructions to stderr. - /// Useful for calling in a debugger session. - void dump(); - void dump(std::ostream& os, bool _dotOutput = false); - -private: - ProgramCounter const m_beginInstIdx; - ProgramCounter const m_endInstIdx; - - llvm::BasicBlock* const m_llvmBB; - - /// Basic black state vector (stack) - current/end values and their positions on stack - /// @internal Must be AFTER m_llvmBB - LocalStack m_stack; - - llvm::IRBuilder<>& m_builder; - - /// This stack contains LLVM values that correspond to items found at - /// the EVM stack when the current basic block starts executing. - /// Location 0 corresponds to the top of the EVM stack, location 1 is - /// the item below the top and so on. The stack grows as the code - /// accesses more items on the EVM stack but once a value is put on - /// the stack, it will never be replaced. - std::vector m_initialStack = {}; - - /// This stack tracks the contents of the EVM stack as the basic block - /// executes. It may grow on both sides, as the code pushes items on - /// top of the stack or changes existing items. - std::vector m_currentStack = {}; - - /// How many items higher is the current stack than the initial one. - /// May be negative. - int m_tosOffset = 0; -}; - -} -} -} - diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt deleted file mode 100644 index 0b3226e14..000000000 --- a/libevmjit/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -cmake_policy(SET CMP0015 NEW) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") - -aux_source_directory(. SRC_LIST) - -set(EXECUTABLE evmjit) - -file(GLOB HEADERS "*.h") -if (EVMJIT_STATIC) - add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) -else() - add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) -endif() - -include_directories(..) - -target_link_libraries(${EXECUTABLE} devcore) -target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} evmcore) - - -if ("${TARGET_PLATFORM}" STREQUAL "w64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") - target_link_libraries(${EXECUTABLE} gcc) - target_link_libraries(${EXECUTABLE} gdi32) - target_link_libraries(${EXECUTABLE} ws2_32) - target_link_libraries(${EXECUTABLE} mswsock) - target_link_libraries(${EXECUTABLE} shlwapi) - target_link_libraries(${EXECUTABLE} iphlpapi) - target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) - set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) -else () - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -endif () - -# LLVM specific config - -find_package(LLVM REQUIRED CONFIG) - -message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") -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(evmjit ${llvm_libs}) - -# end of LLVM specific config - - - -install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) -install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) - -cmake_policy(SET CMP0015 NEW) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp deleted file mode 100644 index 1cc86d8aa..000000000 --- a/libevmjit/Compiler.cpp +++ /dev/null @@ -1,933 +0,0 @@ - -#include "Compiler.h" - -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include "Type.h" -#include "Memory.h" -#include "Stack.h" -#include "Ext.h" -#include "GasMeter.h" -#include "Utils.h" -#include "Endianness.h" -#include "Arith256.h" -#include "Runtime.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Compiler::Compiler(Options const& _options): - m_options(_options), - m_builder(llvm::getGlobalContext()) -{ - Type::init(m_builder.getContext()); -} - -void Compiler::createBasicBlocks(bytes const& _bytecode) -{ - std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end - - std::map directJumpTargets; - std::vector indirectJumpTargets; - boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1))); - - splitPoints.insert(0); // First basic block - validJumpTargets[0] = true; - - for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) - { - ProgramCounter currentPC = curr - _bytecode.begin(); - validJumpTargets[currentPC] = true; - - auto inst = Instruction(*curr); - switch (inst) - { - - case Instruction::ANY_PUSH: - { - auto val = readPushData(curr, _bytecode.end()); - auto next = curr + 1; - if (next == _bytecode.end()) - break; - - auto nextInst = Instruction(*next); - if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) - { - // Create a block for the JUMP target. - ProgramCounter targetPC = val < _bytecode.size() ? val.convert_to() : _bytecode.size(); - splitPoints.insert(targetPC); - - ProgramCounter jumpPC = (next - _bytecode.begin()); - directJumpTargets[jumpPC] = targetPC; - } - break; - } - - case Instruction::JUMPDEST: - { - // A basic block starts here. - splitPoints.insert(currentPC); - indirectJumpTargets.push_back(currentPC); - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - case Instruction::RETURN: - case Instruction::STOP: - case Instruction::SUICIDE: - { - // Create a basic block starting at the following instruction. - if (curr + 1 < _bytecode.end()) - splitPoints.insert(currentPC + 1); - break; - } - - default: - break; - } - } - - // Remove split points generated from jumps out of code or into data. - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - if (*it > _bytecode.size() || !validJumpTargets[*it]) - it = splitPoints.erase(it); - else - ++it; - } - - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - auto beginInstIdx = *it; - ++it; - auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); - basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); - } - - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); - m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); - - for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) - { - if (it->second >= _bytecode.size()) - { - // Jumping out of code means STOP - m_directJumpTargets[it->first] = m_stopBB; - continue; - } - - auto blockIter = basicBlocks.find(it->second); - if (blockIter != basicBlocks.end()) - { - m_directJumpTargets[it->first] = blockIter->second.llvm(); - } - else - { - clog(JIT) << "Bad JUMP at PC " << it->first - << ": " << it->second << " is not a valid PC"; - m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); - } - } - - for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); -} - -std::unique_ptr Compiler::compile(bytes const& _bytecode) -{ - auto module = std::unique_ptr(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 - 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"); - - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); - m_builder.SetInsertPoint(entryBlock); - - createBasicBlocks(_bytecode); - - // Init runtime structures. - RuntimeManager runtimeManager(m_builder); - GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(runtimeManager, gasMeter); - Ext ext(runtimeManager); - Stack stack(m_builder, runtimeManager); - Arith256 arith(m_builder); - - m_builder.CreateBr(basicBlocks.begin()->second); - - for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) - { - auto& basicBlock = basicBlockPairIt->second; - auto iterCopy = basicBlockPairIt; - ++iterCopy; - auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); - } - - // Code for special blocks: - // TODO: move to separate function. - m_builder.SetInsertPoint(m_stopBB); - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - - m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); - - m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - if (m_indirectJumpTargets.size() > 0) - { - auto dest = m_jumpTableBlock->localStack().pop(); - 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; - auto dest = Constant::get(bb->begin()); - switchInstr->addCase(dest, bb->llvm()); - } - } - else - m_builder.CreateBr(m_badJumpBlock->llvm()); - - removeDeadBlocks(); - - dumpCFGifRequired("blocks-init.dot"); - - if (m_options.optimizeStack) - { - std::vector blockList; - for (auto& entry : basicBlocks) - blockList.push_back(&entry.second); - - if (m_jumpTableBlock) - blockList.push_back(m_jumpTableBlock.get()); - - BasicBlock::linkLocalStacks(blockList, m_builder); - - dumpCFGifRequired("blocks-opt.dot"); - } - - for (auto& entry : basicBlocks) - entry.second.synchronizeLocalStack(stack); - if (m_jumpTableBlock) - m_jumpTableBlock->synchronizeLocalStack(stack); - - dumpCFGifRequired("blocks-sync.dot"); - - if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) - { - llvm::FunctionPassManager fpManager(module.get()); - fpManager.add(llvm::createLowerSwitchPass()); - fpManager.doInitialization(); - fpManager.run(*m_mainFunc); - } - - return module; -} - - -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, - Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) -{ - if (!_nextBasicBlock) // this is the last block in the code - _nextBasicBlock = m_stopBB; - - m_builder.SetInsertPoint(_basicBlock.llvm()); - auto& stack = _basicBlock.localStack(); - - for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) - { - auto inst = static_cast(_bytecode[currentPC]); - - _gasMeter.count(inst); - - switch (inst) - { - - case Instruction::ADD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateAdd(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::SUB: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto result = m_builder.CreateSub(lhs, rhs); - stack.push(result); - break; - } - - case Instruction::MUL: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.mul(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::DIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.div(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SDIV: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.sdiv(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::MOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.mod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::SMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = _arith.smod(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::EXP: - { - auto left = stack.pop(); - auto right = stack.pop(); - auto ret = _ext.exp(left, right); - stack.push(ret); - break; - } - - case Instruction::NOT: - { - auto value = stack.pop(); - auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); - stack.push(ret); - break; - } - - case Instruction::LT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpULT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::Word); - stack.push(res256); - break; - } - - case Instruction::GT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpUGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::Word); - stack.push(res256); - break; - } - - case Instruction::SLT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSLT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::Word); - stack.push(res256); - break; - } - - case Instruction::SGT: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpSGT(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::Word); - stack.push(res256); - break; - } - - case Instruction::EQ: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res1 = m_builder.CreateICmpEQ(lhs, rhs); - auto res256 = m_builder.CreateZExt(res1, Type::Word); - stack.push(res256); - break; - } - - case Instruction::ISZERO: - { - auto top = stack.pop(); - auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); - auto result = m_builder.CreateZExt(iszero, Type::Word); - stack.push(result); - break; - } - - case Instruction::AND: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateAnd(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::OR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateOr(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::XOR: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto res = m_builder.CreateXor(lhs, rhs); - stack.push(res); - break; - } - - case Instruction::BYTE: - { - const auto byteNum = stack.pop(); - auto value = stack.pop(); - - value = Endianness::toBE(m_builder, value); - auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); - auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); - value = m_builder.CreateZExt(byte, Type::Word); - - auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); - value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); - stack.push(value); - break; - } - - case Instruction::ADDMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = _arith.addmod(lhs, rhs, mod); - stack.push(res); - break; - } - - case Instruction::MULMOD: - { - auto lhs = stack.pop(); - auto rhs = stack.pop(); - auto mod = stack.pop(); - auto res = _arith.mulmod(lhs, rhs, mod); - stack.push(res); - 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::Word); - 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::Word), "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::Word, 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(); - auto inSize = stack.pop(); - _memory.require(inOff, inSize); - auto hash = _ext.sha3(inOff, inSize); - stack.push(hash); - break; - } - - case Instruction::POP: - { - auto val = stack.pop(); - static_cast(val); - // Generate a dummy use of val to make sure that a get(0) will be emitted at this point, - // so that StackTooSmall will be thrown - // m_builder.CreateICmpEQ(val, val, "dummy"); - break; - } - - case Instruction::ANY_PUSH: - { - auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator - auto value = readPushData(curr, _bytecode.end()); - currentPC = curr - _bytecode.begin(); - - stack.push(Constant::get(value)); - break; - } - - case Instruction::ANY_DUP: - { - auto index = static_cast(inst) - static_cast(Instruction::DUP1); - stack.dup(index); - break; - } - - case Instruction::ANY_SWAP: - { - auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; - stack.swap(index); - break; - } - - case Instruction::MLOAD: - { - auto addr = stack.pop(); - auto word = _memory.loadWord(addr); - stack.push(word); - break; - } - - case Instruction::MSTORE: - { - auto addr = stack.pop(); - auto word = stack.pop(); - _memory.storeWord(addr, word); - break; - } - - case Instruction::MSTORE8: - { - auto addr = stack.pop(); - auto word = stack.pop(); - _memory.storeByte(addr, word); - break; - } - - case Instruction::MSIZE: - { - auto word = _memory.getSize(); - stack.push(word); - break; - } - - case Instruction::SLOAD: - { - auto index = stack.pop(); - auto value = _ext.store(index); - stack.push(value); - break; - } - - case Instruction::SSTORE: - { - auto index = stack.pop(); - auto value = stack.pop(); - _gasMeter.countSStore(_ext, index, value); - _ext.setStore(index, value); - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - { - // Generate direct jump iff: - // 1. this is not the first instruction in the block - // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) - // Otherwise generate a indirect jump (a switch). - llvm::BasicBlock* targetBlock = nullptr; - if (currentPC != _basicBlock.begin()) - { - auto pairIter = m_directJumpTargets.find(currentPC); - if (pairIter != m_directJumpTargets.end()) - targetBlock = pairIter->second; - } - - if (inst == Instruction::JUMP) - { - if (targetBlock) - { - // The target address is computed at compile time, - // just pop it without looking... - stack.pop(); - m_builder.CreateBr(targetBlock); - } - else - m_builder.CreateBr(m_jumpTableBlock->llvm()); - } - else // JUMPI - { - stack.swap(1); - auto val = stack.pop(); - auto zero = Constant::get(0); - auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - - if (targetBlock) - { - stack.pop(); - m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); - } - else - m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); - } - - break; - } - - case Instruction::JUMPDEST: - { - // Nothing to do - break; - } - - case Instruction::PC: - { - auto value = Constant::get(currentPC); - stack.push(value); - break; - } - - case Instruction::GAS: - case Instruction::ADDRESS: - case Instruction::CALLER: - case Instruction::ORIGIN: - case Instruction::CALLVALUE: - case Instruction::CALLDATASIZE: - case Instruction::CODESIZE: - case Instruction::GASPRICE: - case Instruction::PREVHASH: - case Instruction::COINBASE: - case Instruction::TIMESTAMP: - case Instruction::NUMBER: - case Instruction::DIFFICULTY: - case Instruction::GASLIMIT: - { - // Pushes an element of runtime data on stack - stack.push(_runtimeManager.get(inst)); - break; - } - - case Instruction::BALANCE: - { - auto address = stack.pop(); - auto value = _ext.balance(address); - stack.push(value); - break; - } - - case Instruction::EXTCODESIZE: - { - auto addr = stack.pop(); - auto value = _ext.codesizeAt(addr); - stack.push(value); - break; - } - - case Instruction::CALLDATACOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _runtimeManager.getCallData(); - auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); - - _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CODECOPY: - { - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - 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); - break; - } - - case Instruction::EXTCODECOPY: - { - auto extAddr = stack.pop(); - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto srcPtr = _ext.codeAt(extAddr); - auto srcSize = _ext.codesizeAt(extAddr); - - _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); - break; - } - - case Instruction::CALLDATALOAD: - { - auto index = stack.pop(); - auto value = _ext.calldataload(index); - stack.push(value); - break; - } - - case Instruction::CREATE: - { - auto endowment = stack.pop(); - auto initOff = stack.pop(); - auto initSize = stack.pop(); - _memory.require(initOff, initSize); - - auto address = _ext.create(endowment, initOff, initSize); - stack.push(address); - break; - } - - case Instruction::CALL: - case Instruction::CALLCODE: - { - auto gas = stack.pop(); - auto codeAddress = stack.pop(); - auto value = stack.pop(); - auto inOff = stack.pop(); - auto inSize = stack.pop(); - auto outOff = stack.pop(); - auto outSize = stack.pop(); - - _gasMeter.commitCostBlock(gas); - - // Require memory for in and out buffers - _memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one - _memory.require(inOff, inSize); - - auto receiveAddress = codeAddress; - if (inst == Instruction::CALLCODE) - receiveAddress = _runtimeManager.get(RuntimeData::Address); - - auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gas); - stack.push(ret); - break; - } - - case Instruction::RETURN: - { - auto index = stack.pop(); - auto size = stack.pop(); - - _memory.require(index, size); - _runtimeManager.registerReturnData(index, size); - - m_builder.CreateRet(Constant::get(ReturnCode::Return)); - break; - } - - case Instruction::SUICIDE: - case Instruction::STOP: - { - if (inst == Instruction::SUICIDE) - { - auto address = stack.pop(); - _ext.suicide(address); - } - - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); - break; - } - - case Instruction::LOG0: - case Instruction::LOG1: - case Instruction::LOG2: - case Instruction::LOG3: - case Instruction::LOG4: - { - auto beginIdx = stack.pop(); - auto numBytes = stack.pop(); - _memory.require(beginIdx, numBytes); - - // This will commit the current cost block - _gasMeter.countLogData(numBytes); - - std::array topics; - auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); - for (size_t i = 0; i < numTopics; ++i) - topics[i] = stack.pop(); - - _ext.log(beginIdx, numBytes, numTopics, topics); - break; - } - - default: // Invalid instruction - runtime exception - { - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - - } - } - - _gasMeter.commitCostBlock(); - - // Block may have no terminator if the next instruction is a jump destination. - if (!_basicBlock.llvm()->getTerminator()) - m_builder.CreateBr(_nextBasicBlock); -} - - - -void Compiler::removeDeadBlocks() -{ - // Remove dead basic blocks - auto sthErased = false; - do - { - sthErased = false; - for (auto it = basicBlocks.begin(); it != basicBlocks.end();) - { - auto llvmBB = it->second.llvm(); - if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) - { - llvmBB->eraseFromParent(); - basicBlocks.erase(it++); - sthErased = true; - } - else - ++it; - } - } - while (sthErased); - - // Remove jump table block if no predecessors - if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) - { - m_jumpTableBlock->llvm()->eraseFromParent(); - m_jumpTableBlock.reset(); - } -} - -void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) -{ - if (! m_options.dumpCFG) - return; - - // TODO: handle i/o failures - std::ofstream ofs(_dotfilePath); - dumpCFGtoStream(ofs); - ofs.close(); -} - -void Compiler::dumpCFGtoStream(std::ostream& _out) -{ - _out << "digraph BB {\n" - << " node [shape=record, fontname=Courier, fontsize=10];\n" - << " entry [share=record, label=\"entry block\"];\n"; - - std::vector blocks; - for (auto& pair : basicBlocks) - blocks.push_back(&pair.second); - if (m_jumpTableBlock) - blocks.push_back(m_jumpTableBlock.get()); - if (m_badJumpBlock) - blocks.push_back(m_badJumpBlock.get()); - - // std::map phiNodesPerBlock; - - // Output nodes - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - std::ostringstream oss; - bb->dump(oss, true); - - _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; - } - - // Output edges - for (auto bb : blocks) - { - std::string blockName = bb->llvm()->getName(); - - auto end = llvm::pred_end(bb->llvm()); - 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, " : "") - << "];\n"; - } - } - - _out << "}\n"; -} - -void Compiler::dump() -{ - for (auto& entry : basicBlocks) - entry.second.dump(); - if (m_jumpTableBlock != nullptr) - m_jumpTableBlock->dump(); -} - -} -} -} - diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h deleted file mode 100644 index a618f41a3..000000000 --- a/libevmjit/Compiler.h +++ /dev/null @@ -1,92 +0,0 @@ - -#pragma once - -#include - -#include - -#include "BasicBlock.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class Compiler -{ -public: - - struct Options - { - /// Optimize stack operations between basic blocks - bool optimizeStack; - - /// Rewrite switch instructions to sequences of branches - bool rewriteSwitchToBranches; - - /// Dump CFG as a .dot file for graphviz - bool dumpCFG; - - Options(): - optimizeStack(true), - rewriteSwitchToBranches(true), - dumpCFG(false) - {} - }; - - using ProgramCounter = uint64_t; - - Compiler(Options const& _options); - - std::unique_ptr compile(bytes const& _bytecode); - -private: - - void createBasicBlocks(bytes const& _bytecode); - - void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); - - void removeDeadBlocks(); - - /// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled. - void dumpCFGifRequired(std::string const& _dotfilePath); - - /// Dumps basic block graph in graphviz format to a stream. - void dumpCFGtoStream(std::ostream& _out); - - /// Dumps all basic blocks to stderr. Useful in a debugging session. - void dump(); - - /// Compiler options - Options const& m_options; - - /// Helper class for generating IR - llvm::IRBuilder<> m_builder; - - /// Maps a program counter pc to a basic block that starts at pc (if any). - std::map basicBlocks = {}; - - /// Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. - std::map m_directJumpTargets = {}; - - /// A list of possible blocks to which there may be indirect jumps. - std::vector m_indirectJumpTargets = {}; - - /// Stop basic block - terminates execution with STOP code (0) - llvm::BasicBlock* m_stopBB = nullptr; - - /// Block with a jump table. - std::unique_ptr m_jumpTableBlock = nullptr; - - /// Default destination for indirect jumps. - std::unique_ptr m_badJumpBlock = nullptr; - - /// Main program function - llvm::Function* m_mainFunc = nullptr; -}; - -} -} -} diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp deleted file mode 100644 index c4835c32e..000000000 --- a/libevmjit/CompilerHelper.cpp +++ /dev/null @@ -1,44 +0,0 @@ - -#include "CompilerHelper.h" - -#include - -#include "Runtime.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : - m_builder(_builder) -{} - -llvm::Module* CompilerHelper::getModule() -{ - assert(m_builder.GetInsertBlock()); - assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function - return m_builder.GetInsertBlock()->getParent()->getParent(); -} - -llvm::Function* CompilerHelper::getMainFunction() -{ - assert(m_builder.GetInsertBlock()); - auto mainFunc = m_builder.GetInsertBlock()->getParent(); - assert(mainFunc); - if (mainFunc->getName() == "main") - return mainFunc; - return nullptr; -} - - -RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): - CompilerHelper(_runtimeManager.getBuilder()), - m_runtimeManager(_runtimeManager) -{} - -} -} -} diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h deleted file mode 100644 index 19315fe4a..000000000 --- a/libevmjit/CompilerHelper.h +++ /dev/null @@ -1,83 +0,0 @@ - -#pragma once - -#include - - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -/// Base class for compiler helpers like Memory, GasMeter, etc. -class CompilerHelper -{ -protected: - CompilerHelper(llvm::IRBuilder<>& _builder); - - CompilerHelper(const CompilerHelper&) = delete; - void operator=(CompilerHelper) = delete; - - /// Reference to the IR module being compiled - llvm::Module* getModule(); - - /// Reference to the main module function - llvm::Function* getMainFunction(); - - /// Reference to parent compiler IR builder - llvm::IRBuilder<>& m_builder; - llvm::IRBuilder<>& getBuilder() { return m_builder; } - - template - llvm::CallInst* createCall(llvm::Function* _func, _Args*... _args) - { - llvm::Value* args[] = {_args...}; - return getBuilder().CreateCall(_func, args); - } - - friend class RuntimeHelper; -}; - - -/// Compiler helper that depends on runtime data -class RuntimeHelper : public CompilerHelper -{ -protected: - RuntimeHelper(RuntimeManager& _runtimeManager); - - RuntimeManager& getRuntimeManager() { return m_runtimeManager; } - -private: - RuntimeManager& m_runtimeManager; -}; - - -/// Saves the insert point of the IR builder and restores it when destructed -struct InsertPointGuard -{ - InsertPointGuard(llvm::IRBuilder<>& _builder) : - m_builder(_builder), - m_insertBB(m_builder.GetInsertBlock()), - m_insertPt(m_builder.GetInsertPoint()) - {} - - InsertPointGuard(const InsertPointGuard&) = delete; - void operator=(InsertPointGuard) = delete; - - ~InsertPointGuard() - { - m_builder.SetInsertPoint(m_insertBB, m_insertPt); - } - -private: - llvm::IRBuilder<>& m_builder; - llvm::BasicBlock* m_insertBB; - llvm::BasicBlock::iterator m_insertPt; -}; - -} -} -} diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp deleted file mode 100644 index e062fb77e..000000000 --- a/libevmjit/Endianness.cpp +++ /dev/null @@ -1,25 +0,0 @@ - -#include "Endianness.h" - -#include - -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::Value* Endianness::bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word) -{ - // TODO: Native is Little Endian - assert(_word->getType() == Type::Word); - auto bswap = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); - return _builder.CreateCall(bswap, _word); -} - -} -} -} diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h deleted file mode 100644 index 951904358..000000000 --- a/libevmjit/Endianness.h +++ /dev/null @@ -1,34 +0,0 @@ - -#pragma once - -#include - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct Endianness -{ - -#if defined(BOOST_LITTLE_ENDIAN) - static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswap(_builder, _word); } - static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswap(_builder, _word); } - -#elif defined(BOOST_BIG_ENDIAN) - static llvm::Value* toBE(llvm::IRBuilder<>&, llvm::Value* _word) { return _word; } - static llvm::Value* toNative(llvm::IRBuilder<>&, llvm::Value* _word) { return _word; } - -#endif // Add support for PDP endianness if needed - -private: - static llvm::Value* bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word); -}; - -} -} -} diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp deleted file mode 100644 index 02b12d373..000000000 --- a/libevmjit/ExecutionEngine.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "ExecutionEngine.h" - -#include -#include - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#pragma GCC diagnostic pop - - -#include - -#include "Runtime.h" -#include "Memory.h" -#include "Stack.h" -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -ExecutionEngine::ExecutionEngine() -{ -} - -int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool _outputLogs, ExtVMFace& _ext) -{ - auto module = _module.get(); // Keep ownership of the module in _module - - llvm::sys::PrintStackTraceOnErrorSignal(); - static const auto program = "evmcc"; - llvm::PrettyStackTraceProgram X(1, &program); - - auto&& context = llvm::getGlobalContext(); - - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - llvm::InitializeNativeTargetAsmParser(); - - std::string errorMsg; - llvm::EngineBuilder builder(module); - //builder.setMArch(MArch); - //builder.setMCPU(MCPU); - //builder.setMAttrs(MAttrs); - //builder.setRelocationModel(RelocModel); - //builder.setCodeModel(CMModel); - builder.setErrorStr(&errorMsg); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - builder.setMCJITMemoryManager(new llvm::SectionMemoryManager()); - builder.setOptLevel(llvm::CodeGenOpt::None); - - 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 - module->setTargetTriple(triple.str()); - - auto exec = std::unique_ptr(builder.create()); - if (!exec) - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment(errorMsg)); - _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(finalizationEndTime - finalizationStartTime).count(); - - auto entryFunc = module->getFunction("main"); - if (!entryFunc) - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found")); - - ReturnCode returnCode; - std::jmp_buf buf; - Runtime runtime(_gas, _ext, buf, _outputLogs); - auto r = setjmp(buf); - if (r == 0) - { - - auto executionStartTime = std::chrono::high_resolution_clock::now(); - - auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(runtime.getDataPtr())}); - returnCode = static_cast(result.IntVal.getZExtValue()); - - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << "Execution time : " - << std::chrono::duration_cast(executionEndTime - executionStartTime).count(); - - } - else - returnCode = static_cast(r); - - // Return remaining gas - _gas = returnCode == ReturnCode::OutOfGas ? 0 : runtime.getGas(); - - clog(JIT) << "Max stack size: " << Stack::maxStackSize; - - if (returnCode == ReturnCode::Return) - { - returnData = runtime.getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface - - auto&& log = clog(JIT); - log << "RETURN [ "; - for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) - log << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; - log << "]"; - } - else - cslog(JIT) << "RETURN " << (int)returnCode; - - return static_cast(returnCode); -} - -} -} -} diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h deleted file mode 100644 index 8cf1ec746..000000000 --- a/libevmjit/ExecutionEngine.h +++ /dev/null @@ -1,28 +0,0 @@ - -#pragma once - -#include - -#include -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class ExecutionEngine -{ -public: - ExecutionEngine(); - - int run(std::unique_ptr module, u256& _gas, bool _outputLogs, ExtVMFace& _ext); - - bytes returnData; -}; - -} -} -} diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp deleted file mode 100644 index 6eb35acda..000000000 --- a/libevmjit/Ext.cpp +++ /dev/null @@ -1,420 +0,0 @@ - -#include "Ext.h" - -#include -#include -#include - -#include -#include - -#include "Runtime.h" -#include "Type.h" -#include "Endianness.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -// TODO: Copy of fromAddress in VM.h -inline u256 fromAddress(Address _a) -{ - return (u160)_a; -} - -Ext::Ext(RuntimeManager& _runtimeManager): - RuntimeHelper(_runtimeManager), - m_data() -{ - auto&& ctx = m_builder.getContext(); - auto module = getModule(); - - auto i256Ty = m_builder.getIntNTy(256); - - m_args[0] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.index"); - m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value"); - m_arg2 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg2"); - m_arg3 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg3"); - m_arg4 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg4"); - m_arg5 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg5"); - m_arg6 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg6"); - m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg7"); - m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8"); - - using Linkage = llvm::GlobalValue::LinkageTypes; - - llvm::Type* argsTypes[] = {Type::RuntimePtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; - - m_store = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_store", module); - m_setStore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_setStore", module); - m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_calldataload", module); - m_balance = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_balance", module); - m_suicide = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_suicide", module); - m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 5}, false), Linkage::ExternalLinkage, "ext_create", module); - m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), Linkage::ExternalLinkage, "ext_call", module); - m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_sha3", module); - m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module); - m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_codeAt", module); - m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module); - m_log0 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_log0", module); - m_log1 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_log1", module); - m_log2 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 5}, false), Linkage::ExternalLinkage, "ext_log2", module); - m_log3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 6}, false), Linkage::ExternalLinkage, "ext_log3", module); - m_log4 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 7}, false), Linkage::ExternalLinkage, "ext_log4", module); -} - -llvm::Value* Ext::store(llvm::Value* _index) -{ - m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateCall3(m_store, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); // Uses native endianness - return m_builder.CreateLoad(m_args[1]); -} - -void Ext::setStore(llvm::Value* _index, llvm::Value* _value) -{ - m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateStore(_value, m_args[1]); - m_builder.CreateCall3(m_setStore, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); // Uses native endianness -} - -llvm::Value* Ext::calldataload(llvm::Value* _index) -{ - m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateCall3(m_calldataload, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); - auto ret = m_builder.CreateLoad(m_args[1]); - return Endianness::toNative(m_builder, ret); -} - -llvm::Value* Ext::balance(llvm::Value* _address) -{ - auto address = Endianness::toBE(m_builder, _address); - m_builder.CreateStore(address, m_args[0]); - m_builder.CreateCall3(m_balance, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); - return m_builder.CreateLoad(m_args[1]); -} - -void Ext::suicide(llvm::Value* _address) -{ - auto address = Endianness::toBE(m_builder, _address); - m_builder.CreateStore(address, m_args[0]); - m_builder.CreateCall2(m_suicide, getRuntimeManager().getRuntimePtr(), m_args[0]); -} - -llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) -{ - m_builder.CreateStore(_endowment, m_args[0]); - m_builder.CreateStore(_initOff, m_arg2); - m_builder.CreateStore(_initSize, m_arg3); - createCall(m_create, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_args[1]); - llvm::Value* address = m_builder.CreateLoad(m_args[1]); - address = Endianness::toNative(m_builder, address); - return address; -} - -llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) -{ - m_builder.CreateStore(_gas, m_args[0]); - auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); - m_builder.CreateStore(receiveAddress, m_arg2); - m_builder.CreateStore(_value, m_arg3); - m_builder.CreateStore(_inOff, m_arg4); - m_builder.CreateStore(_inSize, m_arg5); - m_builder.CreateStore(_outOff, m_arg6); - m_builder.CreateStore(_outSize, m_arg7); - auto codeAddress = Endianness::toBE(m_builder, _codeAddress); - m_builder.CreateStore(codeAddress, m_arg8); - createCall(m_call, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]); - _gas = m_builder.CreateLoad(m_args[0]); // Return gas - return m_builder.CreateLoad(m_args[1]); -} - -llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) -{ - m_builder.CreateStore(_inOff, m_args[0]); - m_builder.CreateStore(_inSize, m_arg2); - createCall(m_sha3, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]); - llvm::Value* hash = m_builder.CreateLoad(m_args[1]); - hash = Endianness::toNative(m_builder, hash); - return hash; -} - -llvm::Value* Ext::exp(llvm::Value* _left, llvm::Value* _right) -{ - // TODO: Move ext to Arith256 - m_builder.CreateStore(_left, m_args[0]); - m_builder.CreateStore(_right, m_arg2); - createCall(m_exp, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]); - return m_builder.CreateLoad(m_args[1]); -} - -llvm::Value* Ext::codeAt(llvm::Value* _addr) -{ - auto addr = Endianness::toBE(m_builder, _addr); - m_builder.CreateStore(addr, m_args[0]); - return m_builder.CreateCall2(m_codeAt, getRuntimeManager().getRuntimePtr(), m_args[0]); -} - -llvm::Value* Ext::codesizeAt(llvm::Value* _addr) -{ - auto addr = Endianness::toBE(m_builder, _addr); - m_builder.CreateStore(addr, m_args[0]); - createCall(m_codesizeAt, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); - return m_builder.CreateLoad(m_args[1]); -} - -void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array const& _topics) -{ - llvm::Value* args[] = {nullptr, m_args[0], m_args[1], m_arg2, m_arg3, m_arg4, m_arg5}; - llvm::Value* funcs[] = {m_log0, m_log1, m_log2, m_log3, m_log4}; - - args[0] = getRuntimeManager().getRuntimePtr(); - m_builder.CreateStore(_memIdx, m_args[0]); - m_builder.CreateStore(_numBytes, m_args[1]); - - for (size_t i = 0; i < _numTopics; ++i) - m_builder.CreateStore(_topics[i], args[i + 3]); - - m_builder.CreateCall(funcs[_numTopics], llvm::ArrayRef(args, _numTopics + 3)); -} - -} - - -extern "C" -{ - - using namespace dev::eth::jit; - - EXPORT void ext_store(Runtime* _rt, i256* _index, i256* o_value) - { - auto index = llvm2eth(*_index); - auto value = _rt->getExt().store(index); // Interface uses native endianness - *o_value = eth2llvm(value); - } - - EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value) - { - auto index = llvm2eth(*_index); - auto value = llvm2eth(*_value); - auto& ext = _rt->getExt(); - - if (value == 0 && ext.store(index) != 0) // If delete - ext.sub.refunds += c_sstoreRefundGas; // Increase refund counter - - ext.setStore(index, value); // Interface uses native endianness - } - - EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* o_value) - { - auto index = static_cast(llvm2eth(*_index)); - assert(index + 31 > index); // TODO: Handle large index - auto b = reinterpret_cast(o_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* o_value) - { - auto u = _rt->getExt().balance(right160(*_address)); - *o_value = eth2llvm(u); - } - - EXPORT void ext_suicide(Runtime* _rt, h256 const* _address) - { - _rt->getExt().suicide(right160(*_address)); - } - - EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* o_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(llvm2eth(*_initOff)); - auto initSize = static_cast(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); - *o_address = address; - } - else - *o_address = {}; - } - - - - EXPORT void ext_call(Runtime* _rt, i256* io_gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* o_ret) - { - auto&& ext = _rt->getExt(); - auto value = llvm2eth(*_value); - - auto ret = false; - auto gas = llvm2eth(*io_gas); - if (ext.balance(ext.myAddress) >= value) - { - ext.subBalance(value); - auto receiveAddress = right160(*_receiveAddress); - auto inOff = static_cast(llvm2eth(*_inOff)); - auto inSize = static_cast(llvm2eth(*_inSize)); - auto outOff = static_cast(llvm2eth(*_outOff)); - auto outSize = static_cast(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); - } - - *io_gas = eth2llvm(gas); - o_ret->a = ret ? 1 : 0; - } - - EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* o_ret) - { - auto inOff = static_cast(llvm2eth(*_inOff)); - auto inSize = static_cast(llvm2eth(*_inSize)); - auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); - auto hash = sha3(dataRef); - *o_ret = *reinterpret_cast(&hash); - } - - EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* o_ret) - { - bigint left = llvm2eth(*_left); - bigint right = llvm2eth(*_right); - auto ret = static_cast(boost::multiprecision::powm(left, right, bigint(2) << 256)); - *o_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(code.data()); - } - - EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* o_ret) - { - auto&& ext = _rt->getExt(); - auto addr = right160(*_addr256); - auto& code = ext.codeAt(addr); - *o_ret = eth2llvm(u256(code.size())); - } - - void ext_show_bytes(bytesConstRef _bytes) - { - for (auto b : _bytes) - std::cerr << std::hex << std::setw(2) << std::setfill('0') << static_cast(b) << " "; - std::cerr << std::endl; - } - - EXPORT void ext_log0(Runtime* _rt, i256* _memIdx, i256* _numBytes) - { - auto&& ext = _rt->getExt(); - - auto memIdx = llvm2eth(*_memIdx).convert_to(); - auto numBytes = llvm2eth(*_numBytes).convert_to(); - - auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); - ext.log({}, dataRef); - - if (_rt->outputLogs()) - { - std::cerr << "LOG: "; - ext_show_bytes(dataRef); - } - } - - EXPORT void ext_log1(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1) - { - auto&& ext = _rt->getExt(); - - auto memIdx = static_cast(llvm2eth(*_memIdx)); - auto numBytes = static_cast(llvm2eth(*_numBytes)); - - auto topic1 = llvm2eth(*_topic1); - - auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); - ext.log({topic1}, dataRef); - - if (_rt->outputLogs()) - { - std::cerr << "LOG [" << topic1 << "]: "; - ext_show_bytes(dataRef); - } - } - - EXPORT void ext_log2(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2) - { - auto&& ext = _rt->getExt(); - - auto memIdx = static_cast(llvm2eth(*_memIdx)); - auto numBytes = static_cast(llvm2eth(*_numBytes)); - - auto topic1 = llvm2eth(*_topic1); - auto topic2 = llvm2eth(*_topic2); - - auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); - ext.log({topic1, topic2}, dataRef); - - if (_rt->outputLogs()) - { - std::cerr << "LOG [" << topic1 << "][" << topic2 << "]: "; - ext_show_bytes(dataRef); - } - } - - EXPORT void ext_log3(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3) - { - auto&& ext = _rt->getExt(); - - auto memIdx = static_cast(llvm2eth(*_memIdx)); - auto numBytes = static_cast(llvm2eth(*_numBytes)); - - auto topic1 = llvm2eth(*_topic1); - auto topic2 = llvm2eth(*_topic2); - auto topic3 = llvm2eth(*_topic3); - - auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); - ext.log({topic1, topic2, topic3}, dataRef); - - if (_rt->outputLogs()) - { - std::cerr << "LOG [" << topic1 << "][" << topic2 << "][" << topic3 << "]: "; - ext_show_bytes(dataRef); - } - } - - EXPORT void ext_log4(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3, i256* _topic4) - { - auto&& ext = _rt->getExt(); - - auto memIdx = static_cast(llvm2eth(*_memIdx)); - auto numBytes = static_cast(llvm2eth(*_numBytes)); - - auto topic1 = llvm2eth(*_topic1); - auto topic2 = llvm2eth(*_topic2); - auto topic3 = llvm2eth(*_topic3); - auto topic4 = llvm2eth(*_topic4); - - auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); - ext.log({topic1, topic2, topic3, topic4}, dataRef); - - if (_rt->outputLogs()) - { - std::cerr << "LOG [" << topic1 << "][" << topic2 << "][" << topic3 << "][" << topic4 << "]: "; - ext_show_bytes(dataRef); - } - } -} -} -} - diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h deleted file mode 100644 index 54380dda6..000000000 --- a/libevmjit/Ext.h +++ /dev/null @@ -1,69 +0,0 @@ - -#pragma once - -#include - -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class Ext : public RuntimeHelper -{ -public: - Ext(RuntimeManager& _runtimeManager); - - llvm::Value* store(llvm::Value* _index); - void setStore(llvm::Value* _index, llvm::Value* _value); - - llvm::Value* balance(llvm::Value* _address); - void suicide(llvm::Value* _address); - llvm::Value* calldataload(llvm::Value* _index); - llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); - llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); - - llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); - llvm::Value* exp(llvm::Value* _left, llvm::Value* _right); - llvm::Value* codeAt(llvm::Value* _addr); - llvm::Value* codesizeAt(llvm::Value* _addr); - - void log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array const& _topics); - -private: - - llvm::Value* m_args[2]; - llvm::Value* m_arg2; - llvm::Value* m_arg3; - llvm::Value* m_arg4; - llvm::Value* m_arg5; - llvm::Value* m_arg6; - llvm::Value* m_arg7; - llvm::Value* m_arg8; - llvm::Value* m_data; - llvm::Function* m_store; - llvm::Function* m_setStore; - llvm::Function* m_calldataload; - llvm::Function* m_balance; - llvm::Function* m_suicide; - llvm::Function* m_create; - llvm::Function* m_call; - llvm::Function* m_sha3; - llvm::Function* m_exp; - llvm::Function* m_codeAt; - llvm::Function* m_codesizeAt; - llvm::Function* m_log0; - llvm::Function* m_log1; - llvm::Function* m_log2; - llvm::Function* m_log3; - llvm::Function* m_log4; -}; - - -} -} -} - diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp deleted file mode 100644 index 48499259a..000000000 --- a/libevmjit/GasMeter.cpp +++ /dev/null @@ -1,199 +0,0 @@ - -#include "GasMeter.h" - -#include -#include -#include - -#include -#include - -#include "Type.h" -#include "Ext.h" -#include "Runtime.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -namespace // Helper functions -{ - -uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted) -{ - switch (inst) - { - case Instruction::STOP: - case Instruction::SUICIDE: - case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() - return 0; - - case Instruction::SLOAD: - return static_cast(c_sloadGas); - - case Instruction::SHA3: - return static_cast(c_sha3Gas); - - case Instruction::BALANCE: - return static_cast(c_sha3Gas); - - case Instruction::CALL: - case Instruction::CALLCODE: - return static_cast(c_callGas); - - case Instruction::CREATE: - return static_cast(c_createGas); - - case Instruction::LOG0: - case Instruction::LOG1: - case Instruction::LOG2: - case Instruction::LOG3: - case Instruction::LOG4: - { - auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); - return static_cast(c_logGas) + numTopics * static_cast(c_logTopicGas); - } - - default: // Assumes instruction code is valid - return static_cast(c_stepGas); - } -} - -bool isCostBlockEnd(Instruction _inst) -{ - // Basic block terminators like STOP are not needed on the list - // as cost will be commited at the end of basic block - - // CALL & CALLCODE are commited manually - - switch (_inst) - { - case Instruction::CALLDATACOPY: - case Instruction::CODECOPY: - case Instruction::MLOAD: - case Instruction::MSTORE: - case Instruction::MSTORE8: - case Instruction::SSTORE: - case Instruction::GAS: - case Instruction::CREATE: - return true; - - default: - return false; - } -} - -} - -GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) : - CompilerHelper(_builder), - m_runtimeManager(_runtimeManager) -{ - auto module = getModule(); - - m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::Word, false), llvm::Function::PrivateLinkage, "gas.check", module); - InsertPointGuard guard(m_builder); - - auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); - auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); - auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - - m_builder.SetInsertPoint(checkBB); - llvm::Value* cost = m_gasCheckFunc->arg_begin(); - cost->setName("cost"); - auto gas = m_runtimeManager.getGas(); - auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); - m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); - - m_builder.SetInsertPoint(outOfGasBB); - _runtimeManager.raiseException(ReturnCode::OutOfGas); - m_builder.CreateUnreachable(); - - m_builder.SetInsertPoint(updateBB); - gas = m_builder.CreateSub(gas, cost); - m_runtimeManager.setGas(gas); - m_builder.CreateRetVoid(); -} - -void GasMeter::count(Instruction _inst) -{ - if (!m_checkCall) - { - // 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::Word)); - } - - m_blockCost += getStepCost(_inst); - - if (isCostBlockEnd(_inst)) - commitCostBlock(); -} - -void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) -{ - assert(!m_checkCall); // Everything should've been commited before - - 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 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); -} - -void GasMeter::countLogData(llvm::Value* _dataLength) -{ - assert(m_checkCall); - assert(m_blockCost > 0); // LOGn instruction is already counted - auto cost = m_builder.CreateMul(_dataLength, Constant::get(c_logDataGas), "logdata_cost"); - commitCostBlock(cost); -} - -void GasMeter::giveBack(llvm::Value* _gas) -{ - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); -} - -void GasMeter::commitCostBlock(llvm::Value* _additionalCost) -{ - assert(!_additionalCost || m_checkCall); // _additionalCost => m_checkCall; Must be inside cost-block - - // If any uncommited block - if (m_checkCall) - { - if (m_blockCost == 0) // Do not check 0 - { - m_checkCall->eraseFromParent(); // Remove the gas check call - m_checkCall = nullptr; - return; - } - - m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call - m_checkCall = nullptr; // End cost-block - m_blockCost = 0; - - if (_additionalCost) - { - m_builder.CreateCall(m_gasCheckFunc, _additionalCost); - } - } - assert(m_blockCost == 0); -} - -void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords) -{ - auto cost = m_builder.CreateNUWMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); - m_builder.CreateCall(m_gasCheckFunc, cost); -} - -} -} -} - diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h deleted file mode 100644 index dfb4fb548..000000000 --- a/libevmjit/GasMeter.h +++ /dev/null @@ -1,54 +0,0 @@ - -#pragma once - -#include - -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -class GasMeter : public CompilerHelper // TODO: Use RuntimeHelper -{ -public: - GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager); - - /// Count step cost of instruction - void count(Instruction _inst); - - /// Calculate & count gas cost for SSTORE instruction - void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); - - /// Count gas cost of LOG data - void countLogData(llvm::Value* _dataLength); - - /// Finalize cost-block by checking gas needed for the block before the block - /// @param _additionalCost adds additional cost to cost-block before commit - void commitCostBlock(llvm::Value* _additionalCost = nullptr); - - /// Give back an amount of gas not used by a call - void giveBack(llvm::Value* _gas); - - /// Generate code that checks the cost of additional memory used by program - void checkMemory(llvm::Value* _additionalMemoryInWords); - -private: - /// Cumulative gas cost of a block of instructions - /// @TODO Handle overflow - uint64_t m_blockCost = 0; - - llvm::CallInst* m_checkCall = nullptr; - llvm::Function* m_gasCheckFunc = nullptr; - - RuntimeManager& m_runtimeManager; -}; - -} -} -} - diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp deleted file mode 100644 index 53cccf92b..000000000 --- a/libevmjit/Memory.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "Type.h" -#include "Runtime.h" -#include "GasMeter.h" -#include "Endianness.h" -#include "Runtime.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): - RuntimeHelper(_runtimeManager) -{ - auto module = getModule(); - llvm::Type* argTypes[] = {Type::Word, Type::Word}; - auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); - 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 - - m_size = new llvm::GlobalVariable(*module, Type::Word, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); - m_size->setUnnamedAddr(true); // Address is not important - - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module); - llvm::AttrBuilder attrBuilder; - attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter, _runtimeManager); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} - -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager) -{ - llvm::Type* argTypes[] = {Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto offset = func->arg_begin(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); - auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - // BB "Check" - m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); - auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); - auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); - auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); - auto currSize = m_builder.CreateLoad(m_size, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); - auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - - // BB "Resize" - m_builder.SetInsertPoint(resizeBB); - // Check gas first - uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); - auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); - auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); - auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); - wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); - wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); - auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k - auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.checkMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, m_size); - auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData"); - m_builder.CreateStore(newData, m_data); - m_builder.CreateBr(returnBB); - - // BB "Return" - m_builder.SetInsertPoint(returnBB); - m_builder.CreateRetVoid(); - return func; -} - -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) -{ - auto isWord = _valueType == Type::Word; - - llvm::Type* storeArgs[] = {Type::Word, _valueType}; - auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; - auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, Type::Word, false); - auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - 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"); - auto ptr = m_builder.CreateGEP(data, index, "ptr"); - if (isWord) - ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); - if (_isStore) - { - llvm::Value* value = ++func->arg_begin(); - value->setName("value"); - if (isWord) - value = Endianness::toBE(m_builder, value); - m_builder.CreateStore(value, ptr); - m_builder.CreateRetVoid(); - } - else - { - llvm::Value* ret = m_builder.CreateLoad(ptr); - ret = Endianness::toNative(m_builder, ret); - m_builder.CreateRet(ret); - } - - return func; -} - - -llvm::Value* Memory::loadWord(llvm::Value* _addr) -{ - auto value = m_builder.CreateCall(m_loadWord, _addr); - return value; -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - m_builder.CreateCall2(m_storeWord, _addr, _word); -} - -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) -{ - auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - m_builder.CreateCall2(m_storeByte, _addr, byte); -} - -llvm::Value* Memory::getData() -{ - return m_builder.CreateLoad(m_data); -} - -llvm::Value* Memory::getSize() -{ - return m_builder.CreateLoad(m_size); -} - -void Memory::require(llvm::Value* _offset, llvm::Value* _size) -{ - m_builder.CreateCall2(m_require, _offset, _size); -} - -void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, - llvm::Value* _destMemIdx, llvm::Value* _reqBytes) -{ - auto zero256 = llvm::ConstantInt::get(Type::Word, 0); - - require(_destMemIdx, _reqBytes); - - auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx"); - - auto memPtr = getData(); - auto destPtr = m_builder.CreateGEP(memPtr, _destMemIdx, "dest_mem_ptr"); - - // remaining source bytes: - auto remSrcSize = m_builder.CreateSub(_srcSize, _srcIdx); - auto remSizeNegative = m_builder.CreateICmpSLT(remSrcSize, zero256); - auto remSrcBytes = m_builder.CreateSelect(remSizeNegative, zero256, remSrcSize, "rem_src_bytes"); - - auto tooFewSrcBytes = m_builder.CreateICmpULT(remSrcBytes, _reqBytes); - auto bytesToCopy = m_builder.CreateSelect(tooFewSrcBytes, remSrcBytes, _reqBytes, "bytes_to_copy"); - - m_builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); -} - -} -} -} - - -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(); - } -} diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h deleted file mode 100644 index c6ba02a54..000000000 --- a/libevmjit/Memory.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include - -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class Memory : public RuntimeHelper -{ -public: - Memory(RuntimeManager& _runtimeManager, class GasMeter& _gasMeter); - - llvm::Value* loadWord(llvm::Value* _addr); - void storeWord(llvm::Value* _addr, llvm::Value* _word); - void storeByte(llvm::Value* _addr, llvm::Value* _byte); - llvm::Value* getData(); - llvm::Value* getSize(); - void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex, - llvm::Value* _destMemIdx, llvm::Value* _byteCount); - - /// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory. - void require(llvm::Value* _offset, llvm::Value* _size); - -private: - llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager); - - llvm::GlobalVariable* m_data; - llvm::GlobalVariable* m_size; - - llvm::Function* m_resize; - llvm::Function* m_require; - llvm::Function* m_loadWord; - llvm::Function* m_storeWord; - llvm::Function* m_storeByte; - - llvm::Function* m_memDump; -}; - -} -} -} - diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp deleted file mode 100644 index 8e52b648a..000000000 --- a/libevmjit/Runtime.cpp +++ /dev/null @@ -1,210 +0,0 @@ - -#include "Runtime.h" - -#include -#include -#include - -#include - -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::StructType* RuntimeData::getType() -{ - static llvm::StructType* type = nullptr; - if (!type) - { - llvm::Type* elems[] = - { - llvm::ArrayType::get(Type::Word, _size), - Type::BytePtr, - Type::BytePtr, - Type::BytePtr - }; - type = llvm::StructType::create(elems, "Runtime"); - } - return type; -} - -namespace -{ -llvm::Twine getName(RuntimeData::Index _index) -{ - switch (_index) - { - default: return "data"; - case RuntimeData::Gas: return "gas"; - case RuntimeData::Address: return "address"; - case RuntimeData::Caller: return "caller"; - case RuntimeData::Origin: return "origin"; - case RuntimeData::CallValue: return "callvalue"; - case RuntimeData::CallDataSize: return "calldatasize"; - case RuntimeData::GasPrice: return "gasprice"; - case RuntimeData::PrevHash: return "prevhash"; - case RuntimeData::CoinBase: return "coinbase"; - case RuntimeData::TimeStamp: return "timestamp"; - case RuntimeData::Number: return "number"; - case RuntimeData::Difficulty: return "difficulty"; - case RuntimeData::GasLimit: return "gaslimit"; - case RuntimeData::CodeSize: return "codesize"; - } -} -} - -Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf, bool _outputLogs): - m_ext(_ext), - m_outputLogs(_outputLogs) -{ - set(RuntimeData::Gas, _gas); - set(RuntimeData::Address, fromAddress(_ext.myAddress)); - set(RuntimeData::Caller, fromAddress(_ext.caller)); - set(RuntimeData::Origin, fromAddress(_ext.origin)); - set(RuntimeData::CallValue, _ext.value); - set(RuntimeData::CallDataSize, _ext.data.size()); - set(RuntimeData::GasPrice, _ext.gasPrice); - set(RuntimeData::PrevHash, _ext.previousBlock.hash); - set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress)); - set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp); - 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 - m_data.callData = _ext.data.data(); - m_data.code = _ext.code.data(); - m_data.jmpBuf = _jmpBuf; -} - -void Runtime::set(RuntimeData::Index _index, u256 _value) -{ - m_data.elems[_index] = eth2llvm(_value); -} - -u256 Runtime::getGas() const -{ - return llvm2eth(m_data.elems[RuntimeData::Gas]); -} - -bytesConstRef Runtime::getReturnData() const -{ - // TODO: Handle large indexes - auto offset = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset])); - auto size = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataSize])); - - assert(offset + size <= m_memory.size()); - // TODO: Handle invalid data access by returning empty ref - return {m_memory.data() + offset, size}; -} - -bool Runtime::outputLogs() const -{ - return m_outputLogs; -} - - -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) -{ - m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt"); - m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); - - // Export data - auto mainFunc = getMainFunction(); - llvm::Value* dataPtr = &mainFunc->getArgumentList().back(); - m_builder.CreateStore(dataPtr, m_dataPtr); -} - -llvm::Value* RuntimeManager::getRuntimePtr() -{ - if (auto mainFunc = getMainFunction()) - return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function - return m_builder.CreateLoad(m_dataPtr, "rt"); -} - -llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) -{ - llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)}; - return m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr"); -} - -llvm::Value* RuntimeManager::get(RuntimeData::Index _index) -{ - return m_builder.CreateLoad(getPtr(_index), getName(_index)); -} - -void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value) -{ - m_builder.CreateStore(_value, getPtr(_index)); -} - -void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size) -{ - set(RuntimeData::ReturnDataOffset, _offset); - set(RuntimeData::ReturnDataSize, _size); -} - -void RuntimeManager::raiseException(ReturnCode _returnCode) -{ - m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); -} - -llvm::Value* RuntimeManager::get(Instruction _inst) -{ - switch (_inst) - { - default: assert(false); return nullptr; - case Instruction::GAS: return get(RuntimeData::Gas); - case Instruction::ADDRESS: return get(RuntimeData::Address); - case Instruction::CALLER: return get(RuntimeData::Caller); - case Instruction::ORIGIN: return get(RuntimeData::Origin); - case Instruction::CALLVALUE: return get(RuntimeData::CallValue); - case Instruction::CALLDATASIZE: return get(RuntimeData::CallDataSize); - case Instruction::GASPRICE: return get(RuntimeData::GasPrice); - case Instruction::PREVHASH: return get(RuntimeData::PrevHash); - case Instruction::COINBASE: return get(RuntimeData::CoinBase); - case Instruction::TIMESTAMP: return get(RuntimeData::TimeStamp); - case Instruction::NUMBER: return get(RuntimeData::Number); - case Instruction::DIFFICULTY: return get(RuntimeData::Difficulty); - case Instruction::GASLIMIT: return get(RuntimeData::GasLimit); - case Instruction::CODESIZE: return get(RuntimeData::CodeSize); - } -} - -llvm::Value* RuntimeManager::getCallData() -{ - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 1, "calldataPtr"); - return getBuilder().CreateLoad(ptr, "calldata"); -} - -llvm::Value* RuntimeManager::getCode() -{ - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "codePtr"); - return getBuilder().CreateLoad(ptr, "code"); -} - -llvm::Value* RuntimeManager::getJmpBuf() -{ - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 3, "jmpbufPtr"); - return getBuilder().CreateLoad(ptr, "jmpbuf"); -} - -llvm::Value* RuntimeManager::getGas() -{ - return get(RuntimeData::Gas); -} - -void RuntimeManager::setGas(llvm::Value* _gas) -{ - llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(RuntimeData::Gas)}; - auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, "gasPtr"); - m_builder.CreateStore(_gas, ptr); -} - -} -} -} diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h deleted file mode 100644 index 8f485794a..000000000 --- a/libevmjit/Runtime.h +++ /dev/null @@ -1,122 +0,0 @@ - -#pragma once - -#include -#include - -#include - -#include "CompilerHelper.h" -#include "Utils.h" -#include "Type.h" - - -#ifdef _MSC_VER - #define EXPORT __declspec(dllexport) -#else - #define EXPORT -#endif - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct RuntimeData -{ - enum Index: unsigned - { - Gas, - Address, - Caller, - Origin, - CallValue, - CallDataSize, - GasPrice, - PrevHash, - CoinBase, - TimeStamp, - Number, - Difficulty, - GasLimit, - CodeSize, - - _size, - - ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference - ReturnDataSize = CallDataSize - }; - - i256 elems[_size]; - byte const* callData; - byte const* code; - decltype(&jmp_buf{}[0]) jmpBuf; - - static llvm::StructType* getType(); -}; - -using StackImpl = std::vector; -using MemoryImpl = bytes; - -class Runtime -{ -public: - Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf, bool _outputLogs); - - Runtime(const Runtime&) = delete; - void operator=(const Runtime&) = delete; - - RuntimeData* getDataPtr() { return &m_data; } - - StackImpl& getStack() { return m_stack; } - MemoryImpl& getMemory() { return m_memory; } - ExtVMFace& getExt() { return m_ext; } - - u256 getGas() const; - bytesConstRef getReturnData() const; - decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; } - bool outputLogs() const; - -private: - void set(RuntimeData::Index _index, u256 _value); - - /// @internal Must be the first element to asure Runtime* === RuntimeData* - RuntimeData m_data; - StackImpl m_stack; - MemoryImpl m_memory; - ExtVMFace& m_ext; - bool m_outputLogs; ///< write LOG statements to console -}; - -class RuntimeManager: public CompilerHelper -{ -public: - RuntimeManager(llvm::IRBuilder<>& _builder); - - llvm::Value* getRuntimePtr(); - - llvm::Value* get(RuntimeData::Index _index); - llvm::Value* get(Instruction _inst); - llvm::Value* getGas(); // TODO: Remove - llvm::Value* getCallData(); - llvm::Value* getCode(); - void setGas(llvm::Value* _gas); - - void registerReturnData(llvm::Value* _index, llvm::Value* _size); - - void raiseException(ReturnCode _returnCode); - -private: - llvm::Value* getPtr(RuntimeData::Index _index); - void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBuf(); - - llvm::GlobalVariable* m_dataPtr = nullptr; - llvm::Function* m_longjmp = nullptr; -}; - -} -} -} diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp deleted file mode 100644 index 494750b43..000000000 --- a/libevmjit/Stack.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "Stack.h" -#include "Runtime.h" -#include "Type.h" - -#include - -#include -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): - CompilerHelper(_builder), - m_runtimeManager(_runtimeManager) -{ - m_arg = m_builder.CreateAlloca(Type::Word, nullptr, "stack.arg"); - - using namespace llvm; - using Linkage = GlobalValue::LinkageTypes; - - auto module = getModule(); - - llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; - m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); - - llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; - m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); - - llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; - m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); - m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); -} - -llvm::Value* Stack::get(size_t _index) -{ - m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); - return m_builder.CreateLoad(m_arg); -} - -void Stack::set(size_t _index, llvm::Value* _value) -{ - m_builder.CreateStore(_value, m_arg); - m_builder.CreateCall3(m_set, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); -} - -void Stack::pop(size_t _count) -{ - m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); -} - -void Stack::push(llvm::Value* _value) -{ - m_builder.CreateStore(_value, m_arg); - m_builder.CreateCall2(m_push, m_runtimeManager.getRuntimePtr(), m_arg); -} - - -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(ReturnCode::StackTooSmall)); - - stack.erase(stack.end() - _count, stack.end()); - } - - EXPORT void stack_push(Runtime* _rt, i256 const* _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* o_ret) - { - auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - *o_ret = *(stack.rbegin() + _index); - } - - EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) - { - auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - *(stack.rbegin() + _index) = *_word; - } - -} // extern "C" - diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h deleted file mode 100644 index 3e8881e4f..000000000 --- a/libevmjit/Stack.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "CompilerHelper.h" - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class RuntimeManager; - -class Stack : public CompilerHelper -{ -public: - Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); - - llvm::Value* get(size_t _index); - void set(size_t _index, llvm::Value* _value); - void pop(size_t _count); - void push(llvm::Value* _value); - - static size_t maxStackSize; - -private: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp deleted file mode 100644 index a72ec0eda..000000000 --- a/libevmjit/Type.cpp +++ /dev/null @@ -1,59 +0,0 @@ - -#include "Type.h" - -#include - -#include "Runtime.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::IntegerType* Type::Word; -llvm::PointerType* Type::WordPtr; -llvm::IntegerType* Type::lowPrecision; -llvm::IntegerType* Type::Size; -llvm::IntegerType* Type::Byte; -llvm::PointerType* Type::BytePtr; -llvm::Type* Type::Void; -llvm::IntegerType* Type::MainReturn; -llvm::PointerType* Type::RuntimePtr; - -void Type::init(llvm::LLVMContext& _context) -{ - Word = llvm::Type::getIntNTy(_context, 256); - WordPtr = Word->getPointerTo(); - lowPrecision = llvm::Type::getInt64Ty(_context); - // TODO: Size should be architecture-dependent - Size = llvm::Type::getInt64Ty(_context); - Byte = llvm::Type::getInt8Ty(_context); - BytePtr = Byte->getPointerTo(); - Void = llvm::Type::getVoidTy(_context); - MainReturn = llvm::Type::getInt32Ty(_context); - RuntimePtr = RuntimeData::getType()->getPointerTo(); -} - -llvm::ConstantInt* Constant::get(int64_t _n) -{ - return llvm::ConstantInt::getSigned(Type::Word, _n); -} - -llvm::ConstantInt* Constant::get(u256 _n) -{ - llvm::APInt n(256, _n.str(0, std::ios_base::hex), 16); - assert(n.toString(10, false) == _n.str()); - return static_cast(llvm::ConstantInt::get(Type::Word, n)); -} - -llvm::ConstantInt* Constant::get(ReturnCode _returnCode) -{ - return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); -} - -} -} -} - diff --git a/libevmjit/Type.h b/libevmjit/Type.h deleted file mode 100644 index 0d8c6c530..000000000 --- a/libevmjit/Type.h +++ /dev/null @@ -1,63 +0,0 @@ - -#pragma once - -#include -#include -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct Type -{ - static llvm::IntegerType* Word; - static llvm::PointerType* WordPtr; - - /// Type for doing low precision arithmetics where 256-bit precision is not supported by native target - /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required - static llvm::IntegerType* lowPrecision; - - static llvm::IntegerType* Size; - - static llvm::IntegerType* Byte; - static llvm::PointerType* BytePtr; - - static llvm::Type* Void; - - /// Main function return type - static llvm::IntegerType* MainReturn; - - static llvm::PointerType* RuntimePtr; - - static void init(llvm::LLVMContext& _context); -}; - -enum class ReturnCode -{ - Stop = 0, - Return = 1, - Suicide = 2, - - BadJumpDestination = 101, - OutOfGas = 102, - StackTooSmall = 103, - BadInstruction = 104, -}; - -struct Constant -{ - /// Returns word-size constant - static llvm::ConstantInt* get(int64_t _n); - static llvm::ConstantInt* get(u256 _n); - - static llvm::ConstantInt* get(ReturnCode _returnCode); -}; - -} -} -} - diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp deleted file mode 100644 index 548ee0e1f..000000000 --- a/libevmjit/Utils.cpp +++ /dev/null @@ -1,57 +0,0 @@ - -#include "Utils.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -u256 llvm2eth(i256 _i) -{ - u256 u = 0; - u |= _i.d; - u <<= 64; - u |= _i.c; - u <<= 64; - u |= _i.b; - u <<= 64; - u |= _i.a; - return u; -} - -i256 eth2llvm(u256 _u) -{ - i256 i; - u256 mask = 0xFFFFFFFFFFFFFFFF; - i.a = static_cast(_u & mask); - _u >>= 64; - i.b = static_cast(_u & mask); - _u >>= 64; - i.c = static_cast(_u & mask); - _u >>= 64; - i.d = static_cast(_u & mask); - return i; -} - -u256 readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) -{ - auto pushInst = *_curr; - assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); - auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1; - u256 value; - ++_curr; // Point the data - for (decltype(numBytes) i = 0; i < numBytes; ++i) - { - byte b = (_curr != _end) ? *_curr++ : 0; - value <<= 8; - value |= b; - } - --_curr; // Point the last real byte read - return value; -} - -} -} -} diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h deleted file mode 100644 index 54291f3e0..000000000 --- a/libevmjit/Utils.h +++ /dev/null @@ -1,107 +0,0 @@ - -#pragma once - -#include - -#include -#include -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; - -/// Representation of 256-bit value binary compatible with LLVM i256 -// TODO: Replace with h256 -struct i256 -{ - uint64_t a; - uint64_t b; - uint64_t c; - uint64_t d; -}; -static_assert(sizeof(i256) == 32, "Wrong i265 size"); - -u256 llvm2eth(i256); -i256 eth2llvm(u256); - -/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it -/// Reading out of bytecode means reading 0 -/// @param _curr is updates and points the last real byte read -u256 readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); - -#define ANY_PUSH PUSH1: \ - case Instruction::PUSH2: \ - case Instruction::PUSH3: \ - case Instruction::PUSH4: \ - case Instruction::PUSH5: \ - case Instruction::PUSH6: \ - case Instruction::PUSH7: \ - case Instruction::PUSH8: \ - case Instruction::PUSH9: \ - case Instruction::PUSH10: \ - case Instruction::PUSH11: \ - case Instruction::PUSH12: \ - case Instruction::PUSH13: \ - case Instruction::PUSH14: \ - case Instruction::PUSH15: \ - case Instruction::PUSH16: \ - case Instruction::PUSH17: \ - case Instruction::PUSH18: \ - case Instruction::PUSH19: \ - case Instruction::PUSH20: \ - case Instruction::PUSH21: \ - case Instruction::PUSH22: \ - case Instruction::PUSH23: \ - case Instruction::PUSH24: \ - case Instruction::PUSH25: \ - case Instruction::PUSH26: \ - case Instruction::PUSH27: \ - case Instruction::PUSH28: \ - case Instruction::PUSH29: \ - case Instruction::PUSH30: \ - case Instruction::PUSH31: \ - case Instruction::PUSH32 - -#define ANY_DUP DUP1: \ - case Instruction::DUP2: \ - case Instruction::DUP3: \ - case Instruction::DUP4: \ - case Instruction::DUP5: \ - case Instruction::DUP6: \ - case Instruction::DUP7: \ - case Instruction::DUP8: \ - case Instruction::DUP9: \ - case Instruction::DUP10: \ - case Instruction::DUP11: \ - case Instruction::DUP12: \ - case Instruction::DUP13: \ - case Instruction::DUP14: \ - case Instruction::DUP15: \ - case Instruction::DUP16 - -#define ANY_SWAP SWAP1: \ - case Instruction::SWAP2: \ - case Instruction::SWAP3: \ - case Instruction::SWAP4: \ - case Instruction::SWAP5: \ - case Instruction::SWAP6: \ - case Instruction::SWAP7: \ - case Instruction::SWAP8: \ - case Instruction::SWAP9: \ - case Instruction::SWAP10: \ - case Instruction::SWAP11: \ - case Instruction::SWAP12: \ - case Instruction::SWAP13: \ - case Instruction::SWAP14: \ - case Instruction::SWAP15: \ - case Instruction::SWAP16 - -} -} -} diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp deleted file mode 100644 index b968008aa..000000000 --- a/libevmjit/VM.cpp +++ /dev/null @@ -1,46 +0,0 @@ - -#include "VM.h" - -#include -#include - -#include "ExecutionEngine.h" -#include "Compiler.h" -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) -{ - Compiler::Options defaultOptions; - auto module = Compiler(defaultOptions).compile(_ext.code); - - ExecutionEngine engine; - auto exitCode = engine.run(std::move(module), m_gas, false, _ext); - - switch (static_cast(exitCode)) - { - case ReturnCode::BadJumpDestination: - BOOST_THROW_EXCEPTION(BadJumpDestination()); - case ReturnCode::OutOfGas: - BOOST_THROW_EXCEPTION(OutOfGas()); - case ReturnCode::StackTooSmall: - BOOST_THROW_EXCEPTION(StackTooSmall()); - 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 -} - -} -} -} diff --git a/libevmjit/VM.h b/libevmjit/VM.h deleted file mode 100644 index 1c6c71181..000000000 --- a/libevmjit/VM.h +++ /dev/null @@ -1,34 +0,0 @@ - -#pragma once - -#include -#include -#include - -namespace dev -{ -namespace eth -{ - -class VMFactory; - -namespace jit -{ - -class VM: public VMFace -{ - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - - enum Kind: bool { Interpreter, JIT }; - static std::unique_ptr create(Kind, u256 _gas = 0); - -private: - friend VMFactory; - explicit VM(u256 _gas = 0): VMFace(_gas) {} - - bytes m_output; -}; - -} -} -} diff --git a/libevmjit/interface.c b/libevmjit/interface.c deleted file mode 100644 index 47589578b..000000000 --- a/libevmjit/interface.c +++ /dev/null @@ -1,30 +0,0 @@ -#include - -// JIT object opaque type -typedef struct evm_jit evm_jit; - -// Contract execution return code -typedef int evm_jit_return_code; - -// Host-endian 256-bit integer type -typedef struct i256 i256; - -// Big-endian right aligned 256-bit hash -typedef struct h256 h256; - -// Runtime data struct - must be provided by external language (Go, C++, Python) -typedef struct evm_jit_rt evm_jit_rt; - -// Runtime callback functions - implementations must be provided by external language (Go, C++, Python) -void evm_jit_rt_sload(evm_jit_rt* _rt, i256* _index, i256* _ret); -void evm_jit_rt_sstore(evm_jit_rt* _rt, i256* _index, i256* _value); -void evm_jit_rt_balance(evm_jit_rt* _rt, h256* _address, i256* _ret); -// And so on... - -evm_jit* evm_jit_create(evm_jit_rt* _runtime_data); - -evm_jit_return_code evm_jit_execute(evm_jit* _jit); - -void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); - -void evm_jit_destroy(evm_jit* _jit); From cc7578249631bf48aa1f27f09cb36138e1e66c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 09:17:20 +0100 Subject: [PATCH 351/396] Update evmjit submodule --- evmjit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit b/evmjit index 6f84f3d1a..c6fcdbc7d 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 6f84f3d1ade42bcacc99533d4807b9b759a5938b +Subproject commit c6fcdbc7d650054c4ed597e735633a45144dc3df From 72552c4936db8bef2d31ae2d301bfff1db395d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 09:26:07 +0100 Subject: [PATCH 352/396] Move helper functions back to VM --- libevm/VM.h | 19 +++++++++++++------ libevm/VMFace.h | 15 --------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index b4a0664ec..c95242dfa 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -38,6 +38,13 @@ namespace eth class VMFactory; +// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. +// Currently we just pull out the right (low-order in BE) 160-bits. +inline Address asAddress(u256 _item) +{ + return right160(h256(_item)); +} + inline u256 fromAddress(Address _a) { return (u160)_a; @@ -151,7 +158,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::SLOAD: require(1); - runGas = c_sloadGas; + runGas = c_sloadGas; break; // These all operate on memory and therefore potentially expand it: @@ -223,7 +230,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con u256 inOff = m_stack[m_stack.size() - 2]; u256 inSize = m_stack[m_stack.size() - 3]; newTempSize = (bigint)inOff + inSize; - runGas = c_createGas; + runGas = c_createGas; break; } case Instruction::EXP: @@ -399,7 +406,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.pop_back(); break; case Instruction::SDIV: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0; + m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0; m_stack.pop_back(); break; case Instruction::MOD: @@ -407,7 +414,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.pop_back(); break; case Instruction::SMOD: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0; + m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0; m_stack.pop_back(); break; case Instruction::EXP: @@ -430,11 +437,11 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.pop_back(); break; case Instruction::SLT: - m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; + m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; m_stack.pop_back(); break; case Instruction::SGT: - m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; + m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; m_stack.pop_back(); break; case Instruction::EQ: diff --git a/libevm/VMFace.h b/libevm/VMFace.h index 6617db1da..f4dd3096e 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -34,21 +34,6 @@ struct BadJumpDestination: virtual VMException {}; struct OutOfGas: virtual VMException {}; struct StackTooSmall: virtual public VMException {}; -// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. -// Currently we just pull out the right (low-order in BE) 160-bits. -inline Address asAddress(u256 _item) -{ - return right160(h256(_item)); -} - -inline u256 fromAddress(Address _a) -{ - return (u160)_a; - // h256 ret; - // memcpy(&ret, &_a, sizeof(_a)); - // return ret; -} - /** */ class VMFace From 31c3d111ada2285805114cb8b6aa3f487e52c0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 09:43:29 +0100 Subject: [PATCH 353/396] Windows fix & used code removed --- libevm/ExtVMFace.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 9e6601d0a..9d107a4b6 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -36,20 +36,12 @@ namespace dev namespace eth { -template inline std::set toSet(std::vector const& _ts) -{ - std::set ret; - for (auto const& t: _ts) - ret.insert(t); - return ret; -} - using LogBloom = h512; struct LogEntry { LogEntry() {} - LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256s)_r[1]; data = _r[2].toBytes(); } + LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = _r[1].toVector(); data = _r[2].toBytes(); } LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(_ts), data(std::move(_d)) {} void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; } From 312ee43aa2ff2d09c5d37a73e940bcadaab9a9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 10:13:14 +0100 Subject: [PATCH 354/396] Cleanups --- evmjit | 2 +- libethereum/VMFactory.cpp | 4 ++-- windows/LibEvmJitCpp.vcxproj | 4 ++-- windows/LibEvmJitCpp.vcxproj.filters | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/evmjit b/evmjit index c6fcdbc7d..2b9b53024 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit c6fcdbc7d650054c4ed597e735633a45144dc3df +Subproject commit 2b9b53024dfa62b62a322909a43154f65f29d4ce diff --git a/libethereum/VMFactory.cpp b/libethereum/VMFactory.cpp index a5910ed15..3077ed546 100644 --- a/libethereum/VMFactory.cpp +++ b/libethereum/VMFactory.cpp @@ -1,7 +1,7 @@ #include #if ETH_EVMJIT - #include + #include #endif #include "VMFactory.h" @@ -14,7 +14,7 @@ namespace eth std::unique_ptr VMFactory::create(VMFactory::Kind _kind, u256 _gas) { #if ETH_EVMJIT - auto vm = _kind == Kind::JIT ? static_cast(new jit::VM) + auto vm = _kind == Kind::JIT ? static_cast(new JitVM) : static_cast(new VM); #else VMFace* vm = new VM; diff --git a/windows/LibEvmJitCpp.vcxproj b/windows/LibEvmJitCpp.vcxproj index a5094e49c..d72bcd981 100644 --- a/windows/LibEvmJitCpp.vcxproj +++ b/windows/LibEvmJitCpp.vcxproj @@ -127,10 +127,10 @@ - + - + diff --git a/windows/LibEvmJitCpp.vcxproj.filters b/windows/LibEvmJitCpp.vcxproj.filters index 0c37264b0..4bf360cbe 100644 --- a/windows/LibEvmJitCpp.vcxproj.filters +++ b/windows/LibEvmJitCpp.vcxproj.filters @@ -4,10 +4,10 @@ - + - + \ No newline at end of file From 6c5a84cbc13d77780847c0fdb72356f8bf855e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 14:39:24 +0100 Subject: [PATCH 355/396] Fix random test generator --- test/createRandomTest.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 1647ce810..a01eec65c 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of cpp-ethereum. - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file createRandomTest.cpp * @author Christoph Jentzsch @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include "vm.h" @@ -128,6 +129,9 @@ void doMyTests(json_spirit::mValue& v) assert(o.count("pre") > 0); assert(o.count("exec") > 0); + + auto vmObj = eth::VMFactory::create(eth::VMFactory::Interpreter); + auto& vm = *vmObj; dev::test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -141,9 +145,8 @@ void doMyTests(json_spirit::mValue& v) fev.code = fev.thisTxCode; } + vm.reset(fev.gas); bytes output; - eth::VM vm(fev.gas); - u256 gas; bool vmExceptionOccured = false; try From fab154454d52a60634172e1acf584be577c03b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Fri, 5 Dec 2014 15:21:54 +0100 Subject: [PATCH 356/396] jit-related CMakeLists.txt fixes --- CMakeLists.txt | 3 +-- eth/CMakeLists.txt | 3 +-- exp/CMakeLists.txt | 2 +- libethereum/CMakeLists.txt | 1 + neth/CMakeLists.txt | 3 +-- test/CMakeLists.txt | 6 ++---- 6 files changed, 7 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9918b4ee1..ec2c90cc7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,8 +176,7 @@ if (NOT LANGUAGES) endif() if (EVMJIT) - add_subdirectory(libevmjit) - add_subdirectory(evmcc) + add_subdirectory(evmjit) endif() diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index 9239e79ac..918e8d047 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -14,8 +14,7 @@ target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} gmp) if(EVMJIT) - target_link_libraries(${EXECUTABLE} evm) - target_link_libraries(${EXECUTABLE} evmjit) + target_link_libraries(${EXECUTABLE} evmjit-cpp) endif() if(MINIUPNPC_LS) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index fce739007..a5e1cefea 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -18,7 +18,7 @@ endif() target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) if(EVMJIT) - target_link_libraries(${EXECUTABLE} evmjit) + target_link_libraries(${EXECUTABLE} evmjit-cpp) endif() if ("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 6088525fb..973a59ae3 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -30,6 +30,7 @@ target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS}) target_link_libraries(${EXECUTABLE} gmp) if (EVMJIT) target_link_libraries(${EXECUTABLE} evmjit) + target_link_libraries(${EXECUTABLE} evmjit-cpp) endif() if("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/neth/CMakeLists.txt b/neth/CMakeLists.txt index c3d14c983..e65db71fe 100644 --- a/neth/CMakeLists.txt +++ b/neth/CMakeLists.txt @@ -23,8 +23,7 @@ target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() if(EVMJIT) - target_link_libraries(${EXECUTABLE} evm) - target_link_libraries(${EXECUTABLE} evmjit) + target_link_libraries(${EXECUTABLE} evmjit-cpp) endif() if ("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8d8430b5c..3336b4289 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,8 +21,7 @@ if(JSONRPC_LS) target_link_libraries(testeth web3jsonrpc) endif() if (EVMJIT) - target_link_libraries(testeth evm) - target_link_libraries(testeth evmjit) + target_link_libraries(testeth evmjit-cpp) endif() target_link_libraries(createRandomTest ethereum) @@ -30,8 +29,7 @@ target_link_libraries(createRandomTest ethcore) target_link_libraries(createRandomTest boost_chrono) target_link_libraries(createRandomTest boost_unit_test_framework) if (EVMJIT) - target_link_libraries(createRandomTest evm) - target_link_libraries(createRandomTest evmjit) + target_link_libraries(createRandomTest evmjit-cpp) endif() if ("${TARGET_PLATFORM}" STREQUAL "w64") From 1d6f52fc4a2969adf55c5f3c79991e5c1e350800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 15:26:55 +0100 Subject: [PATCH 357/396] evmjit submodule update --- evmjit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit b/evmjit index 2b9b53024..c9f5694a2 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 2b9b53024dfa62b62a322909a43154f65f29d4ce +Subproject commit c9f5694a285412f693b160cf83e6258b0c41c504 From b68e671e2675fb76c9bb95947de91ae00ba67354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 10 Dec 2014 22:08:29 +0100 Subject: [PATCH 358/396] Update evmjit submodule url --- .gitmodules | 2 +- evmjit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index d7fb4f437..26c29d38d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "evmjit"] path = evmjit - url = ../evmjit + url = https://github.com/ethereum/evmjit branch = develop diff --git a/evmjit b/evmjit index c9f5694a2..b1b94de24 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit c9f5694a285412f693b160cf83e6258b0c41c504 +Subproject commit b1b94de243e8dd3a36b8be42794ed70a09271cfe From f47ed026036c5dbb0154a3edb28ac3cc780b05ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 11 Dec 2014 18:42:51 +0100 Subject: [PATCH 359/396] Integrate VMFactory with evmjit submodule --- libevm/VMFactory.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp index af37ec710..b6549ba04 100644 --- a/libevm/VMFactory.cpp +++ b/libevm/VMFactory.cpp @@ -18,6 +18,10 @@ #include "VMFactory.h" #include "VM.h" +#if ETH_EVMJIT +#include +#endif + namespace dev { namespace eth @@ -34,8 +38,12 @@ void VMFactory::setKind(VMKind _kind) std::unique_ptr VMFactory::create(u256 _gas) { - asserts(g_kind == VMKind::Interpreter && "Only interpreter supported for now"); +#if ETH_EVMJIT + return std::unique_ptr(g_kind == VMKind::JIT ? (VMFace*)new JitVM(_gas) : new VM(_gas)); +#else + asserts(g_kind == VMKind::Interpreter && "JIT disabled in build configuration"); return std::unique_ptr(new VM(_gas)); +#endif } } From de2c793effbdebd5787c3c4cca069a3dc21e0e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Dec 2014 11:48:15 +0100 Subject: [PATCH 360/396] Add "--jit" option to State tests --- evmjit | 2 +- test/TestHelper.cpp | 17 +++++++++++++++++ test/TestHelper.h | 1 + test/state.cpp | 2 ++ test/vm.cpp | 19 +++++-------------- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/evmjit b/evmjit index b1b94de24..b3a17341e 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit b1b94de243e8dd3a36b8be42794ed70a09271cfe +Subproject commit b3a17341e4ee3f2af12270d92cf404293deefc73 diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b0935d0b6..6f7bf31db 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace std; using namespace dev::eth; @@ -472,4 +473,20 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun } } + +void processCommandLineOptions() +{ + auto argc = boost::unit_test::framework::master_test_suite().argc; + auto argv = boost::unit_test::framework::master_test_suite().argv; + + for (auto i = 0; i < argc; ++i) + { + if (std::string(argv[i]) == "--jit") + { + eth::VMFactory::setKind(eth::VMKind::JIT); + break; + } + } +} + } } // namespaces diff --git a/test/TestHelper.h b/test/TestHelper.h index 3203eae83..20328c913 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -76,6 +76,7 @@ void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs); void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function doTests); std::string getTestPath(); void userDefinedTest(std::string testTypeFlag, std::function doTests); +void processCommandLineOptions(); template void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) diff --git a/test/state.cpp b/test/state.cpp index 07c8373e2..961f0f13b 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -43,6 +43,8 @@ namespace dev { namespace test { void doStateTests(json_spirit::mValue& v, bool _fillin) { + processCommandLineOptions(); + for (auto& i: v.get_obj()) { cnote << i.first; diff --git a/test/vm.cpp b/test/vm.cpp index bcd7df9b7..075b3f2a0 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -277,6 +277,8 @@ namespace dev { namespace test { void doVMTests(json_spirit::mValue& v, bool _fillin) { + processCommandLineOptions(); + for (auto& i: v.get_obj()) { cnote << i.first; @@ -286,20 +288,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) BOOST_REQUIRE(o.count("pre") > 0); BOOST_REQUIRE(o.count("exec") > 0); - auto argc = boost::unit_test::framework::master_test_suite().argc; - auto argv = boost::unit_test::framework::master_test_suite().argv; - - for (auto i = 0; i < argc; ++i) - { - if (std::string(argv[i]) == "--jit") - { - VMFactory::setKind(VMKind::JIT); - break; - } - } - - dev::test::FakeExtVM fev; - + FakeExtVM fev; fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -340,6 +329,8 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) } auto endTime = std::chrono::high_resolution_clock::now(); + auto argc = boost::unit_test::framework::master_test_suite().argc; + auto argv = boost::unit_test::framework::master_test_suite().argv; for (auto i = 0; i < argc; ++i) { if (std::string(argv[i]) == "--show-times") From 921d816a29beba5495f4aa229d476ec65250df0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Dec 2014 18:53:57 +0100 Subject: [PATCH 361/396] Update Visual Studio projects --- windows/LibEthereum.vcxproj | 7 ++++--- windows/LibEthereum.vcxproj.filters | 12 ++++++++++++ windows/LibEvmJit.vcxproj | 2 ++ windows/LibEvmJit.vcxproj.filters | 2 ++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 66efe7dc2..b4624f962 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -125,7 +125,6 @@ - @@ -146,7 +145,7 @@ true true - + @@ -170,6 +169,7 @@ true true + true true @@ -343,7 +343,6 @@ - @@ -372,6 +371,7 @@ true + @@ -408,6 +408,7 @@ true true + true true diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index 76201d823..e70393706 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -198,6 +198,12 @@ + + libevm + + + libp2p + @@ -437,6 +443,12 @@ libevm + + libevm + + + libp2p + diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index 077757aab..c3b1f65a7 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -130,6 +130,7 @@ + @@ -147,6 +148,7 @@ + diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters index 06f1ed308..88dc8d329 100644 --- a/windows/LibEvmJit.vcxproj.filters +++ b/windows/LibEvmJit.vcxproj.filters @@ -16,6 +16,7 @@ + @@ -35,6 +36,7 @@ + From 2eaed59cd4a003c2f8c2e404893067f3eb73cb9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Dec 2014 18:54:39 +0100 Subject: [PATCH 362/396] Fix dev::contents function on MSVC --- libdevcore/CommonIO.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index 8fc4fedb3..ec8ca605c 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -65,6 +65,8 @@ bytes dev::contents(std::string const& _file) // get length of file: is.seekg (0, is.end); streamoff length = is.tellg(); + if (length == 0) // return early, MSVC does not like reading 0 bytes + return {}; is.seekg (0, is.beg); bytes ret(length); is.read((char*)ret.data(), length); From 1efde49fd7e1ef2f7b7cb573584311f98748e93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 15 Dec 2014 15:13:57 +0100 Subject: [PATCH 363/396] Update usage of ExtVMFace in evmjit submodule --- evmjit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit b/evmjit index b3a17341e..dbf8174fc 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit b3a17341e4ee3f2af12270d92cf404293deefc73 +Subproject commit dbf8174fc6f8be9e6d1e62a627388fa23eb2308f From 6c1beee64d57b2ea8e5c5ecb9992806cb1cfe999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 17:55:50 +0100 Subject: [PATCH 364/396] Update evmjit submodule --- evmjit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit b/evmjit index dbf8174fc..b37ce8e97 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit dbf8174fc6f8be9e6d1e62a627388fa23eb2308f +Subproject commit b37ce8e9727683b8c7afb84520f42a908318f8d8 From 2bff39d4870a6b8c57deb53fbdba2d22cdd0d01b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 17:56:44 +0100 Subject: [PATCH 365/396] Visual Studio project files update --- windows/LibEthereum.vcxproj | 10 ++++------ windows/LibEthereum.vcxproj.filters | 30 ++++++++++++----------------- windows/TestEthereum.vcxproj | 1 + 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index b4624f962..30c5e8a21 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -117,13 +117,12 @@ - - + - + @@ -335,13 +334,12 @@ - - + - + diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index e70393706..39c3a0004 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -58,18 +58,12 @@ libethereum - - libethereum - libethereum libethereum - - libethereum - libethereum @@ -136,9 +130,6 @@ libethereum - - libethereum - libethereum @@ -204,6 +195,12 @@ libp2p + + libethereum + + + libethereum + @@ -272,18 +269,12 @@ libethereum - - libethereum - libethereum libethereum - - libethereum - libethereum @@ -368,9 +359,6 @@ libethereum - - libethereum - libethereum @@ -449,6 +437,12 @@ libp2p + + libethereum + + + libethereum + diff --git a/windows/TestEthereum.vcxproj b/windows/TestEthereum.vcxproj index 93bb98e23..cc737bc31 100644 --- a/windows/TestEthereum.vcxproj +++ b/windows/TestEthereum.vcxproj @@ -111,6 +111,7 @@ Console true + 33554432 From a6e8c122ea88990eb6a0f9a26bfbe81c335b07c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 17:56:54 +0100 Subject: [PATCH 366/396] Windows fix --- test/TestHelper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index d0100db61..ea848c7ce 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -331,9 +331,11 @@ void checkStorage(map _expectedStore, map _resultStore, } } BOOST_CHECK_EQUAL(_resultStore.size(), _expectedStore.size()); - for (auto&& resultStorePair : _resultStore) + for (auto&& resultStorePair: _resultStore) + { if (!_expectedStore.count(resultStorePair.first)) BOOST_ERROR(_expectedAddr << ": unexpected store key " << resultStorePair.first); + } } void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs) From d19d4b29db7b6e958b473ab29278bc5ad700d9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Dec 2014 15:03:34 +0100 Subject: [PATCH 367/396] Update evmjit submodule: object cache speeds up recursive calls --- evmjit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit b/evmjit index b37ce8e97..8287c6040 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit b37ce8e9727683b8c7afb84520f42a908318f8d8 +Subproject commit 8287c6040a4900cb8b091ffbe284c7f478c60c49 From d14ed2d4dc29afcce8c16a0173d7a4e87b2c5974 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 18 Dec 2014 17:04:20 +0100 Subject: [PATCH 368/396] Bit operators should bind more strongly than comparison operators. --- libsolidity/Token.h | 20 ++++++++++---------- test/SolidityNameAndTypeResolution.cpp | 10 ++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 32656096a..897d6eaaa 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -107,9 +107,9 @@ namespace solidity T(COMMA, ",", 1) \ T(OR, "||", 4) \ T(AND, "&&", 5) \ - T(BIT_OR, "|", 6) \ - T(BIT_XOR, "^", 7) \ - T(BIT_AND, "&", 8) \ + T(BIT_OR, "|", 8) \ + T(BIT_XOR, "^", 9) \ + T(BIT_AND, "&", 10) \ T(SHL, "<<", 11) \ T(SAR, ">>", 11) \ T(SHR, ">>>", 11) \ @@ -122,13 +122,13 @@ namespace solidity /* Compare operators sorted by precedence. */ \ /* IsCompareOp() relies on this block of enum values */ \ /* being contiguous and sorted in the same order! */ \ - T(EQ, "==", 9) \ - T(NE, "!=", 9) \ - T(LT, "<", 10) \ - T(GT, ">", 10) \ - T(LTE, "<=", 10) \ - T(GTE, ">=", 10) \ - K(IN, "in", 10) \ + T(EQ, "==", 6) \ + T(NE, "!=", 6) \ + T(LT, "<", 7) \ + T(GT, ">", 7) \ + T(LTE, "<=", 7) \ + T(GTE, ">=", 7) \ + K(IN, "in", 7) \ \ /* Unary operators. */ \ /* IsUnaryOp() relies on this block of enum values */ \ diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 0bda0a1fd..c7f0b3ab8 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -311,6 +311,16 @@ BOOST_AUTO_TEST_CASE(forward_function_reference) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(comparison_bitop_precedence) +{ + char const* text = "contract First {\n" + " function fun() returns (bool ret) {\n" + " return 1 & 2 == 8 & 9;\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + BOOST_AUTO_TEST_SUITE_END() } From ae994f28043065ef9ff8c3a2835a69389a495029 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 18 Dec 2014 17:49:11 +0100 Subject: [PATCH 369/396] Also test non-equality comparison operator. --- test/SolidityNameAndTypeResolution.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index c7f0b3ab8..25bff71f7 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -315,7 +315,7 @@ BOOST_AUTO_TEST_CASE(comparison_bitop_precedence) { char const* text = "contract First {\n" " function fun() returns (bool ret) {\n" - " return 1 & 2 == 8 & 9;\n" + " return 1 & 2 == 8 & 9 && 1 ^ 2 < 4 | 6;\n" " }\n" "}\n"; BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); From fce7f1712d32bb3f3c0c56078201adda4541be2b Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 18 Dec 2014 21:43:40 +0100 Subject: [PATCH 370/396] more refunds tests --- test/stRefundTestFiller.json | 163 +++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/test/stRefundTestFiller.json b/test/stRefundTestFiller.json index 4060bbb72..6b2b2fc15 100644 --- a/test/stRefundTestFiller.json +++ b/test/stRefundTestFiller.json @@ -141,5 +141,168 @@ "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "data" : "" } + }, + + "refund50_1" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 1 ]] 0 [[ 2 ]] 0 [[ 3 ]] 0 [[ 4 ]] 0 [[ 5 ]] 0 }", + "storage" : { + "0x01" : "0x01", + "0x02" : "0x01", + "0x03" : "0x01", + "0x04" : "0x01", + "0x05" : "0x01" + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "refund50_2" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 10 ]] 1 [[ 11 ]] 1 [[ 1 ]] 0 [[ 2 ]] 0 [[ 3 ]] 0 [[ 4 ]] 0 [[ 5 ]] 0 }", + "storage" : { + "0x01" : "0x01", + "0x02" : "0x01", + "0x03" : "0x01", + "0x04" : "0x01", + "0x05" : "0x01" + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "refund500" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ @@1 @@2 [[ 10 ]] (EXP 2 0xff) [[ 11 ]] (BALANCE (ADDRESS)) [[ 1 ]] 0 [[ 2 ]] 0 [[ 3 ]] 0 [[ 4 ]] 0 [[ 5 ]] 0 [[ 6 ]] 0 }", + "storage" : { + "0x01" : "0x01", + "0x02" : "0x01", + "0x03" : "0x01", + "0x04" : "0x01", + "0x05" : "0x01", + "0x06" : "0x01" + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "refund600" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ @@1 @@2 [[ 10 ]] (EXP 2 0xffff) [[ 11 ]] (BALANCE (ADDRESS)) [[ 1 ]] 0 [[ 2 ]] 0 [[ 3 ]] 0 [[ 4 ]] 0 [[ 5 ]] 0 [[ 6 ]] 0 }", + "storage" : { + "0x01" : "0x01", + "0x02" : "0x01", + "0x03" : "0x01", + "0x04" : "0x01", + "0x05" : "0x01", + "0x06" : "0x01" + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } } + } From e427a0a2cafa5ecd4ea3872aadd2b5f19eb705cb Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 18 Dec 2014 22:15:11 +0100 Subject: [PATCH 371/396] Bugfix: Additional swap for compound assignment. --- libsolidity/ExpressionCompiler.cpp | 2 ++ test/SolidityEndToEndTest.cpp | 35 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index f58c157d9..cf641935a 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -62,6 +62,8 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2; m_currentLValue.retrieveValue(_assignment, true); appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType()); + if (m_currentLValue.storesReferenceOnStack()) + m_context << eth::Instruction::SWAP1; } m_currentLValue.storeValue(_assignment); m_currentLValue.reset(); diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index aa74f8186..9559e3702 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -504,6 +504,41 @@ BOOST_AUTO_TEST_CASE(state_smoke_test) BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3))); } +BOOST_AUTO_TEST_CASE(compound_assign) +{ + char const* sourceCode = "contract test {\n" + " uint value1;\n" + " uint value2;\n" + " function f(uint x, uint y) returns (uint w) {\n" + " uint value3 = y;" + " value1 += x;\n" + " value3 *= x;" + " value2 *= value3 + value1;\n" + " return value2 += 7;" + " }\n" + "}\n"; + compileAndRun(sourceCode); + + u256 value1; + u256 value2; + auto f = [&](u256 const& _x, u256 const& _y) -> u256 + { + u256 value3 = _y; + value1 += _x; + value3 *= _x; + value2 *= value3 + value1; + return value2 += 7; + }; + testSolidityAgainstCpp(0, f, u256(0), u256(6)); + testSolidityAgainstCpp(0, f, u256(1), u256(3)); + testSolidityAgainstCpp(0, f, u256(2), u256(25)); + testSolidityAgainstCpp(0, f, u256(3), u256(69)); + testSolidityAgainstCpp(0, f, u256(4), u256(84)); + testSolidityAgainstCpp(0, f, u256(5), u256(2)); + testSolidityAgainstCpp(0, f, u256(6), u256(51)); + testSolidityAgainstCpp(0, f, u256(7), u256(48)); +} + BOOST_AUTO_TEST_CASE(simple_mapping) { char const* sourceCode = "contract test {\n" From f3f5d9ea745bef9455de82fcd57ab9d1dc0b350d Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 18 Dec 2014 23:02:41 +0100 Subject: [PATCH 372/396] correct VMTrace define --- libethereum/State.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index fd00761e1..e02b06bcd 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1017,7 +1017,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) ctrace << "Executing" << e.t() << "on" << h; ctrace << toHex(e.t().rlp()); #endif -#if ETH_TRACE +#if ETH_VMTRACE e.go(e.simpleTrace()); #else e.go(); From 29261206b9293c2e07b2b879aff059bc57e5d1cb Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 19 Dec 2014 10:48:59 +0100 Subject: [PATCH 373/396] Adding const attribute to ABI output --- libsolidity/InterfaceHandler.cpp | 1 + test/SolidityABIJSON.cpp | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 5b5682ff1..60971fbb9 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -56,6 +56,7 @@ std::unique_ptr InterfaceHandler::getABIInterface(ContractDefinitio }; method["name"] = f->getName(); + method["const"] = f->isDeclaredConst(); method["inputs"] = populateParameters(f->getParameters()); method["outputs"] = populateParameters(f->getReturnParameters()); methods.append(method); diff --git a/test/SolidityABIJSON.cpp b/test/SolidityABIJSON.cpp index c734009c3..62ab0458c 100644 --- a/test/SolidityABIJSON.cpp +++ b/test/SolidityABIJSON.cpp @@ -76,6 +76,7 @@ BOOST_AUTO_TEST_CASE(basic_test) char const* interface = R"([ { "name": "f", + "const": false, "inputs": [ { "name": "a", @@ -114,6 +115,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods) char const* interface = R"([ { "name": "f", + "const": false, "inputs": [ { "name": "a", @@ -129,6 +131,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods) }, { "name": "g", + "const": false, "inputs": [ { "name": "b", @@ -156,6 +159,7 @@ BOOST_AUTO_TEST_CASE(multiple_params) char const* interface = R"([ { "name": "f", + "const": false, "inputs": [ { "name": "a", @@ -189,6 +193,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order) char const* interface = R"([ { "name": "c", + "const": false, "inputs": [ { "name": "b", @@ -204,6 +209,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order) }, { "name": "f", + "const": false, "inputs": [ { "name": "a", @@ -222,6 +228,53 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order) checkInterface(sourceCode, interface); } +BOOST_AUTO_TEST_CASE(const_function) +{ + char const* sourceCode = "contract test {\n" + " function foo(uint a, uint b) returns(uint d) { return a + b; }\n" + " function boo(uint32 a) const returns(uint b) { return a * 4; }\n" + "}\n"; + + char const* interface = R"([ + { + "name": "boo", + "const": true, + "inputs": [{ + "name": "a", + "type": "uint32" + }], + "outputs": [ + { + "name": "b", + "type": "uint256" + } + ] + }, + { + "name": "foo", + "const": false, + "inputs": [ + { + "name": "a", + "type": "uint256" + }, + { + "name": "b", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "d", + "type": "uint256" + } + ] + } + ])"; + + checkInterface(sourceCode, interface); +} + BOOST_AUTO_TEST_SUITE_END() } From e80dffeec5fb54e80e4c0ee3c90be4843db0c101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 19 Dec 2014 12:32:36 +0100 Subject: [PATCH 374/396] Clean up and remove some explicit dependencies in cmake files --- alethzero/CMakeLists.txt | 3 --- evmjit | 2 +- libethereum/CMakeLists.txt | 3 --- libevm/CMakeLists.txt | 3 +++ test/CMakeLists.txt | 3 --- 5 files changed, 4 insertions(+), 10 deletions(-) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 4e4e4a93c..39c02d6be 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -46,9 +46,6 @@ target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} jsqrc) -if (EVMJIT) - target_link_libraries(${EXECUTEABLE} evmjit) -endif() # eth_install_executable is defined in cmake/EthExecutableHelper.cmake eth_install_executable(${EXECUTABLE}) diff --git a/evmjit b/evmjit index 8287c6040..232f9fee5 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 8287c6040a4900cb8b091ffbe284c7f478c60c49 +Subproject commit 232f9fee527e454f4008c2c03a9c7dac1c5c85ff diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index e00637dad..3906074fd 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -34,9 +34,6 @@ target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} secp256k1) -if (EVMJIT) - target_link_libraries(${EXECUTABLE} evmjit-cpp) -endif() install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libevm/CMakeLists.txt b/libevm/CMakeLists.txt index 96b8f9ade..4af5eb175 100644 --- a/libevm/CMakeLists.txt +++ b/libevm/CMakeLists.txt @@ -30,6 +30,9 @@ target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) +if (EVMJIT) + target_link_libraries(${EXECUTABLE} evmjit-cpp) +endif() install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 441200fe4..7cedc117b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,9 +25,6 @@ if (JSONRPC) target_link_libraries(testeth web3jsonrpc) target_link_libraries(testeth ${JSON_RPC_CPP_CLIENT_LIBRARIES}) endif() -if (EVMJIT) - target_link_libraries(testeth evmjit-cpp) -endif() target_link_libraries(createRandomTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) target_link_libraries(createRandomTest ethereum) From 6be33f7d8f6dc99b4d32c6538d183ce1af89a8da Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Dec 2014 13:45:12 +0100 Subject: [PATCH 375/396] Revert to 49. --- libethcore/CommonEth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index ff5e6aed0..5e510572e 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -32,7 +32,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 50; +const unsigned c_protocolVersion = 49; const unsigned c_databaseVersion = 5; static const vector> g_units = From 44e55fb928f8ab45b593194d57e4fa81e695b949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 19 Dec 2014 14:22:29 +0100 Subject: [PATCH 376/396] Remove old handcrafted Visual Studio project files --- windows/LLVM.props | 44 ------- windows/LibEvmJit.vcxproj | 174 ------------------------- windows/LibEvmJit.vcxproj.filters | 44 ------- windows/LibEvmJitCpp.vcxproj | 143 -------------------- windows/LibEvmJitCpp.vcxproj.filters | 13 -- windows/evmcc.vcxproj | 187 --------------------------- windows/evmcc.vcxproj.filters | 9 -- 7 files changed, 614 deletions(-) delete mode 100644 windows/LLVM.props delete mode 100644 windows/LibEvmJit.vcxproj delete mode 100644 windows/LibEvmJit.vcxproj.filters delete mode 100644 windows/LibEvmJitCpp.vcxproj delete mode 100644 windows/LibEvmJitCpp.vcxproj.filters delete mode 100644 windows/evmcc.vcxproj delete mode 100644 windows/evmcc.vcxproj.filters diff --git a/windows/LLVM.props b/windows/LLVM.props deleted file mode 100644 index a1537ac7e..000000000 --- a/windows/LLVM.props +++ /dev/null @@ -1,44 +0,0 @@ - - - - - 0 - ../../llvm - ../../_build/llvm/$(Platform) - $(LLVMSrcDir)\include;$(LLVMBuildDir)\include - $(LLVMBuildDir)\$(Configuration)\lib - LLVMX86Disassembler.lib;LLVMX86AsmParser.lib;LLVMX86CodeGen.lib;LLVMSelectionDAG.lib;LLVMAsmPrinter.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86AsmPrinter.lib;LLVMX86Utils.lib;LLVMMCJIT.lib;LLVMTarget.lib;LLVMRuntimeDyld.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMBitWriter.lib;LLVMExecutionEngine.lib;LLVMMC.lib;LLVMCore.lib;LLVMSupport.lib - - - - - $(LLVMIncludeDir);%(AdditionalIncludeDirectories) - 4800;%(DisableSpecificWarnings) - ETH_EVMJIT=$(LLVMEnabled);%(PreprocessorDefinitions) - - - $(LLVMLibDir);%(AdditionalLibraryDirectories) - $(LLVMLibs);%(AdditionalDependencies) - - - - - $(LLVMEnabled) - - - $(LLVMSrcDir) - - - $(LLVMBuildDir) - - - $(LLVMIncludeDir) - - - $(LLVMLibDir) - - - $(LLVMLibs) - - - \ No newline at end of file diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj deleted file mode 100644 index c3b1f65a7..000000000 --- a/windows/LibEvmJit.vcxproj +++ /dev/null @@ -1,174 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {9C816740-5C11-4377-A3A7-46BE12F35FA0} - LibEvmJit - - - - StaticLibrary - true - v120 - - - StaticLibrary - true - v120 - - - StaticLibrary - false - v120 - true - - - StaticLibrary - false - v120 - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Level3 - Disabled - true - - - true - - - - - Level3 - Disabled - true - - - true - - - - - Level3 - MaxSpeed - true - true - true - - - true - true - true - - - - - Level3 - MaxSpeed - true - true - true - - - true - true - true - - - - - {826e68cb-d3ee-4a8a-b540-59a8c3f38d4f} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters deleted file mode 100644 index 88dc8d329..000000000 --- a/windows/LibEvmJit.vcxproj.filters +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/windows/LibEvmJitCpp.vcxproj b/windows/LibEvmJitCpp.vcxproj deleted file mode 100644 index d72bcd981..000000000 --- a/windows/LibEvmJitCpp.vcxproj +++ /dev/null @@ -1,143 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {A5D8764C-FD17-4364-AFCF-5BAF78777569} - LibEvmJitCpp - - - - StaticLibrary - true - v120 - - - StaticLibrary - true - v120 - - - StaticLibrary - false - v120 - true - - - StaticLibrary - false - v120 - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Level3 - Disabled - true - - - true - - - - - Level3 - Disabled - true - - - true - - - - - Level3 - MaxSpeed - true - true - true - - - true - true - true - - - - - Level3 - MaxSpeed - true - true - true - - - true - true - true - - - - - - - - - - - - - - - {9c816740-5c11-4377-a3a7-46be12f35fa0} - - - - - - \ No newline at end of file diff --git a/windows/LibEvmJitCpp.vcxproj.filters b/windows/LibEvmJitCpp.vcxproj.filters deleted file mode 100644 index 4bf360cbe..000000000 --- a/windows/LibEvmJitCpp.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/windows/evmcc.vcxproj b/windows/evmcc.vcxproj deleted file mode 100644 index 6cd0ece89..000000000 --- a/windows/evmcc.vcxproj +++ /dev/null @@ -1,187 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - - {a5d8764c-fd17-4364-afcf-5baf78777569} - - - - - - - - - - {D51A4898-BD9E-4961-BCAE-1FE7F854BB4D} - Win32Proj - evmcc - - - - Application - true - v120 - Unicode - - - Application - true - v120 - - - Application - false - v120 - true - Unicode - - - Application - false - v120 - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ - ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ - false - - - true - false - - - false - ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ - ..\..\_build\$(ProjectName)\$(Platform)_$(Configuration)\ - false - - - false - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - true - ../../llvm-3.5.0/include;../../builds/llvm3.5/include;%(AdditionalIncludeDirectories) - false - false - - - Console - true - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - true - ../../llvm-3.5.0/include;../../builds/llvm3.5/include;%(AdditionalIncludeDirectories) - 4068;4244;4267;4800 - false - false - - - Console - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - true - false - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - true - 4068;4244;4267;4800 - false - - - Console - true - true - true - - - - - - \ No newline at end of file diff --git a/windows/evmcc.vcxproj.filters b/windows/evmcc.vcxproj.filters deleted file mode 100644 index f70c861ba..000000000 --- a/windows/evmcc.vcxproj.filters +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file From acec80d8f1cc27f4b86e970b03b3dd425097cbc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 19 Dec 2014 14:38:03 +0100 Subject: [PATCH 377/396] Remove unnecessary changes --- libethereum/State.h | 1 - libevm/VM.h | 2 +- test/vm.cpp | 40 ++++++++++++++++++++-------------------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/libethereum/State.h b/libethereum/State.h index bea299e6c..763a67451 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -32,7 +32,6 @@ #include #include #include -#include #include "TransactionQueue.h" #include "Account.h" #include "Transaction.h" diff --git a/libevm/VM.h b/libevm/VM.h index 306b1ce63..1f3fc17d5 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -478,7 +478,7 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st break; case Instruction::SIGNEXTEND: if (m_stack.back() < 31) - { + { unsigned const testBit(m_stack.back() * 8 + 7); u256& number = m_stack[m_stack.size() - 2]; u256 mask = ((u256(1) << testBit) - 1); diff --git a/test/vm.cpp b/test/vm.cpp index 5b53bc371..920f0582c 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -422,29 +422,29 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) test.importCallCreates(o["callcreates"].get_array()); test.sub.logs = importLog(o["logs"].get_array()); - checkOutput(output, o); + checkOutput(output, o); - BOOST_CHECK_EQUAL(toInt(o["gas"]), gas); - - auto& expectedAddrs = test.addresses; - auto& resultAddrs = fev.addresses; - for (auto&& expectedPair : expectedAddrs) - { - auto& expectedAddr = expectedPair.first; - auto resultAddrIt = resultAddrs.find(expectedAddr); - if (resultAddrIt == resultAddrs.end()) - BOOST_ERROR("Missing expected address " << expectedAddr); - else - { - auto& expectedState = expectedPair.second; - auto& resultState = resultAddrIt->second; - BOOST_CHECK_MESSAGE(std::get<0>(expectedState) == std::get<0>(resultState), expectedAddr << ": incorrect balance " << std::get<0>(resultState) << ", expected " << std::get<0>(expectedState)); - BOOST_CHECK_MESSAGE(std::get<1>(expectedState) == std::get<1>(resultState), expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState)); - BOOST_CHECK_MESSAGE(std::get<3>(expectedState) == std::get<3>(resultState), expectedAddr << ": incorrect code"); + BOOST_CHECK_EQUAL(toInt(o["gas"]), gas); - checkStorage(std::get<2>(expectedState), std::get<2>(resultState), expectedAddr); + auto& expectedAddrs = test.addresses; + auto& resultAddrs = fev.addresses; + for (auto&& expectedPair : expectedAddrs) + { + auto& expectedAddr = expectedPair.first; + auto resultAddrIt = resultAddrs.find(expectedAddr); + if (resultAddrIt == resultAddrs.end()) + BOOST_ERROR("Missing expected address " << expectedAddr); + else + { + auto& expectedState = expectedPair.second; + auto& resultState = resultAddrIt->second; + BOOST_CHECK_MESSAGE(std::get<0>(expectedState) == std::get<0>(resultState), expectedAddr << ": incorrect balance " << std::get<0>(resultState) << ", expected " << std::get<0>(expectedState)); + BOOST_CHECK_MESSAGE(std::get<1>(expectedState) == std::get<1>(resultState), expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState)); + BOOST_CHECK_MESSAGE(std::get<3>(expectedState) == std::get<3>(resultState), expectedAddr << ": incorrect code"); + + checkStorage(std::get<2>(expectedState), std::get<2>(resultState), expectedAddr); + } } - } checkAddresses, bytes> > >(test.addresses, fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); From 22535d527b46cc831acee3792b72c98ff53649b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 20 Dec 2014 10:41:16 +0100 Subject: [PATCH 378/396] Update evmjit submodule --- evmjit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit b/evmjit index 232f9fee5..ed63ced24 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 232f9fee527e454f4008c2c03a9c7dac1c5c85ff +Subproject commit ed63ced24456c28b6dba345b8fc61e680ed406d7 From d6aee23642688031479c9badb65c9c1b60b3e7cc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 20 Dec 2014 14:25:26 +0100 Subject: [PATCH 379/396] Blocktime targets 12s. --- libethcore/BlockInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 6c08bb346..1ad016fa3 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -190,7 +190,7 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const if (!parentHash) return c_genesisDifficulty; else - return timestamp >= _parent.timestamp + 5 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10)); + return timestamp >= _parent.timestamp + 8 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10)); } void BlockInfo::verifyParent(BlockInfo const& _parent) const From fe34eae4698c9b2f99bf70f141edc3ff0f162b50 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 20 Dec 2014 14:26:20 +0100 Subject: [PATCH 380/396] Versions bump. --- libdevcore/Common.cpp | 2 +- libethcore/CommonEth.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 1de7ef957..428c86d66 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.13"; +char const* Version = "0.8.0"; } diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 5e510572e..9862ee488 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -32,7 +32,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 49; +const unsigned c_protocolVersion = 51; const unsigned c_databaseVersion = 5; static const vector> g_units = From c15da67ba6cc5707f94c6e796eabd3d97ceb8491 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 20 Dec 2014 15:46:33 +0100 Subject: [PATCH 381/396] Documentation, repotting. --- libdevcore/Diff.h | 52 +++++++++++++++++++++++++++++++++++ libethereum/AccountDiff.cpp | 16 ++++++++--- libethereum/AccountDiff.h | 55 +++++++++++++++++++++---------------- 3 files changed, 96 insertions(+), 27 deletions(-) create mode 100644 libdevcore/Diff.h diff --git a/libdevcore/Diff.h b/libdevcore/Diff.h new file mode 100644 index 000000000..fa5f6be2d --- /dev/null +++ b/libdevcore/Diff.h @@ -0,0 +1,52 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Diff.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +namespace dev +{ + +enum class ExistDiff +{ + Same, + New, + Dead +}; + +template +class Diff +{ +public: + Diff() {} + Diff(T _from, T _to): m_from(_from), m_to(_to) {} + + T const& from() const { return m_from; } + T const& to() const { return m_to; } + + explicit operator bool() const { return m_from != m_to; } + +private: + T m_from; + T m_to; +}; + +} + diff --git a/libethereum/AccountDiff.cpp b/libethereum/AccountDiff.cpp index c434086fa..ae82e18d9 100644 --- a/libethereum/AccountDiff.cpp +++ b/libethereum/AccountDiff.cpp @@ -33,11 +33,19 @@ AccountChange AccountDiff::changeType() const return exist ? exist.from() ? AccountChange::Deletion : AccountChange::Creation : (bn && sc) ? AccountChange::All : bn ? AccountChange::Intrinsic: sc ? AccountChange::CodeStorage : AccountChange::None; } -char const* AccountDiff::lead() const +char const* dev::lead(AccountChange _c) const { - bool bn = (balance || nonce); - bool sc = (!storage.empty() || code); - return exist ? exist.from() ? "XXX" : "+++" : (bn && sc) ? "***" : bn ? " * " : sc ? "* *" : " "; + switch (_c) + { + case AccountChange::None: return " "; + case AccountChange::Creation: return "+++"; + case AccountChange::Deletion: return "XXX"; + case AccountChange::Intrinsic: return " * "; + case AccountChange::CodeStorage: return "* *"; + case AccountChange::All: return "***"; + } + assert(false); + return ""; } namespace dev { diff --git a/libethereum/AccountDiff.h b/libethereum/AccountDiff.h index d4c30ead5..0c0ede4ae 100644 --- a/libethereum/AccountDiff.h +++ b/libethereum/AccountDiff.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include namespace dev @@ -29,47 +30,55 @@ namespace dev namespace eth { -enum class ExistDiff { Same, New, Dead }; -template -class Diff +/// Type of change that an account can have from state to state. +enum class AccountChange { -public: - Diff() {} - Diff(T _from, T _to): m_from(_from), m_to(_to) {} - - T const& from() const { return m_from; } - T const& to() const { return m_to; } - - explicit operator bool() const { return m_from != m_to; } - -private: - T m_from; - T m_to; + None, ///< Nothing changed at all. + Creation, ///< Account came into existance. + Deletion, ///< Account was deleted. + Intrinsic, ///< Account was already in existance and some internal aspect of the account altered such as balance, nonce or storage. + CodeStorage, ///< Account was already in existance and the code of the account changed. + All ///< Account was already in existance and all aspects of the account changed. }; -enum class AccountChange { None, Creation, Deletion, Intrinsic, CodeStorage, All }; +/// @returns a three-character code that expresses the type of change. +char const* lead(AccountChange _c); +/** + * @brief Stores the difference between two accounts (typically the same account at two times). + * + * In order to determine what about an account has altered, this struct can be used to specify + * alterations. Use changed() and changeType() to determine what, if anything, is different. + * + * Five members are accessible: to determine the nature of the changes. + */ struct AccountDiff { + /// @returns true if the account has changed at all. inline bool changed() const { return storage.size() || code || nonce || balance || exist; } - char const* lead() const; + /// @returns a three-character code that expresses the change. AccountChange changeType() const; - Diff exist; - Diff balance; - Diff nonce; - std::map> storage; - Diff code; + Diff exist; ///< The account's existance; was it created/deleted or not? + Diff balance; ///< The account's balance; did it alter? + Diff nonce; ///< The account's nonce; did it alter? + std::map> storage; ///< The account's storage addresses; each has its own Diff. + Diff code; ///< The account's code; in general this should only have changed if exist also changed. }; +/** + * @brief Stores the difference between two states; this is just their encumbent accounts. + */ struct StateDiff { - std::map accounts; + std::map accounts; ///< The state's account changes; each has its own AccountDiff. }; } +/// Simple stream output for the StateDiff. std::ostream& operator<<(std::ostream& _out, dev::eth::StateDiff const& _s); +/// Simple stream output for the AccountDiff. std::ostream& operator<<(std::ostream& _out, dev::eth::AccountDiff const& _s); } From 176b682ce12fb42fe47ccf29796da3f18bfab054 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 20 Dec 2014 16:28:28 +0100 Subject: [PATCH 382/396] Use new lead() API. --- libethereum/AccountDiff.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/AccountDiff.cpp b/libethereum/AccountDiff.cpp index ae82e18d9..efef0c05e 100644 --- a/libethereum/AccountDiff.cpp +++ b/libethereum/AccountDiff.cpp @@ -85,7 +85,7 @@ std::ostream& operator<<(std::ostream& _out, dev::eth::StateDiff const& _s) dev::eth::AccountDiff d; _out << d; for (auto const& i: _s.accounts) - _out << i.second.lead() << " " << i.first << ": " << i.second << endl; + _out << lead(i.second.changeType()) << " " << i.first << ": " << i.second << endl; return _out; } From 0119bfca43e06d0a1b7ac29c75e1281564eec20b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 20 Dec 2014 16:44:57 +0100 Subject: [PATCH 383/396] Kill unneeded rubbish. Add docs. --- boost/process.hpp | 50 - boost/process/child.hpp | 200 --- boost/process/config.hpp | 41 - boost/process/context.hpp | 209 --- boost/process/detail/file_handle.hpp | 406 ----- boost/process/detail/pipe.hpp | 187 -- boost/process/detail/posix_ops.hpp | 495 ------ boost/process/detail/stream_info.hpp | 176 -- boost/process/detail/systembuf.hpp | 231 --- boost/process/detail/win32_ops.hpp | 355 ---- boost/process/environment.hpp | 50 - boost/process/operations.hpp | 583 ------- boost/process/pistream.hpp | 116 -- boost/process/posix_child.hpp | 178 -- boost/process/posix_context.hpp | 118 -- boost/process/posix_operations.hpp | 81 - boost/process/posix_status.hpp | 128 -- boost/process/postream.hpp | 117 -- boost/process/process.hpp | 130 -- boost/process/self.hpp | 134 -- boost/process/status.hpp | 105 -- boost/process/stream_behavior.hpp | 234 --- boost/process/win32_child.hpp | 128 -- boost/process/win32_context.hpp | 61 - boost/process/win32_operations.hpp | 77 - doc/Doxyfile | 2364 ++++++++++++++++++++++++++ libethereum/AccountDiff.cpp | 2 +- 27 files changed, 2365 insertions(+), 4591 deletions(-) delete mode 100644 boost/process.hpp delete mode 100644 boost/process/child.hpp delete mode 100644 boost/process/config.hpp delete mode 100644 boost/process/context.hpp delete mode 100644 boost/process/detail/file_handle.hpp delete mode 100644 boost/process/detail/pipe.hpp delete mode 100644 boost/process/detail/posix_ops.hpp delete mode 100644 boost/process/detail/stream_info.hpp delete mode 100644 boost/process/detail/systembuf.hpp delete mode 100644 boost/process/detail/win32_ops.hpp delete mode 100644 boost/process/environment.hpp delete mode 100644 boost/process/operations.hpp delete mode 100644 boost/process/pistream.hpp delete mode 100644 boost/process/posix_child.hpp delete mode 100644 boost/process/posix_context.hpp delete mode 100644 boost/process/posix_operations.hpp delete mode 100644 boost/process/posix_status.hpp delete mode 100644 boost/process/postream.hpp delete mode 100644 boost/process/process.hpp delete mode 100644 boost/process/self.hpp delete mode 100644 boost/process/status.hpp delete mode 100644 boost/process/stream_behavior.hpp delete mode 100644 boost/process/win32_child.hpp delete mode 100644 boost/process/win32_context.hpp delete mode 100644 boost/process/win32_operations.hpp create mode 100644 doc/Doxyfile diff --git a/boost/process.hpp b/boost/process.hpp deleted file mode 100644 index 60511ef57..000000000 --- a/boost/process.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process.hpp - * - * Convenience header that includes all other Boost.Process public header - * files. It is important to note that those headers that are specific to - * a given platform are only included if the library is being used in that - * same platform. - */ - -#ifndef BOOST_PROCESS_HPP -#define BOOST_PROCESS_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -# include -# include -# include -#elif defined(BOOST_WINDOWS_API) -# include -# include -# include -#else -# error "Unsupported platform." -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif diff --git a/boost/process/child.hpp b/boost/process/child.hpp deleted file mode 100644 index 1419b7ea7..000000000 --- a/boost/process/child.hpp +++ /dev/null @@ -1,200 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/child.hpp - * - * Includes the declaration of the child class. - */ - -#ifndef BOOST_PROCESS_CHILD_HPP -#define BOOST_PROCESS_CHILD_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -# include -# include -#elif defined(BOOST_WINDOWS_API) -# include -#else -# error "Unsupported platform." -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Generic implementation of the Child concept. - * - * The child class implements the Child concept in an operating system - * agnostic way. - */ -class child : public process -{ -public: - /** - * Gets a reference to the child's standard input stream. - * - * Returns a reference to a postream object that represents the - * standard input communication channel with the child process. - */ - postream &get_stdin() const - { - BOOST_ASSERT(stdin_); - - return *stdin_; - } - - /** - * Gets a reference to the child's standard output stream. - * - * Returns a reference to a pistream object that represents the - * standard output communication channel with the child process. - */ - pistream &get_stdout() const - { - BOOST_ASSERT(stdout_); - - return *stdout_; - } - - /** - * Gets a reference to the child's standard error stream. - * - * Returns a reference to a pistream object that represents the - * standard error communication channel with the child process. - */ - pistream &get_stderr() const - { - BOOST_ASSERT(stderr_); - - return *stderr_; - } - - /** - * Blocks and waits for the child process to terminate. - * - * Returns a status object that represents the child process' - * finalization condition. The child process object ceases to be - * valid after this call. - * - * \remark Blocking remarks: This call blocks if the child - * process has not finalized execution and waits until - * it terminates. - */ - status wait() - { -#if defined(BOOST_POSIX_API) - int s; - if (::waitpid(get_id(), &s, 0) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::child::wait: waitpid(2) failed")); - return status(s); -#elif defined(BOOST_WINDOWS_API) - ::WaitForSingleObject(process_handle_.get(), INFINITE); - DWORD code; - if (!::GetExitCodeProcess(process_handle_.get(), &code)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::child::wait: GetExitCodeProcess failed")); - return status(code); -#endif - } - - /** - * Creates a new child object that represents the just spawned child - * process \a id. - * - * The \a fhstdin, \a fhstdout and \a fhstderr file handles represent - * the parent's handles used to communicate with the corresponding - * data streams. They needn't be valid but their availability must - * match the redirections configured by the launcher that spawned this - * process. - * - * The \a fhprocess handle represents a handle to the child process. - * It is only used on Windows as the implementation of wait() needs a - * process handle. - */ - child(id_type id, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr, detail::file_handle fhprocess = detail::file_handle()) - : process(id) -#if defined(BOOST_WINDOWS_API) - , process_handle_(fhprocess.release(), ::CloseHandle) -#endif - { - if (fhstdin.valid()) - stdin_.reset(new postream(fhstdin)); - if (fhstdout.valid()) - stdout_.reset(new pistream(fhstdout)); - if (fhstderr.valid()) - stderr_.reset(new pistream(fhstderr)); - } - -private: - /** - * The standard input stream attached to the child process. - * - * This postream object holds the communication channel with the - * child's process standard input. It is stored in a pointer because - * this field is only valid when the user requested to redirect this - * data stream. - */ - boost::shared_ptr stdin_; - - /** - * The standard output stream attached to the child process. - * - * This postream object holds the communication channel with the - * child's process standard output. It is stored in a pointer because - * this field is only valid when the user requested to redirect this - * data stream. - */ - boost::shared_ptr stdout_; - - /** - * The standard error stream attached to the child process. - * - * This postream object holds the communication channel with the - * child's process standard error. It is stored in a pointer because - * this field is only valid when the user requested to redirect this - * data stream. - */ - boost::shared_ptr stderr_; - -#if defined(BOOST_WINDOWS_API) - /** - * Process handle owned by RAII object. - */ - boost::shared_ptr process_handle_; -#endif -}; - -/** - * Collection of child objects. - * - * This convenience type represents a collection of child objects backed - * by a vector. - */ -typedef std::vector children; - -} -} - -#endif diff --git a/boost/process/config.hpp b/boost/process/config.hpp deleted file mode 100644 index f240f86b5..000000000 --- a/boost/process/config.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/config.hpp - * - * Defines macros that are used by the library's code to determine the - * operating system it is running under and the features it supports. - */ - -#ifndef BOOST_PROCESS_CONFIG_HPP -#define BOOST_PROCESS_CONFIG_HPP - -#include -#include - -#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) -# if !defined(BOOST_PROCESS_POSIX_PATH_MAX) -/** - * The macro BOOST_PROCESS_POSIX_PATH_MAX is set to a positive integer - * value which specifies the system's maximal supported path length. - * By default it is set to 259. You should set the macro to PATH_MAX - * which should be defined in limits.h provided by your operating system - * if you experience problems when instantiating a context. The - * constructor of basic_work_directory_context tries to find out - * dynamically the maximal supported path length but uses - * BOOST_PROCESS_POSIX_PATH_MAX if it fails. - */ -# define BOOST_PROCESS_POSIX_PATH_MAX 259 -# endif -#endif - -#endif diff --git a/boost/process/context.hpp b/boost/process/context.hpp deleted file mode 100644 index 51acd35bc..000000000 --- a/boost/process/context.hpp +++ /dev/null @@ -1,209 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/context.hpp - * - * Includes the declaration of the context class and several accessory - * base classes. - */ - -#ifndef BOOST_PROCESS_CONTEXT_HPP -#define BOOST_PROCESS_CONTEXT_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -# include -# include -#elif defined(BOOST_WINDOWS_API) -# include -#else -# error "Unsupported platform." -#endif - -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Base context class that defines the child's work directory. - * - * Base context class that defines the necessary fields to configure a - * child's work directory. This class is useless on its own because no - * function in the library will accept it as a valid Context - * implementation. - */ -template -class basic_work_directory_context -{ -public: - /** - * Constructs a new work directory context. - * - * Constructs a new work directory context making the work directory - * described by the new object point to the caller's current working - * directory. - */ - basic_work_directory_context() - { -#if defined(BOOST_POSIX_API) - errno = 0; - long size = ::pathconf(".", _PC_PATH_MAX); - if (size == -1 && errno) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: pathconf(2) failed")); - else if (size == -1) - size = BOOST_PROCESS_POSIX_PATH_MAX; - boost::scoped_array cwd(new char[size]); - if (!::getcwd(cwd.get(), size)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: getcwd(2) failed")); - work_directory = cwd.get(); -#elif defined(BOOST_WINDOWS_API) - char cwd[MAX_PATH]; - if (!::GetCurrentDirectoryA(sizeof(cwd), cwd)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: GetCurrentDirectory failed")); - work_directory = cwd; -#endif - BOOST_ASSERT(!work_directory.empty()); - } - - /** - * The process' initial work directory. - * - * The work directory is the directory in which the process starts - * execution. - */ - Path work_directory; -}; - -/** - * Base context class that defines the child's environment. - * - * Base context class that defines the necessary fields to configure a - * child's environment variables. This class is useless on its own - * because no function in the library will accept it as a valid Context - * implementation. - */ -class environment_context -{ -public: - /** - * The process' environment. - * - * Contains the list of environment variables, alongside with their - * values, that will be passed to the spawned child process. - */ - boost::process::environment environment; -}; - -/** - * Process startup execution context. - * - * The context class groups all the parameters needed to configure a - * process' environment during its creation. - */ -template -class basic_context : public basic_work_directory_context, public environment_context -{ -public: - /** - * Child's stdin behavior. - */ - stream_behavior stdin_behavior; - - /** - * Child's stdout behavior. - */ - stream_behavior stdout_behavior; - - /** - * Child's stderr behavior. - */ - stream_behavior stderr_behavior; -}; - -typedef basic_context context; - -/** - * Represents a child process in a pipeline. - * - * This convenience class is a triplet that holds all the data required - * to spawn a new child process in a pipeline. - */ -template -class basic_pipeline_entry -{ -public: - /** - * The executable to launch. - */ - Executable executable; - - /** - * The set of arguments to pass to the executable. - */ - Arguments arguments; - - /** - * The child's execution context. - */ - Context context; - - /** - * The type of the Executable concept used in this template - * instantiation. - */ - typedef Executable executable_type; - - /** - * The type of the Arguments concept used in this template - * instantiation. - */ - typedef Arguments arguments_type; - - /** - * The type of the Context concept used in this template - * instantiation. - */ - typedef Context context_type; - - /** - * Constructs a new pipeline_entry object. - * - * Given the executable, set of arguments and execution triplet, - * constructs a new pipeline_entry object that holds the three - * values. - */ - basic_pipeline_entry(const Executable &exe, const Arguments &args, const Context &ctx) - : executable(exe), - arguments(args), - context(ctx) - { - } -}; - -/** - * Default instantiation of basic_pipeline_entry. - */ -typedef basic_pipeline_entry, context> pipeline_entry; - -} -} - -#endif diff --git a/boost/process/detail/file_handle.hpp b/boost/process/detail/file_handle.hpp deleted file mode 100644 index 33f21d9b6..000000000 --- a/boost/process/detail/file_handle.hpp +++ /dev/null @@ -1,406 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/detail/file_handle.hpp - * - * Includes the declaration of the file_handle class. This file is for - * internal usage only and must not be included by the library user. - */ - -#ifndef BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP -#define BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -# include -#elif defined(BOOST_WINDOWS_API) -# include -#else -# error "Unsupported platform." -#endif - -#include -#include -#include - -namespace boost { -namespace process { -namespace detail { - -/** - * Simple RAII model for system file handles. - * - * The \a file_handle class is a simple RAII model for native system file - * handles. This class wraps one of such handles grabbing its ownership, - * and automaticaly closes it upon destruction. It is basically used - * inside the library to avoid leaking open file handles, shall an - * unexpected execution trace occur. - * - * A \a file_handle object can be copied but doing so invalidates the - * source object. There can only be a single valid \a file_handle object - * for a given system file handle. This is similar to std::auto_ptr's - * semantics. - * - * This class also provides some convenience methods to issue special file - * operations under their respective platforms. - */ -class file_handle -{ -public: -#if defined(BOOST_PROCESS_DOXYGEN) - /** - * Opaque name for the native handle type. - * - * Each operating system identifies file handles using a specific type. - * The \a handle_type type is used to transparently refer to file - * handles regarless of the operating system in which this class is - * used. - * - * If this class is used on a POSIX system, \a NativeSystemHandle is - * an integer type while it is a \a HANDLE on a Windows system. - */ - typedef NativeSystemHandle handle_type; -#elif defined(BOOST_POSIX_API) - typedef int handle_type; -#elif defined(BOOST_WINDOWS_API) - typedef HANDLE handle_type; -#endif - - /** - * Constructs an invalid file handle. - * - * This constructor creates a new \a file_handle object that represents - * an invalid file handle. An invalid file handle can be copied but - * cannot be manipulated in any way (except checking for its validity). - * - * \see valid() - */ - file_handle() - : handle_(invalid_value()) - { - } - - /** - * Constructs a new file handle from a native file handle. - * - * This constructor creates a new \a file_handle object that takes - * ownership of the given \a h native file handle. The user must not - * close \a h on his own during the lifetime of the new object. - * Ownership can be reclaimed using release(). - * - * \pre The native file handle must be valid; a close operation must - * succeed on it. - * \see release() - */ - file_handle(handle_type h) - : handle_(h) - { - BOOST_ASSERT(handle_ != invalid_value()); - } - - /** - * Copy constructor; invalidates the source handle. - * - * This copy constructor creates a new file handle from a given one. - * Ownership of the native file handle is transferred to the new - * object, effectively invalidating the source file handle. This - * avoids having two live \a file_handle objects referring to the - * same native file handle. The source file handle needs not be - * valid in the name of simplicity. - * - * \post The source file handle is invalid. - * \post The new file handle owns the source's native file handle. - */ - file_handle(const file_handle &fh) - : handle_(fh.handle_) - { - fh.handle_ = invalid_value(); - } - - /** - * Releases resources if the handle is valid. - * - * If the file handle is valid, the destructor closes it. - * - * \see valid() - */ - ~file_handle() - { - if (valid()) - close(); - } - - /** - * Assignment operator; invalidates the source handle. - * - * This assignment operator transfers ownership of the RHS file - * handle to the LHS one, effectively invalidating the source file - * handle. This avoids having two live \a file_handle objects - * referring to the same native file handle. The source file - * handle needs not be valid in the name of simplicity. - * - * \post The RHS file handle is invalid. - * \post The LHS file handle owns RHS' native file handle. - * \return A reference to the LHS file handle. - */ - file_handle &operator=(const file_handle &fh) - { - handle_ = fh.handle_; - fh.handle_ = invalid_value(); - return *this; - } - - /** - * Checks whether the file handle is valid or not. - * - * Returns a boolean indicating whether the file handle is valid or - * not. If the file handle is invalid, no other methods can be - * executed other than the destructor. - * - * \return true if the file handle is valid; false otherwise. - */ - bool valid() const - { - return handle_ != invalid_value(); - } - - /** - * Closes the file handle. - * - * Explicitly closes the file handle, which must be valid. Upon - * exit, the handle is not valid any more. - * - * \pre The file handle is valid. - * \post The file handle is invalid. - * \post The native file handle is closed. - */ - void close() - { - BOOST_ASSERT(valid()); - -#if defined(BOOST_POSIX_API) - ::close(handle_); -#elif defined(BOOST_WINDOWS_API) - ::CloseHandle(handle_); -#endif - - handle_ = invalid_value(); - } - - /** - * Reclaims ownership of the native file handle. - * - * Explicitly reclaims ownership of the native file handle contained - * in the \a file_handle object, returning the native file handle. - * The caller is responsible of closing it later on. - * - * \pre The file handle is valid. - * \post The file handle is invalid. - * \return The native file handle. - */ - handle_type release() - { - BOOST_ASSERT(valid()); - - handle_type h = handle_; - handle_ = invalid_value(); - return h; - } - - /** - * Gets the native file handle. - * - * Returns the native file handle for the \a file_handle object. - * The caller can issue any operation on it except closing it. - * If closing is required, release() shall be used. - * - * \pre The file handle is valid. - * \post The file handle is valid. - * \return The native file handle. - */ - handle_type get() const - { - BOOST_ASSERT(valid()); - - return handle_; - } - -#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) - /** - * Changes the native file handle to the given one. - * - * Given a new native file handle \a h, this operation assigns this - * handle to the current object, closing its old native file handle. - * In other words, it first calls dup2() to remap the old handle to - * the new one and then closes the old handle. - * - * If \a h is open, it is automatically closed by dup2(). - * - * This operation is only available in POSIX systems. - * - * \pre The file handle is valid. - * \pre The native file handle \a h is valid; i.e., it must be - * closeable. - * \post The file handle's native file handle is \a h. - * \throw boost::system::system_error If the internal remapping - * operation fails. - */ - void posix_remap(handle_type h) - { - BOOST_ASSERT(valid()); - - if (::dup2(handle_, h) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: dup2(2) failed")); - - if (::close(handle_) == -1) - { - ::close(h); - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: close(2) failed")); - } - - handle_ = h; - } - - /** - * Duplicates an open native file handle. - * - * Given a native file handle \a h1, this routine duplicates it so - * that it ends up being identified by the native file handle \a h2 - * and returns a new \a file_handle owning \a h2. - * - * This operation is only available in POSIX systems. - * - * \pre The native file handle \a h1 is open. - * \pre The native file handle \a h2 is valid (non-negative). - * \post The native file handle \a h1 is closed. - * \post The native file handle \a h2 is the same as the old \a h1 - * from the operating system's point of view. - * \return A new \a file_handle object that owns \a h2. - * \throw boost::system::system_error If dup2() fails. - */ - static file_handle posix_dup(int h1, int h2) - { - if (::dup2(h1, h2) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_dup: dup2(2) failed")); - - return file_handle(h2); - } -#endif - -#if defined(BOOST_WINDOWS_API) || defined(BOOST_PROCESS_DOXYGEN) - /** - * Duplicates the \a h native file handle. - * - * Given a native file handle \a h, this routine constructs a new - * \a file_handle object that owns a new duplicate of \a h. The - * duplicate's inheritable flag is set to the value of \a inheritable. - * - * This operation is only available in Windows systems. - * - * \pre The native file handle \a h is valid. - * \return A file handle owning a duplicate of \a h. - * \throw boost::system::system_error If DuplicateHandle() fails. - */ - static file_handle win32_dup(HANDLE h, bool inheritable) - { - HANDLE h2; - if (!::DuplicateHandle(::GetCurrentProcess(), h, ::GetCurrentProcess(), &h2, 0, inheritable ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_dup: DuplicateHandle failed")); - - return file_handle(h2); - } - - /** - * Creates a new duplicate of a standard file handle. - * - * Constructs a new \a file_handle object that owns a duplicate of a - * standard file handle. The \a d parameter specifies which standard - * file handle to duplicate and can be one of \a STD_INPUT_HANDLE, - * \a STD_OUTPUT_HANDLE or \a STD_ERROR_HANDLE. The duplicate's - * inheritable flag is set to the value of \a inheritable. - * - * This operation is only available in Windows systems. - * - * \pre \a d refers to one of the standard handles as described above. - * \return A file handle owning a duplicate of the standard handle - * referred to by \a d. - * \throw boost::system::system_error If GetStdHandle() or - * DuplicateHandle() fails. - */ - static file_handle win32_std(DWORD d, bool inheritable) - { - BOOST_ASSERT(d == STD_INPUT_HANDLE || d == STD_OUTPUT_HANDLE || d == STD_ERROR_HANDLE); - - HANDLE h = ::GetStdHandle(d); - if (h == INVALID_HANDLE_VALUE) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_std: GetStdHandle failed")); - - return win32_dup(h, inheritable); - } - - /** - * Changes the file handle's inheritable flag. - * - * Changes the file handle's inheritable flag to \a i. It is not - * necessary for the file handle's flag to be different than \a i. - * - * This operation is only available in Windows systems. - * - * \pre The file handle is valid. - * \post The native file handle's inheritable flag is set to \a i. - * \throw boost::system::system_error If the property change fails. - */ - void win32_set_inheritable(bool i) - { - BOOST_ASSERT(valid()); - - if (!::SetHandleInformation(handle_, HANDLE_FLAG_INHERIT, i ? HANDLE_FLAG_INHERIT : 0)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_set_inheritable: SetHandleInformation failed")); - } -#endif - -private: - /** - * Internal handle value. - * - * This variable holds the native handle value for the file handle - * hold by this object. It is interesting to note that this needs - * to be mutable because the copy constructor and the assignment - * operator invalidate the source object. - */ - mutable handle_type handle_; - - /** - * Constant function representing an invalid handle value. - * - * Returns the platform-specific handle value that represents an - * invalid handle. This is a constant function rather than a regular - * constant because, in the latter case, we cannot define it under - * Windows due to the value being of a complex type. - */ - static handle_type invalid_value() - { -#if defined(BOOST_POSIX_API) - return -1; -#elif defined(BOOST_WINDOWS_API) - return INVALID_HANDLE_VALUE; -#endif - } -}; - -} -} -} - -#endif diff --git a/boost/process/detail/pipe.hpp b/boost/process/detail/pipe.hpp deleted file mode 100644 index 3c839c228..000000000 --- a/boost/process/detail/pipe.hpp +++ /dev/null @@ -1,187 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/detail/pipe.hpp - * - * Includes the declaration of the pipe class. This file is for - * internal usage only and must not be included by the library user. - */ - -#ifndef BOOST_PROCESS_DETAIL_PIPE_HPP -#define BOOST_PROCESS_DETAIL_PIPE_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -# include -#elif defined(BOOST_WINDOWS_API) -# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE) -# include -# include -# endif -# include -#else -# error "Unsupported platform." -#endif - -#include -#include -#include - -namespace boost { -namespace process { -namespace detail { - -/** - * Simple RAII model for anonymous pipes. - * - * The pipe class is a simple RAII model for anonymous pipes. It - * provides a portable constructor that allocates a new %pipe and creates - * a pipe object that owns the two file handles associated to it: the - * read end and the write end. - * - * These handles can be retrieved for modification according to - * file_handle semantics. Optionally, their ownership can be transferred - * to external \a file_handle objects which comes handy when the two - * ends need to be used in different places (i.e. after a POSIX fork() - * system call). - * - * Pipes can be copied following the same semantics as file handles. - * In other words, copying a %pipe object invalidates the source one. - * - * \see file_handle - */ -class pipe -{ -public: - /** - * Creates a new %pipe. - * - * The default pipe constructor allocates a new anonymous %pipe - * and assigns its ownership to the created pipe object. On Windows - * when the macro BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE is defined - * a named pipe is created. This is required if asynchronous I/O - * should be used as asynchronous I/O is only supported by named - * pipes on Windows. - * - * \throw boost::system::system_error If the anonymous %pipe - * creation fails. - */ - pipe() - { - file_handle::handle_type hs[2]; - -#if defined(BOOST_POSIX_API) - if (::pipe(hs) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::pipe::pipe: pipe(2) failed")); -#elif defined(BOOST_WINDOWS_API) - SECURITY_ATTRIBUTES sa; - ZeroMemory(&sa, sizeof(sa)); - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = FALSE; - -# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE) - static unsigned int nextid = 0; - std::string pipe = "\\\\.\\pipe\\boost_process_" + boost::lexical_cast(::GetCurrentProcessId()) + "_" + boost::lexical_cast(nextid++); - hs[0] = ::CreateNamedPipeA(pipe.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa); - if (hs[0] == INVALID_HANDLE_VALUE) - boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateNamedPipe failed")); - hs[1] = ::CreateFileA(pipe.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - if (hs[1] == INVALID_HANDLE_VALUE) - boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateFile failed")); - - OVERLAPPED overlapped; - ZeroMemory(&overlapped, sizeof(overlapped)); - overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); - if (!overlapped.hEvent) - boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateEvent failed")); - BOOL b = ::ConnectNamedPipe(hs[0], &overlapped); - if (!b) - { - if (::GetLastError() == ERROR_IO_PENDING) - { - if (::WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_FAILED) - { - ::CloseHandle(overlapped.hEvent); - boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: WaitForSingleObject failed")); - } - } - else if (::GetLastError() != ERROR_PIPE_CONNECTED) - { - ::CloseHandle(overlapped.hEvent); - boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: ConnectNamedPipe failed")); - } - } - ::CloseHandle(overlapped.hEvent); -# else - if (!::CreatePipe(&hs[0], &hs[1], &sa, 0)) - boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreatePipe failed")); -# endif -#endif - - read_end_ = file_handle(hs[0]); - write_end_ = file_handle(hs[1]); - } - - /** - * Returns the %pipe's read end file handle. - * - * Obtains a reference to the %pipe's read end file handle. Care - * should be taken to not duplicate the returned object if ownership - * shall remain to the %pipe. - * - * Duplicating the returned object invalidates its corresponding file - * handle in the %pipe. - * - * \return A reference to the %pipe's read end file handle. - */ - file_handle &rend() - { - return read_end_; - } - - /** - * Returns the %pipe's write end file handle. - * - * Obtains a reference to the %pipe's write end file handle. Care - * should be taken to not duplicate the returned object if ownership - * shall remain to the %pipe. - * - * Duplicating the returned object invalidates its corresponding file - * handle in the %pipe. - * - * \return A reference to the %pipe's write end file handle. - */ - file_handle &wend() - { - return write_end_; - } - -private: - /** - * The %pipe's read end file handle. - */ - file_handle read_end_; - - /** - * The %pipe's write end file handle. - */ - file_handle write_end_; -}; - -} -} -} - -#endif diff --git a/boost/process/detail/posix_ops.hpp b/boost/process/detail/posix_ops.hpp deleted file mode 100644 index 8c39e0ebf..000000000 --- a/boost/process/detail/posix_ops.hpp +++ /dev/null @@ -1,495 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/detail/posix_ops.hpp - * - * Provides some convenience functions to start processes under POSIX - * operating systems. - */ - -#ifndef BOOST_PROCESS_DETAIL_POSIX_OPS_HPP -#define BOOST_PROCESS_DETAIL_POSIX_OPS_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace process { -namespace detail { - -/** - * Converts the command line to an array of C strings. - * - * Converts the command line's list of arguments to the format expected - * by the \a argv parameter in the POSIX execve() system call. - * - * This operation is only available on POSIX systems. - * - * \return The first argument of the pair is an integer that indicates - * how many strings are stored in the second argument. The - * second argument is a NULL-terminated, dynamically allocated - * array of dynamically allocated strings holding the arguments - * to the executable. The caller is responsible of freeing them. - */ -template -inline std::pair collection_to_posix_argv(const Arguments &args) -{ - std::size_t nargs = args.size(); - BOOST_ASSERT(nargs > 0); - - char **argv = new char*[nargs + 1]; - typename Arguments::size_type i = 0; - for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it) - { - argv[i] = new char[it->size() + 1]; - std::strncpy(argv[i], it->c_str(), it->size() + 1); - ++i; - } - argv[nargs] = 0; - - return std::pair(nargs, argv); -} - -/** - * Converts an environment to a char** table as used by execve(). - * - * Converts the environment's contents to the format used by the - * execve() system call. The returned char** array is allocated - * in dynamic memory; the caller must free it when not used any - * more. Each entry is also allocated in dynamic memory and is a - * NULL-terminated string of the form var=value; these must also be - * released by the caller. - * - * \return A dynamically allocated char** array that represents - * the environment's content. Each array entry is a - * NULL-terminated string of the form var=value. - */ -inline char **environment_to_envp(const environment &env) -{ - char **envp = new char*[env.size() + 1]; - - environment::size_type i = 0; - for (environment::const_iterator it = env.begin(); it != env.end(); ++it) - { - std::string s = it->first + "=" + it->second; - envp[i] = new char[s.size() + 1]; - std::strncpy(envp[i], s.c_str(), s.size() + 1); - ++i; - } - envp[i] = 0; - - return envp; -} - -/** - * Holds a mapping between native file descriptors and their corresponding - * pipes to set up communication between the parent and the %child process. - */ -typedef std::map info_map; - -/** - * Helper class to configure a POSIX %child. - * - * This helper class is used to hold all the attributes that configure a - * new POSIX %child process and to centralize all the actions needed to - * make them effective. - * - * All its fields are public for simplicity. It is only intended for - * internal use and it is heavily coupled with the Context - * implementations. - */ -struct posix_setup -{ - /** - * The work directory. - * - * This string specifies the directory in which the %child process - * starts execution. It cannot be empty. - */ - std::string work_directory; - - /** - * The chroot directory, if any. - * - * Specifies the directory in which the %child process is chrooted - * before execution. Empty if this feature is not desired. - */ - std::string chroot; - - /** - * The user credentials. - * - * UID that specifies the user credentials to use to run the %child - * process. Defaults to the current UID. - */ - uid_t uid; - - /** - * The effective user credentials. - * - * EUID that specifies the effective user credentials to use to run - * the %child process. Defaults to the current EUID. - */ - uid_t euid; - - /** - * The group credentials. - * - * GID that specifies the group credentials to use to run the %child - * process. Defaults to the current GID. - */ - gid_t gid; - - /** - * The effective group credentials. - * - * EGID that specifies the effective group credentials to use to run - * the %child process. Defaults to the current EGID. - */ - gid_t egid; - - /** - * Creates a new properties set. - * - * Creates a new object that has sensible default values for all the - * properties. - */ - posix_setup() - : uid(::getuid()), - euid(::geteuid()), - gid(::getgid()), - egid(::getegid()) - { - } - - /** - * Sets up the execution environment. - * - * Modifies the current execution environment (that of the %child) so - * that the properties become effective. - * - * \throw boost::system::system_error If any error ocurred during - * environment configuration. The child process should abort - * execution if this happens because its start conditions - * cannot be met. - */ - void operator()() const - { - if (!chroot.empty() && ::chroot(chroot.c_str()) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chroot(2) failed")); - - if (gid != ::getgid() && ::setgid(gid) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setgid(2) failed")); - - if (egid != ::getegid() && ::setegid(egid) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setegid(2) failed")); - - if (uid != ::getuid() && ::setuid(uid) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setuid(2) failed")); - - if (euid != ::geteuid() && ::seteuid(euid) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: seteuid(2) failed")); - - BOOST_ASSERT(!work_directory.empty()); - if (::chdir(work_directory.c_str()) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chdir(2) failed")); - } -}; - -/** - * Configures child process' input streams. - * - * Sets up the current process' input streams to behave according to the - * information in the \a info map. \a closeflags is modified to reflect - * those descriptors that should not be closed because they where modified - * by the function. - * - * Modifies the current execution environment, so this should only be run - * on the child process after the fork(2) has happened. - * - * \throw boost::system::system_error If any error occurs during the - * configuration. - */ -inline void setup_input(info_map &info, bool *closeflags, int maxdescs) -{ - for (info_map::iterator it = info.begin(); it != info.end(); ++it) - { - int d = it->first; - stream_info &si = it->second; - - BOOST_ASSERT(d < maxdescs); - closeflags[d] = false; - - switch (si.type_) - { - case stream_info::use_file: - { - int fd = ::open(si.file_.c_str(), O_RDONLY); - if (fd == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_input: open(2) of " + si.file_ + " failed")); - if (fd != d) - { - file_handle h(fd); - h.posix_remap(d); - h.release(); - } - break; - } - case stream_info::use_handle: - { - if (si.handle_.get() != d) - si.handle_.posix_remap(d); - break; - } - case stream_info::use_pipe: - { - si.pipe_->wend().close(); - if (d != si.pipe_->rend().get()) - si.pipe_->rend().posix_remap(d); - break; - } - default: - { - BOOST_ASSERT(si.type_ == stream_info::inherit); - break; - } - } - } -} - -/** - * Configures child process' output streams. - * - * Sets up the current process' output streams to behave according to the - * information in the \a info map. \a closeflags is modified to reflect - * those descriptors that should not be closed because they where - * modified by the function. - * - * Modifies the current execution environment, so this should only be run - * on the child process after the fork(2) has happened. - * - * \throw boost::system::system_error If any error occurs during the - * configuration. - */ -inline void setup_output(info_map &info, bool *closeflags, int maxdescs) -{ - for (info_map::iterator it = info.begin(); it != info.end(); ++it) - { - int d = it->first; - stream_info &si = it->second; - - BOOST_ASSERT(d < maxdescs); - closeflags[d] = false; - - switch (si.type_) - { - case stream_info::redirect: - { - break; - } - case stream_info::use_file: - { - int fd = ::open(si.file_.c_str(), O_WRONLY); - if (fd == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_output: open(2) of " + si.file_ + " failed")); - if (fd != d) - { - file_handle h(fd); - h.posix_remap(d); - h.release(); - } - break; - } - case stream_info::use_handle: - { - if (si.handle_.get() != d) - si.handle_.posix_remap(d); - break; - } - case stream_info::use_pipe: - { - si.pipe_->rend().close(); - if (d != si.pipe_->wend().get()) - si.pipe_->wend().posix_remap(d); - break; - } - default: - { - BOOST_ASSERT(si.type_ == stream_info::inherit); - break; - } - } - } - - for (info_map::const_iterator it = info.begin(); it != info.end(); ++it) - { - int d = it->first; - const stream_info &si = it->second; - - if (si.type_ == stream_info::redirect) - file_handle::posix_dup(si.desc_to_, d).release(); - } -} - -/** - * Starts a new child process in a POSIX operating system. - * - * This helper functions is provided to simplify the Context's task when - * it comes to starting up a new process in a POSIX operating system. - * The function hides all the details of the fork/exec pair of calls as - * well as all the setup of communication pipes and execution environment. - * - * \param exe The executable to spawn the child process. - * \param args The arguments for the executable. - * \param env The environment variables that the new child process - * receives. - * \param infoin A map describing all input file descriptors to be - * redirected. - * \param infoout A map describing all output file descriptors to be - * redirected. - * \param setup A helper object used to configure the child's execution - * environment. - * \return The new process' PID. The caller is responsible of creating - * an appropriate Child representation for it. - */ -template -inline pid_t posix_start(const Executable &exe, const Arguments &args, const environment &env, info_map &infoin, info_map &infoout, const posix_setup &setup) -{ - pid_t pid = ::fork(); - if (pid == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: fork(2) failed")); - else if (pid == 0) - { -#if defined(F_MAXFD) - int maxdescs = ::fcntl(-1, F_MAXFD, 0); - if (maxdescs == -1) - maxdescs = ::sysconf(_SC_OPEN_MAX); -#else - int maxdescs = ::sysconf(_SC_OPEN_MAX); -#endif - if (maxdescs == -1) - maxdescs = 1024; - try - { - boost::scoped_array closeflags(new bool[maxdescs]); - for (int i = 0; i < maxdescs; ++i) - closeflags[i] = true; - - setup_input(infoin, closeflags.get(), maxdescs); - setup_output(infoout, closeflags.get(), maxdescs); - - for (int i = 0; i < maxdescs; ++i) - { - if (closeflags[i]) - ::close(i); - } - - setup(); - } - catch (const boost::system::system_error &e) - { - ::write(STDERR_FILENO, e.what(), std::strlen(e.what())); - ::write(STDERR_FILENO, "\n", 1); - std::exit(EXIT_FAILURE); - } - - std::pair argcv = collection_to_posix_argv(args); - char **envp = environment_to_envp(env); - - ::execve(exe.c_str(), argcv.second, envp); - boost::system::system_error e(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: execve(2) failed"); - - for (std::size_t i = 0; i < argcv.first; ++i) - delete[] argcv.second[i]; - delete[] argcv.second; - - for (std::size_t i = 0; i < env.size(); ++i) - delete[] envp[i]; - delete[] envp; - - ::write(STDERR_FILENO, e.what(), std::strlen(e.what())); - ::write(STDERR_FILENO, "\n", 1); - std::exit(EXIT_FAILURE); - } - - BOOST_ASSERT(pid > 0); - - for (info_map::iterator it = infoin.begin(); it != infoin.end(); ++it) - { - stream_info &si = it->second; - if (si.type_ == stream_info::use_pipe) - si.pipe_->rend().close(); - } - - for (info_map::iterator it = infoout.begin(); it != infoout.end(); ++it) - { - stream_info &si = it->second; - if (si.type_ == stream_info::use_pipe) - si.pipe_->wend().close(); - } - - return pid; -} - -/** - * Locates a communication pipe and returns one of its endpoints. - * - * Given a \a info map, and a file descriptor \a desc, searches for its - * communicataion pipe in the map and returns one of its endpoints as - * indicated by the \a out flag. This is intended to be used by a - * parent process after a fork(2) call. - * - * \pre If the info map contains the given descriptor, it is configured - * to use a pipe. - * \post The info map does not contain the given descriptor. - * \return If the file descriptor is found in the map, returns the pipe's - * read end if out is true; otherwise its write end. If the - * descriptor is not found returns an invalid file handle. - */ -inline file_handle posix_info_locate_pipe(info_map &info, int desc, bool out) -{ - file_handle fh; - - info_map::iterator it = info.find(desc); - if (it != info.end()) - { - stream_info &si = it->second; - if (si.type_ == stream_info::use_pipe) - { - fh = out ? si.pipe_->rend().release() : si.pipe_->wend().release(); - BOOST_ASSERT(fh.valid()); - } - info.erase(it); - } - - return fh; -} - -} -} -} - -#endif diff --git a/boost/process/detail/stream_info.hpp b/boost/process/detail/stream_info.hpp deleted file mode 100644 index 89f4b361d..000000000 --- a/boost/process/detail/stream_info.hpp +++ /dev/null @@ -1,176 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/detail/stream_info.hpp - * - * Provides the definition of the stream_info structure. - */ - -#ifndef BOOST_PROCESS_DETAIL_STREAM_INFO_HPP -#define BOOST_PROCESS_DETAIL_STREAM_INFO_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -#elif defined(BOOST_WINDOWS_API) -#else -# error "Unsupported platform." -#endif - -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace process { -namespace detail { - -/** - * Configuration data for a file descriptor. - * - * This convenience structure provides a compact way to pass information - * around on how to configure a file descriptor. It is a lower-level - * representation of stream_behavior, as it can hold the same information - * but in a way that can be used by the underlying operating system. - */ -struct stream_info -{ - /** - * Supported stream types. - */ - enum type - { - /** - * Matches stream_behavior::close. - */ - close, - - /** - * Matches stream_behavior::inherit. - */ - inherit, - - /** - * Matches stream_behavior::redirect_to_stdout and - * stream_behavior::posix_redirect. - */ - redirect, - - /** - * Matches stream_behavior::silence. - */ - use_file, - - /** - * TODO: Matches nothing yet ... - */ - use_handle, - - /** - * Matches stream_behavior::capture. - */ - use_pipe - }; - - /** - * Stream type. - */ - type type_; - - /** - * Descriptor to use when stream type is set to \a redirect. - */ - int desc_to_; - - /** - * File to use when stream type is set to \a use_file. - */ - std::string file_; - - /** - * Handle to use when stream type is set to \a use_handle. - */ - file_handle handle_; - - /** - * Pipe to use when stream type is set to \a use_pipe. - */ - boost::optional pipe_; - - /** - * Constructs a new stream_info object. - */ - stream_info(const stream_behavior &sb, bool out) - { - switch (sb.type_) - { - case stream_behavior::close: - { - type_ = close; - break; - } - case stream_behavior::inherit: - { - type_ = inherit; - break; - } - case stream_behavior::redirect_to_stdout: - { - type_ = redirect; -#if defined(BOOST_POSIX_API) - desc_to_ = STDOUT_FILENO; -#elif defined(BOOST_WINDOWS_API) - desc_to_ = 1; -#endif - break; - } -#if defined(BOOST_POSIX_API) - case stream_behavior::posix_redirect: - { - type_ = redirect; - desc_to_ = sb.desc_to_; - break; - } -#endif - case stream_behavior::silence: - { - type_ = use_file; -#if defined(BOOST_POSIX_API) - file_ = out ? "/dev/null" : "/dev/zero"; -#elif defined(BOOST_WINDOWS_API) - file_ = "NUL"; -#endif - break; - } - case stream_behavior::capture: - { - type_ = use_pipe; - pipe_ = pipe(); - break; - } - default: - { - BOOST_ASSERT(false); - } - } - } -}; - -} -} -} - -#endif diff --git a/boost/process/detail/systembuf.hpp b/boost/process/detail/systembuf.hpp deleted file mode 100644 index 332e864f2..000000000 --- a/boost/process/detail/systembuf.hpp +++ /dev/null @@ -1,231 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/detail/systembuf.hpp - * - * Includes the declaration of the systembuf class. This file is for - * internal usage only and must not be included by the library user. - */ - -#ifndef BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP -#define BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -# include -#elif defined(BOOST_WINDOWS_API) -# include -#else -# error "Unsupported platform." -#endif - -#include -#include -#include -#include -#include - -namespace boost { -namespace process { - -class postream; - -namespace detail { - -/** - * std::streambuf implementation for system file handles. - * - * systembuf provides a std::streambuf implementation for system file - * handles. Contrarywise to file_handle, this class does \b not take - * ownership of the native file handle; this should be taken care of - * somewhere else. - * - * This class follows the expected semantics of a std::streambuf object. - * However, it is not copyable to avoid introducing inconsistences with - * the on-disk file and the in-memory buffers. - */ -class systembuf : public std::streambuf, public boost::noncopyable -{ - friend class ::boost::process::postream; - -public: -#if defined(BOOST_PROCESS_DOXYGEN) - /** - * Opaque name for the native handle type. - */ - typedef NativeHandleType handle_type; -#elif defined(BOOST_POSIX_API) - typedef int handle_type; -#elif defined(BOOST_WINDOWS_API) - typedef HANDLE handle_type; -#endif - - /** - * Constructs a new systembuf for the given file handle. - * - * This constructor creates a new systembuf object that reads or - * writes data from/to the \a h native file handle. This handle - * is \b not owned by the created systembuf object; the code - * should take care of it externally. - * - * This class buffers input and output; the buffer size may be - * tuned through the \a bufsize parameter, which defaults to 8192 - * bytes. - * - * \see pistream and postream - */ - explicit systembuf(handle_type h, std::size_t bufsize = 8192) - : handle_(h), - bufsize_(bufsize), - read_buf_(new char[bufsize]), - write_buf_(new char[bufsize]) - { -#if defined(BOOST_POSIX_API) - BOOST_ASSERT(handle_ >= 0); -#elif defined(BOOST_WINDOWS_API) - BOOST_ASSERT(handle_ != INVALID_HANDLE_VALUE); -#endif - BOOST_ASSERT(bufsize_ > 0); - - setp(write_buf_.get(), write_buf_.get() + bufsize_); - } - -protected: - /** - * Reads new data from the native file handle. - * - * This operation is called by input methods when there is no more - * data in the input buffer. The function fills the buffer with new - * data, if available. - * - * \pre All input positions are exhausted (gptr() >= egptr()). - * \post The input buffer has new data, if available. - * \returns traits_type::eof() if a read error occurrs or there are - * no more data to be read. Otherwise returns - * traits_type::to_int_type(*gptr()). - */ - virtual int_type underflow() - { - BOOST_ASSERT(gptr() >= egptr()); - - bool ok; -#if defined(BOOST_POSIX_API) - ssize_t cnt = ::read(handle_, read_buf_.get(), bufsize_); - ok = (cnt != -1 && cnt != 0); -#elif defined(BOOST_WINDOWS_API) - DWORD cnt; - BOOL res = ::ReadFile(handle_, read_buf_.get(), bufsize_, &cnt, NULL); - ok = (res && cnt > 0); -#endif - - if (!ok) - return traits_type::eof(); - else - { - setg(read_buf_.get(), read_buf_.get(), read_buf_.get() + cnt); - return traits_type::to_int_type(*gptr()); - } - } - - /** - * Makes room in the write buffer for additional data. - * - * This operation is called by output methods when there is no more - * space in the output buffer to hold a new element. The function - * first flushes the buffer's contents to disk and then clears it to - * leave room for more characters. The given \a c character is - * stored at the beginning of the new space. - * - * \pre All output positions are exhausted (pptr() >= epptr()). - * \post The output buffer has more space if no errors occurred - * during the write to disk. - * \post *(pptr() - 1) is \a c. - * \returns traits_type::eof() if a write error occurrs. Otherwise - * returns traits_type::not_eof(c). - */ - virtual int_type overflow(int c) - { - BOOST_ASSERT(pptr() >= epptr()); - - if (sync() == -1) - return traits_type::eof(); - - if (!traits_type::eq_int_type(c, traits_type::eof())) - { - traits_type::assign(*pptr(), c); - pbump(1); - } - - return traits_type::not_eof(c); - } - - /** - * Flushes the output buffer to disk. - * - * Synchronizes the systembuf buffers with the contents of the file - * associated to this object through the native file handle. The - * output buffer is flushed to disk and cleared to leave new room - * for more data. - * - * \returns 0 on success, -1 if an error occurred. - */ - virtual int sync() - { -#if defined(BOOST_POSIX_API) - ssize_t cnt = pptr() - pbase(); -#elif defined(BOOST_WINDOWS_API) - long cnt = pptr() - pbase(); -#endif - - bool ok; -#if defined(BOOST_POSIX_API) - ok = ::write(handle_, pbase(), cnt) == cnt; -#elif defined(BOOST_WINDOWS_API) - DWORD rcnt; - BOOL res = ::WriteFile(handle_, pbase(), cnt, &rcnt, NULL); - ok = (res && static_cast(rcnt) == cnt); -#endif - - if (ok) - pbump(-cnt); - return ok ? 0 : -1; - } - -private: - /** - * Native file handle used by the systembuf object. - */ - handle_type handle_; - - /** - * Internal buffer size used during read and write operations. - */ - std::size_t bufsize_; - - /** - * Internal buffer used during read operations. - */ - boost::scoped_array read_buf_; - - /** - * Internal buffer used during write operations. - */ - boost::scoped_array write_buf_; -}; - -} -} -} - -#endif diff --git a/boost/process/detail/win32_ops.hpp b/boost/process/detail/win32_ops.hpp deleted file mode 100644 index d84de9b71..000000000 --- a/boost/process/detail/win32_ops.hpp +++ /dev/null @@ -1,355 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/detail/win32_ops.hpp - * - * Provides some convenience functions to start processes under - * Windows-compatible operating systems. - */ - -#ifndef BOOST_PROCESS_DETAIL_WIN32_OPS_HPP -#define BOOST_PROCESS_DETAIL_WIN32_OPS_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace process { -namespace detail { - -/** - * Converts the command line to a plain string. Converts the command line's - * list of arguments to the format expected by the \a lpCommandLine parameter - * in the CreateProcess() system call. - * - * This operation is only available on Windows systems. - * - * \return A dynamically allocated string holding the command line - * to be passed to the executable. It is returned in a - * shared_array object to ensure its release at some point. - */ -template -inline boost::shared_array collection_to_win32_cmdline(const Arguments &args) -{ - typedef std::vector arguments_t; - arguments_t args2; - typename Arguments::size_type i = 0; - std::size_t size = 0; - for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it) - { - std::string arg = *it; - - std::string::size_type pos = 0; - while ( (pos = arg.find('"', pos)) != std::string::npos) - { - arg.replace(pos, 1, "\\\""); - pos += 2; - } - - if (arg.find(' ') != std::string::npos) - arg = '\"' + arg + '\"'; - - if (i++ != args.size() - 1) - arg += ' '; - - args2.push_back(arg); - size += arg.size() + 1; - } - - boost::shared_array cmdline(new char[size]); - cmdline.get()[0] = '\0'; - for (arguments_t::size_type i = 0; i < args.size(); ++i) -#if defined(__CYGWIN__) - ::strncat(cmdline.get(), args2[i].c_str(), args2[i].size()); -#else - ::strcat_s(cmdline.get(), size, args2[i].c_str()); -#endif - - return cmdline; -} - -/** - * Converts an environment to a string used by CreateProcess(). - * - * Converts the environment's contents to the format used by the - * CreateProcess() system call. The returned char* string is - * allocated in dynamic memory; the caller must free it when not - * used any more. This is enforced by the use of a shared pointer. - * - * \return A dynamically allocated char* string that represents - * the environment's content. This string is of the form - * var1=value1\\0var2=value2\\0\\0. - */ -inline boost::shared_array environment_to_win32_strings(const environment &env) -{ - boost::shared_array envp; - - if (env.empty()) - { - envp.reset(new char[2]); - ::ZeroMemory(envp.get(), 2); - } - else - { - std::string s; - for (environment::const_iterator it = env.begin(); it != env.end(); ++it) - { - s += it->first + "=" + it->second; - s.push_back(0); - } - - envp.reset(new char[s.size() + 1]); -#if defined(__CYGWIN__) - ::memcpy(envp.get(), s.c_str(), s.size() + 1); -#else - ::memcpy_s(envp.get(), s.size() + 1, s.c_str(), s.size() + 1); -#endif - } - - return envp; -} - -/** - * Helper class to configure a Win32 %child. - * - * This helper class is used to hold all the attributes that configure a - * new Win32 %child process. - * - * All its fields are public for simplicity. It is only intended for - * internal use and it is heavily coupled with the Context - * implementations. - */ -struct win32_setup -{ - /** - * The work directory. - * - * This string specifies the directory in which the %child process - * starts execution. It cannot be empty. - */ - std::string work_directory; - - /** - * The process startup properties. - * - * This Win32-specific object holds a list of properties that describe - * how the new process should be started. The \a STARTF_USESTDHANDLES - * flag should not be set in it because it is automatically configured - * by win32_start(). - */ - STARTUPINFOA *startupinfo; -}; - -/** - * Starts a new child process in a Win32 operating system. - * - * This helper functions is provided to simplify the Context's task when - * it comes to starting up a new process in a Win32 operating system. - * - * \param exe The executable to spawn the child process. - * \param args The arguments for the executable. - * \param env The environment variables that the new child process - * receives. - * \param infoin Information that describes stdin's behavior. - * \param infoout Information that describes stdout's behavior. - * \param infoerr Information that describes stderr's behavior. - * \param setup A helper object holding extra child information. - * \return The new process' information as returned by the CreateProcess() - * system call. The caller is responsible of creating an - * appropriate Child representation for it. - * \pre \a setup.startupinfo_ cannot have the \a STARTF_USESTDHANDLES set - * in the \a dwFlags field. - */ -template -inline PROCESS_INFORMATION win32_start(const Executable &exe, const Arguments &args, const environment &env, stream_info &infoin, stream_info &infoout, stream_info &infoerr, const win32_setup &setup) -{ - file_handle chin, chout, cherr; - - BOOST_ASSERT(setup.startupinfo->cb >= sizeof(STARTUPINFOA)); - BOOST_ASSERT(!(setup.startupinfo->dwFlags & STARTF_USESTDHANDLES)); - - boost::scoped_ptr si(new STARTUPINFOA); - ::CopyMemory(si.get(), setup.startupinfo, sizeof(*setup.startupinfo)); - si->dwFlags |= STARTF_USESTDHANDLES; - - switch (infoin.type_) - { - case stream_info::close: - { - break; - } - case stream_info::inherit: - { - chin = file_handle::win32_std(STD_INPUT_HANDLE, true); - break; - } - case stream_info::use_file: - { - HANDLE h = ::CreateFileA(infoin.file_.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed")); - chin = file_handle(h); - break; - } - case stream_info::use_handle: - { - chin = infoin.handle_; - chin.win32_set_inheritable(true); - break; - } - case stream_info::use_pipe: - { - infoin.pipe_->rend().win32_set_inheritable(true); - chin = infoin.pipe_->rend(); - break; - } - default: - { - BOOST_ASSERT(false); - break; - } - } - - si->hStdInput = chin.valid() ? chin.get() : INVALID_HANDLE_VALUE; - - switch (infoout.type_) - { - case stream_info::close: - { - break; - } - case stream_info::inherit: - { - chout = file_handle::win32_std(STD_OUTPUT_HANDLE, true); - break; - } - case stream_info::use_file: - { - HANDLE h = ::CreateFileA(infoout.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed")); - chout = file_handle(h); - break; - } - case stream_info::use_handle: - { - chout = infoout.handle_; - chout.win32_set_inheritable(true); - break; - } - case stream_info::use_pipe: - { - infoout.pipe_->wend().win32_set_inheritable(true); - chout = infoout.pipe_->wend(); - break; - } - default: - { - BOOST_ASSERT(false); - break; - } - } - - si->hStdOutput = chout.valid() ? chout.get() : INVALID_HANDLE_VALUE; - - switch (infoerr.type_) - { - case stream_info::close: - { - break; - } - case stream_info::inherit: - { - cherr = file_handle::win32_std(STD_ERROR_HANDLE, true); - break; - } - case stream_info::redirect: - { - BOOST_ASSERT(infoerr.desc_to_ == 1); - BOOST_ASSERT(chout.valid()); - cherr = file_handle::win32_dup(chout.get(), true); - break; - } - case stream_info::use_file: - { - HANDLE h = ::CreateFileA(infoerr.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed")); - cherr = file_handle(h); - break; - } - case stream_info::use_handle: - { - cherr = infoerr.handle_; - cherr.win32_set_inheritable(true); - break; - } - case stream_info::use_pipe: - { - infoerr.pipe_->wend().win32_set_inheritable(true); - cherr = infoerr.pipe_->wend(); - break; - } - default: - { - BOOST_ASSERT(false); - break; - } - } - - si->hStdError = cherr.valid() ? cherr.get() : INVALID_HANDLE_VALUE; - - PROCESS_INFORMATION pi; - ::ZeroMemory(&pi, sizeof(pi)); - - boost::shared_array cmdline = collection_to_win32_cmdline(args); - - boost::scoped_array executable(new char[exe.size() + 1]); -#if defined(__CYGWIN__) - ::strcpy(executable.get(), exe.c_str()); -#else - ::strcpy_s(executable.get(), exe.size() + 1, exe.c_str()); -#endif - - boost::scoped_array workdir(new char[setup.work_directory.size() + 1]); -#if defined(__CYGWIN__) - ::strcpy(workdir.get(), setup.work_directory.c_str()); -#else - ::strcpy_s(workdir.get(), setup.work_directory.size() + 1, setup.work_directory.c_str()); -#endif - - boost::shared_array envstrs = environment_to_win32_strings(env); - - if (!::CreateProcessA(executable.get()[0] ? executable.get() : NULL, cmdline.get(), NULL, NULL, TRUE, CREATE_NO_WINDOW, envstrs.get(), workdir.get(), si.get(), &pi)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateProcess failed")); - - return pi; -} - -} -} -} - -#endif diff --git a/boost/process/environment.hpp b/boost/process/environment.hpp deleted file mode 100644 index be73ed390..000000000 --- a/boost/process/environment.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/environment.hpp - * - * Includes the declaration of the environment class. - */ - -#ifndef BOOST_PROCESS_ENVIRONMENT_HPP -#define BOOST_PROCESS_ENVIRONMENT_HPP - -#include -#include - -namespace boost { -namespace process { - -/** - * Representation of a process' environment variables. - * - * The environment is a map that stablishes an unidirectional - * association between variable names and their values and is - * represented by a string to string map. - * - * Variables may be defined to the empty string. Be aware that doing so - * is not portable: POSIX systems will treat such variables as being - * defined to the empty value, but Windows systems are not able to - * distinguish them from undefined variables. - * - * Neither POSIX nor Windows systems support a variable with no name. - * - * It is worthy to note that the environment is sorted alphabetically. - * This is provided for-free by the map container used to implement this - * type, and this behavior is required by Windows systems. - */ -typedef std::map environment; - -} -} - -#endif diff --git a/boost/process/operations.hpp b/boost/process/operations.hpp deleted file mode 100644 index f11d3b423..000000000 --- a/boost/process/operations.hpp +++ /dev/null @@ -1,583 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/operations.hpp - * - * Provides miscellaneous free functions. - */ - -#ifndef BOOST_PROCESS_OPERATIONS_HPP -#define BOOST_PROCESS_OPERATIONS_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -# include -# include -# if defined(__CYGWIN__) -# include -# include -# endif -#elif defined(BOOST_WINDOWS_API) -# include -# include -# include -#else -# error "Unsupported platform." -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Locates the executable program \a file in all the directory components - * specified in \a path. If \a path is empty, the value of the PATH - * environment variable is used. - * - * The path variable is interpreted following the same conventions used - * to parse the PATH environment variable in the underlying platform. - * - * \throw boost::filesystem::filesystem_error If the file cannot be found - * in the path. - */ -inline std::string find_executable_in_path(const std::string &file, std::string path = "") -{ -#if defined(BOOST_POSIX_API) - BOOST_ASSERT(file.find('/') == std::string::npos); -#elif defined(BOOST_WINDOWS_API) - BOOST_ASSERT(file.find_first_of("\\/") == std::string::npos); -#endif - - std::string result; - -#if defined(BOOST_POSIX_API) - if (path.empty()) - { - const char *envpath = ::getenv("PATH"); -// if (!envpath) - // boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: retrieving PATH failed", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory))); - - path = envpath; - } - BOOST_ASSERT(!path.empty()); - -#if defined(__CYGWIN__) - if (!::cygwin_posix_path_list_p(path.c_str())) - { - int size = ::cygwin_win32_to_posix_path_list_buf_size(path.c_str()); - boost::scoped_array cygpath(new char[size]); - ::cygwin_win32_to_posix_path_list(path.c_str(), cygpath.get()); - path = cygpath.get(); - } -#endif - - std::string::size_type pos1 = 0, pos2; - do - { - pos2 = path.find(':', pos1); - std::string dir = (pos2 != std::string::npos) ? path.substr(pos1, pos2 - pos1) : path.substr(pos1); - std::string f = dir + (boost::algorithm::ends_with(dir, "/") ? "" : "/") + file; - if (!::access(f.c_str(), X_OK)) - result = f; - pos1 = pos2 + 1; - } while (pos2 != std::string::npos && result.empty()); -#elif defined(BOOST_WINDOWS_API) - const char *exts[] = { "", ".exe", ".com", ".bat", NULL }; - const char **ext = exts; - while (*ext) - { - char buf[MAX_PATH]; - char *dummy; - DWORD size = ::SearchPathA(path.empty() ? NULL : path.c_str(), file.c_str(), *ext, MAX_PATH, buf, &dummy); - BOOST_ASSERT(size < MAX_PATH); - if (size > 0) - { - result = buf; - break; - } - ++ext; - } -#endif - - // if (result.empty()) -// boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: file not found", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory))); - - return result; -} - -/** - * Extracts the program name from a given executable. - * - * \return The program name. On Windows the program name - * is returned without a file extension. - */ -inline std::string executable_to_progname(const std::string &exe) -{ - std::string::size_type begin = 0; - std::string::size_type end = std::string::npos; - -#if defined(BOOST_POSIX_API) - std::string::size_type slash = exe.rfind('/'); -#elif defined(BOOST_WINDOWS_API) - std::string::size_type slash = exe.find_last_of("/\\"); -#endif - if (slash != std::string::npos) - begin = slash + 1; - -#if defined(BOOST_WINDOWS_API) - if (exe.size() > 4 && - (boost::algorithm::iends_with(exe, ".exe") || boost::algorithm::iends_with(exe, ".com") || boost::algorithm::iends_with(exe, ".bat"))) - end = exe.size() - 4; -#endif - - return exe.substr(begin, end - begin); -} - -/** - * Starts a new child process. - * - * Launches a new process based on the binary image specified by the - * executable, the set of arguments to be passed to it and several - * parameters that describe the execution context. - * - * \remark Blocking remarks: This function may block if the device - * holding the executable blocks when loading the image. This might - * happen if, e.g., the binary is being loaded from a network share. - * - * \return A handle to the new child process. - */ -template -inline child launch(const Executable &exe, const Arguments &args, const Context &ctx) -{ - detail::file_handle fhstdin, fhstdout, fhstderr; - - BOOST_ASSERT(!args.empty()); - BOOST_ASSERT(!ctx.work_directory.empty()); - -#if defined(BOOST_POSIX_API) - detail::info_map infoin, infoout; - - if (ctx.stdin_behavior.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false); - infoin.insert(detail::info_map::value_type(STDIN_FILENO, si)); - } - - if (ctx.stdout_behavior.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true); - infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si)); - } - - if (ctx.stderr_behavior.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); - infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); - } - - detail::posix_setup s; - s.work_directory = ctx.work_directory; - - child::id_type pid = detail::posix_start(exe, args, ctx.environment, infoin, infoout, s); - - if (ctx.stdin_behavior.get_type() == stream_behavior::capture) - { - fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false); - BOOST_ASSERT(fhstdin.valid()); - } - - if (ctx.stdout_behavior.get_type() == stream_behavior::capture) - { - fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true); - BOOST_ASSERT(fhstdout.valid()); - } - - if (ctx.stderr_behavior.get_type() == stream_behavior::capture) - { - fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true); - BOOST_ASSERT(fhstderr.valid()); - } - - return child(pid, fhstdin, fhstdout, fhstderr); -#elif defined(BOOST_WINDOWS_API) - detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false); - if (behin.type_ == detail::stream_info::use_pipe) - fhstdin = behin.pipe_->wend(); - detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true); - if (behout.type_ == detail::stream_info::use_pipe) - fhstdout = behout.pipe_->rend(); - detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true); - if (beherr.type_ == detail::stream_info::use_pipe) - fhstderr = beherr.pipe_->rend(); - - STARTUPINFOA si; - ::ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - - detail::win32_setup s; - s.work_directory = ctx.work_directory; - s.startupinfo = &si; - - PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s); - - if (!::CloseHandle(pi.hThread)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch: CloseHandle failed")); - - return child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, detail::file_handle(pi.hProcess)); -#endif -} - -/** - * Launches a shell-based command. - * - * Executes the given command through the default system shell. The - * command is subject to pattern expansion, redirection and pipelining. - * The shell is launched as described by the parameters in the execution - * context. - * - * This function behaves similarly to the system(3) system call. In a - * POSIX system, the command is fed to /bin/sh whereas under a Windows - * system, it is fed to cmd.exe. It is difficult to write portable - * commands as the first parameter, but this function comes in handy in - * multiple situations. - */ -template -inline child launch_shell(const std::string &command, const Context &ctx) -{ - std::string exe; - std::vector args; - -#if defined(BOOST_POSIX_API) - exe = "/bin/sh"; - args.push_back("sh"); - args.push_back("-c"); - args.push_back(command); -#elif defined(BOOST_WINDOWS_API) - char sysdir[MAX_PATH]; - UINT size = ::GetSystemDirectoryA(sysdir, sizeof(sysdir)); - if (!size) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_shell: GetWindowsDirectory failed")); - BOOST_ASSERT(size < MAX_PATH); - - exe = std::string(sysdir) + (sysdir[size - 1] != '\\' ? "\\cmd.exe" : "cmd.exe"); - args.push_back("cmd"); - args.push_back("/c"); - args.push_back(command); -#endif - - return launch(exe, args, ctx); -} - -/** - * Launches a pipelined set of child processes. - * - * Given a collection of pipeline_entry objects describing how to launch - * a set of child processes, spawns them all and connects their inputs and - * outputs in a way that permits pipelined communication. - * - * \pre Let 1..N be the processes in the collection: the input behavior of - * the 2..N processes must be set to close_stream(). - * \pre Let 1..N be the processes in the collection: the output behavior of - * the 1..N-1 processes must be set to close_stream(). - * \remark Blocking remarks: This function may block if the device holding - * the executable of one of the entries blocks when loading the - * image. This might happen if, e.g., the binary is being loaded - * from a network share. - * \return A set of Child objects that represent all the processes spawned - * by this call. You should use wait_children() to wait for their - * termination. - */ -template -inline children launch_pipeline(const Entries &entries) -{ - BOOST_ASSERT(entries.size() >= 2); - - children cs; - detail::file_handle fhinvalid; - - boost::scoped_array pipes(new detail::pipe[entries.size() - 1]); - -#if defined(BOOST_POSIX_API) - { - typename Entries::size_type i = 0; - const typename Entries::value_type::context_type &ctx = entries[i].context; - - detail::info_map infoin, infoout; - - if (ctx.stdin_behavior.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false); - infoin.insert(detail::info_map::value_type(STDIN_FILENO, si)); - } - - BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close); - detail::stream_info si2(close_stream(), true); - si2.type_ = detail::stream_info::use_handle; - si2.handle_ = pipes[i].wend().release(); - infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2)); - - if (ctx.stderr_behavior.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); - infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); - } - - detail::posix_setup s; - s.work_directory = ctx.work_directory; - - pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s); - - detail::file_handle fhstdin; - - if (ctx.stdin_behavior.get_type() == stream_behavior::capture) - { - fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false); - BOOST_ASSERT(fhstdin.valid()); - } - - cs.push_back(child(pid, fhstdin, fhinvalid, fhinvalid)); - } - - for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i) - { - const typename Entries::value_type::context_type &ctx = entries[i].context; - detail::info_map infoin, infoout; - - BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); - detail::stream_info si1(close_stream(), false); - si1.type_ = detail::stream_info::use_handle; - si1.handle_ = pipes[i - 1].rend().release(); - infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1)); - - BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close); - detail::stream_info si2(close_stream(), true); - si2.type_ = detail::stream_info::use_handle; - si2.handle_ = pipes[i].wend().release(); - infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2)); - - if (ctx.stderr_behavior.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); - infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); - } - - detail::posix_setup s; - s.work_directory = ctx.work_directory; - - pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s); - - cs.push_back(child(pid, fhinvalid, fhinvalid, fhinvalid)); - } - - { - typename Entries::size_type i = entries.size() - 1; - const typename Entries::value_type::context_type &ctx = entries[i].context; - - detail::info_map infoin, infoout; - - BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); - detail::stream_info si1(close_stream(), false); - si1.type_ = detail::stream_info::use_handle; - si1.handle_ = pipes[i - 1].rend().release(); - infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1)); - - if (ctx.stdout_behavior.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true); - infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si)); - } - - if (ctx.stderr_behavior.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); - infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); - } - - detail::posix_setup s; - s.work_directory = ctx.work_directory; - - pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s); - - detail::file_handle fhstdout, fhstderr; - - if (ctx.stdout_behavior.get_type() == stream_behavior::capture) - { - fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true); - BOOST_ASSERT(fhstdout.valid()); - } - - if (ctx.stderr_behavior.get_type() == stream_behavior::capture) - { - fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true); - BOOST_ASSERT(fhstderr.valid()); - } - - cs.push_back(child(pid, fhinvalid, fhstdout, fhstderr)); - } -#elif defined(BOOST_WINDOWS_API) - STARTUPINFOA si; - detail::win32_setup s; - s.startupinfo = &si; - - { - typename Entries::size_type i = 0; - const typename Entries::value_type::context_type &ctx = entries[i].context; - - detail::stream_info sii = detail::stream_info(ctx.stdin_behavior, false); - detail::file_handle fhstdin; - if (sii.type_ == detail::stream_info::use_pipe) - fhstdin = sii.pipe_->wend(); - - BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close); - detail::stream_info sio(close_stream(), true); - sio.type_ = detail::stream_info::use_handle; - sio.handle_ = pipes[i].wend().release(); - - detail::stream_info sie(ctx.stderr_behavior, true); - - s.work_directory = ctx.work_directory; - - ::ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s); - - if (!::CloseHandle(pi.hThread)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed")); - - cs.push_back(child(pi.dwProcessId, fhstdin, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess))); - } - - for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i) - { - const typename Entries::value_type::context_type &ctx = entries[i].context; - - BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); - detail::stream_info sii(close_stream(), false); - sii.type_ = detail::stream_info::use_handle; - sii.handle_ = pipes[i - 1].rend().release(); - - detail::stream_info sio(close_stream(), true); - sio.type_ = detail::stream_info::use_handle; - sio.handle_ = pipes[i].wend().release(); - - detail::stream_info sie(ctx.stderr_behavior, true); - - s.work_directory = ctx.work_directory; - - ::ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s); - - if (!::CloseHandle(pi.hThread)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed")); - - cs.push_back(child(pi.dwProcessId, fhinvalid, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess))); - } - - { - typename Entries::size_type i = entries.size() - 1; - const typename Entries::value_type::context_type &ctx = entries[i].context; - - BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); - detail::stream_info sii(close_stream(), false); - sii.type_ = detail::stream_info::use_handle; - sii.handle_ = pipes[i - 1].rend().release(); - - detail::file_handle fhstdout, fhstderr; - - detail::stream_info sio(ctx.stdout_behavior, true); - if (sio.type_ == detail::stream_info::use_pipe) - fhstdout = sio.pipe_->rend(); - detail::stream_info sie(ctx.stderr_behavior, true); - if (sie.type_ == detail::stream_info::use_pipe) - fhstderr = sie.pipe_->rend(); - - s.work_directory = ctx.work_directory; - - ::ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s); - - if (!::CloseHandle(pi.hThread)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed")); - - cs.push_back(child(pi.dwProcessId, fhinvalid, fhstdout, fhstderr, detail::file_handle(pi.hProcess))); - } -#endif - - return cs; -} - -/** - * Waits for a collection of children to terminate. - * - * Given a collection of Child objects (such as std::vector or - * the convenience children type), waits for the termination of all of - * them. - * - * \remark Blocking remarks: This call blocks if any of the children - * processes in the collection has not finalized execution and - * waits until it terminates. - * - * \return The exit status of the first process that returns an error - * code or, if all of them executed correctly, the exit status - * of the last process in the collection. - */ -template -inline status wait_children(Children &cs) -{ - BOOST_ASSERT(cs.size() >= 2); - - typename Children::iterator it = cs.begin(); - while (it != cs.end()) - { - const status s = it->wait(); - ++it; - if (it == cs.end()) - return s; - else if (!s.exited() || s.exit_status() != EXIT_SUCCESS) - { - while (it != cs.end()) - { - it->wait(); - ++it; - } - return s; - } - } - - BOOST_ASSERT(false); - return cs.begin()->wait(); -} - -} -} - -#endif diff --git a/boost/process/pistream.hpp b/boost/process/pistream.hpp deleted file mode 100644 index 958a222d8..000000000 --- a/boost/process/pistream.hpp +++ /dev/null @@ -1,116 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/pistream.hpp - * - * Includes the declaration of the pistream class. - */ - -#ifndef BOOST_PROCESS_PISTREAM_HPP -#define BOOST_PROCESS_PISTREAM_HPP - -#include -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Child process' output stream. - * - * The pistream class represents an output communication channel with the - * child process. The child process writes data to this stream and the - * parent process can read it through the pistream object. In other - * words, from the child's point of view, the communication channel is an - * output one, but from the parent's point of view it is an input one; - * hence the confusing pistream name. - * - * pistream objects cannot be copied because they own the file handle - * they use to communicate with the child and because they buffer data - * that flows through the communication channel. - * - * A pistream object behaves as a std::istream stream in all senses. - * The class is only provided because it must provide a method to let - * the caller explicitly close the communication channel. - * - * \remark Blocking remarks: Functions that read data from this - * stream can block if the associated file handle blocks during - * the read. As this class is used to communicate with child - * processes through anonymous pipes, the most typical blocking - * condition happens when the child has no more data to send to - * the pipe's system buffer. When this happens, the buffer - * eventually empties and the system blocks until the writer - * generates some data. - */ -class pistream : public std::istream, public boost::noncopyable -{ -public: - /** - * Creates a new process' output stream. - * - * Given a file handle, this constructor creates a new pistream - * object that owns the given file handle \a fh. Ownership of - * \a fh is transferred to the created pistream object. - * - * \pre \a fh is valid. - * \post \a fh is invalid. - * \post The new pistream object owns \a fh. - */ - explicit pistream(detail::file_handle &fh) - : std::istream(0), - handle_(fh), - systembuf_(handle_.get()) - { - rdbuf(&systembuf_); - } - - /** - * Returns the file handle managed by this stream. - * - * The file handle must not be copied. Copying invalidates - * the source file handle making the pistream unusable. - */ - detail::file_handle &handle() - { - return handle_; - } - - /** - * Closes the file handle managed by this stream. - * - * Explicitly closes the file handle managed by this stream. This - * function can be used by the user to tell the child process it's - * not willing to receive more data. - */ - void close() - { - handle_.close(); - } - -private: - /** - * The file handle managed by this stream. - */ - detail::file_handle handle_; - - /** - * The systembuf object used to manage this stream's data. - */ - detail::systembuf systembuf_; -}; - -} -} - -#endif diff --git a/boost/process/posix_child.hpp b/boost/process/posix_child.hpp deleted file mode 100644 index 62bdc3180..000000000 --- a/boost/process/posix_child.hpp +++ /dev/null @@ -1,178 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/posix_child.hpp - * - * Includes the declaration of the posix_child class. - */ - -#ifndef BOOST_PROCESS_POSIX_CHILD_HPP -#define BOOST_PROCESS_POSIX_CHILD_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace process { - -/** - * POSIX implementation of the Child concept. - * - * The posix_child class implements the Child concept in a POSIX - * operating system. - * - * A POSIX child differs from a regular child (represented by a - * child object) in that it supports more than three communication - * channels with its parent. These channels are identified by regular - * file descriptors (integers). - * - * This class is built on top of the generic child so as to allow its - * trivial adoption. When a program is changed to use the POSIX-specific - * context (posix_context), it will most certainly need to migrate its - * use of the child class to posix_child. Doing so is only a matter of - * redefining the appropriate object and later using the required extra - * features: there should be no need to modify the existing code (e.g. - * method calls) in any other way. - */ -class posix_child : public child -{ -public: - /** - * Gets a reference to the child's input stream \a desc. - * - * Returns a reference to a postream object that represents one of - * the multiple input communication channels with the child process. - * The channel is identified by \a desc as seen from the child's - * point of view. The parent can use the returned stream to send - * data to the child. - * - * Giving this function the STDIN_FILENO constant (defined in - * unistd.h) is a synonym for the get_stdin() call inherited from - * child. - */ - postream &get_input(int desc) const - { - if (desc == STDIN_FILENO) - return posix_child::get_stdin(); - else - { - input_map_t::const_iterator it = input_map_.find(desc); - BOOST_ASSERT(it != input_map_.end()); - return *it->second; - } - } - - /** - * Gets a reference to the child's output stream \a desc. - * - * Returns a reference to a pistream object that represents one of - * the multiple output communication channels with the child process. - * The channel is identified by \a desc as seen from the child's - * point of view. The parent can use the returned stream to retrieve - * data from the child. - * - * Giving this function the STDOUT_FILENO or STDERR_FILENO constants - * (both defined in unistd.h) are synonyms for the get_stdout() and - * get_stderr() calls inherited from child, respectively. - */ - pistream &get_output(int desc) const - { - if (desc == STDOUT_FILENO) - return posix_child::get_stdout(); - else if (desc == STDERR_FILENO) - return posix_child::get_stderr(); - else - { - output_map_t::const_iterator it = output_map_.find(desc); - BOOST_ASSERT(it != output_map_.end()); - return *it->second; - } - } - - /** - * Constructs a new POSIX child object representing a just - * spawned child process. - * - * Creates a new child object that represents the just spawned process - * \a id. - * - * The \a infoin and \a infoout maps contain the pipes used to handle - * the redirections of the child process; at the moment, no other - * stream_info types are supported. If the launcher was asked to - * redirect any of the three standard flows, their pipes must be - * present in these maps. - */ - posix_child(id_type id, detail::info_map &infoin, detail::info_map &infoout) - : child(id, - detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false), - detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true), - detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true)) - { - for (detail::info_map::iterator it = infoin.begin(); it != infoin.end(); ++it) - { - detail::stream_info &si = it->second; - if (si.type_ == detail::stream_info::use_pipe) - { - BOOST_ASSERT(si.pipe_->wend().valid()); - boost::shared_ptr st(new postream(si.pipe_->wend())); - input_map_.insert(input_map_t::value_type(it->first, st)); - } - } - - for (detail::info_map::iterator it = infoout.begin(); it != infoout.end(); ++it) - { - detail::stream_info &si = it->second; - if (si.type_ == detail::stream_info::use_pipe) - { - BOOST_ASSERT(si.pipe_->rend().valid()); - boost::shared_ptr st(new pistream(si.pipe_->rend())); - output_map_.insert(output_map_t::value_type(it->first, st)); - } - } - } - -private: - /** - * Maps child's file descriptors to postream objects. - */ - typedef std::map > input_map_t; - - /** - * Contains all relationships between child's input file - * descriptors and their corresponding postream objects. - */ - input_map_t input_map_; - - /** - * Maps child's file descriptors to pistream objects. - */ - typedef std::map > output_map_t; - - /** - * Contains all relationships between child's output file - * descriptors and their corresponding pistream objects. - */ - output_map_t output_map_; -}; - -} -} - -#endif diff --git a/boost/process/posix_context.hpp b/boost/process/posix_context.hpp deleted file mode 100644 index 3ca4cf49f..000000000 --- a/boost/process/posix_context.hpp +++ /dev/null @@ -1,118 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/posix_context.hpp - * - * Includes the declaration of the posix_context class. - */ - -#ifndef BOOST_PROCESS_POSIX_CONTEXT_HPP -#define BOOST_PROCESS_POSIX_CONTEXT_HPP - -#include -#include -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Holds a mapping between native file descriptors and their corresponding - * pipes to set up communication between the parent and the %child process. - */ -typedef std::map behavior_map; - -template -class posix_basic_context : public basic_work_directory_context, public environment_context -{ -public: - /** - * Constructs a new POSIX-specific context. - * - * Constructs a new context. It is configured as follows: - * * All communcation channels with the child process are closed. - * * There are no channel mergings. - * * The initial work directory of the child processes is set to the - * current working directory. - * * The environment variables table is empty. - * * The credentials are the same as those of the current process. - */ - posix_basic_context() - : uid(::getuid()), - euid(::geteuid()), - gid(::getgid()), - egid(::getegid()) - { - } - - /** - * List of input streams that will be redirected. - */ - behavior_map input_behavior; - - /** - * List of output streams that will be redirected. - */ - behavior_map output_behavior; - - /** - * The user credentials. - * - * UID that specifies the user credentials to use to run the %child - * process. Defaults to the current UID. - */ - uid_t uid; - - /** - * The effective user credentials. - * - * EUID that specifies the effective user credentials to use to run - * the %child process. Defaults to the current EUID. - */ - uid_t euid; - - /** - * The group credentials. - * - * GID that specifies the group credentials to use to run the %child - * process. Defaults to the current GID. - */ - gid_t gid; - - /** - * The effective group credentials. - * - * EGID that specifies the effective group credentials to use to run - * the %child process. Defaults to the current EGID. - */ - gid_t egid; - - /** - * The chroot directory, if any. - * - * Specifies the directory in which the %child process is chrooted - * before execution. Empty if this feature is not desired. - */ - Path chroot; -}; - -/** - * Default instantiation of posix_basic_context. - */ -typedef posix_basic_context posix_context; - -} -} - -#endif diff --git a/boost/process/posix_operations.hpp b/boost/process/posix_operations.hpp deleted file mode 100644 index 78de54a91..000000000 --- a/boost/process/posix_operations.hpp +++ /dev/null @@ -1,81 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/posix_operations.hpp - * - * Provides miscellaneous free functions specific to POSIX operating - * systems. - */ - -#ifndef BOOST_PROCESS_POSIX_OPERATIONS_HPP -#define BOOST_PROCESS_POSIX_OPERATIONS_HPP - -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Starts a new child process. - * - * Given an executable and the set of arguments passed to it, starts - * a new process with all the parameters configured in the context. - * The context can be reused afterwards to launch other different - * processes. - * - * \return A handle to the new child process. - */ -template -inline posix_child posix_launch(const Executable &exe, const Arguments &args, const Posix_Context &ctx) -{ - detail::info_map input_info; - for (behavior_map::const_iterator it = ctx.input_behavior.begin(); it != ctx.input_behavior.end(); ++it) - { - if (it->second.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(it->second, false); - input_info.insert(detail::info_map::value_type(it->first, si)); - } - } - - detail::info_map output_info; - for (behavior_map::const_iterator it = ctx.output_behavior.begin(); it != ctx.output_behavior.end(); ++it) - { - if (it->second.get_type() != stream_behavior::close) - { - detail::stream_info si = detail::stream_info(it->second, true); - output_info.insert(detail::info_map::value_type(it->first, si)); - } - } - - detail::posix_setup s; - s.work_directory = ctx.work_directory; - s.uid = ctx.uid; - s.euid = ctx.euid; - s.gid = ctx.gid; - s.egid = ctx.egid; - s.chroot = ctx.chroot; - - pid_t pid = detail::posix_start(exe, args, ctx.environment, input_info, output_info, s); - - return posix_child(pid, input_info, output_info); -} - -} -} - -#endif diff --git a/boost/process/posix_status.hpp b/boost/process/posix_status.hpp deleted file mode 100644 index eefb144eb..000000000 --- a/boost/process/posix_status.hpp +++ /dev/null @@ -1,128 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/posix_status.hpp - * - * Includes the declaration of the posix_status class. - */ - -#ifndef BOOST_PROCESS_POSIX_STATUS_HPP -#define BOOST_PROCESS_POSIX_STATUS_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -#elif defined(BOOST_WINDOWS_API) -#else -# error "Unsupported platform." -#endif - -#include -#include - -namespace boost { -namespace process { - -/** - * Status returned by a finalized %child process on a POSIX system. - * - * This class represents the %status returned by a child process after it - * has terminated. It contains some methods not available in the status - * class that provide information only available in POSIX systems. - */ -class posix_status : public status -{ -public: - /** - * Creates a posix_status object from an existing status object. - * - * Creates a new status object representing the exit status of a - * child process. The construction is done based on an existing - * status object which already contains all the available - * information: this class only provides controlled access to it. - */ - posix_status(const status &s) - : status(s) - { - } - - /** - * Returns whether the process exited due to an external - * signal. - */ - bool signaled() const - { - return WIFSIGNALED(flags_); - } - - /** - * If signaled, returns the terminating signal code. - * - * If the process was signaled, returns the terminating signal code. - * - * \pre signaled() is true. - */ - int term_signal() const - { - BOOST_ASSERT(signaled()); - - return WTERMSIG(flags_); - } - - /** - * If signaled, returns whether the process dumped core. - * - * If the process was signaled, returns whether the process - * produced a core dump. - * - * \pre signaled() is true. - */ - bool dumped_core() const - { - BOOST_ASSERT(signaled()); - -#ifdef WCOREDUMP - return WCOREDUMP(flags_); -#else - return false; -#endif - } - - /** - * Returns whether the process was stopped by an external - * signal. - */ - bool stopped() const - { - return WIFSTOPPED(flags_); - } - - /** - * If stopped, returns the stop signal code. - * - * If the process was stopped, returns the stop signal code. - * - * \pre stopped() is true. - */ - int stop_signal() const - { - BOOST_ASSERT(stopped()); - - return WSTOPSIG(flags_); - } -}; - -} -} - -#endif diff --git a/boost/process/postream.hpp b/boost/process/postream.hpp deleted file mode 100644 index 3bb894377..000000000 --- a/boost/process/postream.hpp +++ /dev/null @@ -1,117 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/postream.hpp - * - * Includes the declaration of the postream class. - */ - -#ifndef BOOST_PROCESS_POSTREAM_HPP -#define BOOST_PROCESS_POSTREAM_HPP - -#include -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Child process' input stream. - * - * The postream class represents an input communication channel with the - * child process. The child process reads data from this stream and the - * parent process can write to it through the postream object. In other - * words, from the child's point of view, the communication channel is an - * input one, but from the parent's point of view it is an output one; - * hence the confusing postream name. - * - * postream objects cannot be copied because they own the file handle - * they use to communicate with the child and because they buffer data - * that flows through the communication channel. - * - * A postream object behaves as a std::ostream stream in all senses. - * The class is only provided because it must provide a method to let - * the caller explicitly close the communication channel. - * - * \remark Blocking remarks: Functions that write data to this - * stream can block if the associated file handle blocks during - * the write. As this class is used to communicate with child - * processes through anonymous pipes, the most typical blocking - * condition happens when the child is not processing the data - * in the pipe's system buffer. When this happens, the buffer - * eventually fills up and the system blocks until the reader - * consumes some data, leaving some new room. - */ -class postream : public std::ostream, public boost::noncopyable -{ -public: - /** - * Creates a new process' input stream. - * - * Given a file handle, this constructor creates a new postream - * object that owns the given file handle \a fh. Ownership of - * \a fh is transferred to the created postream object. - * - * \pre \a fh is valid. - * \post \a fh is invalid. - * \post The new postream object owns \a fh. - */ - explicit postream(detail::file_handle &fh) - : std::ostream(0), - handle_(fh), - systembuf_(handle_.get()) - { - rdbuf(&systembuf_); - } - - /** - * Returns the file handle managed by this stream. - * - * The file handle must not be copied. Copying invalidates - * the source file handle making the postream unusable. - */ - detail::file_handle &handle() - { - return handle_; - } - - /** - * Closes the file handle managed by this stream. - * - * Explicitly closes the file handle managed by this stream. This - * function can be used by the user to tell the child process there - * is no more data to send. - */ - void close() - { - systembuf_.sync(); - handle_.close(); - } - -private: - /** - * The file handle managed by this stream. - */ - detail::file_handle handle_; - - /** - * The systembuf object used to manage this stream's data. - */ - detail::systembuf systembuf_; -}; - -} -} - -#endif diff --git a/boost/process/process.hpp b/boost/process/process.hpp deleted file mode 100644 index 4a4825d25..000000000 --- a/boost/process/process.hpp +++ /dev/null @@ -1,130 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/process.hpp - * - * Includes the declaration of the process class. - */ - -#ifndef BOOST_PROCESS_PROCESS_HPP -#define BOOST_PROCESS_PROCESS_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -# include -#elif defined(BOOST_WINDOWS_API) -# include -# include -#else -# error "Unsupported platform." -#endif - -#include -#include - -namespace boost { -namespace process { - -/** - * Generic implementation of the Process concept. - * - * The process class implements the Process concept in an operating system - * agnostic way. - */ -class process -{ -public: -#if defined(BOOST_PROCESS_DOXYGEN) - /** - * Opaque name for the native process' identifier type. - * - * Each operating system identifies processes using a specific type. - * The \a id_type type is used to transparently refer to a process - * regardless of the operating system in which this class is used. - * - * This type is guaranteed to be an integral type on all supported - * platforms. - */ - typedef NativeProcessId id_type; -#elif defined(BOOST_POSIX_API) - typedef pid_t id_type; -#elif defined(BOOST_WINDOWS_API) - typedef DWORD id_type; -#endif - - /** - * Constructs a new process object. - * - * Creates a new process object that represents a running process - * within the system. - */ - process(id_type id) - : id_(id) - { - } - - /** - * Returns the process' identifier. - */ - id_type get_id() const - { - return id_; - } - - /** - * Terminates the process execution. - * - * Forces the termination of the process execution. Some platforms - * allow processes to ignore some external termination notifications - * or to capture them for a proper exit cleanup. You can set the - * \a force flag to true in them to force their termination regardless - * of any exit handler. - * - * After this call, accessing this object can be dangerous because the - * process identifier may have been reused by a different process. It - * might still be valid, though, if the process has refused to die. - * - * \throw boost::system::system_error If the system call used to - * terminate the process fails. - */ - void terminate(bool force = false) const - { -#if defined(BOOST_POSIX_API) - if (::kill(id_, force ? SIGKILL : SIGTERM) == -1) - boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::process::terminate: kill(2) failed")); -#elif defined(BOOST_WINDOWS_API) - HANDLE h = ::OpenProcess(PROCESS_TERMINATE, FALSE, id_); - if (h == NULL) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: OpenProcess failed")); - if (!::TerminateProcess(h, EXIT_FAILURE)) - { - ::CloseHandle(h); - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: TerminateProcess failed")); - } - if (!::CloseHandle(h)) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: CloseHandle failed")); -#endif - } - -private: - /** - * The process' identifier. - */ - id_type id_; -}; - -} -} - -#endif diff --git a/boost/process/self.hpp b/boost/process/self.hpp deleted file mode 100644 index 8a5e85437..000000000 --- a/boost/process/self.hpp +++ /dev/null @@ -1,134 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/self.hpp - * - * Includes the declaration of the self class. - */ - -#ifndef BOOST_PROCESS_SELF_HPP -#define BOOST_PROCESS_SELF_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -#elif defined(BOOST_WINDOWS_API) -# include -#else -# error "Unsupported platform." -#endif - -#include -#include -#include -#include -#include -#include - -#if defined(BOOST_POSIX_API) -extern "C" -{ - extern char **environ; -} -#endif - -namespace boost { -namespace process { - -/** - * Generic implementation of the Process concept. - * - * The self singleton provides access to the current process. - */ -class self : public process, boost::noncopyable -{ -public: - /** - * Returns the self instance representing the caller's process. - */ - static self &get_instance() - { - static self *instance = 0; - if (!instance) - instance = new self; - return *instance; - } - - /** - * Returns the current environment. - * - * Returns the current process' environment variables. Modifying the - * returned object has no effect on the current environment. - */ - static environment get_environment() - { - environment e; - -#if defined(BOOST_POSIX_API) - char **env = ::environ; - while (*env) - { - std::string s = *env; - std::string::size_type pos = s.find('='); - e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1))); - ++env; - } -#elif defined(BOOST_WINDOWS_API) -#ifdef GetEnvironmentStrings -#undef GetEnvironmentStrings -#endif - char *environ = ::GetEnvironmentStrings(); - if (!environ) - boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::self::get_environment: GetEnvironmentStrings failed")); - try - { - char *env = environ; - while (*env) - { - std::string s = env; - std::string::size_type pos = s.find('='); - e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1))); - env += s.size() + 1; - } - } - catch (...) - { - ::FreeEnvironmentStringsA(environ); - throw; - } - ::FreeEnvironmentStringsA(environ); -#endif - - return e; - } - -private: - /** - * Constructs a new self object. - * - * Creates a new self object that represents the current process. - */ - self() : -#if defined(BOOST_POSIX_API) - process(::getpid()) -#elif defined(BOOST_WINDOWS_API) - process(::GetCurrentProcessId()) -#endif - { - } -}; - -} -} - -#endif diff --git a/boost/process/status.hpp b/boost/process/status.hpp deleted file mode 100644 index 533757a3c..000000000 --- a/boost/process/status.hpp +++ /dev/null @@ -1,105 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/status.hpp - * - * Includes the declaration of the status class. - */ - -#ifndef BOOST_PROCESS_STATUS_HPP -#define BOOST_PROCESS_STATUS_HPP - -#include - -#if defined(BOOST_POSIX_API) -# include -#elif defined(BOOST_WINDOWS_API) -#else -# error "Unsupported platform." -#endif - -#include - -namespace boost { -namespace process { - -class child; - -/** - * Status returned by a finalized %child process. - * - * This class represents the %status returned by a child process after it - * has terminated. It only provides that information available under all - * supported platforms. - * - * \see posix_status - */ -class status -{ - friend class child; - -public: - /** - * Returns whether the process exited gracefully or not. - */ - bool exited() const - { -#if defined(BOOST_POSIX_API) - return WIFEXITED(flags_); -#elif defined(BOOST_WINDOWS_API) - return true; -#endif - } - - /** - * If exited, returns the exit code. - * - * If the process exited, returns the exit code it returned. - * - * \pre exited() is true. - */ - int exit_status() const - { - BOOST_ASSERT(exited()); -#if defined(BOOST_POSIX_API) - return WEXITSTATUS(flags_); -#elif defined(BOOST_WINDOWS_API) - return flags_; -#endif - } - -protected: - /** - * Creates a status object based on exit information. - * - * Creates a new status object representing the exit status of a - * child process. - * - * \param flags In a POSIX system this parameter contains the - * flags returned by the ::waitpid() call. In a - * Windows system it contains the exit code only. - */ - status(int flags) - : flags_(flags) - { - } - - /** - * OS-specific codification of exit status. - */ - int flags_; -}; - -} -} - -#endif diff --git a/boost/process/stream_behavior.hpp b/boost/process/stream_behavior.hpp deleted file mode 100644 index 0681a7424..000000000 --- a/boost/process/stream_behavior.hpp +++ /dev/null @@ -1,234 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/stream_behavior.hpp - * - * Includes the declaration of the stream_behavior class and associated - * free functions. - */ - -#ifndef BOOST_PROCESS_STREAM_BEHAVIOR_HPP -#define BOOST_PROCESS_STREAM_BEHAVIOR_HPP - -#include - -namespace boost { -namespace process { - -namespace detail { - struct stream_info; -} - -/** - * Describes the possible states for a communication stream. - */ -class stream_behavior -{ -public: - friend struct detail::stream_info; - friend stream_behavior capture_stream(); - friend stream_behavior close_stream(); - friend stream_behavior inherit_stream(); - friend stream_behavior redirect_stream_to_stdout(); - friend stream_behavior silence_stream(); -#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) - friend stream_behavior posix_redirect_stream(int to); -#endif - - /** - * Describes the possible states for a communication stream. - */ - enum type - { - /** - * The child's stream is connected to the parent by using an - * anonymous pipe so that they can send and receive data to/from - * each other. - */ - capture, - - /** - * The child's stream is closed upon startup so that it will not - * have any access to it. - */ - close, - - /** - * The child's stream is connected to the same stream used by the - * parent. In other words, the corresponding parent's stream is - * inherited. - */ - inherit, - - /** - * The child's stream is connected to child's standard output. - * This is typically used when configuring the standard error - * stream. - */ - redirect_to_stdout, - - /** - * The child's stream is redirected to a null device so that its - * input is always zero or its output is lost, depending on - * whether the stream is an input or an output one. It is - * important to notice that this is different from close because - * the child is still able to write data. If we closed, e.g. - * stdout, the child might not work at all! - */ - silence, - -#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) - /** - * The child redirects the stream's output to the provided file - * descriptor. This is a generalization of the portable - * redirect_to_stdout behavior. - */ - posix_redirect -#endif - }; - - /** - * Constructs a new stream behavior of type close. - * - * The public constructor creates a new stream behavior that defaults - * to the close behavior. In general, you will want to use the - * available free functions to construct a stream behavior (including - * the close one). - */ - stream_behavior() - : type_(stream_behavior::close) - { - } - - /** - * Returns this stream's behavior type. - */ - type get_type() const - { - return type_; - } - -private: - /** - * Constructs a new stream behavior of type \a t. - * - * Constructs a new stream behavior of type \a t. It is the - * responsibility of the caller to fill in any other attributes - * required by the specified type, if any. - */ - stream_behavior(type t) - : type_(t) - { - } - - /** - * This stream's behavior type. - */ - type type_; - -#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) - /** - * File descriptor the stream is redirected to. - */ - int desc_to_; -#endif -}; - -/** - * Creates a new stream_behavior of type stream_behavior::capture. - * - * Creates a new stream_behavior of type stream_behavior::capture, - * meaning that the child's stream is connected to the parent by using an - * anonymous pipe so that they can send and receive data to/from each - * other. - */ -inline stream_behavior capture_stream() -{ - return stream_behavior(stream_behavior::capture); -} - -/** - * Creates a new stream_behavior of type stream_behavior::close. - * - * Creates a new stream_behavior of type stream_behavior::close, - * meaning that the child's stream is closed upon startup so that it - * will not have any access to it. - */ -inline stream_behavior close_stream() -{ - return stream_behavior(stream_behavior::close); -} - -/** - * Creates a new stream_behavior of type stream_behavior::inherit. - * - * Creates a new stream_behavior of type stream_behavior::inherit, - * meaning that the child's stream is connected to the same stream used - * by the parent. In other words, the corresponding parent's stream is - * inherited. - */ -inline stream_behavior inherit_stream() -{ - return stream_behavior(stream_behavior::inherit); -} - -/** - * Creates a new stream_behavior of type - * stream_behavior::redirect_to_stdout. - * - * Creates a new stream_behavior of type - * stream_behavior::redirect_to_stdout, meaning that the child's stream is - * connected to child's standard output. This is typically used when - * configuring the standard error stream. - */ -inline stream_behavior redirect_stream_to_stdout() -{ - return stream_behavior(stream_behavior::redirect_to_stdout); -} - -/** - * Creates a new stream_behavior of type stream_behavior::silence. - * - * Creates a new stream_behavior of type stream_behavior::silence, - * meaning that the child's stream is redirected to a null device so that - * its input is always zero or its output is lost, depending on whether - * the stream is an input or an output one. It is important to notice - * that this is different from close because the child is still able to - * write data. If we closed, e.g. stdout, the child might not work at - * all! - */ -inline stream_behavior silence_stream() -{ - return stream_behavior(stream_behavior::silence); -} - -#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) -/** - * Creates a new stream_behavior of type stream_behavior::posix_redirect. - * - * Creates a new stream_behavior of type stream_behavior::posix_redirect, - * meaning that the child's stream is redirected to the \a to child's - * file descriptor. This is a generalization of the portable - * redirect_stream_to_stdout() behavior. - */ -inline stream_behavior posix_redirect_stream(int to) -{ - stream_behavior sb(stream_behavior::posix_redirect); - sb.desc_to_ = to; - return sb; -} -#endif - -} -} - -#endif diff --git a/boost/process/win32_child.hpp b/boost/process/win32_child.hpp deleted file mode 100644 index e4f0ed7e3..000000000 --- a/boost/process/win32_child.hpp +++ /dev/null @@ -1,128 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/win32_child.hpp - * - * Includes the declaration of the win32_child class. - */ - -#ifndef BOOST_PROCESS_WIN32_CHILD_HPP -#define BOOST_PROCESS_WIN32_CHILD_HPP - -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Windows implementation of the Child concept. - * - * The win32_child class implements the Child concept in a Windows - * operating system. - * - * A Windows child differs from a regular %child (represented by a - * child object) in that it holds additional information about a process. - * Aside from the standard handle, it also includes a handle to the - * process' main thread, together with identifiers to both entities. - * - * This class is built on top of the generic child so as to allow its - * trivial adoption. When a program is changed to use the - * Windows-specific context (win32_context), it will most certainly need - * to migrate its use of the child class to win32_child. Doing so is only - * a matter of redefining the appropriate object and later using the - * required extra features: there should be no need to modify the existing - * code (e.g. method calls) in any other way. - */ -class win32_child : public child -{ -public: - /** - * Constructs a new Windows child object representing a just - * spawned %child process. - * - * Creates a new %child object that represents the process described by - * the \a pi structure. - * - * The \a fhstdin, \a fhstdout and \a fhstderr parameters hold the - * communication streams used to interact with the %child process if - * the launcher configured redirections. See the parent class' - * constructor for more details on these. - * - * \see child - */ - win32_child(const PROCESS_INFORMATION &pi, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr) - : child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, pi.hProcess), - process_information_(pi), - thread_handle_(process_information_.hThread) - { - } - - /** - * Returns the process handle. - * - * Returns a process-specific handle that can be used to access the - * process. This is the value of the \a hProcess field in the - * PROCESS_INFORMATION structure returned by CreateProcess(). - * - * \see get_id() - */ - HANDLE get_handle() const - { - return process_information_.hProcess; - } - - /** - * Returns the primary thread's handle. - * - * Returns a handle to the primary thread of the new process. This is - * the value of the \a hThread field in the PROCESS_INFORMATION - * structure returned by CreateProcess(). - * - * \see get_primary_thread_id() - */ - HANDLE get_primary_thread_handle() const - { - return process_information_.hThread; - } - - /** - * Returns the primary thread's identifier. - * - * Returns a system-wide value that identifies the process's primary - * thread. This is the value of the \a dwThreadId field in the - * PROCESS_INFORMATION structure returned by CreateProcess(). - * - * \see get_primary_thread_handle() - */ - DWORD get_primary_thread_id() const - { - return process_information_.dwThreadId; - } - -private: - /** - * Windows-specific process information. - */ - PROCESS_INFORMATION process_information_; - - /** - * Thread handle owned by RAII object. - */ - detail::file_handle thread_handle_; -}; - -} -} - -#endif diff --git a/boost/process/win32_context.hpp b/boost/process/win32_context.hpp deleted file mode 100644 index 630fd305f..000000000 --- a/boost/process/win32_context.hpp +++ /dev/null @@ -1,61 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/win_32context.hpp - * - * Includes the declaration of the win32_context class. - */ - -#ifndef BOOST_PROCESS_WIN32_CONTEXT_HPP -#define BOOST_PROCESS_WIN32_CONTEXT_HPP - -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Generic implementation of the Context concept. - * - * The context class implements the Context concept in an operating - * system agnostic way; it allows spawning new child processes using - * a single and common interface across different systems. - */ -template -class win32_basic_context : public basic_context -{ -public: - /** - * Initializes the Win32-specific process startup information with NULL. - */ - win32_basic_context() - : startupinfo(NULL) - { - } - - /** - * Win32-specific process startup information. - */ - STARTUPINFOA *startupinfo; -}; - -/** - * Default instantiation of win32_basic_context. - */ -typedef win32_basic_context win32_context; - -} -} - -#endif diff --git a/boost/process/win32_operations.hpp b/boost/process/win32_operations.hpp deleted file mode 100644 index 092e9a368..000000000 --- a/boost/process/win32_operations.hpp +++ /dev/null @@ -1,77 +0,0 @@ -// -// Boost.Process -// ~~~~~~~~~~~~~ -// -// Copyright (c) 2006, 2007 Julio M. Merino Vidal -// Copyright (c) 2008, 2009 Boris Schaeling -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -/** - * \file boost/process/win32_operations.hpp - * - * Provides miscellaneous free functions specific to Windows operating - * systems. - */ - -#ifndef BOOST_PROCESS_WIN32_OPERATIONS_HPP -#define BOOST_PROCESS_WIN32_OPERATIONS_HPP - -#include -#include -#include -#include -#include - -namespace boost { -namespace process { - -/** - * Starts a new child process. - * - * Given an executable and the set of arguments passed to it, starts - * a new process with all the parameters configured in the context. - * The context can be reused afterwards to launch other different - * processes. - * - * \return A handle to the new child process. - */ -template -inline win32_child win32_launch(const Executable &exe, const Arguments &args, const Win32_Context &ctx) -{ - detail::file_handle fhstdin, fhstdout, fhstderr; - - detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false); - if (behin.type_ == detail::stream_info::use_pipe) - fhstdin = behin.pipe_->wend(); - detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true); - if (behout.type_ == detail::stream_info::use_pipe) - fhstdout = behout.pipe_->rend(); - detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true); - if (beherr.type_ == detail::stream_info::use_pipe) - fhstderr = beherr.pipe_->rend(); - - detail::win32_setup s; - s.work_directory = ctx.work_directory; - - STARTUPINFOA si; - if (!ctx.startupinfo) - { - ::ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - s.startupinfo = &si; - } - else - s.startupinfo = ctx.startupinfo; - - PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s); - - return win32_child(pi, fhstdin, fhstdout, fhstderr); -} - -} -} - -#endif diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 000000000..71ca04136 --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,2364 @@ +# Doxyfile 1.8.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Ethereum + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = PoC-8 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "The C++ Implementation of Ethereum" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = gavcoin.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = ../libdevcore \ + ../libdevcrypto \ + ../libethcore \ + ../libethereum \ + ../libevmface \ + ../libevm \ + ../liblll \ + ../libsolidity \ + ../mix \ + ../libwhisper \ + ../libwebthree + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.as \ + *.js + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /