From f5eda1f1b32e97f62b5f80b38fe974ccaf4c5a0b 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 001/466] Moving Compiler to separated files --- evmcc/CMakeLists.txt | 49 ++++++++++++++++++++++ evmcc/Compiler.cpp | 75 +++++++++++++++++++++++++++++++++ evmcc/Compiler.h | 34 +++++++++++++++ evmcc/bytecode/kv.evm | 1 + evmcc/evmcc.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++ evmcc/lll/kv.lll | 10 +++++ 6 files changed, 267 insertions(+) create mode 100644 evmcc/CMakeLists.txt create mode 100644 evmcc/Compiler.cpp create mode 100644 evmcc/Compiler.h create mode 100644 evmcc/bytecode/kv.evm create mode 100644 evmcc/evmcc.cpp create mode 100644 evmcc/lll/kv.lll diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt new file mode 100644 index 000000000..550492583 --- /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(evmcc ${llvm_libs}) + +# end of LLVM specific commands + + + +install( TARGETS ${EXECUTABLE} DESTINATION bin ) + +cmake_policy(SET CMP0015 NEW) 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/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..fc0b03a99 --- /dev/null +++ b/evmcc/evmcc.cpp @@ -0,0 +1,98 @@ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "Compiler.h" + +using namespace dev; + + +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) + { + evmcc::Compiler().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 507ba06b491ba0f892141e8ea0b09090d044993d 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 002/466] ExecutionEngine stub and -i program option for interpreting EVM Code --- evmcc/ExecutionEngine.cpp | 18 ++++++++++++++++++ evmcc/ExecutionEngine.h | 17 +++++++++++++++++ evmcc/evmcc.cpp | 29 ++++++++++++++++------------- 3 files changed, 51 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; } From e33fdeab21d7b5e64f43fc6f9acbc588f7341325 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 003/466] 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 f124be65b7774d3945288281c8a1b3f98010183d 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 004/466] 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 ++-- 5 files changed, 81 insertions(+), 13 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; } From dfa141a9719345b6b43ccde7054e9eb78c4039ce 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 005/466] Staring with Stack helper --- evmcc/Compiler.cpp | 23 ++++++++++++++++++++--- evmcc/Stack.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 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" From bbc3aa4f99df1ec041a60e38630b4d12b0a764c7 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 006/466] 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 e8ff67cb484f62df3978ad83b92df5637dbe70d9 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 007/466] Stack interface and implementation --- evmcc/Compiler.cpp | 23 ++++----- evmcc/Stack.cpp | 118 ++++++++++++++++++++++++++++++++++++++++----- evmcc/Stack.h | 26 ++++++++++ 3 files changed, 143 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 From d8430db13c56dcf718932bfc97db545a5ff12ad9 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 008/466] 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 4266ce54fcc9291cd24652e81fc6ee82acccf21f 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 009/466] 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 3e01d183a085158d0af531ef00dbeb360fb393e9 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 010/466] 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 e53c0a48775da1696bae14a9111534f904aa33c6 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 011/466] 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 58e03d51656e4fefb3f0211d294ba3f2de2d75ab 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 012/466] 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 78b188c4b48958a294859591f502dd6d16e04f11 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 013/466] 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 f3a347bdc8a6f4f1f7f2292570844239c17fa683 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 014/466] Starting ExtVM binary interface --- evmcc/Compiler.cpp | 3 +++ evmcc/ExecutionEngine.cpp | 5 ++++ evmcc/Ext.cpp | 52 +++++++++++++++++++++++++++++++++++++++ evmcc/Ext.h | 22 +++++++++++++++++ 4 files changed, 82 insertions(+) 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 From 68f15f91a0010e7dd2287bfe30d64dcad4b89598 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 30 Sep 2014 21:32:21 +0100 Subject: [PATCH 015/466] 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 00136561a0329e38a47101b4c25f24b60c8e2a6b Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 30 Sep 2014 23:50:15 +0200 Subject: [PATCH 016/466] 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 8cd4326db8aad42552571dd453aad515071c3f63 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 017/466] 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 ++++++++++++++ 9 files changed, 134 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 From 9ba6a7c6d46e58b7b2115094fef67d602731c7c6 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 018/466] 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 ac795c481b7a931b56617253e7a931822d7cc54f 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 019/466] 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 fcde2f3d228999d31c2f2ca0e6f688e7176a4f28 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 020/466] 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 b9cda13a9a66045233cb7595976c55ce96fc3bb4 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 021/466] 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 00f993929f6ed76be3a28c714202e4d5aead84fc Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 1 Oct 2014 15:46:46 +0200 Subject: [PATCH 022/466] 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 eea755cfc6d5112944cf3784e4df2b67c04ba0f5 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 1 Oct 2014 16:32:59 +0200 Subject: [PATCH 023/466] 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 748ee0fe8d48a853a715fc353ed78672160ccd86 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 024/466] 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 edf192b52d7f07eb915850182917c11991664b97 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 025/466] 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 0b8ba6d2e46c762c7e148112192c7550b2ba8d60 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 11:00:28 +0200 Subject: [PATCH 026/466] 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 1d17da1e5f61108075ae7f55a823d43a62b9e18a Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 11:14:09 +0200 Subject: [PATCH 027/466] 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 ad2c4c427404b59bebe5d1f79285e627070c43e3 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 11:45:54 +0200 Subject: [PATCH 028/466] 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 fa76d7a4a0c5e8cc4462032be6bb06a90e62fc33 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 12:22:47 +0200 Subject: [PATCH 029/466] 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 8b625fa954338d1c61a8a4f7f851596d4ef91de8 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 12:36:12 +0200 Subject: [PATCH 030/466] 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 fbe97fd3e115ff1ebb915c5ae8ef30c9f7069700 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 031/466] 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 48d4294d8834e1db39829eb8658ea50c45b3dfb2 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 13:35:04 +0200 Subject: [PATCH 032/466] - 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 09a9f1064f6f253cd8c423ef1768bfa1d5cd9954 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 033/466] 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 c002d9b8432b6d87e1aab02a4e8eef80cd5b43c6 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 034/466] 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 48897f42c85d4409cd4998fe0f7f793088e74c58 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 035/466] 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 710b734236dcbc39071baceb439b636e50059362 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 036/466] 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 320add062e216bf6fa403d72e1f97ac3e1c2aa8b 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 037/466] 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 7bee86aa4bb08513a8785a802cdab73cfebf000e 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 038/466] 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 ++++++------- 8 files changed, 114 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" From b519b73d9478f0a8f54a31b472f85e4d34ad4508 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 039/466] 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 f075b7b22701e24552dce8c50053db7d50fc08c1 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 3 Oct 2014 11:30:15 +0200 Subject: [PATCH 040/466] - 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 3942b2ed2899773f1d170de77966bbbdf3911efe 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 041/466] 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 3f5785829e023f0260aaf87752630f288efc05aa 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 042/466] 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 f230c8259b94d042f1a809f22094515c16e57b93 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 043/466] 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 3cba3a2dca27ea405650059e0adfb11785a2dda0 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 044/466] 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 33e36ce6cce1de6114bf68ce75b2d3816edfaf4b 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 045/466] 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 cc51bfded6093e60c8919735e4fe2d4441effc93 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 046/466] 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 0961908efaa3982c2cee88cd9dd1af45f1c9045a 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 047/466] 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 +++++++++++-- 4 files changed, 60 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; }; } From e52d421955ef46249fd4caabca72ab768438718c 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 048/466] 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 577438e243c9867217c0a44b3166186bf00eb1da 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 049/466] 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 a338b88588bdbeaa70aef7afd11c84945c20888d 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 050/466] 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 1cbb9d57aaf5a0299d8a5c8a84ea8b26a69803de 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 051/466] 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 7a3f3f907902d76153bb5d4c40bc979a7369f025 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 052/466] 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 16ea3bf543e47fcbbee5ab1e92d02946298c64c8 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 053/466] 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 b273b863b127ee8d01f4b51918d46235d17c33ae 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 054/466] 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 bb1954089ce427080f462b5894998216d43b3b2d 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 055/466] 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 58c5950731e9c820d3e916e7e2642524d3d85fbe 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 056/466] 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 dafa5bc890a7627fd6f5044ac8ca18e9b0ce2903 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 057/466] 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 ----------------------------------- 5 files changed, 82 insertions(+), 121 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 From 7f8848744df95ad5d4351e4936a46ec04a1c8e75 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 058/466] 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 d3f59f6de40f2cb50c50d6add744eabd63e999f2 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 059/466] Introducing GasMeter --- evmcc/Compiler.cpp | 4 +++- evmcc/GasMeter.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++++ evmcc/GasMeter.h | 9 +++++++++ 3 files changed, 61 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 From 28d6dd79309d4f38fb2edaa7d207528db39004c9 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 060/466] 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 b7f31afb7a345e599bfaebbd67be3fb34a627a47 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 061/466] Cleanup LLVM types usage --- evmcc/BasicBlock.cpp | 7 ++++--- evmcc/Compiler.cpp | 36 ++++++++++++++++-------------------- evmcc/GasMeter.cpp | 4 +++- evmcc/Type.cpp | 16 ++++++++++++++++ evmcc/Type.h | 16 ++++++++++++++++ 5 files changed, 55 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 From 97644d660ab0c20e982e60a327c8dd268e0fbeab 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 062/466] 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 04cf0cfcea3010a612581e48897711730a1e4e14 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 063/466] 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 e42217d5bca36ac260ca6135a94b225472166595 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 064/466] 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 2b36803c969d8291dfdb54afffa2d07cdfe4b85f Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 10 Oct 2014 10:01:26 +0100 Subject: [PATCH 065/466] 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 67789404b0209b91d88263a95a62e82769b74b81 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 10 Oct 2014 10:03:12 +0100 Subject: [PATCH 066/466] 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 cfb226ba5f2562ad65450e441668d38c5f5c6fa2 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 067/466] 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 52d1ceb1987e2729ab49fe157d9e1ebdfe4d9980 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 10 Oct 2014 13:35:45 +0100 Subject: [PATCH 068/466] 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 09a5899adca65a82d876a13199ea13d31b0aa2f8 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 069/466] 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 fd7069e9afec05bd1e00c16d7fd1899b5ee9cfb4 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 10 Oct 2014 14:22:21 +0100 Subject: [PATCH 070/466] 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 d6915b4d0b50baf4aa0e4707db6b9024f7736856 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 071/466] 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 7a7d4e33e026d5757b73e8fdda9235cbb8d83fad 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 072/466] 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 f825a6020f95cb0a63204268b6b17a42ec570d9a 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 073/466] 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 f5a0975b4a3f670ebc8154673a438c1e12a8a9e8 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 074/466] 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 5f1ea8f832ffe20f1cba84027f70018f483e20ed 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 075/466] 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 4f871447a34169c9af3e6b0b64ec547bb1b64c94 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 076/466] 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 0128f09065bf0bed8d3f84c44968f4e66d478d2c 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 077/466] 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 d6e6a5f558fcb7fd41c6e37ad9038d73c4e9d70f 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 078/466] 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 5470faf9ecc92da19cde1a993fd9d28cff782b4d 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 079/466] 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 4eb65a8b2c337791fb747a37d96d5ed79d6a46a8 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 080/466] 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 39ba3ae1d94519fcc6d084cdca03df7ea8579ae2 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 081/466] 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 d5f7de4a2ea45f78b614857182aed22a4442aa38 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 082/466] 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 2c3d0cc375d30acd081ab1bab9649b8f9438dfb6 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 13:33:04 +0100 Subject: [PATCH 083/466] 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 6e2bcefacaa5687eb0649a061ad2bebaee975e2d Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 13:34:25 +0100 Subject: [PATCH 084/466] 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 56a17a0f2eb1a73d7f957b53c1c9e0e60255e1ea Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 14:46:21 +0100 Subject: [PATCH 085/466] 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 9bdfd59b6f7b5ec3b0fc842de1db0f4c825897d2 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 086/466] 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 efe23ad7b81e0d489c760982b498b2131c9e3d5f 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 087/466] 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 8a522834f0d7d633debffcc6f6cc62e6cd0ae067 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 088/466] 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 a2a496ebceaf7dc19daab30173382c2a8a421e95 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 15:37:40 +0100 Subject: [PATCH 089/466] 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 3a2596960b8c023e3f6cee29db32ea0ae116a9b6 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 090/466] 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 9b3c4465784a7c70c9d8ac3183ac6215fc0c1e4a Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 16:57:13 +0100 Subject: [PATCH 091/466] 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 6caff316972c7326bd0114ef5ad85ef93141b67e Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 17:22:56 +0100 Subject: [PATCH 092/466] 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 8fb6de09e497a8c33b15905d55a8de289ce39cc7 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 093/466] 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 7a89751433dee50d5dae9585c4e5081a7f4d14e1 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 094/466] 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 f95999c6b3745edd0fdbd4e1af6416f751cd8547 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 095/466] 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 7494fdba7ac35cf04cb3fae8f69b8057fc53ac55 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 096/466] 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 475b85d9594a263cbcc098f065c6282a247a8cbb Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 09:24:33 +0100 Subject: [PATCH 097/466] 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 fb87a0b2ab867506faeb1ce55ac4324108b957b5 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 098/466] 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 01ca987093c927e1d353f6c63d3bdb3c25521ccb 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 099/466] 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 ab556c638ad47e04281ed0171ccb978d79467aa0 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 100/466] 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 0931289287f8f5ad97dbb82e12972d2efb371a9d 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 101/466] 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 82cba7a3469db4f2fbb090b59e982525b2a0f2b6 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 102/466] 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 0d9740514a54d7d5944602f1b8d737ec15b0e046 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 14:52:15 +0100 Subject: [PATCH 103/466] 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 9d9e1600a3f76a6dd3ca5084592584eb19fd0e29 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 104/466] 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 42b14ae3348c4eabc0fdc9f634ce569bdb148d17 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 15:19:18 +0100 Subject: [PATCH 105/466] 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 7d674765a47c915c92d93469543809490286f732 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 106/466] 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 1c70f3d099fb72148228a787b77baba3209d7ad1 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 107/466] 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 df932921dcaa6bf0cab041b80e60c643834adacf Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 16:06:34 +0100 Subject: [PATCH 108/466] 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 0d679f0c73bb932523ed3dbbebfa35ac90c36fa1 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 109/466] 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 00e5afc1a52c7f12706252522638534a864be4dc 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 110/466] 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 e11a9bb61bef237502ae2e97bcce6cb8b9608308 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 111/466] 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 04d6ffb178c807391a3e8d77da1527ef12457e69 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 112/466] 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 dbb3e81bdf3cdd1cf697b2d0d321467cdeba51f1 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 113/466] 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 c57de781e45e1561a588c28f3097d696b93bdbc9 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 114/466] 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 7fcf24d3ac9b027062210a1ffacee6bb62e49a0a 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 115/466] 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 564a593bbeb648b5f04b868f118008dc8ecd4c59 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 15 Oct 2014 10:32:37 +0100 Subject: [PATCH 116/466] 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 00a872ec987360e9d8807923a270fc5d2fe22b28 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 15 Oct 2014 13:40:04 +0100 Subject: [PATCH 117/466] * 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 ec2013d5c96daddd2491c5af7ee3a63e985de5a6 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 118/466] 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 67ee0b611366c18a15e4e3f96a0f696f0886ee78 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 119/466] 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 f1ea6c9257cb6eeac45d488e3d6c87564d352362 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 120/466] 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 a2da7c91c84c8e9bb248b541b6f2273be67a1396 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 121/466] 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 11bf67b2d8df34e770f666c98a943ab439644392 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 122/466] 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 07f6bbffe5339887e6b211964fa8bdecd3eea316 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 123/466] 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 5586ff5bdc160c606fb271cc4ce40f5307a07bd6 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 124/466] 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 e094ba9e67a613f24647b7750ea8fa56fd66ad9b 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 125/466] 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 1463897efb42d770f4084aa1d78e3b5be931e4b0 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 126/466] 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 bb51b3476c355dcaad7509284a848bfd6c2f7134 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 127/466] 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 5e13d593be71159c7c2d7816eafb3da8e54aa74a 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 128/466] 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 ++++---------- 9 files changed, 63 insertions(+), 28 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; From c83739e9dc86ebac0f61842d4a2f31229c469cd5 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 129/466] 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 f23312294372f0b5d8da0182fce782711079a8d4 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 16 Oct 2014 12:22:54 +0100 Subject: [PATCH 130/466] 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 8eea4752b2b21d22ef89c90fb3e1253935e89212 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 131/466] 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 72a6fe4b608d68c8ff062f67ef337943f84cacb2 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 132/466] 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 f062fd0165b33ed2b4060942ba9e59734de8a65a Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 16 Oct 2014 12:35:51 +0100 Subject: [PATCH 133/466] 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 7df24fad4a435fb09ac2366ecbc09da640487847 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 134/466] 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 21 files changed, 2 insertions(+), 3 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%) 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 From 9105fb1771ec5050ece7387d9271bdeff3c6c00b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 16 Oct 2014 16:10:42 +0200 Subject: [PATCH 135/466] Merge branch 'develop' into develop-evmcc Conflicts: CMakeLists.txt --- libevmjit/GasMeter.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 9c83ba8db..13c27118f 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -30,26 +30,26 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure return 0; case Instruction::SSTORE: - return static_cast(c_sstoreGas); + return static_cast(FeeStructure::c_sstoreGas); case Instruction::SLOAD: - return static_cast(c_sloadGas); + return static_cast(FeeStructure::c_sloadGas); case Instruction::SHA3: - return static_cast(c_sha3Gas); + return static_cast(FeeStructure::c_sha3Gas); case Instruction::BALANCE: - return static_cast(c_sha3Gas); + return static_cast(FeeStructure::c_sha3Gas); case Instruction::CALL: case Instruction::CALLCODE: - return static_cast(c_callGas); + return static_cast(FeeStructure::c_callGas); case Instruction::CREATE: - return static_cast(c_createGas); + return static_cast(FeeStructure::c_createGas); default: // Assumes instruction code is valid - return static_cast(c_stepGas); + return static_cast(FeeStructure::c_stepGas); } } @@ -134,7 +134,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_sstoreGas); + static const auto sstoreCost = static_cast(FeeStructure::c_sstoreGas); // [ADD] if oldValue == 0 and newValue != 0 => 2*cost // [DEL] if oldValue != 0 and newValue == 0 => 0 @@ -185,7 +185,7 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost) void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder) { // Memory uses other builder, but that can be changes later - auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); + auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(FeeStructure::c_memoryGas)), "memcost"); _builder.CreateCall(m_gasCheckFunc, cost); } From 0f4c8eb63f20eed0a505399c1f926700c271d22f 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 136/466] 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 ++++++++++++++++++++++++++++++ 7 files changed, 85 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; +}; + +} +} +} From 15714cecf65a5d229ddaa54e2d2efed0a2f9cc1e 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 137/466] 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 dd6fbdaf2a6f1e7e38b358c59b220bafe9407bce 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 138/466] 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 f0928f54f3f1ead6ce2c745821f8280bdb4487f7 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 139/466] 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 dfac5a0033e08a2461b19333f82efb57ea8c383f 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 140/466] 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 f31f3bcfc5e6d2e52287891dbcc77527f895a8ba 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 141/466] 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 0febd6ae1a36d44ab4cbb6c8cb6a7fe7045244cf 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 142/466] 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 de8deab6ff60f861e82fa27f54df361f0bb73d3b 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 143/466] 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 6c3af96a40ab1cfde27a8a5a56d9d8953da16741 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 144/466] 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 52ba848c18f494b07ca13907ed6178a2d8f722d8 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 145/466] 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 b13f1ac2aa05e5778deb5dbea210d3d6f725acb3 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 146/466] 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 afe02541ed57b0a2ba8700cd60934b059fa916ef 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 147/466] Endianness handler --- libevmjit/Endianness.cpp | 24 ++++++++++++++++++++++++ libevmjit/Endianness.h | 22 ++++++++++++++++++++++ 2 files changed, 46 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); +}; + +} +} +} From 607458b1936143870e9fc2c00837d5cae2a019fa 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 148/466] 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 54e0824b3164e3cb6da5ea2ed442721ea5abcd0e Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 20 Oct 2014 16:12:00 +0100 Subject: [PATCH 149/466] Updated cmake files after moving the jit compiler to a lib. --- evmcc/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) 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++") From f83e23a7491b45bff7f97514bfde44c8359c441b 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 150/466] 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 c97ca249a0ecf669e9638e3b27f21af9e557a5cc 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 151/466] 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 51fc9adfab3634159f5b42590443700e9c726002 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 152/466] 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 5db20381114aad6c0e89536553be963af22345d1 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 153/466] 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 c7eac0d23c1b41ef3e94f6bff37e423b8bce8070 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 154/466] 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 8ba533fd325f4ce1f4139532263b0c02361e9571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 21 Oct 2014 14:44:09 +0200 Subject: [PATCH 155/466] Merge branch 'develop' into develop-evmcc Conflicts: libevm/FeeStructure.cpp test/vm.cpp --- libevmjit/GasMeter.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index ac7f47d19..6eb8eb6eb 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -30,26 +30,26 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure return 0; case Instruction::SSTORE: - return static_cast(FeeStructure::c_sstoreGas); + return static_cast(c_sstoreGas); case Instruction::SLOAD: - return static_cast(FeeStructure::c_sloadGas); + return static_cast(c_sloadGas); case Instruction::SHA3: - return static_cast(FeeStructure::c_sha3Gas); + return static_cast(c_sha3Gas); case Instruction::BALANCE: - return static_cast(FeeStructure::c_sha3Gas); + return static_cast(c_sha3Gas); case Instruction::CALL: case Instruction::CALLCODE: - return static_cast(FeeStructure::c_callGas); + return static_cast(c_callGas); case Instruction::CREATE: - return static_cast(FeeStructure::c_createGas); + return static_cast(c_createGas); default: // Assumes instruction code is valid - return static_cast(FeeStructure::c_stepGas); + return static_cast(c_stepGas); } } @@ -134,7 +134,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(FeeStructure::c_sstoreGas); + 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 @@ -187,7 +187,7 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost) void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder) { // Memory uses other builder, but that can be changes later - auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(FeeStructure::c_memoryGas)), "memcost"); + auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); _builder.CreateCall(m_gasCheckFunc, cost); } From 0a9e0f587f7fa62d335aa80e3d258148b7f4cf1b Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 14:29:27 +0100 Subject: [PATCH 156/466] 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 c4eb835abae3b7d216b4019ab29141dfafded4b3 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 14:52:43 +0100 Subject: [PATCH 157/466] 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 a4416e563db3088b591ac6206cfe3f239fdbb22a 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 158/466] 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 1cf3549116e0c2b8051080e2f46bbb4a3d18438c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 15:00:43 +0100 Subject: [PATCH 159/466] 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 d95083ade41082b8f34dee40bce2e3dda8b26a32 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 160/466] 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 080cf20f84db00418173e6b2db74c2b50291b4a7 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 15:53:51 +0100 Subject: [PATCH 161/466] 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 5a8ba36fe513f98415c4adfe8b1e813133b660c1 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 16:24:53 +0100 Subject: [PATCH 162/466] 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 05741c2d4e652cb68bb546f0a7c5a4f10f5986b4 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 163/466] 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 920ea2ec7e60701bb259bcbe3e4cb93877c729a3 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 164/466] 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 075752340a9f8ca0a4435f61f754dc3c4a702e4f 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 165/466] 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 f28f8cc0a59f7110a9669967c6fe80220d27120e 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 166/466] 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 170ca152a42be81e9474cef8bcc7b54d7d398766 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 167/466] 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 044e83860aae742c9b8de5cd476d634d44d7f9d9 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 21 Oct 2014 21:52:18 +0100 Subject: [PATCH 168/466] 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 701d99e052991e5315ef27e8f42423d2d1851f7c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 22 Oct 2014 10:01:56 +0100 Subject: [PATCH 169/466] 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 48108f5433812a3e409908695083593723c2e80a 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 170/466] Implement VMFace with jit::VM --- libevmjit/VM.cpp | 7 ++++--- libevmjit/VM.h | 14 +++++--------- 2 files changed, 9 insertions(+), 12 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; }; } From 16de530331c576d77475c379129f1b7930c2eed8 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 171/466] 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 dcb739e44521d0f3b1c493c05e60c03ee40c3f04 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 172/466] 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 fc7a46baf247f1b8e6f0405b304992a693c2f13f 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 173/466] Change the way VMs are created (mostly for tracking where are created) --- libevmjit/VM.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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; }; From d41828fee1528ac0d27d22284e8429bdae0edfe6 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 22 Oct 2014 23:17:48 +0100 Subject: [PATCH 174/466] 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 d28139677b9c802009abd16966eb8849f4a01c5c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 23 Oct 2014 23:56:56 +0100 Subject: [PATCH 175/466] 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 0dae894c05197079456c5f698aebff3eea87e6b7 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 24 Oct 2014 00:00:25 +0100 Subject: [PATCH 176/466] 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 6580a9b286f870d9631ba8de72c602160730ec9f 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 177/466] 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 6c2a120dc1407bd0b4513e9fec1563974c93ae50 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 178/466] 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 547ca3870d541d844bc6dcba3dc275889755249c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 24 Oct 2014 15:08:33 +0100 Subject: [PATCH 179/466] 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 8da55ff8c0d239dd1baddfbad345bfacc941b576 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 180/466] 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 b579c7064327bc1a68001ad014d7d8352a356f70 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 181/466] 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 c388a81cff62e7bb81572d440bc69699d57e6f90 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 182/466] 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 693c4b3dfaa4b3d2c67d19702bc010eab6a494f4 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 183/466] 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 3670e328ba1d5791b0f56f771a054620a96b775f 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 184/466] 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 9ca2663297de7a4543e67759bab5423eb68ba80d 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 185/466] 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 2b898fc06a761e22914299d587d953a2261b7a28 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 186/466] 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 399cf2845e078ae9e51e529c3baa8bed09200ae6 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 187/466] 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 5c1e344a3e7acfe4b0819591189812ddb59d6666 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 188/466] 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 bfe1216d913a763a345a945da61283138a4515dc 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 189/466] 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 088a4efa1698dc1dcaedfc9cffb51fc182b32197 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 190/466] 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 916f5abaaeab655e4b2231254df4d872d06669b4 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 191/466] 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 83b24b627d5d699068f32dab00df6b943ec5d591 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 192/466] 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 3cba47385adae87b7c095c15c070948e8a7a753f 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 193/466] 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 a076ced3c3afdf79a600ae6b0aefd38d3e168391 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 194/466] 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 734dd3158771afed850855ddc93a4dc87d27f05c 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 195/466] 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 a90ebe63dcd58224d57217c4466f50548c1bebb7 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 27 Oct 2014 21:35:58 +0000 Subject: [PATCH 196/466] 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 68ca6962cf7feee6e9faa17471f546c649e9f456 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 27 Oct 2014 23:12:07 +0000 Subject: [PATCH 197/466] 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 64e374890c5be3a6034722458cfa15087ecd526f 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 198/466] 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 6d428d860206ab7e76fb99431853f012a58eb50b 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 199/466] 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 fd7b6da60610dcac6abd0b718b1f4aa030cd83e7 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 200/466] 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 e273299a09d91ee880e70a62061a672cb7185111 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 201/466] 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 6a16efad92850f613e4643a93a9da8bdf44789fe 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 202/466] 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 d5ddbfadbbd2aed2a38dacf117fe877364cf7375 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 28 Oct 2014 09:50:42 +0000 Subject: [PATCH 203/466] 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 0eb8311aa1f380e443e2da63f1bd49bf21c34928 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 204/466] 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 0da6823484bf542bd00da191efc4934455918000 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 205/466] 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 c7ba567f9ae516efcc6eaa9171e3fee95b121cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 12:26:45 +0100 Subject: [PATCH 206/466] Merge branch 'develop' into develop-evmcc Conflicts: libevm/ExtVMFace.h libevm/VM.h test/vm.cpp test/vm.h windows/LibEthereum.vcxproj.filters --- libevmjit/Compiler.cpp | 4 ++-- libevmjit/Ext.cpp | 2 +- libevmjit/GasMeter.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 17d1decc2..0b9fb5b7b 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -369,14 +369,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, break; } - case Instruction::NEG: + /*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::LT: { diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 003b0ae08..34c1ebf5e 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -227,7 +227,7 @@ EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _in 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 address(ext.create(endowment, &gas, initRef, onOp), h256::AlignRight); *_address = address; } else diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 897044cbe..b71fd8286 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_sstoreGas); + return static_cast(c_sstoreResetGas); // FIXME: Check store gas case Instruction::SLOAD: return static_cast(c_sloadGas); @@ -133,7 +133,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_sstoreGas); + 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 5a923d63567afd34afe196b545e07641da19af6e 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 207/466] 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 31c9dd3fcfe53050a0ca49d9b27327233a1a4c89 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 208/466] 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 ac38bf9ac18ff8fa4374f1ab1d66173906de4b5b 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 209/466] 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 6da6f3dc52c88014ce80a49a0a64b22e294ca7fb 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 210/466] 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 2493ef5f9e0e7f12e942428ac3c3fcedf39943c1 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 211/466] 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 4684c6f36353b753fb1015769d1b46454a15930f 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 212/466] 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 6bf994de4d5532495f0f8ff99eb3663acce0b5dc Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 28 Oct 2014 22:25:08 +0000 Subject: [PATCH 213/466] 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 25ccd49acb7ab66483f8a5886f71eae777a76ab5 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 28 Oct 2014 22:29:00 +0000 Subject: [PATCH 214/466] 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 65eaa13c17eb5c10dc5b17c2ffab0118910850f3 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 215/466] 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 cecf5674264868191fdbad3775d7b223cef680d6 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 10:29:34 +0000 Subject: [PATCH 216/466] MULMOD/ADDMOD implemented in separate functions [FIXES #80566276] --- libevmjit/Arith256.cpp | 53 +++++++++++++++++++++++++++++++++++++----- libevmjit/Arith256.h | 6 +++++ libevmjit/Compiler.cpp | 6 ++--- 3 files changed, 55 insertions(+), 10 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; } From ac478d247edb387bd8b85f09d4aa2a5d291cd2dd Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 11:03:41 +0000 Subject: [PATCH 217/466] 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 6e8d1ce25c3788f3b3a7822c4f927955d2e3e7ab Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 11:05:01 +0000 Subject: [PATCH 218/466] 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 887bac95245b7d8d4443652c6f5c68e5408b0b2e 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 219/466] 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 664de3777243fdaba411700e66c26a4ed9f5c174 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 11:52:11 +0000 Subject: [PATCH 220/466] 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 4c9fed96237646fa51971bc6fc45f99a93385d3c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 11:54:02 +0000 Subject: [PATCH 221/466] 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 7e3a9f498406e2e60e82ba27308c9e44e35fa5b9 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 222/466] 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 fa6d4c63dcefabd6a4a63dfe857959544c583ab4 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 223/466] 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 211d3c05e94ab355b23f81219e27e5bd705d02dd 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 224/466] 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 1e8a091897ad659f599421c51fab7087ba4d3350 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 225/466] 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 3ee33cc69950a6a1278d49dae69b0265a5df441f 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 226/466] 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 64513d5aaaf5a9e67ad4668c663c252b4cf9abcb 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 227/466] 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 de67937f2c0db50d14f6f8d30faa66548b766fd6 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 228/466] 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 3212b2b139c549cbf5cd61fca4b2f6d0ef69fc6a 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 229/466] 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 bc1ef19fe03cdd2c9c35cc7330be5aa0d6d08667 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 230/466] 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 c03d36a07ef5894ae34e1c64392eae42e029939f 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 231/466] 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 f06445fcbba074168008f3bd9590acabe5e8ab9d 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 232/466] 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 e24c9c228626fe0e589ad07d4f4c46fd01071ffc 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 233/466] 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 33f1253bbe3d70e2670afab572f50f41be50ef4f 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 234/466] 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 e6b4761765d86fa62e8e3d24640d7b4d6dff268b 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 235/466] 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 c6cf723c682eb4f77c428582048721918c1ec2f3 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 236/466] 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 af0530ba3dcc319ce2848316c431e840c0f63a1f Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Wed, 29 Oct 2014 22:13:25 +0000 Subject: [PATCH 237/466] 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 22e4d16e1f4034ef34b19ed7652078aa8949633d 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 238/466] 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 e4a77c1f69785b058e0095b124a77f968dea68b2 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 239/466] 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 dd75da2d3a3f02c936e72bd2e8866c3fa811fbff 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 240/466] 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 d77864071db8224d1a58b39a75da4d8ea9e85b24 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 241/466] 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 007641a84bb183f028e20161bf310d5068ef2bd2 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 12:56:52 +0000 Subject: [PATCH 242/466] 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 3725432befcdcbf9ae5270e74bae7574d600ed0c 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 243/466] 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 85f67a5582770d2369d5b19d3b4360174a9cc35a 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 244/466] 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 43093d6559101b7c5a6d24b070fca42f6ddb6f38 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 245/466] 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 2d6aa468c6249b682c5f2e3f672fa1dd311632fa Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:42:44 +0000 Subject: [PATCH 246/466] CMakeLists updated, should now build without LLVM when EVMJIT is not enabled [#81588646] --- evmcc/CMakeLists.txt | 7 ++----- libevmjit/CMakeLists.txt | 7 +++---- 2 files changed, 5 insertions(+), 9 deletions(-) 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/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 From 7760b31e42da5be6180ba184a60a9eee27ab8d9b Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:46:01 +0000 Subject: [PATCH 247/466] Cleaning up warnings and build dependencies [#81588646] --- evmcc/evmcc.cpp | 2 - libevmjit/Compiler.cpp | 12 +- libevmjit/Compiler.cpp.orig | 962 ++++++++++++++++++++++++++++++++++ libevmjit/ExecutionEngine.cpp | 7 +- 4 files changed, 975 insertions(+), 8 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/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" From d32daf6cc4cecde83b359554bde3942fdc267881 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:47:43 +0000 Subject: [PATCH 248/466] 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 65af01cda8b78997952efa58cbbc206cb5fe25f0 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 30 Oct 2014 16:51:04 +0000 Subject: [PATCH 249/466] 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 4ff7ba015de411d089c69f26283c784cd235cf0b 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 250/466] 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 1008c70a14c2ad6a6ec70e9233914daa63c8a95d 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 251/466] 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 bfb96606a2854da64897e28baca0012d76404ba9 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 252/466] 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 439561a5fa352e087ef3e3d4ccee0c4fe7ec66fd 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 253/466] 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 273b0f634f7beb3cdf5db0e592221dc88bc33c78 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 254/466] 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 272c568bfcb42257bd9f7b6dd5b06cfaa37e0ca7 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 255/466] 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 350b004e7959c9b7193e1bb8b7a9059b096c3cbe 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 256/466] 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 72398d2c267bf2efb8fc959b6b608a6f1aaebc85 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 257/466] 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 33cc50d1303ca22fb6496952e524c7f139443331 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 258/466] 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 b5abb70075d694f1dfa046bc6ab6381e8e3b3e27 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 259/466] 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 aaaf5439fbdcee15da7579125e8601ecb0fe4544 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 260/466] 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 40561b1270f0cb555d5650017857e83d7665e896 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 14:46:32 +0000 Subject: [PATCH 261/466] 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 8ee32d91976e591e2aa024392fbcd051564c5b74 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 262/466] 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 a44a7ab4ad18b333355ed4b31f2f5ac329e69c2b 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 263/466] 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 6f99869d578d27957e54192c1c7d91ff8b357949 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 15:46:05 +0000 Subject: [PATCH 264/466] 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 8f7b5d6a25b7473855472c2ec7622d273293e4c1 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 15:46:44 +0000 Subject: [PATCH 265/466] 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 ee0e2d310212683939b1f05225145ffe612dd6b0 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 31 Oct 2014 15:47:36 +0000 Subject: [PATCH 266/466] 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 c91c5df4f68b2af29d45f16f4a3b6a0085c8cb4b 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 267/466] 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 9a0f9d3e3c9c10812da1f438285bacaa60a8de69 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 3 Nov 2014 10:31:09 +0000 Subject: [PATCH 268/466] 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 cb870520b2ac0b3487d0bcca3fceb28d4df2e198 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 3 Nov 2014 10:31:34 +0000 Subject: [PATCH 269/466] 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 ae9f57f6870f46279a855d6f109757f9f4d2ef32 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 3 Nov 2014 16:04:31 +0000 Subject: [PATCH 270/466] (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 7305fb32d36477a144061be8cefdab193f3ab86b Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 4 Nov 2014 22:02:11 +0000 Subject: [PATCH 271/466] 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 47e654c06da067696df0af51ebd7abe0a587d3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 6 Nov 2014 18:01:09 +0100 Subject: [PATCH 272/466] Merge branch 'develop' into develop-evmcc --- libevmjit/VM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index f60dbe783..0c89587e9 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -29,7 +29,7 @@ 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()); case ReturnCode::BadInstruction: BOOST_THROW_EXCEPTION(BadInstruction()); default: From cdcbb6be12cb009b899f51d7b6635d90c5c54cb4 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 13 Nov 2014 16:57:01 +0100 Subject: [PATCH 273/466] 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 c907c71f8ae4403b6a06da42b333fca4593da979 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 13 Nov 2014 17:03:39 +0100 Subject: [PATCH 274/466] 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 2bd4d6cd07aed92194bae57064e2b4d14f47afb6 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 275/466] 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 86334f5eff90e4baa555f72e0a2bbb5b664ea27e 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 276/466] 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 aa7fc792062ebdd52c97fac20e14ad6a46bf4886 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 14 Nov 2014 14:39:06 +0100 Subject: [PATCH 277/466] 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 89e6d2f3e663653f4218374267b2b4f3c0164487 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 14 Nov 2014 14:40:34 +0100 Subject: [PATCH 278/466] 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 f7d6554ad6009b30d5d55105bbe8b9b0f9497db6 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 279/466] 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 3517bfc6d0cda5fe229ac0bf65195f6946e424cd 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 280/466] fixed libevmjit dependencies in cmake files --- evmcc/CMakeLists.txt | 5 ++--- libevmjit/CMakeLists.txt | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) 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) From d77ee403d563a1509c7fe68e34045eda2f8af7c1 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 24 Nov 2014 22:42:50 +0100 Subject: [PATCH 281/466] 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 bf6a4d4042dfe0317e41616c6e95aeeddaf2b435 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 282/466] 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 f72cceda5837c5668a7067785a3cf41418e94510 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 283/466] resolved circular dependency between libevm and libevmjit --- libevmjit/VM.cpp | 1 + libevmjit/VM.h | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) 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; From fdd5275a835d302e556c982b10cc600d60483544 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 284/466] 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 94e41d815bc6f77fa35032ea865883a78e51c841 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 285/466] 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 dc82664ede1db5717ca7c76a960ccc875484f622 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 286/466] C Interface draft 1 --- libevmjit/interface.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 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); From 5f61bdcca084241dc09933692cbb65a579ced139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Dec 2014 16:55:45 +0100 Subject: [PATCH 287/466] Starting cmake scripts --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..00ade4305 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,4 @@ + +project(evmjit) + +add_subdirectory(libevmjit) \ No newline at end of file From 99c7113079d2be29355073897cfa69d6f3b360ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 11:57:38 +0100 Subject: [PATCH 288/466] CMake scripts --- CMakeLists.txt | 7 ++- libevmjit-cpp/CMakeLists.txt | 10 +++++ libevmjit/CMakeLists.txt | 84 +++++++++++++++++------------------- 3 files changed, 55 insertions(+), 46 deletions(-) create mode 100644 libevmjit-cpp/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 00ade4305..d2acefc01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,9 @@ +cmake_minimum_required(VERSION 2.8.12) + project(evmjit) -add_subdirectory(libevmjit) \ No newline at end of file +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +add_subdirectory(libevmjit) +add_subdirectory(libevmjit-cpp) \ No newline at end of file diff --git a/libevmjit-cpp/CMakeLists.txt b/libevmjit-cpp/CMakeLists.txt new file mode 100644 index 000000000..799607562 --- /dev/null +++ b/libevmjit-cpp/CMakeLists.txt @@ -0,0 +1,10 @@ + +project(evmjit-cpp LANGUAGES CXX) + +set(SOURCES VM.cpp VM.h) + +source_group("" FILES ${SOURCES}) + +add_library(${PROJECT_NAME} ${SOURCES}) +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "libs") + diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 0b3226e14..155a627c1 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -1,58 +1,52 @@ -cmake_policy(SET CMP0015 NEW) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") +project(evmjit LANGUAGES CXX) -aux_source_directory(. SRC_LIST) +file(GLOB SOURCES "*.cpp") +file(GLOB HEADERS "*.h") +source_group("" FILES ${SOURCES}) +source_group("" FILES ${HEADERS}) -set(EXECUTABLE evmjit) +add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS}) +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "libs") -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 +#include_directories(..) -find_package(LLVM REQUIRED CONFIG) +#target_link_libraries(${EXECUTABLE} devcore) +#target_link_libraries(${EXECUTABLE} ethcore) +#target_link_libraries(${EXECUTABLE} evmcore) -message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") -message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") -include_directories(${LLVM_INCLUDE_DIRS}) -add_definitions(${LLVM_DEFINITIONS}) +# 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_map_components_to_libnames(llvm_libs core support mcjit x86asmparser x86codegen) -target_link_libraries(evmjit ${llvm_libs}) -# end of LLVM specific config +# LLVM +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(${PROJECT_NAME} ${LLVM_LIBS}) +# Boost +find_package(Boost REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) -install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) -install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) -cmake_policy(SET CMP0015 NEW) +#install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +#install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) From 68648a2fb5438e21d5a3341a0a54ddfe811a9f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 11:59:24 +0100 Subject: [PATCH 289/466] Separating EVM JIT from CPP client (WIP) --- {libevmjit => libevmjit-cpp}/VM.cpp | 0 {libevmjit => libevmjit-cpp}/VM.h | 0 libevmjit/Arith256.cpp | 43 +++--- libevmjit/Common.h | 24 +++ libevmjit/Compiler.cpp | 9 +- libevmjit/Compiler.h | 7 +- libevmjit/ExecutionEngine.h | 4 +- libevmjit/Ext.cpp | 4 +- libevmjit/Ext.h | 3 +- libevmjit/GasMeter.cpp | 42 +++-- libevmjit/GasMeter.h | 3 +- libevmjit/Instruction.h | 230 ++++++++++++++++++++++++++++ libevmjit/Memory.cpp | 4 +- libevmjit/Memory.h | 2 - libevmjit/Runtime.cpp | 5 +- libevmjit/Runtime.h | 5 +- libevmjit/Type.h | 2 +- libevmjit/Utils.cpp | 1 + libevmjit/Utils.h | 78 +--------- 19 files changed, 327 insertions(+), 139 deletions(-) rename {libevmjit => libevmjit-cpp}/VM.cpp (100%) rename {libevmjit => libevmjit-cpp}/VM.h (100%) create mode 100644 libevmjit/Common.h create mode 100644 libevmjit/Instruction.h diff --git a/libevmjit/VM.cpp b/libevmjit-cpp/VM.cpp similarity index 100% rename from libevmjit/VM.cpp rename to libevmjit-cpp/VM.cpp diff --git a/libevmjit/VM.h b/libevmjit-cpp/VM.h similarity index 100% rename from libevmjit/VM.h rename to libevmjit-cpp/VM.h diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 79a8fe79c..aa76ec0ef 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -4,8 +4,6 @@ #include -#include - namespace dev { namespace eth @@ -102,56 +100,57 @@ extern "C" { using namespace dev::eth::jit; + using s256 = boost::multiprecision::int256_t; EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result) { - dev::u256 arg1 = llvm2eth(*_arg1); - dev::u256 arg2 = llvm2eth(*_arg2); + auto arg1 = llvm2eth(*_arg1); + auto 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); + auto arg1 = llvm2eth(*_arg1); + auto 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); + auto arg1 = llvm2eth(*_arg1); + auto 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))); + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + *o_result = eth2llvm(arg2 == 0 ? arg2 : (arg1.convert_to() / arg2.convert_to()).convert_to()); } 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))); + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + *o_result = eth2llvm(arg2 == 0 ? arg2 : (arg1.convert_to() % arg2.convert_to()).convert_to()); } 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)); + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + auto arg3 = llvm2eth(*_arg3); + *o_result = eth2llvm(u256((bigint(arg1) * 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)); + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + auto arg3 = llvm2eth(*_arg3); + *o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3)); } } diff --git a/libevmjit/Common.h b/libevmjit/Common.h new file mode 100644 index 000000000..dfc60f4d4 --- /dev/null +++ b/libevmjit/Common.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using byte = uint8_t; +using bytes = std::vector; +using u256 = boost::multiprecision::uint256_t; +using bigint = boost::multiprecision::cpp_int; + +struct NoteChannel {}; // FIXME: Use some log library? + +struct ExtVMFace; + +} +} +} diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1cc86d8aa..beb3d022d 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -13,8 +13,7 @@ #include #include -#include - +#include "Instruction.h" #include "Type.h" #include "Memory.h" #include "Stack.h" @@ -248,7 +247,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode) void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, - Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) + Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) { if (!_nextBasicBlock) // this is the last block in the code _nextBasicBlock = m_stopBB; @@ -490,8 +489,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode 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); + m_builder.CreateSelect(bittest, val1, val0), + word); stack.push(result); break; } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index a618f41a3..e021bfdef 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -3,8 +3,7 @@ #include -#include - +#include "Common.h" #include "BasicBlock.h" namespace dev @@ -44,9 +43,9 @@ public: private: - void createBasicBlocks(bytes const& _bytecode); + 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 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.h b/libevmjit/ExecutionEngine.h index 8cf1ec746..932c19304 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -3,8 +3,8 @@ #include -#include -#include +#include "Common.h" +//#include namespace dev { diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 6eb35acda..588ba4652 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -5,8 +5,8 @@ #include #include -#include -#include +//#include +//#include #include "Runtime.h" #include "Type.h" diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 54380dda6..ad4649177 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -1,8 +1,7 @@ #pragma once -#include - +#include #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 48499259a..d4a5dbfc3 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -5,9 +5,6 @@ #include #include -#include -#include - #include "Type.h" #include "Ext.h" #include "Runtime.h" @@ -22,6 +19,26 @@ namespace jit namespace // Helper functions { +uint64_t const c_stepGas = 1; +uint64_t const c_balanceGas = 20; +uint64_t const c_sha3Gas = 20; +uint64_t const c_sloadGas = 20; +uint64_t const c_sstoreSetGas = 300; +uint64_t const c_sstoreResetGas = 100; +uint64_t const c_sstoreRefundGas = 100; +uint64_t const c_createGas = 100; +uint64_t const c_callGas = 20; +uint64_t const c_expGas = 1; +uint64_t const c_expByteGas = 1; +uint64_t const c_memoryGas = 1; +uint64_t const c_txDataZeroGas = 1; +uint64_t const c_txDataNonZeroGas = 5; +uint64_t const c_txGas = 500; +uint64_t const c_logGas = 32; +uint64_t const c_logDataGas = 1; +uint64_t const c_logTopicGas = 32; +uint64_t const c_copyGas = 1; + uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted) { switch (inst) @@ -31,21 +48,16 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() return 0; - case Instruction::SLOAD: - return static_cast(c_sloadGas); + case Instruction::SLOAD: return c_sloadGas; - case Instruction::SHA3: - return static_cast(c_sha3Gas); + case Instruction::SHA3: return c_sha3Gas; - case Instruction::BALANCE: - return static_cast(c_sha3Gas); + case Instruction::BALANCE: return c_balanceGas; case Instruction::CALL: - case Instruction::CALLCODE: - return static_cast(c_callGas); + case Instruction::CALLCODE: return c_callGas; - case Instruction::CREATE: - return static_cast(c_createGas); + case Instruction::CREATE: return c_createGas; case Instruction::LOG0: case Instruction::LOG1: @@ -54,11 +66,11 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure case Instruction::LOG4: { auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); - return static_cast(c_logGas) + numTopics * static_cast(c_logTopicGas); + return c_logGas + numTopics * c_logTopicGas; } default: // Assumes instruction code is valid - return static_cast(c_stepGas); + return 1; } } diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index dfb4fb548..85ef59a0f 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -1,9 +1,8 @@ #pragma once -#include - #include "CompilerHelper.h" +#include "Instruction.h" namespace dev { diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h new file mode 100644 index 000000000..efc43552c --- /dev/null +++ b/libevmjit/Instruction.h @@ -0,0 +1,230 @@ +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +/// Virtual machine bytecode instruction. +enum class Instruction : uint8_t +{ + STOP = 0x00, ///< halts execution + ADD, ///< addition operation + MUL, ///< mulitplication operation + SUB, ///< subtraction operation + DIV, ///< integer division operation + SDIV, ///< signed integer division operation + MOD, ///< modulo remainder operation + SMOD, ///< signed modulo remainder operation + ADDMOD, ///< unsigned modular addition + MULMOD, ///< unsigned modular multiplication + EXP, ///< exponential operation + SIGNEXTEND, ///< extend length of signed integer + + LT = 0x10, ///< less-than comparision + GT, ///< greater-than comparision + SLT, ///< signed less-than comparision + SGT, ///< signed greater-than comparision + EQ, ///< equality comparision + ISZERO, ///< simple not operator + AND, ///< bitwise AND operation + OR, ///< bitwise OR operation + XOR, ///< bitwise XOR operation + NOT, ///< bitwise NOT opertation + BYTE, ///< retrieve single byte from word + + SHA3 = 0x20, ///< compute SHA3-256 hash + + ADDRESS = 0x30, ///< get address of currently executing account + BALANCE, ///< get balance of the given account + ORIGIN, ///< get execution origination address + CALLER, ///< get caller address + CALLVALUE, ///< get deposited value by the instruction/transaction responsible for this execution + CALLDATALOAD, ///< get input data of current environment + CALLDATASIZE, ///< get size of input data in current environment + CALLDATACOPY, ///< copy input data in current environment to memory + CODESIZE, ///< get size of code running in current environment + CODECOPY, ///< copy code running in current environment to memory + GASPRICE, ///< get price of gas in current environment + EXTCODESIZE, ///< get external code size (from another contract) + EXTCODECOPY, ///< copy external code (from another contract) + + PREVHASH = 0x40, ///< get hash of most recent complete block + COINBASE, ///< get the block's coinbase address + TIMESTAMP, ///< get the block's timestamp + NUMBER, ///< get the block's number + DIFFICULTY, ///< get the block's difficulty + GASLIMIT, ///< get the block's gas limit + + POP = 0x50, ///< remove item from stack + MLOAD, ///< load word from memory + MSTORE, ///< save word to memory + MSTORE8, ///< save byte to memory + SLOAD, ///< load word from storage + SSTORE, ///< save word to storage + JUMP, ///< alter the program counter + JUMPI, ///< conditionally alter the program counter + PC, ///< get the program counter + MSIZE, ///< get the size of active memory + GAS, ///< get the amount of available gas + JUMPDEST, ///< set a potential jump destination + + PUSH1 = 0x60, ///< place 1 byte item on stack + PUSH2, ///< place 2 byte item on stack + PUSH3, ///< place 3 byte item on stack + PUSH4, ///< place 4 byte item on stack + PUSH5, ///< place 5 byte item on stack + PUSH6, ///< place 6 byte item on stack + PUSH7, ///< place 7 byte item on stack + PUSH8, ///< place 8 byte item on stack + PUSH9, ///< place 9 byte item on stack + PUSH10, ///< place 10 byte item on stack + PUSH11, ///< place 11 byte item on stack + PUSH12, ///< place 12 byte item on stack + PUSH13, ///< place 13 byte item on stack + PUSH14, ///< place 14 byte item on stack + PUSH15, ///< place 15 byte item on stack + PUSH16, ///< place 16 byte item on stack + PUSH17, ///< place 17 byte item on stack + PUSH18, ///< place 18 byte item on stack + PUSH19, ///< place 19 byte item on stack + PUSH20, ///< place 20 byte item on stack + PUSH21, ///< place 21 byte item on stack + PUSH22, ///< place 22 byte item on stack + PUSH23, ///< place 23 byte item on stack + PUSH24, ///< place 24 byte item on stack + PUSH25, ///< place 25 byte item on stack + PUSH26, ///< place 26 byte item on stack + PUSH27, ///< place 27 byte item on stack + PUSH28, ///< place 28 byte item on stack + PUSH29, ///< place 29 byte item on stack + PUSH30, ///< place 30 byte item on stack + PUSH31, ///< place 31 byte item on stack + PUSH32, ///< place 32 byte item on stack + + DUP1 = 0x80, ///< copies the highest item in the stack to the top of the stack + DUP2, ///< copies the second highest item in the stack to the top of the stack + DUP3, ///< copies the third highest item in the stack to the top of the stack + DUP4, ///< copies the 4th highest item in the stack to the top of the stack + DUP5, ///< copies the 5th highest item in the stack to the top of the stack + DUP6, ///< copies the 6th highest item in the stack to the top of the stack + DUP7, ///< copies the 7th highest item in the stack to the top of the stack + DUP8, ///< copies the 8th highest item in the stack to the top of the stack + DUP9, ///< copies the 9th highest item in the stack to the top of the stack + DUP10, ///< copies the 10th highest item in the stack to the top of the stack + DUP11, ///< copies the 11th highest item in the stack to the top of the stack + DUP12, ///< copies the 12th highest item in the stack to the top of the stack + DUP13, ///< copies the 13th highest item in the stack to the top of the stack + DUP14, ///< copies the 14th highest item in the stack to the top of the stack + DUP15, ///< copies the 15th highest item in the stack to the top of the stack + DUP16, ///< copies the 16th highest item in the stack to the top of the stack + + SWAP1 = 0x90, ///< swaps the highest and second highest value on the stack + SWAP2, ///< swaps the highest and third highest value on the stack + SWAP3, ///< swaps the highest and 4th highest value on the stack + SWAP4, ///< swaps the highest and 5th highest value on the stack + SWAP5, ///< swaps the highest and 6th highest value on the stack + SWAP6, ///< swaps the highest and 7th highest value on the stack + SWAP7, ///< swaps the highest and 8th highest value on the stack + SWAP8, ///< swaps the highest and 9th highest value on the stack + SWAP9, ///< swaps the highest and 10th highest value on the stack + SWAP10, ///< swaps the highest and 11th highest value on the stack + SWAP11, ///< swaps the highest and 12th highest value on the stack + SWAP12, ///< swaps the highest and 13th highest value on the stack + SWAP13, ///< swaps the highest and 14th highest value on the stack + SWAP14, ///< swaps the highest and 15th highest value on the stack + SWAP15, ///< swaps the highest and 16th highest value on the stack + SWAP16, ///< swaps the highest and 17th highest value on the stack + + LOG0 = 0xa0, ///< Makes a log entry; no topics. + LOG1, ///< Makes a log entry; 1 topic. + LOG2, ///< Makes a log entry; 2 topics. + LOG3, ///< Makes a log entry; 3 topics. + LOG4, ///< Makes a log entry; 4 topics. + + CREATE = 0xf0, ///< create a new account with associated code + CALL, ///< message-call into an account + RETURN, ///< halt execution returning output data + CALLCODE, + SUICIDE = 0xff ///< halt execution and register account for later deletion +}; + +/// 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/Memory.cpp b/libevmjit/Memory.cpp index 53cccf92b..288b33df9 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -10,8 +10,6 @@ #include #include -#include - #include "Type.h" #include "Runtime.h" #include "GasMeter.h" @@ -208,7 +206,7 @@ extern "C" { using namespace dev::eth::jit; - EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size) + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) { auto size = _size->a; // Trunc to 64-bit auto& memory = _rt->getMemory(); diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index c6ba02a54..bbd35b973 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -1,7 +1,5 @@ #pragma once -#include - #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 8e52b648a..b5254c035 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -91,7 +91,7 @@ u256 Runtime::getGas() const return llvm2eth(m_data.elems[RuntimeData::Gas]); } -bytesConstRef Runtime::getReturnData() const +bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy { // TODO: Handle large indexes auto offset = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset])); @@ -99,7 +99,8 @@ bytesConstRef Runtime::getReturnData() const assert(offset + size <= m_memory.size()); // TODO: Handle invalid data access by returning empty ref - return {m_memory.data() + offset, size}; + auto dataBeg = m_memory.begin() + offset; + return {dataBeg, dataBeg + size}; } bool Runtime::outputLogs() const diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 8f485794a..1acda23b4 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -4,8 +4,9 @@ #include #include -#include +//#include +#include "Instruction.h" #include "CompilerHelper.h" #include "Utils.h" #include "Type.h" @@ -75,7 +76,7 @@ public: ExtVMFace& getExt() { return m_ext; } u256 getGas() const; - bytesConstRef getReturnData() const; + bytes getReturnData() const; decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; } bool outputLogs() const; diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 0d8c6c530..d0534bd75 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -3,7 +3,7 @@ #include #include -#include +#include "Common.h" namespace dev { diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 548ee0e1f..0dad56548 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -1,5 +1,6 @@ #include "Utils.h" +#include "Instruction.h" namespace dev { diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 54291f3e0..06ef9af81 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -3,9 +3,7 @@ #include -#include -#include -#include +#include "Common.h" namespace dev { @@ -16,6 +14,8 @@ namespace jit struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; +#define clog(CHANNEL) std::cerr << CHANNEL::name() << ": " + /// Representation of 256-bit value binary compatible with LLVM i256 // TODO: Replace with h256 struct i256 @@ -30,78 +30,6 @@ 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 - } } } From aa771582a76c5b0443acca1123603fac94d8dcec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 13:52:53 +0100 Subject: [PATCH 290/466] Separate runtime classes --- libevmjit/Compiler.cpp | 2 +- libevmjit/CompilerHelper.cpp | 2 +- libevmjit/GasMeter.cpp | 2 +- libevmjit/Memory.cpp | 2 +- libevmjit/Runtime.cpp | 143 +------------------------------ libevmjit/Runtime.h | 61 +------------- libevmjit/RuntimeData.h | 51 +++++++++++ libevmjit/RuntimeManager.cpp | 159 +++++++++++++++++++++++++++++++++++ libevmjit/RuntimeManager.h | 46 ++++++++++ libevmjit/Stack.cpp | 1 + libevmjit/Type.cpp | 4 +- 11 files changed, 265 insertions(+), 208 deletions(-) create mode 100644 libevmjit/RuntimeData.h create mode 100644 libevmjit/RuntimeManager.cpp create mode 100644 libevmjit/RuntimeManager.h diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index beb3d022d..41098510b 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -22,7 +22,7 @@ #include "Utils.h" #include "Endianness.h" #include "Arith256.h" -#include "Runtime.h" +#include "RuntimeManager.h" namespace dev { diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index c4835c32e..6846ffd1c 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -3,7 +3,7 @@ #include -#include "Runtime.h" +#include "RuntimeManager.h" namespace dev { diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index d4a5dbfc3..20b3a8eec 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -7,7 +7,7 @@ #include "Type.h" #include "Ext.h" -#include "Runtime.h" +#include "RuntimeManager.h" namespace dev { diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 288b33df9..7039ce198 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -14,7 +14,7 @@ #include "Runtime.h" #include "GasMeter.h" #include "Endianness.h" -#include "Runtime.h" +#include "RuntimeManager.h" namespace dev { diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index b5254c035..3fa36253b 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -5,9 +5,7 @@ #include #include -#include - -#include "Type.h" +//#include namespace dev { @@ -16,48 +14,6 @@ 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) @@ -109,103 +65,6 @@ bool Runtime::outputLogs() 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"); - 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 index 1acda23b4..1c11afc5d 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -10,6 +10,7 @@ #include "CompilerHelper.h" #include "Utils.h" #include "Type.h" +#include "RuntimeData.h" #ifdef _MSC_VER @@ -25,39 +26,6 @@ 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; @@ -91,33 +59,6 @@ private: 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/RuntimeData.h b/libevmjit/RuntimeData.h new file mode 100644 index 000000000..4925e213f --- /dev/null +++ b/libevmjit/RuntimeData.h @@ -0,0 +1,51 @@ + +#pragma once + +#include + +#include "Utils.h" + + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using jmpBufRef = decltype(&jmp_buf{}[0]); + +struct RuntimeData +{ + enum Index + { + 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; + jmpBufRef jmpBuf; +}; + +} +} +} diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp new file mode 100644 index 000000000..58fbd5a20 --- /dev/null +++ b/libevmjit/RuntimeManager.cpp @@ -0,0 +1,159 @@ + +#include "RuntimeManager.h" + +#include +#include +#include + +#include "RuntimeData.h" +#include "Instruction.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::StructType* RuntimeManager::getRuntimeDataType() +{ + static llvm::StructType* type = nullptr; + if (!type) + { + llvm::Type* elems[] = + { + llvm::ArrayType::get(Type::Word, RuntimeData::_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"; + } +} +} + +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/RuntimeManager.h b/libevmjit/RuntimeManager.h new file mode 100644 index 000000000..1231d9885 --- /dev/null +++ b/libevmjit/RuntimeManager.h @@ -0,0 +1,46 @@ +#pragma once + +#include "CompilerHelper.h" +#include "Type.h" +#include "RuntimeData.h" +#include "Instruction.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +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); + + static llvm::StructType* getRuntimeDataType(); + +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 index 494750b43..9435568a8 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -1,4 +1,5 @@ #include "Stack.h" +#include "RuntimeManager.h" #include "Runtime.h" #include "Type.h" diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index a72ec0eda..c34be45d5 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -3,7 +3,7 @@ #include -#include "Runtime.h" +#include "RuntimeManager.h" namespace dev { @@ -33,7 +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(); + RuntimePtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); } llvm::ConstantInt* Constant::get(int64_t _n) From 0509b3bddd004a1496a708574311b07c544c8d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 14:21:57 +0100 Subject: [PATCH 291/466] Changing Runtime interface --- libevmjit-cpp/Runtime.cpp | 70 +++++++++++++++++++++++++++++++++++++++ libevmjit-cpp/Runtime.h | 64 +++++++++++++++++++++++++++++++++++ libevmjit/Runtime.cpp | 38 +++------------------ libevmjit/Runtime.h | 23 ++++++------- libevmjit/RuntimeData.h | 5 +-- 5 files changed, 150 insertions(+), 50 deletions(-) create mode 100644 libevmjit-cpp/Runtime.cpp create mode 100644 libevmjit-cpp/Runtime.h diff --git a/libevmjit-cpp/Runtime.cpp b/libevmjit-cpp/Runtime.cpp new file mode 100644 index 000000000..3fa36253b --- /dev/null +++ b/libevmjit-cpp/Runtime.cpp @@ -0,0 +1,70 @@ + +#include "Runtime.h" + +#include +#include +#include + +//#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +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]); +} + +bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy +{ + // 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 + auto dataBeg = m_memory.begin() + offset; + return {dataBeg, dataBeg + size}; +} + +bool Runtime::outputLogs() const +{ + return m_outputLogs; +} + + +} +} +} diff --git a/libevmjit-cpp/Runtime.h b/libevmjit-cpp/Runtime.h new file mode 100644 index 000000000..1c11afc5d --- /dev/null +++ b/libevmjit-cpp/Runtime.h @@ -0,0 +1,64 @@ + +#pragma once + +#include +#include + +//#include + +#include "Instruction.h" +#include "CompilerHelper.h" +#include "Utils.h" +#include "Type.h" +#include "RuntimeData.h" + + +#ifdef _MSC_VER + #define EXPORT __declspec(dllexport) +#else + #define EXPORT +#endif + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +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; + bytes 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 +}; + +} +} +} diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 3fa36253b..e725334db 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -14,33 +14,11 @@ namespace eth namespace jit { -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); -} +Runtime::Runtime(RuntimeData* _data, Env* _env, JmpBufRef _jmpBuf): + m_data(*_data), + m_env(*_env), + m_jmpBuf(_jmpBuf) +{} u256 Runtime::getGas() const { @@ -59,12 +37,6 @@ bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy return {dataBeg, dataBeg + size}; } -bool Runtime::outputLogs() const -{ - return m_outputLogs; -} - - } } } diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 1c11afc5d..ace169e00 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -2,9 +2,6 @@ #pragma once #include -#include - -//#include #include "Instruction.h" #include "CompilerHelper.h" @@ -28,11 +25,15 @@ namespace jit using StackImpl = std::vector; using MemoryImpl = bytes; +using JmpBufRef = decltype(&jmp_buf{}[0]); + +/// VM Environment (ExtVM) opaque type +struct Env; class Runtime { public: - Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf, bool _outputLogs); + Runtime(RuntimeData* _data, Env* _env, JmpBufRef _jmpBuf); Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; @@ -41,22 +42,18 @@ public: StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } - ExtVMFace& getExt() { return m_ext; } + Env* getEnvPtr() { return &m_env; } u256 getGas() const; bytes getReturnData() const; - decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; } - bool outputLogs() const; + JmpBufRef getJmpBuf() { return m_jmpBuf; } private: - void set(RuntimeData::Index _index, u256 _value); - - /// @internal Must be the first element to asure Runtime* === RuntimeData* - RuntimeData m_data; + RuntimeData& m_data; + Env& m_env; + JmpBufRef m_jmpBuf; StackImpl m_stack; MemoryImpl m_memory; - ExtVMFace& m_ext; - bool m_outputLogs; ///< write LOG statements to console }; } diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index 4925e213f..c166e5ab5 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -12,9 +12,7 @@ namespace eth { namespace jit { - -using jmpBufRef = decltype(&jmp_buf{}[0]); - + struct RuntimeData { enum Index @@ -43,7 +41,6 @@ struct RuntimeData i256 elems[_size]; byte const* callData; byte const* code; - jmpBufRef jmpBuf; }; } From bb6e6035684db887ab0b4897a6688cb4848f326e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 14:35:12 +0100 Subject: [PATCH 292/466] Updating ExecutionEngine interface --- libevmjit/ExecutionEngine.cpp | 24 +++++++----------------- libevmjit/ExecutionEngine.h | 7 +++---- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 02b12d373..64cb250f7 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -20,9 +20,6 @@ #pragma GCC diagnostic pop - -#include - #include "Runtime.h" #include "Memory.h" #include "Stack.h" @@ -35,11 +32,7 @@ namespace eth namespace jit { -ExecutionEngine::ExecutionEngine() -{ -} - -int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool _outputLogs, ExtVMFace& _ext) +int ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env) { auto module = _module.get(); // Keep ownership of the module in _module @@ -73,7 +66,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool auto exec = std::unique_ptr(builder.create()); if (!exec) - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment(errorMsg)); + return -1; // FIXME: Handle internal errors _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module auto finalizationStartTime = std::chrono::high_resolution_clock::now(); @@ -84,11 +77,11 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool auto entryFunc = module->getFunction("main"); if (!entryFunc) - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found")); + return -2; // FIXME: Handle internal errors ReturnCode returnCode; std::jmp_buf buf; - Runtime runtime(_gas, _ext, buf, _outputLogs); + Runtime runtime(_data, _env, buf); auto r = setjmp(buf); if (r == 0) { @@ -105,15 +98,12 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool } 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 + returnData = runtime.getReturnData(); // TODO: It might be better to place is in Runtime interface auto&& log = clog(JIT); log << "RETURN [ "; @@ -122,7 +112,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, bool log << "]"; } else - cslog(JIT) << "RETURN " << (int)returnCode; + clog(JIT) << "RETURN " << (int)returnCode; return static_cast(returnCode); } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 932c19304..8d8715a95 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -3,8 +3,7 @@ #include -#include "Common.h" -//#include +#include "Runtime.h" namespace dev { @@ -16,9 +15,9 @@ namespace jit class ExecutionEngine { public: - ExecutionEngine(); + // FIXME: constructor? ExecutionEngine(); - int run(std::unique_ptr module, u256& _gas, bool _outputLogs, ExtVMFace& _ext); + int run(std::unique_ptr module, RuntimeData* _data, Env* _env); bytes returnData; }; From 8672c4b65a954620f896f8f283c7aad83fec0788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 14:49:57 +0100 Subject: [PATCH 293/466] Updating Ext interface --- libevmjit-cpp/CMakeLists.txt | 6 +- libevmjit-cpp/Ext.cpp | 420 +++++++++++++++++++++++++++++++++++ libevmjit-cpp/Ext.h | 68 ++++++ libevmjit/Ext.cpp | 232 +------------------ 4 files changed, 497 insertions(+), 229 deletions(-) create mode 100644 libevmjit-cpp/Ext.cpp create mode 100644 libevmjit-cpp/Ext.h diff --git a/libevmjit-cpp/CMakeLists.txt b/libevmjit-cpp/CMakeLists.txt index 799607562..30035243b 100644 --- a/libevmjit-cpp/CMakeLists.txt +++ b/libevmjit-cpp/CMakeLists.txt @@ -1,7 +1,11 @@ project(evmjit-cpp LANGUAGES CXX) -set(SOURCES VM.cpp VM.h) +set(SOURCES + Ext.cpp Ext.h + Runtime.cpp Runtime.h + VM.cpp VM.h +) source_group("" FILES ${SOURCES}) diff --git a/libevmjit-cpp/Ext.cpp b/libevmjit-cpp/Ext.cpp new file mode 100644 index 000000000..588ba4652 --- /dev/null +++ b/libevmjit-cpp/Ext.cpp @@ -0,0 +1,420 @@ + +#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-cpp/Ext.h b/libevmjit-cpp/Ext.h new file mode 100644 index 000000000..ad4649177 --- /dev/null +++ b/libevmjit-cpp/Ext.h @@ -0,0 +1,68 @@ + +#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/Ext.cpp b/libevmjit/Ext.cpp index 588ba4652..9d7bd8d44 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -8,7 +8,7 @@ //#include //#include -#include "Runtime.h" +#include "RuntimeManager.h" #include "Type.h" #include "Endianness.h" @@ -19,12 +19,6 @@ 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() @@ -185,236 +179,18 @@ void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, s 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) + //FIXME: Move to arithmentics + void ext_exp(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); - } - } } + } } From 49b82cdbac09c3c2058e0b4326645e5da37f7133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 15:02:50 +0100 Subject: [PATCH 294/466] Move EXP implementation from Ext to Arith256 --- libevmjit/Arith256.cpp | 14 ++++++++++++++ libevmjit/Arith256.h | 2 ++ libevmjit/Compiler.cpp | 2 +- libevmjit/Ext.cpp | 26 -------------------------- libevmjit/Ext.h | 1 - 5 files changed, 17 insertions(+), 28 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index aa76ec0ef..95d11e3f3 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -31,6 +31,7 @@ Arith256::Arith256(llvm::IRBuilder<>& _builder) : 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_exp = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_exp", 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()); } @@ -80,6 +81,11 @@ llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2) return binaryOp(m_smod, _arg1, _arg2); } +llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_exp, _arg1, _arg2); +} + llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) { return ternaryOp(m_addmod, _arg1, _arg2, _arg3); @@ -137,6 +143,14 @@ extern "C" *o_result = eth2llvm(arg2 == 0 ? arg2 : (arg1.convert_to() % arg2.convert_to()).convert_to()); } + EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result) + { + bigint left = llvm2eth(*_arg1); + bigint right = llvm2eth(*_arg2); + auto ret = static_cast(boost::multiprecision::powm(left, right, bigint(2) << 256)); + *o_result = eth2llvm(ret); + } + EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) { auto arg1 = llvm2eth(*_arg1); diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 2268d5076..57bc061de 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -20,6 +20,7 @@ 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* exp(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); @@ -32,6 +33,7 @@ private: llvm::Function* m_mod; llvm::Function* m_sdiv; llvm::Function* m_smod; + llvm::Function* m_exp; llvm::Function* m_mulmod; llvm::Function* m_addmod; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 41098510b..1ccd7f74e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -331,7 +331,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode { auto left = stack.pop(); auto right = stack.pop(); - auto ret = _ext.exp(left, right); + auto ret = _arith.exp(left, right); stack.push(ret); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 9d7bd8d44..ef7bba69c 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -135,15 +135,6 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) 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); @@ -175,22 +166,5 @@ void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, s } } - - -extern "C" -{ - using namespace dev::eth::jit; - - //FIXME: Move to arithmentics - void ext_exp(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); - } -} - } } - diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index ad4649177..62bdbf61e 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -26,7 +26,6 @@ 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* _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); From 3298e102af98d3bbe1b26a6ae61f037693a12c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 17:03:04 +0100 Subject: [PATCH 295/466] Remove mock declaration --- libevmjit/Common.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libevmjit/Common.h b/libevmjit/Common.h index dfc60f4d4..a645d58b1 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -17,8 +17,6 @@ using bigint = boost::multiprecision::cpp_int; struct NoteChannel {}; // FIXME: Use some log library? -struct ExtVMFace; - } } } From a0d0f85dd04ac0531f27913523700fada1d7df63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 17:18:25 +0100 Subject: [PATCH 296/466] JIT VM updated --- libevmjit-cpp/VM.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/libevmjit-cpp/VM.cpp b/libevmjit-cpp/VM.cpp index b968008aa..d61b23bd7 100644 --- a/libevmjit-cpp/VM.cpp +++ b/libevmjit-cpp/VM.cpp @@ -4,9 +4,8 @@ #include #include -#include "ExecutionEngine.h" -#include "Compiler.h" -#include "Type.h" +#include "../libevmjit/ExecutionEngine.h" +#include "../libevmjit/Compiler.h" namespace dev { @@ -20,8 +19,30 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) Compiler::Options defaultOptions; auto module = Compiler(defaultOptions).compile(_ext.code); + RuntimeData data = {}; + +#define set(INDEX, VALUE) data.elems[INDEX] = eth2llvm(VALUE) + set(RuntimeData::Gas, m_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 + data.callData = _ext.data.data(); + data.code = _ext.code.data(); +#undef set + ExecutionEngine engine; - auto exitCode = engine.run(std::move(module), m_gas, false, _ext); + auto env = reinterpret_cast(&_ext); + auto exitCode = engine.run(std::move(module), &data, env); switch (static_cast(exitCode)) { From 7db676c0122efab82ba1cddbdd2be0e2d22ba9c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 3 Dec 2014 17:38:19 +0100 Subject: [PATCH 297/466] Client side Env updated --- libevmjit-cpp/Ext.cpp | 330 ++++++++---------------------------------- libevmjit-cpp/Ext.h | 51 ------- 2 files changed, 62 insertions(+), 319 deletions(-) diff --git a/libevmjit-cpp/Ext.cpp b/libevmjit-cpp/Ext.cpp index 588ba4652..b5353499e 100644 --- a/libevmjit-cpp/Ext.cpp +++ b/libevmjit-cpp/Ext.cpp @@ -5,254 +5,89 @@ #include #include -//#include -//#include +#include +#include +#include -#include "Runtime.h" -#include "Type.h" -#include "Endianness.h" +#include "../libevmjit/Utils.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" { + #ifdef _MSC_VER + #define EXPORT __declspec(dllexport) + #else + #define EXPORT + #endif - using namespace dev::eth::jit; + using namespace jit; - EXPORT void ext_store(Runtime* _rt, i256* _index, i256* o_value) + EXPORT void ext_store(ExtVMFace* _env, i256* _index, i256* o_value) { auto index = llvm2eth(*_index); - auto value = _rt->getExt().store(index); // Interface uses native endianness + auto value = _env->store(index); // Interface uses native endianness *o_value = eth2llvm(value); } - EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value) + EXPORT void ext_setStore(ExtVMFace* _env, 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 + if (value == 0 && _env->store(index) != 0) // If delete + _env->sub.refunds += c_sstoreRefundGas; // Increase refund counter - ext.setStore(index, value); // Interface uses native endianness + _env->setStore(index, value); // Interface uses native endianness } - EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* o_value) + EXPORT void ext_calldataload(ExtVMFace* _env, 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 + b[j] = i < _env->data.size() ? _env->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) + EXPORT void ext_balance(ExtVMFace* _env, h256* _address, i256* o_value) { - auto u = _rt->getExt().balance(right160(*_address)); + auto u = _env->balance(right160(*_address)); *o_value = eth2llvm(u); } - EXPORT void ext_suicide(Runtime* _rt, h256 const* _address) + EXPORT void ext_suicide(ExtVMFace* _env, h256 const* _address) { - _rt->getExt().suicide(right160(*_address)); + _env->suicide(right160(*_address)); } - EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* o_address) + EXPORT void ext_create(ExtVMFace* _env, i256* _endowment, i256* _initOff, i256* _initSize, h256* o_address) { - auto&& ext = _rt->getExt(); auto endowment = llvm2eth(*_endowment); - if (ext.balance(ext.myAddress) >= endowment) + if (_env->balance(_env->myAddress) >= endowment) { - ext.subBalance(endowment); + _env->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); + //auto&& initRef = bytesConstRef(_rt->getMemory().data() + initOff, initSize); + auto initRef = bytesConstRef(); // FIXME: Handle memory OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(ext.create(endowment, &gas, initRef, onOp), h256::AlignRight); + h256 address(_env->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) + EXPORT void ext_call(ExtVMFace* _env, 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&& ext = *_env; auto value = llvm2eth(*_value); auto ret = false; @@ -265,8 +100,10 @@ extern "C" 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); + //auto&& inRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); + //auto&& outRef = bytesConstRef(_rt->getMemory().data() + outOff, outSize); + auto inRef = bytesConstRef(); // FIXME: Handle memory + auto outRef = bytesConstRef(); // FIXME: Handle memory OnOpFunc onOp {}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); @@ -276,36 +113,27 @@ extern "C" o_ret->a = ret ? 1 : 0; } - EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* o_ret) + EXPORT void ext_sha3(ExtVMFace* _env, 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 dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); + auto dataRef = bytesConstRef(); // FIXME: Handle memory auto hash = sha3(dataRef); *o_ret = *reinterpret_cast(&hash); } - EXPORT void ext_exp(Runtime*, i256* _left, i256* _right, i256* o_ret) + EXPORT unsigned char* ext_codeAt(ExtVMFace* _env, h256* _addr256) { - 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); + auto& code = _env->codeAt(addr); return const_cast(code.data()); } - EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* o_ret) + EXPORT void ext_codesizeAt(ExtVMFace* _env, h256* _addr256, i256* o_ret) { - auto&& ext = _rt->getExt(); auto addr = right160(*_addr256); - auto& code = ext.codeAt(addr); + auto& code = _env->codeAt(addr); *o_ret = eth2llvm(u256(code.size())); } @@ -316,66 +144,43 @@ extern "C" std::cerr << std::endl; } - EXPORT void ext_log0(Runtime* _rt, i256* _memIdx, i256* _numBytes) + EXPORT void ext_log0(ExtVMFace* _env, 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); - } + //auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + auto dataRef = bytesConstRef(); // FIXME: Handle memory + _env->log({}, dataRef); } - EXPORT void ext_log1(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1) + EXPORT void ext_log1(ExtVMFace* _env, 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); - } + //auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + auto dataRef = bytesConstRef(); // FIXME: Handle memory + _env->log({topic1}, dataRef); } - EXPORT void ext_log2(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2) + EXPORT void ext_log2(ExtVMFace* _env, 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); - } + //auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + auto dataRef = bytesConstRef(); // FIXME: Handle memory + _env->log({ topic1, topic2 }, dataRef); } - EXPORT void ext_log3(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3) + EXPORT void ext_log3(ExtVMFace* _env, 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)); @@ -383,20 +188,13 @@ extern "C" 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); - } + //auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + auto dataRef = bytesConstRef(); // FIXME: Handle memory + _env->log({ topic1, topic2, topic3 }, dataRef); } - EXPORT void ext_log4(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3, i256* _topic4) + EXPORT void ext_log4(ExtVMFace* _env, 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)); @@ -405,16 +203,12 @@ extern "C" 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); - } + //auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); + auto dataRef = bytesConstRef(); // FIXME: Handle memory + _env->log({ topic1, topic2, topic3, topic4 }, dataRef); } } + } } diff --git a/libevmjit-cpp/Ext.h b/libevmjit-cpp/Ext.h index ad4649177..d891c19c9 100644 --- a/libevmjit-cpp/Ext.h +++ b/libevmjit-cpp/Ext.h @@ -1,9 +1,6 @@ #pragma once -#include -#include "CompilerHelper.h" - namespace dev { namespace eth @@ -11,55 +8,7 @@ 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; -}; } From b8e0ad1fd433b228f4123bfaa399fde7ce282182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 11:24:22 +0100 Subject: [PATCH 298/466] Fix exporting Env callback symbols --- libevmjit-cpp/{Ext.cpp => Env.cpp} | 18 ++++++------------ libevmjit-cpp/VM.cpp | 7 +++++++ 2 files changed, 13 insertions(+), 12 deletions(-) rename libevmjit-cpp/{Ext.cpp => Env.cpp} (96%) diff --git a/libevmjit-cpp/Ext.cpp b/libevmjit-cpp/Env.cpp similarity index 96% rename from libevmjit-cpp/Ext.cpp rename to libevmjit-cpp/Env.cpp index b5353499e..2e5b94c82 100644 --- a/libevmjit-cpp/Ext.cpp +++ b/libevmjit-cpp/Env.cpp @@ -11,11 +11,6 @@ #include "../libevmjit/Utils.h" -namespace dev -{ -namespace eth -{ - extern "C" { #ifdef _MSC_VER @@ -24,7 +19,10 @@ extern "C" #define EXPORT #endif - using namespace jit; + using namespace dev; + using namespace dev::eth; + using jit::i256; + using jit::eth2llvm; EXPORT void ext_store(ExtVMFace* _env, i256* _index, i256* o_value) { @@ -44,13 +42,12 @@ extern "C" _env->setStore(index, value); // Interface uses native endianness } - EXPORT void ext_calldataload(ExtVMFace* _env, i256* _index, i256* o_value) + EXPORT void ext_calldataload(ExtVMFace* _env, i256* _index, ::byte* 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 < _env->data.size() ? _env->data[i] : 0; // Keep Big Endian + o_value[j] = i < _env->data.size() ? _env->data[i] : 0; // Keep Big Endian // TODO: It all can be done by adding padding to data or by using min() algorithm without branch } @@ -209,6 +206,3 @@ extern "C" } } -} -} - diff --git a/libevmjit-cpp/VM.cpp b/libevmjit-cpp/VM.cpp index d61b23bd7..bef51b5d9 100644 --- a/libevmjit-cpp/VM.cpp +++ b/libevmjit-cpp/VM.cpp @@ -65,3 +65,10 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) } } } + +namespace +{ + // MSVS linker ignores export symbols in Env.cpp if nothing point at least one of them + extern "C" void ext_store(); + void linkerWorkaround() { ext_store(); } +} From 969f1b54a32890e6f7bf6a53750931edb09f0ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 14:37:07 +0100 Subject: [PATCH 299/466] The way runtime data is passed to jit'ed contract changed --- libevmjit/ExecutionEngine.cpp | 2 +- libevmjit/Runtime.h | 2 +- libevmjit/RuntimeManager.cpp | 58 ++++++++++++++++++++++++++--------- libevmjit/RuntimeManager.h | 3 ++ libevmjit/Type.cpp | 4 ++- libevmjit/Type.h | 1 + 6 files changed, 52 insertions(+), 18 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 64cb250f7..5236d1d36 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -88,7 +88,7 @@ int ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _da auto executionStartTime = std::chrono::high_resolution_clock::now(); - auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(runtime.getDataPtr())}); + auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(&runtime)}); returnCode = static_cast(result.IntVal.getZExtValue()); auto executionEndTime = std::chrono::high_resolution_clock::now(); diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index ace169e00..11a995785 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -38,7 +38,7 @@ public: Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; - RuntimeData* getDataPtr() { return &m_data; } + RuntimeData* getDataPtr() { return &m_data; } // FIXME: Remove StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 58fbd5a20..2d80ad131 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -22,10 +22,25 @@ llvm::StructType* RuntimeManager::getRuntimeDataType() { llvm::Type* elems[] = { - llvm::ArrayType::get(Type::Word, RuntimeData::_size), - Type::BytePtr, - Type::BytePtr, - Type::BytePtr + llvm::ArrayType::get(Type::Word, RuntimeData::_size), // i256[] + Type::BytePtr, // callData + Type::BytePtr // code + }; + type = llvm::StructType::create(elems, "RuntimeData"); + } + return type; +} + +llvm::StructType* RuntimeManager::getRuntimeType() +{ + static llvm::StructType* type = nullptr; + if (!type) + { + llvm::Type* elems[] = + { + Type::RuntimeDataPtr, // data + Type::BytePtr, // Env* + Type::BytePtr // jmpbuf }; type = llvm::StructType::create(elems, "Runtime"); } @@ -59,26 +74,39 @@ llvm::Twine getName(RuntimeData::Index _index) 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_rtPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt"); + m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimeDataPtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimeDataPtr), "data"); 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* rtPtr = &mainFunc->getArgumentList().back(); + m_builder.CreateStore(rtPtr, m_rtPtr); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 0, "dataPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + m_builder.CreateStore(data, 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"); + // FIXME: Data ptr + //if (auto mainFunc = getMainFunction()) + // return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function + return m_builder.CreateLoad(m_rtPtr, "rt"); +} + +llvm::Value* RuntimeManager::getDataPtr() +{ + // FIXME: Data ptr + //if (auto mainFunc = getMainFunction()) + // return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function + return m_builder.CreateLoad(m_dataPtr, "data"); } 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"); + return m_builder.CreateInBoundsGEP(getDataPtr(), idxList, getName(_index) + "Ptr"); } llvm::Value* RuntimeManager::get(RuntimeData::Index _index) @@ -126,19 +154,19 @@ llvm::Value* RuntimeManager::get(Instruction _inst) llvm::Value* RuntimeManager::getCallData() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 1, "calldataPtr"); + auto ptr = getBuilder().CreateStructGEP(getDataPtr(), 1, "calldataPtr"); return getBuilder().CreateLoad(ptr, "calldata"); } llvm::Value* RuntimeManager::getCode() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "codePtr"); + auto ptr = getBuilder().CreateStructGEP(getDataPtr(), 2, "codePtr"); return getBuilder().CreateLoad(ptr, "code"); } llvm::Value* RuntimeManager::getJmpBuf() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 3, "jmpbufPtr"); + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); return getBuilder().CreateLoad(ptr, "jmpbuf"); } @@ -150,7 +178,7 @@ llvm::Value* RuntimeManager::getGas() 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"); + auto ptr = m_builder.CreateInBoundsGEP(getDataPtr(), idxList, "gasPtr"); m_builder.CreateStore(_gas, ptr); } diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index 1231d9885..32f7786d7 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -18,6 +18,7 @@ public: RuntimeManager(llvm::IRBuilder<>& _builder); llvm::Value* getRuntimePtr(); + llvm::Value* getDataPtr(); llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); @@ -30,6 +31,7 @@ public: void raiseException(ReturnCode _returnCode); + static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeDataType(); private: @@ -37,6 +39,7 @@ private: void set(RuntimeData::Index _index, llvm::Value* _value); llvm::Value* getJmpBuf(); + llvm::GlobalVariable* m_rtPtr = nullptr; llvm::GlobalVariable* m_dataPtr = nullptr; llvm::Function* m_longjmp = nullptr; }; diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index c34be45d5..405302860 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -20,6 +20,7 @@ llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; llvm::IntegerType* Type::MainReturn; +llvm::PointerType* Type::RuntimeDataPtr; llvm::PointerType* Type::RuntimePtr; void Type::init(llvm::LLVMContext& _context) @@ -33,7 +34,8 @@ void Type::init(llvm::LLVMContext& _context) BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); MainReturn = llvm::Type::getInt32Ty(_context); - RuntimePtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); + RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); + RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); } llvm::ConstantInt* Constant::get(int64_t _n) diff --git a/libevmjit/Type.h b/libevmjit/Type.h index d0534bd75..393b72c5c 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -31,6 +31,7 @@ struct Type /// Main function return type static llvm::IntegerType* MainReturn; + static llvm::PointerType* RuntimeDataPtr; static llvm::PointerType* RuntimePtr; static void init(llvm::LLVMContext& _context); From 2b4430eedfa0614ff765c317ffa2d2c01d31acf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 15:10:53 +0100 Subject: [PATCH 300/466] Change Env functions first argument type to opaque Env* --- libevmjit/Ext.cpp | 22 +++++++++++----------- libevmjit/RuntimeManager.cpp | 12 +++++++++++- libevmjit/RuntimeManager.h | 2 ++ libevmjit/Type.cpp | 28 +++++++++++++++++----------- libevmjit/Type.h | 1 + 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index ef7bba69c..4e681d5be 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -40,7 +40,7 @@ Ext::Ext(RuntimeManager& _runtimeManager): 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}; + llvm::Type* argsTypes[] = {Type::EnvPtr, 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); @@ -63,7 +63,7 @@ Ext::Ext(RuntimeManager& _runtimeManager): 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 + m_builder.CreateCall3(m_store, getRuntimeManager().getEnv(), m_args[0], m_args[1]); // Uses native endianness return m_builder.CreateLoad(m_args[1]); } @@ -71,13 +71,13 @@ 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 + m_builder.CreateCall3(m_setStore, getRuntimeManager().getEnv(), 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]); + m_builder.CreateCall3(m_calldataload, getRuntimeManager().getEnv(), m_args[0], m_args[1]); auto ret = m_builder.CreateLoad(m_args[1]); return Endianness::toNative(m_builder, ret); } @@ -86,7 +86,7 @@ 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]); + m_builder.CreateCall3(m_balance, getRuntimeManager().getEnv(), m_args[0], m_args[1]); return m_builder.CreateLoad(m_args[1]); } @@ -94,7 +94,7 @@ 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]); + m_builder.CreateCall2(m_suicide, getRuntimeManager().getEnv(), m_args[0]); } llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) @@ -120,7 +120,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); - 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]); + createCall(m_call, getRuntimeManager().getEnv(), 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]); } @@ -129,7 +129,7 @@ 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]); + createCall(m_sha3, getRuntimeManager().getEnv(), 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; @@ -139,14 +139,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.CreateCall2(m_codeAt, getRuntimeManager().getRuntimePtr(), m_args[0]); + return m_builder.CreateCall2(m_codeAt, getRuntimeManager().getEnv(), 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]); + createCall(m_codesizeAt, getRuntimeManager().getEnv(), m_args[0], m_args[1]); return m_builder.CreateLoad(m_args[1]); } @@ -155,7 +155,7 @@ void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, s 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(); + args[0] = getRuntimeManager().getEnv(); m_builder.CreateStore(_memIdx, m_args[0]); m_builder.CreateStore(_numBytes, m_args[1]); diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 2d80ad131..56efa0c64 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -39,7 +39,7 @@ llvm::StructType* RuntimeManager::getRuntimeType() llvm::Type* elems[] = { Type::RuntimeDataPtr, // data - Type::BytePtr, // Env* + Type::EnvPtr, // Env* Type::BytePtr // jmpbuf }; type = llvm::StructType::create(elems, "Runtime"); @@ -85,6 +85,10 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui auto dataPtr = m_builder.CreateStructGEP(rtPtr, 0, "dataPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); m_builder.CreateStore(data, m_dataPtr); + + auto envPtr = m_builder.CreateStructGEP(rtPtr, 1, "envPtr"); + m_env = m_builder.CreateLoad(envPtr, "env"); + assert(m_env->getType() == Type::EnvPtr); } llvm::Value* RuntimeManager::getRuntimePtr() @@ -103,6 +107,12 @@ llvm::Value* RuntimeManager::getDataPtr() return m_builder.CreateLoad(m_dataPtr, "data"); } +llvm::Value* RuntimeManager::getEnv() +{ + assert(getMainFunction()); // Available only in main function + return m_env; +} + llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) { llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)}; diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index 32f7786d7..c10c8cd25 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -19,6 +19,7 @@ public: llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); + llvm::Value* getEnv(); llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); @@ -42,6 +43,7 @@ private: llvm::GlobalVariable* m_rtPtr = nullptr; llvm::GlobalVariable* m_dataPtr = nullptr; llvm::Function* m_longjmp = nullptr; + llvm::Value* m_env = nullptr; }; } diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 405302860..62b819dc8 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -20,22 +20,28 @@ llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; llvm::IntegerType* Type::MainReturn; +llvm::PointerType* Type::EnvPtr; llvm::PointerType* Type::RuntimeDataPtr; 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); - RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); - RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); + if (!Word) // Do init only once + { + 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); + + EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); + RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); + RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); + } } llvm::ConstantInt* Constant::get(int64_t _n) diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 393b72c5c..b0e3fa237 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -31,6 +31,7 @@ struct Type /// Main function return type static llvm::IntegerType* MainReturn; + static llvm::PointerType* EnvPtr; static llvm::PointerType* RuntimeDataPtr; static llvm::PointerType* RuntimePtr; From ddfe85bd3390655033d3b8d82a37abf03d412045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 15:22:26 +0100 Subject: [PATCH 301/466] Update VM gas counter after execution --- libevmjit-cpp/VM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libevmjit-cpp/VM.cpp b/libevmjit-cpp/VM.cpp index bef51b5d9..e49607b3f 100644 --- a/libevmjit-cpp/VM.cpp +++ b/libevmjit-cpp/VM.cpp @@ -58,6 +58,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) break; } + m_gas = llvm2eth(data.elems[RuntimeData::Gas]); m_output = std::move(engine.returnData); return {m_output.data(), m_output.size()}; // TODO: This all bytesConstRef stuff sucks } From 259d1d20964c6480eb7384a03110cb74495fb23b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 15:25:53 +0100 Subject: [PATCH 302/466] Old files removed --- libevmjit-cpp/Env.cpp | 2 -- libevmjit-cpp/Ext.h | 17 ---------- libevmjit-cpp/Runtime.cpp | 70 --------------------------------------- libevmjit-cpp/Runtime.h | 64 ----------------------------------- 4 files changed, 153 deletions(-) delete mode 100644 libevmjit-cpp/Ext.h delete mode 100644 libevmjit-cpp/Runtime.cpp delete mode 100644 libevmjit-cpp/Runtime.h diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 2e5b94c82..5014e4947 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -1,6 +1,4 @@ -#include "Ext.h" - #include #include #include diff --git a/libevmjit-cpp/Ext.h b/libevmjit-cpp/Ext.h deleted file mode 100644 index d891c19c9..000000000 --- a/libevmjit-cpp/Ext.h +++ /dev/null @@ -1,17 +0,0 @@ - -#pragma once - -namespace dev -{ -namespace eth -{ -namespace jit -{ - - - - -} -} -} - diff --git a/libevmjit-cpp/Runtime.cpp b/libevmjit-cpp/Runtime.cpp deleted file mode 100644 index 3fa36253b..000000000 --- a/libevmjit-cpp/Runtime.cpp +++ /dev/null @@ -1,70 +0,0 @@ - -#include "Runtime.h" - -#include -#include -#include - -//#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -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]); -} - -bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy -{ - // 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 - auto dataBeg = m_memory.begin() + offset; - return {dataBeg, dataBeg + size}; -} - -bool Runtime::outputLogs() const -{ - return m_outputLogs; -} - - -} -} -} diff --git a/libevmjit-cpp/Runtime.h b/libevmjit-cpp/Runtime.h deleted file mode 100644 index 1c11afc5d..000000000 --- a/libevmjit-cpp/Runtime.h +++ /dev/null @@ -1,64 +0,0 @@ - -#pragma once - -#include -#include - -//#include - -#include "Instruction.h" -#include "CompilerHelper.h" -#include "Utils.h" -#include "Type.h" -#include "RuntimeData.h" - - -#ifdef _MSC_VER - #define EXPORT __declspec(dllexport) -#else - #define EXPORT -#endif - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -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; - bytes 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 -}; - -} -} -} From cc6bb83fc6778a765321d025e756591ada648a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 15:39:36 +0100 Subject: [PATCH 303/466] Simplify JIT logs --- libevmjit/Compiler.cpp | 4 ++++ libevmjit/ExecutionEngine.cpp | 21 +++++++++------------ libevmjit/Utils.h | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1ccd7f74e..cb6eb2541 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -2,6 +2,7 @@ #include "Compiler.h" #include +#include #include @@ -152,6 +153,7 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) std::unique_ptr Compiler::compile(bytes const& _bytecode) { + auto compilationStartTime = std::chrono::high_resolution_clock::now(); auto module = std::unique_ptr(new llvm::Module("main", m_builder.getContext())); // Create main function @@ -242,6 +244,8 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode) fpManager.run(*m_mainFunc); } + auto compilationEndTime = std::chrono::high_resolution_clock::now(); + clog(JIT) << "JIT: " << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count(); return module; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 5236d1d36..ab3f83064 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -69,11 +69,12 @@ int ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _da return -1; // FIXME: Handle internal errors _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - auto finalizationStartTime = std::chrono::high_resolution_clock::now(); + auto finalizationStartTime = std::chrono::high_resolution_clock::now(); // FIXME: It's not compilation time exec->finalizeObject(); auto finalizationEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << "Module finalization time: " - << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); + clog(JIT) << " + " << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); + + auto executionStartTime = std::chrono::high_resolution_clock::now(); auto entryFunc = module->getFunction("main"); if (!entryFunc) @@ -85,21 +86,15 @@ int ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _da auto r = setjmp(buf); if (r == 0) { - - auto executionStartTime = std::chrono::high_resolution_clock::now(); - auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(&runtime)}); 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); - clog(JIT) << "Max stack size: " << Stack::maxStackSize; + auto executionEndTime = std::chrono::high_resolution_clock::now(); + clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms "; + //clog(JIT) << "Max stack size: " << Stack::maxStackSize; if (returnCode == ReturnCode::Return) { @@ -114,6 +109,8 @@ int ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _da else clog(JIT) << "RETURN " << (int)returnCode; + clog(JIT) << "\n"; + return static_cast(returnCode); } diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 06ef9af81..73e01d2ee 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -14,7 +14,7 @@ namespace jit struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; -#define clog(CHANNEL) std::cerr << CHANNEL::name() << ": " +#define clog(CHANNEL) std::cerr /// Representation of 256-bit value binary compatible with LLVM i256 // TODO: Replace with h256 From 4fc4e76fa5744fa522b3dc3fa0b1338bc364f30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 16:18:06 +0100 Subject: [PATCH 304/466] Change the way memory is passed to sha3 Env function --- libevmjit-cpp/Env.cpp | 10 +++------- libevmjit/Compiler.cpp | 2 +- libevmjit/Ext.cpp | 15 +++++++++------ libevmjit/Ext.h | 6 ++++-- libevmjit/Memory.cpp | 9 +++++++-- libevmjit/Memory.h | 1 + 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 5014e4947..392a2595e 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -108,14 +108,10 @@ extern "C" o_ret->a = ret ? 1 : 0; } - EXPORT void ext_sha3(ExtVMFace* _env, i256* _inOff, i256* _inSize, i256* o_ret) + EXPORT void ext_sha3(ExtVMFace* _env, byte* _begin, uint64_t _size, h256* o_hash) { - auto inOff = static_cast(llvm2eth(*_inOff)); - auto inSize = static_cast(llvm2eth(*_inSize)); - //auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); - auto dataRef = bytesConstRef(); // FIXME: Handle memory - auto hash = sha3(dataRef); - *o_ret = *reinterpret_cast(&hash); + auto hash = sha3({_begin, _size}); + *o_hash = hash; } EXPORT unsigned char* ext_codeAt(ExtVMFace* _env, h256* _addr256) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index cb6eb2541..962bbf333 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -172,7 +172,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode) RuntimeManager runtimeManager(m_builder); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); - Ext ext(runtimeManager); + Ext ext(runtimeManager, memory); Stack stack(m_builder, runtimeManager); Arith256 arith(m_builder); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 4e681d5be..4dd55deb3 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -9,6 +9,7 @@ //#include #include "RuntimeManager.h" +#include "Memory.h" #include "Type.h" #include "Endianness.h" @@ -19,9 +20,9 @@ namespace eth namespace jit { -Ext::Ext(RuntimeManager& _runtimeManager): +Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): RuntimeHelper(_runtimeManager), - m_data() + m_memoryMan(_memoryMan) { auto&& ctx = m_builder.getContext(); auto module = getModule(); @@ -49,7 +50,6 @@ Ext::Ext(RuntimeManager& _runtimeManager): 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); @@ -58,6 +58,9 @@ Ext::Ext(RuntimeManager& _runtimeManager): 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::Type* sha3ArgsTypes[] = { Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr }; + m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "ext_sha3", module); } llvm::Value* Ext::store(llvm::Value* _index) @@ -127,9 +130,9 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V 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().getEnv(), m_args[0], m_arg2, m_args[1]); + auto begin = m_memoryMan.getBytePtr(_inOff); + auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size"); + createCall(m_sha3, getRuntimeManager().getEnv(), begin, size, m_args[1]); llvm::Value* hash = m_builder.CreateLoad(m_args[1]); hash = Endianness::toNative(m_builder, hash); return hash; diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 62bdbf61e..3279dd960 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -10,11 +10,12 @@ namespace eth { namespace jit { + class Memory; class Ext : public RuntimeHelper { public: - Ext(RuntimeManager& _runtimeManager); + Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan); llvm::Value* store(llvm::Value* _index); void setStore(llvm::Value* _index, llvm::Value* _value); @@ -32,6 +33,7 @@ public: void log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array const& _topics); private: + Memory& m_memoryMan; llvm::Value* m_args[2]; llvm::Value* m_arg2; @@ -41,7 +43,7 @@ private: llvm::Value* m_arg6; llvm::Value* m_arg7; llvm::Value* m_arg8; - llvm::Value* m_data; + llvm::Value* m_data = nullptr; llvm::Function* m_store; llvm::Function* m_setStore; llvm::Function* m_calldataload; diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 7039ce198..1f31dff72 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -118,8 +118,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet 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"); + auto ptr = getBytePtr(index); if (isWord) ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); if (_isStore) @@ -169,6 +168,12 @@ llvm::Value* Memory::getSize() return m_builder.CreateLoad(m_size); } +llvm::Value* Memory::getBytePtr(llvm::Value* _index) +{ + auto data = m_builder.CreateLoad(m_data, "data"); + return m_builder.CreateGEP(data, _index, "ptr"); +} + void Memory::require(llvm::Value* _offset, llvm::Value* _size) { m_builder.CreateCall2(m_require, _offset, _size); diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index bbd35b973..8d33fbc4f 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -19,6 +19,7 @@ public: void storeByte(llvm::Value* _addr, llvm::Value* _byte); llvm::Value* getData(); llvm::Value* getSize(); + llvm::Value* getBytePtr(llvm::Value* _index); void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex, llvm::Value* _destMemIdx, llvm::Value* _byteCount); From 116ce60b1c0aa69df406ef2c390fd1ffa12a7952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 16:21:13 +0100 Subject: [PATCH 305/466] Remove Env* param from env_sha3 function (not needed) --- libevmjit-cpp/Env.cpp | 2 +- libevmjit/Ext.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 392a2595e..66ceefeac 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -108,7 +108,7 @@ extern "C" o_ret->a = ret ? 1 : 0; } - EXPORT void ext_sha3(ExtVMFace* _env, byte* _begin, uint64_t _size, h256* o_hash) + EXPORT void ext_sha3(byte* _begin, uint64_t _size, h256* o_hash) { auto hash = sha3({_begin, _size}); *o_hash = hash; diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 4dd55deb3..2d1fd2fbd 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -59,7 +59,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): 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::Type* sha3ArgsTypes[] = { Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr }; + llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "ext_sha3", module); } @@ -132,7 +132,7 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) { auto begin = m_memoryMan.getBytePtr(_inOff); auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size"); - createCall(m_sha3, getRuntimeManager().getEnv(), begin, size, m_args[1]); + createCall(m_sha3, begin, size, m_args[1]); llvm::Value* hash = m_builder.CreateLoad(m_args[1]); hash = Endianness::toNative(m_builder, hash); return hash; From 408fda8498899ae4dba6642da9450fbf11493dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 16:28:47 +0100 Subject: [PATCH 306/466] Old code removed --- libevmjit-cpp/Env.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 66ceefeac..487e8c884 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -1,8 +1,4 @@ -#include -#include -#include - #include #include #include @@ -128,13 +124,6 @@ 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(ExtVMFace* _env, i256* _memIdx, i256* _numBytes) { auto memIdx = llvm2eth(*_memIdx).convert_to(); From 6f84f3d1ade42bcacc99533d4807b9b759a5938b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 16:52:16 +0100 Subject: [PATCH 307/466] Rename sload, sstore & sha3 Env functions --- libevmjit-cpp/Env.cpp | 6 +++--- libevmjit-cpp/VM.cpp | 4 ++-- libevmjit/Compiler.cpp | 4 ++-- libevmjit/Ext.cpp | 14 +++++++------- libevmjit/Ext.h | 8 ++++---- libevmjit/GasMeter.cpp | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 487e8c884..91f414554 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -18,14 +18,14 @@ extern "C" using jit::i256; using jit::eth2llvm; - EXPORT void ext_store(ExtVMFace* _env, i256* _index, i256* o_value) + EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) { auto index = llvm2eth(*_index); auto value = _env->store(index); // Interface uses native endianness *o_value = eth2llvm(value); } - EXPORT void ext_setStore(ExtVMFace* _env, i256* _index, i256* _value) + EXPORT void env_sstore(ExtVMFace* _env, i256* _index, i256* _value) { auto index = llvm2eth(*_index); auto value = llvm2eth(*_value); @@ -104,7 +104,7 @@ extern "C" o_ret->a = ret ? 1 : 0; } - EXPORT void ext_sha3(byte* _begin, uint64_t _size, h256* o_hash) + EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) { auto hash = sha3({_begin, _size}); *o_hash = hash; diff --git a/libevmjit-cpp/VM.cpp b/libevmjit-cpp/VM.cpp index e49607b3f..7ac51097d 100644 --- a/libevmjit-cpp/VM.cpp +++ b/libevmjit-cpp/VM.cpp @@ -70,6 +70,6 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) namespace { // MSVS linker ignores export symbols in Env.cpp if nothing point at least one of them - extern "C" void ext_store(); - void linkerWorkaround() { ext_store(); } + extern "C" void env_sload(); + void linkerWorkaround() { env_sload(); } } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 962bbf333..8c9113fde 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -577,7 +577,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::SLOAD: { auto index = stack.pop(); - auto value = _ext.store(index); + auto value = _ext.sload(index); stack.push(value); break; } @@ -587,7 +587,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto index = stack.pop(); auto value = stack.pop(); _gasMeter.countSStore(_ext, index, value); - _ext.setStore(index, value); + _ext.sstore(index, value); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 2d1fd2fbd..4edaf91e3 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -43,8 +43,8 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): llvm::Type* argsTypes[] = {Type::EnvPtr, 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_sload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sload", module); + m_sstore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sstore", 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); @@ -60,21 +60,21 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): m_log4 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 7}, false), Linkage::ExternalLinkage, "ext_log4", module); llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; - m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "ext_sha3", module); + m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); } -llvm::Value* Ext::store(llvm::Value* _index) +llvm::Value* Ext::sload(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateCall3(m_store, getRuntimeManager().getEnv(), m_args[0], m_args[1]); // Uses native endianness + m_builder.CreateCall3(m_sload, getRuntimeManager().getEnv(), 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) +void Ext::sstore(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().getEnv(), m_args[0], m_args[1]); // Uses native endianness + m_builder.CreateCall3(m_sstore, getRuntimeManager().getEnv(), m_args[0], m_args[1]); // Uses native endianness } llvm::Value* Ext::calldataload(llvm::Value* _index) diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 3279dd960..fc1930c34 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -17,8 +17,8 @@ class Ext : public RuntimeHelper public: Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan); - llvm::Value* store(llvm::Value* _index); - void setStore(llvm::Value* _index, llvm::Value* _value); + llvm::Value* sload(llvm::Value* _index); + void sstore(llvm::Value* _index, llvm::Value* _value); llvm::Value* balance(llvm::Value* _address); void suicide(llvm::Value* _address); @@ -44,8 +44,8 @@ private: llvm::Value* m_arg7; llvm::Value* m_arg8; llvm::Value* m_data = nullptr; - llvm::Function* m_store; - llvm::Function* m_setStore; + llvm::Function* m_sload; + llvm::Function* m_sstore; llvm::Function* m_calldataload; llvm::Function* m_balance; llvm::Function* m_suicide; diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 20b3a8eec..96bffc250 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -148,7 +148,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu { assert(!m_checkCall); // Everything should've been commited before - auto oldValue = _ext.store(_index); + auto oldValue = _ext.sload(_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"); From 69dae9a83a9cf958517ca63057336008dc3b5459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 17:32:12 +0100 Subject: [PATCH 308/466] env_create updated --- libevmjit-cpp/Env.cpp | 8 ++------ libevmjit/Ext.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 91f414554..e9439f1ae 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -56,7 +56,7 @@ extern "C" _env->suicide(right160(*_address)); } - EXPORT void ext_create(ExtVMFace* _env, i256* _endowment, i256* _initOff, i256* _initSize, h256* o_address) + EXPORT void env_create(ExtVMFace* _env, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { auto endowment = llvm2eth(*_endowment); @@ -64,12 +64,8 @@ extern "C" { _env->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); - auto initRef = bytesConstRef(); // FIXME: Handle memory OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(_env->create(endowment, &gas, initRef, onOp), h256::AlignRight); + h256 address(_env->create(endowment, &gas, {_initBeg, _initSize}, onOp), h256::AlignRight); *o_address = address; } else diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 4edaf91e3..c870bdf6a 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -48,7 +48,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): 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_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); @@ -61,6 +60,9 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); + + llvm::Type* createArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr}; + m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, createArgsTypes, false), Linkage::ExternalLinkage, "env_create", module); } llvm::Value* Ext::sload(llvm::Value* _index) @@ -103,9 +105,9 @@ void Ext::suicide(llvm::Value* _address) 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]); + auto begin = m_memoryMan.getBytePtr(_initOff); + auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); + createCall(m_create, getRuntimeManager().getEnv(), m_args[0], begin, size, m_args[1]); llvm::Value* address = m_builder.CreateLoad(m_args[1]); address = Endianness::toNative(m_builder, address); return address; From 63719d24bcd94c5b5c6bd701d14cdeb927bd9832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 18:18:39 +0100 Subject: [PATCH 309/466] env_call updated --- libevmjit-cpp/Env.cpp | 29 +++++++++++------------------ libevmjit/Ext.cpp | 16 +++++++++------- libevmjit/Type.cpp | 2 ++ libevmjit/Type.h | 1 + 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index e9439f1ae..b0f95f453 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -36,6 +36,7 @@ extern "C" _env->setStore(index, value); // Interface uses native endianness } + // TODO: Move to Memory/Runtime EXPORT void ext_calldataload(ExtVMFace* _env, i256* _index, ::byte* o_value) { auto index = static_cast(llvm2eth(*_index)); @@ -72,32 +73,24 @@ extern "C" *o_address = {}; } - EXPORT void ext_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* o_ret) + EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { - auto&& ext = *_env; auto value = llvm2eth(*_value); - - auto ret = false; - auto gas = llvm2eth(*io_gas); - if (ext.balance(ext.myAddress) >= value) + if (_env->balance(_env->myAddress) >= value) { - ext.subBalance(value); + _env->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); - auto inRef = bytesConstRef(); // FIXME: Handle memory - auto outRef = bytesConstRef(); // FIXME: Handle memory + auto inRef = bytesConstRef{_inBeg, _inSize}; + auto outRef = bytesConstRef{_outBeg, _outSize}; OnOpFunc onOp {}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); - ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); + auto gas = llvm2eth(*io_gas); + auto ret = _env->call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); + *io_gas = eth2llvm(gas); + return ret; } - *io_gas = eth2llvm(gas); - o_ret->a = ret ? 1 : 0; + return false; } EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index c870bdf6a..51e0b5ded 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -48,7 +48,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): 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_call = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), Linkage::ExternalLinkage, "ext_call", 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); @@ -63,6 +62,9 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): llvm::Type* createArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr}; m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, createArgsTypes, false), Linkage::ExternalLinkage, "env_create", module); + + llvm::Type* callArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr}; + m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, callArgsTypes, false), Linkage::ExternalLinkage, "env_call", module); } llvm::Value* Ext::sload(llvm::Value* _index) @@ -119,15 +121,15 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V 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 inBeg = m_memoryMan.getBytePtr(_inOff); + auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); + auto outBeg = m_memoryMan.getBytePtr(_outOff); + auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); m_builder.CreateStore(codeAddress, m_arg8); - createCall(m_call, getRuntimeManager().getEnv(), m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]); + auto ret = createCall(m_call, getRuntimeManager().getEnv(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8); _gas = m_builder.CreateLoad(m_args[0]); // Return gas - return m_builder.CreateLoad(m_args[1]); + return m_builder.CreateZExt(ret, Type::Word, "ret"); } llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 62b819dc8..dcff24153 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -15,6 +15,7 @@ namespace jit llvm::IntegerType* Type::Word; llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; +llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Size; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; @@ -32,6 +33,7 @@ void Type::init(llvm::LLVMContext& _context) WordPtr = Word->getPointerTo(); lowPrecision = llvm::Type::getInt64Ty(_context); // TODO: Size should be architecture-dependent + Bool = llvm::Type::getInt1Ty(_context); Size = llvm::Type::getInt64Ty(_context); Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); diff --git a/libevmjit/Type.h b/libevmjit/Type.h index b0e3fa237..fd3c905d1 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -21,6 +21,7 @@ struct Type /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required static llvm::IntegerType* lowPrecision; + static llvm::IntegerType* Bool; static llvm::IntegerType* Size; static llvm::IntegerType* Byte; From 4366542b63e9780d84dba404b868b69aad6d1789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 19:27:08 +0100 Subject: [PATCH 310/466] LOGs reimplemented --- libevmjit-cpp/Env.cpp | 67 +++++++----------------------------------- libevmjit/Compiler.cpp | 4 +-- libevmjit/Ext.cpp | 38 ++++++++++++------------ libevmjit/Ext.h | 8 ++--- 4 files changed, 35 insertions(+), 82 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index b0f95f453..13b4002ff 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -113,68 +113,23 @@ extern "C" *o_ret = eth2llvm(u256(code.size())); } - EXPORT void ext_log0(ExtVMFace* _env, i256* _memIdx, i256* _numBytes) + EXPORT void env_log(ExtVMFace* _env, byte* _beg, uint64_t _size, h256* _topic1, h256* _topic2, h256* _topic3, h256* _topic4) { - auto memIdx = llvm2eth(*_memIdx).convert_to(); - auto numBytes = llvm2eth(*_numBytes).convert_to(); + dev::h256s topics; - //auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); - auto dataRef = bytesConstRef(); // FIXME: Handle memory - _env->log({}, dataRef); - } - - EXPORT void ext_log1(ExtVMFace* _env, i256* _memIdx, i256* _numBytes, i256* _topic1) - { - auto memIdx = static_cast(llvm2eth(*_memIdx)); - auto numBytes = static_cast(llvm2eth(*_numBytes)); - - auto topic1 = llvm2eth(*_topic1); - - //auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); - auto dataRef = bytesConstRef(); // FIXME: Handle memory - _env->log({topic1}, dataRef); - } - - EXPORT void ext_log2(ExtVMFace* _env, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2) - { - auto memIdx = static_cast(llvm2eth(*_memIdx)); - auto numBytes = static_cast(llvm2eth(*_numBytes)); + if (_topic1) + topics.push_back(*_topic1); - auto topic1 = llvm2eth(*_topic1); - auto topic2 = llvm2eth(*_topic2); + if (_topic2) + topics.push_back(*_topic2); - //auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); - auto dataRef = bytesConstRef(); // FIXME: Handle memory - _env->log({ topic1, topic2 }, dataRef); - } - - EXPORT void ext_log3(ExtVMFace* _env, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3) - { - 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); - auto dataRef = bytesConstRef(); // FIXME: Handle memory - _env->log({ topic1, topic2, topic3 }, dataRef); - } - - EXPORT void ext_log4(ExtVMFace* _env, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3, i256* _topic4) - { - auto memIdx = static_cast(llvm2eth(*_memIdx)); - auto numBytes = static_cast(llvm2eth(*_numBytes)); + if (_topic3) + topics.push_back(*_topic3); - auto topic1 = llvm2eth(*_topic1); - auto topic2 = llvm2eth(*_topic2); - auto topic3 = llvm2eth(*_topic3); - auto topic4 = llvm2eth(*_topic4); + if (_topic4) + topics.push_back(*_topic4); - //auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes); - auto dataRef = bytesConstRef(); // FIXME: Handle memory - _env->log({ topic1, topic2, topic3, topic4 }, dataRef); + _env->log(std::move(topics), {_beg, _size}); } } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 8c9113fde..91e25c111 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -811,12 +811,12 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode // This will commit the current cost block _gasMeter.countLogData(numBytes); - std::array topics; + 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); + _ext.log(beginIdx, numBytes, topics); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 51e0b5ded..a686f7751 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -48,14 +48,9 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): 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_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module); + m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module); // FIXME: Remove 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::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); @@ -65,6 +60,9 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): llvm::Type* callArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr}; m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, callArgsTypes, false), Linkage::ExternalLinkage, "env_call", module); + + llvm::Type* logArgsTypes[] = {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; + m_log = llvm::Function::Create(llvm::FunctionType::get(Type::Void, logArgsTypes, false), Linkage::ExternalLinkage, "env_log", module); } llvm::Value* Ext::sload(llvm::Value* _index) @@ -157,19 +155,23 @@ 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) +void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, 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().getEnv(); - 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)); + auto begin = m_memoryMan.getBytePtr(_memIdx); + auto size = m_builder.CreateTrunc(_numBytes, Type::Size, "size"); + llvm::Value* args[] = {getRuntimeManager().getEnv(), begin, size, m_arg2, m_arg3, m_arg4, m_arg5}; + + auto topicArgPtr = &args[3]; + for (auto&& topic : _topics) + { + if (topic) + m_builder.CreateStore(Endianness::toBE(m_builder, topic), *topicArgPtr); + else + *topicArgPtr = llvm::ConstantPointerNull::get(Type::WordPtr); + ++topicArgPtr; + } + + m_builder.CreateCall(m_log, args); } } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index fc1930c34..61888e9ff 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -30,7 +30,7 @@ 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); + void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics); private: Memory& m_memoryMan; @@ -55,11 +55,7 @@ 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; + llvm::Function* m_log; }; From 58d2bfbd8a0af5e1fa5088ff04e5e7dc25c81e31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 20:12:05 +0100 Subject: [PATCH 311/466] External code access in Env reimplemented --- libevmjit-cpp/Env.cpp | 12 +++--------- libevmjit/Compiler.cpp | 11 +++++------ libevmjit/Ext.cpp | 22 +++++++++------------- libevmjit/Ext.h | 13 +++++++++---- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 13b4002ff..72775822c 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -99,18 +99,12 @@ extern "C" *o_hash = hash; } - EXPORT unsigned char* ext_codeAt(ExtVMFace* _env, h256* _addr256) + EXPORT byte const* env_getExtCode(ExtVMFace* _env, h256* _addr256, uint64_t* o_size) { auto addr = right160(*_addr256); auto& code = _env->codeAt(addr); - return const_cast(code.data()); - } - - EXPORT void ext_codesizeAt(ExtVMFace* _env, h256* _addr256, i256* o_ret) - { - auto addr = right160(*_addr256); - auto& code = _env->codeAt(addr); - *o_ret = eth2llvm(u256(code.size())); + *o_size = code.size(); + return code.data(); } EXPORT void env_log(ExtVMFace* _env, byte* _beg, uint64_t _size, h256* _topic1, h256* _topic2, h256* _topic3, h256* _topic4) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 91e25c111..32f1579ee 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -681,8 +681,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::EXTCODESIZE: { auto addr = stack.pop(); - auto value = _ext.codesizeAt(addr); - stack.push(value); + auto codeRef = _ext.getExtCode(addr); + stack.push(codeRef.size); break; } @@ -714,15 +714,14 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::EXTCODECOPY: { - auto extAddr = stack.pop(); + auto addr = stack.pop(); auto destMemIdx = stack.pop(); auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto srcPtr = _ext.codeAt(extAddr); - auto srcSize = _ext.codesizeAt(extAddr); + auto codeRef = _ext.getExtCode(addr); - _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + _memory.copyBytes(codeRef.ptr, codeRef.size, srcIdx, destMemIdx, reqBytes); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index a686f7751..d14a67ac0 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -38,6 +38,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): 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"); + m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); using Linkage = llvm::GlobalValue::LinkageTypes; @@ -48,9 +49,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): 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_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module); // FIXME: Remove - 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); llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); @@ -63,6 +61,9 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): llvm::Type* logArgsTypes[] = {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; m_log = llvm::Function::Create(llvm::FunctionType::get(Type::Void, logArgsTypes, false), Linkage::ExternalLinkage, "env_log", module); + + llvm::Type* getExtCodeArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()}; + m_getExtCode = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, getExtCodeArgsTypes, false), Linkage::ExternalLinkage, "env_getExtCode", module); } llvm::Value* Ext::sload(llvm::Value* _index) @@ -140,19 +141,14 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) return hash; } -llvm::Value* Ext::codeAt(llvm::Value* _addr) +MemoryRef Ext::getExtCode(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); m_builder.CreateStore(addr, m_args[0]); - return m_builder.CreateCall2(m_codeAt, getRuntimeManager().getEnv(), 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().getEnv(), m_args[0], m_args[1]); - return m_builder.CreateLoad(m_args[1]); + auto code = createCall(m_getExtCode, getRuntimeManager().getEnv(), m_args[0], m_size); + auto codeSize = m_builder.CreateLoad(m_size); + auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); + return {code, codeSize256}; } void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics) diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 61888e9ff..21e67ba88 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -12,6 +12,12 @@ namespace jit { class Memory; +struct MemoryRef +{ + llvm::Value* ptr; + llvm::Value* size; +}; + class Ext : public RuntimeHelper { public: @@ -27,8 +33,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* _codeAddress); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); - llvm::Value* codeAt(llvm::Value* _addr); - llvm::Value* codesizeAt(llvm::Value* _addr); + MemoryRef getExtCode(llvm::Value* _addr); void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics); @@ -43,6 +48,7 @@ private: llvm::Value* m_arg6; llvm::Value* m_arg7; llvm::Value* m_arg8; + llvm::Value* m_size; llvm::Value* m_data = nullptr; llvm::Function* m_sload; llvm::Function* m_sstore; @@ -53,8 +59,7 @@ private: llvm::Function* m_call; llvm::Function* m_sha3; llvm::Function* m_exp; - llvm::Function* m_codeAt; - llvm::Function* m_codesizeAt; + llvm::Function* m_getExtCode; llvm::Function* m_log; }; From 5362d5056d8384610d9c546ff00b3d606fcaae39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 20:31:56 +0100 Subject: [PATCH 312/466] SDIV & SMOD fixed --- libevmjit/Arith256.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 95d11e3f3..10d3e3449 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -96,6 +96,29 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu return ternaryOp(m_mulmod, _arg1, _arg2, _arg3); } +namespace +{ + using s256 = boost::multiprecision::int256_t; + + inline s256 u2s(u256 _u) + { + static const bigint c_end = (bigint)1 << 256; + static const u256 c_send = (u256)1 << 255; + if (_u < c_send) + return (s256)_u; + else + return (s256)-(c_end - _u); + } + + inline u256 s2u(s256 _u) + { + static const bigint c_end = (bigint)1 << 256; + if (_u >= 0) + return (u256)_u; + else + return (u256)(c_end + _u); + } +} } } @@ -106,7 +129,6 @@ extern "C" { using namespace dev::eth::jit; - using s256 = boost::multiprecision::int256_t; EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result) { @@ -133,14 +155,14 @@ extern "C" { auto arg1 = llvm2eth(*_arg1); auto arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : (arg1.convert_to() / arg2.convert_to()).convert_to()); + *o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) / u2s(arg2))); } EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result) { auto arg1 = llvm2eth(*_arg1); auto arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : (arg1.convert_to() % arg2.convert_to()).convert_to()); + *o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) % u2s(arg2))); } EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result) From b98725861d5c942677f35a32a1f49b855f45e188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 4 Dec 2014 21:05:40 +0100 Subject: [PATCH 313/466] A TODO comment --- libevmjit/Memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 1f31dff72..d87c76035 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -211,7 +211,7 @@ extern "C" { using namespace dev::eth::jit; - EXPORT byte* mem_resize(Runtime* _rt, i256* _size) + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR { auto size = _size->a; // Trunc to 64-bit auto& memory = _rt->getMemory(); From adb5a6869f8a843561641f28c879420b4b166400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 08:43:34 +0100 Subject: [PATCH 314/466] A bit of work in evmcc. Not ready yet. --- evmcc/evmcc.cpp | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 16ab23e9b..3a72bb4f3 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -16,8 +16,8 @@ #include #include #include -#include -#include +#include +#include void parseProgramOptions(int _argc, char** _argv, boost::program_options::variables_map& _varMap) @@ -97,7 +97,7 @@ int main(int argc, char** argv) } std::string src((std::istreambuf_iterator(ifs)), - (std::istreambuf_iterator())); + (std::istreambuf_iterator())); boost::algorithm::trim(src); @@ -165,8 +165,8 @@ int main(int argc, char** argv) if (options.count("verbose")) { std::cerr << "*** Compilation time: " - << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count() - << std::endl; + << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count() + << std::endl; } if (options.count("interpret")) @@ -174,23 +174,24 @@ int main(int argc, char** argv) 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); + // 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 }; + + // BROKEN: env_* functions must be implemented & RuntimeData struct created + auto result = engine.run(std::move(module), gas, ext); return result; } } From c6fcdbc7d650054c4ed597e735633a45144dc3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 08:45:20 +0100 Subject: [PATCH 315/466] Arith performace 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 2b9b53024dfa62b62a322909a43154f65f29d4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 10:11:44 +0100 Subject: [PATCH 316/466] Cleanups --- libevmjit-cpp/Env.cpp | 2 +- libevmjit-cpp/{VM.cpp => JitVM.cpp} | 15 ++++++--------- libevmjit-cpp/{VM.h => JitVM.h} | 13 ++++--------- 3 files changed, 11 insertions(+), 19 deletions(-) rename libevmjit-cpp/{VM.cpp => JitVM.cpp} (91%) rename libevmjit-cpp/{VM.h => JitVM.h} (76%) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 72775822c..fd85a3ccf 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -3,7 +3,7 @@ #include #include -#include "../libevmjit/Utils.h" +#include extern "C" { diff --git a/libevmjit-cpp/VM.cpp b/libevmjit-cpp/JitVM.cpp similarity index 91% rename from libevmjit-cpp/VM.cpp rename to libevmjit-cpp/JitVM.cpp index 7ac51097d..da945139d 100644 --- a/libevmjit-cpp/VM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -1,21 +1,19 @@ -#include "VM.h" - +#include "JitVM.h" #include #include - -#include "../libevmjit/ExecutionEngine.h" -#include "../libevmjit/Compiler.h" +#include +#include namespace dev { namespace eth { -namespace jit -{ -bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) { + using namespace jit; + Compiler::Options defaultOptions; auto module = Compiler(defaultOptions).compile(_ext.code); @@ -63,7 +61,6 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) return {m_output.data(), m_output.size()}; // TODO: This all bytesConstRef stuff sucks } -} } } diff --git a/libevmjit-cpp/VM.h b/libevmjit-cpp/JitVM.h similarity index 76% rename from libevmjit-cpp/VM.h rename to libevmjit-cpp/JitVM.h index 1c6c71181..028dca7a0 100644 --- a/libevmjit-cpp/VM.h +++ b/libevmjit-cpp/JitVM.h @@ -10,12 +10,7 @@ namespace dev namespace eth { -class VMFactory; - -namespace jit -{ - -class VM: public VMFace +class JitVM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; @@ -23,12 +18,12 @@ class VM: public VMFace static std::unique_ptr create(Kind, u256 _gas = 0); private: - friend VMFactory; - explicit VM(u256 _gas = 0): VMFace(_gas) {} + friend class VMFactory; + explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} bytes m_output; }; -} + } } From bd40486c7b4f8665c474853ae1cd4697a3360f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 11:40:06 +0100 Subject: [PATCH 317/466] Moving ext_calldataload helper function to evmjit library (does not depend on Env) --- libevmjit-cpp/Env.cpp | 10 ---------- libevmjit/Ext.cpp | 7 +++++-- libevmjit/Stack.cpp | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index fd85a3ccf..451bce043 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -36,16 +36,6 @@ extern "C" _env->setStore(index, value); // Interface uses native endianness } - // TODO: Move to Memory/Runtime - EXPORT void ext_calldataload(ExtVMFace* _env, i256* _index, ::byte* o_value) - { - auto index = static_cast(llvm2eth(*_index)); - assert(index + 31 > index); // TODO: Handle large index - for (size_t i = index, j = 0; i <= index + 31; ++i, ++j) - o_value[j] = i < _env->data.size() ? _env->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(ExtVMFace* _env, h256* _address, i256* o_value) { auto u = _env->balance(right160(*_address)); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index d14a67ac0..0271694cb 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -46,7 +46,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): m_sload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sload", module); m_sstore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sstore", 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); @@ -64,6 +63,10 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): llvm::Type* getExtCodeArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()}; m_getExtCode = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, getExtCodeArgsTypes, false), Linkage::ExternalLinkage, "env_getExtCode", module); + + // Helper function, not client Env interface + llvm::Type* callDataLoadArgsTypes[] = {Type::RuntimePtr, Type::WordPtr, Type::WordPtr}; + m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, callDataLoadArgsTypes, false), Linkage::ExternalLinkage, "ext_calldataload", module); } llvm::Value* Ext::sload(llvm::Value* _index) @@ -83,7 +86,7 @@ void Ext::sstore(llvm::Value* _index, llvm::Value* _value) llvm::Value* Ext::calldataload(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateCall3(m_calldataload, getRuntimeManager().getEnv(), m_args[0], m_args[1]); + createCall(m_calldataload, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); auto ret = m_builder.CreateLoad(m_args[1]); return Endianness::toNative(m_builder, ret); } diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 9435568a8..f8e9aee70 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -109,5 +109,27 @@ extern "C" *(stack.rbegin() + _index) = *_word; } + EXPORT void ext_calldataload(Runtime* _rt, i256* _index, byte* o_value) + { + // It asumes all indexes are less than 2^64 + + auto index = _index->a; + if (_index->b || _index->c || _index->d) // if bigger that 2^64 + index = std::numeric_limits::max(); // set max to fill with 0 leter + + auto data = _rt->getDataPtr()->callData; + auto size = _rt->getDataPtr()->elems[RuntimeData::CallDataSize].a; + for (auto i = 0; i < 32; ++i) + { + if (index < size) + { + o_value[i] = data[index]; + ++index; // increment only if in range + } + else + o_value[i] = 0; + } + } + } // extern "C" From 46d19261d3d73823630dd36449d3965f627a7f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Fri, 5 Dec 2014 12:40:27 +0100 Subject: [PATCH 318/466] fixed gcc warnings (missing field initializers, unused functions) --- libevmjit-cpp/JitVM.cpp | 10 +++++++--- libevmjit/Compiler.cpp | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index da945139d..2c2143fee 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -17,7 +17,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) Compiler::Options defaultOptions; auto module = Compiler(defaultOptions).compile(_ext.code); - RuntimeData data = {}; + RuntimeData data{{},nullptr,nullptr}; #define set(INDEX, VALUE) data.elems[INDEX] = eth2llvm(VALUE) set(RuntimeData::Gas, m_gas); @@ -63,10 +63,14 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) } } - + namespace { // MSVS linker ignores export symbols in Env.cpp if nothing point at least one of them extern "C" void env_sload(); - void linkerWorkaround() { env_sload(); } + void linkerWorkaround() + { + env_sload(); + (void)linkerWorkaround; // suppress unused function warning from GCC + } } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 32f1579ee..4bbebe9ea 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -810,7 +810,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode // This will commit the current cost block _gasMeter.countLogData(numBytes); - std::array topics{}; + std::array topics{{}}; auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); for (size_t i = 0; i < numTopics; ++i) topics[i] = stack.pop(); From 2fd2446330a910ac2cabf4f8e94712853a9cdbbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 12:49:09 +0100 Subject: [PATCH 319/466] Simplify ExecutionEngine interface. It is possible to pass raw code instead of LLVM module. --- evmcc/evmcc.cpp | 2 +- libevmjit-cpp/JitVM.cpp | 10 +++------- libevmjit-cpp/JitVM.h | 3 --- libevmjit/Common.h | 27 +++++++++++++++++++++++++++ libevmjit/ExecutionEngine.cpp | 20 ++++++++++++++------ libevmjit/ExecutionEngine.h | 15 ++++++++++----- libevmjit/Ext.cpp | 4 ++-- libevmjit/Runtime.h | 5 ----- libevmjit/RuntimeData.h | 8 ++++---- libevmjit/Stack.cpp | 6 +++--- libevmjit/Type.h | 12 ------------ libevmjit/Utils.h | 14 -------------- 12 files changed, 64 insertions(+), 62 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 3a72bb4f3..f76b855db 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -171,7 +171,7 @@ int main(int argc, char** argv) if (options.count("interpret")) { - auto engine = eth::jit::ExecutionEngine(); + eth::jit::ExecutionEngine engine; u256 gas = initialGas; // Create fake ExtVM interface diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index da945139d..02aa7dc64 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -1,9 +1,8 @@ #include "JitVM.h" -#include #include #include -#include +#include namespace dev { @@ -14,9 +13,6 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) { using namespace jit; - Compiler::Options defaultOptions; - auto module = Compiler(defaultOptions).compile(_ext.code); - RuntimeData data = {}; #define set(INDEX, VALUE) data.elems[INDEX] = eth2llvm(VALUE) @@ -40,9 +36,9 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) ExecutionEngine engine; auto env = reinterpret_cast(&_ext); - auto exitCode = engine.run(std::move(module), &data, env); + auto exitCode = engine.run(_ext.code, &data, env); - switch (static_cast(exitCode)) + switch (exitCode) { case ReturnCode::BadJumpDestination: BOOST_THROW_EXCEPTION(BadJumpDestination()); diff --git a/libevmjit-cpp/JitVM.h b/libevmjit-cpp/JitVM.h index 028dca7a0..4b5fedab0 100644 --- a/libevmjit-cpp/JitVM.h +++ b/libevmjit-cpp/JitVM.h @@ -1,9 +1,6 @@ - #pragma once -#include #include -#include namespace dev { diff --git a/libevmjit/Common.h b/libevmjit/Common.h index a645d58b1..d98cc0acb 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -17,6 +17,33 @@ using bigint = boost::multiprecision::cpp_int; struct NoteChannel {}; // FIXME: Use some log library? +enum class ReturnCode +{ + Stop = 0, + Return = 1, + Suicide = 2, + + BadJumpDestination = 101, + OutOfGas = 102, + StackTooSmall = 103, + BadInstruction = 104, + + LLVMConfigError = 201, + LLVMCompileError = 202, + LLVMLinkError = 203, +}; + +/// 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"); + } } } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index ab3f83064..0d5a85144 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -24,6 +24,7 @@ #include "Memory.h" #include "Stack.h" #include "Type.h" +#include "Compiler.h" namespace dev { @@ -32,12 +33,19 @@ namespace eth namespace jit { -int ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env) +ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) +{ + Compiler::Options defaultOptions; + auto module = Compiler(defaultOptions).compile(_code); + return run(std::move(module), _data, _env); +} + +ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env) { auto module = _module.get(); // Keep ownership of the module in _module llvm::sys::PrintStackTraceOnErrorSignal(); - static const auto program = "evmcc"; + static const auto program = "EVM JIT"; llvm::PrettyStackTraceProgram X(1, &program); auto&& context = llvm::getGlobalContext(); @@ -66,10 +74,10 @@ int ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _da auto exec = std::unique_ptr(builder.create()); if (!exec) - return -1; // FIXME: Handle internal errors + return ReturnCode::LLVMConfigError; _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - auto finalizationStartTime = std::chrono::high_resolution_clock::now(); // FIXME: It's not compilation time + auto finalizationStartTime = std::chrono::high_resolution_clock::now(); exec->finalizeObject(); auto finalizationEndTime = std::chrono::high_resolution_clock::now(); clog(JIT) << " + " << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); @@ -78,7 +86,7 @@ int ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _da auto entryFunc = module->getFunction("main"); if (!entryFunc) - return -2; // FIXME: Handle internal errors + return ReturnCode::LLVMLinkError; ReturnCode returnCode; std::jmp_buf buf; @@ -111,7 +119,7 @@ int ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _da clog(JIT) << "\n"; - return static_cast(returnCode); + return returnCode; } } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 8d8715a95..3adceb404 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,9 +1,11 @@ - #pragma once -#include +namespace llvm +{ + class Module; +} -#include "Runtime.h" +#include "RuntimeData.h" namespace dev { @@ -15,9 +17,12 @@ namespace jit class ExecutionEngine { public: - // FIXME: constructor? ExecutionEngine(); + ExecutionEngine() = default; + ExecutionEngine(ExecutionEngine const&) = delete; + void operator=(ExecutionEngine) = delete; - int run(std::unique_ptr module, RuntimeData* _data, Env* _env); + ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); + ReturnCode run(std::unique_ptr module, RuntimeData* _data, Env* _env); bytes returnData; }; diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 0271694cb..3955d21cd 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -65,7 +65,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): m_getExtCode = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, getExtCodeArgsTypes, false), Linkage::ExternalLinkage, "env_getExtCode", module); // Helper function, not client Env interface - llvm::Type* callDataLoadArgsTypes[] = {Type::RuntimePtr, Type::WordPtr, Type::WordPtr}; + llvm::Type* callDataLoadArgsTypes[] = {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr}; m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, callDataLoadArgsTypes, false), Linkage::ExternalLinkage, "ext_calldataload", module); } @@ -86,7 +86,7 @@ void Ext::sstore(llvm::Value* _index, llvm::Value* _value) llvm::Value* Ext::calldataload(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - createCall(m_calldataload, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); + createCall(m_calldataload, getRuntimeManager().getDataPtr(), m_args[0], m_args[1]); auto ret = m_builder.CreateLoad(m_args[1]); return Endianness::toNative(m_builder, ret); } diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 11a995785..d119d5635 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -27,9 +27,6 @@ using StackImpl = std::vector; using MemoryImpl = bytes; using JmpBufRef = decltype(&jmp_buf{}[0]); -/// VM Environment (ExtVM) opaque type -struct Env; - class Runtime { public: @@ -38,8 +35,6 @@ public: Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; - RuntimeData* getDataPtr() { return &m_data; } // FIXME: Remove - StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } Env* getEnvPtr() { return &m_env; } diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index c166e5ab5..fc372fee3 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -1,9 +1,6 @@ - #pragma once -#include - -#include "Utils.h" +#include "Common.h" namespace dev @@ -43,6 +40,9 @@ struct RuntimeData byte const* code; }; +/// VM Environment (ExtVM) opaque type +struct Env; + } } } diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index f8e9aee70..e92f3dd3f 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -109,7 +109,7 @@ extern "C" *(stack.rbegin() + _index) = *_word; } - EXPORT void ext_calldataload(Runtime* _rt, i256* _index, byte* o_value) + EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value) { // It asumes all indexes are less than 2^64 @@ -117,8 +117,8 @@ extern "C" if (_index->b || _index->c || _index->d) // if bigger that 2^64 index = std::numeric_limits::max(); // set max to fill with 0 leter - auto data = _rt->getDataPtr()->callData; - auto size = _rt->getDataPtr()->elems[RuntimeData::CallDataSize].a; + auto data = _rtData->callData; + auto size = _rtData->elems[RuntimeData::CallDataSize].a; for (auto i = 0; i < 32; ++i) { if (index < size) diff --git a/libevmjit/Type.h b/libevmjit/Type.h index fd3c905d1..0a98cb8a1 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -39,18 +39,6 @@ struct Type 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 diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 73e01d2ee..33ff344d6 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -1,8 +1,5 @@ - #pragma once -#include - #include "Common.h" namespace dev @@ -16,17 +13,6 @@ struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; #define clog(CHANNEL) std::cerr -/// 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); From e3ccc03fdeb7f6e83dc8394eae8509871712fd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 12:52:51 +0100 Subject: [PATCH 320/466] Fix MSVC warning --- libevmjit-cpp/JitVM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 0a591f09b..104782405 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -67,6 +67,6 @@ namespace void linkerWorkaround() { env_sload(); - (void)linkerWorkaround; // suppress unused function warning from GCC + (void)&linkerWorkaround; // suppress unused function warning from GCC } } From 5f4c1c7466ca6dcae29b334f696b86b146191ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 13:23:15 +0100 Subject: [PATCH 321/466] Fix evmcc compilation - provide fake runtime data --- evmcc/evmcc.cpp | 45 +++++++++++++++++++++++------------------ libevmjit-cpp/JitVM.cpp | 35 +++++++++++++++----------------- libevmjit/RuntimeData.h | 10 +++++---- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index f76b855db..9828d4876 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -171,28 +171,33 @@ int main(int argc, char** argv) if (options.count("interpret")) { - eth::jit::ExecutionEngine engine; - 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 }; + using namespace eth::jit; + + ExecutionEngine engine; + eth::jit::u256 gas = initialGas; + + // Create random runtime data + RuntimeData data; + data.set(RuntimeData::Gas, gas); + data.set(RuntimeData::Address, (u160)Address(1122334455667788)); + data.set(RuntimeData::Caller, (u160)Address(0xfacefacefaceface)); + data.set(RuntimeData::Origin, (u160)Address(101010101010101010)); + data.set(RuntimeData::CallValue, 0xabcd); + data.set(RuntimeData::CallDataSize, 3); + data.set(RuntimeData::GasPrice, 1003); + data.set(RuntimeData::PrevHash, 1003); + data.set(RuntimeData::CoinBase, (u160)Address(101010101010101015)); + data.set(RuntimeData::TimeStamp, 1005); + data.set(RuntimeData::Number, 1006); + data.set(RuntimeData::Difficulty, 16); + data.set(RuntimeData::GasLimit, 1008); + data.set(RuntimeData::CodeSize, bytecode.size()); + data.callData = (uint8_t*)"abc"; + data.code = bytecode.data(); // BROKEN: env_* functions must be implemented & RuntimeData struct created - auto result = engine.run(std::move(module), gas, ext); - return result; + auto result = engine.run(std::move(module), &data, nullptr); + return static_cast(result); } } diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 104782405..a67678012 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -13,26 +13,23 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) { using namespace jit; - RuntimeData data{{},nullptr,nullptr}; - -#define set(INDEX, VALUE) data.elems[INDEX] = eth2llvm(VALUE) - set(RuntimeData::Gas, m_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 + RuntimeData data; + data.set(RuntimeData::Gas, m_gas); + data.set(RuntimeData::Address, fromAddress(_ext.myAddress)); + data.set(RuntimeData::Caller, fromAddress(_ext.caller)); + data.set(RuntimeData::Origin, fromAddress(_ext.origin)); + data.set(RuntimeData::CallValue, _ext.value); + data.set(RuntimeData::CallDataSize, _ext.data.size()); + data.set(RuntimeData::GasPrice, _ext.gasPrice); + data.set(RuntimeData::PrevHash, _ext.previousBlock.hash); + data.set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress)); + data.set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp); + data.set(RuntimeData::Number, _ext.currentBlock.number); + data.set(RuntimeData::Difficulty, _ext.currentBlock.difficulty); + data.set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); + data.set(RuntimeData::CodeSize, _ext.code.size()); data.callData = _ext.data.data(); data.code = _ext.code.data(); -#undef set ExecutionEngine engine; auto env = reinterpret_cast(&_ext); @@ -62,7 +59,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) namespace { - // MSVS linker ignores export symbols in Env.cpp if nothing point at least one of them + // MSVS linker ignores export symbols in Env.cpp if nothing points at least one of them extern "C" void env_sload(); void linkerWorkaround() { diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index fc372fee3..b17f52620 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -1,6 +1,6 @@ #pragma once -#include "Common.h" +#include "Utils.h" namespace dev @@ -35,9 +35,11 @@ struct RuntimeData ReturnDataSize = CallDataSize }; - i256 elems[_size]; - byte const* callData; - byte const* code; + i256 elems[_size] = {}; + byte const* callData = nullptr; + byte const* code = nullptr; + + void set(Index _index, u256 _value) { elems[_index] = eth2llvm(_value); } }; /// VM Environment (ExtVM) opaque type From b1765749f5f1de3803b8710a2bad7c624b2fc357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 14:00:15 +0100 Subject: [PATCH 322/466] Remove usage of boost::lexical_cast --- libevmjit/BasicBlock.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 1cc0e13fd..d233ea744 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -3,8 +3,6 @@ #include -#include - #include #include #include @@ -112,8 +110,8 @@ llvm::Value* BasicBlock::LocalStack::get(size_t _index) 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); + std::string name = "get_" + std::to_string(_index); + initialStack[initialIdx] = m_bblock.m_builder.CreatePHI(Type::Word, 0, std::move(name)); *itemIter = initialStack[initialIdx]; } From b07f25da4a65a17f5689161775aad135ddd58778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 14:01:10 +0100 Subject: [PATCH 323/466] Detect endianness without boost help --- libevmjit/Endianness.cpp | 19 ++++++++++++++----- libevmjit/Endianness.h | 16 +++------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index e062fb77e..c2cc1ef90 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -12,12 +12,21 @@ namespace eth namespace jit { -llvm::Value* Endianness::bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word) +llvm::Value* Endianness::bswapIfLE(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); + union tester + { + unsigned int x; + unsigned char isLE; + }; + + if (tester{1}.isLE) + { + // OPT: Cache func declaration? + auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); + return _builder.CreateCall(bswapFunc, _word); + } + return _word; } } diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h index 951904358..8a1f41085 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -1,8 +1,6 @@ #pragma once -#include - #include namespace dev @@ -14,19 +12,11 @@ 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 + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } private: - static llvm::Value* bswap(llvm::IRBuilder<>& _builder, llvm::Value* _word); + static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); }; } From 63d699792c7609278f6d84d5f865b84587dfcfae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Fri, 5 Dec 2014 15:11:19 +0100 Subject: [PATCH 324/466] added missing --- libevmjit/ExecutionEngine.cpp | 1 - libevmjit/Runtime.h | 1 + libevmjit/Stack.cpp | 2 -- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 0d5a85144..0960f872b 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,6 +1,5 @@ #include "ExecutionEngine.h" -#include #include #pragma GCC diagnostic push diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index d119d5635..d86acbfc4 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,6 +1,7 @@ #pragma once +#include #include #include "Instruction.h" diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index e92f3dd3f..52782999a 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -3,8 +3,6 @@ #include "Runtime.h" #include "Type.h" -#include - #include #include From c9f5694a285412f693b160cf83e6258b0c41c504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zaw=C5=82ocki?= Date: Fri, 5 Dec 2014 15:12:20 +0100 Subject: [PATCH 325/466] CMakeLists.txt cleanup (in progress) --- CMakeLists.txt | 8 +++++++- evmcc/CMakeLists.txt | 15 ++++++--------- libevmjit-cpp/CMakeLists.txt | 19 +++++++++++-------- libevmjit/CMakeLists.txt | 21 ++++++++++----------- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2acefc01..4243f6676 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,5 +5,11 @@ project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) +# LLVM +find_package(LLVM REQUIRED CONFIG) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + add_subdirectory(libevmjit) -add_subdirectory(libevmjit-cpp) \ No newline at end of file +add_subdirectory(libevmjit-cpp) +add_subdirectory(evmcc) \ No newline at end of file diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index a087539dc..e11baabbb 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -1,12 +1,15 @@ cmake_policy(SET CMP0015 NEW) -aux_source_directory(. SRC_LIST) +project(evmjit CXX) -include_directories(..) +file(GLOB SOURCES "*.cpp") +file(GLOB HEADERS "*.h") +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "tools") set(EXECUTABLE evmcc) +add_executable(${EXECUTABLE} ${HEADERS} ${SOURCES}) -add_executable(${EXECUTABLE} ${SRC_LIST}) +include_directories(../..) target_link_libraries(${EXECUTABLE} boost_program_options) target_link_libraries(${EXECUTABLE} devcore) @@ -31,18 +34,12 @@ else () 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 diff --git a/libevmjit-cpp/CMakeLists.txt b/libevmjit-cpp/CMakeLists.txt index 30035243b..1750b04ce 100644 --- a/libevmjit-cpp/CMakeLists.txt +++ b/libevmjit-cpp/CMakeLists.txt @@ -1,14 +1,17 @@ - -project(evmjit-cpp LANGUAGES CXX) +project(evmjit-cpp CXX) set(SOURCES - Ext.cpp Ext.h - Runtime.cpp Runtime.h - VM.cpp VM.h + Env.cpp + JitVM.cpp JitVM.h ) -source_group("" FILES ${SOURCES}) - add_library(${PROJECT_NAME} ${SOURCES}) -set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "libs") +include_directories(../..) + +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) + +source_group("" FILES ${SOURCES}) +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "libs") \ No newline at end of file diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 155a627c1..82ae0d3b1 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -1,13 +1,9 @@ - -project(evmjit LANGUAGES CXX) +project(evmjit CXX) file(GLOB SOURCES "*.cpp") file(GLOB HEADERS "*.h") -source_group("" FILES ${SOURCES}) -source_group("" FILES ${HEADERS}) add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS}) -set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "libs") #include_directories(..) @@ -31,17 +27,15 @@ set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "libs") # target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) # endif () - -# LLVM +# 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}) +add_definitions(${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen) target_link_libraries(${PROJECT_NAME} ${LLVM_LIBS}) +# end of LLVM specific commands + # Boost find_package(Boost REQUIRED) @@ -50,3 +44,8 @@ include_directories(${Boost_INCLUDE_DIRS}) #install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) #install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + + +source_group("" FILES ${HEADERS}) +source_group("" FILES ${SOURCES}) +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "libs") From b1b94de243e8dd3a36b8be42794ed70a09271cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 15:38:19 +0100 Subject: [PATCH 326/466] Opcodes update --- libevmjit/Instruction.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index efc43552c..86c529e18 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -10,7 +10,7 @@ namespace jit { /// Virtual machine bytecode instruction. -enum class Instruction : uint8_t +enum class Instruction: uint8_t { STOP = 0x00, ///< halts execution ADD, ///< addition operation @@ -148,8 +148,8 @@ enum class Instruction : uint8_t CREATE = 0xf0, ///< create a new account with associated code CALL, ///< message-call into an account + CALLCODE, ///< message-call with another account's code only RETURN, ///< halt execution returning output data - CALLCODE, SUICIDE = 0xff ///< halt execution and register account for later deletion }; From b3a17341e4ee3f2af12270d92cf404293deefc73 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 327/466] Disable JIT logs --- libevmjit/Utils.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 33ff344d6..dd07e72cd 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -11,7 +11,8 @@ namespace jit struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; -#define clog(CHANNEL) std::cerr +//#define clog(CHANNEL) std::cerr +#define clog(CHANNEL) std::ostream({}) u256 llvm2eth(i256); i256 eth2llvm(u256); From 2a7111ce4187eb4eb8edac7eed30652638db2585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Dec 2014 14:20:00 +0100 Subject: [PATCH 328/466] ExecBundle - all information needed to execute a JIT-compiled contracts --- libevmjit/Cache.cpp | 12 +++++++++++ libevmjit/Cache.h | 25 +++++++++++++++++++++++ libevmjit/ExecutionEngine.cpp | 38 +++++++++++++++++++++-------------- libevmjit/ExecutionEngine.h | 4 ++++ 4 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 libevmjit/Cache.cpp create mode 100644 libevmjit/Cache.h diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp new file mode 100644 index 000000000..acc560309 --- /dev/null +++ b/libevmjit/Cache.cpp @@ -0,0 +1,12 @@ +#include "Cache.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +} +} +} diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h new file mode 100644 index 000000000..e75bce27f --- /dev/null +++ b/libevmjit/Cache.h @@ -0,0 +1,25 @@ +#pragma once + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +/// A bundle of objects and information needed for a contract execution +struct ExecBundle +{ + std::unique_ptr engine; + llvm::Function* entryFunc = nullptr; +}; + +class Cache +{ +public: + +}; + +} +} +} diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 0960f872b..9648bb5cb 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -24,6 +24,7 @@ #include "Stack.h" #include "Type.h" #include "Compiler.h" +#include "Cache.h" namespace dev { @@ -34,8 +35,7 @@ namespace jit ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) { - Compiler::Options defaultOptions; - auto module = Compiler(defaultOptions).compile(_code); + auto module = Compiler({}).compile(_code); return run(std::move(module), _data, _env); } @@ -71,41 +71,51 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa 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) + ExecBundle exec; + exec.engine.reset(builder.create()); + if (!exec.engine) return ReturnCode::LLVMConfigError; _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module auto finalizationStartTime = std::chrono::high_resolution_clock::now(); - exec->finalizeObject(); + exec.engine->finalizeObject(); auto finalizationEndTime = std::chrono::high_resolution_clock::now(); clog(JIT) << " + " << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); auto executionStartTime = std::chrono::high_resolution_clock::now(); - auto entryFunc = module->getFunction("main"); - if (!entryFunc) + exec.entryFunc = module->getFunction("main"); + if (!exec.entryFunc) return ReturnCode::LLVMLinkError; + auto returnCode = run(exec, _data, _env); + + auto executionEndTime = std::chrono::high_resolution_clock::now(); + clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms "; + //clog(JIT) << "Max stack size: " << Stack::maxStackSize; + + clog(JIT) << "\n"; + + return returnCode; +} + +ReturnCode ExecutionEngine::run(ExecBundle const& _exec, RuntimeData* _data, Env* _env) +{ ReturnCode returnCode; std::jmp_buf buf; Runtime runtime(_data, _env, buf); auto r = setjmp(buf); if (r == 0) { - auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(&runtime)}); + auto result = _exec.engine->runFunction(_exec.entryFunc, {{}, llvm::GenericValue(&runtime)}); returnCode = static_cast(result.IntVal.getZExtValue()); } else returnCode = static_cast(r); - - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms "; - //clog(JIT) << "Max stack size: " << Stack::maxStackSize; if (returnCode == ReturnCode::Return) { - returnData = runtime.getReturnData(); // TODO: It might be better to place is in Runtime interface + returnData = runtime.getReturnData(); auto&& log = clog(JIT); log << "RETURN [ "; @@ -116,8 +126,6 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa else clog(JIT) << "RETURN " << (int)returnCode; - clog(JIT) << "\n"; - return returnCode; } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 3adceb404..8eb4ff347 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -13,6 +13,7 @@ namespace eth { namespace jit { +class ExecBundle; class ExecutionEngine { @@ -25,6 +26,9 @@ public: ReturnCode run(std::unique_ptr module, RuntimeData* _data, Env* _env); bytes returnData; + +private: + ReturnCode run(ExecBundle const& _exec, RuntimeData* _data, Env* _env); }; } From 7c9cf6e5e761951a2f001892a9835dd303859513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Dec 2014 15:27:50 +0100 Subject: [PATCH 329/466] Trying to cache compiled contracts with pointer to code as a key (it's not a good idea) --- libevmjit/Cache.cpp | 37 +++++++++++++++++++++++++++++++++++ libevmjit/Cache.h | 7 +++++++ libevmjit/ExecutionEngine.cpp | 9 ++++++++- libevmjit/ExecutionEngine.h | 2 +- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index acc560309..1dd6f1d9f 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -1,4 +1,7 @@ #include "Cache.h" +#include +#include +#include namespace dev { @@ -6,6 +9,40 @@ namespace eth { namespace jit { +namespace +{ + using CacheMap = std::unordered_map; + + CacheMap& getCacheMap() + { + static CacheMap map; + return map; + } +} + +#define LOG(...) std::cerr << "CACHE " + +ExecBundle& Cache::registerExec(Cache::Key _key, ExecBundle&& _exec) +{ + auto& map = getCacheMap(); + auto r = map.insert(std::make_pair(_key, std::move(_exec))); + assert(r.second && "Updating cached objects not supported"); + LOG() << "add " << _key << "\n"; + return r.first->second; // return exec, now owned by cache +} + +ExecBundle* Cache::findExec(Cache::Key _key) +{ + auto& map = getCacheMap(); + auto it = map.find(_key); + if (it != map.end()) + { + LOG() << "hit " << _key << "\n"; + return &it->second; + } + LOG() << "miss " << _key << "\n"; + return nullptr; +} } } diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index e75bce27f..c9a74ea91 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,5 +1,9 @@ #pragma once +#include +#include + + namespace dev { namespace eth @@ -17,7 +21,10 @@ struct ExecBundle class Cache { public: + using Key = void const*; + static ExecBundle& registerExec(Key _key, ExecBundle&& _exec); + static ExecBundle* findExec(Key _key); }; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 9648bb5cb..719be9ac6 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -41,6 +41,12 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env) { + auto key = _data->code; // TODO: Change cache key + if (auto cachedExec = Cache::findExec(key)) + { + return run(*cachedExec, _data, _env); + } + auto module = _module.get(); // Keep ownership of the module in _module llvm::sys::PrintStackTraceOnErrorSignal(); @@ -88,7 +94,8 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa if (!exec.entryFunc) return ReturnCode::LLVMLinkError; - auto returnCode = run(exec, _data, _env); + auto& cachedExec = Cache::registerExec(_data->code, std::move(exec)); + auto returnCode = run(cachedExec, _data, _env); auto executionEndTime = std::chrono::high_resolution_clock::now(); clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms "; diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 8eb4ff347..785e4efda 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -13,7 +13,7 @@ namespace eth { namespace jit { -class ExecBundle; +struct ExecBundle; class ExecutionEngine { From da02a1869d7537fe15862324cfda2645d7162603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Dec 2014 16:28:09 +0100 Subject: [PATCH 330/466] Cache key is contract code. Does not work --- evmcc/evmcc.cpp | 2 +- libevmjit/Cache.cpp | 6 +++--- libevmjit/Cache.h | 10 ++++++++-- libevmjit/ExecutionEngine.cpp | 10 +++++----- libevmjit/ExecutionEngine.h | 4 ++-- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 9828d4876..5ee11abb1 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -196,7 +196,7 @@ int main(int argc, char** argv) data.code = bytecode.data(); // BROKEN: env_* functions must be implemented & RuntimeData struct created - auto result = engine.run(std::move(module), &data, nullptr); + auto result = engine.run(std::move(module), &data, nullptr, bytecode); return static_cast(result); } } diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 1dd6f1d9f..663c0d820 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -27,7 +27,7 @@ ExecBundle& Cache::registerExec(Cache::Key _key, ExecBundle&& _exec) auto& map = getCacheMap(); auto r = map.insert(std::make_pair(_key, std::move(_exec))); assert(r.second && "Updating cached objects not supported"); - LOG() << "add " << _key << "\n"; + LOG() << "add\n"; return r.first->second; // return exec, now owned by cache } @@ -37,10 +37,10 @@ ExecBundle* Cache::findExec(Cache::Key _key) auto it = map.find(_key); if (it != map.end()) { - LOG() << "hit " << _key << "\n"; + LOG() << "hit\n"; return &it->second; } - LOG() << "miss " << _key << "\n"; + LOG() << "miss\n"; return nullptr; } diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index c9a74ea91..62875edac 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -12,16 +12,22 @@ namespace jit { /// A bundle of objects and information needed for a contract execution -struct ExecBundle +class ExecBundle { +public: std::unique_ptr engine; llvm::Function* entryFunc = nullptr; + + ExecBundle() = default; + ExecBundle(ExecBundle&&) = default; + ExecBundle(ExecBundle const&) = delete; + void operator=(ExecBundle) = delete; }; class Cache { public: - using Key = void const*; + using Key = std::string; static ExecBundle& registerExec(Key _key, ExecBundle&& _exec); static ExecBundle* findExec(Key _key); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 719be9ac6..936899828 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -36,13 +36,13 @@ namespace jit ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) { auto module = Compiler({}).compile(_code); - return run(std::move(module), _data, _env); + return run(std::move(module), _data, _env, _code); } -ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env) +ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) { - auto key = _data->code; // TODO: Change cache key - if (auto cachedExec = Cache::findExec(key)) + std::string key{reinterpret_cast(_code.data()), _code.size()}; + if (auto cachedExec = Cache::findExec(std::move(key))) { return run(*cachedExec, _data, _env); } @@ -94,7 +94,7 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa if (!exec.entryFunc) return ReturnCode::LLVMLinkError; - auto& cachedExec = Cache::registerExec(_data->code, std::move(exec)); + auto& cachedExec = Cache::registerExec(key, std::move(exec)); auto returnCode = run(cachedExec, _data, _env); auto executionEndTime = std::chrono::high_resolution_clock::now(); diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 785e4efda..499aa894a 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -13,7 +13,7 @@ namespace eth { namespace jit { -struct ExecBundle; +class ExecBundle; class ExecutionEngine { @@ -23,7 +23,7 @@ public: void operator=(ExecutionEngine) = delete; ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); - ReturnCode run(std::unique_ptr module, RuntimeData* _data, Env* _env); + ReturnCode run(std::unique_ptr module, RuntimeData* _data, Env* _env, bytes const& _code); bytes returnData; From 70348d95866efb19e798cf1f13958f0be9a7c836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Dec 2014 18:51:11 +0100 Subject: [PATCH 331/466] Fix cache key and do not compile to LLVM module when it is not needed --- libevmjit/Cache.h | 5 ++++- libevmjit/ExecutionEngine.cpp | 13 +++++++------ libevmjit/Utils.h | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 62875edac..9fd695bfe 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -19,7 +19,10 @@ public: llvm::Function* entryFunc = nullptr; ExecBundle() = default; - ExecBundle(ExecBundle&&) = default; + ExecBundle(ExecBundle&& _other): + engine(std::move(_other.engine)), + entryFunc(_other.entryFunc) {} + ExecBundle(ExecBundle const&) = delete; void operator=(ExecBundle) = delete; }; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 936899828..3fbc1e413 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -35,18 +35,18 @@ namespace jit ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) { + std::string key{reinterpret_cast(_code.data()), _code.size()}; + if (auto cachedExec = Cache::findExec(key)) + { + return run(*cachedExec, _data, _env); + } + auto module = Compiler({}).compile(_code); return run(std::move(module), _data, _env, _code); } ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) { - std::string key{reinterpret_cast(_code.data()), _code.size()}; - if (auto cachedExec = Cache::findExec(std::move(key))) - { - return run(*cachedExec, _data, _env); - } - auto module = _module.get(); // Keep ownership of the module in _module llvm::sys::PrintStackTraceOnErrorSignal(); @@ -94,6 +94,7 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa if (!exec.entryFunc) return ReturnCode::LLVMLinkError; + std::string key{reinterpret_cast(_code.data()), _code.size()}; auto& cachedExec = Cache::registerExec(key, std::move(exec)); auto returnCode = run(cachedExec, _data, _env); diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index dd07e72cd..f672365c6 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -12,7 +12,7 @@ namespace jit struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; //#define clog(CHANNEL) std::cerr -#define clog(CHANNEL) std::ostream({}) +#define clog(CHANNEL) std::ostream(nullptr) u256 llvm2eth(i256); i256 eth2llvm(u256); From 6e318f881609da7507250929abf2f014de939066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Dec 2014 18:51:53 +0100 Subject: [PATCH 332/466] Check current call depth --- libevmjit-cpp/Env.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 451bce043..1a2442791 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -49,6 +49,8 @@ extern "C" EXPORT void env_create(ExtVMFace* _env, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { + assert(_env->depth < 1024); // TODO: Handle call depth + auto endowment = llvm2eth(*_endowment); if (_env->balance(_env->myAddress) >= endowment) @@ -65,6 +67,8 @@ extern "C" EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { + assert(_env->depth < 32); // TODO: Handle call depth + auto value = llvm2eth(*_value); if (_env->balance(_env->myAddress) >= value) { From 45fb3f5625e5ce01c69cd7ce47f94c1a6da39ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 15 Dec 2014 12:16:44 +0100 Subject: [PATCH 333/466] Move some data from stack to JitVM object to save stack space. --- libevmjit-cpp/JitVM.cpp | 42 +++++++++++++++++++---------------------- libevmjit-cpp/JitVM.h | 4 +++- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index a67678012..46dabe275 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -13,28 +13,25 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) { using namespace jit; - RuntimeData data; - data.set(RuntimeData::Gas, m_gas); - data.set(RuntimeData::Address, fromAddress(_ext.myAddress)); - data.set(RuntimeData::Caller, fromAddress(_ext.caller)); - data.set(RuntimeData::Origin, fromAddress(_ext.origin)); - data.set(RuntimeData::CallValue, _ext.value); - data.set(RuntimeData::CallDataSize, _ext.data.size()); - data.set(RuntimeData::GasPrice, _ext.gasPrice); - data.set(RuntimeData::PrevHash, _ext.previousBlock.hash); - data.set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress)); - data.set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp); - data.set(RuntimeData::Number, _ext.currentBlock.number); - data.set(RuntimeData::Difficulty, _ext.currentBlock.difficulty); - data.set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); - data.set(RuntimeData::CodeSize, _ext.code.size()); - data.callData = _ext.data.data(); - data.code = _ext.code.data(); + m_data.set(RuntimeData::Gas, m_gas); + m_data.set(RuntimeData::Address, fromAddress(_ext.myAddress)); + m_data.set(RuntimeData::Caller, fromAddress(_ext.caller)); + m_data.set(RuntimeData::Origin, fromAddress(_ext.origin)); + m_data.set(RuntimeData::CallValue, _ext.value); + m_data.set(RuntimeData::CallDataSize, _ext.data.size()); + m_data.set(RuntimeData::GasPrice, _ext.gasPrice); + m_data.set(RuntimeData::PrevHash, _ext.previousBlock.hash); + m_data.set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp); + m_data.set(RuntimeData::Number, _ext.currentBlock.number); + m_data.set(RuntimeData::Difficulty, _ext.currentBlock.difficulty); + m_data.set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); + m_data.set(RuntimeData::CodeSize, _ext.code.size()); + m_data.callData = _ext.data.data(); + m_data.code = _ext.code.data(); - ExecutionEngine engine; auto env = reinterpret_cast(&_ext); - auto exitCode = engine.run(_ext.code, &data, env); - + auto exitCode = m_engine.run(_ext.code, &m_data, env); switch (exitCode) { case ReturnCode::BadJumpDestination: @@ -49,9 +46,8 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) break; } - m_gas = llvm2eth(data.elems[RuntimeData::Gas]); - m_output = std::move(engine.returnData); - return {m_output.data(), m_output.size()}; // TODO: This all bytesConstRef stuff sucks + m_gas = llvm2eth(m_data.elems[RuntimeData::Gas]); + return {m_engine.returnData.data(), m_engine.returnData.size()}; // TODO: This all bytesConstRef is problematic, review. } } diff --git a/libevmjit-cpp/JitVM.h b/libevmjit-cpp/JitVM.h index 4b5fedab0..90855127e 100644 --- a/libevmjit-cpp/JitVM.h +++ b/libevmjit-cpp/JitVM.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace dev { @@ -18,7 +19,8 @@ private: friend class VMFactory; explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} - bytes m_output; + jit::RuntimeData m_data; + jit::ExecutionEngine m_engine; }; From dc4bc0e9bf43475d2fb993e5af7d82d6d4ba9a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 15 Dec 2014 12:19:49 +0100 Subject: [PATCH 334/466] Jit can handle call stack up to 1024 --- libevmjit-cpp/Env.cpp | 2 +- libevmjit/Cache.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 1a2442791..2ea26fb4a 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -67,7 +67,7 @@ extern "C" EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { - assert(_env->depth < 32); // TODO: Handle call depth + assert(_env->depth < 1024); // TODO: Handle call depth auto value = llvm2eth(*_value); if (_env->balance(_env->myAddress) >= value) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 663c0d820..115322fef 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -20,7 +20,8 @@ namespace } } -#define LOG(...) std::cerr << "CACHE " +//#define LOG(...) std::cerr << "CACHE " +#define LOG(...) std::ostream(nullptr) ExecBundle& Cache::registerExec(Cache::Key _key, ExecBundle&& _exec) { From dbf8174fc6f8be9e6d1e62a627388fa23eb2308f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 15 Dec 2014 15:12:31 +0100 Subject: [PATCH 335/466] Update usage of ExtVMFace --- libevmjit-cpp/Env.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 2ea26fb4a..11761faf9 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -58,7 +58,7 @@ extern "C" _env->subBalance(endowment); u256 gas; // TODO: Handle gas OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(_env->create(endowment, &gas, {_initBeg, _initSize}, onOp), h256::AlignRight); + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); *o_address = address; } else @@ -79,7 +79,7 @@ extern "C" OnOpFunc onOp {}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); auto gas = llvm2eth(*io_gas); - auto ret = _env->call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); *io_gas = eth2llvm(gas); return ret; } From 70279f86796ae883a1dfb9b84ebd293cc6e0aff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 16 Dec 2014 14:46:36 +0100 Subject: [PATCH 336/466] Changes in setjmps --- libevmjit-cpp/Env.cpp | 3 +++ libevmjit/ExecutionEngine.cpp | 6 +++--- libevmjit/Runtime.cpp | 27 +++++++++++++++++++++++---- libevmjit/Runtime.h | 16 ++++++++++------ libevmjit/Utils.cpp | 8 ++++++++ libevmjit/Utils.h | 2 ++ 6 files changed, 49 insertions(+), 13 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 11761faf9..72dc062b4 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -67,6 +67,9 @@ extern "C" EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { + if (_env->depth == 1024) + jit::terminate(jit::ReturnCode::OutOfGas); + assert(_env->depth < 1024); // TODO: Handle call depth auto value = llvm2eth(*_value); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 3fbc1e413..6e625388d 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -110,9 +110,9 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa ReturnCode ExecutionEngine::run(ExecBundle const& _exec, RuntimeData* _data, Env* _env) { ReturnCode returnCode; - std::jmp_buf buf; - Runtime runtime(_data, _env, buf); - auto r = setjmp(buf); + Runtime runtime(_data, _env); + + auto r = setjmp(runtime.getJmpBuf()); if (r == 0) { auto result = _exec.engine->runFunction(_exec.entryFunc, {{}, llvm::GenericValue(&runtime)}); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index e725334db..c0ba5ebee 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -5,7 +5,7 @@ #include #include -//#include +#include namespace dev { @@ -13,12 +13,31 @@ namespace eth { namespace jit { +namespace +{ + jmp_buf_ref g_currJmpBuf; +} + +jmp_buf_ref Runtime::getCurrJmpBuf() +{ + return g_currJmpBuf; +} -Runtime::Runtime(RuntimeData* _data, Env* _env, JmpBufRef _jmpBuf): +Runtime::Runtime(RuntimeData* _data, Env* _env): m_data(*_data), m_env(*_env), - m_jmpBuf(_jmpBuf) -{} + m_currJmpBuf(m_jmpBuf), + m_prevJmpBuf(g_currJmpBuf) +{ + g_currJmpBuf = m_jmpBuf; + std::cerr << "JB push " << g_currJmpBuf << "\n"; +} + +Runtime::~Runtime() +{ + std::cerr << "JB pop " << g_currJmpBuf << "\n"; + g_currJmpBuf = m_prevJmpBuf; +} u256 Runtime::getGas() const { diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index d86acbfc4..adb736ecc 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -26,12 +26,13 @@ namespace jit using StackImpl = std::vector; using MemoryImpl = bytes; -using JmpBufRef = decltype(&jmp_buf{}[0]); +using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); class Runtime { public: - Runtime(RuntimeData* _data, Env* _env, JmpBufRef _jmpBuf); + Runtime(RuntimeData* _data, Env* _env); + ~Runtime(); Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; @@ -42,12 +43,15 @@ public: u256 getGas() const; bytes getReturnData() const; - JmpBufRef getJmpBuf() { return m_jmpBuf; } + jmp_buf_ref getJmpBuf() { return m_jmpBuf; } + static jmp_buf_ref getCurrJmpBuf(); private: - RuntimeData& m_data; - Env& m_env; - JmpBufRef m_jmpBuf; + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. + jmp_buf_ref m_prevJmpBuf; + std::jmp_buf m_jmpBuf; StackImpl m_stack; MemoryImpl m_memory; }; diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 0dad56548..6c2bd81ba 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -1,6 +1,8 @@ +#include #include "Utils.h" #include "Instruction.h" +#include "Runtime.h" namespace dev { @@ -53,6 +55,12 @@ u256 readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) return value; } +void terminate(ReturnCode _returnCode) +{ + auto jmpBuf = Runtime::getCurrJmpBuf(); + std::longjmp(jmpBuf, static_cast(_returnCode)); +} + } } } diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index f672365c6..db0647fdf 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -17,6 +17,8 @@ struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; u256 llvm2eth(i256); i256 eth2llvm(u256); +void terminate(ReturnCode _returnCode); + } } } From 4a9d08d1b03149b5559efc7f8869f157da179787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 16 Dec 2014 16:41:52 +0100 Subject: [PATCH 337/466] Change the way entry function is called. --- libevmjit/ExecutionEngine.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 6e625388d..b56d6bf15 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -112,11 +112,19 @@ ReturnCode ExecutionEngine::run(ExecBundle const& _exec, RuntimeData* _data, Env ReturnCode returnCode; Runtime runtime(_data, _env); + + std::vector args{{}, llvm::GenericValue(&runtime)}; + llvm::GenericValue result; + + typedef ReturnCode(*EntryFuncPtr)(int, Runtime*); + + auto entryFuncVoidPtr = _exec.engine->getPointerToFunction(_exec.entryFunc); + auto entryFuncPtr = static_cast(entryFuncVoidPtr); + auto r = setjmp(runtime.getJmpBuf()); if (r == 0) { - auto result = _exec.engine->runFunction(_exec.entryFunc, {{}, llvm::GenericValue(&runtime)}); - returnCode = static_cast(result.IntVal.getZExtValue()); + returnCode = entryFuncPtr(0, &runtime); } else returnCode = static_cast(r); From 2e1c90f828e83b249476c2be0bc1221af4fb719c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 16 Dec 2014 17:25:14 +0100 Subject: [PATCH 338/466] Change the way entry function is called. --- libevmjit/ExecutionEngine.cpp | 44 ++++++++++++++--------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index b56d6bf15..742aea90a 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -107,41 +107,31 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa return returnCode; } -ReturnCode ExecutionEngine::run(ExecBundle const& _exec, RuntimeData* _data, Env* _env) +namespace +{ +ReturnCode runEntryFunc(ExecBundle const& _exec, Runtime* _runtime) { - ReturnCode returnCode; - Runtime runtime(_data, _env); - - - std::vector args{{}, llvm::GenericValue(&runtime)}; - llvm::GenericValue result; - typedef ReturnCode(*EntryFuncPtr)(int, Runtime*); - auto entryFuncVoidPtr = _exec.engine->getPointerToFunction(_exec.entryFunc); auto entryFuncPtr = static_cast(entryFuncVoidPtr); - auto r = setjmp(runtime.getJmpBuf()); - if (r == 0) - { - returnCode = entryFuncPtr(0, &runtime); - } + ReturnCode returnCode{}; + auto sj = setjmp(_runtime->getJmpBuf()); + if (sj == 0) + returnCode = entryFuncPtr(0, _runtime); // FIXME: Remove int argument else - returnCode = static_cast(r); + returnCode = static_cast(sj); - if (returnCode == ReturnCode::Return) - { - returnData = runtime.getReturnData(); - - 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 - clog(JIT) << "RETURN " << (int)returnCode; + return returnCode; +} +} +ReturnCode ExecutionEngine::run(ExecBundle const& _exec, RuntimeData* _data, Env* _env) +{ + Runtime runtime(_data, _env); + auto returnCode = runEntryFunc(_exec, &runtime); + if (returnCode == ReturnCode::Return) + this->returnData = runtime.getReturnData(); return returnCode; } From 47d92e933ae22cf3a827cc5181cfa154d55b81c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 16 Dec 2014 17:35:28 +0100 Subject: [PATCH 339/466] Remove dummy int argument in entry function --- libevmjit/Compiler.cpp | 5 ++--- libevmjit/ExecutionEngine.cpp | 4 ++-- libevmjit/RuntimeManager.cpp | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 4bbebe9ea..33822f46e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -157,10 +157,9 @@ 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); + auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, Type::RuntimePtr, false); m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get()); - m_mainFunc->arg_begin()->getNextNode()->setName("rt"); + m_mainFunc->getArgumentList().front().setName("rt"); // 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 742aea90a..fb3b878e2 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -111,14 +111,14 @@ namespace { ReturnCode runEntryFunc(ExecBundle const& _exec, Runtime* _runtime) { - typedef ReturnCode(*EntryFuncPtr)(int, Runtime*); + typedef ReturnCode(*EntryFuncPtr)(Runtime*); auto entryFuncVoidPtr = _exec.engine->getPointerToFunction(_exec.entryFunc); auto entryFuncPtr = static_cast(entryFuncVoidPtr); ReturnCode returnCode{}; auto sj = setjmp(_runtime->getJmpBuf()); if (sj == 0) - returnCode = entryFuncPtr(0, _runtime); // FIXME: Remove int argument + returnCode = entryFuncPtr(_runtime); else returnCode = static_cast(sj); diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 56efa0c64..9bb9b3698 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -80,7 +80,7 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui // Export data auto mainFunc = getMainFunction(); - llvm::Value* rtPtr = &mainFunc->getArgumentList().back(); + llvm::Value* rtPtr = &mainFunc->getArgumentList().front(); m_builder.CreateStore(rtPtr, m_rtPtr); auto dataPtr = m_builder.CreateStructGEP(rtPtr, 0, "dataPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); @@ -95,7 +95,7 @@ llvm::Value* RuntimeManager::getRuntimePtr() { // FIXME: Data ptr //if (auto mainFunc = getMainFunction()) - // return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function + // return mainFunc->arg_begin(); // Runtime is the parameter of main function return m_builder.CreateLoad(m_rtPtr, "rt"); } @@ -103,7 +103,7 @@ llvm::Value* RuntimeManager::getDataPtr() { // FIXME: Data ptr //if (auto mainFunc = getMainFunction()) - // return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function + // return mainFunc->arg_begin(); // Runtime is the parameter of main function return m_builder.CreateLoad(m_dataPtr, "data"); } From 91cd37e98dd558d688c5aa57f3fdcf5b3b8dd859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 16 Dec 2014 18:39:44 +0100 Subject: [PATCH 340/466] Remove logs --- libevmjit/Runtime.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index c0ba5ebee..9cc09032e 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -5,8 +5,6 @@ #include #include -#include - namespace dev { namespace eth @@ -30,12 +28,10 @@ Runtime::Runtime(RuntimeData* _data, Env* _env): m_prevJmpBuf(g_currJmpBuf) { g_currJmpBuf = m_jmpBuf; - std::cerr << "JB push " << g_currJmpBuf << "\n"; } Runtime::~Runtime() { - std::cerr << "JB pop " << g_currJmpBuf << "\n"; g_currJmpBuf = m_prevJmpBuf; } From c2699b32eea1b9a826c056b66837d487f42ef934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 16 Dec 2014 18:40:19 +0100 Subject: [PATCH 341/466] Comment about MCJIT and caching pointers to entry functions --- libevmjit/ExecutionEngine.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index fb3b878e2..cb4e16784 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -111,6 +111,14 @@ namespace { ReturnCode runEntryFunc(ExecBundle const& _exec, Runtime* _runtime) { + // That function uses long jumps to handle "execeptions". + // Do not create any non-POD objects here + + // TODO: + // Getting pointer to function seems to be cachable, + // but it looks like getPointerToFunction() method does something special + // to allow function to be executed. + // That might be related to memory manager. Can we share one? typedef ReturnCode(*EntryFuncPtr)(Runtime*); auto entryFuncVoidPtr = _exec.engine->getPointerToFunction(_exec.entryFunc); auto entryFuncPtr = static_cast(entryFuncVoidPtr); From 077cf7be5daa9fa3a1228cc995df9b5955c4eb4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 16 Dec 2014 19:13:39 +0100 Subject: [PATCH 342/466] Count additional cost for EXP exponent --- libevmjit/Compiler.cpp | 7 ++++--- libevmjit/GasMeter.cpp | 15 +++++++++++++++ libevmjit/GasMeter.h | 3 +++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 33822f46e..6c6c00ff7 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -332,9 +332,10 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::EXP: { - auto left = stack.pop(); - auto right = stack.pop(); - auto ret = _arith.exp(left, right); + auto base = stack.pop(); + auto exponent = stack.pop(); + _gasMeter.countExp(exponent); + auto ret = _arith.exp(base, exponent); stack.push(ret); break; } diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 96bffc250..e2f45621b 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -144,6 +144,21 @@ void GasMeter::count(Instruction _inst) commitCostBlock(); } +void GasMeter::countExp(llvm::Value* _exponent) +{ + // Additional cost is 1 per significant byte of exponent + // lz - leading zeros + // cost = ((256 - lz) + 7) / 8 + + // OPT: All calculations can be done on 32/64 bits + + auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); + auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto sigBits = m_builder.CreateSub(Constant::get(256), lz); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + createCall(m_gasCheckFunc, sigBytes); +} + void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) { assert(!m_checkCall); // Everything should've been commited before diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 85ef59a0f..2346bc714 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -23,6 +23,9 @@ public: /// Calculate & count gas cost for SSTORE instruction void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); + /// Calculate & count additional gas cost for EXP instruction + void countExp(llvm::Value* _exponent); + /// Count gas cost of LOG data void countLogData(llvm::Value* _dataLength); From 76d30b8f9f0f0e8b1b4786e8438c6eb105be2da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 16 Dec 2014 19:52:02 +0100 Subject: [PATCH 343/466] Count additional gas cost for memory copies. Some GasMeter improvments. --- libevmjit/GasMeter.cpp | 37 ++++++++++++++++++++++++------------- libevmjit/GasMeter.h | 8 +++++++- libevmjit/Memory.cpp | 10 ++++++++-- libevmjit/Memory.h | 5 ++++- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index e2f45621b..0f67045a3 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -43,11 +43,16 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure { switch (inst) { + default: // Assumes instruction code is valid + return 1; + case Instruction::STOP: case Instruction::SUICIDE: case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() return 0; + case Instruction::EXP: return c_expGas; + case Instruction::SLOAD: return c_sloadGas; case Instruction::SHA3: return c_sha3Gas; @@ -68,9 +73,6 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); return c_logGas + numTopics * c_logTopicGas; } - - default: // Assumes instruction code is valid - return 1; } } @@ -144,6 +146,11 @@ void GasMeter::count(Instruction _inst) commitCostBlock(); } +void GasMeter::count(llvm::Value* _cost) +{ + createCall(m_gasCheckFunc, _cost); +} + void GasMeter::countExp(llvm::Value* _exponent) { // Additional cost is 1 per significant byte of exponent @@ -156,7 +163,7 @@ void GasMeter::countExp(llvm::Value* _exponent) auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); auto sigBits = m_builder.CreateSub(Constant::get(256), lz); auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); - createCall(m_gasCheckFunc, sigBytes); + count(sigBytes); } void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) @@ -172,15 +179,15 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu 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); + count(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); + static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter."); + commitCostBlock(_dataLength); // TODO: commit is not necessary } void GasMeter::giveBack(llvm::Value* _gas) @@ -207,17 +214,21 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost) m_blockCost = 0; if (_additionalCost) - { - m_builder.CreateCall(m_gasCheckFunc, _additionalCost); - } + count(_additionalCost); } assert(m_blockCost == 0); } -void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords) +void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) +{ + static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); + count(_additionalMemoryInWords); +} + +void GasMeter::countCopy(llvm::Value* _copyWords) { - auto cost = m_builder.CreateNUWMul(_additionalMemoryInWords, Constant::get(static_cast(c_memoryGas)), "memcost"); - m_builder.CreateCall(m_gasCheckFunc, cost); + static_assert(c_copyGas == 1, "Copy gas cost has changed. Update GasMeter."); + count(_copyWords); } } diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 2346bc714..2d8fb3044 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -20,6 +20,9 @@ public: /// Count step cost of instruction void count(Instruction _inst); + /// Count additional cost + void count(llvm::Value* _cost); + /// Calculate & count gas cost for SSTORE instruction void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); @@ -37,7 +40,10 @@ public: void giveBack(llvm::Value* _gas); /// Generate code that checks the cost of additional memory used by program - void checkMemory(llvm::Value* _additionalMemoryInWords); + void countMemory(llvm::Value* _additionalMemoryInWords); + + /// Count addional gas cost for memory copy + void countCopy(llvm::Value* _copyWords); private: /// Cumulative gas cost of a block of instructions diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index d87c76035..18d53e63e 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -24,7 +24,8 @@ namespace jit { Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): - RuntimeHelper(_runtimeManager) + RuntimeHelper(_runtimeManager), + m_gasMeter(_gasMeter) { auto module = getModule(); llvm::Type* argTypes[] = {Type::Word, Type::Word}; @@ -88,7 +89,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); + _gasMeter.countMemory(newWords); // Resize m_builder.CreateStore(sizeRequired, m_size); auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData"); @@ -186,6 +187,11 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* require(_destMemIdx, _reqBytes); + // Additional copy cost + // TODO: This round ups to 32 happens in many places + auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); + m_gasMeter.countCopy(copyWords); + auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx"); auto memPtr = getData(); diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index 8d33fbc4f..3ccc54285 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -8,11 +8,12 @@ namespace eth { namespace jit { +class GasMeter; class Memory : public RuntimeHelper { public: - Memory(RuntimeManager& _runtimeManager, class GasMeter& _gasMeter); + Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter); llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); @@ -27,6 +28,8 @@ public: void require(llvm::Value* _offset, llvm::Value* _size); private: + GasMeter& m_gasMeter; + llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager); From 49bd78b4043081b7679f1ed826c676b1f70d9b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 16 Dec 2014 20:14:47 +0100 Subject: [PATCH 344/466] SHA3 gas cost updated --- libevmjit/Compiler.cpp | 1 + libevmjit/GasMeter.cpp | 19 +++++++++++++++++-- libevmjit/GasMeter.h | 3 +++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 6c6c00ff7..3a0d8d034 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -504,6 +504,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto inOff = stack.pop(); auto inSize = stack.pop(); _memory.require(inOff, inSize); + _gasMeter.countSha3Data(inSize); auto hash = _ext.sha3(inOff, inSize); stack.push(hash); break; diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 0f67045a3..3eb16899a 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -21,12 +21,14 @@ namespace // Helper functions uint64_t const c_stepGas = 1; uint64_t const c_balanceGas = 20; -uint64_t const c_sha3Gas = 20; +uint64_t const c_sha3Gas = 10; +uint64_t const c_sha3WordGas = 10; uint64_t const c_sloadGas = 20; uint64_t const c_sstoreSetGas = 300; uint64_t const c_sstoreResetGas = 100; uint64_t const c_sstoreRefundGas = 100; uint64_t const c_createGas = 100; +uint64_t const c_createDataGas = 5; uint64_t const c_callGas = 20; uint64_t const c_expGas = 1; uint64_t const c_expByteGas = 1; @@ -44,7 +46,7 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure switch (inst) { default: // Assumes instruction code is valid - return 1; + return c_stepGas; case Instruction::STOP: case Instruction::SUICIDE: @@ -190,6 +192,19 @@ void GasMeter::countLogData(llvm::Value* _dataLength) commitCostBlock(_dataLength); // TODO: commit is not necessary } +void GasMeter::countSha3Data(llvm::Value* _dataLength) +{ + assert(m_checkCall); + assert(m_blockCost > 0); // SHA3 instruction is already counted + + // TODO: This round ups to 32 happens in many places + // FIXME: Overflow possible but Memory::require() also called. Probably 64-bit arith can be used. + static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); + auto words = m_builder.CreateUDiv(m_builder.CreateAdd(_dataLength, Constant::get(31)), Constant::get(32)); + auto cost = m_builder.CreateNUWMul(Constant::get(c_sha3WordGas), words); + count(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 2d8fb3044..890791ff1 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -32,6 +32,9 @@ public: /// Count gas cost of LOG data void countLogData(llvm::Value* _dataLength); + /// Count gas cost of SHA3 data + void countSha3Data(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 8f3edbcdb3140b7db624463f921d27fcb39d9de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 14:41:09 +0100 Subject: [PATCH 345/466] Disable cache. It's broken. --- libevmjit/ExecutionEngine.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index cb4e16784..27ff5dca4 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -36,10 +36,10 @@ namespace jit ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) { std::string key{reinterpret_cast(_code.data()), _code.size()}; - if (auto cachedExec = Cache::findExec(key)) + /*if (auto cachedExec = Cache::findExec(key)) { return run(*cachedExec, _data, _env); - } + }*/ auto module = Compiler({}).compile(_code); return run(std::move(module), _data, _env, _code); @@ -95,8 +95,8 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa return ReturnCode::LLVMLinkError; std::string key{reinterpret_cast(_code.data()), _code.size()}; - auto& cachedExec = Cache::registerExec(key, std::move(exec)); - auto returnCode = run(cachedExec, _data, _env); + //auto& cachedExec = Cache::registerExec(key, std::move(exec)); + auto returnCode = run(exec, _data, _env); auto executionEndTime = std::chrono::high_resolution_clock::now(); clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms "; From dd63bb30eb2e0253616a81f366682826153feae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 14:41:24 +0100 Subject: [PATCH 346/466] Remove TODO comment --- libevmjit-cpp/Env.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 72dc062b4..def2e5693 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -70,7 +70,7 @@ extern "C" if (_env->depth == 1024) jit::terminate(jit::ReturnCode::OutOfGas); - assert(_env->depth < 1024); // TODO: Handle call depth + assert(_env->depth < 1024); auto value = llvm2eth(*_value); if (_env->balance(_env->myAddress) >= value) From a4927609d7cc3dd81bb622b0c2a507f57368e6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 15:38:33 +0100 Subject: [PATCH 347/466] Using llvm::ExecutionEngine::getFunctionAddress() instead of getPointerToFunction(). Cleanups. --- libevmjit/Cache.h | 5 ++--- libevmjit/ExecutionEngine.cpp | 33 +++++++++++---------------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 9fd695bfe..42e56f544 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -16,12 +16,11 @@ class ExecBundle { public: std::unique_ptr engine; - llvm::Function* entryFunc = nullptr; ExecBundle() = default; ExecBundle(ExecBundle&& _other): - engine(std::move(_other.engine)), - entryFunc(_other.entryFunc) {} + engine(std::move(_other.engine)) + {} ExecBundle(ExecBundle const&) = delete; void operator=(ExecBundle) = delete; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 27ff5dca4..fd217e4ee 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -53,47 +53,37 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa static const auto program = "EVM JIT"; 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()); + std::unique_ptr memoryManager(new llvm::SectionMemoryManager); + builder.setMCJITMemoryManager(memoryManager.get()); 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 + triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format module->setTargetTriple(triple.str()); ExecBundle exec; exec.engine.reset(builder.create()); if (!exec.engine) return ReturnCode::LLVMConfigError; - _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + memoryManager.release(); // and memory manager - auto finalizationStartTime = std::chrono::high_resolution_clock::now(); - exec.engine->finalizeObject(); - auto finalizationEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); + // TODO: Finalization not needed when llvm::ExecutionEngine::getFunctionAddress used + //auto finalizationStartTime = std::chrono::high_resolution_clock::now(); + //exec.engine->finalizeObject(); + //auto finalizationEndTime = std::chrono::high_resolution_clock::now(); + //clog(JIT) << " + " << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); auto executionStartTime = std::chrono::high_resolution_clock::now(); - exec.entryFunc = module->getFunction("main"); - if (!exec.entryFunc) - return ReturnCode::LLVMLinkError; - std::string key{reinterpret_cast(_code.data()), _code.size()}; //auto& cachedExec = Cache::registerExec(key, std::move(exec)); auto returnCode = run(exec, _data, _env); @@ -120,8 +110,7 @@ ReturnCode runEntryFunc(ExecBundle const& _exec, Runtime* _runtime) // to allow function to be executed. // That might be related to memory manager. Can we share one? typedef ReturnCode(*EntryFuncPtr)(Runtime*); - auto entryFuncVoidPtr = _exec.engine->getPointerToFunction(_exec.entryFunc); - auto entryFuncPtr = static_cast(entryFuncVoidPtr); + auto entryFuncPtr = (EntryFuncPtr)_exec.engine->getFunctionAddress("main"); ReturnCode returnCode{}; auto sj = setjmp(_runtime->getJmpBuf()); From 0a642457f7c821f0ae5f233f518fe749f521faee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 17:53:06 +0100 Subject: [PATCH 348/466] Fix checking memory requirements with size 0 --- libevmjit/Memory.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 18d53e63e..116840684 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -60,12 +60,18 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ auto size = offset->getNextNode(); size->setName("size"); + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", 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 "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + // BB "Check" m_builder.SetInsertPoint(checkBB); auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); From b37ce8e9727683b8c7afb84520f42a908318f8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 17:54:51 +0100 Subject: [PATCH 349/466] Gas counting for CREATE instruction --- libevmjit-cpp/Env.cpp | 5 +++-- libevmjit/Compiler.cpp | 6 +++++- libevmjit/Ext.cpp | 10 ++++++---- libevmjit/Ext.h | 2 +- libevmjit/GasMeter.cpp | 3 +-- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index def2e5693..ca3ed2b92 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -47,7 +47,7 @@ extern "C" _env->suicide(right160(*_address)); } - EXPORT void env_create(ExtVMFace* _env, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { assert(_env->depth < 1024); // TODO: Handle call depth @@ -56,9 +56,10 @@ extern "C" if (_env->balance(_env->myAddress) >= endowment) { _env->subBalance(endowment); - u256 gas; // TODO: Handle gas + auto gas = llvm2eth(*io_gas); OnOpFunc onOp {}; // TODO: Handle that thing h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); + *io_gas = eth2llvm(gas); *o_address = address; } else diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 3a0d8d034..80bd647ad 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -741,7 +741,11 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto initSize = stack.pop(); _memory.require(initOff, initSize); - auto address = _ext.create(endowment, initOff, initSize); + _gasMeter.commitCostBlock(); + + auto gas = _runtimeManager.getGas(); + auto address = _ext.create(gas, endowment, initOff, initSize); + _runtimeManager.setGas(gas); stack.push(address); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 3955d21cd..139255a6a 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -52,7 +52,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); - llvm::Type* createArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr}; + llvm::Type* createArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr}; m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, createArgsTypes, false), Linkage::ExternalLinkage, "env_create", module); llvm::Type* callArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr}; @@ -106,12 +106,14 @@ void Ext::suicide(llvm::Value* _address) m_builder.CreateCall2(m_suicide, getRuntimeManager().getEnv(), m_args[0]); } -llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - m_builder.CreateStore(_endowment, m_args[0]); + m_builder.CreateStore(_gas, m_args[0]); + m_builder.CreateStore(_endowment, m_arg2); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(m_create, getRuntimeManager().getEnv(), m_args[0], begin, size, m_args[1]); + createCall(m_create, getRuntimeManager().getEnv(), m_args[0], m_arg2, begin, size, m_args[1]); + _gas = m_builder.CreateLoad(m_args[0]); // Return gas llvm::Value* address = m_builder.CreateLoad(m_args[1]); address = Endianness::toNative(m_builder, address); return address; diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 21e67ba88..b68e09c03 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -29,7 +29,7 @@ public: 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* create(llvm::Value*& _gas, 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); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 3eb16899a..ce53bfc26 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -83,7 +83,7 @@ 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 + // CALL, CALLCODE & CREATE are commited manually switch (_inst) { @@ -94,7 +94,6 @@ bool isCostBlockEnd(Instruction _inst) case Instruction::MSTORE8: case Instruction::SSTORE: case Instruction::GAS: - case Instruction::CREATE: return true; default: From bd85efa299e661228a1ac6283b5fad14e09f88d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Dec 2014 13:00:59 +0100 Subject: [PATCH 350/466] Execution Engine cleanups --- libevmjit/ExecutionEngine.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index fd217e4ee..022fe9f0e 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -53,15 +53,11 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa static const auto program = "EVM JIT"; llvm::PrettyStackTraceProgram X(1, &program); - llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); - llvm::InitializeNativeTargetAsmParser(); llvm::EngineBuilder builder(module); builder.setEngineKind(llvm::EngineKind::JIT); builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); builder.setOptLevel(llvm::CodeGenOpt::None); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); @@ -74,7 +70,6 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa if (!exec.engine) return ReturnCode::LLVMConfigError; _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager // TODO: Finalization not needed when llvm::ExecutionEngine::getFunctionAddress used //auto finalizationStartTime = std::chrono::high_resolution_clock::now(); From 2332595c9c0d315dc9ecde22d236ae477b931863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Dec 2014 13:01:45 +0100 Subject: [PATCH 351/466] Change the name of a module to some hash (for caching) --- libevmjit/Compiler.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 80bd647ad..20b17e9fe 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -1,6 +1,7 @@ #include "Compiler.h" +#include #include #include @@ -153,8 +154,13 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) std::unique_ptr Compiler::compile(bytes const& _bytecode) { + // TODO: Better hash of code needed, probably SHA3 + std::string code{reinterpret_cast(_bytecode.data()), _bytecode.size()}; + auto hash = std::hash{}(code); + auto strHash = std::to_string(hash); + auto compilationStartTime = std::chrono::high_resolution_clock::now(); - auto module = std::unique_ptr(new llvm::Module("main", m_builder.getContext())); + auto module = std::unique_ptr(new llvm::Module(strHash, m_builder.getContext())); // Create main function auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, Type::RuntimePtr, false); From de22a0a1329198cff8337c2655ff040a49419da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Dec 2014 14:20:04 +0100 Subject: [PATCH 352/466] Execution Engine cleanups --- libevmjit/ExecutionEngine.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index fd217e4ee..66d840fd5 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -47,17 +47,14 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) { - auto module = _module.get(); // Keep ownership of the module in _module - llvm::sys::PrintStackTraceOnErrorSignal(); static const auto program = "EVM JIT"; llvm::PrettyStackTraceProgram X(1, &program); llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); - llvm::InitializeNativeTargetAsmParser(); - llvm::EngineBuilder builder(module); + llvm::EngineBuilder builder(_module.get()); builder.setEngineKind(llvm::EngineKind::JIT); builder.setUseMCJIT(true); std::unique_ptr memoryManager(new llvm::SectionMemoryManager); @@ -67,7 +64,7 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa 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()); + _module->setTargetTriple(triple.str()); ExecBundle exec; exec.engine.reset(builder.create()); From 2b83b75c4b1885193bb05dcb4ecafe995c69ca35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Dec 2014 14:27:59 +0100 Subject: [PATCH 353/466] Object cache wit memory leaks --- libevmjit/Cache.cpp | 23 +++++++++++++++++++++++ libevmjit/Cache.h | 22 ++++++++++++++++++++++ libevmjit/ExecutionEngine.cpp | 3 +++ 3 files changed, 48 insertions(+) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 115322fef..f9ca47398 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace dev { @@ -45,6 +46,28 @@ ExecBundle* Cache::findExec(Cache::Key _key) return nullptr; } +ObjectCache* Cache::getObjectCache() +{ + static ObjectCache objectCache; + return &objectCache; +} + + +void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) +{ + auto&& key = _module->getModuleIdentifier(); + auto obj = llvm::MemoryBuffer::getMemBufferCopy(_object->getBuffer()); + m_map.insert(std::make_pair(key, obj)); +} + +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) +{ + auto it = m_map.find(_module->getModuleIdentifier()); + if (it != m_map.end()) + return llvm::MemoryBuffer::getMemBufferCopy(it->second->getBuffer()); + return nullptr; +} + } } } diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 42e56f544..6d1585329 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include namespace dev @@ -26,6 +28,24 @@ public: void operator=(ExecBundle) = delete; }; + +class ObjectCache : public llvm::ObjectCache +{ +public: + /// notifyObjectCompiled - Provides a pointer to compiled code for Module M. + virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) final override; + + /// getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that + /// contains the object which corresponds with Module M, or 0 if an object is + /// not available. The caller owns both the MemoryBuffer returned by this + /// and the memory it references. + virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; + +private: + std::unordered_map m_map; +}; + + class Cache { public: @@ -33,6 +53,8 @@ public: static ExecBundle& registerExec(Key _key, ExecBundle&& _exec); static ExecBundle* findExec(Key _key); + + static ObjectCache* getObjectCache(); }; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 66d840fd5..162851ae8 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -42,6 +42,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en }*/ auto module = Compiler({}).compile(_code); + //module->dump(); return run(std::move(module), _data, _env, _code); } @@ -73,6 +74,8 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module memoryManager.release(); // and memory manager + exec.engine->setObjectCache(Cache::getObjectCache()); + // TODO: Finalization not needed when llvm::ExecutionEngine::getFunctionAddress used //auto finalizationStartTime = std::chrono::high_resolution_clock::now(); //exec.engine->finalizeObject(); From 6543cc4bfc6fadd9474a0a2f71cbf3a2f5a21b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Dec 2014 14:32:30 +0100 Subject: [PATCH 354/466] Execution Engine cleanups (reverted from commit bd85efa299e661228a1ac6283b5fad14e09f88d9) --- libevmjit/ExecutionEngine.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 17d57818c..162851ae8 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -52,11 +52,14 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa static const auto program = "EVM JIT"; llvm::PrettyStackTraceProgram X(1, &program); + llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); llvm::EngineBuilder builder(_module.get()); builder.setEngineKind(llvm::EngineKind::JIT); builder.setUseMCJIT(true); + std::unique_ptr memoryManager(new llvm::SectionMemoryManager); + builder.setMCJITMemoryManager(memoryManager.get()); builder.setOptLevel(llvm::CodeGenOpt::None); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); @@ -69,6 +72,7 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa if (!exec.engine) return ReturnCode::LLVMConfigError; _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + memoryManager.release(); // and memory manager exec.engine->setObjectCache(Cache::getObjectCache()); From 8287c6040a4900cb8b091ffbe284c7f478c60c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Dec 2014 15:01:55 +0100 Subject: [PATCH 355/466] Own cached objects --- libevmjit/Cache.cpp | 4 ++-- libevmjit/Cache.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index f9ca47398..1265273f6 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -56,8 +56,8 @@ ObjectCache* Cache::getObjectCache() void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { auto&& key = _module->getModuleIdentifier(); - auto obj = llvm::MemoryBuffer::getMemBufferCopy(_object->getBuffer()); - m_map.insert(std::make_pair(key, obj)); + std::unique_ptr obj(llvm::MemoryBuffer::getMemBufferCopy(_object->getBuffer())); + m_map.insert(std::make_pair(key, std::move(obj))); } llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 6d1585329..f56716de2 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -42,7 +42,7 @@ public: virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; private: - std::unordered_map m_map; + std::unordered_map> m_map; }; From 232f9fee527e454f4008c2c03a9c7dac1c5c85ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 19 Dec 2014 12:32:01 +0100 Subject: [PATCH 356/466] Refactor cmake files --- CMakeLists.txt | 4 ++- evmcc/CMakeLists.txt | 54 +++++++++--------------------------- libevmjit-cpp/CMakeLists.txt | 13 ++++----- libevmjit/CMakeLists.txt | 46 +++++------------------------- 4 files changed, 29 insertions(+), 88 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4243f6676..06027b883 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,3 @@ - cmake_minimum_required(VERSION 2.8.12) project(evmjit) @@ -10,6 +9,9 @@ find_package(LLVM REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") +# Boost +find_package(Boost REQUIRED) + add_subdirectory(libevmjit) add_subdirectory(libevmjit-cpp) add_subdirectory(evmcc) \ No newline at end of file diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index e11baabbb..b68f7e78b 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -1,48 +1,20 @@ -cmake_policy(SET CMP0015 NEW) +set(TARGET_NAME evmcc) -project(evmjit CXX) +set(SOURCES + evmcc.cpp +) +source_group("" FILES ${SOURCES}) -file(GLOB SOURCES "*.cpp") -file(GLOB HEADERS "*.h") -set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "tools") - -set(EXECUTABLE evmcc) -add_executable(${EXECUTABLE} ${HEADERS} ${SOURCES}) +add_executable(${TARGET_NAME} ${SOURCES}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "tools") include_directories(../..) - -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) 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 - +include_directories(${Boost_INCLUDE_DIRS}) -install( TARGETS ${EXECUTABLE} DESTINATION bin ) +target_link_libraries(${TARGET_NAME} ethereum) +target_link_libraries(${TARGET_NAME} ${Boost_PROGRAM_OPTIONS_LIBRARIES}) +llvm_map_components_to_libnames(LLVM_LIBS bitwriter) +target_link_libraries(${TARGET_NAME} ${LLVM_LIBS}) -cmake_policy(SET CMP0015 NEW) +install(TARGETS ${TARGET_NAME} DESTINATION bin ) \ No newline at end of file diff --git a/libevmjit-cpp/CMakeLists.txt b/libevmjit-cpp/CMakeLists.txt index 1750b04ce..25be95177 100644 --- a/libevmjit-cpp/CMakeLists.txt +++ b/libevmjit-cpp/CMakeLists.txt @@ -1,17 +1,16 @@ -project(evmjit-cpp CXX) +set(TARGET_NAME evmjit-cpp) set(SOURCES Env.cpp JitVM.cpp JitVM.h ) +source_group("" FILES ${SOURCES}) -add_library(${PROJECT_NAME} ${SOURCES}) +add_library(${TARGET_NAME} ${SOURCES}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") include_directories(../..) - -find_package(LLVM REQUIRED CONFIG) include_directories(${LLVM_INCLUDE_DIRS}) -add_definitions(${LLVM_DEFINITIONS}) +include_directories(${Boost_INCLUDE_DIRS}) -source_group("" FILES ${SOURCES}) -set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "libs") \ No newline at end of file +target_link_libraries(${TARGET_NAME} evmjit) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 82ae0d3b1..59c94880b 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -1,51 +1,19 @@ -project(evmjit CXX) +set(TARGET_NAME evmjit) file(GLOB SOURCES "*.cpp") file(GLOB HEADERS "*.h") +source_group("" FILES ${HEADERS}) +source_group("" FILES ${SOURCES}) -add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS}) - -#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 () +add_library(${TARGET_NAME} ${SOURCES} ${HEADERS}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") -# LLVM specific commands -find_package(LLVM REQUIRED CONFIG) include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${Boost_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen) -target_link_libraries(${PROJECT_NAME} ${LLVM_LIBS}) -# end of LLVM specific commands - - -# Boost -find_package(Boost REQUIRED) -include_directories(${Boost_INCLUDE_DIRS}) - +target_link_libraries(${TARGET_NAME} ${LLVM_LIBS}) #install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) #install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) - - -source_group("" FILES ${HEADERS}) -source_group("" FILES ${SOURCES}) -set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "libs") From ed63ced24456c28b6dba345b8fc61e680ed406d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sat, 20 Dec 2014 10:39:07 +0100 Subject: [PATCH 357/466] Disable rtti for Cache as LLVM has not rtti --- libevmjit/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 59c94880b..140e8f24e 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -5,6 +5,11 @@ file(GLOB HEADERS "*.h") source_group("" FILES ${HEADERS}) source_group("" FILES ${SOURCES}) +if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # Disable rtti for Cache as LLVM has no rtti + set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) +endif () + add_library(${TARGET_NAME} ${SOURCES} ${HEADERS}) set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") @@ -15,5 +20,7 @@ add_definitions(${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen) target_link_libraries(${TARGET_NAME} ${LLVM_LIBS}) +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") + #install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) #install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) From 1b490244bf4864b96448d56a7cd20f3d5b0a0b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sun, 21 Dec 2014 01:30:25 +0100 Subject: [PATCH 358/466] Workaround for Ubuntu broken LLVM package (llvm-3.5-dev does not have correct cmake files) --- CMakeLists.txt | 16 +++++++++++++--- evmcc/CMakeLists.txt | 2 -- libevmjit/CMakeLists.txt | 2 -- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 06027b883..26a8010d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,19 @@ project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) # LLVM -find_package(LLVM REQUIRED CONFIG) -message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") -message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") +if(LLVM_DIR) # local LLVM build + find_package(LLVM REQUIRED CONFIG) + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + # TODO: bitwriter is needed only for evmcc + llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter) +else() + # Workaround for Ubuntu broken LLVM package + message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") + execute_process(COMMAND llvm-config-3.5 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS) + message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}") + set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") +endif() # Boost find_package(Boost REQUIRED) diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt index b68f7e78b..4ffbf5fb5 100644 --- a/evmcc/CMakeLists.txt +++ b/evmcc/CMakeLists.txt @@ -14,7 +14,5 @@ include_directories(${Boost_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ethereum) target_link_libraries(${TARGET_NAME} ${Boost_PROGRAM_OPTIONS_LIBRARIES}) -llvm_map_components_to_libnames(LLVM_LIBS bitwriter) -target_link_libraries(${TARGET_NAME} ${LLVM_LIBS}) install(TARGETS ${TARGET_NAME} DESTINATION bin ) \ No newline at end of file diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 140e8f24e..7c35169a7 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -15,9 +15,7 @@ set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) -add_definitions(${LLVM_DEFINITIONS}) -llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen) target_link_libraries(${TARGET_NAME} ${LLVM_LIBS}) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") From 66d5a2b5cdf1361dcf0205b191dd12be090ed224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 22 Dec 2014 14:16:42 +0100 Subject: [PATCH 359/466] Add -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS needed by LLVM --- libevmjit/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 7c35169a7..2b80c1db8 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -10,6 +10,10 @@ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) endif () +# Needed by LLVM +# TODO: If LLVMConfig.cmake is fixed, ${LLVM_DEFINITIONS} var can be used +add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS) + add_library(${TARGET_NAME} ${SOURCES} ${HEADERS}) set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") From 6094aa30add22d56bee145bbb4a7d440c08db5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 22 Dec 2014 14:14:08 -0500 Subject: [PATCH 360/466] Fix compilation with LLVM pre-3.5 (Ubuntu 14.04) --- libevmjit/BasicBlock.cpp | 7 ++++++- libevmjit/Compiler.cpp | 9 +++++++-- libevmjit/ExecutionEngine.cpp | 2 ++ libevmjit/Ext.cpp | 2 +- libevmjit/Memory.cpp | 2 +- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index d233ea744..7371ed54b 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -3,12 +3,17 @@ #include -#include #include #include #include #include +#if defined(LLVM_VERSION_PATCH) // Correct llvm-3.5 +#include +#else // Ubuntu 14.04 crap +#include +#endif + #include "Type.h" namespace dev diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 20b17e9fe..3cbce715b 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -8,13 +8,18 @@ #include #include -#include #include #include #include #include +#if defined(LLVM_VERSION_PATCH) // Correct llvm-3.5 +#include +#else // Ubuntu 14.04 crap +#include +#endif + #include "Instruction.h" #include "Type.h" #include "Memory.h" @@ -481,7 +486,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto idx = stack.pop(); auto word = stack.pop(); - auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32"); + auto k32_ = m_builder.CreateTrunc(idx, llvm::IntegerType::get(m_builder.getContext(), 5), "k_32"); auto k32 = m_builder.CreateZExt(k32_, Type::Word); auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8"); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 162851ae8..bdba78129 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -63,8 +63,10 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa builder.setOptLevel(llvm::CodeGenOpt::None); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); + #if defined(LLVM_VERSION_PATCH) // Not available in llvm-3.5-dev on Ubuntu 14.04 if (triple.getOS() == llvm::Triple::OSType::Win32) triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format + #endif _module->setTargetTriple(triple.str()); ExecBundle exec; diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 139255a6a..d51aa4458 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -27,7 +27,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): auto&& ctx = m_builder.getContext(); auto module = getModule(); - auto i256Ty = m_builder.getIntNTy(256); + auto i256Ty = Type::Word; m_args[0] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.index"); m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "ext.value"); diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 116840684..fa95b90b9 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -42,7 +42,7 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): 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); + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::ReadOnly); m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); m_require = createRequireFunc(_gasMeter, _runtimeManager); From 75fa67200e718bf9fdff2aa1f65f17d757667dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 22 Dec 2014 22:16:37 +0100 Subject: [PATCH 361/466] Fix compilation with LLVM pre-3.5 (Ubuntu 14.04) (reverted from commit 6094aa30add22d56bee145bbb4a7d440c08db5c8) --- libevmjit/BasicBlock.cpp | 7 +------ libevmjit/Compiler.cpp | 9 ++------- libevmjit/ExecutionEngine.cpp | 2 -- libevmjit/Ext.cpp | 2 +- libevmjit/Memory.cpp | 2 +- 5 files changed, 5 insertions(+), 17 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 7371ed54b..d233ea744 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -3,17 +3,12 @@ #include +#include #include #include #include #include -#if defined(LLVM_VERSION_PATCH) // Correct llvm-3.5 -#include -#else // Ubuntu 14.04 crap -#include -#endif - #include "Type.h" namespace dev diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 3cbce715b..20b17e9fe 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -8,18 +8,13 @@ #include #include +#include #include #include #include #include -#if defined(LLVM_VERSION_PATCH) // Correct llvm-3.5 -#include -#else // Ubuntu 14.04 crap -#include -#endif - #include "Instruction.h" #include "Type.h" #include "Memory.h" @@ -486,7 +481,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto idx = stack.pop(); auto word = stack.pop(); - auto k32_ = m_builder.CreateTrunc(idx, llvm::IntegerType::get(m_builder.getContext(), 5), "k_32"); + 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"); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index bdba78129..162851ae8 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -63,10 +63,8 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa builder.setOptLevel(llvm::CodeGenOpt::None); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); - #if defined(LLVM_VERSION_PATCH) // Not available in llvm-3.5-dev on Ubuntu 14.04 if (triple.getOS() == llvm::Triple::OSType::Win32) triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format - #endif _module->setTargetTriple(triple.str()); ExecBundle exec; diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index d51aa4458..139255a6a 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -27,7 +27,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): auto&& ctx = m_builder.getContext(); auto module = getModule(); - auto i256Ty = Type::Word; + 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"); diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index fa95b90b9..116840684 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -42,7 +42,7 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): 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::ReadOnly); + 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); From 20190b145b45bdf1afec71f11cc6de592d0a9f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 22 Dec 2014 22:16:46 +0100 Subject: [PATCH 362/466] Add -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS needed by LLVM (reverted from commit 66d5a2b5cdf1361dcf0205b191dd12be090ed224) --- libevmjit/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 2b80c1db8..7c35169a7 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -10,10 +10,6 @@ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) endif () -# Needed by LLVM -# TODO: If LLVMConfig.cmake is fixed, ${LLVM_DEFINITIONS} var can be used -add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS) - add_library(${TARGET_NAME} ${SOURCES} ${HEADERS}) set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") From 43e08ea32d9aa965315cdf9b507c9c844b28614c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 22 Dec 2014 22:54:51 +0100 Subject: [PATCH 363/466] Handle create/call depth limit in CREATE instruction --- libevmjit-cpp/Env.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index ca3ed2b92..50945583b 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -49,7 +49,10 @@ extern "C" EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { - assert(_env->depth < 1024); // TODO: Handle call depth + if (_env->depth == 1024) + jit::terminate(jit::ReturnCode::OutOfGas); + + assert(_env->depth < 1024); auto endowment = llvm2eth(*_endowment); From 4254b3fec10f4cf2e2e9fd57623766550fe029f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 22 Dec 2014 23:52:33 +0100 Subject: [PATCH 364/466] Fix memory copy [Delivers #84703344] --- libevmjit/Memory.cpp | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 116840684..59dc47e83 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -189,8 +189,6 @@ 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::Word, 0); - require(_destMemIdx, _reqBytes); // Additional copy cost @@ -198,20 +196,28 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); m_gasMeter.countCopy(copyWords); - 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); + // Algorithm: + // isOutsideData = idx256 >= size256 + // idx64 = trunc idx256 + // size64 = trunc size256 + // dataLeftSize = size64 - idx64 // safe if not isOutsideData + // reqBytes64 = trunc _reqBytes // require() handles large values + // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min + // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) + + auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto dataLeftSize = m_builder.CreateSub(size64, idx64); + auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); + auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); + + auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); + auto dst = m_builder.CreateGEP(getData(), _destMemIdx, "dst"); + m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); } } From 30f0a7a8948cc2a1c45f92c6965de0f2e3ee48dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 23 Dec 2014 00:03:31 +0100 Subject: [PATCH 365/466] Type usage and other cleanups --- libevmjit/Compiler.cpp | 2 +- libevmjit/Ext.cpp | 21 +++++++++------------ libevmjit/Ext.h | 1 - 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 20b17e9fe..ebc743d50 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -488,7 +488,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode // 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 bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest"); auto mask_ = m_builder.CreateShl(Constant::get(1), bitpos); auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 139255a6a..a4a1fc350 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -24,20 +24,17 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): RuntimeHelper(_runtimeManager), m_memoryMan(_memoryMan) { - 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"); + m_args[0] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.index"); + m_args[1] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.value"); + m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg2"); + m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg3"); + m_arg4 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg4"); + m_arg5 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg5"); + m_arg6 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg6"); + m_arg7 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg7"); + m_arg8 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg8"); m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); using Linkage = llvm::GlobalValue::LinkageTypes; diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index b68e09c03..0227d806d 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -58,7 +58,6 @@ private: llvm::Function* m_create; llvm::Function* m_call; llvm::Function* m_sha3; - llvm::Function* m_exp; llvm::Function* m_getExtCode; llvm::Function* m_log; }; From eaed9c3c4ffb9a8da6d602ade83f541fc34591b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 23 Dec 2014 00:41:45 +0100 Subject: [PATCH 366/466] Read push data using llvm::APInt --- libevmjit/Compiler.cpp | 2 +- libevmjit/Instruction.h | 7 ++++++- libevmjit/Type.cpp | 6 ++---- libevmjit/Type.h | 2 +- libevmjit/Utils.cpp | 4 ++-- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index ebc743d50..bc65bafa8 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -71,7 +71,7 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) 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.ult(_bytecode.size()) ? val.getZExtValue() : _bytecode.size(); splitPoints.insert(targetPC); ProgramCounter jumpPC = (next - _bytecode.begin()); diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index 86c529e18..502c4b66e 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -2,6 +2,11 @@ #include "Common.h" +namespace llvm +{ + class APInt; +} + namespace dev { namespace eth @@ -156,7 +161,7 @@ enum class Instruction: uint8_t /// 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); +llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index dcff24153..22ccea12e 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -51,11 +51,9 @@ llvm::ConstantInt* Constant::get(int64_t _n) return llvm::ConstantInt::getSigned(Type::Word, _n); } -llvm::ConstantInt* Constant::get(u256 _n) +llvm::ConstantInt* Constant::get(llvm::APInt const& _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)); + return llvm::ConstantInt::get(Type::Word->getContext(), _n); } llvm::ConstantInt* Constant::get(ReturnCode _returnCode) diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 0a98cb8a1..d4804ee59 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -43,7 +43,7 @@ struct Constant { /// Returns word-size constant static llvm::ConstantInt* get(int64_t _n); - static llvm::ConstantInt* get(u256 _n); + static llvm::ConstantInt* get(llvm::APInt const& _n); static llvm::ConstantInt* get(ReturnCode _returnCode); }; diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 6c2bd81ba..f1ffbf67f 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -38,12 +38,12 @@ i256 eth2llvm(u256 _u) return i; } -u256 readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +llvm::APInt 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; + llvm::APInt value(256, 0); ++_curr; // Point the data for (decltype(numBytes) i = 0; i < numBytes; ++i) { From 6acbfe07b27cafd6eb1438c01924e3d3193aaa59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 23 Dec 2014 00:49:01 +0100 Subject: [PATCH 367/466] Remove unused function --- libevmjit/Runtime.cpp | 5 ----- libevmjit/Runtime.h | 1 - 2 files changed, 6 deletions(-) diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 9cc09032e..27c81ea86 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -35,11 +35,6 @@ Runtime::~Runtime() g_currJmpBuf = m_prevJmpBuf; } -u256 Runtime::getGas() const -{ - return llvm2eth(m_data.elems[RuntimeData::Gas]); -} - bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy { // TODO: Handle large indexes diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index adb736ecc..25da2475a 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -41,7 +41,6 @@ public: MemoryImpl& getMemory() { return m_memory; } Env* getEnvPtr() { return &m_env; } - u256 getGas() const; bytes getReturnData() const; jmp_buf_ref getJmpBuf() { return m_jmpBuf; } static jmp_buf_ref getCurrJmpBuf(); From 69930b9bcd27bb46d24890889bc1a4bdb2742271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 23 Dec 2014 00:49:23 +0100 Subject: [PATCH 368/466] Use sub "no-wrap" --- libevmjit/Memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 59dc47e83..b088fb808 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -208,7 +208,7 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); - auto dataLeftSize = m_builder.CreateSub(size64, idx64); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); From c5ebca65d5eaf94663cde58f319958e851c00fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 29 Dec 2014 18:44:05 +0100 Subject: [PATCH 369/466] More aggresive gas counting optimization: do not commit cost before memory access. --- libevmjit/GasMeter.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index ce53bfc26..801d5b938 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -87,11 +87,6 @@ bool isCostBlockEnd(Instruction _inst) switch (_inst) { - case Instruction::CALLDATACOPY: - case Instruction::CODECOPY: - case Instruction::MLOAD: - case Instruction::MSTORE: - case Instruction::MSTORE8: case Instruction::SSTORE: case Instruction::GAS: return true; From c5de54dbb0c92af6cfa1e9f76904d29bdb3b1cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 29 Dec 2014 18:54:27 +0100 Subject: [PATCH 370/466] More aggresive gas counting optimization: do not commit cost before SSTORE. --- libevmjit/GasMeter.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 801d5b938..515eefaaa 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -87,7 +87,6 @@ bool isCostBlockEnd(Instruction _inst) switch (_inst) { - case Instruction::SSTORE: case Instruction::GAS: return true; @@ -164,8 +163,6 @@ void GasMeter::countExp(llvm::Value* _exponent) void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) { - assert(!m_checkCall); // Everything should've been commited before - auto oldValue = _ext.sload(_index); auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero"); auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero"); From 5d5259e4e09797f8924abc9df1d5cd8180d2cc0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 29 Dec 2014 19:22:50 +0100 Subject: [PATCH 371/466] Do not auto-commit cost block --- libevmjit/Compiler.cpp | 6 ++++++ libevmjit/GasMeter.cpp | 20 -------------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index bc65bafa8..2dc2b0c65 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -658,6 +658,12 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode } case Instruction::GAS: + { + _gasMeter.commitCostBlock(); + stack.push(_runtimeManager.getGas()); + break; + } + case Instruction::ADDRESS: case Instruction::CALLER: case Instruction::ORIGIN: diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 515eefaaa..e5acbdc1d 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -78,23 +78,6 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure } } -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 & CREATE are commited manually - - switch (_inst) - { - case Instruction::GAS: - return true; - - default: - return false; - } -} - } GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) : @@ -136,9 +119,6 @@ void GasMeter::count(Instruction _inst) } m_blockCost += getStepCost(_inst); - - if (isCostBlockEnd(_inst)) - commitCostBlock(); } void GasMeter::count(llvm::Value* _cost) From 90cb4a753e81e8cff1b97ad74efca677508078c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 29 Dec 2014 19:48:02 +0100 Subject: [PATCH 372/466] More aggresive gas counting optimization: do not commit cost before LOG. [#81461534] --- libevmjit/GasMeter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index e5acbdc1d..5a5ced154 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -160,7 +160,7 @@ void GasMeter::countLogData(llvm::Value* _dataLength) assert(m_checkCall); assert(m_blockCost > 0); // LOGn instruction is already counted static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter."); - commitCostBlock(_dataLength); // TODO: commit is not necessary + count(_dataLength); } void GasMeter::countSha3Data(llvm::Value* _dataLength) From e3245e140be3f8a328bf249f7739b92dab8ef2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 29 Dec 2014 19:49:16 +0100 Subject: [PATCH 373/466] Remove addtional cost param from commitCostBlock(). Count additional cost manually. [#81461534] --- libevmjit/Compiler.cpp | 3 ++- libevmjit/GasMeter.cpp | 7 +------ libevmjit/GasMeter.h | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 2dc2b0c65..40dff5cb1 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -773,7 +773,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto outOff = stack.pop(); auto outSize = stack.pop(); - _gasMeter.commitCostBlock(gas); + _gasMeter.commitCostBlock(); // Require memory for in and out buffers _memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one @@ -783,6 +783,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); + _gasMeter.count(gas); auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); _gasMeter.giveBack(gas); stack.push(ret); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 5a5ced154..db386551d 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -181,10 +181,8 @@ void GasMeter::giveBack(llvm::Value* _gas) m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); } -void GasMeter::commitCostBlock(llvm::Value* _additionalCost) +void GasMeter::commitCostBlock() { - assert(!_additionalCost || m_checkCall); // _additionalCost => m_checkCall; Must be inside cost-block - // If any uncommited block if (m_checkCall) { @@ -198,9 +196,6 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost) 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) - count(_additionalCost); } assert(m_blockCost == 0); } diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 890791ff1..56da6eb9f 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -36,8 +36,7 @@ public: void countSha3Data(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); + void commitCostBlock(); /// Give back an amount of gas not used by a call void giveBack(llvm::Value* _gas); From 6643af52245a0d98a4e9a8477341f26c93d8ab40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Dec 2014 13:31:46 +0100 Subject: [PATCH 374/466] Use code hash as main function name --- libevmjit/Cache.h | 4 +++- libevmjit/Compiler.cpp | 2 +- libevmjit/CompilerHelper.cpp | 4 +++- libevmjit/ExecutionEngine.cpp | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index f56716de2..d36b9fc0b 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -18,10 +18,12 @@ class ExecBundle { public: std::unique_ptr engine; + std::string mainFuncName; ExecBundle() = default; ExecBundle(ExecBundle&& _other): - engine(std::move(_other.engine)) + engine(std::move(_other.engine)), + mainFuncName(std::move(_other.mainFuncName)) {} ExecBundle(ExecBundle const&) = delete; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 40dff5cb1..8d4556d87 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -164,7 +164,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode) // Create main function auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, Type::RuntimePtr, false); - m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get()); + m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, strHash, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); // Create the basic blocks. diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index 6846ffd1c..badf9d889 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -2,6 +2,7 @@ #include "CompilerHelper.h" #include +#include #include "RuntimeManager.h" @@ -25,10 +26,11 @@ llvm::Module* CompilerHelper::getModule() llvm::Function* CompilerHelper::getMainFunction() { + // TODO: Rename or change semantics of getMainFunction() function assert(m_builder.GetInsertBlock()); auto mainFunc = m_builder.GetInsertBlock()->getParent(); assert(mainFunc); - if (mainFunc->getName() == "main") + if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module return mainFunc; return nullptr; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 162851ae8..fc1b4ea3a 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -68,6 +68,7 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa _module->setTargetTriple(triple.str()); ExecBundle exec; + exec.mainFuncName = _module->getModuleIdentifier(); exec.engine.reset(builder.create()); if (!exec.engine) return ReturnCode::LLVMConfigError; @@ -110,7 +111,7 @@ ReturnCode runEntryFunc(ExecBundle const& _exec, Runtime* _runtime) // to allow function to be executed. // That might be related to memory manager. Can we share one? typedef ReturnCode(*EntryFuncPtr)(Runtime*); - auto entryFuncPtr = (EntryFuncPtr)_exec.engine->getFunctionAddress("main"); + auto entryFuncPtr = (EntryFuncPtr)_exec.engine->getFunctionAddress(_exec.mainFuncName); ReturnCode returnCode{}; auto sj = setjmp(_runtime->getJmpBuf()); From f8ffdfa30c4ed9b6d4c04ecd1ef5909a8fda0919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Dec 2014 17:58:10 +0100 Subject: [PATCH 375/466] Remove global privite pointers to runtime instance and runtime data --- libevmjit/Ext.cpp | 16 +++++++------- libevmjit/GasMeter.cpp | 18 ++++++++++------ libevmjit/Memory.cpp | 34 +++++++++++++++++------------- libevmjit/Memory.h | 2 +- libevmjit/RuntimeManager.cpp | 41 ++++++++++++++++-------------------- libevmjit/RuntimeManager.h | 7 +++--- 6 files changed, 60 insertions(+), 58 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index a4a1fc350..2b9802bb0 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -69,7 +69,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): llvm::Value* Ext::sload(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateCall3(m_sload, getRuntimeManager().getEnv(), m_args[0], m_args[1]); // Uses native endianness + m_builder.CreateCall3(m_sload, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness return m_builder.CreateLoad(m_args[1]); } @@ -77,7 +77,7 @@ void Ext::sstore(llvm::Value* _index, llvm::Value* _value) { m_builder.CreateStore(_index, m_args[0]); m_builder.CreateStore(_value, m_args[1]); - m_builder.CreateCall3(m_sstore, getRuntimeManager().getEnv(), m_args[0], m_args[1]); // Uses native endianness + m_builder.CreateCall3(m_sstore, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness } llvm::Value* Ext::calldataload(llvm::Value* _index) @@ -92,7 +92,7 @@ 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().getEnv(), m_args[0], m_args[1]); + m_builder.CreateCall3(m_balance, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); return m_builder.CreateLoad(m_args[1]); } @@ -100,7 +100,7 @@ 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().getEnv(), m_args[0]); + m_builder.CreateCall2(m_suicide, getRuntimeManager().getEnvPtr(), m_args[0]); } llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) @@ -109,7 +109,7 @@ llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Valu m_builder.CreateStore(_endowment, m_arg2); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(m_create, getRuntimeManager().getEnv(), m_args[0], m_arg2, begin, size, m_args[1]); + createCall(m_create, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, begin, size, m_args[1]); _gas = m_builder.CreateLoad(m_args[0]); // Return gas llvm::Value* address = m_builder.CreateLoad(m_args[1]); address = Endianness::toNative(m_builder, address); @@ -128,7 +128,7 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); m_builder.CreateStore(codeAddress, m_arg8); - auto ret = createCall(m_call, getRuntimeManager().getEnv(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8); + auto ret = createCall(m_call, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8); _gas = m_builder.CreateLoad(m_args[0]); // Return gas return m_builder.CreateZExt(ret, Type::Word, "ret"); } @@ -147,7 +147,7 @@ MemoryRef Ext::getExtCode(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); m_builder.CreateStore(addr, m_args[0]); - auto code = createCall(m_getExtCode, getRuntimeManager().getEnv(), m_args[0], m_size); + auto code = createCall(m_getExtCode, getRuntimeManager().getEnvPtr(), m_args[0], m_size); auto codeSize = m_builder.CreateLoad(m_size); auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); return {code, codeSize256}; @@ -157,7 +157,7 @@ void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array& _builder, RuntimeManager& _runtimeManager) { auto module = getModule(); - m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::Word, false), llvm::Function::PrivateLinkage, "gas.check", module); + llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); InsertPointGuard guard(m_builder); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); @@ -94,14 +95,17 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) 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 arg = m_gasCheckFunc->arg_begin(); + arg->setName("rt"); + ++arg; + arg->setName("cost"); + auto cost = arg; 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_runtimeManager.raiseException(ReturnCode::OutOfGas); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); @@ -115,7 +119,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::Word)); + m_checkCall = createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)); } m_blockCost += getStepCost(_inst); @@ -123,7 +127,7 @@ void GasMeter::count(Instruction _inst) void GasMeter::count(llvm::Value* _cost) { - createCall(m_gasCheckFunc, _cost); + createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), _cost); } void GasMeter::countExp(llvm::Value* _exponent) @@ -193,7 +197,7 @@ void GasMeter::commitCostBlock() return; } - m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call + m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block m_blockCost = 0; } diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index b088fb808..74e21cbfe 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -24,7 +24,7 @@ namespace jit { Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): - RuntimeHelper(_runtimeManager), + RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed m_gasMeter(_gasMeter) { auto module = getModule(); @@ -45,17 +45,19 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): 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_require = createRequireFunc(_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::Function* Memory::createRequireFunc(GasMeter& _gasMeter) { - llvm::Type* argTypes[] = {Type::Word, Type::Word}; + llvm::Type* argTypes[] = {Type::RuntimePtr, 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(); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); offset->setName("offset"); auto size = offset->getNextNode(); size->setName("size"); @@ -98,7 +100,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ _gasMeter.countMemory(newWords); // Resize m_builder.CreateStore(sizeRequired, m_size); - auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData"); + auto newData = m_builder.CreateCall2(m_resize, rt, m_size, "newData"); m_builder.CreateStore(newData, m_data); m_builder.CreateBr(returnBB); @@ -112,15 +114,18 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet { auto isWord = _valueType == Type::Word; - llvm::Type* storeArgs[] = {Type::Word, _valueType}; + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; 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 funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, 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(); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto index = rt->getNextNode(); index->setName("index"); auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; @@ -130,7 +135,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); if (_isStore) { - llvm::Value* value = ++func->arg_begin(); + llvm::Value* value = index->getNextNode(); value->setName("value"); if (isWord) value = Endianness::toBE(m_builder, value); @@ -150,19 +155,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); - return value; + return createCall(m_loadWord, getRuntimeManager().getRuntimePtr(), _addr); } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - m_builder.CreateCall2(m_storeWord, _addr, _word); + createCall(m_storeWord, getRuntimeManager().getRuntimePtr(), _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); + createCall(m_storeByte, getRuntimeManager().getRuntimePtr(), _addr, byte); } llvm::Value* Memory::getData() @@ -183,7 +187,7 @@ llvm::Value* Memory::getBytePtr(llvm::Value* _index) void Memory::require(llvm::Value* _offset, llvm::Value* _size) { - m_builder.CreateCall2(m_require, _offset, _size); + createCall(m_require, getRuntimeManager().getRuntimePtr(), _offset, _size); } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index 3ccc54285..85b0cb833 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -31,7 +31,7 @@ private: GasMeter& m_gasMeter; llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager); + llvm::Function* createRequireFunc(GasMeter& _gasMeter); llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 9bb9b3698..b324da641 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -74,43 +74,38 @@ llvm::Twine getName(RuntimeData::Index _index) RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) { - m_rtPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt"); - m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimeDataPtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimeDataPtr), "data"); m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); - // Export data - auto mainFunc = getMainFunction(); - llvm::Value* rtPtr = &mainFunc->getArgumentList().front(); - m_builder.CreateStore(rtPtr, m_rtPtr); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 0, "dataPtr"); - auto data = m_builder.CreateLoad(dataPtr, "data"); - m_builder.CreateStore(data, m_dataPtr); - - auto envPtr = m_builder.CreateStructGEP(rtPtr, 1, "envPtr"); - m_env = m_builder.CreateLoad(envPtr, "env"); - assert(m_env->getType() == Type::EnvPtr); + // Unpack data + auto rtPtr = getRuntimePtr(); + m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); + assert(m_dataPtr->getType() == Type::RuntimeDataPtr); + m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env"); + assert(m_envPtr->getType() == Type::EnvPtr); } llvm::Value* RuntimeManager::getRuntimePtr() { - // FIXME: Data ptr - //if (auto mainFunc = getMainFunction()) - // return mainFunc->arg_begin(); // Runtime is the parameter of main function - return m_builder.CreateLoad(m_rtPtr, "rt"); + // Expect first argument of a function to be a pointer to Runtime + auto func = m_builder.GetInsertBlock()->getParent(); + auto rtPtr = &func->getArgumentList().front(); + assert(rtPtr->getType() == Type::RuntimePtr); + return rtPtr; } llvm::Value* RuntimeManager::getDataPtr() { - // FIXME: Data ptr - //if (auto mainFunc = getMainFunction()) - // return mainFunc->arg_begin(); // Runtime is the parameter of main function - return m_builder.CreateLoad(m_dataPtr, "data"); + if (getMainFunction()) + return m_dataPtr; + + auto rtPtr = getRuntimePtr(); + return m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); } -llvm::Value* RuntimeManager::getEnv() +llvm::Value* RuntimeManager::getEnvPtr() { assert(getMainFunction()); // Available only in main function - return m_env; + return m_envPtr; } llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index c10c8cd25..1cff606e3 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -19,7 +19,7 @@ public: llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); - llvm::Value* getEnv(); + llvm::Value* getEnvPtr(); // TODO: Can we make it const? llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); @@ -40,10 +40,9 @@ private: void set(RuntimeData::Index _index, llvm::Value* _value); llvm::Value* getJmpBuf(); - llvm::GlobalVariable* m_rtPtr = nullptr; - llvm::GlobalVariable* m_dataPtr = nullptr; llvm::Function* m_longjmp = nullptr; - llvm::Value* m_env = nullptr; + llvm::Value* m_dataPtr = nullptr; + llvm::Value* m_envPtr = nullptr; }; } From 713b33ee4260dd549da63ace7af4b722fa460a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Dec 2014 18:41:18 +0100 Subject: [PATCH 376/466] Remove global private memory pointers --- libevmjit/Memory.cpp | 28 ++++++++++++++-------------- libevmjit/Memory.h | 3 --- libevmjit/Runtime.h | 2 ++ libevmjit/RuntimeManager.cpp | 4 +++- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 74e21cbfe..95e38d4a8 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -33,12 +33,6 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): 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; @@ -80,7 +74,9 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) 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 rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "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? @@ -99,9 +95,10 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); _gasMeter.countMemory(newWords); // Resize - m_builder.CreateStore(sizeRequired, m_size); - auto newData = m_builder.CreateCall2(m_resize, rt, m_size, "newData"); - m_builder.CreateStore(newData, m_data); + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); m_builder.CreateBr(returnBB); // BB "Return" @@ -171,18 +168,21 @@ void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) llvm::Value* Memory::getData() { - return m_builder.CreateLoad(m_data); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + return m_builder.CreateLoad(dataPtr, "data"); } llvm::Value* Memory::getSize() { - return m_builder.CreateLoad(m_size); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + return m_builder.CreateLoad(sizePtr, "size"); } llvm::Value* Memory::getBytePtr(llvm::Value* _index) { - auto data = m_builder.CreateLoad(m_data, "data"); - return m_builder.CreateGEP(data, _index, "ptr"); + return m_builder.CreateGEP(getData(), _index, "ptr"); } void Memory::require(llvm::Value* _offset, llvm::Value* _size) diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index 85b0cb833..c99f1583f 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); - llvm::GlobalVariable* m_data; - llvm::GlobalVariable* m_size; - llvm::Function* m_resize; llvm::Function* m_require; llvm::Function* m_loadWord; diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 25da2475a..e11dac319 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -49,6 +49,8 @@ private: RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. + byte* m_memoryData = nullptr; + i256 m_memorySize = {}; jmp_buf_ref m_prevJmpBuf; std::jmp_buf m_jmpBuf; StackImpl m_stack; diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index b324da641..e07adbe65 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -40,7 +40,9 @@ llvm::StructType* RuntimeManager::getRuntimeType() { Type::RuntimeDataPtr, // data Type::EnvPtr, // Env* - Type::BytePtr // jmpbuf + Type::BytePtr, // jmpbuf + Type::BytePtr, // memory data + Type::Word, // memory size }; type = llvm::StructType::create(elems, "Runtime"); } From 9d9e73ac915ba2a232f4310e62d9565f5e375e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Dec 2014 19:02:36 +0100 Subject: [PATCH 377/466] Using one ExecutionEngine to cache compiled contracts --- libevmjit/Cache.h | 2 +- libevmjit/ExecutionEngine.cpp | 79 +++++++++++++++++++++++++---------- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index d36b9fc0b..377c1f6a2 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -17,7 +17,7 @@ namespace jit class ExecBundle { public: - std::unique_ptr engine; + llvm::ExecutionEngine* engine = nullptr; std::string mainFuncName; ExecBundle() = default; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index fc1b4ea3a..429ad0a90 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -48,34 +48,68 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) { - llvm::sys::PrintStackTraceOnErrorSignal(); - static const auto program = "EVM JIT"; - llvm::PrettyStackTraceProgram X(1, &program); + // TODO: Use it in evmcc + //llvm::sys::PrintStackTraceOnErrorSignal(); + //static const auto program = "EVM JIT"; + //llvm::PrettyStackTraceProgram X(1, &program); - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); + static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? - llvm::EngineBuilder builder(_module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::None); + typedef ReturnCode(*EntryFuncPtr)(Runtime*); + EntryFuncPtr entryFuncPtr{}; - 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()); ExecBundle exec; exec.mainFuncName = _module->getModuleIdentifier(); - exec.engine.reset(builder.create()); - if (!exec.engine) - return ReturnCode::LLVMConfigError; - _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - exec.engine->setObjectCache(Cache::getObjectCache()); + if (!ee) + { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + llvm::EngineBuilder builder(_module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + std::unique_ptr memoryManager(new llvm::SectionMemoryManager); + builder.setMCJITMemoryManager(memoryManager.get()); + 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()); + + ee.reset(builder.create()); + if (!ee) + return ReturnCode::LLVMConfigError; + + _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + memoryManager.release(); // and memory manager + + //ee->setObjectCache(Cache::getObjectCache()); + } + else + { + if (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(_module->getModuleIdentifier())) + { + entryFuncPtr = nullptr; + } + else + { + ee->addModule(_module.get()); + //std::cerr << _module->getModuleIdentifier() << "\n"; + _module.release(); + } + } + + assert(ee); + + //ExecBundle exec; + //exec.engine.reset(builder.create()); + //if (!exec.engine) + // return ReturnCode::LLVMConfigError; + + exec.engine = ee.get(); // TODO: Finalization not needed when llvm::ExecutionEngine::getFunctionAddress used //auto finalizationStartTime = std::chrono::high_resolution_clock::now(); @@ -113,13 +147,16 @@ ReturnCode runEntryFunc(ExecBundle const& _exec, Runtime* _runtime) typedef ReturnCode(*EntryFuncPtr)(Runtime*); auto entryFuncPtr = (EntryFuncPtr)_exec.engine->getFunctionAddress(_exec.mainFuncName); + //std::cerr << _exec.mainFuncName << " F: " << entryFuncPtr << "\n"; ReturnCode returnCode{}; + //std::cerr << _exec.mainFuncName << " +S: " << &returnCode << "\n"; auto sj = setjmp(_runtime->getJmpBuf()); if (sj == 0) returnCode = entryFuncPtr(_runtime); else returnCode = static_cast(sj); + //std::cerr << _exec.mainFuncName << " -S: " << &returnCode << "\n"; return returnCode; } } From fe90c6f107f5ac2b6a84f2b395273520d353d5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 30 Dec 2014 19:11:09 +0100 Subject: [PATCH 378/466] Clean up ExecutionEngine --- libevmjit/ExecutionEngine.cpp | 66 +++++++++++++++-------------------- libevmjit/ExecutionEngine.h | 3 -- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 429ad0a90..f8fe9b23d 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -46,6 +46,30 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en return run(std::move(module), _data, _env, _code); } +namespace +{ +ReturnCode runEntryFunc(ExecBundle const& _exec, Runtime* _runtime) +{ + // That function uses long jumps to handle "execeptions". + // Do not create any non-POD objects here + + typedef ReturnCode(*EntryFuncPtr)(Runtime*); + auto entryFuncPtr = (EntryFuncPtr)_exec.engine->getFunctionAddress(_exec.mainFuncName); + + //std::cerr << _exec.mainFuncName << " F: " << entryFuncPtr << "\n"; + ReturnCode returnCode{}; + //std::cerr << _exec.mainFuncName << " +S: " << &returnCode << "\n"; + auto sj = setjmp(_runtime->getJmpBuf()); + if (sj == 0) + returnCode = entryFuncPtr(_runtime); + else + returnCode = static_cast(sj); + + //std::cerr << _exec.mainFuncName << " -S: " << &returnCode << "\n"; + return returnCode; +} +} + ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) { // TODO: Use it in evmcc @@ -121,7 +145,10 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa std::string key{reinterpret_cast(_code.data()), _code.size()}; //auto& cachedExec = Cache::registerExec(key, std::move(exec)); - auto returnCode = run(exec, _data, _env); + Runtime runtime(_data, _env); + auto returnCode = runEntryFunc(exec, &runtime); + if (returnCode == ReturnCode::Return) + this->returnData = runtime.getReturnData(); auto executionEndTime = std::chrono::high_resolution_clock::now(); clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms "; @@ -132,43 +159,6 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa return returnCode; } -namespace -{ -ReturnCode runEntryFunc(ExecBundle const& _exec, Runtime* _runtime) -{ - // That function uses long jumps to handle "execeptions". - // Do not create any non-POD objects here - - // TODO: - // Getting pointer to function seems to be cachable, - // but it looks like getPointerToFunction() method does something special - // to allow function to be executed. - // That might be related to memory manager. Can we share one? - typedef ReturnCode(*EntryFuncPtr)(Runtime*); - auto entryFuncPtr = (EntryFuncPtr)_exec.engine->getFunctionAddress(_exec.mainFuncName); - - //std::cerr << _exec.mainFuncName << " F: " << entryFuncPtr << "\n"; - ReturnCode returnCode{}; - //std::cerr << _exec.mainFuncName << " +S: " << &returnCode << "\n"; - auto sj = setjmp(_runtime->getJmpBuf()); - if (sj == 0) - returnCode = entryFuncPtr(_runtime); - else - returnCode = static_cast(sj); - - //std::cerr << _exec.mainFuncName << " -S: " << &returnCode << "\n"; - return returnCode; -} -} - -ReturnCode ExecutionEngine::run(ExecBundle const& _exec, RuntimeData* _data, Env* _env) -{ - Runtime runtime(_data, _env); - auto returnCode = runEntryFunc(_exec, &runtime); - if (returnCode == ReturnCode::Return) - this->returnData = runtime.getReturnData(); - return returnCode; -} } } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 499aa894a..8ca416c48 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -26,9 +26,6 @@ public: ReturnCode run(std::unique_ptr module, RuntimeData* _data, Env* _env, bytes const& _code); bytes returnData; - -private: - ReturnCode run(ExecBundle const& _exec, RuntimeData* _data, Env* _env); }; } From ece7fe77820661e27e5e828964fbb442c0a58667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 31 Dec 2014 13:14:50 +0100 Subject: [PATCH 379/466] Clean up ExecutionEngine --- libevmjit/ExecutionEngine.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index f8fe9b23d..c2c7a8628 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -48,26 +48,24 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en namespace { -ReturnCode runEntryFunc(ExecBundle const& _exec, Runtime* _runtime) + +typedef ReturnCode(*EntryFuncPtr)(Runtime*); + +ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) { // That function uses long jumps to handle "execeptions". // Do not create any non-POD objects here - typedef ReturnCode(*EntryFuncPtr)(Runtime*); - auto entryFuncPtr = (EntryFuncPtr)_exec.engine->getFunctionAddress(_exec.mainFuncName); - - //std::cerr << _exec.mainFuncName << " F: " << entryFuncPtr << "\n"; ReturnCode returnCode{}; - //std::cerr << _exec.mainFuncName << " +S: " << &returnCode << "\n"; auto sj = setjmp(_runtime->getJmpBuf()); if (sj == 0) - returnCode = entryFuncPtr(_runtime); + returnCode = _mainFunc(_runtime); else returnCode = static_cast(sj); - //std::cerr << _exec.mainFuncName << " -S: " << &returnCode << "\n"; return returnCode; } + } ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) @@ -83,8 +81,7 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa EntryFuncPtr entryFuncPtr{}; - ExecBundle exec; - exec.mainFuncName = _module->getModuleIdentifier(); + auto&& mainFuncName = _module->getModuleIdentifier(); if (!ee) { @@ -133,8 +130,6 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa //if (!exec.engine) // return ReturnCode::LLVMConfigError; - exec.engine = ee.get(); - // TODO: Finalization not needed when llvm::ExecutionEngine::getFunctionAddress used //auto finalizationStartTime = std::chrono::high_resolution_clock::now(); //exec.engine->finalizeObject(); @@ -146,7 +141,8 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa std::string key{reinterpret_cast(_code.data()), _code.size()}; //auto& cachedExec = Cache::registerExec(key, std::move(exec)); Runtime runtime(_data, _env); - auto returnCode = runEntryFunc(exec, &runtime); + auto mainFunc = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + auto returnCode = runEntryFunc(mainFunc, &runtime); if (returnCode == ReturnCode::Return) this->returnData = runtime.getReturnData(); From de024259c23a4dd83427745c5bfa91aaf0ea9e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 31 Dec 2014 13:54:43 +0100 Subject: [PATCH 380/466] Clean up ExecutionEngine --- libevmjit/ExecutionEngine.cpp | 42 +++++++++-------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index c2c7a8628..354c6e151 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -35,12 +35,6 @@ namespace jit ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) { - std::string key{reinterpret_cast(_code.data()), _code.size()}; - /*if (auto cachedExec = Cache::findExec(key)) - { - return run(*cachedExec, _data, _env); - }*/ - auto module = Compiler({}).compile(_code); //module->dump(); return run(std::move(module), _data, _env, _code); @@ -77,10 +71,12 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? - typedef ReturnCode(*EntryFuncPtr)(Runtime*); EntryFuncPtr entryFuncPtr{}; + + Runtime runtime(_data, _env); + auto&& mainFuncName = _module->getModuleIdentifier(); if (!ee) @@ -108,47 +104,29 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa memoryManager.release(); // and memory manager //ee->setObjectCache(Cache::getObjectCache()); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else { - if (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(_module->getModuleIdentifier())) - { - entryFuncPtr = nullptr; - } - else + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + if (!entryFuncPtr) { ee->addModule(_module.get()); - //std::cerr << _module->getModuleIdentifier() << "\n"; _module.release(); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } } + assert(entryFuncPtr); - assert(ee); - - //ExecBundle exec; - //exec.engine.reset(builder.create()); - //if (!exec.engine) - // return ReturnCode::LLVMConfigError; - - // TODO: Finalization not needed when llvm::ExecutionEngine::getFunctionAddress used - //auto finalizationStartTime = std::chrono::high_resolution_clock::now(); - //exec.engine->finalizeObject(); - //auto finalizationEndTime = std::chrono::high_resolution_clock::now(); - //clog(JIT) << " + " << std::chrono::duration_cast(finalizationEndTime - finalizationStartTime).count(); auto executionStartTime = std::chrono::high_resolution_clock::now(); - - std::string key{reinterpret_cast(_code.data()), _code.size()}; - //auto& cachedExec = Cache::registerExec(key, std::move(exec)); - Runtime runtime(_data, _env); - auto mainFunc = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - auto returnCode = runEntryFunc(mainFunc, &runtime); + //auto mainFunc = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + auto returnCode = runEntryFunc(entryFuncPtr, &runtime); if (returnCode == ReturnCode::Return) this->returnData = runtime.getReturnData(); auto executionEndTime = std::chrono::high_resolution_clock::now(); clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms "; - //clog(JIT) << "Max stack size: " << Stack::maxStackSize; clog(JIT) << "\n"; From 28a062318cd1bd66d549397fda993ff186010eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 31 Dec 2014 14:29:49 +0100 Subject: [PATCH 381/466] Clean up ExecutionEngine --- libevmjit/Cache.cpp | 32 -------------------------------- libevmjit/Cache.h | 23 ----------------------- libevmjit/ExecutionEngine.cpp | 24 +++--------------------- 3 files changed, 3 insertions(+), 76 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 1265273f6..bbd2c95b8 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -10,42 +10,10 @@ namespace eth { namespace jit { -namespace -{ - using CacheMap = std::unordered_map; - - CacheMap& getCacheMap() - { - static CacheMap map; - return map; - } -} //#define LOG(...) std::cerr << "CACHE " #define LOG(...) std::ostream(nullptr) -ExecBundle& Cache::registerExec(Cache::Key _key, ExecBundle&& _exec) -{ - auto& map = getCacheMap(); - auto r = map.insert(std::make_pair(_key, std::move(_exec))); - assert(r.second && "Updating cached objects not supported"); - LOG() << "add\n"; - return r.first->second; // return exec, now owned by cache -} - -ExecBundle* Cache::findExec(Cache::Key _key) -{ - auto& map = getCacheMap(); - auto it = map.find(_key); - if (it != map.end()) - { - LOG() << "hit\n"; - return &it->second; - } - LOG() << "miss\n"; - return nullptr; -} - ObjectCache* Cache::getObjectCache() { static ObjectCache objectCache; diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 377c1f6a2..80fe47ade 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -13,24 +13,6 @@ namespace eth namespace jit { -/// A bundle of objects and information needed for a contract execution -class ExecBundle -{ -public: - llvm::ExecutionEngine* engine = nullptr; - std::string mainFuncName; - - ExecBundle() = default; - ExecBundle(ExecBundle&& _other): - engine(std::move(_other.engine)), - mainFuncName(std::move(_other.mainFuncName)) - {} - - ExecBundle(ExecBundle const&) = delete; - void operator=(ExecBundle) = delete; -}; - - class ObjectCache : public llvm::ObjectCache { public: @@ -51,11 +33,6 @@ private: class Cache { public: - using Key = std::string; - - static ExecBundle& registerExec(Key _key, ExecBundle&& _exec); - static ExecBundle* findExec(Key _key); - static ObjectCache* getObjectCache(); }; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 354c6e151..2174df4eb 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -2,10 +2,6 @@ #include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" - -#include #include #include #include @@ -13,12 +9,8 @@ #include #include #include -#include -#include #include -#pragma GCC diagnostic pop - #include "Runtime.h" #include "Memory.h" #include "Stack.h" @@ -42,7 +34,6 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en namespace { - typedef ReturnCode(*EntryFuncPtr)(Runtime*); ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) @@ -59,7 +50,6 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } - } ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) @@ -72,12 +62,8 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? EntryFuncPtr entryFuncPtr{}; - - - - Runtime runtime(_data, _env); - auto&& mainFuncName = _module->getModuleIdentifier(); + Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls if (!ee) { @@ -118,22 +104,18 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa } assert(entryFuncPtr); - auto executionStartTime = std::chrono::high_resolution_clock::now(); - //auto mainFunc = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + auto returnCode = runEntryFunc(entryFuncPtr, &runtime); if (returnCode == ReturnCode::Return) this->returnData = runtime.getReturnData(); auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms "; - - clog(JIT) << "\n"; + clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; return returnCode; } - } } } From 6a22491af2c684abad353c6599e46c9356c536cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 31 Dec 2014 14:52:15 +0100 Subject: [PATCH 382/466] Clean up ExecutionEngine --- evmcc/evmcc.cpp | 5 +++++ libevmjit/ExecutionEngine.cpp | 9 --------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 5ee11abb1..9ac3639e2 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include @@ -85,6 +87,9 @@ void parseProgramOptions(int _argc, char** _argv, boost::program_options::variab int main(int argc, char** argv) { + llvm::sys::PrintStackTraceOnErrorSignal(); + llvm::PrettyStackTraceProgram X(argc, argv); + boost::program_options::variables_map options; parseProgramOptions(argc, argv, options); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 2174df4eb..5c0125f35 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -6,15 +6,11 @@ #include #include #include -#include #include #include #include #include "Runtime.h" -#include "Memory.h" -#include "Stack.h" -#include "Type.h" #include "Compiler.h" #include "Cache.h" @@ -54,11 +50,6 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) { - // TODO: Use it in evmcc - //llvm::sys::PrintStackTraceOnErrorSignal(); - //static const auto program = "EVM JIT"; - //llvm::PrettyStackTraceProgram X(1, &program); - static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? EntryFuncPtr entryFuncPtr{}; From 2b31cba5d2b9b9b3fa2f349599cf1c5661072048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 31 Dec 2014 14:56:43 +0100 Subject: [PATCH 383/466] Memory manager cleanup --- libevmjit/Memory.cpp | 8 +------- libevmjit/Memory.h | 2 -- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 95e38d4a8..c60a5e554 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -27,14 +27,8 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed m_gasMeter(_gasMeter) { - 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); - 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); + m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); 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)); diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index c99f1583f..ed9c51805 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -38,8 +38,6 @@ private: llvm::Function* m_loadWord; llvm::Function* m_storeWord; llvm::Function* m_storeByte; - - llvm::Function* m_memDump; }; } From 3df5a125fa0baa579528abce80402118cad803fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 31 Dec 2014 16:04:38 +0100 Subject: [PATCH 384/466] Do not compile LLVM module if machine code available in memory --- evmcc/evmcc.cpp | 5 ++- libevmjit/Compiler.cpp | 11 ++--- libevmjit/Compiler.h | 2 +- libevmjit/ExecutionEngine.cpp | 80 ++++++++++++++++++----------------- libevmjit/ExecutionEngine.h | 7 --- 5 files changed, 49 insertions(+), 56 deletions(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 9ac3639e2..3c43ab78b 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -132,7 +132,7 @@ int main(int argc, char** argv) compilerOptions.rewriteSwitchToBranches = optimize || options.count("rewrite-switch") > 0; auto compiler = eth::jit::Compiler(compilerOptions); - auto module = compiler.compile(bytecode); + auto module = compiler.compile(bytecode, "main"); auto compilationEndTime = std::chrono::high_resolution_clock::now(); @@ -201,7 +201,8 @@ int main(int argc, char** argv) data.code = bytecode.data(); // BROKEN: env_* functions must be implemented & RuntimeData struct created - auto result = engine.run(std::move(module), &data, nullptr, bytecode); + // TODO: Do not compile module again + auto result = engine.run(bytecode, &data, nullptr); return static_cast(result); } } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 8d4556d87..73c96b60b 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -152,19 +152,14 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); } -std::unique_ptr Compiler::compile(bytes const& _bytecode) +std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) { - // TODO: Better hash of code needed, probably SHA3 - std::string code{reinterpret_cast(_bytecode.data()), _bytecode.size()}; - auto hash = std::hash{}(code); - auto strHash = std::to_string(hash); - auto compilationStartTime = std::chrono::high_resolution_clock::now(); - auto module = std::unique_ptr(new llvm::Module(strHash, m_builder.getContext())); + auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); // Create main function auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, Type::RuntimePtr, false); - m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, strHash, module.get()); + m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); // Create the basic blocks. diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index e021bfdef..8e3bf357c 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -39,7 +39,7 @@ public: Compiler(Options const& _options); - std::unique_ptr compile(bytes const& _bytecode); + std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); private: diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 5c0125f35..23a64da65 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -21,13 +21,6 @@ namespace eth namespace jit { -ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) -{ - auto module = Compiler({}).compile(_code); - //module->dump(); - return run(std::move(module), _data, _env, _code); -} - namespace { typedef ReturnCode(*EntryFuncPtr)(Runtime*); @@ -48,50 +41,61 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) } } -ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeData* _data, Env* _env, bytes const& _code) +ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? + + // TODO: Better hash of code needed, probably SHA3 + std::string code{reinterpret_cast(_code.data()), _code.size()}; + auto hash = std::hash{}(code); + auto mainFuncName = std::to_string(hash); + EntryFuncPtr entryFuncPtr{}; - auto&& mainFuncName = _module->getModuleIdentifier(); Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls - if (!ee) + if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(_module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - 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()); - - ee.reset(builder.create()); - if (!ee) - return ReturnCode::LLVMConfigError; - - _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - - //ee->setObjectCache(Cache::getObjectCache()); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else { - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - if (!entryFuncPtr) + auto module = Compiler({}).compile(_code, mainFuncName); + if (!ee) { - ee->addModule(_module.get()); - _module.release(); + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + llvm::EngineBuilder builder(module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + std::unique_ptr memoryManager(new llvm::SectionMemoryManager); + builder.setMCJITMemoryManager(memoryManager.get()); + 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()); + + ee.reset(builder.create()); + if (!ee) + return ReturnCode::LLVMConfigError; + + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + memoryManager.release(); // and memory manager + + //ee->setObjectCache(Cache::getObjectCache()); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } + else + { + if (!entryFuncPtr) + { + ee->addModule(module.get()); + module.release(); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + } + } } assert(entryFuncPtr); diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 8ca416c48..559701bba 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,10 +1,5 @@ #pragma once -namespace llvm -{ - class Module; -} - #include "RuntimeData.h" namespace dev @@ -13,7 +8,6 @@ namespace eth { namespace jit { -class ExecBundle; class ExecutionEngine { @@ -23,7 +17,6 @@ public: void operator=(ExecutionEngine) = delete; ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); - ReturnCode run(std::unique_ptr module, RuntimeData* _data, Env* _env, bytes const& _code); bytes returnData; }; From 5be8c59ff14510d99149099a785e40c29885646c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 31 Dec 2014 17:53:46 +0100 Subject: [PATCH 385/466] Byte swap for constants --- libevmjit/Endianness.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index c2cc1ef90..be62ac058 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -22,6 +22,9 @@ llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _wo if (tester{1}.isLE) { + if (auto constant = llvm::dyn_cast(_word)) + return _builder.getInt(constant->getValue().byteSwap()); + // OPT: Cache func declaration? auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); return _builder.CreateCall(bswapFunc, _word); From ec30ce47af9bd3be28ec304681c8bb2174c9a154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 2 Jan 2015 12:24:38 +0100 Subject: [PATCH 386/466] Object cache --- libevmjit/Cache.cpp | 31 +++++++++++++++++++++++++------ libevmjit/ExecutionEngine.cpp | 27 +++++++++++++++++++-------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index bbd2c95b8..a887d91e9 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include namespace dev { @@ -23,16 +26,32 @@ ObjectCache* Cache::getObjectCache() void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { - auto&& key = _module->getModuleIdentifier(); - std::unique_ptr obj(llvm::MemoryBuffer::getMemBufferCopy(_object->getBuffer())); - m_map.insert(std::make_pair(key, std::move(obj))); + auto&& id = _module->getModuleIdentifier(); + llvm::SmallString<256> cachePath; + llvm::sys::path::system_temp_directory(false, cachePath); + llvm::sys::path::append(cachePath, "evm_objs"); + + if (llvm::sys::fs::create_directory(cachePath.str())) + return; // TODO: Add log + + llvm::sys::path::append(cachePath, id); + + std::string error; + llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); + cacheFile << _object->getBuffer(); } llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) { - auto it = m_map.find(_module->getModuleIdentifier()); - if (it != m_map.end()) - return llvm::MemoryBuffer::getMemBufferCopy(it->second->getBuffer()); + auto&& id = _module->getModuleIdentifier(); + llvm::SmallString<256> cachePath; + llvm::sys::path::system_temp_directory(false, cachePath); + llvm::sys::path::append(cachePath, "evm_objs", id); + + if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) + return llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) + std::cerr << r.getError().message(); // TODO: Add log return nullptr; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 23a64da65..862586575 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -14,6 +14,8 @@ #include "Compiler.h" #include "Cache.h" +extern "C" void env_sha3(dev::eth::jit::byte const* _begin, uint64_t _size, std::array* o_hash); + namespace dev { namespace eth @@ -39,18 +41,26 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } + +std::string codeHash(bytes const& _code) +{ + std::array binHash; + env_sha3(_code.data(), _code.size(), &binHash); + + std::ostringstream os; + for (auto i: binHash) + os << std::hex << std::setfill('0') << std::setw(2) << (int)(std::make_unsigned::type)i; + + return os.str(); +} + } ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? - - // TODO: Better hash of code needed, probably SHA3 - std::string code{reinterpret_cast(_code.data()), _code.size()}; - auto hash = std::hash{}(code); - auto mainFuncName = std::to_string(hash); - + auto mainFuncName = codeHash(_code); EntryFuncPtr entryFuncPtr{}; Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls @@ -60,6 +70,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en else { auto module = Compiler({}).compile(_code, mainFuncName); + //module->dump(); if (!ee) { llvm::InitializeNativeTarget(); @@ -70,7 +81,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en builder.setUseMCJIT(true); std::unique_ptr memoryManager(new llvm::SectionMemoryManager); builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::None); + builder.setOptLevel(llvm::CodeGenOpt::Default); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) @@ -84,7 +95,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module memoryManager.release(); // and memory manager - //ee->setObjectCache(Cache::getObjectCache()); + ee->setObjectCache(Cache::getObjectCache()); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else From ae6e70913aebc9a4ab645b8ae97cf2c1f715d9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 2 Jan 2015 14:02:30 +0100 Subject: [PATCH 387/466] Disalbe bswap constant folding --- libevmjit/Endianness.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index be62ac058..db7edfdc9 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -22,8 +22,9 @@ llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _wo if (tester{1}.isLE) { - if (auto constant = llvm::dyn_cast(_word)) - return _builder.getInt(constant->getValue().byteSwap()); + // FIXME: Disabled because of problems with BYTE + //if (auto constant = llvm::dyn_cast(_word)) + // return _builder.getInt(constant->getValue().byteSwap()); // OPT: Cache func declaration? auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); From e12fa127f4f6bf3293c65761cf5825e8d12b32eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 2 Jan 2015 16:05:59 +0100 Subject: [PATCH 388/466] Suicide rework --- libevmjit-cpp/Env.cpp | 5 ----- libevmjit-cpp/JitVM.cpp | 4 ++++ libevmjit/Compiler.cpp | 13 +++++++------ libevmjit/Ext.cpp | 8 -------- libevmjit/Ext.h | 2 -- libevmjit/RuntimeData.h | 4 +++- libevmjit/RuntimeManager.cpp | 5 +++++ libevmjit/RuntimeManager.h | 1 + 8 files changed, 20 insertions(+), 22 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 50945583b..c0d8db75a 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -42,11 +42,6 @@ extern "C" *o_value = eth2llvm(u); } - EXPORT void ext_suicide(ExtVMFace* _env, h256 const* _address) - { - _env->suicide(right160(*_address)); - } - EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { if (_env->depth == 1024) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 46dabe275..815aa6332 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -34,6 +34,10 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) auto exitCode = m_engine.run(_ext.code, &m_data, env); switch (exitCode) { + case ReturnCode::Suicide: + _ext.suicide(right160(m_data.get(RuntimeData::SuicideDestAddress))); + break; + case ReturnCode::BadJumpDestination: BOOST_THROW_EXCEPTION(BadJumpDestination()); case ReturnCode::OutOfGas: diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 73c96b60b..48dc50d60 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -798,14 +798,15 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode } case Instruction::SUICIDE: - case Instruction::STOP: { - if (inst == Instruction::SUICIDE) - { - auto address = stack.pop(); - _ext.suicide(address); - } + _runtimeManager.registerSuicide(stack.pop()); + m_builder.CreateRet(Constant::get(ReturnCode::Suicide)); + break; + } + + case Instruction::STOP: + { m_builder.CreateRet(Constant::get(ReturnCode::Stop)); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 2b9802bb0..98063b538 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -44,7 +44,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): m_sload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sload", module); m_sstore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sstore", 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); llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); @@ -96,13 +95,6 @@ llvm::Value* Ext::balance(llvm::Value* _address) 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().getEnvPtr(), m_args[0]); -} - llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { m_builder.CreateStore(_gas, m_args[0]); diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 0227d806d..9c79b93d5 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -27,7 +27,6 @@ public: void sstore(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*& _gas, 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); @@ -54,7 +53,6 @@ private: llvm::Function* m_sstore; llvm::Function* m_calldataload; llvm::Function* m_balance; - llvm::Function* m_suicide; llvm::Function* m_create; llvm::Function* m_call; llvm::Function* m_sha3; diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index b17f52620..89987bdeb 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -32,7 +32,8 @@ struct RuntimeData _size, ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference - ReturnDataSize = CallDataSize + ReturnDataSize = CallDataSize, + SuicideDestAddress = Address, ///< Suicide balance destination address }; i256 elems[_size] = {}; @@ -40,6 +41,7 @@ struct RuntimeData byte const* code = nullptr; void set(Index _index, u256 _value) { elems[_index] = eth2llvm(_value); } + u256 get(Index _index) { return llvm2eth(elems[_index]); } }; /// VM Environment (ExtVM) opaque type diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index e07adbe65..14280f80f 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -132,6 +132,11 @@ void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size set(RuntimeData::ReturnDataSize, _size); } +void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) +{ + set(RuntimeData::SuicideDestAddress, _balanceAddress); +} + void RuntimeManager::raiseException(ReturnCode _returnCode) { m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index 1cff606e3..ce60424ac 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -29,6 +29,7 @@ public: void setGas(llvm::Value* _gas); void registerReturnData(llvm::Value* _index, llvm::Value* _size); + void registerSuicide(llvm::Value* _balanceAddress); void raiseException(ReturnCode _returnCode); From 533531bd07cb2d95f3fa017231484e91196d87a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 2 Jan 2015 17:13:09 +0100 Subject: [PATCH 389/466] Create helper/external functions on demand (env_balance for now) --- libevmjit-cpp/Env.cpp | 2 +- libevmjit/Ext.cpp | 13 +++++++++++-- libevmjit/Ext.h | 4 +++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index c0d8db75a..1dcd38162 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -36,7 +36,7 @@ extern "C" _env->setStore(index, value); // Interface uses native endianness } - EXPORT void ext_balance(ExtVMFace* _env, h256* _address, i256* o_value) + EXPORT void env_balance(ExtVMFace* _env, h256* _address, i256* o_value) { auto u = _env->balance(right160(*_address)); *o_value = eth2llvm(u); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 98063b538..38adffd3f 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -43,7 +43,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): m_sload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sload", module); m_sstore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sstore", module); - m_balance = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_balance", module); llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); @@ -65,6 +64,16 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, callDataLoadArgsTypes, false), Linkage::ExternalLinkage, "ext_calldataload", module); } +llvm::Function* Ext::getBalanceFunc() +{ + if (!m_balance) + { + llvm::Type* argsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr}; + m_balance = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), llvm::Function::ExternalLinkage, "env_balance", getModule()); + } + return m_balance; +} + llvm::Value* Ext::sload(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); @@ -91,7 +100,7 @@ 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().getEnvPtr(), m_args[0], m_args[1]); + createCall(getBalanceFunc(), getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); return m_builder.CreateLoad(m_args[1]); } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 9c79b93d5..be71dc1ff 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -52,12 +52,14 @@ private: llvm::Function* m_sload; llvm::Function* m_sstore; llvm::Function* m_calldataload; - llvm::Function* m_balance; + llvm::Function* m_balance = nullptr; llvm::Function* m_create; llvm::Function* m_call; llvm::Function* m_sha3; llvm::Function* m_getExtCode; llvm::Function* m_log; + + llvm::Function* getBalanceFunc(); }; From 9bf0b75159587b016f7d69a2fb7523d0421aa076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 7 Jan 2015 12:12:16 +0100 Subject: [PATCH 390/466] Create helper/external functions on demand --- libevmjit/Ext.cpp | 48 ++++++++++++++++++++++++++++++++++------------- libevmjit/Ext.h | 24 +++++++++++++++++++++--- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 38adffd3f..ea6bf531a 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -39,11 +39,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): using Linkage = llvm::GlobalValue::LinkageTypes; - llvm::Type* argsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; - - m_sload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sload", module); - m_sstore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sstore", module); - llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); @@ -64,20 +59,47 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, callDataLoadArgsTypes, false), Linkage::ExternalLinkage, "ext_calldataload", module); } -llvm::Function* Ext::getBalanceFunc() + +using FuncDesc = std::tuple; + +llvm::FunctionType* getFunctionType(llvm::Type* _returnType, std::initializer_list const& _argsTypes) +{ + return llvm::FunctionType::get(_returnType, llvm::ArrayRef{_argsTypes.begin(), _argsTypes.size()}, false); +} + +std::array::value> const& getEnvFuncDescs() +{ + static std::array::value> descs{{ + FuncDesc{"env_sload", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + }}; + + return descs; +} + +llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) +{ + auto&& desc = getEnvFuncDescs()[static_cast(_id)]; + return llvm::Function::Create(std::get<1>(desc), llvm::Function::ExternalLinkage, std::get<0>(desc), _module); +} + +template +llvm::CallInst* Ext::createCall(EnvFunc _funcId, _Args*... _args) { - if (!m_balance) + auto& func = m_funcs[static_cast(_funcId)]; + if (!func) { - llvm::Type* argsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr}; - m_balance = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), llvm::Function::ExternalLinkage, "env_balance", getModule()); + func = createFunc(_funcId, getModule()); } - return m_balance; + llvm::Value* args[] = {_args...}; + return getBuilder().CreateCall(func, args); } llvm::Value* Ext::sload(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateCall3(m_sload, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness + createCall(EnvFunc::sload, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness return m_builder.CreateLoad(m_args[1]); } @@ -85,7 +107,7 @@ void Ext::sstore(llvm::Value* _index, llvm::Value* _value) { m_builder.CreateStore(_index, m_args[0]); m_builder.CreateStore(_value, m_args[1]); - m_builder.CreateCall3(m_sstore, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness + createCall(EnvFunc::sstore, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness } llvm::Value* Ext::calldataload(llvm::Value* _index) @@ -100,7 +122,7 @@ llvm::Value* Ext::balance(llvm::Value* _address) { auto address = Endianness::toBE(m_builder, _address); m_builder.CreateStore(address, m_args[0]); - createCall(getBalanceFunc(), getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); + createCall(EnvFunc::balance, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); return m_builder.CreateLoad(m_args[1]); } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index be71dc1ff..964198e5d 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -18,6 +18,21 @@ struct MemoryRef llvm::Value* size; }; +template +struct sizeOf +{ + static const size_t value = static_cast(_EnumT::_size); +}; + +enum class EnvFunc +{ + sload, + sstore, + balance, + + _size +}; + class Ext : public RuntimeHelper { public: @@ -49,8 +64,6 @@ private: llvm::Value* m_arg8; llvm::Value* m_size; llvm::Value* m_data = nullptr; - llvm::Function* m_sload; - llvm::Function* m_sstore; llvm::Function* m_calldataload; llvm::Function* m_balance = nullptr; llvm::Function* m_create; @@ -59,7 +72,12 @@ private: llvm::Function* m_getExtCode; llvm::Function* m_log; - llvm::Function* getBalanceFunc(); + std::array::value> m_funcs = {}; + + template + llvm::CallInst* createCall(EnvFunc _funcId, _Args*... _args); + + using CompilerHelper::createCall; }; From b77a975a33180994553d65daa4ec6ddf58ef1db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 7 Jan 2015 12:58:09 +0100 Subject: [PATCH 391/466] Create helper/external functions on demand --- libevmjit/Ext.cpp | 56 +++++++++++++++-------------------------------- libevmjit/Ext.h | 18 ++++++--------- 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index ea6bf531a..f8125f816 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -24,8 +24,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): RuntimeHelper(_runtimeManager), m_memoryMan(_memoryMan) { - auto module = getModule(); - m_args[0] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.index"); m_args[1] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.value"); m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg2"); @@ -36,27 +34,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): m_arg7 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg7"); m_arg8 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg8"); m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); - - using Linkage = llvm::GlobalValue::LinkageTypes; - - llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; - m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); - - llvm::Type* createArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr}; - m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, createArgsTypes, false), Linkage::ExternalLinkage, "env_create", module); - - llvm::Type* callArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr}; - m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, callArgsTypes, false), Linkage::ExternalLinkage, "env_call", module); - - llvm::Type* logArgsTypes[] = {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; - m_log = llvm::Function::Create(llvm::FunctionType::get(Type::Void, logArgsTypes, false), Linkage::ExternalLinkage, "env_log", module); - - llvm::Type* getExtCodeArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()}; - m_getExtCode = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, getExtCodeArgsTypes, false), Linkage::ExternalLinkage, "env_getExtCode", module); - - // Helper function, not client Env interface - llvm::Type* callDataLoadArgsTypes[] = {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr}; - m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, callDataLoadArgsTypes, false), Linkage::ExternalLinkage, "ext_calldataload", module); } @@ -72,7 +49,13 @@ std::array::value> const& getEnvFuncDescs() static std::array::value> descs{{ FuncDesc{"env_sload", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_getExtCode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, + FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})}, }}; return descs; @@ -84,22 +67,19 @@ llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) return llvm::Function::Create(std::get<1>(desc), llvm::Function::ExternalLinkage, std::get<0>(desc), _module); } -template -llvm::CallInst* Ext::createCall(EnvFunc _funcId, _Args*... _args) +llvm::CallInst* Ext::createCall(EnvFunc _funcId, std::initializer_list const& _args) { auto& func = m_funcs[static_cast(_funcId)]; if (!func) - { func = createFunc(_funcId, getModule()); - } - llvm::Value* args[] = {_args...}; - return getBuilder().CreateCall(func, args); + + return getBuilder().CreateCall(func, {_args.begin(), _args.size()}); } llvm::Value* Ext::sload(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - createCall(EnvFunc::sload, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness + createCall(EnvFunc::sload, {getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]}); // Uses native endianness return m_builder.CreateLoad(m_args[1]); } @@ -107,13 +87,13 @@ void Ext::sstore(llvm::Value* _index, llvm::Value* _value) { m_builder.CreateStore(_index, m_args[0]); m_builder.CreateStore(_value, m_args[1]); - createCall(EnvFunc::sstore, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness + createCall(EnvFunc::sstore, {getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]}); // Uses native endianness } llvm::Value* Ext::calldataload(llvm::Value* _index) { m_builder.CreateStore(_index, m_args[0]); - createCall(m_calldataload, getRuntimeManager().getDataPtr(), m_args[0], m_args[1]); + createCall(EnvFunc::calldataload, {getRuntimeManager().getDataPtr(), m_args[0], m_args[1]}); auto ret = m_builder.CreateLoad(m_args[1]); return Endianness::toNative(m_builder, ret); } @@ -122,7 +102,7 @@ llvm::Value* Ext::balance(llvm::Value* _address) { auto address = Endianness::toBE(m_builder, _address); m_builder.CreateStore(address, m_args[0]); - createCall(EnvFunc::balance, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); + createCall(EnvFunc::balance, {getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]}); return m_builder.CreateLoad(m_args[1]); } @@ -132,7 +112,7 @@ llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Valu m_builder.CreateStore(_endowment, m_arg2); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(m_create, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, begin, size, m_args[1]); + createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, begin, size, m_args[1]}); _gas = m_builder.CreateLoad(m_args[0]); // Return gas llvm::Value* address = m_builder.CreateLoad(m_args[1]); address = Endianness::toNative(m_builder, address); @@ -151,7 +131,7 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); m_builder.CreateStore(codeAddress, m_arg8); - auto ret = createCall(m_call, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8); + auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8}); _gas = m_builder.CreateLoad(m_args[0]); // Return gas return m_builder.CreateZExt(ret, Type::Word, "ret"); } @@ -160,7 +140,7 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) { auto begin = m_memoryMan.getBytePtr(_inOff); auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size"); - createCall(m_sha3, begin, size, m_args[1]); + createCall(EnvFunc::sha3, {begin, size, m_args[1]}); llvm::Value* hash = m_builder.CreateLoad(m_args[1]); hash = Endianness::toNative(m_builder, hash); return hash; @@ -170,7 +150,7 @@ MemoryRef Ext::getExtCode(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); m_builder.CreateStore(addr, m_args[0]); - auto code = createCall(m_getExtCode, getRuntimeManager().getEnvPtr(), m_args[0], m_size); + auto code = createCall(EnvFunc::getExtCode, {getRuntimeManager().getEnvPtr(), m_args[0], m_size}); auto codeSize = m_builder.CreateLoad(m_size); auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); return {code, codeSize256}; @@ -192,7 +172,7 @@ void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array } } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 964198e5d..766ac4c7e 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -28,7 +28,13 @@ enum class EnvFunc { sload, sstore, + sha3, balance, + create, + call, + log, + getExtCode, + calldataload, // Helper function, not client Env interface _size }; @@ -64,20 +70,10 @@ private: llvm::Value* m_arg8; llvm::Value* m_size; llvm::Value* m_data = nullptr; - llvm::Function* m_calldataload; - llvm::Function* m_balance = nullptr; - llvm::Function* m_create; - llvm::Function* m_call; - llvm::Function* m_sha3; - llvm::Function* m_getExtCode; - llvm::Function* m_log; std::array::value> m_funcs = {}; - template - llvm::CallInst* createCall(EnvFunc _funcId, _Args*... _args); - - using CompilerHelper::createCall; + llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list const& _args); }; From b6248cc38d0da3cc90ffa1fdddfdc9aa1e503cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 7 Jan 2015 13:17:39 +0100 Subject: [PATCH 392/466] Detemplatify createCall helper --- libevmjit/CompilerHelper.cpp | 5 +++++ libevmjit/CompilerHelper.h | 7 +------ libevmjit/GasMeter.cpp | 4 ++-- libevmjit/Memory.cpp | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index badf9d889..9cccecd79 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -35,6 +35,11 @@ llvm::Function* CompilerHelper::getMainFunction() return nullptr; } +llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) +{ + return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); +} + RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): CompilerHelper(_runtimeManager.getBuilder()), diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index 19315fe4a..62733ca72 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -31,12 +31,7 @@ protected: 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); - } + llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); friend class RuntimeHelper; }; diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index c31942a45..39f4560e5 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -119,7 +119,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 = createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)}); } m_blockCost += getStepCost(_inst); @@ -127,7 +127,7 @@ void GasMeter::count(Instruction _inst) void GasMeter::count(llvm::Value* _cost) { - createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), _cost); + createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); } void GasMeter::countExp(llvm::Value* _exponent) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c60a5e554..9f57c7a4b 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -146,18 +146,18 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet llvm::Value* Memory::loadWord(llvm::Value* _addr) { - return createCall(m_loadWord, getRuntimeManager().getRuntimePtr(), _addr); + return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - createCall(m_storeWord, getRuntimeManager().getRuntimePtr(), _addr, _word); + createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); } void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, getRuntimeManager().getRuntimePtr(), _addr, byte); + createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); } llvm::Value* Memory::getData() @@ -181,7 +181,7 @@ llvm::Value* Memory::getBytePtr(llvm::Value* _index) void Memory::require(llvm::Value* _offset, llvm::Value* _size) { - createCall(m_require, getRuntimeManager().getRuntimePtr(), _offset, _size); + createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, From 4f4fc6349a6e838d9bcf983b6b750fcb14a364b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 7 Jan 2015 15:08:36 +0100 Subject: [PATCH 393/466] Alloc stack elemnent for external function call argument on demand --- libevmjit/Ext.cpp | 41 ++++++++++++++++++++++++++++++----------- libevmjit/Ext.h | 4 ++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index f8125f816..dc8a23815 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -67,27 +67,47 @@ llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) return llvm::Function::Create(std::get<1>(desc), llvm::Function::ExternalLinkage, std::get<0>(desc), _module); } +llvm::Value* Ext::getArgAlloca() +{ + auto& a = m_argAllocas[m_argCounter++]; + if (!a) + { + // FIXME: Improve order and names + InsertPointGuard g{getBuilder()}; + getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); + a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); + } + + return a; +} + +llvm::Value* Ext::byPtr(llvm::Value* _value) +{ + auto a = getArgAlloca(); + getBuilder().CreateStore(_value, a); + return a; +} + llvm::CallInst* Ext::createCall(EnvFunc _funcId, std::initializer_list const& _args) { auto& func = m_funcs[static_cast(_funcId)]; if (!func) func = createFunc(_funcId, getModule()); + m_argCounter = 0; return getBuilder().CreateCall(func, {_args.begin(), _args.size()}); } llvm::Value* Ext::sload(llvm::Value* _index) { - m_builder.CreateStore(_index, m_args[0]); - createCall(EnvFunc::sload, {getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]}); // Uses native endianness - return m_builder.CreateLoad(m_args[1]); + auto ret = getArgAlloca(); + createCall(EnvFunc::sload, {getRuntimeManager().getEnvPtr(), byPtr(_index), ret}); // Uses native endianness + return m_builder.CreateLoad(ret); } void Ext::sstore(llvm::Value* _index, llvm::Value* _value) { - m_builder.CreateStore(_index, m_args[0]); - m_builder.CreateStore(_value, m_args[1]); - createCall(EnvFunc::sstore, {getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]}); // Uses native endianness + createCall(EnvFunc::sstore, {getRuntimeManager().getEnvPtr(), byPtr(_index), byPtr(_value)}); // Uses native endianness } llvm::Value* Ext::calldataload(llvm::Value* _index) @@ -101,9 +121,9 @@ llvm::Value* Ext::calldataload(llvm::Value* _index) llvm::Value* Ext::balance(llvm::Value* _address) { auto address = Endianness::toBE(m_builder, _address); - m_builder.CreateStore(address, m_args[0]); - createCall(EnvFunc::balance, {getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]}); - return m_builder.CreateLoad(m_args[1]); + auto ret = getArgAlloca(); + createCall(EnvFunc::balance, {getRuntimeManager().getEnvPtr(), byPtr(address), ret}); + return m_builder.CreateLoad(ret); } llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) @@ -149,8 +169,7 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) MemoryRef Ext::getExtCode(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); - m_builder.CreateStore(addr, m_args[0]); - auto code = createCall(EnvFunc::getExtCode, {getRuntimeManager().getEnvPtr(), m_args[0], m_size}); + auto code = createCall(EnvFunc::getExtCode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size}); auto codeSize = m_builder.CreateLoad(m_size); auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); return {code, codeSize256}; diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 766ac4c7e..bd238e43a 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -72,8 +72,12 @@ private: llvm::Value* m_data = nullptr; std::array::value> m_funcs = {}; + std::array m_argAllocas = {}; + size_t m_argCounter = 0; llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list const& _args); + llvm::Value* getArgAlloca(); + llvm::Value* byPtr(llvm::Value* _value); }; From e5d0fb35aab682268d5abfebaddf9c4634f9aaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 7 Jan 2015 15:17:46 +0100 Subject: [PATCH 394/466] Alloc stack elemnent for external function call argument on demand --- libevmjit/Ext.cpp | 41 +++++++++++++++-------------------------- libevmjit/Ext.h | 8 -------- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index dc8a23815..f2db32137 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -24,15 +24,6 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): RuntimeHelper(_runtimeManager), m_memoryMan(_memoryMan) { - m_args[0] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.index"); - m_args[1] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.value"); - m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg3"); - m_arg4 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg4"); - m_arg5 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg5"); - m_arg6 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg6"); - m_arg7 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg7"); - m_arg8 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg8"); m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); } @@ -112,9 +103,9 @@ void Ext::sstore(llvm::Value* _index, llvm::Value* _value) llvm::Value* Ext::calldataload(llvm::Value* _index) { - m_builder.CreateStore(_index, m_args[0]); - createCall(EnvFunc::calldataload, {getRuntimeManager().getDataPtr(), m_args[0], m_args[1]}); - auto ret = m_builder.CreateLoad(m_args[1]); + auto ret = getArgAlloca(); + createCall(EnvFunc::calldataload, {getRuntimeManager().getDataPtr(), byPtr(_index), ret}); + ret = m_builder.CreateLoad(ret); return Endianness::toNative(m_builder, ret); } @@ -128,31 +119,28 @@ llvm::Value* Ext::balance(llvm::Value* _address) llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - m_builder.CreateStore(_gas, m_args[0]); - m_builder.CreateStore(_endowment, m_arg2); + auto gas = byPtr(_gas); + auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, begin, size, m_args[1]}); - _gas = m_builder.CreateLoad(m_args[0]); // Return gas - llvm::Value* address = m_builder.CreateLoad(m_args[1]); + createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); + _gas = m_builder.CreateLoad(gas); // Return gas + llvm::Value* address = m_builder.CreateLoad(ret); 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 gas = byPtr(_gas); auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); - m_builder.CreateStore(receiveAddress, m_arg2); - m_builder.CreateStore(_value, m_arg3); auto inBeg = m_memoryMan.getBytePtr(_inOff); auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); auto outBeg = m_memoryMan.getBytePtr(_outOff); auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); - m_builder.CreateStore(codeAddress, m_arg8); - auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8}); - _gas = m_builder.CreateLoad(m_args[0]); // Return gas + auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); + _gas = m_builder.CreateLoad(gas); // Return gas return m_builder.CreateZExt(ret, Type::Word, "ret"); } @@ -160,8 +148,9 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) { auto begin = m_memoryMan.getBytePtr(_inOff); auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size"); - createCall(EnvFunc::sha3, {begin, size, m_args[1]}); - llvm::Value* hash = m_builder.CreateLoad(m_args[1]); + auto ret = getArgAlloca(); + createCall(EnvFunc::sha3, {begin, size, ret}); + llvm::Value* hash = m_builder.CreateLoad(ret); hash = Endianness::toNative(m_builder, hash); return hash; } @@ -179,7 +168,7 @@ void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array Date: Wed, 7 Jan 2015 16:02:16 +0100 Subject: [PATCH 395/466] New CALL/CREATE depth limit semantics --- libevmjit-cpp/Env.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 1dcd38162..4112774ee 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -44,14 +44,8 @@ extern "C" EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { - if (_env->depth == 1024) - jit::terminate(jit::ReturnCode::OutOfGas); - - assert(_env->depth < 1024); - auto endowment = llvm2eth(*_endowment); - - if (_env->balance(_env->myAddress) >= endowment) + if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) { _env->subBalance(endowment); auto gas = llvm2eth(*io_gas); @@ -66,13 +60,8 @@ extern "C" EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { - if (_env->depth == 1024) - jit::terminate(jit::ReturnCode::OutOfGas); - - assert(_env->depth < 1024); - auto value = llvm2eth(*_value); - if (_env->balance(_env->myAddress) >= value) + if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) { _env->subBalance(value); auto receiveAddress = right160(*_receiveAddress); From 86553cda81eb726327e9ba544caf9e42cea0322b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 7 Jan 2015 16:19:35 +0100 Subject: [PATCH 396/466] Remove terminate() function --- libevmjit/Runtime.cpp | 23 +++-------------------- libevmjit/Runtime.h | 3 --- libevmjit/Utils.cpp | 9 +-------- libevmjit/Utils.h | 2 -- 4 files changed, 4 insertions(+), 33 deletions(-) diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 27c81ea86..2522e8ace 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -11,29 +11,12 @@ namespace eth { namespace jit { -namespace -{ - jmp_buf_ref g_currJmpBuf; -} - -jmp_buf_ref Runtime::getCurrJmpBuf() -{ - return g_currJmpBuf; -} -Runtime::Runtime(RuntimeData* _data, Env* _env): +Runtime::Runtime(RuntimeData* _data, Env* _env) : m_data(*_data), m_env(*_env), - m_currJmpBuf(m_jmpBuf), - m_prevJmpBuf(g_currJmpBuf) -{ - g_currJmpBuf = m_jmpBuf; -} - -Runtime::~Runtime() -{ - g_currJmpBuf = m_prevJmpBuf; -} + m_currJmpBuf(m_jmpBuf) +{} bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy { diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index e11dac319..cedfaaf70 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -32,7 +32,6 @@ class Runtime { public: Runtime(RuntimeData* _data, Env* _env); - ~Runtime(); Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; @@ -43,7 +42,6 @@ public: bytes getReturnData() const; jmp_buf_ref getJmpBuf() { return m_jmpBuf; } - static jmp_buf_ref getCurrJmpBuf(); private: RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. @@ -51,7 +49,6 @@ private: jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. byte* m_memoryData = nullptr; i256 m_memorySize = {}; - jmp_buf_ref m_prevJmpBuf; std::jmp_buf m_jmpBuf; StackImpl m_stack; MemoryImpl m_memory; diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index f1ffbf67f..9d9b3acbb 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -1,8 +1,7 @@ -#include +#include #include "Utils.h" #include "Instruction.h" -#include "Runtime.h" namespace dev { @@ -55,12 +54,6 @@ llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _en return value; } -void terminate(ReturnCode _returnCode) -{ - auto jmpBuf = Runtime::getCurrJmpBuf(); - std::longjmp(jmpBuf, static_cast(_returnCode)); -} - } } } diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index db0647fdf..f672365c6 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -17,8 +17,6 @@ struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; u256 llvm2eth(i256); i256 eth2llvm(u256); -void terminate(ReturnCode _returnCode); - } } } From ed614c5d2a76e14f4ed1a65bb4512ec6beb3750d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 7 Jan 2015 20:19:03 +0100 Subject: [PATCH 397/466] Mandatory JUMPDEST for jumps and new static jumps recognition strategy --- libevmjit/Common.h | 2 + libevmjit/Compiler.cpp | 99 +++++++++++++----------------------------- libevmjit/Compiler.h | 7 +-- 3 files changed, 33 insertions(+), 75 deletions(-) diff --git a/libevmjit/Common.h b/libevmjit/Common.h index d98cc0acb..436931dcd 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -44,6 +44,8 @@ struct i256 }; static_assert(sizeof(i256) == 32, "Wrong i265 size"); +#define UNTESTED assert(false) + } } } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 48dc50d60..50d131575 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -5,8 +5,6 @@ #include #include -#include - #include #include #include @@ -44,17 +42,13 @@ 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) @@ -62,21 +56,7 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) 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.ult(_bytecode.size()) ? val.getZExtValue() : _bytecode.size(); - splitPoints.insert(targetPC); - - ProgramCounter jumpPC = (next - _bytecode.begin()); - directJumpTargets[jumpPC] = targetPC; - } + readPushData(curr, _bytecode.end()); break; } @@ -105,15 +85,6 @@ void Compiler::createBasicBlocks(bytes const& _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]) - it = splitPoints.erase(it); - else - ++it; - } - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) { auto beginInstIdx = *it; @@ -126,30 +97,8 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) 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); + m_jumpDests[*it] = basicBlocks.find(*it)->second.llvm(); } std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) @@ -196,16 +145,15 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - if (m_indirectJumpTargets.size() > 0) + if (m_jumpDests.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 switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), m_jumpDests.size()); + for (auto it = m_jumpDests.cbegin(); it != m_jumpDests.cend(); ++it) { auto& bb = *it; - auto dest = Constant::get(bb->begin()); - switchInstr->addCase(dest, bb->llvm()); + auto dest = Constant::get(it->first); + switchInstr->addCase(dest, it->second); } } else @@ -596,16 +544,23 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode 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 target = stack.pop(); + if (auto constant = llvm::dyn_cast(target)) { - auto pairIter = m_directJumpTargets.find(currentPC); - if (pairIter != m_directJumpTargets.end()) - targetBlock = pairIter->second; + auto&& c = constant->getValue(); + if (c.ult(_bytecode.size())) + { + auto v = c.getZExtValue(); + auto it = m_jumpDests.find(v); + if (it != m_jumpDests.end()) + targetBlock = it->second; + } + + if (!targetBlock) + { + targetBlock = m_badJumpBlock->llvm(); + } } if (inst == Instruction::JUMP) @@ -614,26 +569,30 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode { // The target address is computed at compile time, // just pop it without looking... - stack.pop(); m_builder.CreateBr(targetBlock); } else + { + stack.push(target); 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 + { + UNTESTED; + stack.push(target); m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); + } } break; diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 8e3bf357c..557be1083 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -67,11 +67,8 @@ private: /// 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 = {}; + /// Map of jump destinations + std::map m_jumpDests = {}; /// Stop basic block - terminates execution with STOP code (0) llvm::BasicBlock* m_stopBB = nullptr; From c21237f7b05387bae15de15dc1ad2d42d03246cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 10:05:24 +0100 Subject: [PATCH 398/466] Remove unnecessary jump dest map. Create jump table block on demand. --- libevmjit/BasicBlock.h | 7 ++++++ libevmjit/Compiler.cpp | 56 ++++++++++++++++++------------------------ libevmjit/Compiler.h | 7 +++--- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index f0643f342..4a789a8ec 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -67,6 +67,9 @@ public: ProgramCounter begin() { return m_beginInstIdx; } ProgramCounter end() { return m_endInstIdx; } + bool isJumpDest() const { return m_isJumpDest; } + void markAsJumpDest() { m_isJumpDest = true; } + LocalStack& localStack() { return m_stack; } /// Optimization: propagates values between local stacks in basic blocks @@ -109,6 +112,10 @@ private: /// How many items higher is the current stack than the initial one. /// May be negative. int m_tosOffset = 0; + + /// Is the basic block a valid jump destination. + /// JUMPDEST is the first instruction of the basic block. + bool m_isJumpDest = false; }; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 50d131575..d6e61db5e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -95,10 +95,27 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) 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 = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - m_jumpDests[*it] = basicBlocks.find(*it)->second.llvm(); + basicBlocks.find(*it)->second.markAsJumpDest(); +} + +BasicBlock& Compiler::getJumpTableBlock() +{ + if (!m_jumpTableBlock) + { + m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder)); + InsertPointGuard g{m_builder}; + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + auto dest = m_jumpTableBlock->localStack().pop(); + auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm()); + for (auto&& p : basicBlocks) + { + if (p.second.isJumpDest()) + switchInstr->addCase(Constant::get(p.first), p.second.llvm()); + } + } + return *m_jumpTableBlock; } std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) @@ -142,22 +159,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str 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_jumpDests.size() > 0) - { - auto dest = m_jumpTableBlock->localStack().pop(); - auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), m_jumpDests.size()); - for (auto it = m_jumpDests.cbegin(); it != m_jumpDests.cend(); ++it) - { - auto& bb = *it; - auto dest = Constant::get(it->first); - switchInstr->addCase(dest, it->second); - } - } - else - m_builder.CreateBr(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); removeDeadBlocks(); @@ -552,15 +554,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode if (c.ult(_bytecode.size())) { auto v = c.getZExtValue(); - auto it = m_jumpDests.find(v); - if (it != m_jumpDests.end()) - targetBlock = it->second; + auto it = basicBlocks.find(v); + if (it != basicBlocks.end() && it->second.isJumpDest()) + targetBlock = it->second.llvm(); } if (!targetBlock) - { targetBlock = m_badJumpBlock->llvm(); - } } if (inst == Instruction::JUMP) @@ -574,7 +574,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode else { stack.push(target); - m_builder.CreateBr(m_jumpTableBlock->llvm()); + m_builder.CreateBr(getJumpTableBlock().llvm()); } } else // JUMPI @@ -594,7 +594,6 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); } } - break; } @@ -830,13 +829,6 @@ void Compiler::removeDeadBlocks() } } 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) diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 557be1083..74b795318 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -47,6 +47,8 @@ private: 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); + BasicBlock& getJumpTableBlock(); + void removeDeadBlocks(); /// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled. @@ -65,10 +67,7 @@ private: llvm::IRBuilder<> m_builder; /// Maps a program counter pc to a basic block that starts at pc (if any). - std::map basicBlocks = {}; - - /// Map of jump destinations - std::map m_jumpDests = {}; + std::map basicBlocks; /// Stop basic block - terminates execution with STOP code (0) llvm::BasicBlock* m_stopBB = nullptr; From 024639bef6b9f0daa1a2dae6b7e8a693d9ed6bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 10:24:38 +0100 Subject: [PATCH 399/466] Create bad jump block on demand --- libevmjit/Compiler.cpp | 28 ++++++++++++++++++---------- libevmjit/Compiler.h | 10 ++++++---- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index d6e61db5e..0ec12569d 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -94,13 +94,12 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) } m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) basicBlocks.find(*it)->second.markAsJumpDest(); } -BasicBlock& Compiler::getJumpTableBlock() +llvm::BasicBlock* Compiler::getJumpTableBlock() { if (!m_jumpTableBlock) { @@ -108,14 +107,26 @@ BasicBlock& Compiler::getJumpTableBlock() InsertPointGuard g{m_builder}; m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); auto dest = m_jumpTableBlock->localStack().pop(); - auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm()); + auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); for (auto&& p : basicBlocks) { if (p.second.isJumpDest()) switchInstr->addCase(Constant::get(p.first), p.second.llvm()); } } - return *m_jumpTableBlock; + return m_jumpTableBlock->llvm(); +} + +llvm::BasicBlock* Compiler::getBadJumpBlock() +{ + if (!m_badJumpBlock) + { + m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder)); + InsertPointGuard g{m_builder}; + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + } + return m_badJumpBlock->llvm(); } std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) @@ -158,9 +169,6 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str 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)); - removeDeadBlocks(); dumpCFGifRequired("blocks-init.dot"); @@ -560,7 +568,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode } if (!targetBlock) - targetBlock = m_badJumpBlock->llvm(); + targetBlock = getBadJumpBlock(); } if (inst == Instruction::JUMP) @@ -574,7 +582,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode else { stack.push(target); - m_builder.CreateBr(getJumpTableBlock().llvm()); + m_builder.CreateBr(getJumpTableBlock()); } } else // JUMPI @@ -591,7 +599,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode { UNTESTED; stack.push(target); - m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); + m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); } } break; diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 74b795318..1c00dc711 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -47,7 +47,9 @@ private: 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); - BasicBlock& getJumpTableBlock(); + llvm::BasicBlock* getJumpTableBlock(); + + llvm::BasicBlock* getBadJumpBlock(); void removeDeadBlocks(); @@ -73,10 +75,10 @@ private: llvm::BasicBlock* m_stopBB = nullptr; /// Block with a jump table. - std::unique_ptr m_jumpTableBlock = nullptr; + std::unique_ptr m_jumpTableBlock; - /// Default destination for indirect jumps. - std::unique_ptr m_badJumpBlock = nullptr; + /// Destination for invalid jumps + std::unique_ptr m_badJumpBlock; /// Main program function llvm::Function* m_mainFunc = nullptr; From 681adc12af6e12e98b1a897f5cebd1c293269185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 10:54:00 +0100 Subject: [PATCH 400/466] Remove PREVHASH instruction --- libevmjit-cpp/JitVM.cpp | 1 - libevmjit/Compiler.cpp | 4 +++- libevmjit/Instruction.h | 2 +- libevmjit/RuntimeData.h | 1 - libevmjit/RuntimeManager.cpp | 2 -- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 815aa6332..dda8133a8 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -20,7 +20,6 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) m_data.set(RuntimeData::CallValue, _ext.value); m_data.set(RuntimeData::CallDataSize, _ext.data.size()); m_data.set(RuntimeData::GasPrice, _ext.gasPrice); - m_data.set(RuntimeData::PrevHash, _ext.previousBlock.hash); m_data.set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress)); m_data.set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp); m_data.set(RuntimeData::Number, _ext.currentBlock.number); diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 0ec12569d..6f256a571 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -40,6 +40,8 @@ Compiler::Compiler(Options const& _options): void Compiler::createBasicBlocks(bytes const& _bytecode) { + // FIXME: Simplify this algorithm. All can be done in one pass + std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end std::vector indirectJumpTargets; @@ -632,7 +634,6 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::CALLDATASIZE: case Instruction::CODESIZE: case Instruction::GASPRICE: - case Instruction::PREVHASH: case Instruction::COINBASE: case Instruction::TIMESTAMP: case Instruction::NUMBER: @@ -801,6 +802,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode default: // Invalid instruction - runtime exception { + // TODO: Replace with return statement _runtimeManager.raiseException(ReturnCode::BadInstruction); } diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index 502c4b66e..3f84efa08 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -58,7 +58,7 @@ enum class Instruction: uint8_t EXTCODESIZE, ///< get external code size (from another contract) EXTCODECOPY, ///< copy external code (from another contract) - PREVHASH = 0x40, ///< get hash of most recent complete block + BLOCKHASH = 0x40, ///< get hash of most recent complete block COINBASE, ///< get the block's coinbase address TIMESTAMP, ///< get the block's timestamp NUMBER, ///< get the block's number diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index 89987bdeb..bb52f7864 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -21,7 +21,6 @@ struct RuntimeData CallValue, CallDataSize, GasPrice, - PrevHash, CoinBase, TimeStamp, Number, diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 14280f80f..ea2fe20b5 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -63,7 +63,6 @@ llvm::Twine getName(RuntimeData::Index _index) 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"; @@ -154,7 +153,6 @@ llvm::Value* RuntimeManager::get(Instruction _inst) 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); From 7b9d4956a52c2e8794ac44d44bb44c9b561652af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 11:10:10 +0100 Subject: [PATCH 401/466] BLOCKHASH instruction --- libevmjit-cpp/Env.cpp | 5 +++++ libevmjit/Compiler.cpp | 8 ++++++++ libevmjit/Ext.cpp | 9 +++++++++ libevmjit/Ext.h | 2 ++ 4 files changed, 24 insertions(+) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 4112774ee..9fa15735e 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -42,6 +42,11 @@ extern "C" *o_value = eth2llvm(u); } + EXPORT void env_blockhash(ExtVMFace* _env, i256* _number, h256* o_hash) + { + *o_hash = _env->prevhash(llvm2eth(*_number)); + } + EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { auto endowment = llvm2eth(*_endowment); diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 6f256a571..7733321aa 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -645,6 +645,14 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode break; } + case Instruction::BLOCKHASH: + { + auto number = stack.pop(); + auto hash = _ext.blockhash(number); + stack.push(hash); + break; + } + case Instruction::BALANCE: { auto address = stack.pop(); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index f2db32137..c30b0a1e3 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -45,6 +45,7 @@ std::array::value> const& getEnvFuncDescs() FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_getExtCode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})}, }}; @@ -117,6 +118,14 @@ llvm::Value* Ext::balance(llvm::Value* _address) return m_builder.CreateLoad(ret); } +llvm::Value* Ext::blockhash(llvm::Value* _number) +{ + auto hash = getArgAlloca(); + createCall(EnvFunc::blockhash, {getRuntimeManager().getEnvPtr(), byPtr(_number), hash}); + hash = m_builder.CreateLoad(hash); + return Endianness::toNative(getBuilder(), hash); +} + llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { auto gas = byPtr(_gas); diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 9a9b3548a..2850be072 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -33,6 +33,7 @@ enum class EnvFunc create, call, log, + blockhash, getExtCode, calldataload, // Helper function, not client Env interface @@ -51,6 +52,7 @@ public: llvm::Value* calldataload(llvm::Value* _index); llvm::Value* create(llvm::Value*& _gas, 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* blockhash(llvm::Value* _number); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); MemoryRef getExtCode(llvm::Value* _addr); From 30f3e0d5c0e4e9caf39205bddaee191a9d3c2e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 11:25:48 +0100 Subject: [PATCH 402/466] Fix evmcc --- evmcc/evmcc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp index 3c43ab78b..e86f948f2 100644 --- a/evmcc/evmcc.cpp +++ b/evmcc/evmcc.cpp @@ -190,7 +190,6 @@ int main(int argc, char** argv) data.set(RuntimeData::CallValue, 0xabcd); data.set(RuntimeData::CallDataSize, 3); data.set(RuntimeData::GasPrice, 1003); - data.set(RuntimeData::PrevHash, 1003); data.set(RuntimeData::CoinBase, (u160)Address(101010101010101015)); data.set(RuntimeData::TimeStamp, 1005); data.set(RuntimeData::Number, 1006); From 5b4e1300a8fb996bd78070419cf3c1a6fad82c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 11:26:01 +0100 Subject: [PATCH 403/466] Function rename --- libevmjit-cpp/Env.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index 9fa15735e..6320aa222 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -44,7 +44,7 @@ extern "C" EXPORT void env_blockhash(ExtVMFace* _env, i256* _number, h256* o_hash) { - *o_hash = _env->prevhash(llvm2eth(*_number)); + *o_hash = _env->blockhash(llvm2eth(*_number)); } EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) From 035c3760e0482bf882800c7b18c87a1cd9cc9648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 11:41:53 +0100 Subject: [PATCH 404/466] All jump support code paths tested. Thanks @CJentzsch. --- libevmjit/Compiler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 7733321aa..abd725c7f 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -599,7 +599,6 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode } else { - UNTESTED; stack.push(target); m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); } From 961166443c193be490106684f3c29e894d21dcfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 12:53:38 +0100 Subject: [PATCH 405/466] Fix some GCC initialization warnings --- libevmjit/Common.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/Common.h b/libevmjit/Common.h index 436931dcd..1d8451c74 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -37,10 +37,10 @@ enum class ReturnCode // TODO: Replace with h256 struct i256 { - uint64_t a; - uint64_t b; - uint64_t c; - uint64_t d; + uint64_t a = 0; + uint64_t b = 0; + uint64_t c = 0; + uint64_t d = 0; }; static_assert(sizeof(i256) == 32, "Wrong i265 size"); From b8f9f3cffe541b1da477463aa6639c498fe138fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 15:06:50 +0100 Subject: [PATCH 406/466] Fix warnings --- libevmjit/BasicBlock.h | 4 ++-- libevmjit/Cache.h | 1 - libevmjit/ExecutionEngine.cpp | 5 +++++ libevmjit/Ext.h | 4 ++-- libevmjit/Runtime.h | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 4a789a8ec..dd099af8a 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -102,12 +102,12 @@ private: /// 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 = {}; + 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 = {}; + std::vector m_currentStack; /// How many items higher is the current stack than the initial one. /// May be negative. diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 80fe47ade..d1027288e 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -2,7 +2,6 @@ #include #include -#include #include diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 862586575..499312b38 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -4,8 +4,13 @@ #include #include +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" #include #include +#pragma warning(pop) +#pragma GCC diagnostic pop #include #include #include diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 2850be072..e6f1e4667 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -65,8 +65,8 @@ private: llvm::Value* m_size; llvm::Value* m_data = nullptr; - std::array::value> m_funcs = {}; - std::array m_argAllocas = {}; + std::array::value> m_funcs = {{}}; + std::array m_argAllocas = {{}}; size_t m_argCounter = 0; llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list const& _args); diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index cedfaaf70..8cc5b7968 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -48,7 +48,7 @@ private: Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. byte* m_memoryData = nullptr; - i256 m_memorySize = {}; + i256 m_memorySize; std::jmp_buf m_jmpBuf; StackImpl m_stack; MemoryImpl m_memory; From b4284f05dcbbc4cb8d7598413fbf0642c92d9d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 8 Jan 2015 16:19:11 +0100 Subject: [PATCH 407/466] skipPushData() helper function --- libevmjit/Compiler.cpp | 4 +--- libevmjit/Instruction.cpp | 40 +++++++++++++++++++++++++++++++++++++++ libevmjit/Instruction.h | 6 +++++- libevmjit/Utils.cpp | 19 ------------------- 4 files changed, 46 insertions(+), 23 deletions(-) create mode 100644 libevmjit/Instruction.cpp diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index abd725c7f..04152a22e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -57,10 +57,8 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) { case Instruction::ANY_PUSH: - { - readPushData(curr, _bytecode.end()); + skipPushData(curr, _bytecode.end()); break; - } case Instruction::JUMPDEST: { diff --git a/libevmjit/Instruction.cpp b/libevmjit/Instruction.cpp new file mode 100644 index 000000000..fdc40d043 --- /dev/null +++ b/libevmjit/Instruction.cpp @@ -0,0 +1,40 @@ + +#include "Instruction.h" +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::APInt 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; + llvm::APInt value(256, 0); + ++_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; +} + +void skipPushData(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; + --_end; + for (decltype(numBytes) i = 0; i < numBytes && _curr < _end; ++i, ++_curr) {} +} + +} +} +} diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index 3f84efa08..158490dee 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -160,9 +160,13 @@ enum class Instruction: uint8_t /// 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 +/// @param _curr is updated and points the last real byte read llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); +/// Skips PUSH data in pointed fragment of bytecode. +/// @param _curr is updated and points the last real byte skipped +void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); + #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ case Instruction::PUSH3: \ diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 9d9b3acbb..0fd9c0e41 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -1,7 +1,5 @@ -#include #include "Utils.h" -#include "Instruction.h" namespace dev { @@ -37,23 +35,6 @@ i256 eth2llvm(u256 _u) return i; } -llvm::APInt 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; - llvm::APInt value(256, 0); - ++_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; -} - } } } From bb37986cad4d325a4bd7af59c67b425971e187f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 12:27:07 +0100 Subject: [PATCH 408/466] Rewrite basic block creation code --- libevmjit/Compiler.cpp | 77 ++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 04152a22e..36683a6ae 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -40,63 +40,58 @@ Compiler::Compiler(Options const& _options): void Compiler::createBasicBlocks(bytes const& _bytecode) { - // FIXME: Simplify this algorithm. All can be done in one pass - - std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end - - std::vector indirectJumpTargets; - - splitPoints.insert(0); // First basic block - - for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) + /// Helper function that skips push data and finds next iterator (can be the end) + auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end) { - ProgramCounter currentPC = curr - _bytecode.begin(); - - auto inst = Instruction(*curr); - switch (inst) - { - - case Instruction::ANY_PUSH: - skipPushData(curr, _bytecode.end()); - break; + static const auto push1 = static_cast(Instruction::PUSH1); + static const auto push32 = static_cast(Instruction::PUSH32); + size_t offset = 1; + if (*_curr >= push1 && *_curr <= push32) + offset += std::min(*_curr - push1 + 1, (_end - _curr) - 1); + return _curr + offset; + }; + + ProgramCounter beginIdx = 0; + bool nextJumpDest = false; + for (auto curr = _bytecode.begin(), next = curr; curr != _bytecode.end(); curr = next) + { + next = skipPushDataAndGetNext(curr, _bytecode.end()); - case Instruction::JUMPDEST: + bool isEnd = false; + switch (Instruction(*curr)) { - // 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); + isEnd = true; + break; + + case Instruction::JUMPDEST: + nextJumpDest = true; break; - } default: break; } - } - 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)); + assert(next <= _bytecode.end()); + if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST) + isEnd = true; + + if (isEnd) + { + auto nextIdx = next - _bytecode.begin(); + auto p = basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(beginIdx, nextIdx, m_mainFunc, m_builder)); + if (nextJumpDest) + p.first->second.markAsJumpDest(); + nextJumpDest = false; + beginIdx = nextIdx; + } } m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - - for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - basicBlocks.find(*it)->second.markAsJumpDest(); } llvm::BasicBlock* Compiler::getJumpTableBlock() @@ -153,7 +148,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str Stack stack(m_builder, runtimeManager); Arith256 arith(m_builder); - m_builder.CreateBr(basicBlocks.begin()->second); + m_builder.CreateBr(basicBlocks.empty() ? m_stopBB : basicBlocks.begin()->second); for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) { From 098632804dd5e9a11d292d992a85feedf8333b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 12:58:39 +0100 Subject: [PATCH 409/466] Refactor / rename --- libevmjit/BasicBlock.h | 2 +- libevmjit/Compiler.cpp | 26 +++++++++++++------------- libevmjit/Compiler.h | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index dd099af8a..0a04e5939 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -61,7 +61,7 @@ public: BasicBlock(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete; - operator llvm::BasicBlock*() { return m_llvmBB; } + operator llvm::BasicBlock*() { return m_llvmBB; } // TODO: Remove it llvm::BasicBlock* llvm() { return m_llvmBB; } ProgramCounter begin() { return m_beginInstIdx; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 36683a6ae..37c8bd991 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -83,7 +83,7 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) if (isEnd) { auto nextIdx = next - _bytecode.begin(); - auto p = basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(beginIdx, nextIdx, m_mainFunc, m_builder)); + auto p = m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(beginIdx, nextIdx, m_mainFunc, m_builder)); if (nextJumpDest) p.first->second.markAsJumpDest(); nextJumpDest = false; @@ -103,7 +103,7 @@ llvm::BasicBlock* Compiler::getJumpTableBlock() m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); auto dest = m_jumpTableBlock->localStack().pop(); auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); - for (auto&& p : basicBlocks) + for (auto&& p : m_basicBlocks) { if (p.second.isJumpDest()) switchInstr->addCase(Constant::get(p.first), p.second.llvm()); @@ -148,14 +148,14 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str Stack stack(m_builder, runtimeManager); Arith256 arith(m_builder); - m_builder.CreateBr(basicBlocks.empty() ? m_stopBB : basicBlocks.begin()->second); + m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second); - for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) + for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) { auto& basicBlock = basicBlockPairIt->second; auto iterCopy = basicBlockPairIt; ++iterCopy; - auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; + auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } @@ -171,7 +171,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str if (m_options.optimizeStack) { std::vector blockList; - for (auto& entry : basicBlocks) + for (auto& entry : m_basicBlocks) blockList.push_back(&entry.second); if (m_jumpTableBlock) @@ -182,7 +182,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str dumpCFGifRequired("blocks-opt.dot"); } - for (auto& entry : basicBlocks) + for (auto& entry : m_basicBlocks) entry.second.synchronizeLocalStack(stack); if (m_jumpTableBlock) m_jumpTableBlock->synchronizeLocalStack(stack); @@ -557,8 +557,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode if (c.ult(_bytecode.size())) { auto v = c.getZExtValue(); - auto it = basicBlocks.find(v); - if (it != basicBlocks.end() && it->second.isJumpDest()) + auto it = m_basicBlocks.find(v); + if (it != m_basicBlocks.end() && it->second.isJumpDest()) targetBlock = it->second.llvm(); } @@ -825,13 +825,13 @@ void Compiler::removeDeadBlocks() do { sthErased = false; - for (auto it = basicBlocks.begin(); it != basicBlocks.end();) + for (auto it = m_basicBlocks.begin(); it != m_basicBlocks.end();) { auto llvmBB = it->second.llvm(); if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) { llvmBB->eraseFromParent(); - basicBlocks.erase(it++); + m_basicBlocks.erase(it++); sthErased = true; } else @@ -859,7 +859,7 @@ void Compiler::dumpCFGtoStream(std::ostream& _out) << " entry [share=record, label=\"entry block\"];\n"; std::vector blocks; - for (auto& pair : basicBlocks) + for (auto& pair : m_basicBlocks) blocks.push_back(&pair.second); if (m_jumpTableBlock) blocks.push_back(m_jumpTableBlock.get()); @@ -898,7 +898,7 @@ void Compiler::dumpCFGtoStream(std::ostream& _out) void Compiler::dump() { - for (auto& entry : basicBlocks) + for (auto& entry : m_basicBlocks) entry.second.dump(); if (m_jumpTableBlock != nullptr) m_jumpTableBlock->dump(); diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 1c00dc711..640acfa05 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -69,7 +69,7 @@ private: llvm::IRBuilder<> m_builder; /// Maps a program counter pc to a basic block that starts at pc (if any). - std::map basicBlocks; + std::map m_basicBlocks; /// Stop basic block - terminates execution with STOP code (0) llvm::BasicBlock* m_stopBB = nullptr; From be7713ac335ab4bfa1393245bc9523cf8ca39588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 13:28:35 +0100 Subject: [PATCH 410/466] Use iterators in basic block compilation --- libevmjit/Compiler.cpp | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 37c8bd991..c2f670eef 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -212,9 +212,12 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode m_builder.SetInsertPoint(_basicBlock.llvm()); auto& stack = _basicBlock.localStack(); - for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) + auto begin = _bytecode.begin() + _basicBlock.begin(); + auto end = _bytecode.begin() + _basicBlock.end(); + + for (auto it = begin; it != end; ++it) { - auto inst = static_cast(_bytecode[currentPC]); + auto inst = Instruction(*it); _gasMeter.count(inst); @@ -476,10 +479,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _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 value = readPushData(it, end); stack.push(Constant::get(value)); break; } @@ -554,24 +554,16 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode if (auto constant = llvm::dyn_cast(target)) { auto&& c = constant->getValue(); - if (c.ult(_bytecode.size())) - { - auto v = c.getZExtValue(); - auto it = m_basicBlocks.find(v); - if (it != m_basicBlocks.end() && it->second.isJumpDest()) - targetBlock = it->second.llvm(); - } - - if (!targetBlock) - targetBlock = getBadJumpBlock(); + auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1; + auto it = m_basicBlocks.find(targetIdx); + targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(); } + // TODO: Improve; check for constants if (inst == Instruction::JUMP) { if (targetBlock) { - // The target address is computed at compile time, - // just pop it without looking... m_builder.CreateBr(targetBlock); } else @@ -607,7 +599,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::PC: { - auto value = Constant::get(currentPC); + auto value = Constant::get(it - _bytecode.begin()); stack.push(value); break; } From f0008a31240d097a5a689c1e0937b3117e766431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 14:03:10 +0100 Subject: [PATCH 411/466] Use iterators in BasicBlock --- libevmjit/BasicBlock.cpp | 11 +++++------ libevmjit/BasicBlock.h | 16 +++++++--------- libevmjit/Compiler.cpp | 17 +++++++---------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index d233ea744..bae16392e 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -20,17 +20,16 @@ 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)), +BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : + m_begin(_begin), + m_end(_end), + // TODO: Add begin index to name + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _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) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 0a04e5939..7a36090a5 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -1,9 +1,7 @@ #pragma once - #include - #include - +#include "Common.h" #include "Stack.h" namespace dev @@ -52,10 +50,10 @@ public: BasicBlock& m_bblock; }; - /// Basic block name prefix. The rest is beging instruction index. + /// Basic block name prefix. The rest is instruction index. static const char* NamePrefix; - explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); + explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); BasicBlock(const BasicBlock&) = delete; @@ -64,8 +62,8 @@ public: operator llvm::BasicBlock*() { return m_llvmBB; } // TODO: Remove it llvm::BasicBlock* llvm() { return m_llvmBB; } - ProgramCounter begin() { return m_beginInstIdx; } - ProgramCounter end() { return m_endInstIdx; } + bytes::const_iterator begin() { return m_begin; } + bytes::const_iterator end() { return m_end; } bool isJumpDest() const { return m_isJumpDest; } void markAsJumpDest() { m_isJumpDest = true; } @@ -85,8 +83,8 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - ProgramCounter const m_beginInstIdx; - ProgramCounter const m_endInstIdx; + bytes::const_iterator const m_begin; + bytes::const_iterator const m_end; llvm::BasicBlock* const m_llvmBB; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index c2f670eef..7e1851c8a 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -51,9 +51,9 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) return _curr + offset; }; - ProgramCounter beginIdx = 0; + auto begin = _bytecode.begin(); bool nextJumpDest = false; - for (auto curr = _bytecode.begin(), next = curr; curr != _bytecode.end(); curr = next) + for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next) { next = skipPushDataAndGetNext(curr, _bytecode.end()); @@ -82,12 +82,12 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) if (isEnd) { - auto nextIdx = next - _bytecode.begin(); - auto p = m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(beginIdx, nextIdx, m_mainFunc, m_builder)); + auto beginIdx = begin - _bytecode.begin(); + auto p = m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(begin, next, m_mainFunc, m_builder)); if (nextJumpDest) p.first->second.markAsJumpDest(); nextJumpDest = false; - beginIdx = nextIdx; + begin = next; } } @@ -212,10 +212,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode m_builder.SetInsertPoint(_basicBlock.llvm()); auto& stack = _basicBlock.localStack(); - auto begin = _bytecode.begin() + _basicBlock.begin(); - auto end = _bytecode.begin() + _basicBlock.end(); - - for (auto it = begin; it != end; ++it) + for (auto it = _basicBlock.begin(); it != _basicBlock.end(); ++it) { auto inst = Instruction(*it); @@ -479,7 +476,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::ANY_PUSH: { - auto value = readPushData(it, end); + auto value = readPushData(it, _basicBlock.end()); stack.push(Constant::get(value)); break; } From 6fee45a3e327f51387b9b04aeb350f1072f60d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 14:12:18 +0100 Subject: [PATCH 412/466] Set "jump dest" flag in constructor of BasicBlock --- libevmjit/BasicBlock.cpp | 10 ++++++---- libevmjit/BasicBlock.h | 7 +++---- libevmjit/Compiler.cpp | 9 ++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index bae16392e..dda0fbc36 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -20,19 +20,21 @@ namespace jit const char* BasicBlock::NamePrefix = "Instr."; -BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : +BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : m_begin(_begin), m_end(_end), // TODO: Add begin index to name m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)), m_stack(*this), - m_builder(_builder) + m_builder(_builder), + m_isJumpDest(isJumpDest) {} -BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : +BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), m_stack(*this), - m_builder(_builder) + m_builder(_builder), + m_isJumpDest(isJumpDest) {} BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 7a36090a5..8d3c31922 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -53,8 +53,8 @@ public: /// Basic block name prefix. The rest is instruction index. static const char* NamePrefix; - explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); - explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); + explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); BasicBlock(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete; @@ -66,7 +66,6 @@ public: bytes::const_iterator end() { return m_end; } bool isJumpDest() const { return m_isJumpDest; } - void markAsJumpDest() { m_isJumpDest = true; } LocalStack& localStack() { return m_stack; } @@ -113,7 +112,7 @@ private: /// Is the basic block a valid jump destination. /// JUMPDEST is the first instruction of the basic block. - bool m_isJumpDest = false; + bool const m_isJumpDest = false; }; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 7e1851c8a..70d40b431 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -83,9 +83,8 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) if (isEnd) { auto beginIdx = begin - _bytecode.begin(); - auto p = m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(begin, next, m_mainFunc, m_builder)); - if (nextJumpDest) - p.first->second.markAsJumpDest(); + m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), + std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; begin = next; } @@ -98,7 +97,7 @@ llvm::BasicBlock* Compiler::getJumpTableBlock() { if (!m_jumpTableBlock) { - m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder)); + m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true)); InsertPointGuard g{m_builder}; m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); auto dest = m_jumpTableBlock->localStack().pop(); @@ -116,7 +115,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock() { if (!m_badJumpBlock) { - m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder)); + m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true)); InsertPointGuard g{m_builder}; m_builder.SetInsertPoint(m_badJumpBlock->llvm()); m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); From 47886c844ad4914edd2ad4a3a433e43f09dfcf4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 14:49:24 +0100 Subject: [PATCH 413/466] Remove compleated TODO task --- libevmjit/GasMeter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 39f4560e5..84266111e 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -41,7 +41,7 @@ uint64_t const c_logDataGas = 1; uint64_t const c_logTopicGas = 32; uint64_t const c_copyGas = 1; -uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted) +uint64_t getStepCost(Instruction inst) { switch (inst) { From cb8fa0a5b229539d1975669c19db697480ea51b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 15:30:13 +0100 Subject: [PATCH 414/466] Fix MSVC build --- libevmjit/Ext.cpp | 4 +++- libevmjit/Ext.h | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index c30b0a1e3..cd741ad24 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -22,7 +22,9 @@ namespace jit Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): RuntimeHelper(_runtimeManager), - m_memoryMan(_memoryMan) + m_memoryMan(_memoryMan), + m_funcs{}, + m_argAllocas{} { m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index e6f1e4667..86a8a6190 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -65,8 +65,8 @@ private: llvm::Value* m_size; llvm::Value* m_data = nullptr; - std::array::value> m_funcs = {{}}; - std::array m_argAllocas = {{}}; + std::array::value> m_funcs; + std::array m_argAllocas; size_t m_argCounter = 0; llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list const& _args); From 3990e5b97ab8cd26c5504147546a9ddda8dcee38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 15:30:51 +0100 Subject: [PATCH 415/466] Add _SCL_SECURE_NO_WARNINGS for LLVM on Windows --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 26a8010d1..222fa5b72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,8 @@ else() set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") endif() +add_definitions(-D_SCL_SECURE_NO_WARNINGS) # LLVM needs it on Windows + # Boost find_package(Boost REQUIRED) From 9c244ed08eb0f674637b6f0a103059de6b8534cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 16:14:45 +0100 Subject: [PATCH 416/466] Load cached object without compiling LLVM module --- libevmjit/Cache.cpp | 40 ++++++++++++++++++++++++++--------- libevmjit/Cache.h | 1 + libevmjit/ExecutionEngine.cpp | 11 ++++++++-- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index a887d91e9..2311c0496 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,32 @@ ObjectCache* Cache::getObjectCache() return &objectCache; } +namespace +{ + llvm::MemoryBuffer* lastObject; +} + +std::unique_ptr Cache::getObject(std::string const& id) +{ + assert(!lastObject); + llvm::SmallString<256> cachePath; + llvm::sys::path::system_temp_directory(false, cachePath); + llvm::sys::path::append(cachePath, "evm_objs", id); + + if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) + lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) + std::cerr << r.getError().message(); // TODO: Add log + + if (lastObject) // if object found create fake module + { + auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); + auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); + auto func = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + } + return nullptr; +} + void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { @@ -43,16 +70,9 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) { - auto&& id = _module->getModuleIdentifier(); - llvm::SmallString<256> cachePath; - llvm::sys::path::system_temp_directory(false, cachePath); - llvm::sys::path::append(cachePath, "evm_objs", id); - - if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - return llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); - else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) - std::cerr << r.getError().message(); // TODO: Add log - return nullptr; + auto o = lastObject; + lastObject = nullptr; + return o; } } diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index d1027288e..1cad537cd 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -33,6 +33,7 @@ class Cache { public: static ObjectCache* getObjectCache(); + static std::unique_ptr getObject(std::string const& id); }; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 499312b38..7e99932c3 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -74,7 +74,13 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en } else { - auto module = Compiler({}).compile(_code, mainFuncName); + bool objectCacheEnabled = true; + auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; + std::unique_ptr module; + if (objectCache) + module = Cache::getObject(mainFuncName); + if (!module) + module = Compiler({}).compile(_code, mainFuncName); //module->dump(); if (!ee) { @@ -100,7 +106,8 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module memoryManager.release(); // and memory manager - ee->setObjectCache(Cache::getObjectCache()); + if (objectCache) + ee->setObjectCache(objectCache); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else From 98a30815ac5a794002dd7b9bb8d1af1ea35687d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 17:01:16 +0100 Subject: [PATCH 417/466] Cleanups --- libevmjit/BasicBlock.h | 1 - libevmjit/Compiler.cpp | 2 +- libevmjit/Compiler.h | 12 +++--------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 8d3c31922..7a5364a4e 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -59,7 +59,6 @@ public: BasicBlock(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete; - operator llvm::BasicBlock*() { return m_llvmBB; } // TODO: Remove it llvm::BasicBlock* llvm() { return m_llvmBB; } bytes::const_iterator begin() { return m_begin; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 70d40b431..bfcb9cea1 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -147,7 +147,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str Stack stack(m_builder, runtimeManager); Arith256 arith(m_builder); - m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second); + m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) { diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 640acfa05..720a48cf9 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -20,19 +20,13 @@ public: struct Options { /// Optimize stack operations between basic blocks - bool optimizeStack; + bool optimizeStack = true; /// Rewrite switch instructions to sequences of branches - bool rewriteSwitchToBranches; + bool rewriteSwitchToBranches = true; /// Dump CFG as a .dot file for graphviz - bool dumpCFG; - - Options(): - optimizeStack(true), - rewriteSwitchToBranches(true), - dumpCFG(false) - {} + bool dumpCFG = false; }; using ProgramCounter = uint64_t; From 858273bc89e620fad7c18e477c6739a6e0598e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 9 Jan 2015 17:23:10 +0100 Subject: [PATCH 418/466] Handle return memory of size 0 and large offset --- libevmjit/Runtime.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 2522e8ace..911dc469d 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -24,8 +24,10 @@ bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy 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 + assert(offset + size <= m_memory.size() || size == 0); + if (offset + size > m_memory.size()) + return {}; + auto dataBeg = m_memory.begin() + offset; return {dataBeg, dataBeg + size}; } From 85ef08a9a0fe717f45447148a8322f1eecbec6b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sun, 11 Jan 2015 01:23:16 +0100 Subject: [PATCH 419/466] Add preprocessor definitions required by LLVM --- CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 222fa5b72..18601b921 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ if(LLVM_DIR) # local LLVM build find_package(LLVM REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + add_definitions(${LLVM_DEFINITIONS}) # TODO: bitwriter is needed only for evmcc llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter) else() @@ -19,11 +20,9 @@ else() set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") endif() -add_definitions(-D_SCL_SECURE_NO_WARNINGS) # LLVM needs it on Windows - # Boost find_package(Boost REQUIRED) add_subdirectory(libevmjit) add_subdirectory(libevmjit-cpp) -add_subdirectory(evmcc) \ No newline at end of file +add_subdirectory(evmcc) From a0de919f65a7b6e47a8c4afcaf7fa550a4c8346f Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 11:35:54 +0100 Subject: [PATCH 420/466] read in vm test over standard in --- test/vm.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/vm.cpp b/test/vm.cpp index 6ae95f256..8187378e5 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -560,6 +560,40 @@ BOOST_AUTO_TEST_CASE(vmRandom) } } +BOOST_AUTO_TEST_CASE(checkRandomTest) +{ + for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) + { + string arg = boost::unit_test::framework::master_test_suite().argv[i]; + if (arg == "--randomTest") + { + try + { + cout << "RANDOM::::::RANDOM" << endl; + json_spirit::mValue v; + string s;// = boost::unit_test::framework::master_test_suite().argv[i + 1]; + string line; + while ( getline(cin, line) && !line.empty() ) + s += line; + cout << "my test: AAAHHHAAA: \n" << s << endl; + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of argument is empty"); + json_spirit::read_string(s, v); + doVMTests(v, false); + cout << "RANDOM::::::RANDOM--done" << endl; + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); + } + catch (std::exception const& _e) + { + BOOST_ERROR("Failed test with Exception: " << _e.what()); + } + break; + } + } +} + BOOST_AUTO_TEST_CASE(userDefinedFileVM) { dev::test::userDefinedTest("--vmtest", dev::test::doVMTests); From 389b0973c4ef343faf3b35fec4d7859ad0a5c4e1 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 12:46:40 +0100 Subject: [PATCH 421/466] start with block info opcodes --- test/createRandomTest.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 1af12f64d..40ed1aa9c 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -54,18 +54,26 @@ int main(int argc, char *argv[]) gen.seed(static_cast(timeSinceEpoch)); boost::random::uniform_int_distribution<> lengthOfCodeDist(2, 16); boost::random::uniform_int_distribution<> opcodeDist(0, 255); + boost::random::uniform_int_distribution<> BlockInfoOpcodeDist(0x41, 0x45); boost::random::variate_generator > randGen(gen, opcodeDist); + boost::random::variate_generator > randGenBlockInfoOpcode(gen, BlockInfoOpcodeDist); int lengthOfCode = lengthOfCodeDist(gen); string randomCode; for (int i = 0; i < lengthOfCode; ++i) { - uint8_t opcode = randGen(); + if (i < 8 && (randGen() < 192)) + { + randomCode += toHex(toCompactBigEndian((uint8_t)randGenBlockInfoOpcode())); + continue; + } - // disregard all invalid commands, except of one (0x10) - if (dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || opcode == 0x10) + uint8_t opcode = randGen(); + // disregard all invalid commands, except of one (0x0c) + if (dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || opcode == 0x0a) randomCode += toHex(toCompactBigEndian(opcode)); else i--; @@ -77,9 +85,9 @@ int main(int argc, char *argv[]) \"env\" : {\n\ \"previousHash\" : \"5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6\",\n\ \"currentNumber\" : \"0\",\n\ - \"currentGasLimit\" : \"1000000\",\n\ - \"currentDifficulty\" : \"256\",\n\ - \"currentTimestamp\" : 1,\n\ + \"currentGasLimit\" : \"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\n\ + \"currentDifficulty\" : \"1\",\n\ + \"currentTimestamp\" : 2,\n\ \"currentCoinbase\" : \"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\"\n\ },\n\ \"pre\" : {\n\ @@ -106,7 +114,7 @@ int main(int argc, char *argv[]) read_string(s, v); // insert new random code - v.get_obj().find("randomVMtest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode; + v.get_obj().find("randomVMtest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + "55"; // execute code in vm doMyTests(v); From 3ebef61c5b942de674bebe32844f33ee7bda304b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 12 Jan 2015 15:25:46 +0100 Subject: [PATCH 422/466] Fix portability problems --- libevmjit/Cache.cpp | 4 ++-- libevmjit/Ext.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 2311c0496..0b725bc24 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -45,7 +45,7 @@ std::unique_ptr Cache::getObject(std::string const& id) { auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); - auto func = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); } return nullptr; } @@ -68,7 +68,7 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory cacheFile << _object->getBuffer(); } -llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) { auto o = lastObject; lastObject = nullptr; diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index cd741ad24..f0767d9e0 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -23,8 +23,8 @@ namespace jit Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): RuntimeHelper(_runtimeManager), m_memoryMan(_memoryMan), - m_funcs{}, - m_argAllocas{} + m_funcs({}), // The only std::array initialization that works in both Visual Studio & GCC + m_argAllocas({}) { m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); } From 8acd9b110732c8c690181c465011dc43a8f0427d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 9 Jan 2015 17:02:39 +0100 Subject: [PATCH 423/466] Work in prgress for creating natspec in alethzero at contract creation --- alethzero/MainWin.cpp | 30 ++++++++++++++- alethzero/MainWin.h | 5 ++- alethzero/NatspecHandler.cpp | 58 +++++++++++++++++++++++++++++ alethzero/NatspecHandler.h | 45 ++++++++++++++++++++++ alethzero/OurWebThreeStubServer.cpp | 12 +++--- alethzero/OurWebThreeStubServer.h | 6 ++- libethereum/Defaults.h | 1 + libsolidity/CompilerStack.cpp | 7 ++++ libsolidity/CompilerStack.h | 4 ++ 9 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 alethzero/NatspecHandler.cpp create mode 100644 alethzero/NatspecHandler.h diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 01b112b50..b05bcf1cc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -158,7 +158,7 @@ Main::Main(QWidget *parent) : m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"})); m_qwebConnector.reset(new QWebThreeConnector()); - m_server.reset(new OurWebThreeStubServer(*m_qwebConnector, *web3(), keysAsVector(m_myKeys))); + m_server.reset(new OurWebThreeStubServer(*m_qwebConnector, *web3(), keysAsVector(m_myKeys), this)); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); m_server->setIdentities(keysAsVector(owned())); m_server->StartListening(); @@ -1872,7 +1872,30 @@ void Main::on_send_clicked() debugFinished(); Secret s = i.secret(); if (isCreation()) + { ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice()); + + // LTODO: work in progress, recompile contract and get the hash of the code + // Also .. yeah improve the heuristic for Solidity and abstract to a function + string src = ui->data->toPlainText().toStdString(); + if (src.substr(0, 8) == "contract" || src.substr(0, 2) == "/*") // improve this heuristic + { + + dev::solidity::CompilerStack compiler; + try + { + m_data = compiler.compile(src, m_enableOptimizer); + for (std::string& s: compiler.getContractNames()) + m_natspecDB.add(compiler.getContractCodeHash(s), + compiler.getMetadata(s, dev::solidity::DocumentationType::NATSPEC_USER)); + + } + catch (...) + { + statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); + } + } + } else ethereum()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); return; @@ -2257,6 +2280,11 @@ void Main::on_post_clicked() whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value())); } +std::string Main::lookupNatSpec(dev::h256 const& _contractHash) const +{ + return m_natspecDB.retrieve(_contractHash); +} + void Main::refreshWhispers() { ui->whispers->clear(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 52a71102d..e20aac27d 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -37,6 +37,8 @@ #include #include +#include "NatspecHandler.h" + namespace Ui { class Main; } @@ -80,7 +82,7 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } - std::string lookupNatSpec(dev::h256 const& _contractCode) const { (void)_contractCode; return ""; } // TODO: actually implement with leveldb & a UI. + std::string lookupNatSpec(dev::h256 const& _contractHash) const; QList owned() const { return m_myIdentities + m_myKeys; } @@ -269,4 +271,5 @@ private: QWebThree* m_qweb = nullptr; static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr); + NatspecHandler m_natspecDB; }; diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp new file mode 100644 index 000000000..ae58208f1 --- /dev/null +++ b/alethzero/NatspecHandler.cpp @@ -0,0 +1,58 @@ +/* + 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 NatspecHandler.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#include "NatspecHandler.h" +#include +#include + +#include +#include + +using namespace dev; +using namespace dev::eth; + +NatspecHandler::NatspecHandler() +{ + std::string path = Defaults::dbPath(); + boost::filesystem::create_directories(path); + ldb::Options o; + o.create_if_missing = true; + ldb::DB::Open(o, path + "/natspec", &m_db); +} + + +void NatspecHandler::add(dev::h256 const& _contractHash, std::string const& _doc) +{ + bytes k = _contractHash.asBytes(); + std::string v = _doc; + m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); +} + +std::string NatspecHandler::retrieve(dev::h256 const& _contractHash) const +{ + bytes k = _contractHash.asBytes(); + std::string ret; + m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); + return ret; +} + + + diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h new file mode 100644 index 000000000..36554fc44 --- /dev/null +++ b/alethzero/NatspecHandler.h @@ -0,0 +1,45 @@ +/* + 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 NatspecHandler.h + * @author Lefteris Karapetsas + * @date 2015 + */ + +#pragma once + +#pragma warning(push) +#pragma warning(disable: 4100 4267) +#include +#pragma warning(pop) +#include + +namespace ldb = leveldb; + +class NatspecHandler +{ + public: + NatspecHandler(); + + void add(dev::h256 const& _contractHash, std::string const& _doc); + std::string retrieve(dev::h256 const& _contractHash) const; + + private: + ldb::ReadOptions m_readOptions; + ldb::WriteOptions m_writeOptions; + ldb::DB* m_db; +}; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 0d840e8d4..a156eeb1c 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -24,12 +24,14 @@ #include #include #include "MainWin.h" + using namespace std; using namespace dev; using namespace dev::eth; -OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts): - WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3) +OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, + std::vector const& _accounts, Main* main): + WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main) {} std::string OurWebThreeStubServer::shh_newIdentity() @@ -41,13 +43,11 @@ std::string OurWebThreeStubServer::shh_newIdentity() bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const { - return true; + // return true; // To get the balance of the sender cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from); - Main* main; // don't know this yet, should be a member and set at construction time by Main, who will construct us. - h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); if (contractCodeHash == EmptySHA3) @@ -57,7 +57,7 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con return true; // or whatever. } - std::string natspecJson = main->lookupNatSpec(contractCodeHash); + std::string natspecJson = m_main->lookupNatSpec(contractCodeHash); if (natspecJson.empty()) { diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index 9ff973371..506a77884 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -24,12 +24,15 @@ #include #include +class Main; + class OurWebThreeStubServer: public QObject, public WebThreeStubServer { Q_OBJECT public: - OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); + OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, + std::vector const& _accounts, Main* main); virtual std::string shh_newIdentity() override; virtual bool authenticate(dev::TransactionSkeleton const& _t) const; @@ -39,4 +42,5 @@ signals: private: dev::WebThreeDirect* m_web3; + Main* m_main; }; diff --git a/libethereum/Defaults.h b/libethereum/Defaults.h index 91d5872f7..3b19166b1 100644 --- a/libethereum/Defaults.h +++ b/libethereum/Defaults.h @@ -23,6 +23,7 @@ #include + namespace dev { namespace eth diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 174f9cd22..547e5fe21 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -200,6 +200,13 @@ bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimiz return stack.compile(_sourceCode, _optimize); } +dev::h256 CompilerStack::getContractCodeHash(std::string const& _contractName) +{ + //LTODO + (void) _contractName; + return dev::h256(""); +} + void CompilerStack::reset(bool _keepSources) { m_parseSuccessful = false; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index afc9a5162..6b60f1dd3 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace dev { namespace solidity { @@ -104,6 +105,9 @@ public: /// scanning the source code - this is useful for printing exception information. static bytes staticCompile(std::string const& _sourceCode, bool _optimize = false); + /// Get the runtime context's code hash for a contract. LTODO + dev::h256 getContractCodeHash(std::string const& _contractName); + private: /** * Information pertaining to one source unit, filled gradually during parsing and compilation. From 070d1d800c8f830f095b0c1fd099f17e09865446 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 15:42:28 +0100 Subject: [PATCH 424/466] rests current gas limit in vm test --- test/createRandomTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 40ed1aa9c..d9638cebe 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -85,8 +85,8 @@ int main(int argc, char *argv[]) \"env\" : {\n\ \"previousHash\" : \"5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6\",\n\ \"currentNumber\" : \"0\",\n\ - \"currentGasLimit\" : \"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\n\ - \"currentDifficulty\" : \"1\",\n\ + \"currentGasLimit\" : \"1000000\",\n\ + \"currentDifficulty\" : \"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\n\ \"currentTimestamp\" : 2,\n\ \"currentCoinbase\" : \"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\"\n\ },\n\ From 549811ade15c453c4d0ca4f1668d8b838b3284a4 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 16:18:27 +0100 Subject: [PATCH 425/466] addmod mulmod doing mod 0 should return 0 instead of an not VM exception --- libevm/VM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 4307d9da0..aa3caff44 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -398,12 +398,12 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.pop_back(); break; case Instruction::ADDMOD: - m_stack[m_stack.size() - 3] = u256((bigint(m_stack.back()) + bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]); + m_stack[m_stack.size() - 3] = m_stack[m_stack.size() - 3] ? u256((bigint(m_stack.back()) + bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]) : 0; m_stack.pop_back(); m_stack.pop_back(); break; case Instruction::MULMOD: - m_stack[m_stack.size() - 3] = u256((bigint(m_stack.back()) * bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]); + m_stack[m_stack.size() - 3] = m_stack[m_stack.size() - 3] ? u256((bigint(m_stack.back()) * bigint(m_stack[m_stack.size() - 2])) % m_stack[m_stack.size() - 3]) : 0; m_stack.pop_back(); m_stack.pop_back(); break; From 42940c18ceae91b0412b2e017c54dac114ad2014 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 16:28:56 +0100 Subject: [PATCH 426/466] addmod mulmod div by zero tests --- test/vmArithmeticTestFiller.json | 168 +++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/test/vmArithmeticTestFiller.json b/test/vmArithmeticTestFiller.json index 12574f51c..9e8b3f61c 100644 --- a/test/vmArithmeticTestFiller.json +++ b/test/vmArithmeticTestFiller.json @@ -1346,6 +1346,90 @@ } }, + "addmodDivByZero": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADDMOD 4 1 0) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "addmodDivByZero1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADDMOD 0 1 0) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "addmodDivByZero1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADDMOD 1 0 0) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "mulmod0": { "env" : { @@ -1543,6 +1627,90 @@ } }, + "mulmoddivByZero": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (MULMOD 5 1 0) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "mulmoddivByZero1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (MULMOD 0 1 0) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "mulmoddivByZero2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (MULMOD 1 0 0) } ", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "exp0": { "env" : { From fdefaca4103017fc1f44ed076254a16d22e990d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 12 Jan 2015 16:41:00 +0100 Subject: [PATCH 427/466] Compute SHA3 additional gas cost in 64-bit precision --- libevmjit/GasMeter.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 84266111e..4aa6a738d 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -173,10 +173,12 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) assert(m_blockCost > 0); // SHA3 instruction is already counted // TODO: This round ups to 32 happens in many places - // FIXME: Overflow possible but Memory::require() also called. Probably 64-bit arith can be used. + // FIXME: 64-bit arith used, but not verified static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); - auto words = m_builder.CreateUDiv(m_builder.CreateAdd(_dataLength, Constant::get(31)), Constant::get(32)); - auto cost = m_builder.CreateNUWMul(Constant::get(c_sha3WordGas), words); + auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); + auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); + auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); + auto cost = getBuilder().CreateZExt(cost64, Type::Word); count(cost); } From 7906cdd2e8ba2a46763d45e4df8c57642d5df84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 12 Jan 2015 16:41:28 +0100 Subject: [PATCH 428/466] Handle ADDMOD/MULMOD case with 3rd argument being 0 --- libevmjit/Arith256.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 10d3e3449..b5319bda7 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -178,7 +178,10 @@ extern "C" auto arg1 = llvm2eth(*_arg1); auto arg2 = llvm2eth(*_arg2); auto arg3 = llvm2eth(*_arg3); - *o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3)); + if (arg3 != 0) + *o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3)); + else + *o_result = {}; } EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) @@ -186,7 +189,10 @@ extern "C" auto arg1 = llvm2eth(*_arg1); auto arg2 = llvm2eth(*_arg2); auto arg3 = llvm2eth(*_arg3); - *o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3)); + if (arg3 != 0) + *o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3)); + else + *o_result = {}; } } From 3b207c26e9745950c5d85f5852cf636480a73f00 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 12 Jan 2015 17:13:27 +0100 Subject: [PATCH 429/466] Alethzero: Showing a contract's function's hashes at creation --- alethzero/MainWin.cpp | 1 + libsolidity/CompilerStack.cpp | 18 ++++++++++++++++++ libsolidity/CompilerStack.h | 3 +++ 3 files changed, 22 insertions(+) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index b05bcf1cc..5de05848e 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1657,6 +1657,7 @@ void Main::on_data_textChanged() solidity = "

Solidity

"; solidity += "
" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "
"; solidity += "
" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "
"; + solidity += "
" + QString::fromStdString(compiler.getFunctionHashes()).toHtmlEscaped() + "
"; } catch (dev::Exception const& exception) { diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 547e5fe21..f0d2e7f75 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -179,6 +179,24 @@ string const& CompilerStack::getMetadata(string const& _contractName, Documentat return *(*doc); } +std::string const CompilerStack::getFunctionHashes(std::string const& _contractName) +{ + if (!m_parseSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + + std::string ret = ""; + Contract const& contract = getContract(_contractName); + auto interfaceFunctions = contract.contract->getInterfaceFunctions(); + + for (auto const& it: interfaceFunctions) + { + ret += it.first.abridged(); + ret += " :"; + ret += it.second->getName() + "\n"; + } + return ret; +} + Scanner const& CompilerStack::getScanner(string const& _sourceName) const { return *getSource(_sourceName).scanner; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 6b60f1dd3..da0adf57e 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -93,6 +93,9 @@ public: /// Can be one of 4 types defined at @c DocumentationType std::string const& getMetadata(std::string const& _contractName, DocumentationType _type) const; + /// Convenience function to return all contract method hashes in a string + std::string const getFunctionHashes(std::string const& _contractName = ""); + /// @returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner(std::string const& _sourceName = "") const; /// @returns the parsed source unit with the supplied name. From b0c94c62e3eb1bbc1dbecb1f05116e9afaf601ae Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 17:17:05 +0100 Subject: [PATCH 430/466] call to precomppiled contract test --- test/vmSystemOperationsTestFiller.json | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/vmSystemOperationsTestFiller.json b/test/vmSystemOperationsTestFiller.json index 1df2697e0..a5cd79030 100644 --- a/test/vmSystemOperationsTestFiller.json +++ b/test/vmSystemOperationsTestFiller.json @@ -147,6 +147,36 @@ } }, + "CallToPrecompiledContract" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "currentGasLimit" : "1000000", + "currentNumber" : "0", + "currentTimestamp" : "2", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x4243434242434243f14555", + "data" : "0x", + "gas" : "10000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x4243434242434243f14555", + "nonce" : "0", + "storage" : { + } + } + } + }, + "CallToReturn1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From 4e2b5dd352b3cf59fae343ca7a68d6ed575b4204 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 12 Jan 2015 18:37:38 +0100 Subject: [PATCH 431/466] fixed running with qt 5.2 --- mix/qml/NewProjectDialog.qml | 4 ++-- mix/qml/ProjectList.qml | 1 - mix/qml/js/ProjectModel.js | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mix/qml/NewProjectDialog.qml b/mix/qml/NewProjectDialog.qml index 406dc02b2..9f88d5238 100644 --- a/mix/qml/NewProjectDialog.qml +++ b/mix/qml/NewProjectDialog.qml @@ -1,8 +1,8 @@ import QtQuick 2.2 -import QtQuick.Controls 1.2 +import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.0 -import QtQuick.Dialogs 1.2 +import QtQuick.Dialogs 1.1 Window { diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index 077aae28e..af3f4b155 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -80,7 +80,6 @@ Item { hoverEnabled: true z:2 onClicked: { - console.log("clicked"); textInput.forceActiveFocus(); } } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 7cf2b3018..836b75e13 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -90,7 +90,7 @@ function addFile(fileName) { name: isContract ? "Contract" : fileName, documentId: fileName, isText: isContract || extension === ".html" || extension === ".js", - isContract: fileData, + isContract: isContract, }; projectListModel.append(fileData); @@ -130,11 +130,11 @@ function doCreateProject(title, path) { var contractsFile = "contracts.sol"; var projectData = { title: title, - files: [ indexFile, contractsFile ] + files: [ contractsFile, indexFile ] }; //TODO: copy from template fileIo.writeFile(dirPath + indexFile, ""); - fileIo.writeFile(dirPath + contractsFile, "contract MyContract {\n }\n"); + fileIo.writeFile(dirPath + contractsFile, "contract MyContract {\n}\n"); var json = JSON.stringify(projectData); fileIo.writeFile(projectFile, json); loadProject(dirPath); From 720f49e19ade9319daf5086632000a2879242257 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 13 Jan 2015 09:53:46 +0100 Subject: [PATCH 432/466] reinclude invalid opcode in random tests --- test/createRandomTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index d9638cebe..d2522cf47 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -54,7 +54,7 @@ int main(int argc, char *argv[]) gen.seed(static_cast(timeSinceEpoch)); boost::random::uniform_int_distribution<> lengthOfCodeDist(2, 16); boost::random::uniform_int_distribution<> opcodeDist(0, 255); - boost::random::uniform_int_distribution<> BlockInfoOpcodeDist(0x41, 0x45); + boost::random::uniform_int_distribution<> BlockInfoOpcodeDist(0x40, 0x45); boost::random::variate_generator > randGen(gen, opcodeDist); boost::random::variate_generator Date: Tue, 13 Jan 2015 11:18:08 +0100 Subject: [PATCH 433/466] fixed warnings for msvc build --- cmake/EthCompilerSettings.cmake | 13 +++++++++++-- libserpent/rewriteutils.cpp | 2 +- libserpent/util.cpp | 2 +- libsolidity/AST.h | 0 libsolidity/CompilerContext.cpp | 4 ++-- libsolidity/CompilerContext.h | 6 +++--- libsolidity/CompilerStack.cpp | 2 +- libsolidity/Types.h | 2 +- libsolidity/Utils.h | 6 ++++++ test/SolidityEndToEndTest.cpp | 4 ++++ test/boostTest.cpp | 2 +- test/vm.cpp | 2 +- 12 files changed, 32 insertions(+), 13 deletions(-) mode change 100644 => 100755 cmake/EthCompilerSettings.cmake mode change 100644 => 100755 libserpent/rewriteutils.cpp mode change 100644 => 100755 libserpent/util.cpp mode change 100644 => 100755 libsolidity/AST.h mode change 100644 => 100755 libsolidity/Utils.h diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake old mode 100644 new mode 100755 index 24252cc0b..12adc1d02 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -28,8 +28,17 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # specify Exception Handling Model in msvc - set(CMAKE_C_FLAGS "/EHsc") - set(CMAKE_CXX_FLAGS "/EHsc") + # disable unknown pragma warning (4068) + # disable unsafe function warning (4996) + # disable decorated name length exceeded, name was truncated (4503) + # disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests) + # declare Windows XP requirement + add_compile_options(/EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501) + # disable empty object file warning + set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") + # warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification + # warning LNK4099: pdb was not found with lib + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075") # windows likes static set(ETH_STATIC 1) diff --git a/libserpent/rewriteutils.cpp b/libserpent/rewriteutils.cpp old mode 100644 new mode 100755 index e6429434a..7296a5e27 --- a/libserpent/rewriteutils.cpp +++ b/libserpent/rewriteutils.cpp @@ -54,7 +54,7 @@ bool isValidFunctionName(std::string f) { vfMap[validFunctions[i][0]] = true; } } - return vfMap.count(f); + return vfMap.count(f) != 0; } // Cool function for debug purposes (named cerrStringList to make diff --git a/libserpent/util.cpp b/libserpent/util.cpp old mode 100644 new mode 100755 index 4b99a5ea5..18a8bafc2 --- a/libserpent/util.cpp +++ b/libserpent/util.cpp @@ -260,7 +260,7 @@ std::string get_file_contents(std::string filename) { std::string contents; in.seekg(0, std::ios::end); - contents.resize(in.tellg()); + contents.resize((unsigned)in.tellg()); in.seekg(0, std::ios::beg); in.read(&contents[0], contents.size()); in.close(); diff --git a/libsolidity/AST.h b/libsolidity/AST.h old mode 100644 new mode 100755 diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index 18357bf0c..5d10a5f95 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -53,8 +53,8 @@ void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _decla { addVariable(_declaration); - unsigned const size = _declaration.getType()->getSizeOnStack(); - for (unsigned i = 0; i < size; ++i) + int const size = _declaration.getType()->getSizeOnStack(); + for (int i = 0; i < size; ++i) *this << u256(0); m_asm.adjustDeposit(-size); } diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 795f447ab..14672c956 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -51,10 +51,10 @@ public: void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } - bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration); } - bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration); } + bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; } + bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration) != 0; } bool isLocalVariable(Declaration const* _declaration) const; - bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration); } + bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration) != 0; } eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const; /// Returns the distance of the given local variable from the top of the local variable stack. diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 174f9cd22..904c77c5a 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -39,7 +39,7 @@ namespace solidity bool CompilerStack::addSource(string const& _name, string const& _content) { - bool existed = m_sources.count(_name); + bool existed = m_sources.count(_name) != 0; reset(true); m_sources[_name].scanner = make_shared(CharStream(_content), _name); return existed; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index deabe1160..1ccdd706a 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -178,7 +178,7 @@ public: int getNumBits() const { return m_bits; } bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } bool isAddress() const { return m_modifier == Modifier::ADDRESS; } - int isSigned() const { return m_modifier == Modifier::SIGNED; } + bool isSigned() const { return m_modifier == Modifier::SIGNED; } static const MemberList AddressMemberList; diff --git a/libsolidity/Utils.h b/libsolidity/Utils.h old mode 100644 new mode 100755 index 8d6a3ab08..1411f66b4 --- a/libsolidity/Utils.h +++ b/libsolidity/Utils.h @@ -45,5 +45,11 @@ inline void solAssertAux(bool _condition, std::string const& _errorDescription, << ::boost::throw_line(_line)); } +inline void solAssertAux(void const* _pointer, std::string const& _errorDescription, unsigned _line, + char const* _file, char const* _function) +{ + solAssertAux(_pointer != nullptr, _errorDescription, _line, _file, _function); +} + } } diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 2afe875f2..9543497a7 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -28,6 +28,10 @@ #include #include +#ifdef _MSC_VER +#pragma warning(disable: 4307) //integral constant overflow for high_bits_cleaning +#endif + using namespace std; namespace dev diff --git a/test/boostTest.cpp b/test/boostTest.cpp index cef3cc0a7..1523a7a11 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -23,6 +23,6 @@ #define BOOST_TEST_MODULE EthereumTests #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" +#define BOOST_DISABLE_WIN32 //disables SEH warning #include -#pragma warning(pop) #pragma GCC diagnostic pop diff --git a/test/vm.cpp b/test/vm.cpp index 6ae95f256..8b8c75a04 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -345,7 +345,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) output = vm->go(fev, fev.simpleTrace()).toBytes(); gas = vm->gas(); } - catch (VMException const& _e) + catch (VMException const&) { cnote << "Safe VM Exception"; vmExceptionOccured = true; From 7fd64c15964417ba8d6a5147e9cbd61ab8009eb1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 11:04:31 +0000 Subject: [PATCH 434/466] Fix for JS API formatting. --- libjsqrc/ethereumjs/lib/abi.js | 26 +++++++++++++++----------- libp2p/Host.cpp | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/libjsqrc/ethereumjs/lib/abi.js b/libjsqrc/ethereumjs/lib/abi.js index cae4f7519..1a88317bc 100644 --- a/libjsqrc/ethereumjs/lib/abi.js +++ b/libjsqrc/ethereumjs/lib/abi.js @@ -84,6 +84,18 @@ var calcRealPadding = function (type, expected) { var setupInputTypes = function () { + // convert from int, decimal-string, prefixed hex string whatever into a bare hex string. + var formatStandard = function (value) { + if (typeof value === "number") + return value.toString(16); + else if (typeof value === "string" && value.indexOf('0x') === 0) + return value.substr(2); + else if (typeof value === "string") + return web3.toHex(value); + else + return (+value).toString(16); + }; + var prefixedType = function (prefix, calcPadding) { return function (type, value) { var expected = prefix; @@ -98,15 +110,7 @@ var setupInputTypes = function () { if (prefix === "string") return web3.fromAscii(value, padding).substr(2); - if (typeof value === "number") - value = value.toString(16); - else if (typeof value === "string") - value = web3.toHex(value); - else if (value.indexOf('0x') === 0) - value = value.substr(2); - else - value = (+value).toString(16); - return padLeft(value, padding * 2); + return padLeft(formatStandard(value), padding * 2); }; }; @@ -123,7 +127,7 @@ var setupInputTypes = function () { }; var formatBool = function (value) { - return value ? '0x1' : '0x0'; + return value ? '01' : '00'; }; return [ @@ -133,7 +137,7 @@ var setupInputTypes = function () { prefixedType('string', calcBytePadding), prefixedType('real', calcRealPadding), prefixedType('ureal', calcRealPadding), - namedType('address', 20), + namedType('address', 20, formatStandard), namedType('bool', 1, formatBool), ]; }; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 4be6f228f..4cc985d65 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -184,7 +184,7 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, boo { RecursiveGuard l(x_peers); if (_a.port() < 30300 || _a.port() > 30305) - cwarn << "Weird port being recorded: " << _a.port(); + cwarn << "Non-standard port being recorded: " << _a.port(); if (_a.port() >= /*49152*/32768) { From 070f9b9a09145603135b5da76bcb7d5144b064b1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 11:06:43 +0000 Subject: [PATCH 435/466] Auto-generated commits, too. --- libjsqrc/ethereumjs/dist/ethereum.js | 26 ++++++++++++++---------- libjsqrc/ethereumjs/dist/ethereum.js.map | 4 ++-- libjsqrc/ethereumjs/dist/ethereum.min.js | 2 +- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/libjsqrc/ethereumjs/dist/ethereum.js b/libjsqrc/ethereumjs/dist/ethereum.js index 400a66815..a422171be 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js +++ b/libjsqrc/ethereumjs/dist/ethereum.js @@ -85,6 +85,18 @@ var calcRealPadding = function (type, expected) { var setupInputTypes = function () { + // convert from int, decimal-string, prefixed hex string whatever into a bare hex string. + var formatStandard = function (value) { + if (typeof value === "number") + return value.toString(16); + else if (typeof value === "string" && value.indexOf('0x') === 0) + return value.substr(2); + else if (typeof value === "string") + return web3.toHex(value); + else + return (+value).toString(16); + }; + var prefixedType = function (prefix, calcPadding) { return function (type, value) { var expected = prefix; @@ -99,15 +111,7 @@ var setupInputTypes = function () { if (prefix === "string") return web3.fromAscii(value, padding).substr(2); - if (typeof value === "number") - value = value.toString(16); - else if (typeof value === "string") - value = web3.toHex(value); - else if (value.indexOf('0x') === 0) - value = value.substr(2); - else - value = (+value).toString(16); - return padLeft(value, padding * 2); + return padLeft(formatStandard(value), padding * 2); }; }; @@ -124,7 +128,7 @@ var setupInputTypes = function () { }; var formatBool = function (value) { - return value ? '0x1' : '0x0'; + return value ? '01' : '00'; }; return [ @@ -134,7 +138,7 @@ var setupInputTypes = function () { prefixedType('string', calcBytePadding), prefixedType('real', calcRealPadding), prefixedType('ureal', calcRealPadding), - namedType('address', 20), + namedType('address', 20, formatStandard), namedType('bool', 1, formatBool), ]; }; diff --git a/libjsqrc/ethereumjs/dist/ethereum.js.map b/libjsqrc/ethereumjs/dist/ethereum.js.map index e60f94922..4a38cddfd 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js.map +++ b/libjsqrc/ethereumjs/dist/ethereum.js.map @@ -12,12 +12,12 @@ "index.js" ], "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "file": "generated.js", "sourceRoot": "", "sourcesContent": [ "(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o.\n*/\n/** @file abi.js\n * @authors:\n * Marek Kotewicz \n * Gav Wood \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\n// TODO: make these be actually accurate instead of falling back onto JS's doubles.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\nvar findMethodIndex = function (json, methodName) {\n return findIndex(json, function (method) {\n return method.name === methodName;\n });\n};\n\nvar padLeft = function (string, chars) {\n return new Array(chars - string.length + 1).join(\"0\") + string;\n};\n\nvar calcBitPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value) / 8;\n};\n\nvar calcBytePadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value);\n};\n\nvar calcRealPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n var sizes = value.split('x');\n for (var padding = 0, i = 0; i < sizes; i++) {\n padding += (sizes[i] / 8);\n }\n return padding;\n};\n\nvar setupInputTypes = function () {\n \n var prefixedType = function (prefix, calcPadding) {\n return function (type, value) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return false;\n }\n\n var padding = calcPadding(type, expected);\n if (padding > 32)\n return false; // not allowed to be so big.\n padding = 32; // override as per the new ABI.\n\n if (prefix === \"string\")\n return web3.fromAscii(value, padding).substr(2);\n if (typeof value === \"number\")\n value = value.toString(16);\n else if (typeof value === \"string\")\n value = web3.toHex(value); \n else if (value.indexOf('0x') === 0)\n value = value.substr(2);\n else\n value = (+value).toString(16);\n return padLeft(value, padding * 2);\n };\n };\n\n var namedType = function (name, padding, formatter) {\n return function (type, value) {\n if (type !== name) {\n return false;\n }\n\n padding = 32; //override as per the new ABI.\n\n return padLeft(formatter ? formatter(value) : value, padding * 2);\n };\n };\n\n var formatBool = function (value) {\n return value ? '0x1' : '0x0';\n };\n\n return [\n prefixedType('uint', calcBitPadding),\n prefixedType('int', calcBitPadding),\n prefixedType('hash', calcBitPadding),\n prefixedType('string', calcBytePadding),\n prefixedType('real', calcRealPadding),\n prefixedType('ureal', calcRealPadding),\n namedType('address', 20),\n namedType('bool', 1, formatBool),\n ];\n};\n\nvar inputTypes = setupInputTypes();\n\nvar toAbiInput = function (json, methodName, params) {\n var bytes = \"\";\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n var method = json[index];\n\n for (var i = 0; i < method.inputs.length; i++) {\n var found = false;\n for (var j = 0; j < inputTypes.length && !found; j++) {\n found = inputTypes[j](method.inputs[i].type, params[i]);\n }\n if (!found) {\n console.error('unsupported json type: ' + method.inputs[i].type);\n }\n bytes += found;\n }\n return bytes;\n};\n\nvar setupOutputTypes = function () {\n\n var prefixedType = function (prefix, calcPadding) {\n return function (type) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return -1;\n }\n\n var padding = calcPadding(type, expected);\n if (padding > 32)\n return -1; // not allowed to be so big.\n padding = 32; // override as per the new ABI.\n return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\n padding = 32; // override as per the new ABI.\n return name === type ? padding * 2 : -1;\n };\n };\n\n var formatInt = function (value) {\n return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);\n };\n\n var formatHash = function (value) {\n return \"0x\" + value;\n };\n\n var formatBool = function (value) {\n return value === '1' ? true : false;\n };\n\n var formatString = function (value) {\n return web3.toAscii(value);\n };\n\n return [\n { padding: prefixedType('uint', calcBitPadding), format: formatInt },\n { padding: prefixedType('int', calcBitPadding), format: formatInt },\n { padding: prefixedType('hash', calcBitPadding), format: formatHash },\n { padding: prefixedType('string', calcBytePadding), format: formatString },\n { padding: prefixedType('real', calcRealPadding), format: formatInt },\n { padding: prefixedType('ureal', calcRealPadding), format: formatInt },\n { padding: namedType('address', 20) },\n { padding: namedType('bool', 1), format: formatBool }\n ];\n};\n\nvar outputTypes = setupOutputTypes();\n\nvar fromAbiOutput = function (json, methodName, output) {\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n output = output.slice(2);\n\n var result = [];\n var method = json[index];\n for (var i = 0; i < method.outputs.length; i++) {\n var padding = -1;\n for (var j = 0; j < outputTypes.length && padding === -1; j++) {\n padding = outputTypes[j].padding(method.outputs[i].type);\n }\n\n if (padding === -1) {\n // not found output parsing\n continue;\n }\n var res = output.slice(0, padding);\n var formatter = outputTypes[j - 1].format;\n result.push(formatter ? formatter(res) : (\"0x\" + res));\n output = output.slice(padding);\n }\n\n return result;\n};\n\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n return toAbiInput(json, method.name, params);\n };\n });\n\n return parser;\n};\n\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function (output) {\n return fromAbiOutput(json, method.name, output);\n };\n });\n\n return parser;\n};\n\nvar methodSignature = function (json, name) {\n var method = json[findMethodIndex(json, name)];\n var result = name + '(';\n var inputTypes = method.inputs.map(function (inp) {\n return inp.type;\n });\n result += inputTypes.join(',');\n result += ')';\n\n return web3.sha3(web3.fromAscii(result));\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file abi.js\n * @authors:\n * Marek Kotewicz \n * Gav Wood \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\n// TODO: make these be actually accurate instead of falling back onto JS's doubles.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\nvar findMethodIndex = function (json, methodName) {\n return findIndex(json, function (method) {\n return method.name === methodName;\n });\n};\n\nvar padLeft = function (string, chars) {\n return new Array(chars - string.length + 1).join(\"0\") + string;\n};\n\nvar calcBitPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value) / 8;\n};\n\nvar calcBytePadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value);\n};\n\nvar calcRealPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n var sizes = value.split('x');\n for (var padding = 0, i = 0; i < sizes; i++) {\n padding += (sizes[i] / 8);\n }\n return padding;\n};\n\nvar setupInputTypes = function () {\n \n // convert from int, decimal-string, prefixed hex string whatever into a bare hex string.\n var formatStandard = function (value) {\n if (typeof value === \"number\")\n return value.toString(16);\n else if (typeof value === \"string\" && value.indexOf('0x') === 0)\n return value.substr(2);\n else if (typeof value === \"string\")\n return web3.toHex(value);\n else\n return (+value).toString(16);\n };\n\n var prefixedType = function (prefix, calcPadding) {\n return function (type, value) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return false;\n }\n\n var padding = calcPadding(type, expected);\n if (padding > 32)\n return false; // not allowed to be so big.\n padding = 32; // override as per the new ABI.\n\n if (prefix === \"string\")\n return web3.fromAscii(value, padding).substr(2);\n return padLeft(formatStandard(value), padding * 2);\n };\n };\n\n var namedType = function (name, padding, formatter) {\n return function (type, value) {\n if (type !== name) {\n return false;\n }\n\n padding = 32; //override as per the new ABI.\n\n return padLeft(formatter ? formatter(value) : value, padding * 2);\n };\n };\n\n var formatBool = function (value) {\n return value ? '01' : '00';\n };\n\n return [\n prefixedType('uint', calcBitPadding),\n prefixedType('int', calcBitPadding),\n prefixedType('hash', calcBitPadding),\n prefixedType('string', calcBytePadding),\n prefixedType('real', calcRealPadding),\n prefixedType('ureal', calcRealPadding),\n namedType('address', 20, formatStandard),\n namedType('bool', 1, formatBool),\n ];\n};\n\nvar inputTypes = setupInputTypes();\n\nvar toAbiInput = function (json, methodName, params) {\n var bytes = \"\";\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n var method = json[index];\n\n for (var i = 0; i < method.inputs.length; i++) {\n var found = false;\n for (var j = 0; j < inputTypes.length && !found; j++) {\n found = inputTypes[j](method.inputs[i].type, params[i]);\n }\n if (!found) {\n console.error('unsupported json type: ' + method.inputs[i].type);\n }\n bytes += found;\n }\n return bytes;\n};\n\nvar setupOutputTypes = function () {\n\n var prefixedType = function (prefix, calcPadding) {\n return function (type) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return -1;\n }\n\n var padding = calcPadding(type, expected);\n if (padding > 32)\n return -1; // not allowed to be so big.\n padding = 32; // override as per the new ABI.\n return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\n padding = 32; // override as per the new ABI.\n return name === type ? padding * 2 : -1;\n };\n };\n\n var formatInt = function (value) {\n return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);\n };\n\n var formatHash = function (value) {\n return \"0x\" + value;\n };\n\n var formatBool = function (value) {\n return value === '1' ? true : false;\n };\n\n var formatString = function (value) {\n return web3.toAscii(value);\n };\n\n return [\n { padding: prefixedType('uint', calcBitPadding), format: formatInt },\n { padding: prefixedType('int', calcBitPadding), format: formatInt },\n { padding: prefixedType('hash', calcBitPadding), format: formatHash },\n { padding: prefixedType('string', calcBytePadding), format: formatString },\n { padding: prefixedType('real', calcRealPadding), format: formatInt },\n { padding: prefixedType('ureal', calcRealPadding), format: formatInt },\n { padding: namedType('address', 20) },\n { padding: namedType('bool', 1), format: formatBool }\n ];\n};\n\nvar outputTypes = setupOutputTypes();\n\nvar fromAbiOutput = function (json, methodName, output) {\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n output = output.slice(2);\n\n var result = [];\n var method = json[index];\n for (var i = 0; i < method.outputs.length; i++) {\n var padding = -1;\n for (var j = 0; j < outputTypes.length && padding === -1; j++) {\n padding = outputTypes[j].padding(method.outputs[i].type);\n }\n\n if (padding === -1) {\n // not found output parsing\n continue;\n }\n var res = output.slice(0, padding);\n var formatter = outputTypes[j - 1].format;\n result.push(formatter ? formatter(res) : (\"0x\" + res));\n output = output.slice(padding);\n }\n\n return result;\n};\n\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n return toAbiInput(json, method.name, params);\n };\n });\n\n return parser;\n};\n\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function (output) {\n return fromAbiOutput(json, method.name, output);\n };\n });\n\n return parser;\n};\n\nvar methodSignature = function (json, name) {\n var method = json[findMethodIndex(json, name)];\n var result = name + '(';\n var inputTypes = method.inputs.map(function (inp) {\n return inp.type;\n });\n result += inputTypes.join(',');\n result += ')';\n\n return web3.sha3(web3.fromAscii(result));\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file autoprovider.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\n/*\n * @brief if qt object is available, uses QtProvider,\n * if not tries to connect over websockets\n * if it fails, it uses HttpRpcProvider\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var WebSocket = require('ws'); // jshint ignore:line\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\nvar AutoProvider = function (userOptions) {\n if (web3.haveProvider()) {\n return;\n }\n\n // before we determine what provider we are, we have to cache request\n this.sendQueue = [];\n this.onmessageQueue = [];\n\n if (navigator.qt) {\n this.provider = new web3.providers.QtProvider();\n return;\n }\n\n userOptions = userOptions || {};\n var options = {\n httprpc: userOptions.httprpc || 'http://localhost:8080',\n websockets: userOptions.websockets || 'ws://localhost:40404/eth'\n };\n\n var self = this;\n var closeWithSuccess = function (success) {\n ws.close();\n if (success) {\n self.provider = new web3.providers.WebSocketProvider(options.websockets);\n } else {\n self.provider = new web3.providers.HttpRpcProvider(options.httprpc);\n self.poll = self.provider.poll.bind(self.provider);\n }\n self.sendQueue.forEach(function (payload) {\n self.provider(payload);\n });\n self.onmessageQueue.forEach(function (handler) {\n self.provider.onmessage = handler;\n });\n };\n\n var ws = new WebSocket(options.websockets);\n\n ws.onopen = function() {\n closeWithSuccess(true);\n };\n\n ws.onerror = function() {\n closeWithSuccess(false);\n };\n};\n\nAutoProvider.prototype.send = function (payload) {\n if (this.provider) {\n this.provider.send(payload);\n return;\n }\n this.sendQueue.push(payload);\n};\n\nObject.defineProperty(AutoProvider.prototype, 'onmessage', {\n set: function (handler) {\n if (this.provider) {\n this.provider.onmessage = handler;\n return;\n }\n this.onmessageQueue.push(handler);\n }\n});\n\nmodule.exports = AutoProvider;\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\nvar abi = require('./abi');\n\n// method signature length in bytes\nvar ETH_METHOD_SIGNATURE_LENGTH = 4;\n\nvar contract = function (address, desc) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n var contract = {};\n\n desc.forEach(function (method) {\n contract[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n var parsed = inputParser[method.name].apply(null, params);\n\n var onSuccess = function (result) {\n return outputParser[method.name](result);\n };\n\n return {\n call: function (extra) {\n extra = extra || {};\n extra.to = address;\n return abi.methodSignature(desc, method.name).then(function (signature) {\n extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;\n return web3.eth.call(extra).then(onSuccess);\n });\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n return abi.methodSignature(desc, method.name).then(function (signature) {\n extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;\n return web3.eth.transact(extra).then(onSuccess);\n });\n }\n };\n };\n });\n\n return contract;\n};\n\nmodule.exports = contract;\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httprpc.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpRpcProvider = function (host) {\n this.handlers = [];\n this.host = host;\n};\n\nfunction formatJsonRpcObject(object) {\n return {\n jsonrpc: '2.0',\n method: object.call,\n params: object.args,\n id: object._id\n };\n}\n\nfunction formatJsonRpcMessage(message) {\n var object = JSON.parse(message);\n\n return {\n _id: object.id,\n data: object.result,\n error: object.error\n };\n}\n\nHttpRpcProvider.prototype.sendRequest = function (payload, cb) {\n var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open(\"POST\", this.host, true);\n request.send(JSON.stringify(data));\n request.onreadystatechange = function () {\n if (request.readyState === 4 && cb) {\n cb(request);\n }\n };\n};\n\nHttpRpcProvider.prototype.send = function (payload) {\n var self = this;\n this.sendRequest(payload, function (request) {\n self.handlers.forEach(function (handler) {\n handler.call(self, formatJsonRpcMessage(request.responseText));\n });\n });\n};\n\nHttpRpcProvider.prototype.poll = function (payload, id) {\n var self = this;\n this.sendRequest(payload, function (request) {\n var parsed = JSON.parse(request.responseText);\n if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) {\n return;\n }\n self.handlers.forEach(function (handler) {\n handler.call(self, {_event: payload.call, _id: id, data: parsed.result});\n });\n });\n};\n\nObject.defineProperty(HttpRpcProvider.prototype, \"onmessage\", {\n set: function (handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = HttpRpcProvider;\n", diff --git a/libjsqrc/ethereumjs/dist/ethereum.min.js b/libjsqrc/ethereumjs/dist/ethereum.min.js index 1d909e464..1eae35bd3 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.min.js +++ b/libjsqrc/ethereumjs/dist/ethereum.min.js @@ -1 +1 @@ -require=function t(e,n,r){function o(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ai;i++)o+=r[i]/8;return o},c=function(){var t=function(t,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return a>32?!1:(a=32,"string"===t?web3.fromAscii(r,a).substr(2):(r="number"==typeof r?r.toString(16):"string"==typeof r?web3.toHex(r):0===r.indexOf("0x")?r.substr(2):(+r).toString(16),i(r,2*a)))}},e=function(t,e,n){return function(r,o){return r!==t?!1:(e=32,i(n?n(o):o,2*e))}},n=function(t){return t?"0x1":"0x0"};return[t("uint",a),t("int",a),t("hash",a),t("string",s),t("real",u),t("ureal",u),e("address",20),e("bool",1,n)]},l=c(),h=function(t,e,n){var r="",i=o(t,e);if(-1!==i){for(var a=t[i],s=0;s32?-1:(o=32,2*o)}},e=function(t,e){return function(n){return e=32,t===n?2*e:-1}},r=function(t){return t.length<=8?+parseInt(t,16):n(t)},o=function(t){return"0x"+t},i=function(t){return"1"===t?!0:!1},c=function(t){return web3.toAscii(t)};return[{padding:t("uint",a),format:r},{padding:t("int",a),format:r},{padding:t("hash",a),format:o},{padding:t("string",s),format:c},{padding:t("real",u),format:r},{padding:t("ureal",u),format:r},{padding:e("address",20)},{padding:e("bool",1),format:i}]},p=f(),d=function(t,e,n){var r=o(t,e);if(-1!==r){n=n.slice(2);for(var i=[],a=t[r],s=0;sn;n+=2){var o=t.charCodeAt(n);if(0===o)break;e+=String.fromCharCode(parseInt(t.substr(n,2),16))}return e},fromAscii:function(t,e){e=void 0===e?0:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return p(t.substring(2))},fromDecimal:function(t){return"0x"+d(t)},toEth:function(t){for(var e="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,n=0,r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e>3e3&&ni;i++)o+=r[i]/8;return o},c=function(){var t=function(t){return"number"==typeof t?t.toString(16):"string"==typeof t&&0===t.indexOf("0x")?t.substr(2):"string"==typeof t?web3.toHex(t):(+t).toString(16)},e=function(e,n){return function(r,o){var a=e;if(0!==r.indexOf(a))return!1;var s=n(r,a);return s>32?!1:(s=32,"string"===e?web3.fromAscii(o,s).substr(2):i(t(o),2*s))}},n=function(t,e,n){return function(r,o){return r!==t?!1:(e=32,i(n?n(o):o,2*e))}},r=function(t){return t?"01":"00"};return[e("uint",a),e("int",a),e("hash",a),e("string",s),e("real",u),e("ureal",u),n("address",20,t),n("bool",1,r)]},l=c(),h=function(t,e,n){var r="",i=o(t,e);if(-1!==i){for(var a=t[i],s=0;s32?-1:(o=32,2*o)}},e=function(t,e){return function(n){return e=32,t===n?2*e:-1}},r=function(t){return t.length<=8?+parseInt(t,16):n(t)},o=function(t){return"0x"+t},i=function(t){return"1"===t?!0:!1},c=function(t){return web3.toAscii(t)};return[{padding:t("uint",a),format:r},{padding:t("int",a),format:r},{padding:t("hash",a),format:o},{padding:t("string",s),format:c},{padding:t("real",u),format:r},{padding:t("ureal",u),format:r},{padding:e("address",20)},{padding:e("bool",1),format:i}]},p=f(),d=function(t,e,n){var r=o(t,e);if(-1!==r){n=n.slice(2);for(var i=[],a=t[r],s=0;sn;n+=2){var o=t.charCodeAt(n);if(0===o)break;e+=String.fromCharCode(parseInt(t.substr(n,2),16))}return e},fromAscii:function(t,e){e=void 0===e?0:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return p(t.substring(2))},fromDecimal:function(t){return"0x"+d(t)},toEth:function(t){for(var e="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,n=0,r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e>3e3&&n Date: Tue, 13 Jan 2015 12:08:19 +0000 Subject: [PATCH 436/466] Add merge master script. --- mergeMaster.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 mergeMaster.sh diff --git a/mergeMaster.sh b/mergeMaster.sh new file mode 100755 index 000000000..a55502799 --- /dev/null +++ b/mergeMaster.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +git checkout master && git merge --no-ff $1+ && git push && git tag -f $1 && git push --tags -f + From 799e09508ead08ac13fbe39cb368a2e5fa5166ce Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 12:10:30 +0000 Subject: [PATCH 437/466] New ignores for node modules. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2c9d286d2..b6abc22a3 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,4 @@ project.pbxproj evmjit doc/html *.autosave +node_modules/ From 51a4ae1807f1e9e40eec47f2c11757488f5101f8 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 13 Jan 2015 14:22:12 +0100 Subject: [PATCH 438/466] check test with JIT for random test simulations --- test/CMakeLists.txt | 6 + test/checkRandomTest.cpp | 279 ++++++++++++++++++++++++++++++++++++++ test/createRandomTest.cpp | 2 + test/vm.cpp | 34 ----- 4 files changed, 287 insertions(+), 34 deletions(-) create mode 100644 test/checkRandomTest.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7cedc117b..764bf928e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_policy(SET CMP0015 NEW) aux_source_directory(. SRC_LIST) list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp") +list(REMOVE_ITEM SRC_LIST "./checkRandomTest.cpp") include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) @@ -12,6 +13,7 @@ include_directories(..) file(GLOB HEADERS "*.h") add_executable(testeth ${SRC_LIST} ${HEADERS}) add_executable(createRandomTest createRandomTest.cpp vm.cpp TestHelper.cpp) +add_executable(checkRandomTest checkRandomTest.cpp vm.cpp TestHelper.cpp) target_link_libraries(testeth ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) target_link_libraries(testeth ${CURL_LIBRARIES}) @@ -29,3 +31,7 @@ endif() target_link_libraries(createRandomTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) target_link_libraries(createRandomTest ethereum) target_link_libraries(createRandomTest ethcore) +target_link_libraries(checkRandomTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) +target_link_libraries(checkRandomTest ethereum) +target_link_libraries(checkRandomTest ethcore) + diff --git a/test/checkRandomTest.cpp b/test/checkRandomTest.cpp new file mode 100644 index 000000000..4299cdac8 --- /dev/null +++ b/test/checkRandomTest.cpp @@ -0,0 +1,279 @@ +/* + 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 checkRandomTest.cpp + * @author Christoph Jentzsch + * @date 2015 + * Check a random test and return 0/1 for success or failure. To be used for efficiency in the random test simulation. + */ + +#include +#include +#include +#include +#include "vm.h" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +using namespace std; +using namespace json_spirit; +using namespace dev::test; +using namespace dev; + +bool doVMTest(mValue& v); + +int main(int argc, char *argv[]) +{ + g_logVerbosity = 0; + bool ret = false; + + try + { + mValue v; + string s; + for (int i = 1; i < argc; ++i) + s += argv[i]; + if (asserts(s.length() > 0)) + { + cout << "Content of argument is empty\n"; + return 1; + } + read_string(s, v); + ret = doVMTest(v); + } + catch (Exception const& _e) + { + cout << "Failed test with Exception: " << diagnostic_information(_e) << endl; + ret = false; + } + catch (std::exception const& _e) + { + cout << "Failed test with Exception: " << _e.what() << endl; + ret = false; + } + return ret; +} + +bool doVMTest(mValue& v) +{ + eth::VMFactory::setKind(eth::VMKind::JIT); + + for (auto& i: v.get_obj()) + { + cnote << i.first; + mObject& o = i.second.get_obj(); + + assert(o.count("env") > 0); + assert(o.count("pre") > 0); + assert(o.count("exec") > 0); + + FakeExtVM fev; + fev.importEnv(o["env"].get_obj()); + fev.importState(o["pre"].get_obj()); + + fev.importExec(o["exec"].get_obj()); + if (fev.code.empty()) + { + fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); + fev.code = fev.thisTxCode; + } + + bytes output; + u256 gas; + bool vmExceptionOccured = false; + try + { + auto vm = eth::VMFactory::create(fev.gas); + output = vm->go(fev, fev.simpleTrace()).toBytes(); + gas = vm->gas(); + } + catch (eth::VMException const& _e) + { + cnote << "Safe VM Exception"; + vmExceptionOccured = true; + } + catch (Exception const& _e) + { + cnote << "VM did throw an exception: " << diagnostic_information(_e); + cnote << "Failed VM Test with Exception: " << _e.what(); + return 1; + } + catch (std::exception const& _e) + { + cnote << "VM did throw an exception: " << _e.what(); + cnote << "Failed VM Test with Exception: " << _e.what(); + return 1; + } + + // delete null entries in storage for the sake of comparison + for (auto &a: fev.addresses) + { + vector keystoDelete; + for (auto &s: get<2>(a.second)) + { + if (s.second == 0) + keystoDelete.push_back(s.first); + } + for (auto const key: keystoDelete ) + { + get<2>(a.second).erase(key); + } + } + + if (o.count("post") > 0) // No exceptions expected + { + if (asserts(!vmExceptionOccured) || asserts(o.count("post") > 0) || asserts(o.count("callcreates") > 0) || asserts(o.count("out") > 0) || asserts(o.count("gas") > 0) || asserts(o.count("logs") > 0)) + return 1; + + dev::test::FakeExtVM test; + test.importState(o["post"].get_obj()); + test.importCallCreates(o["callcreates"].get_array()); + test.sub.logs = importLog(o["logs"].get_array()); + + //checkOutput(output, o); + int j = 0; + if (o["out"].type() == array_type) + for (auto const& d: o["out"].get_array()) + { + if (asserts(output[j] == toInt(d))) + { + cout << "Output byte [" << j << "] different!"; + return 1; + } + ++j; + } + else if (o["out"].get_str().find("0x") == 0) + { + if (asserts(output == fromHex(o["out"].get_str().substr(2)))) + return 1; + } + else + { + if (asserts(output == fromHex(o["out"].get_str()))) + return 1; + } + + if (asserts(toInt(o["gas"]) == gas)) + return 1; + + 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()) + { + cout << "Missing expected address " << expectedAddr; + return 1; + } + else + { + auto& expectedState = expectedPair.second; + auto& resultState = resultAddrIt->second; + if (asserts(std::get<0>(expectedState) == std::get<0>(resultState))) + { + cout << expectedAddr << ": incorrect balance " << std::get<0>(resultState) << ", expected " << std::get<0>(expectedState); + return 1; + } + if (asserts(std::get<1>(expectedState) == std::get<1>(resultState))) + { + cout << expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState); + return 1; + } + if (asserts(std::get<3>(expectedState) == std::get<3>(resultState))) + { + cout << expectedAddr << ": incorrect code"; + return 1; + } + + //checkStorage(std::get<2>(expectedState), std::get<2>(resultState), expectedAddr); + for (auto&& expectedStorePair : std::get<2>(expectedState)) + { + auto& expectedStoreKey = expectedStorePair.first; + auto resultStoreIt = std::get<2>(resultState).find(expectedStoreKey); + if (resultStoreIt == std::get<2>(resultState).end()) + { + cout << expectedAddr << ": missing store key " << expectedStoreKey << endl; + return 1; + } + else + { + auto& expectedStoreValue = expectedStorePair.second; + auto& resultStoreValue = resultStoreIt->second; + if (asserts(expectedStoreValue == resultStoreValue)) + { + cout << expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue << endl; + return 1; + } + } + } + if (assertsEqual(std::get<2>(resultState).size(), std::get<2>(expectedState).size())) + return 1; + for (auto&& resultStorePair: std::get<2>(resultState)) + { + if (!std::get<2>(expectedState).count(resultStorePair.first)) + { + cout << expectedAddr << ": unexpected store key " << resultStorePair.first << endl; + return 1; + } + } + } + } + + //checkAddresses, bytes> > >(test.addresses, fev.addresses); + for (auto& resultPair : fev.addresses) + { + auto& resultAddr = resultPair.first; + auto expectedAddrIt = test.addresses.find(resultAddr); + if (expectedAddrIt == test.addresses.end()) + { + cout << "Missing result address " << resultAddr << endl; + return 1; + } + } + if (asserts(test.addresses == fev.addresses)) + return 1; + + if (asserts(test.callcreates == fev.callcreates)) + return 1; + + //checkLog(fev.sub.logs, test.sub.logs); + { + if (assertsEqual(fev.sub.logs.size(), test.sub.logs.size())) + return 1; + + for (size_t i = 0; i < fev.sub.logs.size(); ++i) + { + if (assertsEqual(fev.sub.logs[i].address, test.sub.logs[i].address)) + return 1; + if (assertsEqual(fev.sub.logs[i].topics, test.sub.logs[i].topics)) + return 1; + if (asserts(fev.sub.logs[i].data == test.sub.logs[i].data)) + return 1; + } + } + + } + else // Exception expected + { + if (asserts(vmExceptionOccured)) + return 1; + } + } + // test passed + return 0; +} + diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 1af12f64d..b3700fd0f 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -119,6 +119,8 @@ int main(int argc, char *argv[]) void doMyTests(json_spirit::mValue& v) { + eth::VMFactory::setKind(eth::VMKind::Interpreter); + for (auto& i: v.get_obj()) { cnote << i.first; diff --git a/test/vm.cpp b/test/vm.cpp index 8187378e5..6ae95f256 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -560,40 +560,6 @@ BOOST_AUTO_TEST_CASE(vmRandom) } } -BOOST_AUTO_TEST_CASE(checkRandomTest) -{ - for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) - { - string arg = boost::unit_test::framework::master_test_suite().argv[i]; - if (arg == "--randomTest") - { - try - { - cout << "RANDOM::::::RANDOM" << endl; - json_spirit::mValue v; - string s;// = boost::unit_test::framework::master_test_suite().argv[i + 1]; - string line; - while ( getline(cin, line) && !line.empty() ) - s += line; - cout << "my test: AAAHHHAAA: \n" << s << endl; - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of argument is empty"); - json_spirit::read_string(s, v); - doVMTests(v, false); - cout << "RANDOM::::::RANDOM--done" << endl; - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed test with Exception: " << _e.what()); - } - break; - } - } -} - BOOST_AUTO_TEST_CASE(userDefinedFileVM) { dev::test::userDefinedTest("--vmtest", dev::test::doVMTests); From dc76791dbbc482ab4165753b05ccbf0ff4bbe2cd Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 13 Jan 2015 14:38:36 +0100 Subject: [PATCH 439/466] random test optimization --- test/createRandomTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index d2522cf47..b3a704e9d 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) \"currentNumber\" : \"0\",\n\ \"currentGasLimit\" : \"1000000\",\n\ \"currentDifficulty\" : \"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\n\ - \"currentTimestamp\" : 5,\n\ + \"currentTimestamp\" : 2,\n\ \"currentCoinbase\" : \"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\"\n\ },\n\ \"pre\" : {\n\ From 6e62485aa2c92ce815b8a1c1ac915413bf7df39d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 13:50:43 +0000 Subject: [PATCH 440/466] Fix for filters/watches. --- CMakeLists.txt | 12 +++++++++++- libethereum/Client.cpp | 7 +++++-- libethereum/Client.h | 5 ++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e5be63eb..f1246e152 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,7 @@ endfunction() function(createBuildInfo) # Set build platform; to be written to BuildInfo.h - set(ETH_BUILD_PLATFORM ${TARGET_PLATFORM}) + set(ETH_BUILD_PLATFORM "${TARGET_PLATFORM}") if (CMAKE_COMPILER_IS_MINGW) set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/mingw") elseif (CMAKE_COMPILER_IS_MSYS) @@ -64,6 +64,16 @@ function(createBuildInfo) set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/unknown") endif () + if (EVMJIT) + set(ETH_BUILD_PLATFORM "${TARGET_PLATFORM}/JIT") + else () + set(ETH_BUILD_PLATFORM "${TARGET_PLATFORM}/int") + endif () + + if (PARANOIA) + set(ETH_BUILD_PLATFORM "${TARGET_PLATFORM}/PARA") + endif () + #cmake build type may be not specified when using msvc if (CMAKE_BUILD_TYPE) set(_cmake_build_type ${CMAKE_BUILD_TYPE}) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index c963ee401..41f0bcfbc 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -185,6 +185,8 @@ unsigned Client::installWatch(h256 _h) cwatch << "+++" << ret << _h; } auto ch = logs(ret); + if (ch.empty()) + ch.push_back(InitialChange); { Guard l(m_filterLock); swap(m_watches[ret].changes, ch); @@ -229,9 +231,10 @@ void Client::noteChanged(h256Set const& _filters) if (_filters.count(i.second.id)) { // cwatch << "!!!" << i.first << i.second.id; - try { + if (m_filters.count(i.second.id)) i.second.changes += m_filters.at(i.second.id).changes; - } catch(...){} + else + i.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); } // clear the filters now. for (auto& i: m_filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index d0dce4cc1..824190b6f 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -84,13 +84,16 @@ struct InstalledFilter static const h256 PendingChangedFilter = u256(0); static const h256 ChainChangedFilter = u256(1); +static const LogEntry SpecialLogEntry = LogEntry(Address(), h256s(), bytes()); +static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0); + struct ClientWatch { ClientWatch() {} explicit ClientWatch(h256 _id): id(_id) {} h256 id; - LocalisedLogEntries changes; + LocalisedLogEntries changes = { InitialChange }; }; struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; }; From ba6fc4efe03dfccb6c0f65fcb88fe25382597a1c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 14:17:27 +0000 Subject: [PATCH 441/466] Fix #597 --- eth/main.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index dfe020763..515197ddc 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -270,13 +270,14 @@ int main(int argc, char** argv) mining = ~(unsigned)0; else if (isFalse(m)) mining = 0; - else if (int i = stoi(m)) - mining = i; else - { - cerr << "Unknown -m/--mining option: " << m << endl; - return -1; - } + try { + mining = stoi(m); + } + catch (...) { + cerr << "Unknown -m/--mining option: " << m << endl; + return -1; + } } else if (arg == "-b" || arg == "--bootstrap") bootstrap = true; From 165c33395e5b72ce6c36f69d79cba2ada9b7438e Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 13 Jan 2015 15:47:36 +0100 Subject: [PATCH 442/466] fix callcreates imoport --- test/TestHelper.cpp | 13 +++++++++++++ test/TestHelper.h | 2 ++ test/vm.cpp | 7 ++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index ff330d60e..355a5080d 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -350,6 +350,19 @@ void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs) } } +void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates) +{ + BOOST_REQUIRE_EQUAL(_resultCallCreates.size(), _expectedCallCreates.size()); + + for (size_t i = 0; i < _resultCallCreates.size(); ++i) + { + BOOST_CHECK(_resultCallCreates[i].data() == _expectedCallCreates[i].data()); + BOOST_CHECK(_resultCallCreates[i].receiveAddress() == _expectedCallCreates[i].receiveAddress()); + BOOST_CHECK(_resultCallCreates[i].gas() == _expectedCallCreates[i].gas()); + BOOST_CHECK(_resultCallCreates[i].value() == _expectedCallCreates[i].value()); + } +} + std::string getTestPath() { string testPath; diff --git a/test/TestHelper.h b/test/TestHelper.h index 85017c842..2ef5c6d53 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -73,6 +73,8 @@ json_spirit::mArray exportLog(eth::LogEntries _logs); void checkOutput(bytes const& _output, json_spirit::mObject& _o); void checkStorage(std::map _expectedStore, std::map _resultStore, Address _expectedAddr); void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs); +void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates); + void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function doTests); std::string getTestPath(); void userDefinedTest(std::string testTypeFlag, std::function doTests); diff --git a/test/vm.cpp b/test/vm.cpp index 8b8c75a04..8af752caa 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -237,8 +237,8 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) BOOST_REQUIRE(tx.count("destination") > 0); BOOST_REQUIRE(tx.count("gasLimit") > 0); Transaction t = tx["destination"].get_str().empty() ? - Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), data.toBytes()) : - Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), Address(tx["destination"].get_str()), data.toBytes()); + Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), fromHex(tx["data"].get_str())) : + Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), Address(tx["destination"].get_str()), fromHex(tx["data"].get_str())); callcreates.push_back(t); } } @@ -448,7 +448,8 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) } checkAddresses, bytes> > >(test.addresses, fev.addresses); - BOOST_CHECK(test.callcreates == fev.callcreates); + + checkCallCreates(fev.callcreates, test.callcreates); checkLog(fev.sub.logs, test.sub.logs); } From f401d34ac8599f1901ef293e69675b1f28e328a5 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 13 Jan 2015 15:59:07 +0100 Subject: [PATCH 443/466] fix spaces->tab, detailed callcreate check --- test/checkRandomTest.cpp | 474 ++++++++++++++++++++------------------- 1 file changed, 246 insertions(+), 228 deletions(-) diff --git a/test/checkRandomTest.cpp b/test/checkRandomTest.cpp index 4299cdac8..e3442d438 100644 --- a/test/checkRandomTest.cpp +++ b/test/checkRandomTest.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 checkRandomTest.cpp * @author Christoph Jentzsch @@ -36,244 +36,262 @@ bool doVMTest(mValue& v); int main(int argc, char *argv[]) { - g_logVerbosity = 0; - bool ret = false; + g_logVerbosity = 0; + bool ret = false; - try - { - mValue v; - string s; - for (int i = 1; i < argc; ++i) - s += argv[i]; - if (asserts(s.length() > 0)) - { - cout << "Content of argument is empty\n"; - return 1; - } - read_string(s, v); - ret = doVMTest(v); - } - catch (Exception const& _e) - { - cout << "Failed test with Exception: " << diagnostic_information(_e) << endl; - ret = false; - } - catch (std::exception const& _e) - { - cout << "Failed test with Exception: " << _e.what() << endl; - ret = false; - } - return ret; + try + { + mValue v; + string s; + for (int i = 1; i < argc; ++i) + s += argv[i]; + if (asserts(s.length() > 0)) + { + cout << "Content of argument is empty\n"; + return 1; + } + read_string(s, v); + ret = doVMTest(v); + } + catch (Exception const& _e) + { + cout << "Failed test with Exception: " << diagnostic_information(_e) << endl; + ret = false; + } + catch (std::exception const& _e) + { + cout << "Failed test with Exception: " << _e.what() << endl; + ret = false; + } + return ret; } bool doVMTest(mValue& v) { - eth::VMFactory::setKind(eth::VMKind::JIT); + eth::VMFactory::setKind(eth::VMKind::JIT); - for (auto& i: v.get_obj()) - { - cnote << i.first; - mObject& o = i.second.get_obj(); + for (auto& i: v.get_obj()) + { + cnote << i.first; + mObject& o = i.second.get_obj(); - assert(o.count("env") > 0); - assert(o.count("pre") > 0); - assert(o.count("exec") > 0); + assert(o.count("env") > 0); + assert(o.count("pre") > 0); + assert(o.count("exec") > 0); - FakeExtVM fev; - fev.importEnv(o["env"].get_obj()); - fev.importState(o["pre"].get_obj()); + FakeExtVM fev; + fev.importEnv(o["env"].get_obj()); + fev.importState(o["pre"].get_obj()); - fev.importExec(o["exec"].get_obj()); - if (fev.code.empty()) - { - fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); - fev.code = fev.thisTxCode; - } + fev.importExec(o["exec"].get_obj()); + if (fev.code.empty()) + { + fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); + fev.code = fev.thisTxCode; + } - bytes output; - u256 gas; - bool vmExceptionOccured = false; - try - { - auto vm = eth::VMFactory::create(fev.gas); - output = vm->go(fev, fev.simpleTrace()).toBytes(); - gas = vm->gas(); - } - catch (eth::VMException const& _e) - { - cnote << "Safe VM Exception"; - vmExceptionOccured = true; - } - catch (Exception const& _e) - { - cnote << "VM did throw an exception: " << diagnostic_information(_e); - cnote << "Failed VM Test with Exception: " << _e.what(); - return 1; - } - catch (std::exception const& _e) - { - cnote << "VM did throw an exception: " << _e.what(); - cnote << "Failed VM Test with Exception: " << _e.what(); - return 1; - } + bytes output; + u256 gas; + bool vmExceptionOccured = false; + try + { + auto vm = eth::VMFactory::create(fev.gas); + output = vm->go(fev, fev.simpleTrace()).toBytes(); + gas = vm->gas(); + } + catch (eth::VMException) + { + cnote << "Safe VM Exception"; + vmExceptionOccured = true; + } + catch (Exception const& _e) + { + cnote << "VM did throw an exception: " << diagnostic_information(_e); + cnote << "Failed VM Test with Exception: " << _e.what(); + return 1; + } + catch (std::exception const& _e) + { + cnote << "VM did throw an exception: " << _e.what(); + cnote << "Failed VM Test with Exception: " << _e.what(); + return 1; + } - // delete null entries in storage for the sake of comparison - for (auto &a: fev.addresses) - { - vector keystoDelete; - for (auto &s: get<2>(a.second)) - { - if (s.second == 0) - keystoDelete.push_back(s.first); - } - for (auto const key: keystoDelete ) - { - get<2>(a.second).erase(key); - } - } + // delete null entries in storage for the sake of comparison + for (auto &a: fev.addresses) + { + vector keystoDelete; + for (auto &s: get<2>(a.second)) + { + if (s.second == 0) + keystoDelete.push_back(s.first); + } + for (auto const key: keystoDelete ) + { + get<2>(a.second).erase(key); + } + } - if (o.count("post") > 0) // No exceptions expected - { - if (asserts(!vmExceptionOccured) || asserts(o.count("post") > 0) || asserts(o.count("callcreates") > 0) || asserts(o.count("out") > 0) || asserts(o.count("gas") > 0) || asserts(o.count("logs") > 0)) - return 1; + if (o.count("post") > 0) // No exceptions expected + { + if (asserts(!vmExceptionOccured) || asserts(o.count("post") > 0) || asserts(o.count("callcreates") > 0) || asserts(o.count("out") > 0) || asserts(o.count("gas") > 0) || asserts(o.count("logs") > 0)) + return 1; - dev::test::FakeExtVM test; - test.importState(o["post"].get_obj()); - test.importCallCreates(o["callcreates"].get_array()); - test.sub.logs = importLog(o["logs"].get_array()); + dev::test::FakeExtVM test; + test.importState(o["post"].get_obj()); + test.importCallCreates(o["callcreates"].get_array()); + test.sub.logs = importLog(o["logs"].get_array()); - //checkOutput(output, o); - int j = 0; - if (o["out"].type() == array_type) - for (auto const& d: o["out"].get_array()) - { - if (asserts(output[j] == toInt(d))) - { - cout << "Output byte [" << j << "] different!"; - return 1; - } - ++j; - } - else if (o["out"].get_str().find("0x") == 0) - { - if (asserts(output == fromHex(o["out"].get_str().substr(2)))) - return 1; - } - else - { - if (asserts(output == fromHex(o["out"].get_str()))) - return 1; - } + //checkOutput(output, o); + int j = 0; + if (o["out"].type() == array_type) + for (auto const& d: o["out"].get_array()) + { + if (asserts(output[j] == toInt(d))) + { + cout << "Output byte [" << j << "] different!"; + return 1; + } + ++j; + } + else if (o["out"].get_str().find("0x") == 0) + { + if (asserts(output == fromHex(o["out"].get_str().substr(2)))) + return 1; + } + else + { + if (asserts(output == fromHex(o["out"].get_str()))) + return 1; + } - if (asserts(toInt(o["gas"]) == gas)) - return 1; + if (asserts(toInt(o["gas"]) == gas)) + return 1; - 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()) - { - cout << "Missing expected address " << expectedAddr; - return 1; - } - else - { - auto& expectedState = expectedPair.second; - auto& resultState = resultAddrIt->second; - if (asserts(std::get<0>(expectedState) == std::get<0>(resultState))) - { - cout << expectedAddr << ": incorrect balance " << std::get<0>(resultState) << ", expected " << std::get<0>(expectedState); - return 1; - } - if (asserts(std::get<1>(expectedState) == std::get<1>(resultState))) - { - cout << expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState); - return 1; - } - if (asserts(std::get<3>(expectedState) == std::get<3>(resultState))) - { - cout << expectedAddr << ": incorrect code"; - return 1; - } + 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()) + { + cout << "Missing expected address " << expectedAddr; + return 1; + } + else + { + auto& expectedState = expectedPair.second; + auto& resultState = resultAddrIt->second; + if (asserts(std::get<0>(expectedState) == std::get<0>(resultState))) + { + cout << expectedAddr << ": incorrect balance " << std::get<0>(resultState) << ", expected " << std::get<0>(expectedState); + return 1; + } + if (asserts(std::get<1>(expectedState) == std::get<1>(resultState))) + { + cout << expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState); + return 1; + } + if (asserts(std::get<3>(expectedState) == std::get<3>(resultState))) + { + cout << expectedAddr << ": incorrect code"; + return 1; + } - //checkStorage(std::get<2>(expectedState), std::get<2>(resultState), expectedAddr); - for (auto&& expectedStorePair : std::get<2>(expectedState)) - { - auto& expectedStoreKey = expectedStorePair.first; - auto resultStoreIt = std::get<2>(resultState).find(expectedStoreKey); - if (resultStoreIt == std::get<2>(resultState).end()) - { - cout << expectedAddr << ": missing store key " << expectedStoreKey << endl; - return 1; - } - else - { - auto& expectedStoreValue = expectedStorePair.second; - auto& resultStoreValue = resultStoreIt->second; - if (asserts(expectedStoreValue == resultStoreValue)) - { - cout << expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue << endl; - return 1; - } - } - } - if (assertsEqual(std::get<2>(resultState).size(), std::get<2>(expectedState).size())) - return 1; - for (auto&& resultStorePair: std::get<2>(resultState)) - { - if (!std::get<2>(expectedState).count(resultStorePair.first)) - { - cout << expectedAddr << ": unexpected store key " << resultStorePair.first << endl; - return 1; - } - } - } - } + //checkStorage(std::get<2>(expectedState), std::get<2>(resultState), expectedAddr); + for (auto&& expectedStorePair : std::get<2>(expectedState)) + { + auto& expectedStoreKey = expectedStorePair.first; + auto resultStoreIt = std::get<2>(resultState).find(expectedStoreKey); + if (resultStoreIt == std::get<2>(resultState).end()) + { + cout << expectedAddr << ": missing store key " << expectedStoreKey << endl; + return 1; + } + else + { + auto& expectedStoreValue = expectedStorePair.second; + auto& resultStoreValue = resultStoreIt->second; + if (asserts(expectedStoreValue == resultStoreValue)) + { + cout << expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue << endl; + return 1; + } + } + } + if (assertsEqual(std::get<2>(resultState).size(), std::get<2>(expectedState).size())) + return 1; + for (auto&& resultStorePair: std::get<2>(resultState)) + { + if (!std::get<2>(expectedState).count(resultStorePair.first)) + { + cout << expectedAddr << ": unexpected store key " << resultStorePair.first << endl; + return 1; + } + } + } + } - //checkAddresses, bytes> > >(test.addresses, fev.addresses); - for (auto& resultPair : fev.addresses) - { - auto& resultAddr = resultPair.first; - auto expectedAddrIt = test.addresses.find(resultAddr); - if (expectedAddrIt == test.addresses.end()) - { - cout << "Missing result address " << resultAddr << endl; - return 1; - } - } - if (asserts(test.addresses == fev.addresses)) - return 1; + //checkAddresses, bytes> > >(test.addresses, fev.addresses); + for (auto& resultPair : fev.addresses) + { + auto& resultAddr = resultPair.first; + auto expectedAddrIt = test.addresses.find(resultAddr); + if (expectedAddrIt == test.addresses.end()) + { + cout << "Missing result address " << resultAddr << endl; + return 1; + } + } + if (asserts(test.addresses == fev.addresses)) + return 1; - if (asserts(test.callcreates == fev.callcreates)) - return 1; + if (asserts(test.callcreates == fev.callcreates)) + return 1; - //checkLog(fev.sub.logs, test.sub.logs); - { - if (assertsEqual(fev.sub.logs.size(), test.sub.logs.size())) - return 1; + //checkCallCreates(fev.callcreates, test.callcreates); + { + if (assertsEqual(test.callcreates.size(), fev.callcreates.size())) + return 1; - for (size_t i = 0; i < fev.sub.logs.size(); ++i) - { - if (assertsEqual(fev.sub.logs[i].address, test.sub.logs[i].address)) - return 1; - if (assertsEqual(fev.sub.logs[i].topics, test.sub.logs[i].topics)) - return 1; - if (asserts(fev.sub.logs[i].data == test.sub.logs[i].data)) - return 1; - } - } + for (size_t i = 0; i < test.callcreates.size(); ++i) + { + if (asserts(test.callcreates[i].data() == fev.callcreates[i].data())) + return 1; + if (asserts(test.callcreates[i].receiveAddress() == fev.callcreates[i].receiveAddress())) + return 1; + if (asserts(test.callcreates[i].gas() == fev.callcreates[i].gas())) + return 1; + if (asserts(test.callcreates[i].value() == fev.callcreates[i].value())) + return 1; + } + } - } - else // Exception expected - { - if (asserts(vmExceptionOccured)) - return 1; - } - } - // test passed - return 0; + //checkLog(fev.sub.logs, test.sub.logs); + { + if (assertsEqual(fev.sub.logs.size(), test.sub.logs.size())) + return 1; + + for (size_t i = 0; i < fev.sub.logs.size(); ++i) + { + if (assertsEqual(fev.sub.logs[i].address, test.sub.logs[i].address)) + return 1; + if (assertsEqual(fev.sub.logs[i].topics, test.sub.logs[i].topics)) + return 1; + if (asserts(fev.sub.logs[i].data == test.sub.logs[i].data)) + return 1; + } + } + + } + else // Exception expected + { + if (asserts(vmExceptionOccured)) + return 1; + } + } + // test passed + return 0; } From 18dd4515bd0c32e79275f4ebd98e3f505f684954 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 13 Jan 2015 15:59:42 +0100 Subject: [PATCH 444/466] A first version of Natspec warning popup - Runtime Contract code hash can now be retrieved from the Compiler - Using the hash the Natspec handler stores and later retrieves Natspec JSON for a given contract. --- alethzero/MainWin.cpp | 10 ++- alethzero/MainWin.h | 1 + alethzero/NatspecHandler.cpp | 17 +++++ alethzero/NatspecHandler.h | 11 +++ alethzero/OurWebThreeStubServer.cpp | 33 +++++--- libdevcore/CommonData.h | 3 + .../ethereumjs/example/natspec_contract.html | 76 +++++++++++++++++++ libsolidity/Compiler.cpp | 5 +- libsolidity/Compiler.h | 2 + libsolidity/CompilerStack.cpp | 20 +++-- libsolidity/CompilerStack.h | 10 ++- 11 files changed, 163 insertions(+), 25 deletions(-) create mode 100644 libjsqrc/ethereumjs/example/natspec_contract.html diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 5de05848e..ae24e4af0 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1887,8 +1887,11 @@ void Main::on_send_clicked() { m_data = compiler.compile(src, m_enableOptimizer); for (std::string& s: compiler.getContractNames()) - m_natspecDB.add(compiler.getContractCodeHash(s), + { + h256 contractHash = compiler.getContractCodeHash(s); + m_natspecDB.add(contractHash, compiler.getMetadata(s, dev::solidity::DocumentationType::NATSPEC_USER)); + } } catch (...) @@ -2286,6 +2289,11 @@ std::string Main::lookupNatSpec(dev::h256 const& _contractHash) const return m_natspecDB.retrieve(_contractHash); } +std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) +{ + return m_natspecDB.getUserNotice(_contractHash, _methodName); +} + void Main::refreshWhispers() { ui->whispers->clear(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index e20aac27d..a7922287f 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -83,6 +83,7 @@ public: std::shared_ptr whisper() const { return m_webThree->whisper(); } std::string lookupNatSpec(dev::h256 const& _contractHash) const; + std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); QList owned() const { return m_myIdentities + m_myKeys; } diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index ae58208f1..415f8ca2a 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -25,6 +25,8 @@ #include #include +#include + using namespace dev; using namespace dev::eth; @@ -55,4 +57,19 @@ std::string NatspecHandler::retrieve(dev::h256 const& _contractHash) const } +std::string NatspecHandler::getUserNotice(std::string const& json, std::string const& _methodName) +{ + Json::Value natspec, userNotice; + std::string retStr; + m_reader.parse(json, natspec); + retStr = natspec["methods"][_methodName]["notice"].toStyledString(); + + return (retStr == "null\n") ? "" : retStr; +} + +std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) +{ + return getUserNotice(retrieve(_contractHash), _methodName); +} + diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 36554fc44..9ea1103af 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -26,6 +26,7 @@ #pragma warning(disable: 4100 4267) #include #pragma warning(pop) +#include #include namespace ldb = leveldb; @@ -35,11 +36,21 @@ class NatspecHandler public: NatspecHandler(); + /// Stores locally in a levelDB a key value pair of contract code hash to natspec documentation void add(dev::h256 const& _contractHash, std::string const& _doc); + /// Retrieves the natspec documentation as a string given a contract code hash std::string retrieve(dev::h256 const& _contractHash) const; + + /// Given a json natspec string, retrieve the user notice string + std::string getUserNotice(std::string const& json, std::string const& _methodName); + /// Given a contract code hash, retrieve the natspec documentation's user notice for that contract + /// @returns The user notice or an empty string if no natspec for the contract exists + /// or if the existing natspec does not document the @c _methodName + std::string getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); private: ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; ldb::DB* m_db; + Json::Reader m_reader; }; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index a156eeb1c..6d771f219 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -43,8 +43,6 @@ std::string OurWebThreeStubServer::shh_newIdentity() bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const { - // return true; - // To get the balance of the sender cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from); @@ -57,18 +55,31 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con return true; // or whatever. } - std::string natspecJson = m_main->lookupNatSpec(contractCodeHash); + //LTODO: Just for debugging here + cnote << "Contract hash:\n" << contractCodeHash; + cnote << "Transaction Value:\n" << "0x" + toHex(_t.value); + cnote << "Transaction Data:\n" << "0x" + toHex(_t.data); + - if (natspecJson.empty()) + //LTODO: Actually find and use the method name here + std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, "multiply"); + if (userNotice.empty()) { - // TODO: HUGE warning - we don't know what this will do! - return false; // or whatever. + QMessageBox userInput; + userInput.setText("Unverified Pending Transaction"); + userInput.setInformativeText("An undocumented transaction is about to be executed." + "Are you really sure you want to go through with it?"); + userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.setDefaultButton(QMessageBox::Cancel); + return userInput.exec() == QMessageBox::Ok; } - // otherwise it's a transaction to contract for which we have the natspec: - // determine the actual message (embellish with real data) and ask user. - -// QMessageBox::question(); + // otherwise it's a transaction to a contract for which we have the natspec + QMessageBox userInput; + userInput.setText("Pending Transaction"); + userInput.setInformativeText(QString::fromStdString(userNotice)); + userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.setDefaultButton(QMessageBox::Cancel); + return userInput.exec() == QMessageBox::Ok; - return true; } diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 6fab67452..2573995c5 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -110,6 +110,9 @@ inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toB inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; } +/// Convenience function for conversion of a u256 to hex +inline std::string toHex(u256 val) { return toHex(toBigEndian(val)); } + /// Convenience function for toBigEndian. /// @returns a byte array just big enough to represent @a _val. template diff --git a/libjsqrc/ethereumjs/example/natspec_contract.html b/libjsqrc/ethereumjs/example/natspec_contract.html new file mode 100644 index 000000000..b8e3bc617 --- /dev/null +++ b/libjsqrc/ethereumjs/example/natspec_contract.html @@ -0,0 +1,76 @@ + + + + + + + + + +

contract

+
+
+ +
+ +
+ + + diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 782a7efe2..bd6571b9a 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -50,10 +50,9 @@ void Compiler::compileContract(ContractDefinition const& _contract, vectoraccept(*this); // Swap the runtime context with the creation-time context - CompilerContext runtimeContext; - swap(m_context, runtimeContext); + swap(m_context, m_runtimeContext); initializeContext(_contract, _magicGlobals, _contracts); - packIntoContractCreator(_contract, runtimeContext); + packIntoContractCreator(_contract, m_runtimeContext); } void Compiler::initializeContext(ContractDefinition const& _contract, vector const& _magicGlobals, diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index e83d1ed3a..c229a7a8a 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -35,6 +35,7 @@ public: void compileContract(ContractDefinition const& _contract, std::vector const& _magicGlobals, std::map const& _contracts); bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } + bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } private: @@ -70,6 +71,7 @@ private: bool const m_optimize; CompilerContext m_context; + CompilerContext m_runtimeContext; std::vector m_breakTags; ///< tag to jump to for a "break" statement std::vector m_continueTags; ///< tag to jump to for a "continue" statement eth::AssemblyItem m_returnTag; ///< tag to jump to for a "return" statement diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index f0d2e7f75..b06423497 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -30,6 +30,8 @@ #include #include +#include + using namespace std; namespace dev @@ -117,6 +119,7 @@ void CompilerStack::compile(bool _optimize) contractBytecode); Contract& compiledContract = m_contracts[contract->getName()]; compiledContract.bytecode = compiler->getAssembledBytecode(); + compiledContract.runtimeBytecode = compiler->getRuntimeBytecode(); compiledContract.compiler = move(compiler); contractBytecode[compiledContract.contract] = &compiledContract.bytecode; } @@ -134,6 +137,16 @@ bytes const& CompilerStack::getBytecode(string const& _contractName) const return getContract(_contractName).bytecode; } +bytes const& CompilerStack::getRuntimeBytecode(std::string const& _contractName) const +{ + return getContract(_contractName).runtimeBytecode; +} + +dev::h256 CompilerStack::getContractCodeHash(std::string const& _contractName) const +{ + return dev::sha3(getRuntimeBytecode(_contractName)); +} + void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName) const { getContract(_contractName).compiler->streamAssembly(_outStream); @@ -218,13 +231,6 @@ bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimiz return stack.compile(_sourceCode, _optimize); } -dev::h256 CompilerStack::getContractCodeHash(std::string const& _contractName) -{ - //LTODO - (void) _contractName; - return dev::h256(""); -} - void CompilerStack::reset(bool _keepSources) { m_parseSuccessful = false; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index da0adf57e..202f1b321 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -76,7 +76,13 @@ public: /// @returns the compiled bytecode bytes const& compile(std::string const& _sourceCode, bool _optimize = false); + /// Gets the assembled bytecode for a contract bytes const& getBytecode(std::string const& _contractName = "") const; + /// Get the runtime context's bytecode for a contract + bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; + /// Get the runtime context's code hash for a contract + dev::h256 getContractCodeHash(std::string const& _contractName = "") const; + /// Streams a verbose version of the assembly to @a _outStream. /// Prerequisite: Successful compilation. void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "") const; @@ -108,9 +114,6 @@ public: /// scanning the source code - this is useful for printing exception information. static bytes staticCompile(std::string const& _sourceCode, bool _optimize = false); - /// Get the runtime context's code hash for a contract. LTODO - dev::h256 getContractCodeHash(std::string const& _contractName); - private: /** * Information pertaining to one source unit, filled gradually during parsing and compilation. @@ -128,6 +131,7 @@ private: ContractDefinition const* contract = nullptr; std::shared_ptr compiler; bytes bytecode; + bytes runtimeBytecode; std::shared_ptr interfaceHandler; mutable std::unique_ptr interface; mutable std::unique_ptr solidityInterface; From 106a7a84727d70dd556faf65bd22e5a9c556a20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 13 Jan 2015 16:05:03 +0100 Subject: [PATCH 445/466] Allways generate stack_get() call to detect stack underflow cases --- evmjit/libevmjit/BasicBlock.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index dda0fbc36..5868c0f43 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -168,16 +168,13 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) 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); - } + // 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); // OPT: Value may be never user but we need to check stack heigth + // It is probably a good idea to keep heigth as a local variable accesible by LLVM directly + phi->replaceAllUsesWith(newVal); phi->eraseFromParent(); } From 5b36d3c163bf11424a5fcfad04c5ec9090cff33e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 13 Jan 2015 16:15:32 +0100 Subject: [PATCH 446/466] Natspec method key is now the Canonical Signature --- libsolidity/InterfaceHandler.cpp | 4 +-- test/SolidityNatspecJSON.cpp | 42 ++++++++++++++++---------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index a5c6f4a1d..4c7ae5f45 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -106,7 +106,7 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefi if (!m_notice.empty()) {// since @notice is the only user tag if missing function should not appear user["notice"] = Json::Value(m_notice); - methods[it.second->getName()] = user; + methods[it.second->getCanonicalSignature()] = user; } } } @@ -162,7 +162,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin method["return"] = m_return; if (!method.empty()) // add the function, only if we have any documentation to add - methods[it.second->getName()] = method; + methods[it.second->getCanonicalSignature()] = method; } } doc["methods"] = methods; diff --git a/test/SolidityNatspecJSON.cpp b/test/SolidityNatspecJSON.cpp index 7edb97a7b..d43aebc2b 100644 --- a/test/SolidityNatspecJSON.cpp +++ b/test/SolidityNatspecJSON.cpp @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(user_basic_test) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" + " \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* devNatspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256)\":{ \n" " \"details\": \"Multiplies a number by 7\"\n" " }\n" " }\n" @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* userNatspec = "{" "\"methods\":{" - " \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" + " \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}" "}}"; checkNatspec(sourceCode, devNatspec, false); @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(user_multiline_comment) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}" + " \"mul_and_add(uint256,uint256)\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -157,9 +157,9 @@ BOOST_AUTO_TEST_CASE(user_multiple_functions) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}," - " \"divide\":{ \"notice\": \"Divides `input` by `div`\"}," - " \"sub\":{ \"notice\": \"Subtracts 3 from `input`\"}" + " \"mul_and_add(uint256,uint256)\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}," + " \"divide(uint256,uint256)\":{ \"notice\": \"Divides `input` by `div`\"}," + " \"sub(int256)\":{ \"notice\": \"Subtracts 3 from `input`\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -205,7 +205,7 @@ BOOST_AUTO_TEST_CASE(dev_desc_after_nl) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \" Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" @@ -228,7 +228,7 @@ BOOST_AUTO_TEST_CASE(dev_multiple_params) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" @@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE(dev_mutiline_param_description) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \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" @@ -289,21 +289,21 @@ BOOST_AUTO_TEST_CASE(dev_multiple_functions) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" " \"second\": \"Documentation for the second parameter\"\n" " }\n" " },\n" - " \"divide\":{ \n" + " \"divide(uint256,uint256)\":{ \n" " \"details\": \"Divides 2 numbers\",\n" " \"params\": {\n" " \"input\": \"Documentation for the input parameter\",\n" " \"div\": \"Documentation for the div parameter\"\n" " }\n" " },\n" - " \"sub\":{ \n" + " \"sub(int256)\":{ \n" " \"details\": \"Subtracts 3 from `input`\",\n" " \"params\": {\n" " \"input\": \"Documentation for the input parameter\"\n" @@ -327,7 +327,7 @@ BOOST_AUTO_TEST_CASE(dev_return) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \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" @@ -353,7 +353,7 @@ BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \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" @@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \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" @@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(dev_multiline_comment) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \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" @@ -432,7 +432,7 @@ BOOST_AUTO_TEST_CASE(dev_contract_no_doc) char const* natspec = "{" " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\"\n" " }\n" " }\n" @@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE(dev_contract_doc) " \"author\": \"Lefteris\"," " \"title\": \"Just a test contract\"," " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\"\n" " }\n" " }\n" @@ -477,7 +477,7 @@ BOOST_AUTO_TEST_CASE(dev_author_at_function) " \"author\": \"Lefteris\"," " \"title\": \"Just a test contract\"," " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\",\n" " \"author\": \"John Doe\",\n" " }\n" @@ -501,7 +501,7 @@ BOOST_AUTO_TEST_CASE(dev_title_at_function_error) " \"author\": \"Lefteris\"," " \"title\": \"Just a test contract\"," " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\"\n" " }\n" " }\n" From c9ddc4468ae5eb9caaf7a5e01216f81f8eba54e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 13 Jan 2015 16:36:58 +0100 Subject: [PATCH 447/466] Temporary remove evmjit subtree --- evmjit/CMakeLists.txt | 28 - evmjit/evmcc/CMakeLists.txt | 18 - evmjit/evmcc/evmcc.cpp | 210 ---- evmjit/evmcc/test/arith/addmod.evm | 1 - evmjit/evmcc/test/arith/addmod.lll | 12 - evmjit/evmcc/test/arith/arith1.evm | 1 - evmjit/evmcc/test/arith/arith1.lll | 37 - evmjit/evmcc/test/arith/arith_bnot.evm | 1 - evmjit/evmcc/test/arith/arith_bnot.lll | 14 - evmjit/evmcc/test/arith/div.evm | 1 - evmjit/evmcc/test/arith/div.lll | 10 - evmjit/evmcc/test/arith/fib1.evm | 1 - evmjit/evmcc/test/arith/fib1.lll | 57 -- evmjit/evmcc/test/arith/mul.evm | 1 - evmjit/evmcc/test/arith/mul.lll | 13 - evmjit/evmcc/test/arith/mulmod.evm | 1 - evmjit/evmcc/test/arith/mulmod.lll | 12 - evmjit/evmcc/test/except/badinst1.evm | 1 - evmjit/evmcc/test/ext/calldatacopy1.evm | 1 - evmjit/evmcc/test/ext/calldatacopy1.lll | 13 - evmjit/evmcc/test/ext/calldatacopy2.evm | 1 - evmjit/evmcc/test/ext/calldatacopy2.lll | 13 - evmjit/evmcc/test/ext/codecopy1.evm | 1 - evmjit/evmcc/test/ext/codecopy1.lll | 13 - evmjit/evmcc/test/ext/codecopy2.evm | 1 - evmjit/evmcc/test/ext/codecopy2.lll | 13 - evmjit/evmcc/test/ext/codecopy3.evm | 1 - evmjit/evmcc/test/ext/codecopy3.lll | 13 - evmjit/evmcc/test/ext/ext_test.evm | 1 - evmjit/evmcc/test/ext/ext_test.lll | 55 -- evmjit/evmcc/test/ext/extcodecopy1.evm | 1 - evmjit/evmcc/test/ext/extcodecopy1.lll | 11 - evmjit/evmcc/test/ext/store_delete.evm | 1 - evmjit/evmcc/test/ext/store_delete.lll | 9 - evmjit/evmcc/test/ext/store_test.evm | 1 - evmjit/evmcc/test/ext/store_test.lll | 14 - evmjit/evmcc/test/jump/ackermann.ethel | 7 - evmjit/evmcc/test/jump/ackermann.evm | 1 - evmjit/evmcc/test/jump/badindirect1.evm | 1 - evmjit/evmcc/test/jump/badindirect1.lll | 9 - evmjit/evmcc/test/jump/badindirect2.evm | 1 - evmjit/evmcc/test/jump/badindirect2.lll | 12 - evmjit/evmcc/test/jump/badjump1.evm | 1 - evmjit/evmcc/test/jump/badjump1.lll | 6 - evmjit/evmcc/test/jump/badjump2.evm | 1 - evmjit/evmcc/test/jump/badjump2.lll | 9 - evmjit/evmcc/test/jump/call1.ethel | 5 - evmjit/evmcc/test/jump/call1.evm | 1 - evmjit/evmcc/test/jump/call2.ethel | 5 - evmjit/evmcc/test/jump/call2.evm | 1 - evmjit/evmcc/test/jump/fac.ethel | 5 - evmjit/evmcc/test/jump/fac.evm | 1 - evmjit/evmcc/test/jump/fac_tail.ethel | 5 - evmjit/evmcc/test/jump/fac_tail.evm | 1 - evmjit/evmcc/test/jump/fib1.ethel | 6 - evmjit/evmcc/test/jump/fib1.evm | 1 - evmjit/evmcc/test/jump/for1.evm | 1 - evmjit/evmcc/test/jump/for1.lll | 3 - evmjit/evmcc/test/jump/for2.evm | 1 - evmjit/evmcc/test/jump/for2.lll | 3 - evmjit/evmcc/test/jump/if1.ethel | 1 - evmjit/evmcc/test/jump/if1.evm | 1 - evmjit/evmcc/test/jump/if2.ethel | 1 - evmjit/evmcc/test/jump/if2.evm | 1 - evmjit/evmcc/test/jump/indirect1.evm | 1 - evmjit/evmcc/test/jump/indirect1.lll | 13 - evmjit/evmcc/test/jump/indirect2.evm | 1 - evmjit/evmcc/test/jump/indirect2.lll | 19 - evmjit/evmcc/test/jump/indirect3.evm | 1 - evmjit/evmcc/test/jump/indirect3.lll | 14 - evmjit/evmcc/test/jump/indirect4.evm | 1 - evmjit/evmcc/test/jump/indirect4.lll | 15 - evmjit/evmcc/test/jump/jump1.evm | 1 - evmjit/evmcc/test/jump/jump1.lll | 11 - evmjit/evmcc/test/jump/jump2.evm | 1 - evmjit/evmcc/test/jump/jump2.lll | 10 - evmjit/evmcc/test/jump/jump3.evm | 1 - evmjit/evmcc/test/jump/jump3.lll | 10 - evmjit/evmcc/test/jump/jump4.evm | 1 - evmjit/evmcc/test/jump/jump4.lll | 17 - evmjit/evmcc/test/jump/jump5.evm | 1 - evmjit/evmcc/test/jump/jump5.lll | 16 - evmjit/evmcc/test/jump/jump6.evm | 1 - evmjit/evmcc/test/jump/jump6.lll | 32 - evmjit/evmcc/test/jump/jumpi_at_the_end.evm | 1 - evmjit/evmcc/test/jump/jumpi_at_the_end.lll | 1 - evmjit/evmcc/test/jump/loop1.evm | 1 - evmjit/evmcc/test/jump/loop1.lll | 27 - evmjit/evmcc/test/jump/loop2.evm | 1 - evmjit/evmcc/test/jump/loop2.lll | 28 - evmjit/evmcc/test/jump/rec1.ethel | 4 - evmjit/evmcc/test/jump/rec1.evm | 1 - evmjit/evmcc/test/jump/when1.asm | 10 - evmjit/evmcc/test/jump/when1.evm | 1 - evmjit/evmcc/test/jump/when1.lll | 2 - evmjit/evmcc/test/kv.evm | 1 - evmjit/evmcc/test/kv.lll | 10 - evmjit/evmcc/test/mem/byte.evm | 1 - evmjit/evmcc/test/mem/byte.lll | 105 -- evmjit/evmcc/test/mem/mem2.evm | 1 - evmjit/evmcc/test/mem/mem2.lll | 15 - evmjit/evmcc/test/mem/memtest1.evm | 1 - evmjit/evmcc/test/mem/memtest1.lll | 18 - evmjit/evmcc/test/mem/mstore1.evm | 1 - evmjit/evmcc/test/mem/mstore1.lll | 6 - evmjit/evmcc/test/ret/return1.evm | 1 - evmjit/evmcc/test/ret/return1.lll | 6 - evmjit/evmcc/test/ret/return2.evm | 1 - evmjit/evmcc/test/ret/return2.lll | 6 - evmjit/evmcc/test/ret/return_test.evm | 1 - evmjit/evmcc/test/ret/return_test.lll | 15 - evmjit/evmcc/test/stack/oos.evm | 1 - evmjit/evmcc/test/stack/oos.lll | 11 - evmjit/evmcc/test/stack/push_test.evm | 1 - evmjit/evmcc/test/stack/push_test.lll | 35 - evmjit/evmcc/test/stack/stack_test.evm | 1 - evmjit/evmcc/test/stack/stack_test.lll | 8 - evmjit/evmcc/test/stack/stackjump.evm | 1 - evmjit/evmcc/test/stack/stackjump.lll | 3 - evmjit/evmcc/test/stack/swap.evm | 1 - evmjit/evmcc/test/stack/swap.lll | 31 - evmjit/evmcc/test/stack/swapswap.evm | 1 - evmjit/evmcc/test/stack/swapswap.lll | 32 - evmjit/evmcc/test/stack/test.evm | 1 - .../test/vmtests/vmArithPerformanceTest.json | 260 ----- .../evmcc/test/vmtests/vmPerformanceTest.json | 214 ----- evmjit/evmcc/test/vmtests/vm_jump.json | 41 - evmjit/libevmjit-cpp/CMakeLists.txt | 16 - evmjit/libevmjit-cpp/Env.cpp | 119 --- evmjit/libevmjit-cpp/JitVM.cpp | 68 -- evmjit/libevmjit-cpp/JitVM.h | 28 - evmjit/libevmjit/Arith256.cpp | 200 ---- evmjit/libevmjit/Arith256.h | 49 - evmjit/libevmjit/BasicBlock.cpp | 378 -------- evmjit/libevmjit/BasicBlock.h | 120 --- evmjit/libevmjit/CMakeLists.txt | 24 - evmjit/libevmjit/Cache.cpp | 80 -- evmjit/libevmjit/Cache.h | 41 - evmjit/libevmjit/Common.h | 51 - evmjit/libevmjit/Compiler.cpp | 898 ------------------ evmjit/libevmjit/Compiler.h | 83 -- evmjit/libevmjit/CompilerHelper.cpp | 51 - evmjit/libevmjit/CompilerHelper.h | 78 -- evmjit/libevmjit/Endianness.cpp | 38 - evmjit/libevmjit/Endianness.h | 24 - evmjit/libevmjit/ExecutionEngine.cpp | 139 --- evmjit/libevmjit/ExecutionEngine.h | 26 - evmjit/libevmjit/Ext.cpp | 199 ---- evmjit/libevmjit/Ext.h | 81 -- evmjit/libevmjit/GasMeter.cpp | 224 ----- evmjit/libevmjit/GasMeter.h | 64 -- evmjit/libevmjit/Instruction.cpp | 40 - evmjit/libevmjit/Instruction.h | 239 ----- evmjit/libevmjit/Memory.cpp | 237 ----- evmjit/libevmjit/Memory.h | 46 - evmjit/libevmjit/Runtime.cpp | 37 - evmjit/libevmjit/Runtime.h | 59 -- evmjit/libevmjit/RuntimeData.h | 51 - evmjit/libevmjit/RuntimeManager.cpp | 197 ---- evmjit/libevmjit/RuntimeManager.h | 51 - evmjit/libevmjit/Stack.cpp | 133 --- evmjit/libevmjit/Stack.h | 43 - evmjit/libevmjit/Type.cpp | 67 -- evmjit/libevmjit/Type.h | 54 -- evmjit/libevmjit/Utils.cpp | 40 - evmjit/libevmjit/Utils.h | 22 - evmjit/libevmjit/interface.c | 30 - 167 files changed, 6173 deletions(-) delete mode 100644 evmjit/CMakeLists.txt delete mode 100644 evmjit/evmcc/CMakeLists.txt delete mode 100644 evmjit/evmcc/evmcc.cpp delete mode 100644 evmjit/evmcc/test/arith/addmod.evm delete mode 100644 evmjit/evmcc/test/arith/addmod.lll delete mode 100644 evmjit/evmcc/test/arith/arith1.evm delete mode 100644 evmjit/evmcc/test/arith/arith1.lll delete mode 100644 evmjit/evmcc/test/arith/arith_bnot.evm delete mode 100644 evmjit/evmcc/test/arith/arith_bnot.lll delete mode 100644 evmjit/evmcc/test/arith/div.evm delete mode 100644 evmjit/evmcc/test/arith/div.lll delete mode 100644 evmjit/evmcc/test/arith/fib1.evm delete mode 100644 evmjit/evmcc/test/arith/fib1.lll delete mode 100644 evmjit/evmcc/test/arith/mul.evm delete mode 100644 evmjit/evmcc/test/arith/mul.lll delete mode 100644 evmjit/evmcc/test/arith/mulmod.evm delete mode 100644 evmjit/evmcc/test/arith/mulmod.lll delete mode 100644 evmjit/evmcc/test/except/badinst1.evm delete mode 100644 evmjit/evmcc/test/ext/calldatacopy1.evm delete mode 100644 evmjit/evmcc/test/ext/calldatacopy1.lll delete mode 100644 evmjit/evmcc/test/ext/calldatacopy2.evm delete mode 100644 evmjit/evmcc/test/ext/calldatacopy2.lll delete mode 100644 evmjit/evmcc/test/ext/codecopy1.evm delete mode 100644 evmjit/evmcc/test/ext/codecopy1.lll delete mode 100644 evmjit/evmcc/test/ext/codecopy2.evm delete mode 100644 evmjit/evmcc/test/ext/codecopy2.lll delete mode 100644 evmjit/evmcc/test/ext/codecopy3.evm delete mode 100644 evmjit/evmcc/test/ext/codecopy3.lll delete mode 100644 evmjit/evmcc/test/ext/ext_test.evm delete mode 100644 evmjit/evmcc/test/ext/ext_test.lll delete mode 100644 evmjit/evmcc/test/ext/extcodecopy1.evm delete mode 100644 evmjit/evmcc/test/ext/extcodecopy1.lll delete mode 100644 evmjit/evmcc/test/ext/store_delete.evm delete mode 100644 evmjit/evmcc/test/ext/store_delete.lll delete mode 100644 evmjit/evmcc/test/ext/store_test.evm delete mode 100644 evmjit/evmcc/test/ext/store_test.lll delete mode 100644 evmjit/evmcc/test/jump/ackermann.ethel delete mode 100644 evmjit/evmcc/test/jump/ackermann.evm delete mode 100644 evmjit/evmcc/test/jump/badindirect1.evm delete mode 100644 evmjit/evmcc/test/jump/badindirect1.lll delete mode 100644 evmjit/evmcc/test/jump/badindirect2.evm delete mode 100644 evmjit/evmcc/test/jump/badindirect2.lll delete mode 100644 evmjit/evmcc/test/jump/badjump1.evm delete mode 100644 evmjit/evmcc/test/jump/badjump1.lll delete mode 100644 evmjit/evmcc/test/jump/badjump2.evm delete mode 100644 evmjit/evmcc/test/jump/badjump2.lll delete mode 100644 evmjit/evmcc/test/jump/call1.ethel delete mode 100644 evmjit/evmcc/test/jump/call1.evm delete mode 100644 evmjit/evmcc/test/jump/call2.ethel delete mode 100644 evmjit/evmcc/test/jump/call2.evm delete mode 100644 evmjit/evmcc/test/jump/fac.ethel delete mode 100644 evmjit/evmcc/test/jump/fac.evm delete mode 100644 evmjit/evmcc/test/jump/fac_tail.ethel delete mode 100644 evmjit/evmcc/test/jump/fac_tail.evm delete mode 100644 evmjit/evmcc/test/jump/fib1.ethel delete mode 100644 evmjit/evmcc/test/jump/fib1.evm delete mode 100644 evmjit/evmcc/test/jump/for1.evm delete mode 100644 evmjit/evmcc/test/jump/for1.lll delete mode 100644 evmjit/evmcc/test/jump/for2.evm delete mode 100644 evmjit/evmcc/test/jump/for2.lll delete mode 100644 evmjit/evmcc/test/jump/if1.ethel delete mode 100644 evmjit/evmcc/test/jump/if1.evm delete mode 100644 evmjit/evmcc/test/jump/if2.ethel delete mode 100644 evmjit/evmcc/test/jump/if2.evm delete mode 100644 evmjit/evmcc/test/jump/indirect1.evm delete mode 100644 evmjit/evmcc/test/jump/indirect1.lll delete mode 100644 evmjit/evmcc/test/jump/indirect2.evm delete mode 100644 evmjit/evmcc/test/jump/indirect2.lll delete mode 100644 evmjit/evmcc/test/jump/indirect3.evm delete mode 100644 evmjit/evmcc/test/jump/indirect3.lll delete mode 100644 evmjit/evmcc/test/jump/indirect4.evm delete mode 100644 evmjit/evmcc/test/jump/indirect4.lll delete mode 100644 evmjit/evmcc/test/jump/jump1.evm delete mode 100644 evmjit/evmcc/test/jump/jump1.lll delete mode 100644 evmjit/evmcc/test/jump/jump2.evm delete mode 100644 evmjit/evmcc/test/jump/jump2.lll delete mode 100644 evmjit/evmcc/test/jump/jump3.evm delete mode 100644 evmjit/evmcc/test/jump/jump3.lll delete mode 100644 evmjit/evmcc/test/jump/jump4.evm delete mode 100644 evmjit/evmcc/test/jump/jump4.lll delete mode 100644 evmjit/evmcc/test/jump/jump5.evm delete mode 100644 evmjit/evmcc/test/jump/jump5.lll delete mode 100644 evmjit/evmcc/test/jump/jump6.evm delete mode 100644 evmjit/evmcc/test/jump/jump6.lll delete mode 100644 evmjit/evmcc/test/jump/jumpi_at_the_end.evm delete mode 100644 evmjit/evmcc/test/jump/jumpi_at_the_end.lll delete mode 100644 evmjit/evmcc/test/jump/loop1.evm delete mode 100644 evmjit/evmcc/test/jump/loop1.lll delete mode 100644 evmjit/evmcc/test/jump/loop2.evm delete mode 100644 evmjit/evmcc/test/jump/loop2.lll delete mode 100644 evmjit/evmcc/test/jump/rec1.ethel delete mode 100644 evmjit/evmcc/test/jump/rec1.evm delete mode 100644 evmjit/evmcc/test/jump/when1.asm delete mode 100644 evmjit/evmcc/test/jump/when1.evm delete mode 100644 evmjit/evmcc/test/jump/when1.lll delete mode 100644 evmjit/evmcc/test/kv.evm delete mode 100644 evmjit/evmcc/test/kv.lll delete mode 100644 evmjit/evmcc/test/mem/byte.evm delete mode 100644 evmjit/evmcc/test/mem/byte.lll delete mode 100644 evmjit/evmcc/test/mem/mem2.evm delete mode 100644 evmjit/evmcc/test/mem/mem2.lll delete mode 100644 evmjit/evmcc/test/mem/memtest1.evm delete mode 100644 evmjit/evmcc/test/mem/memtest1.lll delete mode 100644 evmjit/evmcc/test/mem/mstore1.evm delete mode 100644 evmjit/evmcc/test/mem/mstore1.lll delete mode 100644 evmjit/evmcc/test/ret/return1.evm delete mode 100644 evmjit/evmcc/test/ret/return1.lll delete mode 100644 evmjit/evmcc/test/ret/return2.evm delete mode 100644 evmjit/evmcc/test/ret/return2.lll delete mode 100644 evmjit/evmcc/test/ret/return_test.evm delete mode 100644 evmjit/evmcc/test/ret/return_test.lll delete mode 100644 evmjit/evmcc/test/stack/oos.evm delete mode 100644 evmjit/evmcc/test/stack/oos.lll delete mode 100644 evmjit/evmcc/test/stack/push_test.evm delete mode 100644 evmjit/evmcc/test/stack/push_test.lll delete mode 100644 evmjit/evmcc/test/stack/stack_test.evm delete mode 100644 evmjit/evmcc/test/stack/stack_test.lll delete mode 100644 evmjit/evmcc/test/stack/stackjump.evm delete mode 100644 evmjit/evmcc/test/stack/stackjump.lll delete mode 100644 evmjit/evmcc/test/stack/swap.evm delete mode 100644 evmjit/evmcc/test/stack/swap.lll delete mode 100644 evmjit/evmcc/test/stack/swapswap.evm delete mode 100644 evmjit/evmcc/test/stack/swapswap.lll delete mode 100644 evmjit/evmcc/test/stack/test.evm delete mode 100644 evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json delete mode 100644 evmjit/evmcc/test/vmtests/vmPerformanceTest.json delete mode 100644 evmjit/evmcc/test/vmtests/vm_jump.json delete mode 100644 evmjit/libevmjit-cpp/CMakeLists.txt delete mode 100644 evmjit/libevmjit-cpp/Env.cpp delete mode 100644 evmjit/libevmjit-cpp/JitVM.cpp delete mode 100644 evmjit/libevmjit-cpp/JitVM.h delete mode 100644 evmjit/libevmjit/Arith256.cpp delete mode 100644 evmjit/libevmjit/Arith256.h delete mode 100644 evmjit/libevmjit/BasicBlock.cpp delete mode 100644 evmjit/libevmjit/BasicBlock.h delete mode 100644 evmjit/libevmjit/CMakeLists.txt delete mode 100644 evmjit/libevmjit/Cache.cpp delete mode 100644 evmjit/libevmjit/Cache.h delete mode 100644 evmjit/libevmjit/Common.h delete mode 100644 evmjit/libevmjit/Compiler.cpp delete mode 100644 evmjit/libevmjit/Compiler.h delete mode 100644 evmjit/libevmjit/CompilerHelper.cpp delete mode 100644 evmjit/libevmjit/CompilerHelper.h delete mode 100644 evmjit/libevmjit/Endianness.cpp delete mode 100644 evmjit/libevmjit/Endianness.h delete mode 100644 evmjit/libevmjit/ExecutionEngine.cpp delete mode 100644 evmjit/libevmjit/ExecutionEngine.h delete mode 100644 evmjit/libevmjit/Ext.cpp delete mode 100644 evmjit/libevmjit/Ext.h delete mode 100644 evmjit/libevmjit/GasMeter.cpp delete mode 100644 evmjit/libevmjit/GasMeter.h delete mode 100644 evmjit/libevmjit/Instruction.cpp delete mode 100644 evmjit/libevmjit/Instruction.h delete mode 100644 evmjit/libevmjit/Memory.cpp delete mode 100644 evmjit/libevmjit/Memory.h delete mode 100644 evmjit/libevmjit/Runtime.cpp delete mode 100644 evmjit/libevmjit/Runtime.h delete mode 100644 evmjit/libevmjit/RuntimeData.h delete mode 100644 evmjit/libevmjit/RuntimeManager.cpp delete mode 100644 evmjit/libevmjit/RuntimeManager.h delete mode 100644 evmjit/libevmjit/Stack.cpp delete mode 100644 evmjit/libevmjit/Stack.h delete mode 100644 evmjit/libevmjit/Type.cpp delete mode 100644 evmjit/libevmjit/Type.h delete mode 100644 evmjit/libevmjit/Utils.cpp delete mode 100644 evmjit/libevmjit/Utils.h delete mode 100644 evmjit/libevmjit/interface.c diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt deleted file mode 100644 index 18601b921..000000000 --- a/evmjit/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -cmake_minimum_required(VERSION 2.8.12) - -project(evmjit) - -set_property(GLOBAL PROPERTY USE_FOLDERS ON) - -# LLVM -if(LLVM_DIR) # local LLVM build - find_package(LLVM REQUIRED CONFIG) - message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") - message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - add_definitions(${LLVM_DEFINITIONS}) - # TODO: bitwriter is needed only for evmcc - llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter) -else() - # Workaround for Ubuntu broken LLVM package - message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") - execute_process(COMMAND llvm-config-3.5 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS) - message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}") - set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") -endif() - -# Boost -find_package(Boost REQUIRED) - -add_subdirectory(libevmjit) -add_subdirectory(libevmjit-cpp) -add_subdirectory(evmcc) diff --git a/evmjit/evmcc/CMakeLists.txt b/evmjit/evmcc/CMakeLists.txt deleted file mode 100644 index 4ffbf5fb5..000000000 --- a/evmjit/evmcc/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(TARGET_NAME evmcc) - -set(SOURCES - evmcc.cpp -) -source_group("" FILES ${SOURCES}) - -add_executable(${TARGET_NAME} ${SOURCES}) -set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "tools") - -include_directories(../..) -include_directories(${LLVM_INCLUDE_DIRS}) -include_directories(${Boost_INCLUDE_DIRS}) - -target_link_libraries(${TARGET_NAME} ethereum) -target_link_libraries(${TARGET_NAME} ${Boost_PROGRAM_OPTIONS_LIBRARIES}) - -install(TARGETS ${TARGET_NAME} DESTINATION bin ) \ No newline at end of file diff --git a/evmjit/evmcc/evmcc.cpp b/evmjit/evmcc/evmcc.cpp deleted file mode 100644 index e86f948f2..000000000 --- a/evmjit/evmcc/evmcc.cpp +++ /dev/null @@ -1,210 +0,0 @@ - -#include -#include -#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) -{ - llvm::sys::PrintStackTraceOnErrorSignal(); - llvm::PrettyStackTraceProgram X(argc, 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, "main"); - - 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")) - { - using namespace eth::jit; - - ExecutionEngine engine; - eth::jit::u256 gas = initialGas; - - // Create random runtime data - RuntimeData data; - data.set(RuntimeData::Gas, gas); - data.set(RuntimeData::Address, (u160)Address(1122334455667788)); - data.set(RuntimeData::Caller, (u160)Address(0xfacefacefaceface)); - data.set(RuntimeData::Origin, (u160)Address(101010101010101010)); - data.set(RuntimeData::CallValue, 0xabcd); - data.set(RuntimeData::CallDataSize, 3); - data.set(RuntimeData::GasPrice, 1003); - data.set(RuntimeData::CoinBase, (u160)Address(101010101010101015)); - data.set(RuntimeData::TimeStamp, 1005); - data.set(RuntimeData::Number, 1006); - data.set(RuntimeData::Difficulty, 16); - data.set(RuntimeData::GasLimit, 1008); - data.set(RuntimeData::CodeSize, bytecode.size()); - data.callData = (uint8_t*)"abc"; - data.code = bytecode.data(); - - // BROKEN: env_* functions must be implemented & RuntimeData struct created - // TODO: Do not compile module again - auto result = engine.run(bytecode, &data, nullptr); - return static_cast(result); - } - } - - return 0; -} diff --git a/evmjit/evmcc/test/arith/addmod.evm b/evmjit/evmcc/test/arith/addmod.evm deleted file mode 100644 index 4ca71e065..000000000 --- a/evmjit/evmcc/test/arith/addmod.evm +++ /dev/null @@ -1 +0,0 @@ -60646107b760271460005560006001f2 diff --git a/evmjit/evmcc/test/arith/addmod.lll b/evmjit/evmcc/test/arith/addmod.lll deleted file mode 100644 index 11a6b2cb9..000000000 --- a/evmjit/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/evmjit/evmcc/test/arith/arith1.evm b/evmjit/evmcc/test/arith/arith1.evm deleted file mode 100644 index c7a029f52..000000000 --- a/evmjit/evmcc/test/arith/arith1.evm +++ /dev/null @@ -1 +0,0 @@ -60016001900160070260050160029004600490066021900560150160030260059007600303600960110860005460086000f2 diff --git a/evmjit/evmcc/test/arith/arith1.lll b/evmjit/evmcc/test/arith/arith1.lll deleted file mode 100644 index 4757a7420..000000000 --- a/evmjit/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/evmjit/evmcc/test/arith/arith_bnot.evm b/evmjit/evmcc/test/arith/arith_bnot.evm deleted file mode 100644 index 4cfaf8f55..000000000 --- a/evmjit/evmcc/test/arith/arith_bnot.evm +++ /dev/null @@ -1 +0,0 @@ -6201e2406000546000530960005460206000f2 diff --git a/evmjit/evmcc/test/arith/arith_bnot.lll b/evmjit/evmcc/test/arith/arith_bnot.lll deleted file mode 100644 index a83b05a9a..000000000 --- a/evmjit/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/evmjit/evmcc/test/arith/div.evm b/evmjit/evmcc/test/arith/div.evm deleted file mode 100644 index b68d5d202..000000000 --- a/evmjit/evmcc/test/arith/div.evm +++ /dev/null @@ -1 +0,0 @@ -60027ffedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432100460005460206000f2 diff --git a/evmjit/evmcc/test/arith/div.lll b/evmjit/evmcc/test/arith/div.lll deleted file mode 100644 index 72c22bfdc..000000000 --- a/evmjit/evmcc/test/arith/div.lll +++ /dev/null @@ -1,10 +0,0 @@ -(asm -0x2 -0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 -DIV -0 -MSTORE -32 -0 -RETURN -) diff --git a/evmjit/evmcc/test/arith/fib1.evm b/evmjit/evmcc/test/arith/fib1.evm deleted file mode 100644 index 4c141314e..000000000 --- a/evmjit/evmcc/test/arith/fib1.evm +++ /dev/null @@ -1 +0,0 @@ -60016001818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101 diff --git a/evmjit/evmcc/test/arith/fib1.lll b/evmjit/evmcc/test/arith/fib1.lll deleted file mode 100644 index 286bed275..000000000 --- a/evmjit/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/evmjit/evmcc/test/arith/mul.evm b/evmjit/evmcc/test/arith/mul.evm deleted file mode 100644 index 7e8afd268..000000000 --- a/evmjit/evmcc/test/arith/mul.evm +++ /dev/null @@ -1 +0,0 @@ -7001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba0987654321020260005460206000f2 diff --git a/evmjit/evmcc/test/arith/mul.lll b/evmjit/evmcc/test/arith/mul.lll deleted file mode 100644 index b0fa343bb..000000000 --- a/evmjit/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/evmjit/evmcc/test/arith/mulmod.evm b/evmjit/evmcc/test/arith/mulmod.evm deleted file mode 100644 index e34a06154..000000000 --- a/evmjit/evmcc/test/arith/mulmod.evm +++ /dev/null @@ -1 +0,0 @@ -6064601b60251560005560006001f2 diff --git a/evmjit/evmcc/test/arith/mulmod.lll b/evmjit/evmcc/test/arith/mulmod.lll deleted file mode 100644 index 5e87f0843..000000000 --- a/evmjit/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/evmjit/evmcc/test/except/badinst1.evm b/evmjit/evmcc/test/except/badinst1.evm deleted file mode 100644 index 69aadac5e..000000000 --- a/evmjit/evmcc/test/except/badinst1.evm +++ /dev/null @@ -1 +0,0 @@ -4a diff --git a/evmjit/evmcc/test/ext/calldatacopy1.evm b/evmjit/evmcc/test/ext/calldatacopy1.evm deleted file mode 100644 index f20019651..000000000 --- a/evmjit/evmcc/test/ext/calldatacopy1.evm +++ /dev/null @@ -1 +0,0 @@ -60326000600a37600053600a6014f2 diff --git a/evmjit/evmcc/test/ext/calldatacopy1.lll b/evmjit/evmcc/test/ext/calldatacopy1.lll deleted file mode 100644 index 3d2ae0a78..000000000 --- a/evmjit/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/evmjit/evmcc/test/ext/calldatacopy2.evm b/evmjit/evmcc/test/ext/calldatacopy2.evm deleted file mode 100644 index e8eea8da7..000000000 --- a/evmjit/evmcc/test/ext/calldatacopy2.evm +++ /dev/null @@ -1 +0,0 @@ -606464e8d4a510006000376000536000600af2 diff --git a/evmjit/evmcc/test/ext/calldatacopy2.lll b/evmjit/evmcc/test/ext/calldatacopy2.lll deleted file mode 100644 index 6bbea48d8..000000000 --- a/evmjit/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/evmjit/evmcc/test/ext/codecopy1.evm b/evmjit/evmcc/test/ext/codecopy1.evm deleted file mode 100644 index d286f9232..000000000 --- a/evmjit/evmcc/test/ext/codecopy1.evm +++ /dev/null @@ -1 +0,0 @@ -60146000600a39600053600a6014f2 diff --git a/evmjit/evmcc/test/ext/codecopy1.lll b/evmjit/evmcc/test/ext/codecopy1.lll deleted file mode 100644 index 85a02b5d7..000000000 --- a/evmjit/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/evmjit/evmcc/test/ext/codecopy2.evm b/evmjit/evmcc/test/ext/codecopy2.evm deleted file mode 100644 index 71cd92525..000000000 --- a/evmjit/evmcc/test/ext/codecopy2.evm +++ /dev/null @@ -1 +0,0 @@ -606464e8d4a510006000396000536000600af2 diff --git a/evmjit/evmcc/test/ext/codecopy2.lll b/evmjit/evmcc/test/ext/codecopy2.lll deleted file mode 100644 index dcbbcaa46..000000000 --- a/evmjit/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/evmjit/evmcc/test/ext/codecopy3.evm b/evmjit/evmcc/test/ext/codecopy3.evm deleted file mode 100644 index e4b6a9253..000000000 --- a/evmjit/evmcc/test/ext/codecopy3.evm +++ /dev/null @@ -1 +0,0 @@ -3860006000396000536000600af2 diff --git a/evmjit/evmcc/test/ext/codecopy3.lll b/evmjit/evmcc/test/ext/codecopy3.lll deleted file mode 100644 index 80d9982c6..000000000 --- a/evmjit/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/evmjit/evmcc/test/ext/ext_test.evm b/evmjit/evmcc/test/ext/ext_test.evm deleted file mode 100644 index 580bd9675..000000000 --- a/evmjit/evmcc/test/ext/ext_test.evm +++ /dev/null @@ -1 +0,0 @@ -5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f1600053611000545b60200260002030ff60016002f2 diff --git a/evmjit/evmcc/test/ext/ext_test.lll b/evmjit/evmcc/test/ext/ext_test.lll deleted file mode 100644 index 3287ae95f..000000000 --- a/evmjit/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/evmjit/evmcc/test/ext/extcodecopy1.evm b/evmjit/evmcc/test/ext/extcodecopy1.evm deleted file mode 100644 index 6132b52d8..000000000 --- a/evmjit/evmcc/test/ext/extcodecopy1.evm +++ /dev/null @@ -1 +0,0 @@ -60c86000600a303c60005360006020f2 diff --git a/evmjit/evmcc/test/ext/extcodecopy1.lll b/evmjit/evmcc/test/ext/extcodecopy1.lll deleted file mode 100644 index c37054574..000000000 --- a/evmjit/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/evmjit/evmcc/test/ext/store_delete.evm b/evmjit/evmcc/test/ext/store_delete.evm deleted file mode 100644 index d6acae03d..000000000 --- a/evmjit/evmcc/test/ext/store_delete.evm +++ /dev/null @@ -1 +0,0 @@ -6104d26063576000606357 diff --git a/evmjit/evmcc/test/ext/store_delete.lll b/evmjit/evmcc/test/ext/store_delete.lll deleted file mode 100644 index 3d8f0f23a..000000000 --- a/evmjit/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/evmjit/evmcc/test/ext/store_test.evm b/evmjit/evmcc/test/ext/store_test.evm deleted file mode 100644 index 54c9419b5..000000000 --- a/evmjit/evmcc/test/ext/store_test.evm +++ /dev/null @@ -1 +0,0 @@ -607b607c60015760005760015660005603 diff --git a/evmjit/evmcc/test/ext/store_test.lll b/evmjit/evmcc/test/ext/store_test.lll deleted file mode 100644 index c40471c40..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/ackermann.ethel b/evmjit/evmcc/test/jump/ackermann.ethel deleted file mode 100644 index 971fd2b8d..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/ackermann.evm b/evmjit/evmcc/test/jump/ackermann.evm deleted file mode 100644 index 964844045..000000000 --- a/evmjit/evmcc/test/jump/ackermann.evm +++ /dev/null @@ -1 +0,0 @@ -6009600360086012585d60005460206000f26000820e6047596000810e603859603460018303603084600185036012585d6012585d60445860436001830360016012585d604b5860018101905090509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/badindirect1.evm b/evmjit/evmcc/test/jump/badindirect1.evm deleted file mode 100644 index b2a8aad67..000000000 --- a/evmjit/evmcc/test/jump/badindirect1.evm +++ /dev/null @@ -1 +0,0 @@ -601b602502585d diff --git a/evmjit/evmcc/test/jump/badindirect1.lll b/evmjit/evmcc/test/jump/badindirect1.lll deleted file mode 100644 index d6291be68..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/badindirect2.evm b/evmjit/evmcc/test/jump/badindirect2.evm deleted file mode 100644 index 22217523d..000000000 --- a/evmjit/evmcc/test/jump/badindirect2.evm +++ /dev/null @@ -1 +0,0 @@ -60016003600302596000600058 diff --git a/evmjit/evmcc/test/jump/badindirect2.lll b/evmjit/evmcc/test/jump/badindirect2.lll deleted file mode 100644 index 53a6294f7..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/badjump1.evm b/evmjit/evmcc/test/jump/badjump1.evm deleted file mode 100644 index 5c11a8661..000000000 --- a/evmjit/evmcc/test/jump/badjump1.evm +++ /dev/null @@ -1 +0,0 @@ -6103e758 diff --git a/evmjit/evmcc/test/jump/badjump1.lll b/evmjit/evmcc/test/jump/badjump1.lll deleted file mode 100644 index 1834a62ef..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/badjump2.evm b/evmjit/evmcc/test/jump/badjump2.evm deleted file mode 100644 index 900a1c15a..000000000 --- a/evmjit/evmcc/test/jump/badjump2.evm +++ /dev/null @@ -1 +0,0 @@ -6004586000600058 diff --git a/evmjit/evmcc/test/jump/badjump2.lll b/evmjit/evmcc/test/jump/badjump2.lll deleted file mode 100644 index ce61276d7..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/call1.ethel b/evmjit/evmcc/test/jump/call1.ethel deleted file mode 100644 index 414ad0124..000000000 --- a/evmjit/evmcc/test/jump/call1.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let f n = n + 1 - -return f 2 - - diff --git a/evmjit/evmcc/test/jump/call1.evm b/evmjit/evmcc/test/jump/call1.evm deleted file mode 100644 index 252aaf778..000000000 --- a/evmjit/evmcc/test/jump/call1.evm +++ /dev/null @@ -1 +0,0 @@ -600760026010585d60005460206000f28060010190509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/call2.ethel b/evmjit/evmcc/test/jump/call2.ethel deleted file mode 100644 index bdeb9b734..000000000 --- a/evmjit/evmcc/test/jump/call2.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let f a b = a + b - -return f 2 3 - - diff --git a/evmjit/evmcc/test/jump/call2.evm b/evmjit/evmcc/test/jump/call2.evm deleted file mode 100644 index 6832e044d..000000000 --- a/evmjit/evmcc/test/jump/call2.evm +++ /dev/null @@ -1 +0,0 @@ -6009600260036012585d60005460206000f2818101905090509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac.ethel b/evmjit/evmcc/test/jump/fac.ethel deleted file mode 100644 index 8bfe94dd6..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/fac.evm b/evmjit/evmcc/test/jump/fac.evm deleted file mode 100644 index 04cd3e4f4..000000000 --- a/evmjit/evmcc/test/jump/fac.evm +++ /dev/null @@ -1 +0,0 @@ -6007603c6010585d60005460206000f26000810e6026596020600182036010585d8102602858600190509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac_tail.ethel b/evmjit/evmcc/test/jump/fac_tail.ethel deleted file mode 100644 index 9ce5ecac7..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/fac_tail.evm b/evmjit/evmcc/test/jump/fac_tail.evm deleted file mode 100644 index 8384d94e4..000000000 --- a/evmjit/evmcc/test/jump/fac_tail.evm +++ /dev/null @@ -1 +0,0 @@ -60096001603c6012585d60005460206000f26000810e6029596025818302600183036012585d602a5881905090509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fib1.ethel b/evmjit/evmcc/test/jump/fib1.ethel deleted file mode 100644 index 81b869f41..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/fib1.evm b/evmjit/evmcc/test/jump/fib1.evm deleted file mode 100644 index 5042a192f..000000000 --- a/evmjit/evmcc/test/jump/fib1.evm +++ /dev/null @@ -1 +0,0 @@ -6007600a6010585d60005460206000f26003810a602f596020600282036010585d602a600183036010585d01603158600190509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/for1.evm b/evmjit/evmcc/test/jump/for1.evm deleted file mode 100644 index f8e65cbf2..000000000 --- a/evmjit/evmcc/test/jump/for1.evm +++ /dev/null @@ -1 +0,0 @@ -600a60805460006080530b0f60255960a0536080530160a054600160805303608054600558 diff --git a/evmjit/evmcc/test/jump/for1.lll b/evmjit/evmcc/test/jump/for1.lll deleted file mode 100644 index 419fc9b54..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/for2.evm b/evmjit/evmcc/test/jump/for2.evm deleted file mode 100644 index 628297778..000000000 --- a/evmjit/evmcc/test/jump/for2.evm +++ /dev/null @@ -1 +0,0 @@ -6000608054600a6080530a0f60255960a0536080530160a054600160805301608054600558 diff --git a/evmjit/evmcc/test/jump/for2.lll b/evmjit/evmcc/test/jump/for2.lll deleted file mode 100644 index de17d65ac..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/if1.ethel b/evmjit/evmcc/test/jump/if1.ethel deleted file mode 100644 index 85c3e126b..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/if1.evm b/evmjit/evmcc/test/jump/if1.evm deleted file mode 100644 index 51fbe04bd..000000000 --- a/evmjit/evmcc/test/jump/if1.evm +++ /dev/null @@ -1 +0,0 @@ -60006300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/if2.ethel b/evmjit/evmcc/test/jump/if2.ethel deleted file mode 100644 index 2a58d6365..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/if2.evm b/evmjit/evmcc/test/jump/if2.evm deleted file mode 100644 index 6d823b374..000000000 --- a/evmjit/evmcc/test/jump/if2.evm +++ /dev/null @@ -1 +0,0 @@ -60016300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/indirect1.evm b/evmjit/evmcc/test/jump/indirect1.evm deleted file mode 100644 index ab6928304..000000000 --- a/evmjit/evmcc/test/jump/indirect1.evm +++ /dev/null @@ -1 +0,0 @@ -600460030158005d6001600054 diff --git a/evmjit/evmcc/test/jump/indirect1.lll b/evmjit/evmcc/test/jump/indirect1.lll deleted file mode 100644 index 1ee7dc347..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/indirect2.evm b/evmjit/evmcc/test/jump/indirect2.evm deleted file mode 100644 index e9697eaa1..000000000 --- a/evmjit/evmcc/test/jump/indirect2.evm +++ /dev/null @@ -1 +0,0 @@ -600860060158005d6001600054005d600260005400 diff --git a/evmjit/evmcc/test/jump/indirect2.lll b/evmjit/evmcc/test/jump/indirect2.lll deleted file mode 100644 index f2f068630..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/indirect3.evm b/evmjit/evmcc/test/jump/indirect3.evm deleted file mode 100644 index 1fb0a356c..000000000 --- a/evmjit/evmcc/test/jump/indirect3.evm +++ /dev/null @@ -1 +0,0 @@ -6001600460050159005d6001600054 diff --git a/evmjit/evmcc/test/jump/indirect3.lll b/evmjit/evmcc/test/jump/indirect3.lll deleted file mode 100644 index d6a679f9a..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/indirect4.evm b/evmjit/evmcc/test/jump/indirect4.evm deleted file mode 100644 index f0e31a8f4..000000000 --- a/evmjit/evmcc/test/jump/indirect4.evm +++ /dev/null @@ -1 +0,0 @@ -60006007600501596001600054005d00 diff --git a/evmjit/evmcc/test/jump/indirect4.lll b/evmjit/evmcc/test/jump/indirect4.lll deleted file mode 100644 index 7fbe0b833..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/jump1.evm b/evmjit/evmcc/test/jump/jump1.evm deleted file mode 100644 index 0df9b4036..000000000 --- a/evmjit/evmcc/test/jump/jump1.evm +++ /dev/null @@ -1 +0,0 @@ -600458006001600154 diff --git a/evmjit/evmcc/test/jump/jump1.lll b/evmjit/evmcc/test/jump/jump1.lll deleted file mode 100644 index 33119edb3..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/jump2.evm b/evmjit/evmcc/test/jump/jump2.evm deleted file mode 100644 index 35d75941d..000000000 --- a/evmjit/evmcc/test/jump/jump2.evm +++ /dev/null @@ -1 +0,0 @@ -6008586001600154 diff --git a/evmjit/evmcc/test/jump/jump2.lll b/evmjit/evmcc/test/jump/jump2.lll deleted file mode 100644 index a70d50ecb..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/jump3.evm b/evmjit/evmcc/test/jump/jump3.evm deleted file mode 100644 index 599d4a764..000000000 --- a/evmjit/evmcc/test/jump/jump3.evm +++ /dev/null @@ -1 +0,0 @@ -602a586001600154 diff --git a/evmjit/evmcc/test/jump/jump3.lll b/evmjit/evmcc/test/jump/jump3.lll deleted file mode 100644 index bc897e30c..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/jump4.evm b/evmjit/evmcc/test/jump/jump4.evm deleted file mode 100644 index 41713f43e..000000000 --- a/evmjit/evmcc/test/jump/jump4.evm +++ /dev/null @@ -1 +0,0 @@ -600b6009580000600558005d6001600154 diff --git a/evmjit/evmcc/test/jump/jump4.lll b/evmjit/evmcc/test/jump/jump4.lll deleted file mode 100644 index 131baee2d..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/jump5.evm b/evmjit/evmcc/test/jump/jump5.evm deleted file mode 100644 index c36d9615b..000000000 --- a/evmjit/evmcc/test/jump/jump5.evm +++ /dev/null @@ -1 +0,0 @@ -6005600e585d600160015400600f5800 diff --git a/evmjit/evmcc/test/jump/jump5.lll b/evmjit/evmcc/test/jump/jump5.lll deleted file mode 100644 index d28b7d4ac..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/jump6.evm b/evmjit/evmcc/test/jump/jump6.evm deleted file mode 100644 index 029db7191..000000000 --- a/evmjit/evmcc/test/jump/jump6.evm +++ /dev/null @@ -1 +0,0 @@ -600358600f600d58006014600758005d6001600154005d600260025400 diff --git a/evmjit/evmcc/test/jump/jump6.lll b/evmjit/evmcc/test/jump/jump6.lll deleted file mode 100644 index 1116aa663..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/jumpi_at_the_end.evm b/evmjit/evmcc/test/jump/jumpi_at_the_end.evm deleted file mode 100644 index 2d7411761..000000000 --- a/evmjit/evmcc/test/jump/jumpi_at_the_end.evm +++ /dev/null @@ -1 +0,0 @@ -600a6000545d6000536001900380600054600659 diff --git a/evmjit/evmcc/test/jump/jumpi_at_the_end.lll b/evmjit/evmcc/test/jump/jumpi_at_the_end.lll deleted file mode 100644 index 263ada6a7..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/loop1.evm b/evmjit/evmcc/test/jump/loop1.evm deleted file mode 100644 index 7724d6308..000000000 --- a/evmjit/evmcc/test/jump/loop1.evm +++ /dev/null @@ -1 +0,0 @@ -600a600181038060025960005460015460025400 diff --git a/evmjit/evmcc/test/jump/loop1.lll b/evmjit/evmcc/test/jump/loop1.lll deleted file mode 100644 index 0044ec1fb..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/loop2.evm b/evmjit/evmcc/test/jump/loop2.evm deleted file mode 100644 index faffa4e5b..000000000 --- a/evmjit/evmcc/test/jump/loop2.evm +++ /dev/null @@ -1 +0,0 @@ -600a80600190038060025960005460015460025400 diff --git a/evmjit/evmcc/test/jump/loop2.lll b/evmjit/evmcc/test/jump/loop2.lll deleted file mode 100644 index 9996c52ba..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/rec1.ethel b/evmjit/evmcc/test/jump/rec1.ethel deleted file mode 100644 index f83c8e81e..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/rec1.evm b/evmjit/evmcc/test/jump/rec1.evm deleted file mode 100644 index 2ae62aff6..000000000 --- a/evmjit/evmcc/test/jump/rec1.evm +++ /dev/null @@ -1 +0,0 @@ -6007600a6010585d60005460206000f26000810e6024596020600182036010585d602658600290509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/when1.asm b/evmjit/evmcc/test/jump/when1.asm deleted file mode 100644 index 01d41c266..000000000 --- a/evmjit/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/evmjit/evmcc/test/jump/when1.evm b/evmjit/evmcc/test/jump/when1.evm deleted file mode 100644 index 303b02623..000000000 --- a/evmjit/evmcc/test/jump/when1.evm +++ /dev/null @@ -1 +0,0 @@ -60010f600b59600d608054 diff --git a/evmjit/evmcc/test/jump/when1.lll b/evmjit/evmcc/test/jump/when1.lll deleted file mode 100644 index 990a6e64a..000000000 --- a/evmjit/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/evmjit/evmcc/test/kv.evm b/evmjit/evmcc/test/kv.evm deleted file mode 100644 index 55141ea59..000000000 --- a/evmjit/evmcc/test/kv.evm +++ /dev/null @@ -1 +0,0 @@ -33604557602a8060106000396000f200604556330e0f602a59366080530a0f602a59602060805301356080533557604060805301608054600958 diff --git a/evmjit/evmcc/test/kv.lll b/evmjit/evmcc/test/kv.lll deleted file mode 100644 index c62d9fa70..000000000 --- a/evmjit/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/evmjit/evmcc/test/mem/byte.evm b/evmjit/evmcc/test/mem/byte.evm deleted file mode 100644 index ab63431ee..000000000 --- a/evmjit/evmcc/test/mem/byte.evm +++ /dev/null @@ -1 +0,0 @@ -7f112233445566778899001122334455667788990011223344556677889900aabb6000137f112233445566778899001122334455667788990011223344556677889900aabb6001137f112233445566778899001122334455667788990011223344556677889900aabb6002137f112233445566778899001122334455667788990011223344556677889900aabb6003137f112233445566778899001122334455667788990011223344556677889900aabb6004137f112233445566778899001122334455667788990011223344556677889900aabb6005137f112233445566778899001122334455667788990011223344556677889900aabb6006137f112233445566778899001122334455667788990011223344556677889900aabb6007137f112233445566778899001122334455667788990011223344556677889900aabb6008137f112233445566778899001122334455667788990011223344556677889900aabb6009137f112233445566778899001122334455667788990011223344556677889900aabb600a137f112233445566778899001122334455667788990011223344556677889900aabb600b137f112233445566778899001122334455667788990011223344556677889900aabb600c137f112233445566778899001122334455667788990011223344556677889900aabb600d137f112233445566778899001122334455667788990011223344556677889900aabb600e137f112233445566778899001122334455667788990011223344556677889900aabb600f137f112233445566778899001122334455667788990011223344556677889900aabb6010137f112233445566778899001122334455667788990011223344556677889900aabb6011137f112233445566778899001122334455667788990011223344556677889900aabb6012137f112233445566778899001122334455667788990011223344556677889900aabb6013137f112233445566778899001122334455667788990011223344556677889900aabb6014137f112233445566778899001122334455667788990011223344556677889900aabb6015137f112233445566778899001122334455667788990011223344556677889900aabb6016137f112233445566778899001122334455667788990011223344556677889900aabb6017137f112233445566778899001122334455667788990011223344556677889900aabb6018137f112233445566778899001122334455667788990011223344556677889900aabb6019137f112233445566778899001122334455667788990011223344556677889900aabb601a137f112233445566778899001122334455667788990011223344556677889900aabb601b137f112233445566778899001122334455667788990011223344556677889900aabb601c137f112233445566778899001122334455667788990011223344556677889900aabb601d137f112233445566778899001122334455667788990011223344556677889900aabb601e137f112233445566778899001122334455667788990011223344556677889900aabb601f137f112233445566778899001122334455667788990011223344556677889900aabb6020137f112233445566778899001122334455667788990011223344556677889900aabb6107de13 diff --git a/evmjit/evmcc/test/mem/byte.lll b/evmjit/evmcc/test/mem/byte.lll deleted file mode 100644 index 95b0f99dc..000000000 --- a/evmjit/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/evmjit/evmcc/test/mem/mem2.evm b/evmjit/evmcc/test/mem/mem2.evm deleted file mode 100644 index 49cc6e8b1..000000000 --- a/evmjit/evmcc/test/mem/mem2.evm +++ /dev/null @@ -1 +0,0 @@ -6001610d805b01556504409585d6df620493e05462061a80535b01 diff --git a/evmjit/evmcc/test/mem/mem2.lll b/evmjit/evmcc/test/mem/mem2.lll deleted file mode 100644 index 5345ee47c..000000000 --- a/evmjit/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/evmjit/evmcc/test/mem/memtest1.evm b/evmjit/evmcc/test/mem/memtest1.evm deleted file mode 100644 index 0506bf928..000000000 --- a/evmjit/evmcc/test/mem/memtest1.evm +++ /dev/null @@ -1 +0,0 @@ -6002600055600360015560005360015301600254 diff --git a/evmjit/evmcc/test/mem/memtest1.lll b/evmjit/evmcc/test/mem/memtest1.lll deleted file mode 100644 index 4b4389ad8..000000000 --- a/evmjit/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/evmjit/evmcc/test/mem/mstore1.evm b/evmjit/evmcc/test/mem/mstore1.evm deleted file mode 100644 index ba6141ab1..000000000 --- a/evmjit/evmcc/test/mem/mstore1.evm +++ /dev/null @@ -1 +0,0 @@ -6001600054 diff --git a/evmjit/evmcc/test/mem/mstore1.lll b/evmjit/evmcc/test/mem/mstore1.lll deleted file mode 100644 index 2d2ca32b5..000000000 --- a/evmjit/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/evmjit/evmcc/test/ret/return1.evm b/evmjit/evmcc/test/ret/return1.evm deleted file mode 100644 index 8092cb007..000000000 --- a/evmjit/evmcc/test/ret/return1.evm +++ /dev/null @@ -1 +0,0 @@ -600160805460006080530b601b59600160005460206000f2602a58602760005460206000f26002608054 diff --git a/evmjit/evmcc/test/ret/return1.lll b/evmjit/evmcc/test/ret/return1.lll deleted file mode 100644 index 159d15ca3..000000000 --- a/evmjit/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/evmjit/evmcc/test/ret/return2.evm b/evmjit/evmcc/test/ret/return2.evm deleted file mode 100644 index e29da7664..000000000 --- a/evmjit/evmcc/test/ret/return2.evm +++ /dev/null @@ -1 +0,0 @@ -6001620f4240f2 diff --git a/evmjit/evmcc/test/ret/return2.lll b/evmjit/evmcc/test/ret/return2.lll deleted file mode 100644 index f5ee68f6e..000000000 --- a/evmjit/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/evmjit/evmcc/test/ret/return_test.evm b/evmjit/evmcc/test/ret/return_test.evm deleted file mode 100644 index 977cf7c19..000000000 --- a/evmjit/evmcc/test/ret/return_test.evm +++ /dev/null @@ -1 +0,0 @@ -60016064546002608454600360a45460606064f2 diff --git a/evmjit/evmcc/test/ret/return_test.lll b/evmjit/evmcc/test/ret/return_test.lll deleted file mode 100644 index c87a2d812..000000000 --- a/evmjit/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/evmjit/evmcc/test/stack/oos.evm b/evmjit/evmcc/test/stack/oos.evm deleted file mode 100644 index ea2f1c890..000000000 --- a/evmjit/evmcc/test/stack/oos.evm +++ /dev/null @@ -1 +0,0 @@ -60018194505050509150 diff --git a/evmjit/evmcc/test/stack/oos.lll b/evmjit/evmcc/test/stack/oos.lll deleted file mode 100644 index 5394b06ba..000000000 --- a/evmjit/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/evmjit/evmcc/test/stack/push_test.evm b/evmjit/evmcc/test/stack/push_test.evm deleted file mode 100644 index d624cee1d..000000000 --- a/evmjit/evmcc/test/stack/push_test.evm +++ /dev/null @@ -1 +0,0 @@ -60656107d26204a0c763026921f4640bc5588eb165372d0f1dca6e661ba1d901961c71670c55f7bc23038e3868056bc75e2d630fffff69021e19e0c9bab24000016a085d1c6e8050f0ea1c71bd6b0688be36543f3c36e638e37a6c03d41f73d55d0d482ae55555376dc76810d0fe03c91964d31c71c6f46e615dd0360c07d931663b14e38e38b16f2da3f99955a3adcf27ebb1caaaaaaa6e7014ccba6a8bb1ed35bd86bf065c71c71c2b7109491c5d4781b79c9009de6bfb8e38e38de8720414a0f6fdec81304d4c563e740bffffffffa573118427b3b4a05bc8a8a4de8459868000000000017406eb15e7331e727940d4ac54b7cdca1c71c71c71bd750567a91c9fefc96ebaa626a22f98c5e638e38e38e37a76032abd16c5b68006e15d5aa307e383f4e55555555555377701a6427bdc4f0d58eab5f48a3ec67f64e21c71c71c71c6f478080dd0a0c9b9ff2c2a0c740b06853a0a980ee38e38e38e38b17903c679cb5e8f2f9cb3b5d6652b0e7334f746faaaaaaaaaaaaa6e7a01b873815917ebb2bf3b890a1af495d6235bae3c71c71c71c71c2b7b07ae4cca96e1a55dfa49c85ad3c3e60e426b92fb8e38e38e38e38de87c036018bf074e292bcc7d6c8bea0f9699443046178bffffffffffffffa57d0e7d34c64a9c85d4460dbbca87196b61618a4bd2168000000000000000017e05b901f48a5b994d6572502bc4ea43140486666416aa1c71c71c71c71c71bd7f047889870c178fc477414ea231d70467a388fffe31b4e638e38e38e38e38e37a diff --git a/evmjit/evmcc/test/stack/push_test.lll b/evmjit/evmcc/test/stack/push_test.lll deleted file mode 100644 index 832daaec1..000000000 --- a/evmjit/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/evmjit/evmcc/test/stack/stack_test.evm b/evmjit/evmcc/test/stack/stack_test.evm deleted file mode 100644 index 02417c967..000000000 --- a/evmjit/evmcc/test/stack/stack_test.evm +++ /dev/null @@ -1 +0,0 @@ -65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae81819290 diff --git a/evmjit/evmcc/test/stack/stack_test.lll b/evmjit/evmcc/test/stack/stack_test.lll deleted file mode 100644 index fdf83594c..000000000 --- a/evmjit/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/evmjit/evmcc/test/stack/stackjump.evm b/evmjit/evmcc/test/stack/stackjump.evm deleted file mode 100644 index baddec42e..000000000 --- a/evmjit/evmcc/test/stack/stackjump.evm +++ /dev/null @@ -1 +0,0 @@ -600460066009601358600a036000545b6000f260005401600958 \ No newline at end of file diff --git a/evmjit/evmcc/test/stack/stackjump.lll b/evmjit/evmcc/test/stack/stackjump.lll deleted file mode 100644 index f5da5e733..000000000 --- a/evmjit/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/evmjit/evmcc/test/stack/swap.evm b/evmjit/evmcc/test/stack/swap.evm deleted file mode 100644 index d17f0ee09..000000000 --- a/evmjit/evmcc/test/stack/swap.evm +++ /dev/null @@ -1 +0,0 @@ -600560026001600c59505000906001601559505000036000546001601ff2 diff --git a/evmjit/evmcc/test/stack/swap.lll b/evmjit/evmcc/test/stack/swap.lll deleted file mode 100644 index 90dee585d..000000000 --- a/evmjit/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/evmjit/evmcc/test/stack/swapswap.evm b/evmjit/evmcc/test/stack/swapswap.evm deleted file mode 100644 index fb4f1bf75..000000000 --- a/evmjit/evmcc/test/stack/swapswap.evm +++ /dev/null @@ -1 +0,0 @@ -600260056001600c5950500090906001601659505000036000546001601ff2 diff --git a/evmjit/evmcc/test/stack/swapswap.lll b/evmjit/evmcc/test/stack/swapswap.lll deleted file mode 100644 index 1fedf726e..000000000 --- a/evmjit/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/evmjit/evmcc/test/stack/test.evm b/evmjit/evmcc/test/stack/test.evm deleted file mode 100644 index ea2f1c890..000000000 --- a/evmjit/evmcc/test/stack/test.evm +++ /dev/null @@ -1 +0,0 @@ -60018194505050509150 diff --git a/evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json b/evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json deleted file mode 100644 index d9017517f..000000000 --- a/evmjit/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/evmjit/evmcc/test/vmtests/vmPerformanceTest.json b/evmjit/evmcc/test/vmtests/vmPerformanceTest.json deleted file mode 100644 index 604e45993..000000000 --- a/evmjit/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/evmjit/evmcc/test/vmtests/vm_jump.json b/evmjit/evmcc/test/vmtests/vm_jump.json deleted file mode 100644 index 6b63edeae..000000000 --- a/evmjit/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/evmjit/libevmjit-cpp/CMakeLists.txt b/evmjit/libevmjit-cpp/CMakeLists.txt deleted file mode 100644 index 25be95177..000000000 --- a/evmjit/libevmjit-cpp/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(TARGET_NAME evmjit-cpp) - -set(SOURCES - Env.cpp - JitVM.cpp JitVM.h -) -source_group("" FILES ${SOURCES}) - -add_library(${TARGET_NAME} ${SOURCES}) -set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") - -include_directories(../..) -include_directories(${LLVM_INCLUDE_DIRS}) -include_directories(${Boost_INCLUDE_DIRS}) - -target_link_libraries(${TARGET_NAME} evmjit) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp deleted file mode 100644 index 6320aa222..000000000 --- a/evmjit/libevmjit-cpp/Env.cpp +++ /dev/null @@ -1,119 +0,0 @@ - -#include -#include -#include - -#include - -extern "C" -{ - #ifdef _MSC_VER - #define EXPORT __declspec(dllexport) - #else - #define EXPORT - #endif - - using namespace dev; - using namespace dev::eth; - using jit::i256; - using jit::eth2llvm; - - EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) - { - auto index = llvm2eth(*_index); - auto value = _env->store(index); // Interface uses native endianness - *o_value = eth2llvm(value); - } - - EXPORT void env_sstore(ExtVMFace* _env, i256* _index, i256* _value) - { - auto index = llvm2eth(*_index); - auto value = llvm2eth(*_value); - - if (value == 0 && _env->store(index) != 0) // If delete - _env->sub.refunds += c_sstoreRefundGas; // Increase refund counter - - _env->setStore(index, value); // Interface uses native endianness - } - - EXPORT void env_balance(ExtVMFace* _env, h256* _address, i256* o_value) - { - auto u = _env->balance(right160(*_address)); - *o_value = eth2llvm(u); - } - - EXPORT void env_blockhash(ExtVMFace* _env, i256* _number, h256* o_hash) - { - *o_hash = _env->blockhash(llvm2eth(*_number)); - } - - EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) - { - auto endowment = llvm2eth(*_endowment); - if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) - { - _env->subBalance(endowment); - auto gas = llvm2eth(*io_gas); - OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); - *io_gas = eth2llvm(gas); - *o_address = address; - } - else - *o_address = {}; - } - - EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) - { - auto value = llvm2eth(*_value); - if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) - { - _env->subBalance(value); - auto receiveAddress = right160(*_receiveAddress); - auto inRef = bytesConstRef{_inBeg, _inSize}; - auto outRef = bytesConstRef{_outBeg, _outSize}; - OnOpFunc onOp {}; // TODO: Handle that thing - auto codeAddress = right160(*_codeAddress); - auto gas = llvm2eth(*io_gas); - auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); - *io_gas = eth2llvm(gas); - return ret; - } - - return false; - } - - EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) - { - auto hash = sha3({_begin, _size}); - *o_hash = hash; - } - - EXPORT byte const* env_getExtCode(ExtVMFace* _env, h256* _addr256, uint64_t* o_size) - { - auto addr = right160(*_addr256); - auto& code = _env->codeAt(addr); - *o_size = code.size(); - return code.data(); - } - - EXPORT void env_log(ExtVMFace* _env, byte* _beg, uint64_t _size, h256* _topic1, h256* _topic2, h256* _topic3, h256* _topic4) - { - dev::h256s topics; - - if (_topic1) - topics.push_back(*_topic1); - - if (_topic2) - topics.push_back(*_topic2); - - if (_topic3) - topics.push_back(*_topic3); - - if (_topic4) - topics.push_back(*_topic4); - - _env->log(std::move(topics), {_beg, _size}); - } -} - diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp deleted file mode 100644 index dda8133a8..000000000 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ /dev/null @@ -1,68 +0,0 @@ - -#include "JitVM.h" -#include -#include -#include - -namespace dev -{ -namespace eth -{ - -bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) -{ - using namespace jit; - - m_data.set(RuntimeData::Gas, m_gas); - m_data.set(RuntimeData::Address, fromAddress(_ext.myAddress)); - m_data.set(RuntimeData::Caller, fromAddress(_ext.caller)); - m_data.set(RuntimeData::Origin, fromAddress(_ext.origin)); - m_data.set(RuntimeData::CallValue, _ext.value); - m_data.set(RuntimeData::CallDataSize, _ext.data.size()); - m_data.set(RuntimeData::GasPrice, _ext.gasPrice); - m_data.set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress)); - m_data.set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp); - m_data.set(RuntimeData::Number, _ext.currentBlock.number); - m_data.set(RuntimeData::Difficulty, _ext.currentBlock.difficulty); - m_data.set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); - m_data.set(RuntimeData::CodeSize, _ext.code.size()); - m_data.callData = _ext.data.data(); - m_data.code = _ext.code.data(); - - auto env = reinterpret_cast(&_ext); - auto exitCode = m_engine.run(_ext.code, &m_data, env); - switch (exitCode) - { - case ReturnCode::Suicide: - _ext.suicide(right160(m_data.get(RuntimeData::SuicideDestAddress))); - break; - - 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_gas = llvm2eth(m_data.elems[RuntimeData::Gas]); - return {m_engine.returnData.data(), m_engine.returnData.size()}; // TODO: This all bytesConstRef is problematic, review. -} - -} -} - -namespace -{ - // MSVS linker ignores export symbols in Env.cpp if nothing points at least one of them - extern "C" void env_sload(); - void linkerWorkaround() - { - env_sload(); - (void)&linkerWorkaround; // suppress unused function warning from GCC - } -} diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h deleted file mode 100644 index 90855127e..000000000 --- a/evmjit/libevmjit-cpp/JitVM.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include - -namespace dev -{ -namespace eth -{ - -class JitVM: 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 class VMFactory; - explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} - - jit::RuntimeData m_data; - jit::ExecutionEngine m_engine; -}; - - -} -} diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp deleted file mode 100644 index b5319bda7..000000000 --- a/evmjit/libevmjit/Arith256.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "Arith256.h" -#include "Runtime.h" -#include "Type.h" - -#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_exp = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_exp", 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::exp(llvm::Value* _arg1, llvm::Value* _arg2) -{ - return binaryOp(m_exp, _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); -} - -namespace -{ - using s256 = boost::multiprecision::int256_t; - - inline s256 u2s(u256 _u) - { - static const bigint c_end = (bigint)1 << 256; - static const u256 c_send = (u256)1 << 255; - if (_u < c_send) - return (s256)_u; - else - return (s256)-(c_end - _u); - } - - inline u256 s2u(s256 _u) - { - static const bigint c_end = (bigint)1 << 256; - if (_u >= 0) - return (u256)_u; - else - return (u256)(c_end + _u); - } -} - -} -} -} - - -extern "C" -{ - - using namespace dev::eth::jit; - - EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result) - { - auto arg1 = llvm2eth(*_arg1); - auto arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg1 * arg2); - } - - EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result) - { - auto arg1 = llvm2eth(*_arg1); - auto arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); - } - - EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result) - { - auto arg1 = llvm2eth(*_arg1); - auto arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); - } - - EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result) - { - auto arg1 = llvm2eth(*_arg1); - auto arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) / u2s(arg2))); - } - - EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result) - { - auto arg1 = llvm2eth(*_arg1); - auto arg2 = llvm2eth(*_arg2); - *o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) % u2s(arg2))); - } - - EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result) - { - bigint left = llvm2eth(*_arg1); - bigint right = llvm2eth(*_arg2); - auto ret = static_cast(boost::multiprecision::powm(left, right, bigint(2) << 256)); - *o_result = eth2llvm(ret); - } - - EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) - { - auto arg1 = llvm2eth(*_arg1); - auto arg2 = llvm2eth(*_arg2); - auto arg3 = llvm2eth(*_arg3); - if (arg3 != 0) - *o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3)); - else - *o_result = {}; - } - - EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) - { - auto arg1 = llvm2eth(*_arg1); - auto arg2 = llvm2eth(*_arg2); - auto arg3 = llvm2eth(*_arg3); - if (arg3 != 0) - *o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3)); - else - *o_result = {}; - } - -} - - diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h deleted file mode 100644 index 57bc061de..000000000 --- a/evmjit/libevmjit/Arith256.h +++ /dev/null @@ -1,49 +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* exp(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_exp; - 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/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp deleted file mode 100644 index 5868c0f43..000000000 --- a/evmjit/libevmjit/BasicBlock.cpp +++ /dev/null @@ -1,378 +0,0 @@ - -#include "BasicBlock.h" - -#include - -#include -#include -#include -#include -#include - -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -const char* BasicBlock::NamePrefix = "Instr."; - -BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : - m_begin(_begin), - m_end(_end), - // TODO: Add begin index to name - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)), - m_stack(*this), - m_builder(_builder), - m_isJumpDest(isJumpDest) -{} - -BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), - m_stack(*this), - m_builder(_builder), - m_isJumpDest(isJumpDest) -{} - -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_" + std::to_string(_index); - initialStack[initialIdx] = m_bblock.m_builder.CreatePHI(Type::Word, 0, std::move(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; - - llvm::PHINode* phi = llvm::cast(val); - // 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); // OPT: Value may be never user but we need to check stack heigth - // It is probably a good idea to keep heigth as a local variable accesible by LLVM directly - phi->replaceAllUsesWith(newVal); - phi->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/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h deleted file mode 100644 index 7a5364a4e..000000000 --- a/evmjit/libevmjit/BasicBlock.h +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once -#include -#include -#include "Common.h" -#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 instruction index. - static const char* NamePrefix; - - explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); - explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); - - BasicBlock(const BasicBlock&) = delete; - void operator=(const BasicBlock&) = delete; - - llvm::BasicBlock* llvm() { return m_llvmBB; } - - bytes::const_iterator begin() { return m_begin; } - bytes::const_iterator end() { return m_end; } - - bool isJumpDest() const { return m_isJumpDest; } - - 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: - bytes::const_iterator const m_begin; - bytes::const_iterator const m_end; - - 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; - - /// Is the basic block a valid jump destination. - /// JUMPDEST is the first instruction of the basic block. - bool const m_isJumpDest = false; -}; - -} -} -} - diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt deleted file mode 100644 index 7c35169a7..000000000 --- a/evmjit/libevmjit/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -set(TARGET_NAME evmjit) - -file(GLOB SOURCES "*.cpp") -file(GLOB HEADERS "*.h") -source_group("" FILES ${HEADERS}) -source_group("" FILES ${SOURCES}) - -if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # Disable rtti for Cache as LLVM has no rtti - set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) -endif () - -add_library(${TARGET_NAME} ${SOURCES} ${HEADERS}) -set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") - -include_directories(${LLVM_INCLUDE_DIRS}) -include_directories(${Boost_INCLUDE_DIRS}) - -target_link_libraries(${TARGET_NAME} ${LLVM_LIBS}) - -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") - -#install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) -#install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp deleted file mode 100644 index 0b725bc24..000000000 --- a/evmjit/libevmjit/Cache.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "Cache.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -//#define LOG(...) std::cerr << "CACHE " -#define LOG(...) std::ostream(nullptr) - -ObjectCache* Cache::getObjectCache() -{ - static ObjectCache objectCache; - return &objectCache; -} - -namespace -{ - llvm::MemoryBuffer* lastObject; -} - -std::unique_ptr Cache::getObject(std::string const& id) -{ - assert(!lastObject); - llvm::SmallString<256> cachePath; - llvm::sys::path::system_temp_directory(false, cachePath); - llvm::sys::path::append(cachePath, "evm_objs", id); - - if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); - else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) - std::cerr << r.getError().message(); // TODO: Add log - - if (lastObject) // if object found create fake module - { - auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); - auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); - llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); - } - return nullptr; -} - - -void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) -{ - auto&& id = _module->getModuleIdentifier(); - llvm::SmallString<256> cachePath; - llvm::sys::path::system_temp_directory(false, cachePath); - llvm::sys::path::append(cachePath, "evm_objs"); - - if (llvm::sys::fs::create_directory(cachePath.str())) - return; // TODO: Add log - - llvm::sys::path::append(cachePath, id); - - std::string error; - llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); - cacheFile << _object->getBuffer(); -} - -llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) -{ - auto o = lastObject; - lastObject = nullptr; - return o; -} - -} -} -} diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h deleted file mode 100644 index 1cad537cd..000000000 --- a/evmjit/libevmjit/Cache.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include -#include - - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class ObjectCache : public llvm::ObjectCache -{ -public: - /// notifyObjectCompiled - Provides a pointer to compiled code for Module M. - virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) final override; - - /// getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that - /// contains the object which corresponds with Module M, or 0 if an object is - /// not available. The caller owns both the MemoryBuffer returned by this - /// and the memory it references. - virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; - -private: - std::unordered_map> m_map; -}; - - -class Cache -{ -public: - static ObjectCache* getObjectCache(); - static std::unique_ptr getObject(std::string const& id); -}; - -} -} -} diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h deleted file mode 100644 index 1d8451c74..000000000 --- a/evmjit/libevmjit/Common.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -using byte = uint8_t; -using bytes = std::vector; -using u256 = boost::multiprecision::uint256_t; -using bigint = boost::multiprecision::cpp_int; - -struct NoteChannel {}; // FIXME: Use some log library? - -enum class ReturnCode -{ - Stop = 0, - Return = 1, - Suicide = 2, - - BadJumpDestination = 101, - OutOfGas = 102, - StackTooSmall = 103, - BadInstruction = 104, - - LLVMConfigError = 201, - LLVMCompileError = 202, - LLVMLinkError = 203, -}; - -/// Representation of 256-bit value binary compatible with LLVM i256 -// TODO: Replace with h256 -struct i256 -{ - uint64_t a = 0; - uint64_t b = 0; - uint64_t c = 0; - uint64_t d = 0; -}; -static_assert(sizeof(i256) == 32, "Wrong i265 size"); - -#define UNTESTED assert(false) - -} -} -} diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp deleted file mode 100644 index bfcb9cea1..000000000 --- a/evmjit/libevmjit/Compiler.cpp +++ /dev/null @@ -1,898 +0,0 @@ - -#include "Compiler.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "Instruction.h" -#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 "RuntimeManager.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) -{ - /// Helper function that skips push data and finds next iterator (can be the end) - auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end) - { - static const auto push1 = static_cast(Instruction::PUSH1); - static const auto push32 = static_cast(Instruction::PUSH32); - size_t offset = 1; - if (*_curr >= push1 && *_curr <= push32) - offset += std::min(*_curr - push1 + 1, (_end - _curr) - 1); - return _curr + offset; - }; - - auto begin = _bytecode.begin(); - bool nextJumpDest = false; - for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next) - { - next = skipPushDataAndGetNext(curr, _bytecode.end()); - - bool isEnd = false; - switch (Instruction(*curr)) - { - case Instruction::JUMP: - case Instruction::JUMPI: - case Instruction::RETURN: - case Instruction::STOP: - case Instruction::SUICIDE: - isEnd = true; - break; - - case Instruction::JUMPDEST: - nextJumpDest = true; - break; - - default: - break; - } - - assert(next <= _bytecode.end()); - if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST) - isEnd = true; - - if (isEnd) - { - auto beginIdx = begin - _bytecode.begin(); - m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), - std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); - nextJumpDest = false; - begin = next; - } - } - - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); -} - -llvm::BasicBlock* Compiler::getJumpTableBlock() -{ - if (!m_jumpTableBlock) - { - m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true)); - InsertPointGuard g{m_builder}; - m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - auto dest = m_jumpTableBlock->localStack().pop(); - auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); - for (auto&& p : m_basicBlocks) - { - if (p.second.isJumpDest()) - switchInstr->addCase(Constant::get(p.first), p.second.llvm()); - } - } - return m_jumpTableBlock->llvm(); -} - -llvm::BasicBlock* Compiler::getBadJumpBlock() -{ - if (!m_badJumpBlock) - { - m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true)); - InsertPointGuard g{m_builder}; - m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); - } - return m_badJumpBlock->llvm(); -} - -std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) -{ - auto compilationStartTime = std::chrono::high_resolution_clock::now(); - auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); - - // Create main function - auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, Type::RuntimePtr, false); - m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); - m_mainFunc->getArgumentList().front().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, memory); - Stack stack(m_builder, runtimeManager); - Arith256 arith(m_builder); - - m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); - - for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) - { - auto& basicBlock = basicBlockPairIt->second; - auto iterCopy = basicBlockPairIt; - ++iterCopy; - auto nextBasicBlock = (iterCopy != m_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)); - - removeDeadBlocks(); - - dumpCFGifRequired("blocks-init.dot"); - - if (m_options.optimizeStack) - { - std::vector blockList; - for (auto& entry : m_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 : m_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); - } - - auto compilationEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << "JIT: " << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count(); - 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 it = _basicBlock.begin(); it != _basicBlock.end(); ++it) - { - auto inst = Instruction(*it); - - _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 base = stack.pop(); - auto exponent = stack.pop(); - _gasMeter.countExp(exponent); - auto ret = _arith.exp(base, exponent); - 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, Type::Bool, "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); - _gasMeter.countSha3Data(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 value = readPushData(it, _basicBlock.end()); - 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.sload(index); - stack.push(value); - break; - } - - case Instruction::SSTORE: - { - auto index = stack.pop(); - auto value = stack.pop(); - _gasMeter.countSStore(_ext, index, value); - _ext.sstore(index, value); - break; - } - - case Instruction::JUMP: - case Instruction::JUMPI: - { - llvm::BasicBlock* targetBlock = nullptr; - auto target = stack.pop(); - if (auto constant = llvm::dyn_cast(target)) - { - auto&& c = constant->getValue(); - auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1; - auto it = m_basicBlocks.find(targetIdx); - targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(); - } - - // TODO: Improve; check for constants - if (inst == Instruction::JUMP) - { - if (targetBlock) - { - m_builder.CreateBr(targetBlock); - } - else - { - stack.push(target); - m_builder.CreateBr(getJumpTableBlock()); - } - } - else // JUMPI - { - auto val = stack.pop(); - auto zero = Constant::get(0); - auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); - - if (targetBlock) - { - m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); - } - else - { - stack.push(target); - m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); - } - } - break; - } - - case Instruction::JUMPDEST: - { - // Nothing to do - break; - } - - case Instruction::PC: - { - auto value = Constant::get(it - _bytecode.begin()); - stack.push(value); - break; - } - - case Instruction::GAS: - { - _gasMeter.commitCostBlock(); - stack.push(_runtimeManager.getGas()); - break; - } - - case Instruction::ADDRESS: - case Instruction::CALLER: - case Instruction::ORIGIN: - case Instruction::CALLVALUE: - case Instruction::CALLDATASIZE: - case Instruction::CODESIZE: - case Instruction::GASPRICE: - 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::BLOCKHASH: - { - auto number = stack.pop(); - auto hash = _ext.blockhash(number); - stack.push(hash); - 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 codeRef = _ext.getExtCode(addr); - stack.push(codeRef.size); - 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 addr = stack.pop(); - auto destMemIdx = stack.pop(); - auto srcIdx = stack.pop(); - auto reqBytes = stack.pop(); - - auto codeRef = _ext.getExtCode(addr); - - _memory.copyBytes(codeRef.ptr, codeRef.size, 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); - - _gasMeter.commitCostBlock(); - - auto gas = _runtimeManager.getGas(); - auto address = _ext.create(gas, endowment, initOff, initSize); - _runtimeManager.setGas(gas); - 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(); - - // 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); - - _gasMeter.count(gas); - 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: - { - _runtimeManager.registerSuicide(stack.pop()); - m_builder.CreateRet(Constant::get(ReturnCode::Suicide)); - break; - } - - - case Instruction::STOP: - { - 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, topics); - break; - } - - default: // Invalid instruction - runtime exception - { - // TODO: Replace with return statement - _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 = m_basicBlocks.begin(); it != m_basicBlocks.end();) - { - auto llvmBB = it->second.llvm(); - if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) - { - llvmBB->eraseFromParent(); - m_basicBlocks.erase(it++); - sthErased = true; - } - else - ++it; - } - } - while (sthErased); -} - -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 : m_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 : m_basicBlocks) - entry.second.dump(); - if (m_jumpTableBlock != nullptr) - m_jumpTableBlock->dump(); -} - -} -} -} - diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h deleted file mode 100644 index 720a48cf9..000000000 --- a/evmjit/libevmjit/Compiler.h +++ /dev/null @@ -1,83 +0,0 @@ - -#pragma once - -#include - -#include "Common.h" -#include "BasicBlock.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class Compiler -{ -public: - - struct Options - { - /// Optimize stack operations between basic blocks - bool optimizeStack = true; - - /// Rewrite switch instructions to sequences of branches - bool rewriteSwitchToBranches = true; - - /// Dump CFG as a .dot file for graphviz - bool dumpCFG = false; - }; - - using ProgramCounter = uint64_t; - - Compiler(Options const& _options); - - std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); - -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); - - llvm::BasicBlock* getJumpTableBlock(); - - llvm::BasicBlock* getBadJumpBlock(); - - 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 m_basicBlocks; - - /// Stop basic block - terminates execution with STOP code (0) - llvm::BasicBlock* m_stopBB = nullptr; - - /// Block with a jump table. - std::unique_ptr m_jumpTableBlock; - - /// Destination for invalid jumps - std::unique_ptr m_badJumpBlock; - - /// Main program function - llvm::Function* m_mainFunc = nullptr; -}; - -} -} -} diff --git a/evmjit/libevmjit/CompilerHelper.cpp b/evmjit/libevmjit/CompilerHelper.cpp deleted file mode 100644 index 9cccecd79..000000000 --- a/evmjit/libevmjit/CompilerHelper.cpp +++ /dev/null @@ -1,51 +0,0 @@ - -#include "CompilerHelper.h" - -#include -#include - -#include "RuntimeManager.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() -{ - // TODO: Rename or change semantics of getMainFunction() function - assert(m_builder.GetInsertBlock()); - auto mainFunc = m_builder.GetInsertBlock()->getParent(); - assert(mainFunc); - if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module - return mainFunc; - return nullptr; -} - -llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) -{ - return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); -} - - -RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): - CompilerHelper(_runtimeManager.getBuilder()), - m_runtimeManager(_runtimeManager) -{} - -} -} -} diff --git a/evmjit/libevmjit/CompilerHelper.h b/evmjit/libevmjit/CompilerHelper.h deleted file mode 100644 index 62733ca72..000000000 --- a/evmjit/libevmjit/CompilerHelper.h +++ /dev/null @@ -1,78 +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; } - - llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _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/evmjit/libevmjit/Endianness.cpp b/evmjit/libevmjit/Endianness.cpp deleted file mode 100644 index db7edfdc9..000000000 --- a/evmjit/libevmjit/Endianness.cpp +++ /dev/null @@ -1,38 +0,0 @@ - -#include "Endianness.h" - -#include - -#include "Type.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) -{ - union tester - { - unsigned int x; - unsigned char isLE; - }; - - if (tester{1}.isLE) - { - // FIXME: Disabled because of problems with BYTE - //if (auto constant = llvm::dyn_cast(_word)) - // return _builder.getInt(constant->getValue().byteSwap()); - - // OPT: Cache func declaration? - auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); - return _builder.CreateCall(bswapFunc, _word); - } - return _word; -} - -} -} -} diff --git a/evmjit/libevmjit/Endianness.h b/evmjit/libevmjit/Endianness.h deleted file mode 100644 index 8a1f41085..000000000 --- a/evmjit/libevmjit/Endianness.h +++ /dev/null @@ -1,24 +0,0 @@ - -#pragma once - -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct Endianness -{ - static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } - -private: - static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); -}; - -} -} -} diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp deleted file mode 100644 index 7e99932c3..000000000 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "ExecutionEngine.h" - -#include - -#include -#include -#pragma warning(push) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include -#include -#pragma warning(pop) -#pragma GCC diagnostic pop -#include -#include -#include - -#include "Runtime.h" -#include "Compiler.h" -#include "Cache.h" - -extern "C" void env_sha3(dev::eth::jit::byte const* _begin, uint64_t _size, std::array* o_hash); - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -namespace -{ -typedef ReturnCode(*EntryFuncPtr)(Runtime*); - -ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) -{ - // That function uses long jumps to handle "execeptions". - // Do not create any non-POD objects here - - ReturnCode returnCode{}; - auto sj = setjmp(_runtime->getJmpBuf()); - if (sj == 0) - returnCode = _mainFunc(_runtime); - else - returnCode = static_cast(sj); - - return returnCode; -} - -std::string codeHash(bytes const& _code) -{ - std::array binHash; - env_sha3(_code.data(), _code.size(), &binHash); - - std::ostringstream os; - for (auto i: binHash) - os << std::hex << std::setfill('0') << std::setw(2) << (int)(std::make_unsigned::type)i; - - return os.str(); -} - -} - -ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) -{ - static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? - - auto mainFuncName = codeHash(_code); - EntryFuncPtr entryFuncPtr{}; - Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls - - if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) - { - } - else - { - bool objectCacheEnabled = true; - auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; - std::unique_ptr module; - if (objectCache) - module = Cache::getObject(mainFuncName); - if (!module) - module = Compiler({}).compile(_code, mainFuncName); - //module->dump(); - if (!ee) - { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::Default); - - 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()); - - ee.reset(builder.create()); - if (!ee) - return ReturnCode::LLVMConfigError; - - module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - - if (objectCache) - ee->setObjectCache(objectCache); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - else - { - if (!entryFuncPtr) - { - ee->addModule(module.get()); - module.release(); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - } - } - assert(entryFuncPtr); - - auto executionStartTime = std::chrono::high_resolution_clock::now(); - - auto returnCode = runEntryFunc(entryFuncPtr, &runtime); - if (returnCode == ReturnCode::Return) - this->returnData = runtime.getReturnData(); - - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; - - return returnCode; -} - -} -} -} diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h deleted file mode 100644 index 559701bba..000000000 --- a/evmjit/libevmjit/ExecutionEngine.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "RuntimeData.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class ExecutionEngine -{ -public: - ExecutionEngine() = default; - ExecutionEngine(ExecutionEngine const&) = delete; - void operator=(ExecutionEngine) = delete; - - ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); - - bytes returnData; -}; - -} -} -} diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp deleted file mode 100644 index f0767d9e0..000000000 --- a/evmjit/libevmjit/Ext.cpp +++ /dev/null @@ -1,199 +0,0 @@ - -#include "Ext.h" - -#include -#include -#include - -//#include -//#include - -#include "RuntimeManager.h" -#include "Memory.h" -#include "Type.h" -#include "Endianness.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): - RuntimeHelper(_runtimeManager), - m_memoryMan(_memoryMan), - m_funcs({}), // The only std::array initialization that works in both Visual Studio & GCC - m_argAllocas({}) -{ - m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); -} - - -using FuncDesc = std::tuple; - -llvm::FunctionType* getFunctionType(llvm::Type* _returnType, std::initializer_list const& _argsTypes) -{ - return llvm::FunctionType::get(_returnType, llvm::ArrayRef{_argsTypes.begin(), _argsTypes.size()}, false); -} - -std::array::value> const& getEnvFuncDescs() -{ - static std::array::value> descs{{ - FuncDesc{"env_sload", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, - FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, - FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, - FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_getExtCode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, - FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})}, - }}; - - return descs; -} - -llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) -{ - auto&& desc = getEnvFuncDescs()[static_cast(_id)]; - return llvm::Function::Create(std::get<1>(desc), llvm::Function::ExternalLinkage, std::get<0>(desc), _module); -} - -llvm::Value* Ext::getArgAlloca() -{ - auto& a = m_argAllocas[m_argCounter++]; - if (!a) - { - // FIXME: Improve order and names - InsertPointGuard g{getBuilder()}; - getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); - a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); - } - - return a; -} - -llvm::Value* Ext::byPtr(llvm::Value* _value) -{ - auto a = getArgAlloca(); - getBuilder().CreateStore(_value, a); - return a; -} - -llvm::CallInst* Ext::createCall(EnvFunc _funcId, std::initializer_list const& _args) -{ - auto& func = m_funcs[static_cast(_funcId)]; - if (!func) - func = createFunc(_funcId, getModule()); - - m_argCounter = 0; - return getBuilder().CreateCall(func, {_args.begin(), _args.size()}); -} - -llvm::Value* Ext::sload(llvm::Value* _index) -{ - auto ret = getArgAlloca(); - createCall(EnvFunc::sload, {getRuntimeManager().getEnvPtr(), byPtr(_index), ret}); // Uses native endianness - return m_builder.CreateLoad(ret); -} - -void Ext::sstore(llvm::Value* _index, llvm::Value* _value) -{ - createCall(EnvFunc::sstore, {getRuntimeManager().getEnvPtr(), byPtr(_index), byPtr(_value)}); // Uses native endianness -} - -llvm::Value* Ext::calldataload(llvm::Value* _index) -{ - auto ret = getArgAlloca(); - createCall(EnvFunc::calldataload, {getRuntimeManager().getDataPtr(), byPtr(_index), ret}); - ret = m_builder.CreateLoad(ret); - return Endianness::toNative(m_builder, ret); -} - -llvm::Value* Ext::balance(llvm::Value* _address) -{ - auto address = Endianness::toBE(m_builder, _address); - auto ret = getArgAlloca(); - createCall(EnvFunc::balance, {getRuntimeManager().getEnvPtr(), byPtr(address), ret}); - return m_builder.CreateLoad(ret); -} - -llvm::Value* Ext::blockhash(llvm::Value* _number) -{ - auto hash = getArgAlloca(); - createCall(EnvFunc::blockhash, {getRuntimeManager().getEnvPtr(), byPtr(_number), hash}); - hash = m_builder.CreateLoad(hash); - return Endianness::toNative(getBuilder(), hash); -} - -llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) -{ - auto gas = byPtr(_gas); - auto ret = getArgAlloca(); - auto begin = m_memoryMan.getBytePtr(_initOff); - auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - _gas = m_builder.CreateLoad(gas); // Return gas - llvm::Value* address = m_builder.CreateLoad(ret); - 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) -{ - auto gas = byPtr(_gas); - auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); - auto inBeg = m_memoryMan.getBytePtr(_inOff); - auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); - auto outBeg = m_memoryMan.getBytePtr(_outOff); - auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); - auto codeAddress = Endianness::toBE(m_builder, _codeAddress); - auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); - _gas = m_builder.CreateLoad(gas); // Return gas - return m_builder.CreateZExt(ret, Type::Word, "ret"); -} - -llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) -{ - auto begin = m_memoryMan.getBytePtr(_inOff); - auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size"); - auto ret = getArgAlloca(); - createCall(EnvFunc::sha3, {begin, size, ret}); - llvm::Value* hash = m_builder.CreateLoad(ret); - hash = Endianness::toNative(m_builder, hash); - return hash; -} - -MemoryRef Ext::getExtCode(llvm::Value* _addr) -{ - auto addr = Endianness::toBE(m_builder, _addr); - auto code = createCall(EnvFunc::getExtCode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size}); - auto codeSize = m_builder.CreateLoad(m_size); - auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); - return {code, codeSize256}; -} - -void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics) -{ - auto begin = m_memoryMan.getBytePtr(_memIdx); - auto size = m_builder.CreateTrunc(_numBytes, Type::Size, "size"); - llvm::Value* args[] = {getRuntimeManager().getEnvPtr(), begin, size, getArgAlloca(), getArgAlloca(), getArgAlloca(), getArgAlloca()}; - - auto topicArgPtr = &args[3]; - for (auto&& topic : _topics) - { - if (topic) - m_builder.CreateStore(Endianness::toBE(m_builder, topic), *topicArgPtr); - else - *topicArgPtr = llvm::ConstantPointerNull::get(Type::WordPtr); - ++topicArgPtr; - } - - createCall(EnvFunc::log, {args[0], args[1], args[2], args[3], args[4], args[5], args[6]}); // TODO: use std::initializer_list<> -} - -} -} -} diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h deleted file mode 100644 index 86a8a6190..000000000 --- a/evmjit/libevmjit/Ext.h +++ /dev/null @@ -1,81 +0,0 @@ - -#pragma once - -#include -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - class Memory; - -struct MemoryRef -{ - llvm::Value* ptr; - llvm::Value* size; -}; - -template -struct sizeOf -{ - static const size_t value = static_cast(_EnumT::_size); -}; - -enum class EnvFunc -{ - sload, - sstore, - sha3, - balance, - create, - call, - log, - blockhash, - getExtCode, - calldataload, // Helper function, not client Env interface - - _size -}; - -class Ext : public RuntimeHelper -{ -public: - Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan); - - llvm::Value* sload(llvm::Value* _index); - void sstore(llvm::Value* _index, llvm::Value* _value); - - llvm::Value* balance(llvm::Value* _address); - llvm::Value* calldataload(llvm::Value* _index); - llvm::Value* create(llvm::Value*& _gas, 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* blockhash(llvm::Value* _number); - - llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); - MemoryRef getExtCode(llvm::Value* _addr); - - void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics); - -private: - Memory& m_memoryMan; - - llvm::Value* m_size; - llvm::Value* m_data = nullptr; - - std::array::value> m_funcs; - std::array m_argAllocas; - size_t m_argCounter = 0; - - llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list const& _args); - llvm::Value* getArgAlloca(); - llvm::Value* byPtr(llvm::Value* _value); -}; - - -} -} -} - diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp deleted file mode 100644 index 4aa6a738d..000000000 --- a/evmjit/libevmjit/GasMeter.cpp +++ /dev/null @@ -1,224 +0,0 @@ - -#include "GasMeter.h" - -#include -#include -#include - -#include "Type.h" -#include "Ext.h" -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -namespace // Helper functions -{ - -uint64_t const c_stepGas = 1; -uint64_t const c_balanceGas = 20; -uint64_t const c_sha3Gas = 10; -uint64_t const c_sha3WordGas = 10; -uint64_t const c_sloadGas = 20; -uint64_t const c_sstoreSetGas = 300; -uint64_t const c_sstoreResetGas = 100; -uint64_t const c_sstoreRefundGas = 100; -uint64_t const c_createGas = 100; -uint64_t const c_createDataGas = 5; -uint64_t const c_callGas = 20; -uint64_t const c_expGas = 1; -uint64_t const c_expByteGas = 1; -uint64_t const c_memoryGas = 1; -uint64_t const c_txDataZeroGas = 1; -uint64_t const c_txDataNonZeroGas = 5; -uint64_t const c_txGas = 500; -uint64_t const c_logGas = 32; -uint64_t const c_logDataGas = 1; -uint64_t const c_logTopicGas = 32; -uint64_t const c_copyGas = 1; - -uint64_t getStepCost(Instruction inst) -{ - switch (inst) - { - default: // Assumes instruction code is valid - return c_stepGas; - - case Instruction::STOP: - case Instruction::SUICIDE: - case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() - return 0; - - case Instruction::EXP: return c_expGas; - - case Instruction::SLOAD: return c_sloadGas; - - case Instruction::SHA3: return c_sha3Gas; - - case Instruction::BALANCE: return c_balanceGas; - - case Instruction::CALL: - case Instruction::CALLCODE: return c_callGas; - - case Instruction::CREATE: return 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 c_logGas + numTopics * c_logTopicGas; - } - } -} - -} - -GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) : - CompilerHelper(_builder), - m_runtimeManager(_runtimeManager) -{ - auto module = getModule(); - - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; - m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, 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); - auto arg = m_gasCheckFunc->arg_begin(); - arg->setName("rt"); - ++arg; - arg->setName("cost"); - auto cost = arg; - auto gas = m_runtimeManager.getGas(); - auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); - m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); - - m_builder.SetInsertPoint(outOfGasBB); - m_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 = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)}); - } - - m_blockCost += getStepCost(_inst); -} - -void GasMeter::count(llvm::Value* _cost) -{ - createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); -} - -void GasMeter::countExp(llvm::Value* _exponent) -{ - // Additional cost is 1 per significant byte of exponent - // lz - leading zeros - // cost = ((256 - lz) + 7) / 8 - - // OPT: All calculations can be done on 32/64 bits - - auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); - auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); - auto sigBits = m_builder.CreateSub(Constant::get(256), lz); - auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); - count(sigBytes); -} - -void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) -{ - auto oldValue = _ext.sload(_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"); - count(cost); -} - -void GasMeter::countLogData(llvm::Value* _dataLength) -{ - assert(m_checkCall); - assert(m_blockCost > 0); // LOGn instruction is already counted - static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter."); - count(_dataLength); -} - -void GasMeter::countSha3Data(llvm::Value* _dataLength) -{ - assert(m_checkCall); - assert(m_blockCost > 0); // SHA3 instruction is already counted - - // TODO: This round ups to 32 happens in many places - // FIXME: 64-bit arith used, but not verified - static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); - auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); - auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); - auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); - auto cost = getBuilder().CreateZExt(cost64, Type::Word); - count(cost); -} - -void GasMeter::giveBack(llvm::Value* _gas) -{ - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); -} - -void GasMeter::commitCostBlock() -{ - // 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(1, Constant::get(m_blockCost)); // Update block cost in gas check call - m_checkCall = nullptr; // End cost-block - m_blockCost = 0; - } - assert(m_blockCost == 0); -} - -void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) -{ - static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - count(_additionalMemoryInWords); -} - -void GasMeter::countCopy(llvm::Value* _copyWords) -{ - static_assert(c_copyGas == 1, "Copy gas cost has changed. Update GasMeter."); - count(_copyWords); -} - -} -} -} - diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h deleted file mode 100644 index 56da6eb9f..000000000 --- a/evmjit/libevmjit/GasMeter.h +++ /dev/null @@ -1,64 +0,0 @@ - -#pragma once - -#include "CompilerHelper.h" -#include "Instruction.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); - - /// Count additional cost - void count(llvm::Value* _cost); - - /// Calculate & count gas cost for SSTORE instruction - void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); - - /// Calculate & count additional gas cost for EXP instruction - void countExp(llvm::Value* _exponent); - - /// Count gas cost of LOG data - void countLogData(llvm::Value* _dataLength); - - /// Count gas cost of SHA3 data - void countSha3Data(llvm::Value* _dataLength); - - /// Finalize cost-block by checking gas needed for the block before the block - void commitCostBlock(); - - /// 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 countMemory(llvm::Value* _additionalMemoryInWords); - - /// Count addional gas cost for memory copy - void countCopy(llvm::Value* _copyWords); - -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/evmjit/libevmjit/Instruction.cpp b/evmjit/libevmjit/Instruction.cpp deleted file mode 100644 index fdc40d043..000000000 --- a/evmjit/libevmjit/Instruction.cpp +++ /dev/null @@ -1,40 +0,0 @@ - -#include "Instruction.h" -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::APInt 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; - llvm::APInt value(256, 0); - ++_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; -} - -void skipPushData(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; - --_end; - for (decltype(numBytes) i = 0; i < numBytes && _curr < _end; ++i, ++_curr) {} -} - -} -} -} diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h deleted file mode 100644 index 158490dee..000000000 --- a/evmjit/libevmjit/Instruction.h +++ /dev/null @@ -1,239 +0,0 @@ -#pragma once - -#include "Common.h" - -namespace llvm -{ - class APInt; -} - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -/// Virtual machine bytecode instruction. -enum class Instruction: uint8_t -{ - STOP = 0x00, ///< halts execution - ADD, ///< addition operation - MUL, ///< mulitplication operation - SUB, ///< subtraction operation - DIV, ///< integer division operation - SDIV, ///< signed integer division operation - MOD, ///< modulo remainder operation - SMOD, ///< signed modulo remainder operation - ADDMOD, ///< unsigned modular addition - MULMOD, ///< unsigned modular multiplication - EXP, ///< exponential operation - SIGNEXTEND, ///< extend length of signed integer - - LT = 0x10, ///< less-than comparision - GT, ///< greater-than comparision - SLT, ///< signed less-than comparision - SGT, ///< signed greater-than comparision - EQ, ///< equality comparision - ISZERO, ///< simple not operator - AND, ///< bitwise AND operation - OR, ///< bitwise OR operation - XOR, ///< bitwise XOR operation - NOT, ///< bitwise NOT opertation - BYTE, ///< retrieve single byte from word - - SHA3 = 0x20, ///< compute SHA3-256 hash - - ADDRESS = 0x30, ///< get address of currently executing account - BALANCE, ///< get balance of the given account - ORIGIN, ///< get execution origination address - CALLER, ///< get caller address - CALLVALUE, ///< get deposited value by the instruction/transaction responsible for this execution - CALLDATALOAD, ///< get input data of current environment - CALLDATASIZE, ///< get size of input data in current environment - CALLDATACOPY, ///< copy input data in current environment to memory - CODESIZE, ///< get size of code running in current environment - CODECOPY, ///< copy code running in current environment to memory - GASPRICE, ///< get price of gas in current environment - EXTCODESIZE, ///< get external code size (from another contract) - EXTCODECOPY, ///< copy external code (from another contract) - - BLOCKHASH = 0x40, ///< get hash of most recent complete block - COINBASE, ///< get the block's coinbase address - TIMESTAMP, ///< get the block's timestamp - NUMBER, ///< get the block's number - DIFFICULTY, ///< get the block's difficulty - GASLIMIT, ///< get the block's gas limit - - POP = 0x50, ///< remove item from stack - MLOAD, ///< load word from memory - MSTORE, ///< save word to memory - MSTORE8, ///< save byte to memory - SLOAD, ///< load word from storage - SSTORE, ///< save word to storage - JUMP, ///< alter the program counter - JUMPI, ///< conditionally alter the program counter - PC, ///< get the program counter - MSIZE, ///< get the size of active memory - GAS, ///< get the amount of available gas - JUMPDEST, ///< set a potential jump destination - - PUSH1 = 0x60, ///< place 1 byte item on stack - PUSH2, ///< place 2 byte item on stack - PUSH3, ///< place 3 byte item on stack - PUSH4, ///< place 4 byte item on stack - PUSH5, ///< place 5 byte item on stack - PUSH6, ///< place 6 byte item on stack - PUSH7, ///< place 7 byte item on stack - PUSH8, ///< place 8 byte item on stack - PUSH9, ///< place 9 byte item on stack - PUSH10, ///< place 10 byte item on stack - PUSH11, ///< place 11 byte item on stack - PUSH12, ///< place 12 byte item on stack - PUSH13, ///< place 13 byte item on stack - PUSH14, ///< place 14 byte item on stack - PUSH15, ///< place 15 byte item on stack - PUSH16, ///< place 16 byte item on stack - PUSH17, ///< place 17 byte item on stack - PUSH18, ///< place 18 byte item on stack - PUSH19, ///< place 19 byte item on stack - PUSH20, ///< place 20 byte item on stack - PUSH21, ///< place 21 byte item on stack - PUSH22, ///< place 22 byte item on stack - PUSH23, ///< place 23 byte item on stack - PUSH24, ///< place 24 byte item on stack - PUSH25, ///< place 25 byte item on stack - PUSH26, ///< place 26 byte item on stack - PUSH27, ///< place 27 byte item on stack - PUSH28, ///< place 28 byte item on stack - PUSH29, ///< place 29 byte item on stack - PUSH30, ///< place 30 byte item on stack - PUSH31, ///< place 31 byte item on stack - PUSH32, ///< place 32 byte item on stack - - DUP1 = 0x80, ///< copies the highest item in the stack to the top of the stack - DUP2, ///< copies the second highest item in the stack to the top of the stack - DUP3, ///< copies the third highest item in the stack to the top of the stack - DUP4, ///< copies the 4th highest item in the stack to the top of the stack - DUP5, ///< copies the 5th highest item in the stack to the top of the stack - DUP6, ///< copies the 6th highest item in the stack to the top of the stack - DUP7, ///< copies the 7th highest item in the stack to the top of the stack - DUP8, ///< copies the 8th highest item in the stack to the top of the stack - DUP9, ///< copies the 9th highest item in the stack to the top of the stack - DUP10, ///< copies the 10th highest item in the stack to the top of the stack - DUP11, ///< copies the 11th highest item in the stack to the top of the stack - DUP12, ///< copies the 12th highest item in the stack to the top of the stack - DUP13, ///< copies the 13th highest item in the stack to the top of the stack - DUP14, ///< copies the 14th highest item in the stack to the top of the stack - DUP15, ///< copies the 15th highest item in the stack to the top of the stack - DUP16, ///< copies the 16th highest item in the stack to the top of the stack - - SWAP1 = 0x90, ///< swaps the highest and second highest value on the stack - SWAP2, ///< swaps the highest and third highest value on the stack - SWAP3, ///< swaps the highest and 4th highest value on the stack - SWAP4, ///< swaps the highest and 5th highest value on the stack - SWAP5, ///< swaps the highest and 6th highest value on the stack - SWAP6, ///< swaps the highest and 7th highest value on the stack - SWAP7, ///< swaps the highest and 8th highest value on the stack - SWAP8, ///< swaps the highest and 9th highest value on the stack - SWAP9, ///< swaps the highest and 10th highest value on the stack - SWAP10, ///< swaps the highest and 11th highest value on the stack - SWAP11, ///< swaps the highest and 12th highest value on the stack - SWAP12, ///< swaps the highest and 13th highest value on the stack - SWAP13, ///< swaps the highest and 14th highest value on the stack - SWAP14, ///< swaps the highest and 15th highest value on the stack - SWAP15, ///< swaps the highest and 16th highest value on the stack - SWAP16, ///< swaps the highest and 17th highest value on the stack - - LOG0 = 0xa0, ///< Makes a log entry; no topics. - LOG1, ///< Makes a log entry; 1 topic. - LOG2, ///< Makes a log entry; 2 topics. - LOG3, ///< Makes a log entry; 3 topics. - LOG4, ///< Makes a log entry; 4 topics. - - CREATE = 0xf0, ///< create a new account with associated code - CALL, ///< message-call into an account - CALLCODE, ///< message-call with another account's code only - RETURN, ///< halt execution returning output data - SUICIDE = 0xff ///< halt execution and register account for later deletion -}; - -/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it -/// Reading out of bytecode means reading 0 -/// @param _curr is updated and points the last real byte read -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); - -/// Skips PUSH data in pointed fragment of bytecode. -/// @param _curr is updated and points the last real byte skipped -void skipPushData(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/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp deleted file mode 100644 index 9f57c7a4b..000000000 --- a/evmjit/libevmjit/Memory.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Type.h" -#include "Runtime.h" -#include "GasMeter.h" -#include "Endianness.h" -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): - RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed - m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); - 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_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) -{ - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto offset = rt->getNextNode(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", 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 "Pre": Ignore checks with size 0 - m_builder.SetInsertPoint(preBB); - auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); - m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); - - // 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 rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - auto currSize = m_builder.CreateLoad(sizePtr, "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.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - m_builder.CreateStore(newData, dataPtr); - 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::RuntimePtr, Type::Word, _valueType}; - llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; - auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; - auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, 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)); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto index = rt->getNextNode(); - index->setName("index"); - - auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - this->require(index, Constant::get(valueSize)); - auto ptr = getBytePtr(index); - if (isWord) - ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); - if (_isStore) - { - llvm::Value* value = index->getNextNode(); - 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) -{ - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); -} - -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) -{ - auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); -} - -llvm::Value* Memory::getData() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - return m_builder.CreateLoad(dataPtr, "data"); -} - -llvm::Value* Memory::getSize() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - return m_builder.CreateLoad(sizePtr, "size"); -} - -llvm::Value* Memory::getBytePtr(llvm::Value* _index) -{ - return m_builder.CreateGEP(getData(), _index, "ptr"); -} - -void Memory::require(llvm::Value* _offset, llvm::Value* _size) -{ - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); -} - -void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, - llvm::Value* _destMemIdx, llvm::Value* _reqBytes) -{ - require(_destMemIdx, _reqBytes); - - // Additional copy cost - // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); - m_gasMeter.countCopy(copyWords); - - // Algorithm: - // isOutsideData = idx256 >= size256 - // idx64 = trunc idx256 - // size64 = trunc size256 - // dataLeftSize = size64 - idx64 // safe if not isOutsideData - // reqBytes64 = trunc _reqBytes // require() handles large values - // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min - // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) - - auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); - auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); - - auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); - auto dst = m_builder.CreateGEP(getData(), _destMemIdx, "dst"); - m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); -} - -} -} -} - - -extern "C" -{ - using namespace dev::eth::jit; - - EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR - { - auto size = _size->a; // Trunc to 64-bit - auto& memory = _rt->getMemory(); - memory.resize(size); - return memory.data(); - } -} diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h deleted file mode 100644 index ed9c51805..000000000 --- a/evmjit/libevmjit/Memory.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include "CompilerHelper.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ -class GasMeter; - -class Memory : public RuntimeHelper -{ -public: - Memory(RuntimeManager& _runtimeManager, 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(); - llvm::Value* getBytePtr(llvm::Value* _index); - 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: - GasMeter& m_gasMeter; - - llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter); - - llvm::Function* m_resize; - llvm::Function* m_require; - llvm::Function* m_loadWord; - llvm::Function* m_storeWord; - llvm::Function* m_storeByte; -}; - -} -} -} - diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp deleted file mode 100644 index 911dc469d..000000000 --- a/evmjit/libevmjit/Runtime.cpp +++ /dev/null @@ -1,37 +0,0 @@ - -#include "Runtime.h" - -#include -#include -#include - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Runtime::Runtime(RuntimeData* _data, Env* _env) : - m_data(*_data), - m_env(*_env), - m_currJmpBuf(m_jmpBuf) -{} - -bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy -{ - // 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() || size == 0); - if (offset + size > m_memory.size()) - return {}; - - auto dataBeg = m_memory.begin() + offset; - return {dataBeg, dataBeg + size}; -} - -} -} -} diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h deleted file mode 100644 index 8cc5b7968..000000000 --- a/evmjit/libevmjit/Runtime.h +++ /dev/null @@ -1,59 +0,0 @@ - -#pragma once - -#include -#include - -#include "Instruction.h" -#include "CompilerHelper.h" -#include "Utils.h" -#include "Type.h" -#include "RuntimeData.h" - - -#ifdef _MSC_VER - #define EXPORT __declspec(dllexport) -#else - #define EXPORT -#endif - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -using StackImpl = std::vector; -using MemoryImpl = bytes; -using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); - -class Runtime -{ -public: - Runtime(RuntimeData* _data, Env* _env); - - Runtime(const Runtime&) = delete; - void operator=(const Runtime&) = delete; - - StackImpl& getStack() { return m_stack; } - MemoryImpl& getMemory() { return m_memory; } - Env* getEnvPtr() { return &m_env; } - - bytes getReturnData() const; - jmp_buf_ref getJmpBuf() { return m_jmpBuf; } - -private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. - byte* m_memoryData = nullptr; - i256 m_memorySize; - std::jmp_buf m_jmpBuf; - StackImpl m_stack; - MemoryImpl m_memory; -}; - -} -} -} diff --git a/evmjit/libevmjit/RuntimeData.h b/evmjit/libevmjit/RuntimeData.h deleted file mode 100644 index bb52f7864..000000000 --- a/evmjit/libevmjit/RuntimeData.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "Utils.h" - - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct RuntimeData -{ - enum Index - { - Gas, - Address, - Caller, - Origin, - CallValue, - CallDataSize, - GasPrice, - CoinBase, - TimeStamp, - Number, - Difficulty, - GasLimit, - CodeSize, - - _size, - - ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference - ReturnDataSize = CallDataSize, - SuicideDestAddress = Address, ///< Suicide balance destination address - }; - - i256 elems[_size] = {}; - byte const* callData = nullptr; - byte const* code = nullptr; - - void set(Index _index, u256 _value) { elems[_index] = eth2llvm(_value); } - u256 get(Index _index) { return llvm2eth(elems[_index]); } -}; - -/// VM Environment (ExtVM) opaque type -struct Env; - -} -} -} diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp deleted file mode 100644 index ea2fe20b5..000000000 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ /dev/null @@ -1,197 +0,0 @@ - -#include "RuntimeManager.h" - -#include -#include -#include - -#include "RuntimeData.h" -#include "Instruction.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::StructType* RuntimeManager::getRuntimeDataType() -{ - static llvm::StructType* type = nullptr; - if (!type) - { - llvm::Type* elems[] = - { - llvm::ArrayType::get(Type::Word, RuntimeData::_size), // i256[] - Type::BytePtr, // callData - Type::BytePtr // code - }; - type = llvm::StructType::create(elems, "RuntimeData"); - } - return type; -} - -llvm::StructType* RuntimeManager::getRuntimeType() -{ - static llvm::StructType* type = nullptr; - if (!type) - { - llvm::Type* elems[] = - { - Type::RuntimeDataPtr, // data - Type::EnvPtr, // Env* - Type::BytePtr, // jmpbuf - Type::BytePtr, // memory data - Type::Word, // memory size - }; - 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::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"; - } -} -} - -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) -{ - m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); - - // Unpack data - auto rtPtr = getRuntimePtr(); - m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); - assert(m_dataPtr->getType() == Type::RuntimeDataPtr); - m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env"); - assert(m_envPtr->getType() == Type::EnvPtr); -} - -llvm::Value* RuntimeManager::getRuntimePtr() -{ - // Expect first argument of a function to be a pointer to Runtime - auto func = m_builder.GetInsertBlock()->getParent(); - auto rtPtr = &func->getArgumentList().front(); - assert(rtPtr->getType() == Type::RuntimePtr); - return rtPtr; -} - -llvm::Value* RuntimeManager::getDataPtr() -{ - if (getMainFunction()) - return m_dataPtr; - - auto rtPtr = getRuntimePtr(); - return m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); -} - -llvm::Value* RuntimeManager::getEnvPtr() -{ - assert(getMainFunction()); // Available only in main function - return m_envPtr; -} - -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(getDataPtr(), 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::registerSuicide(llvm::Value* _balanceAddress) -{ - set(RuntimeData::SuicideDestAddress, _balanceAddress); -} - -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::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(getDataPtr(), 1, "calldataPtr"); - return getBuilder().CreateLoad(ptr, "calldata"); -} - -llvm::Value* RuntimeManager::getCode() -{ - auto ptr = getBuilder().CreateStructGEP(getDataPtr(), 2, "codePtr"); - return getBuilder().CreateLoad(ptr, "code"); -} - -llvm::Value* RuntimeManager::getJmpBuf() -{ - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "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(getDataPtr(), idxList, "gasPtr"); - m_builder.CreateStore(_gas, ptr); -} - -} -} -} diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h deleted file mode 100644 index ce60424ac..000000000 --- a/evmjit/libevmjit/RuntimeManager.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "CompilerHelper.h" -#include "Type.h" -#include "RuntimeData.h" -#include "Instruction.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -class RuntimeManager: public CompilerHelper -{ -public: - RuntimeManager(llvm::IRBuilder<>& _builder); - - llvm::Value* getRuntimePtr(); - llvm::Value* getDataPtr(); - llvm::Value* getEnvPtr(); // TODO: Can we make it const? - - 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 registerSuicide(llvm::Value* _balanceAddress); - - void raiseException(ReturnCode _returnCode); - - static llvm::StructType* getRuntimeType(); - static llvm::StructType* getRuntimeDataType(); - -private: - llvm::Value* getPtr(RuntimeData::Index _index); - void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBuf(); - - llvm::Function* m_longjmp = nullptr; - llvm::Value* m_dataPtr = nullptr; - llvm::Value* m_envPtr = nullptr; -}; - -} -} -} diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp deleted file mode 100644 index 52782999a..000000000 --- a/evmjit/libevmjit/Stack.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "Stack.h" -#include "RuntimeManager.h" -#include "Runtime.h" -#include "Type.h" - -#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; - } - - EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value) - { - // It asumes all indexes are less than 2^64 - - auto index = _index->a; - if (_index->b || _index->c || _index->d) // if bigger that 2^64 - index = std::numeric_limits::max(); // set max to fill with 0 leter - - auto data = _rtData->callData; - auto size = _rtData->elems[RuntimeData::CallDataSize].a; - for (auto i = 0; i < 32; ++i) - { - if (index < size) - { - o_value[i] = data[index]; - ++index; // increment only if in range - } - else - o_value[i] = 0; - } - } - -} // extern "C" - diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h deleted file mode 100644 index 3e8881e4f..000000000 --- a/evmjit/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/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp deleted file mode 100644 index 22ccea12e..000000000 --- a/evmjit/libevmjit/Type.cpp +++ /dev/null @@ -1,67 +0,0 @@ - -#include "Type.h" - -#include - -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -llvm::IntegerType* Type::Word; -llvm::PointerType* Type::WordPtr; -llvm::IntegerType* Type::lowPrecision; -llvm::IntegerType* Type::Bool; -llvm::IntegerType* Type::Size; -llvm::IntegerType* Type::Byte; -llvm::PointerType* Type::BytePtr; -llvm::Type* Type::Void; -llvm::IntegerType* Type::MainReturn; -llvm::PointerType* Type::EnvPtr; -llvm::PointerType* Type::RuntimeDataPtr; -llvm::PointerType* Type::RuntimePtr; - -void Type::init(llvm::LLVMContext& _context) -{ - if (!Word) // Do init only once - { - Word = llvm::Type::getIntNTy(_context, 256); - WordPtr = Word->getPointerTo(); - lowPrecision = llvm::Type::getInt64Ty(_context); - // TODO: Size should be architecture-dependent - Bool = llvm::Type::getInt1Ty(_context); - Size = llvm::Type::getInt64Ty(_context); - Byte = llvm::Type::getInt8Ty(_context); - BytePtr = Byte->getPointerTo(); - Void = llvm::Type::getVoidTy(_context); - MainReturn = llvm::Type::getInt32Ty(_context); - - EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); - RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); - RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); - } -} - -llvm::ConstantInt* Constant::get(int64_t _n) -{ - return llvm::ConstantInt::getSigned(Type::Word, _n); -} - -llvm::ConstantInt* Constant::get(llvm::APInt const& _n) -{ - return llvm::ConstantInt::get(Type::Word->getContext(), _n); -} - -llvm::ConstantInt* Constant::get(ReturnCode _returnCode) -{ - return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); -} - -} -} -} - diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h deleted file mode 100644 index d4804ee59..000000000 --- a/evmjit/libevmjit/Type.h +++ /dev/null @@ -1,54 +0,0 @@ - -#pragma once - -#include -#include -#include "Common.h" - -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* Bool; - 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* EnvPtr; - static llvm::PointerType* RuntimeDataPtr; - static llvm::PointerType* RuntimePtr; - - static void init(llvm::LLVMContext& _context); -}; - -struct Constant -{ - /// Returns word-size constant - static llvm::ConstantInt* get(int64_t _n); - static llvm::ConstantInt* get(llvm::APInt const& _n); - - static llvm::ConstantInt* get(ReturnCode _returnCode); -}; - -} -} -} - diff --git a/evmjit/libevmjit/Utils.cpp b/evmjit/libevmjit/Utils.cpp deleted file mode 100644 index 0fd9c0e41..000000000 --- a/evmjit/libevmjit/Utils.cpp +++ /dev/null @@ -1,40 +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; -} - -} -} -} diff --git a/evmjit/libevmjit/Utils.h b/evmjit/libevmjit/Utils.h deleted file mode 100644 index f672365c6..000000000 --- a/evmjit/libevmjit/Utils.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "Common.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; - -//#define clog(CHANNEL) std::cerr -#define clog(CHANNEL) std::ostream(nullptr) - -u256 llvm2eth(i256); -i256 eth2llvm(u256); - -} -} -} diff --git a/evmjit/libevmjit/interface.c b/evmjit/libevmjit/interface.c deleted file mode 100644 index 47589578b..000000000 --- a/evmjit/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 5096dbfc22a843b7a4ff118356ae19144d394329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 13 Jan 2015 16:05:03 +0100 Subject: [PATCH 448/466] Allways generate stack_get() call to detect stack underflow cases --- evmjit/libevmjit/BasicBlock.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index dda0fbc36..5868c0f43 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -168,16 +168,13 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) 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); - } + // 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); // OPT: Value may be never user but we need to check stack heigth + // It is probably a good idea to keep heigth as a local variable accesible by LLVM directly + phi->replaceAllUsesWith(newVal); phi->eraseFromParent(); } From e7ac3ba8697f49e22290c6033d9693b8c8efc703 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 13 Jan 2015 17:54:09 +0100 Subject: [PATCH 449/466] Natspechandler: Get function hash from transaction data --- alethzero/MainWin.cpp | 5 +++ alethzero/MainWin.h | 1 + alethzero/NatspecHandler.cpp | 33 ++++++++++++++++++- alethzero/NatspecHandler.h | 6 +++- alethzero/OurWebThreeStubServer.cpp | 8 +++-- .../ethereumjs/example/natspec_contract.html | 2 +- 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ae24e4af0..50a362150 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2294,6 +2294,11 @@ std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::s return m_natspecDB.getUserNotice(_contractHash, _methodName); } +std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) +{ + return m_natspecDB.getUserNotice(_contractHash, _transactionData); +} + void Main::refreshWhispers() { ui->whispers->clear(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index a7922287f..64de6a9e9 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -84,6 +84,7 @@ public: std::string lookupNatSpec(dev::h256 const& _contractHash) const; std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); + std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData); QList owned() const { return m_myIdentities + m_myKeys; } diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 415f8ca2a..2a99e69ef 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -25,7 +25,9 @@ #include #include +#include #include +#include using namespace dev; @@ -62,14 +64,43 @@ std::string NatspecHandler::getUserNotice(std::string const& json, std::string c Json::Value natspec, userNotice; std::string retStr; m_reader.parse(json, natspec); - retStr = natspec["methods"][_methodName]["notice"].toStyledString(); + retStr = natspec["methods"][_methodName]["notice"].asString(); return (retStr == "null\n") ? "" : retStr; } +std::string NatspecHandler::getUserNotice(std::string const& json, const dev::bytes& _transactionData) +{ + Json::Value natspec, userNotice; + std::string retStr; + m_reader.parse(json, natspec); + bytes transactionFunctionPart(_transactionData.begin(), _transactionData.begin() + 4); + FixedHash<4> transactionFunctionHash(transactionFunctionPart); + + // for (auto const& it: natspec["methods"]) + Json::Value methods = natspec["methods"]; + for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it ) + { + std::string functionSig = it.key().asString(); + FixedHash<4> functionHash(dev::sha3(functionSig)); + + if (functionHash == transactionFunctionHash) { + return (*it)["notice"].asString(); + } + } + + // not found + return ""; +} + std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) { return getUserNotice(retrieve(_contractHash), _methodName); } +std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) +{ + return getUserNotice(retrieve(_contractHash), _transactionData); +} + diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 9ea1103af..23e05fa51 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -43,10 +43,14 @@ class NatspecHandler /// Given a json natspec string, retrieve the user notice string std::string getUserNotice(std::string const& json, std::string const& _methodName); + std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData); /// Given a contract code hash, retrieve the natspec documentation's user notice for that contract + std::string getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); + /// Given a contract code hash and the transaction's data retrieve the natspec documention's + /// user notice for that transaction. /// @returns The user notice or an empty string if no natspec for the contract exists /// or if the existing natspec does not document the @c _methodName - std::string getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); + std::string getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionDacta); private: ldb::ReadOptions m_readOptions; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 6d771f219..b5be016ea 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -22,6 +22,7 @@ #include "OurWebThreeStubServer.h" #include +#include #include #include "MainWin.h" @@ -62,7 +63,8 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con //LTODO: Actually find and use the method name here - std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, "multiply"); + // std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, "multiply"); + std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data); if (userNotice.empty()) { QMessageBox userInput; @@ -77,8 +79,10 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con // otherwise it's a transaction to a contract for which we have the natspec QMessageBox userInput; userInput.setText("Pending Transaction"); - userInput.setInformativeText(QString::fromStdString(userNotice)); + userInput.setInformativeText(QString::fromStdString(userNotice + "\n Do you wish to allow this?")); userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.button(QMessageBox::Ok)->setText("Allow"); + userInput.button(QMessageBox::Cancel)->setText("Reject"); userInput.setDefaultButton(QMessageBox::Cancel); return userInput.exec() == QMessageBox::Ok; diff --git a/libjsqrc/ethereumjs/example/natspec_contract.html b/libjsqrc/ethereumjs/example/natspec_contract.html index b8e3bc617..94edda68d 100644 --- a/libjsqrc/ethereumjs/example/natspec_contract.html +++ b/libjsqrc/ethereumjs/example/natspec_contract.html @@ -12,7 +12,7 @@ // solidity source code var source = "" + "contract test {\n" + - " /// @notice This is an awesome function for multiplication. \n" + + " /// @notice Will multiplty `a` by 7. \n" + " function multiply(uint a) returns(uint d) {\n" + " return a * 7;\n" + " }\n" + From 607c71e785b78306455d8ac0047ea499736fc2ba Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 13 Jan 2015 17:58:14 +0100 Subject: [PATCH 450/466] more randomness in the optimizations --- test/createRandomTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index b3a704e9d..37d61fac9 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -73,7 +73,7 @@ int main(int argc, char *argv[]) uint8_t opcode = randGen(); // disregard all invalid commands, except of one (0x0c) - if ((dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || (opcode == 0x0c))) + if ((dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || (randGen() > 128))) randomCode += toHex(toCompactBigEndian(opcode)); else i--; @@ -84,7 +84,7 @@ int main(int argc, char *argv[]) \"randomVMtest\": {\n\ \"env\" : {\n\ \"previousHash\" : \"5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6\",\n\ - \"currentNumber\" : \"0\",\n\ + \"currentNumber\" : \"300\",\n\ \"currentGasLimit\" : \"1000000\",\n\ \"currentDifficulty\" : \"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\n\ \"currentTimestamp\" : 2,\n\ @@ -114,7 +114,7 @@ int main(int argc, char *argv[]) read_string(s, v); // insert new random code - v.get_obj().find("randomVMtest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + "55"; + v.get_obj().find("randomVMtest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + (randGen() > 128 ? "55" : ""); // execute code in vm doMyTests(v); From 3d01e66c1d2812f670287abc314983e592534cd6 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 13 Jan 2015 18:00:00 +0100 Subject: [PATCH 451/466] replace BOOST_REQUIRE with assert, because it is used outside the boost test framework --- test/vm.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 8b8c75a04..42113e7b6 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -232,10 +232,10 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) for (mValue& v: _callcreates) { auto tx = v.get_obj(); - BOOST_REQUIRE(tx.count("data") > 0); - BOOST_REQUIRE(tx.count("value") > 0); - BOOST_REQUIRE(tx.count("destination") > 0); - BOOST_REQUIRE(tx.count("gasLimit") > 0); + assert(tx.count("data") > 0); + assert(tx.count("value") > 0); + assert(tx.count("destination") > 0); + assert(tx.count("gasLimit") > 0); Transaction t = tx["destination"].get_str().empty() ? Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), data.toBytes()) : Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), Address(tx["destination"].get_str()), data.toBytes()); From 1b36ff453bd219cc6f01fcb75b3123f4090fda03 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 12 Jan 2015 12:47:37 +0100 Subject: [PATCH 452/466] Modify gas and value for external function call. --- libsolidity/ExpressionCompiler.cpp | 98 ++++++++++++++++++++---------- libsolidity/ExpressionCompiler.h | 14 +---- libsolidity/Types.cpp | 60 ++++++++++++++++-- libsolidity/Types.h | 26 ++++++-- test/SolidityEndToEndTest.cpp | 80 +++++++++++++++++++++++- 5 files changed, 222 insertions(+), 56 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 1c02f4f32..8cecbb1b6 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -232,27 +232,41 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } case Location::EXTERNAL: case Location::BARE: + _functionCall.getExpression().accept(*this); + appendExternalFunctionCall(function, arguments, function.getLocation() == Location::BARE); + break; + case Location::SET_GAS: { - FunctionCallOptions options; - options.bare = function.getLocation() == Location::BARE; - options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); }; - appendExternalFunctionCall(function, arguments, options); + // stack layout: contract_address function_id [gas] [value] + _functionCall.getExpression().accept(*this); + arguments.front()->accept(*this); + appendTypeConversion(*arguments.front()->getType(), IntegerType(256), true); + // Note that function is not the original function, but the ".gas" function. + // Its values of gasSet and valueSet is equal to the original function's though. + unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0); + if (stackDepth > 0) + m_context << eth::swapInstruction(stackDepth); + if (function.gasSet()) + m_context << eth::Instruction::POP; break; } + case Location::SET_VALUE: + // stack layout: contract_address function_id [gas] [value] + _functionCall.getExpression().accept(*this); + // Note that function is not the original function, but the ".value" function. + // Its values of gasSet and valueSet is equal to the original function's though. + if (function.valueSet()) + m_context << eth::Instruction::POP; + arguments.front()->accept(*this); + break; case Location::SEND: - { - FunctionCallOptions options; - options.bare = true; - options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); }; - options.obtainValue = [&]() - { - arguments.front()->accept(*this); - appendTypeConversion(*arguments.front()->getType(), - *function.getParameterTypes().front(), true); - }; - appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, Location::EXTERNAL), {}, options); + // TODO set gas to min + _functionCall.getExpression().accept(*this); + arguments.front()->accept(*this); + appendTypeConversion(*arguments.front()->getType(), + *function.getParameterTypes().front(), true); + appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, Location::EXTERNAL, false, true), {}, true); break; - } case Location::SUICIDE: arguments.front()->accept(*this); appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); @@ -289,11 +303,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) static const map contractAddresses{{Location::ECRECOVER, 1}, {Location::SHA256, 2}, {Location::RIPEMD160, 3}}; - u256 contractAddress = contractAddresses.find(function.getLocation())->second; - FunctionCallOptions options; - options.bare = true; - options.obtainAddress = [&]() { m_context << contractAddress; }; - appendExternalFunctionCall(function, arguments, options); + m_context << contractAddresses.find(function.getLocation())->second; + appendExternalFunctionCall(function, arguments, true); break; } default: @@ -370,6 +381,10 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); break; + case Type::Category::FUNCTION: + solAssert(!!_memberAccess.getExpression().getType()->getMemberType(member), + "Invalid member access to function."); + break; case Type::Category::MAGIC: // we can ignore the kind of magic and only look at the name of the member if (member == "coinbase") @@ -646,15 +661,25 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functionType, vector> const& _arguments, - FunctionCallOptions const& _options) + bool bare) { solAssert(_arguments.size() == _functionType.getParameterTypes().size(), ""); - _options.obtainAddress(); - if (!_options.bare) + // Assumed stack content here: + // + // value [if _functionType.valueSet()] + // gas [if _functionType.gasSet()] + // function identifier [unless options.bare] + // contract address + + unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0); + if (!bare) + { + m_context << eth::dupInstruction(gasValueSize + 1); CompilerUtils(m_context).storeInMemory(0, CompilerUtils::dataStartOffset); + } - unsigned dataOffset = _options.bare ? 0 : CompilerUtils::dataStartOffset; // reserve 4 bytes for the function's hash identifier + unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; // reserve 4 bytes for the function's hash identifier for (unsigned i = 0; i < _arguments.size(); ++i) { _arguments[i]->accept(*this); @@ -676,16 +701,25 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio unsigned retSize = firstType ? CompilerUtils::getPaddedSize(firstType->getCalldataEncodedSize()) : 0; // CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top) m_context << u256(retSize) << u256(0) << u256(dataOffset) << u256(0); - if (_options.obtainValue) - _options.obtainValue(); + if (_functionType.valueSet()) + m_context << eth::dupInstruction(5); else m_context << u256(0); - m_context << eth::dupInstruction(6); //copy contract address + m_context << eth::dupInstruction(6 + gasValueSize + (bare ? 0 : 1)); //copy contract address - m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB - << eth::Instruction::CALL - << eth::Instruction::POP // @todo do not ignore failure indicator - << eth::Instruction::POP; // pop contract address + if (_functionType.gasSet()) + m_context << eth::dupInstruction(7 + (_functionType.valueSet() ? 1 : 0)); + else + m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB; + m_context << eth::Instruction::CALL + << eth::Instruction::POP; // @todo do not ignore failure indicator + if (_functionType.valueSet()) + m_context << eth::Instruction::POP; + if (_functionType.gasSet()) + m_context << eth::Instruction::POP; + if (!bare) + m_context << eth::Instruction::POP; + m_context << eth::Instruction::POP; // pop contract address if (retSize > 0) { diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 98f58c854..024c4644c 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -87,21 +87,9 @@ private: //// Appends code that cleans higher-order bits for integer types. void appendHighBitsCleanup(IntegerType const& _typeOnStack); - /// Additional options used in appendExternalFunctionCall. - struct FunctionCallOptions - { - FunctionCallOptions() {} - /// Invoked to copy the address to the stack - std::function obtainAddress; - /// Invoked to copy the ethe value to the stack (if not specified, value is 0). - std::function obtainValue; - /// If true, do not prepend function index to call data - bool bare = false; - }; - /// Appends code to call a function of the given type with the given arguments. void appendExternalFunctionCall(FunctionType const& _functionType, std::vector> const& _arguments, - FunctionCallOptions const& _options = FunctionCallOptions()); + bool bare = false); /** * Helper class to store and retrieve lvalues to and from various locations. diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7ca1dc6d5..59b8c31b7 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -561,6 +561,21 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal m_location = _isInternal ? Location::INTERNAL : Location::EXTERNAL; } +FunctionType::FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, + FunctionType::Location _location, bool _gasSet, bool _valueSet): + m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), + m_location(_location), m_gasSet(_gasSet), m_valueSet(_valueSet) +{ + if (m_location == Location::EXTERNAL) + m_sizeOnStack = 2; + else if (m_location == Location::INTERNAL || m_location == Location::BARE) + m_sizeOnStack = 1; + if (m_gasSet) + m_sizeOnStack++; + if (m_valueSet) + m_sizeOnStack++; +} + bool FunctionType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) @@ -580,6 +595,9 @@ bool FunctionType::operator==(Type const& _other) const if (!equal(m_returnParameterTypes.cbegin(), m_returnParameterTypes.cend(), other.m_returnParameterTypes.cbegin(), typeCompare)) return false; + //@todo this is ugly, but cannot be prevented right now + if (m_gasSet != other.m_gasSet || m_valueSet != other.m_valueSet) + return false; return true; } @@ -595,17 +613,42 @@ string FunctionType::toString() const } unsigned FunctionType::getSizeOnStack() const +{ + unsigned size = 0; + if (m_location == Location::EXTERNAL) + size = 2; + else if (m_location == Location::INTERNAL || m_location == Location::BARE) + size = 1; + if (m_gasSet) + size++; + if (m_valueSet) + size++; + return size; +} + +MemberList const& FunctionType::getMembers() const { switch (m_location) { - case Location::INTERNAL: - return 1; case Location::EXTERNAL: - return 2; + case Location::ECRECOVER: + case Location::SHA256: + case Location::RIPEMD160: case Location::BARE: - return 1; + if (!m_members) + { + map members{ + {"gas", make_shared(parseElementaryTypeVector({"uint"}), + TypePointers{copyAndSetGasOrValue(true, false)}, + Location::SET_GAS, m_gasSet, m_valueSet)}, + {"value", make_shared(parseElementaryTypeVector({"uint"}), + TypePointers{copyAndSetGasOrValue(false, true)}, + Location::SET_VALUE, m_gasSet, m_valueSet)}}; + m_members.reset(new MemberList(members)); + } + return *m_members; default: - return 0; + return EmptyMemberList; } } @@ -628,6 +671,13 @@ TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) return pointers; } +TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) const +{ + return make_shared(m_parameterTypes, m_returnParameterTypes, m_location, + m_gasSet || _setGas, m_valueSet || _setValue); +} + + bool MappingType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 1ccdd706a..2060987c4 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -345,10 +345,15 @@ class FunctionType: public Type { public: /// The meaning of the value(s) on the stack referencing the function: - /// INTERNAL: jump tag, EXTERNAL: contract address + function index, + /// INTERNAL: jump tag, EXTERNAL: contract address + function identifier, /// BARE: contract address (non-abi contract call) /// OTHERS: special virtual function, nothing on the stack - enum class Location { INTERNAL, EXTERNAL, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160, LOG0, LOG1, LOG2, LOG3, LOG4, BARE }; + enum class Location { INTERNAL, EXTERNAL, SEND, + SHA3, SUICIDE, + ECRECOVER, SHA256, RIPEMD160, + LOG0, LOG1, LOG2, LOG3, LOG4, + SET_GAS, SET_VALUE, + BARE }; virtual Category getCategory() const override { return Category::FUNCTION; } explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); @@ -357,9 +362,8 @@ public: FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), _location) {} FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, - Location _location = Location::INTERNAL): - m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), - m_location(_location) {} + Location _location = Location::INTERNAL, + bool _gasSet = false, bool _valueSet = false); TypePointers const& getParameterTypes() const { return m_parameterTypes; } TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; } @@ -370,16 +374,28 @@ public: virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); } virtual bool canLiveOutsideStorage() const override { return false; } virtual unsigned getSizeOnStack() const override; + virtual MemberList const& getMembers() const override; Location const& getLocation() const { return m_location; } std::string getCanonicalSignature() const; + bool gasSet() const { return m_gasSet; } + bool valueSet() const { return m_valueSet; } + + /// @returns a copy of this type, where gas or value are set manually. This will never set one + /// of the parameters to fals. + TypePointer copyAndSetGasOrValue(bool _setGas, bool _setValue) const; + private: static TypePointers parseElementaryTypeVector(strings const& _types); TypePointers m_parameterTypes; TypePointers m_returnParameterTypes; Location m_location; + unsigned m_sizeOnStack = 0; + bool m_gasSet = false; ///< true iff the gas value to be used is on the stack + bool m_valueSet = false; ///< true iff the value to be sent is on the stack + mutable std::unique_ptr m_members; }; /** diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 9543497a7..774df3d9f 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -1295,7 +1295,85 @@ BOOST_AUTO_TEST_CASE(contracts_as_addresses) } )"; compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("getBalance()") == toBigEndian(u256(20 - 5)) + toBigEndian(u256(5))); + BOOST_REQUIRE(callContractFunction("getBalance()") == encodeArgs(u256(20 - 5), u256(5))); +} + +BOOST_AUTO_TEST_CASE(gas_and_value_basic) +{ + char const* sourceCode = R"( + contract helper { + bool flag; + function getBalance() returns (uint256 myBalance) { + return this.balance; + } + function setFlag() { flag = true; } + function getFlag() returns (bool fl) { return flag; } + } + contract test { + helper h; + function test() { h = new helper(); } + function sendAmount(uint amount) returns (uint256 bal) { + return h.getBalance.value(amount)(); + } + function outOfGas() returns (bool flagBefore, bool flagAfter, uint myBal) { + flagBefore = h.getFlag(); + h.setFlag.gas(2)(); // should fail due to OOG, return value can be garbage + flagAfter = h.getFlag(); + myBal = this.balance; + } + } + )"; + compileAndRun(sourceCode, 20); + BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5)); + // call to helper should not succeed but amount should be transferred anyway + BOOST_REQUIRE(callContractFunction("outOfGas()", 5) == encodeArgs(false, false, 20 - 5)); +} + +BOOST_AUTO_TEST_CASE(value_complex) +{ + char const* sourceCode = R"( + contract helper { + function getBalance() returns (uint256 myBalance) { + return this.balance; + } + } + contract test { + helper h; + function test() { h = new helper(); } + function sendAmount(uint amount) returns (uint256 bal) { + var x1 = h.getBalance.value(amount); + uint someStackElement = 20; + var x2 = x1.gas(1000); + return x2.value(amount + 3)();// overwrite value + } + } + )"; + compileAndRun(sourceCode, 20); + BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(8)); +} + +BOOST_AUTO_TEST_CASE(value_insane) +{ + char const* sourceCode = R"( + contract helper { + function getBalance() returns (uint256 myBalance) { + return this.balance; + } + } + contract test { + helper h; + function test() { h = new helper(); } + function sendAmount(uint amount) returns (uint256 bal) { + var x1 = h.getBalance.value; + uint someStackElement = 20; + var x2 = x1(amount).gas; + var x3 = x2(1000).value; + return x3(amount + 3)();// overwrite value + } + } + )"; + compileAndRun(sourceCode, 20); + BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(8)); } BOOST_AUTO_TEST_SUITE_END() From de3e6a09db9612ca6fd28c7ccd02d82a1f27da6e Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 13 Jan 2015 18:12:19 +0100 Subject: [PATCH 453/466] Specify value for contract creation. --- libsolidity/AST.cpp | 15 ++--- libsolidity/AST.h | 10 +-- libsolidity/AST_accept.h | 6 -- libsolidity/ExpressionCompiler.cpp | 102 ++++++++++++++++------------- libsolidity/ExpressionCompiler.h | 4 ++ libsolidity/Parser.cpp | 24 +++---- libsolidity/Types.cpp | 3 + libsolidity/Types.h | 4 +- libsolidity/grammar.txt | 2 +- test/SolidityEndToEndTest.cpp | 28 ++++++++ 10 files changed, 113 insertions(+), 85 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index d171006a8..66de5995d 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -309,20 +309,13 @@ bool FunctionCall::isTypeConversion() const void NewExpression::checkTypeRequirements() { m_contractName->checkTypeRequirements(); - for (ASTPointer const& argument: m_arguments) - argument->checkTypeRequirements(); - m_contract = dynamic_cast(m_contractName->getReferencedDeclaration()); if (!m_contract) BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract.")); - shared_ptr type = make_shared(*m_contract); - m_type = type; - TypePointers const& parameterTypes = type->getConstructorType()->getParameterTypes(); - if (parameterTypes.size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call.")); - for (size_t i = 0; i < m_arguments.size(); ++i) - if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) - BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in constructor call.")); + shared_ptr contractType = make_shared(*m_contract); + TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes(); + m_type = make_shared(parameterTypes, TypePointers{contractType}, + FunctionType::Location::CREATION); } void MemberAccess::checkTypeRequirements() diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 95121d4cb..048b808a7 100755 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -790,26 +790,22 @@ private: }; /** - * Expression that creates a new contract, e.g. "new SomeContract(1, 2)". + * Expression that creates a new contract, e.g. the "new SomeContract" part in "new SomeContract(1, 2)". */ class NewExpression: public Expression { public: - NewExpression(Location const& _location, ASTPointer const& _contractName, - std::vector> const& _arguments): - Expression(_location), m_contractName(_contractName), m_arguments(_arguments) {} + NewExpression(Location const& _location, ASTPointer const& _contractName): + Expression(_location), m_contractName(_contractName) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; - std::vector> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; } - /// Returns the referenced contract. Can only be called after type checking. ContractDefinition const* getContract() const { solAssert(m_contract, ""); return m_contract; } private: ASTPointer m_contractName; - std::vector> m_arguments; ContractDefinition const* m_contract = nullptr; }; diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 0e5a71b62..7f3db85a1 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -452,20 +452,14 @@ void FunctionCall::accept(ASTConstVisitor& _visitor) const void NewExpression::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) - { m_contractName->accept(_visitor); - listAccept(m_arguments, _visitor); - } _visitor.endVisit(*this); } void NewExpression::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) - { m_contractName->accept(_visitor); - listAccept(m_arguments, _visitor); - } _visitor.endVisit(*this); } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 8cecbb1b6..ff08a326c 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -235,6 +235,36 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) _functionCall.getExpression().accept(*this); appendExternalFunctionCall(function, arguments, function.getLocation() == Location::BARE); break; + case Location::CREATION: + { + _functionCall.getExpression().accept(*this); + solAssert(!function.gasSet(), "Gas limit set for contract creation."); + solAssert(function.getReturnParameterTypes().size() == 1, ""); + ContractDefinition const& contract = dynamic_cast( + *function.getReturnParameterTypes().front()).getContractDefinition(); + // copy the contract's code into memory + bytes const& bytecode = m_context.getCompiledContract(contract); + m_context << u256(bytecode.size()); + //@todo could be done by actually appending the Assembly, but then we probably need to compile + // multiple times. Will revisit once external fuctions are inlined. + m_context.appendData(bytecode); + //@todo copy to memory position 0, shift as soon as we use memory + m_context << u256(0) << eth::Instruction::CODECOPY; + + unsigned length = bytecode.size(); + length += appendArgumentCopyToMemory(function.getParameterTypes(), arguments, length); + // size, offset, endowment + m_context << u256(length) << u256(0); + if (function.valueSet()) + m_context << eth::dupInstruction(3); + else + m_context << u256(0); + m_context << eth::Instruction::CREATE; + if (function.valueSet()) + m_context << eth::swapInstruction(1) << eth::Instruction::POP; + return false; + break; + } case Location::SET_GAS: { // stack layout: contract_address function_id [gas] [value] @@ -316,38 +346,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) bool ExpressionCompiler::visit(NewExpression const& _newExpression) { - ContractType const* type = dynamic_cast(_newExpression.getType().get()); - solAssert(type, ""); - TypePointers const& types = type->getConstructorType()->getParameterTypes(); - vector> arguments = _newExpression.getArguments(); - solAssert(arguments.size() == types.size(), ""); - - // copy the contracts code into memory - bytes const& bytecode = m_context.getCompiledContract(*_newExpression.getContract()); - m_context << u256(bytecode.size()); - //@todo could be done by actually appending the Assembly, but then we probably need to compile - // multiple times. Will revisit once external fuctions are inlined. - m_context.appendData(bytecode); - //@todo copy to memory position 0, shift as soon as we use memory - m_context << u256(0) << eth::Instruction::CODECOPY; - - unsigned dataOffset = bytecode.size(); - for (unsigned i = 0; i < arguments.size(); ++i) - { - arguments[i]->accept(*this); - appendTypeConversion(*arguments[i]->getType(), *types[i], true); - unsigned const c_numBytes = types[i]->getCalldataEncodedSize(); - if (c_numBytes > 32) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(arguments[i]->getLocation()) - << errinfo_comment("Type " + types[i]->toString() + " not yet supported.")); - bool const c_leftAligned = types[i]->getCategory() == Type::Category::STRING; - bool const c_padToWords = true; - dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, c_numBytes, - c_leftAligned, c_padToWords); - } - // size, offset, endowment - m_context << u256(dataOffset) << u256(0) << u256(0) << eth::Instruction::CREATE; + // code is created for the function call (CREATION) only return false; } @@ -680,21 +679,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio } unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; // reserve 4 bytes for the function's hash identifier - for (unsigned i = 0; i < _arguments.size(); ++i) - { - _arguments[i]->accept(*this); - Type const& type = *_functionType.getParameterTypes()[i]; - appendTypeConversion(*_arguments[i]->getType(), type, true); - unsigned const c_numBytes = type.getCalldataEncodedSize(); - if (c_numBytes == 0 || c_numBytes > 32) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_arguments[i]->getLocation()) - << errinfo_comment("Type " + type.toString() + " not yet supported.")); - bool const c_leftAligned = type.getCategory() == Type::Category::STRING; - bool const c_padToWords = true; - dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, c_numBytes, - c_leftAligned, c_padToWords); - } + dataOffset += appendArgumentCopyToMemory(_functionType.getParameterTypes(), _arguments, dataOffset); + //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : _functionType.getReturnParameterTypes().front().get(); @@ -728,6 +714,28 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio } } +unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _types, + vector> const& _arguments, + unsigned _memoryOffset) +{ + unsigned length = 0; + for (unsigned i = 0; i < _arguments.size(); ++i) + { + _arguments[i]->accept(*this); + appendTypeConversion(*_arguments[i]->getType(), *_types[i], true); + unsigned const c_numBytes = _types[i]->getCalldataEncodedSize(); + if (c_numBytes == 0 || c_numBytes > 32) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(_arguments[i]->getLocation()) + << errinfo_comment("Type " + _types[i]->toString() + " not yet supported.")); + bool const c_leftAligned = _types[i]->getCategory() == Type::Category::STRING; + bool const c_padToWords = true; + length += CompilerUtils(m_context).storeInMemory(_memoryOffset + length, c_numBytes, + c_leftAligned, c_padToWords); + } + return length; +} + ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, unsigned _baseStackOffset): m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset), diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 024c4644c..4a696c39d 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -90,6 +90,10 @@ private: /// Appends code to call a function of the given type with the given arguments. void appendExternalFunctionCall(FunctionType const& _functionType, std::vector> const& _arguments, bool bare = false); + /// Appends code that copies the given arguments to memory (with optional offset). + /// @returns the number of bytes copied to memory + unsigned appendArgumentCopyToMemory(TypePointers const& _functionType, std::vector> const& _arguments, + unsigned _memoryOffset = 0); /** * Helper class to store and retrieve lvalues to and from various locations. diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index e287319d2..ebff3ba40 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -466,17 +466,7 @@ ASTPointer Parser::parseUnaryExpression() { ASTNodeFactory nodeFactory(*this); Token::Value token = m_scanner->getCurrentToken(); - if (token == Token::NEW) - { - expectToken(Token::NEW); - ASTPointer contractName = ASTNodeFactory(*this).createNode(expectIdentifierToken()); - expectToken(Token::LPAREN); - vector> arguments(parseFunctionCallArguments()); - expectToken(Token::RPAREN); - nodeFactory.markEndPosition(); - return nodeFactory.createNode(contractName, arguments); - } - else if (Token::isUnaryOp(token) || Token::isCountOp(token)) + if (Token::isUnaryOp(token) || Token::isCountOp(token)) { // prefix expression m_scanner->next(); @@ -500,7 +490,17 @@ ASTPointer Parser::parseUnaryExpression() ASTPointer Parser::parseLeftHandSideExpression() { ASTNodeFactory nodeFactory(*this); - ASTPointer expression = parsePrimaryExpression(); + ASTPointer expression; + if (m_scanner->getCurrentToken() == Token::NEW) + { + expectToken(Token::NEW); + ASTPointer contractName = ASTNodeFactory(*this).createNode(expectIdentifierToken()); + nodeFactory.markEndPosition(); + expression = nodeFactory.createNode(contractName); + } + else + expression = parsePrimaryExpression(); + while (true) { switch (m_scanner->getCurrentToken()) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 59b8c31b7..ea2da0b6f 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -631,6 +631,7 @@ MemberList const& FunctionType::getMembers() const switch (m_location) { case Location::EXTERNAL: + case Location::CREATION: case Location::ECRECOVER: case Location::SHA256: case Location::RIPEMD160: @@ -644,6 +645,8 @@ MemberList const& FunctionType::getMembers() const {"value", make_shared(parseElementaryTypeVector({"uint"}), TypePointers{copyAndSetGasOrValue(false, true)}, Location::SET_VALUE, m_gasSet, m_valueSet)}}; + if (m_location == Location::CREATION) + members.erase("gas"); m_members.reset(new MemberList(members)); } return *m_members; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 2060987c4..c0ffe864e 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -291,6 +291,8 @@ public: virtual MemberList const& getMembers() const override; + ContractDefinition const& getContractDefinition() const { return m_contract; } + /// Returns the function type of the constructor. Note that the location part of the function type /// is not used, as this type cannot be the type of a variable or expression. std::shared_ptr const& getConstructorType() const; @@ -348,7 +350,7 @@ public: /// INTERNAL: jump tag, EXTERNAL: contract address + function identifier, /// BARE: contract address (non-abi contract call) /// OTHERS: special virtual function, nothing on the stack - enum class Location { INTERNAL, EXTERNAL, SEND, + enum class Location { INTERNAL, EXTERNAL, CREATION, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160, LOG0, LOG1, LOG2, LOG3, LOG4, diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index 8c34997b9..f06d4def2 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -33,7 +33,7 @@ Expression = Assignment | UnaryOperation | BinaryOperation | FunctionCall | NewE // The expression syntax is actually much more complicated Assignment = Expression (AssignmentOp Expression) FunctionCall = Expression '(' Expression ( ',' Expression )* ')' -NewExpression = 'new' Identifier '(' ( Expression ( ',' Expression )* ) ')' +NewExpression = 'new' Identifier MemberAccess = Expression '.' Identifier IndexAccess = Expression '[' Expresison ']' PrimaryExpression = Identifier | NumberLiteral | StringLiteral | ElementaryTypeName | '(' Expression ')' diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 774df3d9f..16787c8e7 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -1376,6 +1376,34 @@ BOOST_AUTO_TEST_CASE(value_insane) BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(8)); } +BOOST_AUTO_TEST_CASE(value_for_constructor) +{ + char const* sourceCode = R"( + contract Helper { + string3 name; + bool flag; + function Helper(string3 x, bool f) { + name = x; + flag = f; + } + function getName() returns (string3 ret) { return name; } + function getFlag() returns (bool ret) { return flag; } + } + contract Main { + Helper h; + function Main() { + h = new Helper.value(10)("abc", true); + } + function getFlag() returns (bool ret) { return h.getFlag(); } + function getName() returns (string3 ret) { return h.getName(); } + function getBalances() returns (uint me, uint them) { me = this.balance; them = h.balance;} + })"; + compileAndRun(sourceCode, 22, "Main"); + BOOST_REQUIRE(callContractFunction("getFlag()") == encodeArgs(true)); + BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc")); + BOOST_REQUIRE(callContractFunction("getBalances()") == encodeArgs(12, 10)); +} + BOOST_AUTO_TEST_SUITE_END() } From 08a1566b85dc42d0e5beab4819447b2c6d61ca11 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 09:28:52 +0100 Subject: [PATCH 454/466] Cleaned up some unused functions --- alethzero/MainWin.cpp | 5 ----- alethzero/MainWin.h | 1 - alethzero/NatspecHandler.cpp | 20 +------------------ alethzero/NatspecHandler.h | 5 +---- alethzero/OurWebThreeStubServer.cpp | 2 +- .../ethereumjs/example/natspec_contract.html | 3 ++- 6 files changed, 5 insertions(+), 31 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 50a362150..2e23c8dc7 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2289,11 +2289,6 @@ std::string Main::lookupNatSpec(dev::h256 const& _contractHash) const return m_natspecDB.retrieve(_contractHash); } -std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) -{ - return m_natspecDB.getUserNotice(_contractHash, _methodName); -} - std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) { return m_natspecDB.getUserNotice(_contractHash, _transactionData); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 64de6a9e9..7a8df3bdf 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -83,7 +83,6 @@ public: std::shared_ptr whisper() const { return m_webThree->whisper(); } std::string lookupNatSpec(dev::h256 const& _contractHash) const; - std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData); QList owned() const { return m_myIdentities + m_myKeys; } diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 2a99e69ef..3449d0aec 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -42,7 +42,6 @@ NatspecHandler::NatspecHandler() ldb::DB::Open(o, path + "/natspec", &m_db); } - void NatspecHandler::add(dev::h256 const& _contractHash, std::string const& _doc) { bytes k = _contractHash.asBytes(); @@ -58,17 +57,6 @@ std::string NatspecHandler::retrieve(dev::h256 const& _contractHash) const return ret; } - -std::string NatspecHandler::getUserNotice(std::string const& json, std::string const& _methodName) -{ - Json::Value natspec, userNotice; - std::string retStr; - m_reader.parse(json, natspec); - retStr = natspec["methods"][_methodName]["notice"].asString(); - - return (retStr == "null\n") ? "" : retStr; -} - std::string NatspecHandler::getUserNotice(std::string const& json, const dev::bytes& _transactionData) { Json::Value natspec, userNotice; @@ -77,9 +65,8 @@ std::string NatspecHandler::getUserNotice(std::string const& json, const dev::by bytes transactionFunctionPart(_transactionData.begin(), _transactionData.begin() + 4); FixedHash<4> transactionFunctionHash(transactionFunctionPart); - // for (auto const& it: natspec["methods"]) Json::Value methods = natspec["methods"]; - for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it ) + for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it) { std::string functionSig = it.key().asString(); FixedHash<4> functionHash(dev::sha3(functionSig)); @@ -93,11 +80,6 @@ std::string NatspecHandler::getUserNotice(std::string const& json, const dev::by return ""; } -std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) -{ - return getUserNotice(retrieve(_contractHash), _methodName); -} - std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) { return getUserNotice(retrieve(_contractHash), _transactionData); diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 23e05fa51..e9b2f50f0 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -41,11 +41,8 @@ class NatspecHandler /// Retrieves the natspec documentation as a string given a contract code hash std::string retrieve(dev::h256 const& _contractHash) const; - /// Given a json natspec string, retrieve the user notice string - std::string getUserNotice(std::string const& json, std::string const& _methodName); + /// Given a json natspec string and the transaction data return the user notice std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData); - /// Given a contract code hash, retrieve the natspec documentation's user notice for that contract - std::string getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); /// Given a contract code hash and the transaction's data retrieve the natspec documention's /// user notice for that transaction. /// @returns The user notice or an empty string if no natspec for the contract exists diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index b5be016ea..1b8023ade 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -53,7 +53,7 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con { // recipient has no code - nothing special about this transaction. // TODO: show basic message for value transfer. - return true; // or whatever. + return true; } //LTODO: Just for debugging here diff --git a/libjsqrc/ethereumjs/example/natspec_contract.html b/libjsqrc/ethereumjs/example/natspec_contract.html index 94edda68d..8d12b4a81 100644 --- a/libjsqrc/ethereumjs/example/natspec_contract.html +++ b/libjsqrc/ethereumjs/example/natspec_contract.html @@ -68,7 +68,8 @@
From 5ff846e1c76347f1b309f7aecb23f9bf9cb85949 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 14 Jan 2015 09:39:21 +0100 Subject: [PATCH 455/466] less invalid opcode tests --- test/createRandomTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 37d61fac9..a913d697f 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -73,7 +73,7 @@ int main(int argc, char *argv[]) uint8_t opcode = randGen(); // disregard all invalid commands, except of one (0x0c) - if ((dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || (randGen() > 128))) + if ((dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || (randGen() > 250))) randomCode += toHex(toCompactBigEndian(opcode)); else i--; From ee682f19492c3a981475451859d8ca7216d65520 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 10:03:09 +0100 Subject: [PATCH 456/466] Cleaning up debug messages and abstracting some functionality --- alethzero/MainWin.cpp | 17 ++++++---- alethzero/MainWin.h | 3 ++ alethzero/OurWebThreeStubServer.cpp | 48 ++++++++++------------------- alethzero/OurWebThreeStubServer.h | 2 ++ 4 files changed, 32 insertions(+), 38 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2e23c8dc7..41a1b1b62 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1635,6 +1635,13 @@ static shh::Topic topicFromText(QString _s) return ret; } + +bool Main::sourceIsSolidity(std::string const& _source) +{ + // TODO: Improve this heuristic + return (_source.substr(0, 8) == "contract" || _source.substr(0, 2) == "/*"); +} + void Main::on_data_textChanged() { m_pcWarp.clear(); @@ -1648,7 +1655,7 @@ void Main::on_data_textChanged() { m_data = fromHex(src); } - else if (src.substr(0, 8) == "contract" || src.substr(0, 5) == "//sol") // improve this heuristic + else if (sourceIsSolidity(src)) { dev::solidity::CompilerStack compiler; try @@ -1874,12 +1881,11 @@ void Main::on_send_clicked() Secret s = i.secret(); if (isCreation()) { + // If execution is a contract creation, add Natspec to + // a local Natspec LEVELDB ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice()); - - // LTODO: work in progress, recompile contract and get the hash of the code - // Also .. yeah improve the heuristic for Solidity and abstract to a function string src = ui->data->toPlainText().toStdString(); - if (src.substr(0, 8) == "contract" || src.substr(0, 2) == "/*") // improve this heuristic + if (sourceIsSolidity(src)) { dev::solidity::CompilerStack compiler; @@ -1892,7 +1898,6 @@ void Main::on_send_clicked() m_natspecDB.add(contractHash, compiler.getMetadata(s, dev::solidity::DocumentationType::NATSPEC_USER)); } - } catch (...) { diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 7a8df3bdf..23280eec4 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -230,6 +230,9 @@ private: void refreshBlockCount(); void refreshBalances(); + /// Attempts to infer that @c _source contains Solidity code + bool sourceIsSolidity(std::string const& _source); + std::unique_ptr ui; std::unique_ptr m_webThree; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 1b8023ade..ff477dd29 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -42,48 +42,32 @@ std::string OurWebThreeStubServer::shh_newIdentity() return toJS(kp.pub()); } -bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showAuthenticationPopup(std::string const& _title, std::string const& _text) const { - // To get the balance of the sender - cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from); + // otherwise it's a transaction to a contract for which we have the natspec + QMessageBox userInput; + userInput.setText(QString::fromStdString(_title)); + userInput.setInformativeText(QString::fromStdString(_text + "\n Do you wish to allow this?")); + userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.button(QMessageBox::Ok)->setText("Allow"); + userInput.button(QMessageBox::Cancel)->setText("Reject"); + userInput.setDefaultButton(QMessageBox::Cancel); + return userInput.exec() == QMessageBox::Ok; +} +bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const +{ h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); - if (contractCodeHash == EmptySHA3) - { // recipient has no code - nothing special about this transaction. // TODO: show basic message for value transfer. return true; - } - - //LTODO: Just for debugging here - cnote << "Contract hash:\n" << contractCodeHash; - cnote << "Transaction Value:\n" << "0x" + toHex(_t.value); - cnote << "Transaction Data:\n" << "0x" + toHex(_t.data); - - //LTODO: Actually find and use the method name here - // std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, "multiply"); std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data); if (userNotice.empty()) - { - QMessageBox userInput; - userInput.setText("Unverified Pending Transaction"); - userInput.setInformativeText("An undocumented transaction is about to be executed." - "Are you really sure you want to go through with it?"); - userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - userInput.setDefaultButton(QMessageBox::Cancel); - return userInput.exec() == QMessageBox::Ok; - } + return showAuthenticationPopup("Unverified Pending Transaction", + "An undocumented transaction is about to be executed."); // otherwise it's a transaction to a contract for which we have the natspec - QMessageBox userInput; - userInput.setText("Pending Transaction"); - userInput.setInformativeText(QString::fromStdString(userNotice + "\n Do you wish to allow this?")); - userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - userInput.button(QMessageBox::Ok)->setText("Allow"); - userInput.button(QMessageBox::Cancel)->setText("Reject"); - userInput.setDefaultButton(QMessageBox::Cancel); - return userInput.exec() == QMessageBox::Ok; - + return showAuthenticationPopup("Pending Transaction", userNotice); } diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index 506a77884..a67af0827 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -41,6 +41,8 @@ signals: void onNewId(QString _s); private: + bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const; + dev::WebThreeDirect* m_web3; Main* m_main; }; From e16d88c894aca5aae90bfc094906d2c138534296 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 14 Jan 2015 10:16:58 +0100 Subject: [PATCH 457/466] Check for hash collisions already before compiling. --- libsolidity/AST.cpp | 38 ++++++++++++++++++++------ libsolidity/AST.h | 2 ++ test/SolidityNameAndTypeResolution.cpp | 12 ++++++++ 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index d171006a8..ea8ecdb75 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -50,18 +50,27 @@ void ContractDefinition::checkTypeRequirements() for (ASTPointer const& function: getDefinedFunctions()) function->checkTypeRequirements(); + + // check for hash collisions in function signatures + vector, FunctionDefinition const*>> exportedFunctionList = getInterfaceFunctionList(); + set> hashes; + for (auto const& hashAndFunction: getInterfaceFunctionList()) + { + FixedHash<4> const& hash = hashAndFunction.first; + if (hashes.count(hash)) + BOOST_THROW_EXCEPTION(createTypeError("Function signature hash collision for " + + hashAndFunction.second->getCanonicalSignature())); + hashes.insert(hash); + } } map, FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() const { - map, FunctionDefinition const*> exportedFunctions; - for (ASTPointer const& f: m_definedFunctions) - if (f->isPublic() && f->getName() != getName()) - { - FixedHash<4> hash(dev::sha3(f->getCanonicalSignature())); - auto res = exportedFunctions.insert(std::make_pair(hash,f.get())); - solAssert(res.second, "Hash collision at Function Definition Hash calculation"); - } + vector, FunctionDefinition const*>> exportedFunctionList = getInterfaceFunctionList(); + map, FunctionDefinition const*> exportedFunctions(exportedFunctionList.begin(), + exportedFunctionList.end()); + solAssert(exportedFunctionList.size() == exportedFunctions.size(), + "Hash collision at Function Definition Hash calculation"); return exportedFunctions; } @@ -74,6 +83,19 @@ FunctionDefinition const* ContractDefinition::getConstructor() const return nullptr; } +vector, FunctionDefinition const*>> ContractDefinition::getInterfaceFunctionList() const +{ + vector, FunctionDefinition const*>> exportedFunctions; + for (ASTPointer const& f: m_definedFunctions) + if (f->isPublic() && f->getName() != getName()) + { + FixedHash<4> hash(dev::sha3(f->getCanonicalSignature())); + exportedFunctions.push_back(make_pair(hash, f.get())); + } + + return exportedFunctions; +} + void StructDefinition::checkMemberTypes() const { for (ASTPointer const& member: getMembers()) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 95121d4cb..28fb7f0a5 100755 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -191,6 +191,8 @@ public: FunctionDefinition const* getConstructor() const; private: + std::vector, FunctionDefinition const*>> getInterfaceFunctionList() const; + std::vector> m_definedStructs; std::vector> m_stateVariables; std::vector> m_definedFunctions; diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 94271b1f7..e2b4f160d 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -357,6 +357,18 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases) } } + +BOOST_AUTO_TEST_CASE(hash_collision_in_interface) +{ + char const* text = "contract test {\n" + " function gsf() {\n" + " }\n" + " function tgeo() {\n" + " }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From 1419263ccc1bf30e57fb688e6f373bc33b2d4dd7 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 14 Jan 2015 10:46:44 +0100 Subject: [PATCH 458/466] Use min gas for send(). --- libsolidity/ExpressionCompiler.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index ff08a326c..93645187c 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -290,12 +290,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) arguments.front()->accept(*this); break; case Location::SEND: - // TODO set gas to min _functionCall.getExpression().accept(*this); + m_context << u256(0); // 0 gas, we do not want to execute code arguments.front()->accept(*this); appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); - appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, Location::EXTERNAL, false, true), {}, true); + appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, + Location::EXTERNAL, true, true), {}, true); break; case Location::SUICIDE: arguments.front()->accept(*this); @@ -696,7 +697,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio if (_functionType.gasSet()) m_context << eth::dupInstruction(7 + (_functionType.valueSet() ? 1 : 0)); else - m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB; + // send all gas except for the 21 needed to execute "SUB" and "CALL" + m_context << u256(21) << eth::Instruction::GAS << eth::Instruction::SUB; m_context << eth::Instruction::CALL << eth::Instruction::POP; // @todo do not ignore failure indicator if (_functionType.valueSet()) From 43602427a1a5687a7758f7c385bf1d9437c0cbc4 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 14 Jan 2015 11:01:42 +0100 Subject: [PATCH 459/466] Remove redundancy in FunctionType::getSizeOnStack. --- libsolidity/Types.cpp | 20 ++------------------ libsolidity/Types.h | 11 ++++++----- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index ea2da0b6f..6a1b120c9 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -546,7 +546,8 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested.")); } -FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal) +FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal): + m_location(_isInternal ? Location::INTERNAL : Location::EXTERNAL) { TypePointers params; TypePointers retParams; @@ -558,22 +559,6 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal retParams.push_back(var->getType()); swap(params, m_parameterTypes); swap(retParams, m_returnParameterTypes); - m_location = _isInternal ? Location::INTERNAL : Location::EXTERNAL; -} - -FunctionType::FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, - FunctionType::Location _location, bool _gasSet, bool _valueSet): - m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), - m_location(_location), m_gasSet(_gasSet), m_valueSet(_valueSet) -{ - if (m_location == Location::EXTERNAL) - m_sizeOnStack = 2; - else if (m_location == Location::INTERNAL || m_location == Location::BARE) - m_sizeOnStack = 1; - if (m_gasSet) - m_sizeOnStack++; - if (m_valueSet) - m_sizeOnStack++; } bool FunctionType::operator==(Type const& _other) const @@ -680,7 +665,6 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con m_gasSet || _setGas, m_valueSet || _setValue); } - bool MappingType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index c0ffe864e..158d58eb9 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -365,7 +365,9 @@ public: _location) {} FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, Location _location = Location::INTERNAL, - bool _gasSet = false, bool _valueSet = false); + bool _gasSet = false, bool _valueSet = false): + m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), + m_location(_location), m_gasSet(_gasSet), m_valueSet(_valueSet) {} TypePointers const& getParameterTypes() const { return m_parameterTypes; } TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; } @@ -393,10 +395,9 @@ private: TypePointers m_parameterTypes; TypePointers m_returnParameterTypes; - Location m_location; - unsigned m_sizeOnStack = 0; - bool m_gasSet = false; ///< true iff the gas value to be used is on the stack - bool m_valueSet = false; ///< true iff the value to be sent is on the stack + Location const m_location; + bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack + bool const m_valueSet = false; ///< true iff the value to be sent is on the stack mutable std::unique_ptr m_members; }; From 9da6bb3629ae9faf5762e1cd77b0a4eae0be1085 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 14 Jan 2015 11:57:22 +0100 Subject: [PATCH 460/466] More flexible access to stack during external function call. --- libsolidity/CompilerContext.cpp | 5 +++++ libsolidity/CompilerContext.h | 3 +++ libsolidity/ExpressionCompiler.cpp | 17 ++++++++++++----- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index 5d10a5f95..29e98eabf 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -95,6 +95,11 @@ unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const return _baseOffset + m_asm.deposit(); } +unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const +{ + return -baseToCurrentStackOffset(-_offset); +} + u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const { auto it = m_stateVariables.find(&_declaration); diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 14672c956..cf505d654 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -62,6 +62,9 @@ public: /// If supplied by a value returned by @ref getBaseStackOffsetOfVariable(variable), returns /// the distance of that variable from the current top of the stack. unsigned baseToCurrentStackOffset(unsigned _baseOffset) const; + /// Converts an offset relative to the current stack height to a value that can be used later + /// with baseToCurrentStackOffset to point to the same stack element. + unsigned currentToBaseStackOffset(unsigned _offset) const; u256 getStorageLocationOfVariable(Declaration const& _declaration) const; /// Appends a JUMPI instruction to a new tag and @returns the tag diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 93645187c..5c81b7c23 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -669,17 +669,24 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio // // value [if _functionType.valueSet()] // gas [if _functionType.gasSet()] - // function identifier [unless options.bare] + // function identifier [unless bare] // contract address unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0); + + unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + (bare ? 0 : 1)); + unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize); + unsigned valueStackPos = m_context.currentToBaseStackOffset(1); + if (!bare) { + // copy function identifier m_context << eth::dupInstruction(gasValueSize + 1); CompilerUtils(m_context).storeInMemory(0, CompilerUtils::dataStartOffset); } - unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; // reserve 4 bytes for the function's hash identifier + // reserve space for the function identifier + unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; dataOffset += appendArgumentCopyToMemory(_functionType.getParameterTypes(), _arguments, dataOffset); //@todo only return the first return value for now @@ -689,13 +696,13 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio // CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top) m_context << u256(retSize) << u256(0) << u256(dataOffset) << u256(0); if (_functionType.valueSet()) - m_context << eth::dupInstruction(5); + m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos)); else m_context << u256(0); - m_context << eth::dupInstruction(6 + gasValueSize + (bare ? 0 : 1)); //copy contract address + m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos)); if (_functionType.gasSet()) - m_context << eth::dupInstruction(7 + (_functionType.valueSet() ? 1 : 0)); + m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos)); else // send all gas except for the 21 needed to execute "SUB" and "CALL" m_context << u256(21) << eth::Instruction::GAS << eth::Instruction::SUB; From 917cade8167c2720cd8cedb19a94679d599d6ed6 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 14 Jan 2015 12:00:28 +0100 Subject: [PATCH 461/466] Style. --- libsolidity/ExpressionCompiler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 5c81b7c23..bcb577374 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -262,7 +262,6 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << eth::Instruction::CREATE; if (function.valueSet()) m_context << eth::swapInstruction(1) << eth::Instruction::POP; - return false; break; } case Location::SET_GAS: From 8ab39943f02216b592714f97fbf50e91070384b5 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 14 Jan 2015 12:07:08 +0100 Subject: [PATCH 462/466] Work around Visual Studio's C2797. --- libethereum/Client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.h b/libethereum/Client.h index 824190b6f..9d2396e46 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -93,7 +93,7 @@ struct ClientWatch explicit ClientWatch(h256 _id): id(_id) {} h256 id; - LocalisedLogEntries changes = { InitialChange }; + LocalisedLogEntries changes = LocalisedLogEntries{ InitialChange }; }; struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; }; From 396fe954b6044f1da7c31f76def8fc508e5d969d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 14:30:52 +0100 Subject: [PATCH 463/466] Small fixes AZ MainWin.cpp --- alethzero/MainWin.cpp | 4 ++-- alethzero/NatspecHandler.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 41a1b1b62..ae239d412 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1639,7 +1639,7 @@ static shh::Topic topicFromText(QString _s) bool Main::sourceIsSolidity(std::string const& _source) { // TODO: Improve this heuristic - return (_source.substr(0, 8) == "contract" || _source.substr(0, 2) == "/*"); + return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol"); } void Main::on_data_textChanged() @@ -1901,7 +1901,7 @@ void Main::on_send_clicked() } catch (...) { - statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); + statusBar()->showMessage("Couldn't compile Solidity Contract."); } } } diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 3449d0aec..a6255a3e7 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -15,7 +15,7 @@ along with cpp-ethereum. If not, see . */ -/** @file NatspecHandler.h +/** @file NatspecHandler.cpp * @author Lefteris Karapetsas * @date 2015 */ From 4ad3ab21741c610e1b34b7d181a9bca86e27af54 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 16:49:09 +0100 Subject: [PATCH 464/466] Fixes and additional checks for Natspec Popup authentication --- alethzero/MainWin.cpp | 20 +++++++++++++-- alethzero/MainWin.h | 4 +++ alethzero/NatspecHandler.cpp | 40 ++++++++++++++++++++--------- alethzero/NatspecHandler.h | 1 + alethzero/OurWebThreeStubServer.cpp | 1 - libethereum/Defaults.h | 1 - libsolidity/CompilerStack.cpp | 22 ++-------------- libsolidity/CompilerStack.h | 9 +++---- 8 files changed, 56 insertions(+), 42 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ae239d412..e281fda94 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -1642,6 +1642,22 @@ bool Main::sourceIsSolidity(std::string const& _source) return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol"); } +string const Main::getFunctionHashes(dev::solidity::CompilerStack const &_compiler, + string const& _contractName) +{ + string ret = ""; + auto const& contract = _compiler.getContractDefinition(_contractName); + auto interfaceFunctions = contract.getInterfaceFunctions(); + + for (auto const& it: interfaceFunctions) + { + ret += it.first.abridged(); + ret += " :"; + ret += it.second->getName() + "\n"; + } + return ret; +} + void Main::on_data_textChanged() { m_pcWarp.clear(); @@ -1664,7 +1680,7 @@ void Main::on_data_textChanged() solidity = "

Solidity

"; solidity += "
" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "
"; solidity += "
" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "
"; - solidity += "
" + QString::fromStdString(compiler.getFunctionHashes()).toHtmlEscaped() + "
"; + solidity += "
" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "
"; } catch (dev::Exception const& exception) { diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 23280eec4..96a4b1128 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -36,6 +36,7 @@ #include #include #include +#include #include "NatspecHandler.h" @@ -232,6 +233,9 @@ private: /// Attempts to infer that @c _source contains Solidity code bool sourceIsSolidity(std::string const& _source); + /// @eturns all method hashes of a Solidity contract in a string + std::string const getFunctionHashes(dev::solidity::CompilerStack const &_compiler, + std::string const& _contractName = ""); std::unique_ptr ui; diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index a6255a3e7..5cccb608a 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -26,41 +26,49 @@ #include #include #include +#include #include #include using namespace dev; using namespace dev::eth; +using namespace std; NatspecHandler::NatspecHandler() { - std::string path = Defaults::dbPath(); + string path = Defaults::dbPath(); boost::filesystem::create_directories(path); ldb::Options o; o.create_if_missing = true; ldb::DB::Open(o, path + "/natspec", &m_db); } -void NatspecHandler::add(dev::h256 const& _contractHash, std::string const& _doc) +NatspecHandler::~NatspecHandler() +{ + delete m_db; +} + +void NatspecHandler::add(dev::h256 const& _contractHash, string const& _doc) { bytes k = _contractHash.asBytes(); - std::string v = _doc; + string v = _doc; m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); } -std::string NatspecHandler::retrieve(dev::h256 const& _contractHash) const +string NatspecHandler::retrieve(dev::h256 const& _contractHash) const { bytes k = _contractHash.asBytes(); - std::string ret; + string ret; m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); return ret; } -std::string NatspecHandler::getUserNotice(std::string const& json, const dev::bytes& _transactionData) +string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _transactionData) { - Json::Value natspec, userNotice; - std::string retStr; + Json::Value natspec; + Json::Value userNotice; + string retStr; m_reader.parse(json, natspec); bytes transactionFunctionPart(_transactionData.begin(), _transactionData.begin() + 4); FixedHash<4> transactionFunctionHash(transactionFunctionPart); @@ -68,11 +76,19 @@ std::string NatspecHandler::getUserNotice(std::string const& json, const dev::by Json::Value methods = natspec["methods"]; for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it) { - std::string functionSig = it.key().asString(); + Json::Value keyValue = it.key(); + if (!keyValue.isString()) + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Illegal Natspec JSON detected")); + + string functionSig = keyValue.asString(); FixedHash<4> functionHash(dev::sha3(functionSig)); - if (functionHash == transactionFunctionHash) { - return (*it)["notice"].asString(); + if (functionHash == transactionFunctionHash) + { + Json::Value val = (*it)["notice"]; + if (!val.isString()) + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Illegal Natspec JSON detected")); + return val.asString(); } } @@ -80,7 +96,7 @@ std::string NatspecHandler::getUserNotice(std::string const& json, const dev::by return ""; } -std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) +string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) { return getUserNotice(retrieve(_contractHash), _transactionData); } diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index e9b2f50f0..edd9281d7 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -35,6 +35,7 @@ class NatspecHandler { public: NatspecHandler(); + ~NatspecHandler(); /// Stores locally in a levelDB a key value pair of contract code hash to natspec documentation void add(dev::h256 const& _contractHash, std::string const& _doc); diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index ff477dd29..ce1f28507 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -44,7 +44,6 @@ std::string OurWebThreeStubServer::shh_newIdentity() bool OurWebThreeStubServer::showAuthenticationPopup(std::string const& _title, std::string const& _text) const { - // otherwise it's a transaction to a contract for which we have the natspec QMessageBox userInput; userInput.setText(QString::fromStdString(_title)); userInput.setInformativeText(QString::fromStdString(_text + "\n Do you wish to allow this?")); diff --git a/libethereum/Defaults.h b/libethereum/Defaults.h index 3b19166b1..91d5872f7 100644 --- a/libethereum/Defaults.h +++ b/libethereum/Defaults.h @@ -23,7 +23,6 @@ #include - namespace dev { namespace eth diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index b06423497..11d90d08b 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -137,12 +137,12 @@ bytes const& CompilerStack::getBytecode(string const& _contractName) const return getContract(_contractName).bytecode; } -bytes const& CompilerStack::getRuntimeBytecode(std::string const& _contractName) const +bytes const& CompilerStack::getRuntimeBytecode(string const& _contractName) const { return getContract(_contractName).runtimeBytecode; } -dev::h256 CompilerStack::getContractCodeHash(std::string const& _contractName) const +dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const { return dev::sha3(getRuntimeBytecode(_contractName)); } @@ -192,24 +192,6 @@ string const& CompilerStack::getMetadata(string const& _contractName, Documentat return *(*doc); } -std::string const CompilerStack::getFunctionHashes(std::string const& _contractName) -{ - if (!m_parseSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - - std::string ret = ""; - Contract const& contract = getContract(_contractName); - auto interfaceFunctions = contract.contract->getInterfaceFunctions(); - - for (auto const& it: interfaceFunctions) - { - ret += it.first.abridged(); - ret += " :"; - ret += it.second->getName() + "\n"; - } - return ret; -} - Scanner const& CompilerStack::getScanner(string const& _sourceName) const { return *getSource(_sourceName).scanner; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 202f1b321..29de69d59 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -76,11 +76,11 @@ public: /// @returns the compiled bytecode bytes const& compile(std::string const& _sourceCode, bool _optimize = false); - /// Gets the assembled bytecode for a contract + /// @returns the assembled bytecode for a contract. bytes const& getBytecode(std::string const& _contractName = "") const; - /// Get the runtime context's bytecode for a contract + /// @returns the runtime context's bytecode for a contract. bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; - /// Get the runtime context's code hash for a contract + /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. dev::h256 getContractCodeHash(std::string const& _contractName = "") const; /// Streams a verbose version of the assembly to @a _outStream. @@ -99,9 +99,6 @@ public: /// Can be one of 4 types defined at @c DocumentationType std::string const& getMetadata(std::string const& _contractName, DocumentationType _type) const; - /// Convenience function to return all contract method hashes in a string - std::string const getFunctionHashes(std::string const& _contractName = ""); - /// @returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner(std::string const& _sourceName = "") const; /// @returns the parsed source unit with the supplied name. From 79b953d9e5ac86d26b603c0e5a0270c9747ad997 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 17:14:46 +0100 Subject: [PATCH 465/466] Minor style fixes --- alethzero/NatspecHandler.cpp | 2 +- libsolidity/CompilerStack.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 5cccb608a..98d2879c7 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -74,7 +74,7 @@ string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _tran FixedHash<4> transactionFunctionHash(transactionFunctionPart); Json::Value methods = natspec["methods"]; - for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it) + for (Json::ValueIterator it = methods.begin(); it != methods.end(); ++it) { Json::Value keyValue = it.key(); if (!keyValue.isString()) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 29de69d59..aa55abe50 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -78,9 +78,9 @@ public: /// @returns the assembled bytecode for a contract. bytes const& getBytecode(std::string const& _contractName = "") const; - /// @returns the runtime context's bytecode for a contract. - bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. + bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; + /// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor. dev::h256 getContractCodeHash(std::string const& _contractName = "") const; /// Streams a verbose version of the assembly to @a _outStream. From 6ee8be71bac498b90f59100bf33cf5ad046eb809 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 15 Jan 2015 01:36:18 +0100 Subject: [PATCH 466/466] more style fixes and an addition to the coding style --- CodingStandards.txt | 16 ++++++++++++++++ alethzero/MainWin.cpp | 5 +---- alethzero/NatspecHandler.cpp | 7 +++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/CodingStandards.txt b/CodingStandards.txt index 672a20958..9d4b5f9d0 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -162,3 +162,19 @@ d. In general expressions should be roughly as important/semantically meaningful a. Comments should be doxygen-compilable, using @notation rather than \notation. +12. Include Headers + +a. Includes should go in order of lower level (STL -> boost -> libdevcore -> libdevcrypto -> libethcore -> libethereum) to higher level. Lower levels are basically dependencies to the higher levels. For example: + +#include +#include + +#include +#include +#include +#include +#include +#include + +b. The only exception to the above rule is the top of a .cpp file where its corresponding header should be located. + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e281fda94..117d500cc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1902,11 +1902,9 @@ void Main::on_send_clicked() ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice()); string src = ui->data->toPlainText().toStdString(); if (sourceIsSolidity(src)) - { - - dev::solidity::CompilerStack compiler; try { + dev::solidity::CompilerStack compiler; m_data = compiler.compile(src, m_enableOptimizer); for (std::string& s: compiler.getContractNames()) { @@ -1919,7 +1917,6 @@ void Main::on_send_clicked() { statusBar()->showMessage("Couldn't compile Solidity Contract."); } - } } else ethereum()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 98d2879c7..25cc13d4a 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -20,16 +20,15 @@ * @date 2015 */ #include "NatspecHandler.h" -#include #include +#include -#include #include #include #include #include #include - +#include using namespace dev; using namespace dev::eth; @@ -93,7 +92,7 @@ string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _tran } // not found - return ""; + return string(); } string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData)