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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] - 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] - 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] * 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] (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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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/403] 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 6d48f3e98764fff270397fc00d37f9c6328294fd Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 17 Dec 2014 18:53:18 +0100 Subject: [PATCH 368/403] Work in progress for /** ... */ natspec comments - Work in progress on the scanner for recognizing the second type of doxygen comments for Natspec. --- libsolidity/Scanner.cpp | 58 +++++++++++++++++++++++++++++++++++++--- libsolidity/Scanner.h | 3 ++- test/solidityScanner.cpp | 7 +++++ 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 1a21149a1..2e9b7b454 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -219,7 +219,7 @@ Token::Value Scanner::skipSingleLineComment() return Token::WHITESPACE; } -Token::Value Scanner::scanDocumentationComment() +Token::Value Scanner::scanSingleLineDocComment() { LiteralScope literal(this, LITERAL_TYPE_COMMENT); advance(); //consume the last '/' @@ -250,7 +250,6 @@ Token::Value Scanner::scanDocumentationComment() Token::Value Scanner::skipMultiLineComment() { - solAssert(m_char == '*', ""); advance(); while (!isSourcePastEndOfInput()) { @@ -270,6 +269,43 @@ Token::Value Scanner::skipMultiLineComment() return Token::ILLEGAL; } +Token::Value Scanner::scanMultiLineDocComment() +{ + LiteralScope literal(this, LITERAL_TYPE_COMMENT); + bool endFound = false; + + advance(); //consume the last '*' + while (!isSourcePastEndOfInput()) + { + // skip starting '*' in multiine comments + if (isLineTerminator(m_char)) + { + skipWhitespace(); + if (!m_source.isPastEndOfInput(2) && m_source.get(1) == '*' && m_source.get(2) != '/') + { + addCommentLiteralChar('\n'); + m_char = m_source.advanceAndGet(3); + } + else + addCommentLiteralChar('\n'); + } + + if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '/') + { + m_source.advanceAndGet(2); + endFound = true; + break; + } + addCommentLiteralChar(m_char); + advance(); + } + literal.complete(); + if (!endFound) + return Token::ILLEGAL; + else + return Token::COMMENT_LITERAL; +} + void Scanner::scanToken() { m_nextToken.literal.clear(); @@ -381,7 +417,7 @@ void Scanner::scanToken() { Token::Value comment; m_nextSkippedComment.location.start = getSourcePos(); - comment = scanDocumentationComment(); + comment = scanSingleLineDocComment(); m_nextSkippedComment.location.end = getSourcePos(); m_nextSkippedComment.token = comment; token = Token::WHITESPACE; @@ -390,7 +426,21 @@ void Scanner::scanToken() token = skipSingleLineComment(); } else if (m_char == '*') - token = skipMultiLineComment(); + { + if (!advance()) /* slash star comment before EOS */ + token = Token::WHITESPACE; + else if (m_char == '*') + { + Token::Value comment; + m_nextSkippedComment.location.start = getSourcePos(); + comment = scanMultiLineDocComment(); + m_nextSkippedComment.location.end = getSourcePos(); + m_nextSkippedComment.token = comment; + token = Token::WHITESPACE; + } + else + token = skipMultiLineComment(); + } else if (m_char == '=') token = selectToken(Token::ASSIGN_DIV); else diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 18b1f5d3a..7f1b18352 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -190,7 +190,8 @@ private: Token::Value scanIdentifierOrKeyword(); Token::Value scanString(); - Token::Value scanDocumentationComment(); + Token::Value scanSingleLineDocComment(); + Token::Value scanMultiLineDocComment(); /// Scans an escape-sequence which is part of a string and adds the /// decoded character to the current literal. Returns true if a pattern diff --git a/test/solidityScanner.cpp b/test/solidityScanner.cpp index 573affe6d..2b8c7c458 100644 --- a/test/solidityScanner.cpp +++ b/test/solidityScanner.cpp @@ -160,6 +160,13 @@ BOOST_AUTO_TEST_CASE(documentation_comments_parsed_begin) BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), " Send $(value / 1000) chocolates to the user"); } +BOOST_AUTO_TEST_CASE(multiline_documentation_comments_parsed_begin) +{ + Scanner scanner(CharStream("/** Send $(value / 1000) chocolates to the user*/")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::EOS); + BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), " Send $(value / 1000) chocolates to the user"); +} + BOOST_AUTO_TEST_CASE(documentation_comments_parsed) { Scanner scanner(CharStream("some other tokens /// Send $(value / 1000) chocolates to the user")); From 61a1f4436c5561a6c521b9c6009c57c76d275adb Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 18 Dec 2014 13:27:25 +0100 Subject: [PATCH 369/403] Scanner properly scans multiline natspec comments - Single and multiline natspect comments get the initial whitespace skipped now - Some rules introduced for the multiline comments. If first line is empty then no newline is added to the literal. Same thing with the last line. Finally in all lines initial '*' are skipped --- libsolidity/Scanner.cpp | 36 ++++++++++++++++++++++++++++-------- libsolidity/Scanner.h | 2 ++ test/solidityScanner.cpp | 25 ++++++++++++++++++++++--- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 2e9b7b454..890d69494 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -209,6 +209,15 @@ bool Scanner::skipWhitespace() return getSourcePos() != startPosition; } +bool Scanner::skipWhitespaceExceptLF() +{ + int const startPosition = getSourcePos(); + while (m_char == ' ' || m_char == '\t') + advance(); + // Return whether or not we skipped any characters. + return getSourcePos() != startPosition; +} + Token::Value Scanner::skipSingleLineComment() { // The line terminator at the end of the line is not considered @@ -222,7 +231,8 @@ Token::Value Scanner::skipSingleLineComment() Token::Value Scanner::scanSingleLineDocComment() { LiteralScope literal(this, LITERAL_TYPE_COMMENT); - advance(); //consume the last '/' + advance(); //consume the last '/' at /// + skipWhitespaceExceptLF(); while (!isSourcePastEndOfInput()) { if (isLineTerminator(m_char)) @@ -273,18 +283,27 @@ Token::Value Scanner::scanMultiLineDocComment() { LiteralScope literal(this, LITERAL_TYPE_COMMENT); bool endFound = false; + bool charsAdded = false; - advance(); //consume the last '*' + advance(); //consume the last '*' at /** + skipWhitespaceExceptLF(); while (!isSourcePastEndOfInput()) { - // skip starting '*' in multiine comments + //handle newlines in multline comments if (isLineTerminator(m_char)) { skipWhitespace(); - if (!m_source.isPastEndOfInput(2) && m_source.get(1) == '*' && m_source.get(2) != '/') - { - addCommentLiteralChar('\n'); - m_char = m_source.advanceAndGet(3); + if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) != '/') + { // skip first '*' in subsequent lines + if (charsAdded) + addCommentLiteralChar('\n'); + m_char = m_source.advanceAndGet(2); + } + else if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '/') + { // if after newline the comment ends, don't insert the newline + m_char = m_source.advanceAndGet(2); + endFound = true; + break; } else addCommentLiteralChar('\n'); @@ -292,11 +311,12 @@ Token::Value Scanner::scanMultiLineDocComment() if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '/') { - m_source.advanceAndGet(2); + m_char = m_source.advanceAndGet(2); endFound = true; break; } addCommentLiteralChar(m_char); + charsAdded = true; advance(); } literal.complete(); diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 7f1b18352..5e70db51d 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -182,6 +182,8 @@ private: /// Skips all whitespace and @returns true if something was skipped. bool skipWhitespace(); + /// Skips all whitespace except Line feeds and returns true if something was skipped + bool skipWhitespaceExceptLF(); Token::Value skipSingleLineComment(); Token::Value skipMultiLineComment(); diff --git a/test/solidityScanner.cpp b/test/solidityScanner.cpp index 2b8c7c458..159e53055 100644 --- a/test/solidityScanner.cpp +++ b/test/solidityScanner.cpp @@ -157,14 +157,14 @@ BOOST_AUTO_TEST_CASE(documentation_comments_parsed_begin) { Scanner scanner(CharStream("/// Send $(value / 1000) chocolates to the user")); BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::EOS); - BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), " Send $(value / 1000) chocolates to the user"); + BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "Send $(value / 1000) chocolates to the user"); } BOOST_AUTO_TEST_CASE(multiline_documentation_comments_parsed_begin) { Scanner scanner(CharStream("/** Send $(value / 1000) chocolates to the user*/")); BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::EOS); - BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), " Send $(value / 1000) chocolates to the user"); + BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "Send $(value / 1000) chocolates to the user"); } BOOST_AUTO_TEST_CASE(documentation_comments_parsed) @@ -174,7 +174,19 @@ BOOST_AUTO_TEST_CASE(documentation_comments_parsed) BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); - BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), " Send $(value / 1000) chocolates to the user"); + BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "Send $(value / 1000) chocolates to the user"); +} + +BOOST_AUTO_TEST_CASE(multiline_documentation_comments_parsed) +{ + Scanner scanner(CharStream("some other tokens /**\n" + "* Send $(value / 1000) chocolates to the user\n" + "*/")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "Send $(value / 1000) chocolates to the user"); } BOOST_AUTO_TEST_CASE(comment_before_eos) @@ -191,6 +203,13 @@ BOOST_AUTO_TEST_CASE(documentation_comment_before_eos) BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), ""); } +BOOST_AUTO_TEST_CASE(empty_multiline_documentation_comment_before_eos) +{ + Scanner scanner(CharStream("/***/")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::EOS); + BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), ""); +} + BOOST_AUTO_TEST_CASE(comments_mixed_in_sequence) { Scanner scanner(CharStream("hello_world ///documentation comment \n" From 30beaca35955476ef07ee1f9c82735b0d63241bf Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 18 Dec 2014 14:43:35 +0100 Subject: [PATCH 370/403] Changes in InterfaceHandler to deal with multiline natspec - Also now Solidity scanner considers Carriage Return as whitespace - Tests for Natspec generation with the new multiline comments --- libsolidity/InterfaceHandler.cpp | 46 +++++++++++++------------------- libsolidity/InterfaceHandler.h | 3 ++- libsolidity/Scanner.cpp | 2 +- test/solidityNatspecJSON.cpp | 29 ++++++++++++++++++++ 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index c734fa38c..9ae284b40 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -166,9 +166,12 @@ static inline std::string::const_iterator skipLineOrEOS(std::string::const_itera std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos, std::string::const_iterator _end, std::string& _tagString, - DocTagType _tagType) + DocTagType _tagType, + bool _appending) { auto nlPos = std::find(_pos, _end, '\n'); + if (_appending && *_pos != ' ') + _tagString += " "; std::copy(_pos, nlPos, back_inserter(_tagString)); m_lastTag = _tagType; return skipLineOrEOS(nlPos, _end); @@ -201,7 +204,8 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con solAssert(!m_params.empty(), "Internal: Tried to append to empty parameter"); auto pair = m_params.back(); - pair.second += " "; + if (*_pos != ' ') + pair.second += " "; auto nlPos = std::find(_pos, _end, '\n'); std::copy(_pos, nlPos, back_inserter(pair.second)); @@ -221,17 +225,17 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite if (m_lastTag == DocTagType::NONE || _tag != "") { if (_tag == "dev") - return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV); + return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV, false); else if (_tag == "notice") - return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE); + return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE, false); else if (_tag == "return") - return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN); + return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN, false); else if (_tag == "author") { if (_owner == CommentOwner::CONTRACT) - return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR); + return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR, false); else if (_owner == CommentOwner::FUNCTION) - return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR); + return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR, false); else // LTODO: for now this else makes no sense but later comments will go to more language constructs BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag is legal only for contracts")); @@ -239,7 +243,7 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite else if (_tag == "title") { if (_owner == CommentOwner::CONTRACT) - return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE); + return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE, false); else // LTODO: Unknown tag, throw some form of warning and not just an exception BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag is legal only for contracts")); @@ -261,34 +265,22 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it switch (m_lastTag) { case DocTagType::DEV: - m_dev += " "; - return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV); + return parseDocTagLine(_pos, _end, m_dev, DocTagType::DEV, true); case DocTagType::NOTICE: - m_notice += " "; - return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE); + return parseDocTagLine(_pos, _end, m_notice, DocTagType::NOTICE, true); case DocTagType::RETURN: - m_return += " "; - return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN); + return parseDocTagLine(_pos, _end, m_return, DocTagType::RETURN, true); case DocTagType::AUTHOR: if (_owner == CommentOwner::CONTRACT) - { - m_contractAuthor += " "; - return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR); - } + return parseDocTagLine(_pos, _end, m_contractAuthor, DocTagType::AUTHOR, true); else if (_owner == CommentOwner::FUNCTION) - { - m_author += " "; - return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR); - } + return parseDocTagLine(_pos, _end, m_author, DocTagType::AUTHOR, true); else // LTODO: Unknown tag, throw some form of warning and not just an exception BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@author tag in illegal comment")); case DocTagType::TITLE: if (_owner == CommentOwner::CONTRACT) - { - m_title += " "; - return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE); - } + return parseDocTagLine(_pos, _end, m_title, DocTagType::TITLE, true); else // LTODO: Unknown tag, throw some form of warning and not just an exception BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("@title tag in illegal comment")); @@ -329,7 +321,7 @@ void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _ currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner); } else if (m_lastTag != DocTagType::NONE) // continuation of the previous tag - currPos = appendDocTag(currPos + 1, end, _owner); + currPos = appendDocTag(currPos, end, _owner); else if (currPos != end) // skip the line if a newline was found currPos = nlPos + 1; } diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index d271a6697..c8399d71f 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -92,7 +92,8 @@ private: std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos, std::string::const_iterator _end, std::string& _tagString, - DocTagType _tagType); + DocTagType _tagType, + bool _appending); std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos, std::string::const_iterator _end); std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos, diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 890d69494..69b61ce4b 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -80,7 +80,7 @@ bool isLineTerminator(char c) } bool isWhiteSpace(char c) { - return c == ' ' || c == '\n' || c == '\t'; + return c == ' ' || c == '\n' || c == '\t' || c == '\r'; } bool isIdentifierStart(char c) { diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index 2c3ded08d..5b48a67ce 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -394,6 +394,35 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return) checkNatspec(sourceCode, natspec, false); } +BOOST_AUTO_TEST_CASE(dev_multiline_comment) +{ + char const* sourceCode = "contract test {\n" + " /**\n" + " * @dev Multiplies a number by 7 and adds second parameter\n" + " * @param a Documentation for the first parameter starts here.\n" + " * Since it's a really complicated parameter we need 2 lines\n" + " * @param second Documentation for the second parameter\n" + " * @return The result of the multiplication\n" + " * and cookies with nutella\n" + " */" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" + " \"params\": {\n" + " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" + " \"second\": \"Documentation for the second parameter\"\n" + " },\n" + " \"return\": \"The result of the multiplication and cookies with nutella\"\n" + " }\n" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} + BOOST_AUTO_TEST_CASE(dev_contract_no_doc) { char const* sourceCode = "contract test {\n" From 0b5b6c7cd40adc20944067bca42a9434c70a51d1 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 18 Dec 2014 16:27:17 +0100 Subject: [PATCH 371/403] Adressing some natspec issues --- libsolidity/InterfaceHandler.cpp | 4 ++-- libsolidity/Scanner.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 9ae284b40..5b5682ff1 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -170,7 +170,7 @@ std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const bool _appending) { auto nlPos = std::find(_pos, _end, '\n'); - if (_appending && *_pos != ' ') + if (_appending && _pos < _end && *_pos != ' ') _tagString += " "; std::copy(_pos, nlPos, back_inserter(_tagString)); m_lastTag = _tagType; @@ -204,7 +204,7 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con solAssert(!m_params.empty(), "Internal: Tried to append to empty parameter"); auto pair = m_params.back(); - if (*_pos != ' ') + if (_pos < _end && *_pos != ' ') pair.second += " "; auto nlPos = std::find(_pos, _end, '\n'); std::copy(_pos, nlPos, back_inserter(pair.second)); diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 69b61ce4b..90a3b4545 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -328,6 +328,7 @@ Token::Value Scanner::scanMultiLineDocComment() void Scanner::scanToken() { + int savedPosition; m_nextToken.literal.clear(); m_nextSkippedComment.literal.clear(); Token::Value token; @@ -428,6 +429,7 @@ void Scanner::scanToken() break; case '/': // / // /* /= + savedPosition = getSourcePos(); advance(); if (m_char == '/') { @@ -436,7 +438,7 @@ void Scanner::scanToken() else if (m_char == '/') { Token::Value comment; - m_nextSkippedComment.location.start = getSourcePos(); + m_nextSkippedComment.location.start = savedPosition; comment = scanSingleLineDocComment(); m_nextSkippedComment.location.end = getSourcePos(); m_nextSkippedComment.token = comment; @@ -447,12 +449,13 @@ void Scanner::scanToken() } else if (m_char == '*') { + // /** doxygent style natspec comment if (!advance()) /* slash star comment before EOS */ token = Token::WHITESPACE; else if (m_char == '*') { Token::Value comment; - m_nextSkippedComment.location.start = getSourcePos(); + m_nextSkippedComment.location.start = savedPosition; comment = scanMultiLineDocComment(); m_nextSkippedComment.location.end = getSourcePos(); m_nextSkippedComment.token = comment; From 73593674419a4c2e2aea7a03a554b5577aa31405 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 18 Dec 2014 16:48:25 +0100 Subject: [PATCH 372/403] More multiline natspec tests and small issue fix --- libsolidity/Scanner.cpp | 4 ++-- test/solidityScanner.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 90a3b4545..124c88d92 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -212,7 +212,7 @@ bool Scanner::skipWhitespace() bool Scanner::skipWhitespaceExceptLF() { int const startPosition = getSourcePos(); - while (m_char == ' ' || m_char == '\t') + while (isWhiteSpace(m_char) && !isLineTerminator(m_char)) advance(); // Return whether or not we skipped any characters. return getSourcePos() != startPosition; @@ -305,7 +305,7 @@ Token::Value Scanner::scanMultiLineDocComment() endFound = true; break; } - else + else if (charsAdded) addCommentLiteralChar('\n'); } diff --git a/test/solidityScanner.cpp b/test/solidityScanner.cpp index 159e53055..355ea9e22 100644 --- a/test/solidityScanner.cpp +++ b/test/solidityScanner.cpp @@ -189,6 +189,30 @@ BOOST_AUTO_TEST_CASE(multiline_documentation_comments_parsed) BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "Send $(value / 1000) chocolates to the user"); } +BOOST_AUTO_TEST_CASE(multiline_documentation_no_stars) +{ + Scanner scanner(CharStream("some other tokens /**\n" + " Send $(value / 1000) chocolates to the user\n" + "*/")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "Send $(value / 1000) chocolates to the user"); +} + +BOOST_AUTO_TEST_CASE(multiline_documentation_whitespace_hell) +{ + Scanner scanner(CharStream("some other tokens /** \t \r \n" + "\t \r * Send $(value / 1000) chocolates to the user\n" + "*/")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "Send $(value / 1000) chocolates to the user"); +} + BOOST_AUTO_TEST_CASE(comment_before_eos) { Scanner scanner(CharStream("//")); From b162e267acee2654e000a71af05b5d93db0d613f Mon Sep 17 00:00:00 2001 From: ethdev Date: Thu, 18 Dec 2014 17:10:00 +0100 Subject: [PATCH 373/403] windows fixes --- libserpent/compiler.cpp | 2 +- libserpent/rewriteutils.cpp | 1 + libserpent/util.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libserpent/compiler.cpp b/libserpent/compiler.cpp index a3e5b1c60..886eee6df 100644 --- a/libserpent/compiler.cpp +++ b/libserpent/compiler.cpp @@ -173,7 +173,7 @@ programData opcodeify(Node node, } // Comments do nothing else if (node.val == "comment") { - Node nodelist[] = { }; + Node* nodelist = nullptr; return pd(aux, multiToken(nodelist, 0, m), 0); } // Custom operation sequence diff --git a/libserpent/rewriteutils.cpp b/libserpent/rewriteutils.cpp index 0d810bdbc..e6429434a 100644 --- a/libserpent/rewriteutils.cpp +++ b/libserpent/rewriteutils.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "util.h" #include "lllparser.h" #include "bignum.h" diff --git a/libserpent/util.cpp b/libserpent/util.cpp index 5e83c0e41..4b99a5ea5 100644 --- a/libserpent/util.cpp +++ b/libserpent/util.cpp @@ -5,6 +5,7 @@ #include "util.h" #include "bignum.h" #include +#include #include //Token or value node constructor From d14ed2d4dc29afcce8c16a0173d7a4e87b2c5974 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 18 Dec 2014 17:04:20 +0100 Subject: [PATCH 374/403] 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 49f60a1d6d0b93fad28cea57e03beb261d9f09b1 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 18 Dec 2014 17:30:10 +0100 Subject: [PATCH 375/403] Factoring forward slash scanning out to its own function --- libsolidity/Scanner.cpp | 85 ++++++++++++++++++++++------------------- libsolidity/Scanner.h | 2 + 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 124c88d92..f22e69bc8 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -326,9 +326,52 @@ Token::Value Scanner::scanMultiLineDocComment() return Token::COMMENT_LITERAL; } +Token::Value Scanner::scanSlash() +{ + int firstSlashPosition = getSourcePos(); + advance(); + if (m_char == '/') + { + if (!advance()) /* double slash comment directly before EOS */ + return Token::WHITESPACE; + else if (m_char == '/') + { + // doxygen style /// comment + Token::Value comment; + m_nextSkippedComment.location.start = firstSlashPosition; + comment = scanSingleLineDocComment(); + m_nextSkippedComment.location.end = getSourcePos(); + m_nextSkippedComment.token = comment; + return Token::WHITESPACE; + } + else + return skipSingleLineComment(); + } + else if (m_char == '*') + { + // doxygen style /** natspec comment + if (!advance()) /* slash star comment before EOS */ + return Token::WHITESPACE; + else if (m_char == '*') + { + Token::Value comment; + m_nextSkippedComment.location.start = firstSlashPosition; + comment = scanMultiLineDocComment(); + m_nextSkippedComment.location.end = getSourcePos(); + m_nextSkippedComment.token = comment; + return Token::WHITESPACE; + } + else + return skipMultiLineComment(); + } + else if (m_char == '=') + return selectToken(Token::ASSIGN_DIV); + else + return Token::DIV; +} + void Scanner::scanToken() { - int savedPosition; m_nextToken.literal.clear(); m_nextSkippedComment.literal.clear(); Token::Value token; @@ -429,45 +472,7 @@ void Scanner::scanToken() break; case '/': // / // /* /= - savedPosition = getSourcePos(); - advance(); - if (m_char == '/') - { - if (!advance()) /* double slash comment directly before EOS */ - token = Token::WHITESPACE; - else if (m_char == '/') - { - Token::Value comment; - m_nextSkippedComment.location.start = savedPosition; - comment = scanSingleLineDocComment(); - m_nextSkippedComment.location.end = getSourcePos(); - m_nextSkippedComment.token = comment; - token = Token::WHITESPACE; - } - else - token = skipSingleLineComment(); - } - else if (m_char == '*') - { - // /** doxygent style natspec comment - if (!advance()) /* slash star comment before EOS */ - token = Token::WHITESPACE; - else if (m_char == '*') - { - Token::Value comment; - m_nextSkippedComment.location.start = savedPosition; - comment = scanMultiLineDocComment(); - m_nextSkippedComment.location.end = getSourcePos(); - m_nextSkippedComment.token = comment; - token = Token::WHITESPACE; - } - else - token = skipMultiLineComment(); - } - else if (m_char == '=') - token = selectToken(Token::ASSIGN_DIV); - else - token = Token::DIV; + token = scanSlash(); break; case '&': // & && &= diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 5e70db51d..5b90a94eb 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -194,6 +194,8 @@ private: Token::Value scanString(); Token::Value scanSingleLineDocComment(); Token::Value scanMultiLineDocComment(); + /// Scans a slash '/' and depending on the characters returns the appropriate token + Token::Value scanSlash(); /// Scans an escape-sequence which is part of a string and adds the /// decoded character to the current literal. Returns true if a pattern From ae994f28043065ef9ff8c3a2835a69389a495029 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 18 Dec 2014 17:49:11 +0100 Subject: [PATCH 376/403] 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 4165e45464eaec9ed8f62d2571f2a10111599376 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 18 Dec 2014 18:16:43 +0100 Subject: [PATCH 377/403] updating solidity parser natspec tests to comply with recent changes --- test/SolidityParser.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index f978cdd9b..c14c05122 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation) BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); BOOST_REQUIRE_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is a test function"); + BOOST_CHECK_EQUAL(*function->getDocumentation(), "This is a test function"); } BOOST_AUTO_TEST_CASE(function_normal_comments) @@ -166,17 +166,17 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) auto functions = contract->getDefinedFunctions(); BOOST_REQUIRE_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 1"); + BOOST_CHECK_EQUAL(*function->getDocumentation(), "This is test function 1"); BOOST_REQUIRE_NO_THROW(function = functions.at(1)); - BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 2"); + BOOST_CHECK_EQUAL(*function->getDocumentation(), "This is test function 2"); BOOST_REQUIRE_NO_THROW(function = functions.at(2)); BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr, "Should not have gotten natspec comment for functionName3()"); BOOST_REQUIRE_NO_THROW(function = functions.at(3)); - BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 4"); + BOOST_CHECK_EQUAL(*function->getDocumentation(), "This is test function 4"); } BOOST_AUTO_TEST_CASE(multiline_function_documentation) @@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) BOOST_REQUIRE_NO_THROW(function = functions.at(0)); BOOST_CHECK_EQUAL(*function->getDocumentation(), - " This is a test function\n" + "This is a test function\n" " and it has 2 lines"); } @@ -220,11 +220,11 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) auto functions = contract->getDefinedFunctions(); BOOST_REQUIRE_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation(), " fun1 description"); + BOOST_CHECK_EQUAL(*function->getDocumentation(), "fun1 description"); BOOST_REQUIRE_NO_THROW(function = functions.at(1)); BOOST_CHECK_EQUAL(*function->getDocumentation(), - " This is a test function\n" + "This is a test function\n" " and it has 2 lines"); } From 672c1ca15b5d749609ef8c68267fe58e9a69e6e8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Dec 2014 18:44:55 +0100 Subject: [PATCH 378/403] Version 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 55250b418..1de7ef957 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.12"; +char const* Version = "0.7.13"; } diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 5e510572e..ff5e6aed0 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 = 50; const unsigned c_databaseVersion = 5; static const vector> g_units = From fce7f1712d32bb3f3c0c56078201adda4541be2b Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 18 Dec 2014 21:43:40 +0100 Subject: [PATCH 379/403] 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 380/403] 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 381/403] 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 382/403] 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 383/403] 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 384/403] 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 385/403] 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 386/403] 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 387/403] 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 388/403] 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 389/403] 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 390/403] 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 391/403] 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 392/403] 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 +# , /