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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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/588] 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 68ccbefc94e9c24684ccbe9a520aeb13aff0a067 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 30 Sep 2014 22:51:53 +0200 Subject: [PATCH 016/588] init --- .gitignore | 14 ++ ethereum.js | 534 ++++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 29 +++ 3 files changed, 577 insertions(+) create mode 100644 .gitignore create mode 100644 ethereum.js create mode 100644 index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..de3a847ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store +ethereum/ethereum +ethereal/ethereal + diff --git a/ethereum.js b/ethereum.js new file mode 100644 index 000000000..2af7d15a1 --- /dev/null +++ b/ethereum.js @@ -0,0 +1,534 @@ +(function(window) { + function isPromise(o) { + return typeof o === "object" && o.then + } + + var eth = { + _callbacks: {}, + _events: {}, + prototype: Object(), + + toHex: function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; + }, + + toAscii: function(hex) { + // Find termination + var str = ""; + var i = 0, l = hex.length; + for(; i < l; i+=2) { + var code = hex.charCodeAt(i) + if(code == 0) { + break; + } + + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + + return str; + }, + + fromAscii: function(str, pad) { + if(pad === undefined) { + pad = 32 + } + + var hex = this.toHex(str); + + while(hex.length < pad*2) + hex += "00"; + + return hex + }, + + block: function(numberOrHash) { + return new Promise(function(resolve, reject) { + var func; + if(typeof numberOrHash == "string") { + func = "getBlockByHash"; + } else { + func = "getBlockByNumber"; + } + + postData({call: func, args: [numberOrHash]}, function(block) { + if(block) + resolve(block); + else + reject("not found"); + + }); + }); + }, + + transact: function(params) { + if(params === undefined) { + params = {}; + } + + if(params.endowment !== undefined) + params.value = params.endowment; + if(params.code !== undefined) + params.data = params.code; + + + var promises = [] + if(isPromise(params.to)) { + promises.push(params.to.then(function(_to) { params.to = _to; })); + } + if(isPromise(params.from)) { + promises.push(params.from.then(function(_from) { params.from = _from; })); + } + + if(typeof params.data !== "object" || isPromise(params.data)) { + params.data = [params.data] + } + + var data = params.data; + for(var i = 0; i < params.data.length; i++) { + if(isPromise(params.data[i])) { + var promise = params.data[i]; + var _i = i; + promises.push(promise.then(function(_arg) { params.data[_i] = _arg; })); + } + } + + // Make sure everything is string + var fields = ["value", "gas", "gasPrice"]; + for(var i = 0; i < fields.length; i++) { + if(params[fields[i]] === undefined) { + params[fields[i]] = ""; + } + params[fields[i]] = params[fields[i]].toString(); + } + + // Load promises then call the last "transact". + return Promise.all(promises).then(function() { + return new Promise(function(resolve, reject) { + params.data = params.data.join(""); + postData({call: "transact", args: [params]}, function(data) { + if(data[1]) + reject(data[0]); + else + resolve(data[0]); + }); + }); + }) + }, + + compile: function(code) { + return new Promise(function(resolve, reject) { + postData({call: "compile", args: [code]}, function(data) { + if(data[1]) + reject(data[0]); + else + resolve(data[0]); + }); + }); + }, + + balanceAt: function(address) { + var promises = []; + + if(isPromise(address)) { + promises.push(address.then(function(_address) { address = _address; })); + } + + return Promise.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getBalanceAt", args: [address]}, function(balance) { + resolve(balance); + }); + }); + }); + }, + + countAt: function(address) { + var promises = []; + + if(isPromise(address)) { + promises.push(address.then(function(_address) { address = _address; })); + } + + return Promise.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getCountAt", args: [address]}, function(count) { + resolve(count); + }); + }); + }); + }, + + codeAt: function(address) { + var promises = []; + + if(isPromise(address)) { + promises.push(address.then(function(_address) { address = _address; })); + } + + return Promise.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getCodeAt", args: [address]}, function(code) { + resolve(code); + }); + }); + }); + }, + + storageAt: function(address, storageAddress) { + var promises = []; + + if(isPromise(address)) { + promises.push(address.then(function(_address) { address = _address; })); + } + + if(isPromise(storageAddress)) { + promises.push(storageAddress.then(function(_sa) { storageAddress = _sa; })); + } + + return Promise.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getStorageAt", args: [address, storageAddress]}, function(entry) { + resolve(entry); + }); + }); + }); + }, + + stateAt: function(address, storageAddress) { + return this.storageAt(address, storageAddress); + }, + + call: function(params) { + if(params === undefined) { + params = {}; + } + + if(params.endowment !== undefined) + params.value = params.endowment; + if(params.code !== undefined) + params.data = params.code; + + + var promises = [] + if(isPromise(params.to)) { + promises.push(params.to.then(function(_to) { params.to = _to; })); + } + if(isPromise(params.from)) { + promises.push(params.from.then(function(_from) { params.from = _from; })); + } + + if(isPromise(params.data)) { + promises.push(params.data.then(function(_code) { params.data = _code; })); + } else { + if(typeof params.data === "object") { + data = ""; + for(var i = 0; i < params.data.length; i++) { + data += params.data[i] + } + } else { + data = params.data; + } + } + + // Make sure everything is string + var fields = ["value", "gas", "gasPrice"]; + for(var i = 0; i < fields.length; i++) { + if(params[fields[i]] === undefined) { + params[fields[i]] = ""; + } + params[fields[i]] = params[fields[i]].toString(); + } + + // Load promises then call the last "transact". + return Promise.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "call", args: params}, function(data) { + if(data[1]) + reject(data[0]); + else + resolve(data[0]); + }); + }); + }) + }, + + watch: function(params) { + return new Filter(params); + }, + + secretToAddress: function(key) { + var promises = []; + if(isPromise(key)) { + promises.push(key.then(function(_key) { key = _key; })); + } + + return Promise.all(promises).then(function() { + return new Promise(function(resolve, reject) { + postData({call: "getSecretToAddress", args: [key]}, function(address) { + resolve(address); + }); + }); + }); + }, + + on: function(event, cb) { + if(eth._events[event] === undefined) { + eth._events[event] = []; + } + + eth._events[event].push(cb); + + return this + }, + + off: function(event, cb) { + if(eth._events[event] !== undefined) { + var callbacks = eth._events[event]; + for(var i = 0; i < callbacks.length; i++) { + if(callbacks[i] === cb) { + delete callbacks[i]; + } + } + } + + return this + }, + + trigger: function(event, data) { + var callbacks = eth._events[event]; + if(callbacks !== undefined) { + for(var i = 0; i < callbacks.length; i++) { + // Figure out whether the returned data was an array + // array means multiple return arguments (multiple params) + if(data instanceof Array) { + callbacks[i].apply(this, data); + } else { + callbacks[i].call(this, data); + } + } + } + }, + }; + + // Eth object properties + Object.defineProperty(eth, "key", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getKey"}, function(k) { + resolve(k); + }); + }); + }, + }); + + Object.defineProperty(eth, "gasPrice", { + get: function() { + return "10000000000000" + } + }); + + Object.defineProperty(eth, "coinbase", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getCoinBase"}, function(coinbase) { + resolve(coinbase); + }); + }); + }, + }); + + Object.defineProperty(eth, "listening", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getIsListening"}, function(listening) { + resolve(listening); + }); + }); + }, + }); + + + Object.defineProperty(eth, "mining", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getIsMining"}, function(mining) { + resolve(mining); + }); + }); + }, + }); + + Object.defineProperty(eth, "peerCount", { + get: function() { + return new Promise(function(resolve, reject) { + postData({call: "getPeerCount"}, function(peerCount) { + resolve(peerCount); + }); + }); + }, + }); + + var EthWebSocket = function(host) { + // onmessage handlers + this.handlers = []; + // queue will be filled with messages if send is invoked before the ws is ready + this.queued = []; + this.ready = false; + + this.ws = new WebSocket(host); + + var self = this; + this.ws.onmessage = function(event) { + for(var i = 0; i < self.handlers.length; i++) { + self.handlers[i].call(self, event.data, event) + } + }; + + this.ws.onopen = function() { + self.ready = true; + + for(var i = 0; i < self.queued.length; i++) { + // Resend + self.send(self.queued[i]); + } + }; + }; + + EthWebSocket.prototype.send = function(jsonData) { + if(this.ready) { + var data = JSON.stringify(jsonData); + + this.ws.send(data); + } else { + this.queued.push(jsonData); + } + }; + + EthWebSocket.prototype.onMessage = function(handler) { + this.handlers.push(handler); + }; + eth.WebSocket = EthWebSocket; + + var filters = []; + var Filter = function(options) { + filters.push(this); + + this.callbacks = []; + this.options = options; + + var call; + if(options === "chain") { + call = "newFilterString" + } else if(typeof options === "object") { + call = "newFilter" + } + + var self = this; // Cheaper than binding + this.promise = new Promise(function(resolve, reject) { + postData({call: call, args: [options]}, function(id) { + self.id = id; + + resolve(id); + }); + }); + }; + + Filter.prototype.changed = function(callback) { + var self = this; + this.promise.then(function(id) { + self.callbacks.push(callback); + }); + }; + + Filter.prototype.trigger = function(messages, id) { + if(id == this.id) { + for(var i = 0; i < this.callbacks.length; i++) { + this.callbacks[i].call(this, messages); + } + } + }; + + Filter.prototype.uninstall = function() { + this.promise.then(function(id) { + postData({call: "uninstallFilter", args:[id]}); + }); + }; + + Filter.prototype.messages = function() { + var self=this; + return Promise.all([this.promise]).then(function() { + var id = self.id + return new Promise(function(resolve, reject) { + postData({call: "getMessages", args: [id]}, function(messages) { + resolve(messages); + }); + }); + }); + }; + + // Register to the messages callback. "messages" will be emitted when new messages + // from the client have been created. + eth.on("messages", function(messages, id) { + for(var i = 0; i < filters.length; i++) { + filters[i].trigger(messages, id); + } + }); + + var g_seed = 1; + function postData(data, cb) { + //console.log("postData", data.call) + + data.seed = g_seed; + if(cb) { + eth._callbacks[data.seed] = cb; + } + + if(data.args === undefined) { + data.args = []; + } + + g_seed++; + + window._messagingAdapter.call(this, data) + } + + var sock; + eth.init = function(addr) { + if(sock) + sock.ws.close(); + + sock = new eth.WebSocket(addr); + sock.onMessage(function(ev) { + var data = JSON.parse(ev) + + if(data._event !== undefined) { + eth.trigger(data._event, data.data); + } else { + if(data.seed) { + var cb = eth._callbacks[data.seed]; + if(cb) { + cb.call(this, data.data) + + // Remove the "trigger" callback + delete eth._callbacks[ev.seed]; + } + } + } + }); + + window._messagingAdapter = function(data) { + sock.send(data); + }; + } + + eth.init("ws://localhost:40404/eth"); + + window.eth = eth; +})(this); + diff --git a/index.html b/index.html new file mode 100644 index 000000000..50006905b --- /dev/null +++ b/index.html @@ -0,0 +1,29 @@ + + + + + + + + + + +

std::name_reg

+ + +
+ + + + From 0cae9c3c1b46c3323c6e217c7bb709cff92960b7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 30 Sep 2014 22:55:07 +0200 Subject: [PATCH 017/588] Readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..c777013d0 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Ethereum JavaScript API + +This is the Ethereum compatible JavaScript API implemented using +`WebSocket` and `Promise`s. + +For an example see `index.html`. + +**Please note this repo is in it's early stage.** From a3c66b2740b28c0bca3289c09f9eea39fdd15bd7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 30 Sep 2014 22:58:09 +0200 Subject: [PATCH 018/588] How to spawn a websocket node --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index c777013d0..239a78d28 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,13 @@ This is the Ethereum compatible JavaScript API implemented using For an example see `index.html`. **Please note this repo is in it's early stage.** + +If you'd like to run a WebSocket ethereum node check out +[go-ethereum](https://github.com/ethereum/go-ethereum). + +To install ethereum and spawn a node: + +``` +go get github.com/ethereum/go-ethereum/ethereum +ethereum -ws -loglevel=4 +``` From 00136561a0329e38a47101b4c25f24b60c8e2a6b Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 30 Sep 2014 23:50:15 +0200 Subject: [PATCH 019/588] 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 020/588] 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 021/588] 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 022/588] 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 023/588] 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 024/588] 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 025/588] 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 026/588] 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 027/588] 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 028/588] 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 3bc238b1cece4fbe27af3bcec4300ed977b090f3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 2 Oct 2014 10:56:22 +0200 Subject: [PATCH 029/588] Added eth providers An ethereum provider provides an interface from which communication can be done. --- ethereum.js => main.js | 139 ++++++++++++++++++++++++++++------------- 1 file changed, 94 insertions(+), 45 deletions(-) rename ethereum.js => main.js (82%) diff --git a/ethereum.js b/main.js similarity index 82% rename from ethereum.js rename to main.js index 2af7d15a1..992c41c7d 100644 --- a/ethereum.js +++ b/main.js @@ -56,7 +56,7 @@ func = "getBlockByNumber"; } - postData({call: func, args: [numberOrHash]}, function(block) { + eth.provider.send({call: func, args: [numberOrHash]}, function(block) { if(block) resolve(block); else @@ -111,7 +111,7 @@ return Promise.all(promises).then(function() { return new Promise(function(resolve, reject) { params.data = params.data.join(""); - postData({call: "transact", args: [params]}, function(data) { + eth.provider.send({call: "transact", args: [params]}, function(data) { if(data[1]) reject(data[0]); else @@ -123,7 +123,7 @@ compile: function(code) { return new Promise(function(resolve, reject) { - postData({call: "compile", args: [code]}, function(data) { + eth.provider.send({call: "compile", args: [code]}, function(data) { if(data[1]) reject(data[0]); else @@ -141,7 +141,7 @@ return Promise.all(promises).then(function() { return new Promise(function(resolve, reject) { - postData({call: "getBalanceAt", args: [address]}, function(balance) { + eth.provider.send({call: "getBalanceAt", args: [address]}, function(balance) { resolve(balance); }); }); @@ -157,7 +157,7 @@ return Promise.all(promises).then(function() { return new Promise(function(resolve, reject) { - postData({call: "getCountAt", args: [address]}, function(count) { + eth.provider.send({call: "getCountAt", args: [address]}, function(count) { resolve(count); }); }); @@ -173,7 +173,7 @@ return Promise.all(promises).then(function() { return new Promise(function(resolve, reject) { - postData({call: "getCodeAt", args: [address]}, function(code) { + eth.provider.send({call: "getCodeAt", args: [address]}, function(code) { resolve(code); }); }); @@ -193,7 +193,7 @@ return Promise.all(promises).then(function() { return new Promise(function(resolve, reject) { - postData({call: "getStorageAt", args: [address, storageAddress]}, function(entry) { + eth.provider.send({call: "getStorageAt", args: [address, storageAddress]}, function(entry) { resolve(entry); }); }); @@ -248,7 +248,7 @@ // Load promises then call the last "transact". return Promise.all(promises).then(function() { return new Promise(function(resolve, reject) { - postData({call: "call", args: params}, function(data) { + eth.provider.send({call: "call", args: params}, function(data) { if(data[1]) reject(data[0]); else @@ -270,7 +270,7 @@ return Promise.all(promises).then(function() { return new Promise(function(resolve, reject) { - postData({call: "getSecretToAddress", args: [key]}, function(address) { + eth.provider.send({call: "getSecretToAddress", args: [key]}, function(address) { resolve(address); }); }); @@ -320,7 +320,7 @@ Object.defineProperty(eth, "key", { get: function() { return new Promise(function(resolve, reject) { - postData({call: "getKey"}, function(k) { + eth.provider.send({call: "getKey"}, function(k) { resolve(k); }); }); @@ -336,7 +336,7 @@ Object.defineProperty(eth, "coinbase", { get: function() { return new Promise(function(resolve, reject) { - postData({call: "getCoinBase"}, function(coinbase) { + eth.provider.send({call: "getCoinBase"}, function(coinbase) { resolve(coinbase); }); }); @@ -346,7 +346,7 @@ Object.defineProperty(eth, "listening", { get: function() { return new Promise(function(resolve, reject) { - postData({call: "getIsListening"}, function(listening) { + eth.provider.send({call: "getIsListening"}, function(listening) { resolve(listening); }); }); @@ -357,7 +357,7 @@ Object.defineProperty(eth, "mining", { get: function() { return new Promise(function(resolve, reject) { - postData({call: "getIsMining"}, function(mining) { + eth.provider.send({call: "getIsMining"}, function(mining) { resolve(mining); }); }); @@ -367,13 +367,66 @@ Object.defineProperty(eth, "peerCount", { get: function() { return new Promise(function(resolve, reject) { - postData({call: "getPeerCount"}, function(peerCount) { + eth.provider.send({call: "getPeerCount"}, function(peerCount) { resolve(peerCount); }); }); }, }); + var ProviderManager = function() { + this.queued = []; + this.ready = false; + this.provider = undefined; + this.seed = 1; + }; + ProviderManager.prototype.send = function(data, cb) { + data.seed = this.seed; + if(cb) { + eth._callbacks[data.seed] = cb; + } + + if(data.args === undefined) { + data.args = []; + } + + this.seed++; + + if(this.provider !== undefined) { + this.provider.send(data); + } else { + this.queued = data; + } + }; + + ProviderManager.prototype.set = function(provider) { + if(this.provider !== undefined && this.provider.unload !== undefined) { + this.provider.unload(); + } + + this.provider = provider; + this.ready = true; + }; + + ProviderManager.prototype.sendQueued = function() { + for(var i = 0; this.queued.length; i++) { + // Resend + this.send(this.queued[i]); + } + }; + + ProviderManager.prototype.installed = function() { + return this.provider !== undefined; + }; + + eth.provider = new ProviderManager(); + + eth.setProvider = function(provider) { + eth.provider.set(provider); + + eth.provider.sendQueued(); + }; + var EthWebSocket = function(host) { // onmessage handlers this.handlers = []; @@ -413,6 +466,10 @@ EthWebSocket.prototype.onMessage = function(handler) { this.handlers.push(handler); }; + + EthWebSocket.prototype.unload = function() { + this.ws.close(); + }; eth.WebSocket = EthWebSocket; var filters = []; @@ -431,7 +488,7 @@ var self = this; // Cheaper than binding this.promise = new Promise(function(resolve, reject) { - postData({call: call, args: [options]}, function(id) { + eth.provider.send({call: call, args: [options]}, function(id) { self.id = id; resolve(id); @@ -456,7 +513,7 @@ Filter.prototype.uninstall = function() { this.promise.then(function(id) { - postData({call: "uninstallFilter", args:[id]}); + eth.provider.send({call: "uninstallFilter", args:[id]}); }); }; @@ -465,7 +522,7 @@ return Promise.all([this.promise]).then(function() { var id = self.id return new Promise(function(resolve, reject) { - postData({call: "getMessages", args: [id]}, function(messages) { + eth.provider.send({call: "getMessages", args: [id]}, function(messages) { resolve(messages); }); }); @@ -480,30 +537,10 @@ } }); - var g_seed = 1; - function postData(data, cb) { - //console.log("postData", data.call) - - data.seed = g_seed; - if(cb) { - eth._callbacks[data.seed] = cb; - } - - if(data.args === undefined) { - data.args = []; - } - - g_seed++; - - window._messagingAdapter.call(this, data) - } - var sock; - eth.init = function(addr) { - if(sock) - sock.ws.close(); - - sock = new eth.WebSocket(addr); + // Install default provider + if(!eth.provider.installed()) { + var sock = new eth.WebSocket("ws://localhost:40404/eth"); sock.onMessage(function(ev) { var data = JSON.parse(ev) @@ -522,13 +559,25 @@ } }); - window._messagingAdapter = function(data) { - sock.send(data); - }; + eth.setProvider(sock); } - eth.init("ws://localhost:40404/eth"); - window.eth = eth; })(this); +/* + function eth.provider.send(data, cb) { + data.seed = g_seed; + if(cb) { + eth._callbacks[data.seed] = cb; + } + + if(data.args === undefined) { + data.args = []; + } + + g_seed++; + + window._messagingAdapter.call(this, data) + } + */ From 0b8ba6d2e46c762c7e148112192c7550b2ba8d60 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 2 Oct 2014 11:00:28 +0200 Subject: [PATCH 030/588] 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 031/588] 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 032/588] 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 033/588] 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 034/588] 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 035/588] 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 036/588] - 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 037/588] 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 038/588] 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 039/588] 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 040/588] 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 041/588] 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 042/588] 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 043/588] 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 044/588] - 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 045/588] 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 046/588] 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 047/588] 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 048/588] 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 049/588] 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 c95dfec5e47185be79b32871a0c2cf8b59572cce Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 6 Oct 2014 19:26:51 +0200 Subject: [PATCH 050/588] push data instead of assign --- main.js | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/main.js b/main.js index 992c41c7d..c82774711 100644 --- a/main.js +++ b/main.js @@ -1,6 +1,6 @@ (function(window) { function isPromise(o) { - return typeof o === "object" && o.then + return o instanceof Promise } var eth = { @@ -111,7 +111,7 @@ return Promise.all(promises).then(function() { return new Promise(function(resolve, reject) { params.data = params.data.join(""); - eth.provider.send({call: "transact", args: [params]}, function(data) { + eth.provider.send({call: "transact", args: ["0x"+params]}, function(data) { if(data[1]) reject(data[0]); else @@ -395,7 +395,7 @@ if(this.provider !== undefined) { this.provider.send(data); } else { - this.queued = data; + this.queued.push(data); } }; @@ -564,20 +564,3 @@ window.eth = eth; })(this); - -/* - function eth.provider.send(data, cb) { - data.seed = g_seed; - if(cb) { - eth._callbacks[data.seed] = cb; - } - - if(data.args === undefined) { - data.args = []; - } - - g_seed++; - - window._messagingAdapter.call(this, data) - } - */ 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 051/588] 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 052/588] 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 053/588] 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 054/588] 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 055/588] 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 056/588] 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 057/588] 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 058/588] 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 059/588] 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 060/588] 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 061/588] 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 062/588] 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 063/588] 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 064/588] 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 065/588] 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 066/588] 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 067/588] 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 068/588] 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 069/588] 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 070/588] 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 071/588] 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 072/588] 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 073/588] 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 074/588] 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 075/588] 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 076/588] 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 077/588] 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 078/588] 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 079/588] 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 080/588] 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 081/588] 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 082/588] 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 083/588] 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 084/588] 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 085/588] 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 086/588] 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 087/588] 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 088/588] 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 089/588] 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 090/588] 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 091/588] 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 092/588] 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 093/588] 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 094/588] 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 095/588] 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 096/588] 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 097/588] 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 098/588] 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 099/588] 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 100/588] 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 101/588] 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 102/588] 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 103/588] 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 104/588] 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 105/588] 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 106/588] 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 107/588] 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 108/588] 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 109/588] 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 110/588] 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 111/588] 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 112/588] 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 113/588] 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 114/588] 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 115/588] 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 116/588] 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 117/588] 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 118/588] 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 119/588] 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 120/588] 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 121/588] 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 122/588] * 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 123/588] 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 124/588] 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 125/588] 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 126/588] 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 127/588] 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 128/588] 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 129/588] 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 130/588] 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 131/588] 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 132/588] 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 133/588] 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 134/588] 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 135/588] 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 136/588] 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 137/588] 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 138/588] 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 139/588] 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 140/588] 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 141/588] 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 142/588] 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 143/588] 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 144/588] 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 145/588] 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 146/588] 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 147/588] 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 148/588] 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 149/588] 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 150/588] 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 151/588] 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 152/588] 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 153/588] 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 154/588] 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 155/588] 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 156/588] 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 157/588] 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 590c393680e78daf77e871c1a089c98141b6d70e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 21 Oct 2014 00:14:41 +0200 Subject: [PATCH 158/588] Updated according to the new Generic JSON RPC API --- index.html | 2 +- main.js | 490 ++++++++++++++++++++++++----------------------------- 2 files changed, 227 insertions(+), 265 deletions(-) diff --git a/index.html b/index.html index 50006905b..939a4c65b 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - + + + + - + @@ -25,8 +30,10 @@ function registerName() {

std::name_reg

- -
+ + +
+result:
From 7305fb32d36477a144061be8cefdab193f3ab86b Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 4 Nov 2014 22:02:11 +0000 Subject: [PATCH 303/588] 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 4be4db5e6cfdde4ba5c1243b2bafeb6bbae3643c Mon Sep 17 00:00:00 2001 From: Marian Oancea Date: Wed, 5 Nov 2014 19:46:01 +0200 Subject: [PATCH 304/588] Converted to node module Converted to npm package Added brower Added browserify with minification Updated Readme --- .bowerrc | 5 + .editorconfig | 12 + .gitignore | 5 +- .jshintrc | 50 ++ .travis.yml | 6 + LICENSE | 14 + README.md | 52 ++- bower.json | 47 ++ dist/ethereum.js | 765 +++++++++++++++++++++++++++++++ dist/ethereum.min.js | 1 + index.html => example/index.html | 14 +- example/node-app.js | 16 + gulpfile.js | 56 +++ httprpc.js | 92 ---- index.js | 6 + lib/browser_fix/xhr.js | 35 ++ lib/httprpc.js | 92 ++++ lib/index.js | 6 + lib/main.js | 458 ++++++++++++++++++ qt.js => lib/qt.js | 39 +- lib/websocket.js | 73 +++ main.js | 458 ------------------ package.json | 64 +++ websocket.js | 72 --- 24 files changed, 1785 insertions(+), 653 deletions(-) create mode 100644 .bowerrc create mode 100644 .editorconfig create mode 100644 .jshintrc create mode 100644 .travis.yml create mode 100644 LICENSE create mode 100644 bower.json create mode 100644 dist/ethereum.js create mode 100644 dist/ethereum.min.js rename index.html => example/index.html (62%) create mode 100644 example/node-app.js create mode 100644 gulpfile.js delete mode 100644 httprpc.js create mode 100644 index.js create mode 100644 lib/browser_fix/xhr.js create mode 100644 lib/httprpc.js create mode 100644 lib/index.js create mode 100644 lib/main.js rename qt.js => lib/qt.js (53%) create mode 100644 lib/websocket.js delete mode 100644 main.js create mode 100644 package.json delete mode 100644 websocket.js diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 000000000..c3a8813e8 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,5 @@ +{ + "directory": "example/js/", + "cwd": "./", + "analytics": false +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..fac40a5f5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false \ No newline at end of file diff --git a/.gitignore b/.gitignore index de3a847ac..b0c55cc4e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,7 @@ */**/.DS_Store ethereum/ethereum ethereal/ethereal - +example/js +node_modules +bower_components +npm-debug.log diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 000000000..c0ec5f89d --- /dev/null +++ b/.jshintrc @@ -0,0 +1,50 @@ +{ + "predef": [ + "console", + "require", + "equal", + "test", + "testBoth", + "testWithDefault", + "raises", + "deepEqual", + "start", + "stop", + "ok", + "strictEqual", + "module", + "expect", + "reject", + "impl" + ], + + "esnext": true, + "proto": true, + "node" : true, + "browser" : true, + "browserify" : true, + + "boss" : true, + "curly": false, + "debug": true, + "devel": true, + "eqeqeq": true, + "evil": true, + "forin": false, + "immed": false, + "laxbreak": false, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "regexp": false, + "undef": true, + "sub": true, + "strict": false, + "white": false, + "shadow": true, + "eqnull": true +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..76a5b361a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - "0.10" +# before_script: +# - npm install +# - gulp build \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..0f187b873 --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +This file is part of ethereum.js. + +ethereum.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +ethereum.js 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with ethereum.js. If not, see . \ No newline at end of file diff --git a/README.md b/README.md index 86e2969be..539420c3d 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,57 @@ # Ethereum JavaScript API This is the Ethereum compatible JavaScript API using `Promise`s -which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. +which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js -For an example see `index.html`. +### Installation + +## Node.js + + npm install ethereum.js + +## For browser +Bower + + bower install ethereum.js + +Component + + component install ethereum/ethereum.js + +* Include `ethereum.min.js` in your html file. +* Include [es6-promise](https://github.com/jakearchibald/es6-promise) or another ES6-Shim if your browser doesn't support ECMAScript 6. + +### Usage +Require the library: + + var web3 = require('web3'); + +Set a provider (QtProvider, WebSocketProvider, HttpRpcProvider) + + var web3.setProvider(new web3.providers.WebSocketProvider('ws://localhost:40404/eth')); + +There you go, now you can use it: + +``` +web3.eth.coinbase.then(function(result){ + console.log(result); + return web3.eth.balanceAt(result); +}).then(function(balance){ + console.log(web3.toDecimal(balance)); +}).catch(function(err){ + console.log(err); +}); +``` + + +For another example see `example/index.html`. + +### Building + +* `gulp build` + + +### Testing **Please note this repo is in it's early stage.** diff --git a/bower.json b/bower.json new file mode 100644 index 000000000..b4b7a1427 --- /dev/null +++ b/bower.json @@ -0,0 +1,47 @@ +{ + "name": "ethereum.js", + "namespace": "ethereum", + "version": "0.0.1", + "description": "Ethereum Compatible JavaScript API", + "main": "dist/ethereum.js", + "dependencies": { + "es6-promise": "#master" + }, + "repository": { + "type": "git", + "url": "https://github.com/ethereum/ethereum.js.git" + }, + "bugs": { + "url": "https://github.com/ethereum/ethereum.js/issues" + }, + "keywords": [ + "ethereum", + "javascript", + "API" + ], + "authors": [ + { + "name": "Marek Kotewicz", + "email": "marek@ethdev.com", + "homepage": "https://github.com/debris" + }, + { + "name": "Marian Oancea", + "email": "marian.oancea@gmail.com", + "homepage": "https://github.com/cubedro" + } + ], + "license": "LGPL-3.0", + "ignore": [ + "example", + "lib", + "node_modules", + "package.json", + ".editorconfig", + ".gitignore", + ".jshintrc", + ".travis.yml", + "*.js", + "**/*.txt" + ] +} \ No newline at end of file diff --git a/dist/ethereum.js b/dist/ethereum.js new file mode 100644 index 000000000..30a0a3797 --- /dev/null +++ b/dist/ethereum.js @@ -0,0 +1,765 @@ +require=(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. +*/ +/** @file httprpc.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + + +var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line + + +var HttpRpcProvider = function (host) { + this.handlers = []; + this.host = host; +}; + +function formatJsonRpcObject(object) { + return { + jsonrpc: '2.0', + method: object.call, + params: object.args, + id: object._id + }; +} + +function formatJsonRpcMessage(message) { + var object = JSON.parse(message); + + return { + _id: object.id, + data: object.result + }; +} + +HttpRpcProvider.prototype.sendRequest = function (payload, cb) { + var data = formatJsonRpcObject(payload); + + var request = new XMLHttpRequest(); + request.open("POST", this.host, true); + request.send(JSON.stringify(data)); + request.onreadystatechange = function () { + if (request.readyState === 4 && cb) { + cb(request); + } + }; +}; + +HttpRpcProvider.prototype.send = function (payload) { + var self = this; + this.sendRequest(payload, function (request) { + self.handlers.forEach(function (handler) { + handler.call(self, formatJsonRpcMessage(request.responseText)); + }); + }); +}; + +HttpRpcProvider.prototype.poll = function (payload, id) { + var self = this; + this.sendRequest(payload, function (request) { + var parsed = JSON.parse(request.responseText); + if (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result) { + return; + } + self.handlers.forEach(function (handler) { + handler.call(self, {_event: payload.call, _id: id, data: parsed.result}); + }); + }); +}; + +Object.defineProperty(HttpRpcProvider.prototype, "onmessage", { + set: function (handler) { + this.handlers.push(handler); + } +}); + +module.exports = HttpRpcProvider; + +},{"xmlhttprequest":1}],3:[function(require,module,exports){ +/* +This file is part of ethereum.js. + +ethereum.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +ethereum.js 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with ethereum.js. If not, see . +*/ +/** @file main.js +* @authors: +* Jeffrey Wilcke +* Marek Kotewicz +* Marian Oancea +* @date 2014 +*/ + + +function isPromise(o) { + return o instanceof Promise; +} + +function flattenPromise (obj) { + if (obj instanceof Promise) { + return Promise.resolve(obj); + } + + if (obj instanceof Array) { + return new Promise(function (resolve) { + var promises = obj.map(function (o) { + return flattenPromise(o); + }); + + return Promise.all(promises).then(function (res) { + for (var i = 0; i < obj.length; i++) { + obj[i] = res[i]; + } + resolve(obj); + }); + }); + } + + if (obj instanceof Object) { + return new Promise(function (resolve) { + var keys = Object.keys(obj); + var promises = keys.map(function (key) { + return flattenPromise(obj[key]); + }); + + return Promise.all(promises).then(function (res) { + for (var i = 0; i < keys.length; i++) { + obj[keys[i]] = res[i]; + } + resolve(obj); + }); + }); + } + + return Promise.resolve(obj); +} + +var ethMethods = function () { + var blockCall = function (args) { + return typeof args[0] === "string" ? "blockByHash" : "blockByNumber"; + }; + + var transactionCall = function (args) { + return typeof args[0] === "string" ? 'transactionByHash' : 'transactionByNumber'; + }; + + var uncleCall = function (args) { + return typeof args[0] === "string" ? 'uncleByHash' : 'uncleByNumber'; + }; + + var methods = [ + { name: 'balanceAt', call: 'balanceAt' }, + { name: 'stateAt', call: 'stateAt' }, + { name: 'countAt', call: 'countAt'}, + { name: 'codeAt', call: 'codeAt' }, + { name: 'transact', call: 'transact' }, + { name: 'call', call: 'call' }, + { name: 'block', call: blockCall }, + { name: 'transaction', call: transactionCall }, + { name: 'uncle', call: uncleCall }, + { name: 'compile', call: 'compile' } + ]; + return methods; +}; + +var ethProperties = function () { + return [ + { name: 'coinbase', getter: 'coinbase', setter: 'setCoinbase' }, + { name: 'listening', getter: 'listening', setter: 'setListening' }, + { name: 'mining', getter: 'mining', setter: 'setMining' }, + { name: 'gasPrice', getter: 'gasPrice' }, + { name: 'account', getter: 'account' }, + { name: 'accounts', getter: 'accounts' }, + { name: 'peerCount', getter: 'peerCount' }, + { name: 'defaultBlock', getter: 'defaultBlock', setter: 'setDefaultBlock' }, + { name: 'number', getter: 'number'} + ]; +}; + +var dbMethods = function () { + return [ + { name: 'put', call: 'put' }, + { name: 'get', call: 'get' }, + { name: 'putString', call: 'putString' }, + { name: 'getString', call: 'getString' } + ]; +}; + +var shhMethods = function () { + return [ + { name: 'post', call: 'post' }, + { name: 'newIdentity', call: 'newIdentity' }, + { name: 'haveIdentity', call: 'haveIdentity' }, + { name: 'newGroup', call: 'newGroup' }, + { name: 'addToGroup', call: 'addToGroup' } + ]; +}; + +var ethWatchMethods = function () { + var newFilter = function (args) { + return typeof args[0] === 'string' ? 'newFilterString' : 'newFilter'; + }; + + return [ + { name: 'newFilter', call: newFilter }, + { name: 'uninstallFilter', call: 'uninstallFilter' }, + { name: 'getMessages', call: 'getMessages' } + ]; +}; + +var shhWatchMethods = function () { + return [ + { name: 'newFilter', call: 'shhNewFilter' }, + { name: 'uninstallFilter', call: 'shhUninstallFilter' }, + { name: 'getMessage', call: 'shhGetMessages' } + ]; +}; + +var setupMethods = function (obj, methods) { + methods.forEach(function (method) { + obj[method.name] = function () { + return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) { + var call = typeof method.call === "function" ? method.call(args) : method.call; + return {call: call, args: args}; + }).then(function (request) { + return new Promise(function (resolve, reject) { + web3.provider.send(request, function (result) { + if (result || typeof result === "boolean") { + resolve(result); + return; + } + reject(result); + }); + }); + }).catch(function( err) { + console.error(err); + }); + }; + }); +}; + +var setupProperties = function (obj, properties) { + properties.forEach(function (property) { + var proto = {}; + proto.get = function () { + return new Promise(function(resolve, reject) { + web3.provider.send({call: property.getter}, function(result) { + resolve(result); + }); + }); + }; + if (property.setter) { + proto.set = function (val) { + return flattenPromise([val]).then(function (args) { + return new Promise(function (resolve) { + web3.provider.send({call: property.setter, args: args}, function (result) { + if (result) { + resolve(result); + } else { + reject(result); + } + }); + }); + }).catch(function (err) { + console.error(err); + }); + }; + } + Object.defineProperty(obj, property.name, proto); + }); +}; + +var web3 = { + _callbacks: {}, + _events: {}, + providers: {}, + toHex: function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; + }, + + toAscii: function(hex) { + // Find termination + var str = ""; + var i = 0, l = hex.length; + for(; i < l; i+=2) { + var code = hex.charCodeAt(i); + if(code === 0) { + break; + } + + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + + return str; + }, + + toDecimal: function (val) { + return parseInt(val, 16); + }, + + fromAscii: function(str, pad) { + pad = pad === undefined ? 32 : pad; + var hex = this.toHex(str); + while(hex.length < pad*2) + hex += "00"; + return hex; + }, + + eth: { + prototype: Object(), // jshint ignore:line + watch: function (params) { + return new Filter(params, ethWatch); + } + }, + + db: { + prototype: Object() // jshint ignore:line + }, + + shh: { + prototype: Object(), // jshint ignore:line + watch: function (params) { + return new Filter(params, shhWatch); + } + }, + + on: function(event, id, cb) { + if(web3._events[event] === undefined) { + web3._events[event] = {}; + } + + web3._events[event][id] = cb; + return this; + }, + + off: function(event, id) { + if(web3._events[event] !== undefined) { + delete web3._events[event][id]; + } + + return this; + }, + + trigger: function(event, id, data) { + var callbacks = web3._events[event]; + if (!callbacks || !callbacks[id]) { + return; + } + var cb = callbacks[id]; + cb(data); + } +}; + +var eth = web3.eth; +setupMethods(eth, ethMethods()); +setupProperties(eth, ethProperties()); +setupMethods(web3.db, dbMethods()); +setupMethods(web3.shh, shhMethods()); + +var ethWatch = { + changed: 'changed' +}; +setupMethods(ethWatch, ethWatchMethods()); +var shhWatch = { + changed: 'shhChanged' +}; +setupMethods(shhWatch, shhWatchMethods()); + +var ProviderManager = function() { + this.queued = []; + this.polls = []; + this.ready = false; + this.provider = undefined; + this.id = 1; + + var self = this; + var poll = function () { + if (self.provider && self.provider.poll) { + self.polls.forEach(function (data) { + data.data._id = self.id; + self.id++; + self.provider.poll(data.data, data.id); + }); + } + setTimeout(poll, 12000); + }; + poll(); +}; + +ProviderManager.prototype.send = function(data, cb) { + data._id = this.id; + if (cb) { + web3._callbacks[data._id] = cb; + } + + data.args = data.args || []; + this.id++; + + if(this.provider !== undefined) { + this.provider.send(data); + } else { + console.warn("provider is not set"); + this.queued.push(data); + } +}; + +ProviderManager.prototype.set = function(provider) { + if(this.provider !== undefined && this.provider.unload !== undefined) { + this.provider.unload(); + } + + this.provider = provider; + this.ready = true; +}; + +ProviderManager.prototype.sendQueued = function() { + for(var i = 0; this.queued.length; i++) { + // Resend + this.send(this.queued[i]); + } +}; + +ProviderManager.prototype.installed = function() { + return this.provider !== undefined; +}; + +ProviderManager.prototype.startPolling = function (data, pollId) { + if (!this.provider || !this.provider.poll) { + return; + } + this.polls.push({data: data, id: pollId}); +}; + +ProviderManager.prototype.stopPolling = function (pollId) { + for (var i = this.polls.length; i--;) { + var poll = this.polls[i]; + if (poll.id === pollId) { + this.polls.splice(i, 1); + } + } +}; + +web3.provider = new ProviderManager(); + +web3.setProvider = function(provider) { + provider.onmessage = messageHandler; + web3.provider.set(provider); + web3.provider.sendQueued(); +}; + +var Filter = function(options, impl) { + this.impl = impl; + this.callbacks = []; + + var self = this; + this.promise = impl.newFilter(options); + this.promise.then(function (id) { + self.id = id; + web3.on(impl.changed, id, self.trigger.bind(self)); + web3.provider.startPolling({call: impl.changed, args: [id]}, id); + }); +}; + +Filter.prototype.arrived = function(callback) { + this.changed(callback); +}; + +Filter.prototype.changed = function(callback) { + var self = this; + this.promise.then(function(id) { + self.callbacks.push(callback); + }); +}; + +Filter.prototype.trigger = function(messages) { + for(var i = 0; i < this.callbacks.length; i++) { + this.callbacks[i].call(this, messages); + } +}; + +Filter.prototype.uninstall = function() { + var self = this; + this.promise.then(function (id) { + self.impl.uninstallFilter(id); + web3.provider.stopPolling(id); + web3.off(impl.changed, id); + }); +}; + +Filter.prototype.messages = function() { + var self = this; + return this.promise.then(function (id) { + return self.impl.getMessages(id); + }); +}; + +function messageHandler(data) { + if(data._event !== undefined) { + web3.trigger(data._event, data._id, data.data); + return; + } + + if(data._id) { + var cb = web3._callbacks[data._id]; + if (cb) { + cb.call(this, data.data); + delete web3._callbacks[data._id]; + } + } +} + +/* +// Install default provider +if(!web3.provider.installed()) { + var sock = new web3.providers.WebSocketProvider("ws://localhost:40404/eth"); + + web3.setProvider(sock); +} +*/ + +module.exports = web3; + +},{}],4:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file qt.js + * @authors: + * Marek Kotewicz + * @date 2014 + */ + +var QtProvider = function() { + this.handlers = []; + + var self = this; + navigator.qt.onmessage = function (message) { + self.handlers.forEach(function (handler) { + handler.call(self, JSON.parse(message.data)); + }); + }; +}; + +QtProvider.prototype.send = function(payload) { + navigator.qt.postMessage(JSON.stringify(payload)); +}; + +Object.defineProperty(QtProvider.prototype, "onmessage", { + set: function(handler) { + this.handlers.push(handler); + } +}); + +module.exports = QtProvider; + +},{}],5:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file websocket.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +var WebSocket = require('ws'); // jshint ignore:line + + +var WebSocketProvider = function(host) { + // onmessage handlers + this.handlers = []; + // queue will be filled with messages if send is invoked before the ws is ready + this.queued = []; + this.ready = false; + + this.ws = new WebSocket(host); + + var self = this; + this.ws.onmessage = function(event) { + for(var i = 0; i < self.handlers.length; i++) { + self.handlers[i].call(self, JSON.parse(event.data), event); + } + }; + + this.ws.onopen = function() { + self.ready = true; + + for(var i = 0; i < self.queued.length; i++) { + // Resend + self.send(self.queued[i]); + } + }; +}; +WebSocketProvider.prototype.send = function(payload) { + if(this.ready) { + var data = JSON.stringify(payload); + + this.ws.send(data); + } else { + this.queued.push(payload); + } +}; + +WebSocketProvider.prototype.onMessage = function(handler) { + this.handlers.push(handler); +}; + +WebSocketProvider.prototype.unload = function() { + this.ws.close(); +}; +Object.defineProperty(WebSocketProvider.prototype, "onmessage", { + set: function(provider) { this.onMessage(provider); } +}); + +module.exports = WebSocketProvider; + +},{"ws":6}],6:[function(require,module,exports){ + +/** + * Module dependencies. + */ + +var global = (function() { return this; })(); + +/** + * WebSocket constructor. + */ + +var WebSocket = global.WebSocket || global.MozWebSocket; + +/** + * Module exports. + */ + +module.exports = WebSocket ? ws : null; + +/** + * WebSocket constructor. + * + * The third `opts` options object gets ignored in web browsers, since it's + * non-standard, and throws a TypeError if passed to the constructor. + * See: https://github.com/einaros/ws/issues/227 + * + * @param {String} uri + * @param {Array} protocols (optional) + * @param {Object) opts (optional) + * @api public + */ + +function ws(uri, protocols, opts) { + var instance; + if (protocols) { + instance = new WebSocket(uri, protocols); + } else { + instance = new WebSocket(uri); + } + return instance; +} + +if (WebSocket) ws.prototype = WebSocket.prototype; + +},{}],"web3":[function(require,module,exports){ +var web3 = require('./lib/main'); +web3.providers.WebSocketProvider = require('./lib/websocket'); +web3.providers.HttpRpcProvider = require('./lib/httprpc'); +web3.providers.QtProvider = require('./lib/qt'); + +module.exports = web3; +},{"./lib/httprpc":2,"./lib/main":3,"./lib/qt":4,"./lib/websocket":5}]},{},[]); diff --git a/dist/ethereum.min.js b/dist/ethereum.min.js new file mode 100644 index 000000000..f5fadf79a --- /dev/null +++ b/dist/ethereum.min.js @@ -0,0 +1 @@ +require=function t(e,n,r){function o(s,a){if(!n[s]){if(!e[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var l=new Error("Cannot find module '"+s+"'");throw l.code="MODULE_NOT_FOUND",l}var u=n[s]={exports:{}};e[s][0].call(u.exports,function(t){var n=e[s][1][t];return o(n?n:t)},u,u.exports,t,e,n,r)}return n[s].exports}for(var i="function"==typeof require&&require,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},toDecimal:function(t){return parseInt(t,16)},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return n},eth:{prototype:Object(),watch:function(t){return new m(t,d)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(t){return new m(t,v)}},on:function(t,e,n){return void 0===f._events[t]&&(f._events[t]={}),f._events[t][e]=n,this},off:function(t,e){return void 0!==f._events[t]&&delete f._events[t][e],this},trigger:function(t,e,n){var r=f._events[t];if(r&&r[e]){var o=r[e];o(n)}}},h=f.eth;u(h,o()),p(h,i()),u(f.db,s()),u(f.shh,a());var d={changed:"changed"};u(d,c());var v={changed:"shhChanged"};u(v,l());var g=function(){this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1;var t=this,e=function(){t.provider&&t.provider.poll&&t.polls.forEach(function(e){e.data._id=t.id,t.id++,t.provider.poll(e.data,e.id)}),setTimeout(e,12e3)};e()};g.prototype.send=function(t,e){t._id=this.id,e&&(f._callbacks[t._id]=e),t.args=t.args||[],this.id++,void 0!==this.provider?this.provider.send(t):(console.warn("provider is not set"),this.queued.push(t))},g.prototype.set=function(t){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=t,this.ready=!0},g.prototype.sendQueued=function(){for(var t=0;this.queued.length;t++)this.send(this.queued[t])},g.prototype.installed=function(){return void 0!==this.provider},g.prototype.startPolling=function(t,e){this.provider&&this.provider.poll&&this.polls.push({data:t,id:e})},g.prototype.stopPolling=function(t){for(var e=this.polls.length;e--;){var n=this.polls[e];n.id===t&&this.polls.splice(e,1)}},f.provider=new g,f.setProvider=function(t){t.onmessage=r,f.provider.set(t),f.provider.sendQueued()};var m=function(t,e){this.impl=e,this.callbacks=[];var n=this;this.promise=e.newFilter(t),this.promise.then(function(t){n.id=t,f.on(e.changed,t,n.trigger.bind(n)),f.provider.startPolling({call:e.changed,args:[t]},t)})};m.prototype.arrived=function(t){this.changed(t)},m.prototype.changed=function(t){var e=this;this.promise.then(function(){e.callbacks.push(t)})},m.prototype.trigger=function(t){for(var e=0;e - - - - - + + + - + + } + - -

std::name_reg

- - - -
-result:
- +

std::name_reg

+ + +
+ result: +
- + diff --git a/lib/abi.js b/lib/abi.js index 9102454b0..0ac27e6b8 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -8,11 +8,17 @@ var findIndex = function (array, callback) { return end ? i - 1 : -1; }; +var findMethodIndex = function (json, methodName) { + return findIndex(json, function (method) { + return method.name === methodName; + }); +}; + var padLeft = function (number, n) { return (new Array(n * 2 - number.toString().length + 1)).join("0") + number; }; -var setupTypes = function () { +var setupInputTypes = function () { var prefixedType = function (prefix) { return function (type, value) { var expected = prefix; @@ -25,32 +31,34 @@ var setupTypes = function () { }; }; - var namedType = function (name, padding) { + var namedType = function (name, padding, formatter) { return function (type, value) { if (type !== name) { return false; } - return padLeft(value, padding); + return padLeft(formatter ? value : formatter(value), padding); }; }; + var formatBool = function (value) { + return value ? '1' : '0'; + }; + return [ prefixedType('uint'), prefixedType('int'), namedType('address', 20), - namedType('bool', 1), + namedType('bool', 1, formatBool), ]; }; -var types = setupTypes(); +var inputTypes = setupInputTypes(); -var toBytes = function (json, methodName, params) { +var toAbiInput = function (json, methodName, params) { var bytes = ""; - var index = findIndex(json, function (method) { - return method.name === methodName; - }); - + var index = findMethodIndex(json, methodName); + if (index === -1) { return; } @@ -62,8 +70,8 @@ var toBytes = function (json, methodName, params) { for (var i = 0; i < method.inputs.length; i++) { var found = false; - for (var j = 0; j < types.length && !found; j++) { - found = types[j](method.inputs[i].type, params[i]); + for (var j = 0; j < inputTypes.length && !found; j++) { + found = inputTypes[j](method.inputs[i].type, params[i]); } if (!found) { console.error('unsupported json type: ' + method.inputs[i].type); @@ -73,7 +81,75 @@ var toBytes = function (json, methodName, params) { return bytes; }; +var setupOutputTypes = function () { + var prefixedType = function (prefix) { + return function (type) { + var expected = prefix; + if (type.indexOf(expected) !== 0) { + return -1; + } + + var padding = parseInt(type.slice(expected.length)) / 8; + return padding * 2; + }; + }; + + var namedType = function (name, padding) { + return function (type) { + return name === type ? padding * 2: -1; + }; + }; + + var formatInt = function (value) { + return parseInt(value, 16); + }; + + var formatBool = function (value) { + return value === '1' ? true : false; + }; + + return [ + { padding: prefixedType('uint'), format: formatInt }, + { padding: prefixedType('int'), format: formatInt }, + { padding: namedType('address', 20) }, + { padding: namedType('bool', 1), format: formatBool } + ]; +}; + +var outputTypes = setupOutputTypes(); + +var fromAbiOutput = function (json, methodName, output) { + var index = findMethodIndex(json, methodName); + + if (index === -1) { + return; + } + + output = output.slice(2); + + var result = []; + var method = json[index]; + for (var i = 0; i < method.outputs.length; i++) { + var padding = -1; + for (var j = 0; j < outputTypes.length && padding === -1; j++) { + padding = outputTypes[j].padding(method.outputs[i].type); + } + + if (padding === -1) { + // not found output parsing + continue; + } + var res = output.slice(0, padding); + var formatter = outputTypes[j - 1].format; + result.push(formatter ? formatter(res): res); + output = output.slice(padding); + } + + return result; +}; + module.exports = { - toBytes: toBytes + toAbiInput: toAbiInput, + fromAbiOutput: fromAbiOutput }; From 0e67fcd361ea1681f989077969417e166ea8453e Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 13 Nov 2014 12:24:34 +0100 Subject: [PATCH 335/588] contract object --- dist/ethereum.js | 6 +++--- dist/ethereum.js.map | 6 +++--- dist/ethereum.min.js | 2 +- index.js | 2 +- lib/abi.js | 15 ++++++++++++--- lib/main.js | 4 +--- 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index decf71e53..2cbd42f81 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -1,17 +1,17 @@ require=(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;oi&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ir&&(t=e.charCodeAt(r),0!==t);r+=2)n+=String.fromCharCode(parseInt(e.substr(r,2),16));return n},toDecimal:function(e){return parseInt(e,16)},fromAscii:function(e,t){t=void 0===t?32:t;for(var n=this.toHex(e);n.length<2*t;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(e){return new a(e,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(e){return new a(e,i)}},on:function(e,t,n){return void 0===g._events[e]&&(g._events[e]={}),g._events[e][t]=n,this},off:function(e,t){return void 0!==g._events[e]&&delete g._events[e][t],this},trigger:function(e,t,n){var r,o=g._events[e];o&&o[t]&&(r=o[t])(n)}},m=g.eth;f(m,c()),v(m,u()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,d()),i={changed:"shh_changed"},f(i,p()),s=function(){var e,t;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,e=this,(t=function(){e.provider&&e.provider.poll&&e.polls.forEach(function(t){t.data._id=e.id,e.id++,e.provider.poll(t.data,t.id)}),setTimeout(t,12e3)})()},s.prototype.send=function(e,t){e._id=this.id,t&&(g._callbacks[e._id]=t),e.args=e.args||[],this.id++,void 0!==this.provider?this.provider.send(e):(console.warn("provider is not set"),this.queued.push(e))},s.prototype.set=function(e){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=e,this.ready=!0},s.prototype.sendQueued=function(){for(var e=0;this.queued.length;e++)this.send(this.queued[e])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(e,t){this.provider&&this.provider.poll&&this.polls.push({data:e,id:t})},s.prototype.stopPolling=function(e){var t,n;for(t=this.polls.length;t--;)n=this.polls[t],n.id===e&&this.polls.splice(t,1)},g.provider=new s,g.setProvider=function(e){e.onmessage=r,g.provider.set(e),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(e,t){this.impl=t,this.callbacks=[];var n=this;this.promise=t.newFilter(e),this.promise.then(function(e){n.id=e,g.on(t.changed,e,n.trigger.bind(n)),g.provider.startPolling({call:t.changed,args:[e]},e)})},a.prototype.arrived=function(e){this.changed(e)},a.prototype.changed=function(e){var t=this;this.promise.then(function(){t.callbacks.push(e)})},a.prototype.trigger=function(e){for(var t=0;tr&&(t=e.charCodeAt(r),0!==t);r+=2)n+=String.fromCharCode(parseInt(e.substr(r,2),16));return n},toDecimal:function(e){return parseInt(e,16)},fromAscii:function(e,t){t=void 0===t?32:t;for(var n=this.toHex(e);n.length<2*t;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(e){return new a(e,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(e){return new a(e,i)}},on:function(e,t,n){return void 0===g._events[e]&&(g._events[e]={}),g._events[e][t]=n,this},off:function(e,t){return void 0!==g._events[e]&&delete g._events[e][t],this},trigger:function(e,t,n){var r,o=g._events[e];o&&o[t]&&(r=o[t])(n)}},m=g.eth;f(m,c()),v(m,u()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,d()),i={changed:"shh_changed"},f(i,p()),s=function(){var e,t;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,e=this,(t=function(){e.provider&&e.provider.poll&&e.polls.forEach(function(t){t.data._id=e.id,e.id++,e.provider.poll(t.data,t.id)}),setTimeout(t,12e3)})()},s.prototype.send=function(e,t){e._id=this.id,t&&(g._callbacks[e._id]=t),e.args=e.args||[],this.id++,void 0!==this.provider?this.provider.send(e):(console.warn("provider is not set"),this.queued.push(e))},s.prototype.set=function(e){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=e,this.ready=!0},s.prototype.sendQueued=function(){for(var e=0;this.queued.length;e++)this.send(this.queued[e])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(e,t){this.provider&&this.provider.poll&&this.polls.push({data:e,id:t})},s.prototype.stopPolling=function(e){var t,n;for(t=this.polls.length;t--;)n=this.polls[t],n.id===e&&this.polls.splice(t,1)},g.provider=new s,g.setProvider=function(e){e.onmessage=r,g.provider.set(e),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(e,t){this.impl=t,this.callbacks=[];var n=this;this.promise=t.newFilter(e),this.promise.then(function(e){n.id=e,g.on(t.changed,e,n.trigger.bind(n)),g.provider.startPolling({call:t.changed,args:[e]},e)})},a.prototype.arrived=function(e){this.changed(e)},a.prototype.changed=function(e){var t=this;this.promise.then(function(){t.callbacks.push(e)})},a.prototype.trigger=function(e){for(var t=0;t Date: Thu, 13 Nov 2014 16:57:01 +0100 Subject: [PATCH 336/588] 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 337/588] 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 b1428555d10c5449e0f91f53f1dd0e8d1a1f9732 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 13 Nov 2014 18:29:31 +0100 Subject: [PATCH 338/588] added storageAt --- dist/ethereum.js | 2 +- dist/ethereum.js.map | 2 +- dist/ethereum.min.js | 2 +- lib/main.js | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index 2cbd42f81..32dfb596a 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -5,7 +5,7 @@ var AutoProvider=function(userOptions){var options,self,closeWithSuccess,ws;if(! },{}],3:[function(require,module,exports){ function formatJsonRpcObject(object){return{jsonrpc:"2.0",method:object.call,params:object.args,id:object._id}}function formatJsonRpcMessage(message){var object=JSON.parse(message);return{_id:object.id,data:object.result,error:object.error}}var HttpRpcProvider=function(host){this.handlers=[],this.host=host};HttpRpcProvider.prototype.sendRequest=function(payload,cb){var data=formatJsonRpcObject(payload),request=new XMLHttpRequest;request.open("POST",this.host,!0),request.send(JSON.stringify(data)),request.onreadystatechange=function(){4===request.readyState&&cb&&cb(request)}},HttpRpcProvider.prototype.send=function(payload){var self=this;this.sendRequest(payload,function(request){self.handlers.forEach(function(handler){handler.call(self,formatJsonRpcMessage(request.responseText))})})},HttpRpcProvider.prototype.poll=function(payload,id){var self=this;this.sendRequest(payload,function(request){var parsed=JSON.parse(request.responseText);!parsed.error&&(parsed.result instanceof Array?0!==parsed.result.length:parsed.result)&&self.handlers.forEach(function(handler){handler.call(self,{_event:payload.call,_id:id,data:parsed.result})})})},Object.defineProperty(HttpRpcProvider.prototype,"onmessage",{set:function(handler){this.handlers.push(handler)}}),module.exports=HttpRpcProvider; },{}],4:[function(require,module,exports){ -function flattenPromise(obj){return obj instanceof Promise?Promise.resolve(obj):obj instanceof Array?new Promise(function(resolve){var promises=obj.map(function(o){return flattenPromise(o)});return Promise.all(promises).then(function(res){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ir&&(t=e.charCodeAt(r),0!==t);r+=2)n+=String.fromCharCode(parseInt(e.substr(r,2),16));return n},toDecimal:function(e){return parseInt(e,16)},fromAscii:function(e,t){t=void 0===t?32:t;for(var n=this.toHex(e);n.length<2*t;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(e){return new a(e,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(e){return new a(e,i)}},on:function(e,t,n){return void 0===g._events[e]&&(g._events[e]={}),g._events[e][t]=n,this},off:function(e,t){return void 0!==g._events[e]&&delete g._events[e][t],this},trigger:function(e,t,n){var r,o=g._events[e];o&&o[t]&&(r=o[t])(n)}},m=g.eth;f(m,c()),v(m,u()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,d()),i={changed:"shh_changed"},f(i,p()),s=function(){var e,t;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,e=this,(t=function(){e.provider&&e.provider.poll&&e.polls.forEach(function(t){t.data._id=e.id,e.id++,e.provider.poll(t.data,t.id)}),setTimeout(t,12e3)})()},s.prototype.send=function(e,t){e._id=this.id,t&&(g._callbacks[e._id]=t),e.args=e.args||[],this.id++,void 0!==this.provider?this.provider.send(e):(console.warn("provider is not set"),this.queued.push(e))},s.prototype.set=function(e){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=e,this.ready=!0},s.prototype.sendQueued=function(){for(var e=0;this.queued.length;e++)this.send(this.queued[e])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(e,t){this.provider&&this.provider.poll&&this.polls.push({data:e,id:t})},s.prototype.stopPolling=function(e){var t,n;for(t=this.polls.length;t--;)n=this.polls[t],n.id===e&&this.polls.splice(t,1)},g.provider=new s,g.setProvider=function(e){e.onmessage=r,g.provider.set(e),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(e,t){this.impl=t,this.callbacks=[];var n=this;this.promise=t.newFilter(e),this.promise.then(function(e){n.id=e,g.on(t.changed,e,n.trigger.bind(n)),g.provider.startPolling({call:t.changed,args:[e]},e)})},a.prototype.arrived=function(e){this.changed(e)},a.prototype.changed=function(e){var t=this;this.promise.then(function(){t.callbacks.push(e)})},a.prototype.trigger=function(e){for(var t=0;tr&&(t=e.charCodeAt(r),0!==t);r+=2)n+=String.fromCharCode(parseInt(e.substr(r,2),16));return n},toDecimal:function(e){return parseInt(e,16)},fromAscii:function(e,t){t=void 0===t?32:t;for(var n=this.toHex(e);n.length<2*t;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(e){return new a(e,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(e){return new a(e,i)}},on:function(e,t,n){return void 0===g._events[e]&&(g._events[e]={}),g._events[e][t]=n,this},off:function(e,t){return void 0!==g._events[e]&&delete g._events[e][t],this},trigger:function(e,t,n){var r,o=g._events[e];o&&o[t]&&(r=o[t])(n)}},m=g.eth;f(m,c()),v(m,u()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,d()),i={changed:"shh_changed"},f(i,p()),s=function(){var e,t;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,e=this,(t=function(){e.provider&&e.provider.poll&&e.polls.forEach(function(t){t.data._id=e.id,e.id++,e.provider.poll(t.data,t.id)}),setTimeout(t,12e3)})()},s.prototype.send=function(e,t){e._id=this.id,t&&(g._callbacks[e._id]=t),e.args=e.args||[],this.id++,void 0!==this.provider?this.provider.send(e):(console.warn("provider is not set"),this.queued.push(e))},s.prototype.set=function(e){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=e,this.ready=!0},s.prototype.sendQueued=function(){for(var e=0;this.queued.length;e++)this.send(this.queued[e])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(e,t){this.provider&&this.provider.poll&&this.polls.push({data:e,id:t})},s.prototype.stopPolling=function(e){var t,n;for(t=this.polls.length;t--;)n=this.polls[t],n.id===e&&this.polls.splice(t,1)},g.provider=new s,g.setProvider=function(e){e.onmessage=r,g.provider.set(e),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(e,t){this.impl=t,this.callbacks=[];var n=this;this.promise=t.newFilter(e),this.promise.then(function(e){n.id=e,g.on(t.changed,e,n.trigger.bind(n)),g.provider.startPolling({call:t.changed,args:[e]},e)})},a.prototype.arrived=function(e){this.changed(e)},a.prototype.changed=function(e){var t=this;this.promise.then(function(){t.callbacks.push(e)})},a.prototype.trigger=function(e){for(var t=0;t Date: Thu, 13 Nov 2014 19:28:58 +0100 Subject: [PATCH 339/588] improved example --- example/index.html | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/example/index.html b/example/index.html index dc507ec9c..4847f68c0 100644 --- a/example/index.html +++ b/example/index.html @@ -4,34 +4,38 @@ - - + + -

std::name_reg

- - +

balance

+
- result: -
+
+
+
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 340/588] 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 341/588] 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 ea8db7a4aecb034c6a967ccd3b17c50f423cb77c Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 14 Nov 2014 13:11:47 +0100 Subject: [PATCH 342/588] improved contracts interface --- dist/ethereum.js | 10 +++--- dist/ethereum.js.map | 6 ++-- dist/ethereum.min.js | 2 +- example/contract.html | 75 +++++++++++++++++++++++++++++++++++++++++++ example/index.html | 2 +- index.js | 1 - index_qt.js | 1 - lib/abi.js | 48 +++++++++++++++++++++++---- lib/main.js | 42 ++++++++++++++++++++++-- 9 files changed, 166 insertions(+), 21 deletions(-) create mode 100644 example/contract.html diff --git a/dist/ethereum.js b/dist/ethereum.js index 32dfb596a..cdf76aff2 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -1,18 +1,18 @@ require=(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;oi&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}},eth=web3.eth;setupMethods(eth,ethMethods()),setupProperties(eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ir&&(t=e.charCodeAt(r),0!==t);r+=2)n+=String.fromCharCode(parseInt(e.substr(r,2),16));return n},toDecimal:function(e){return parseInt(e,16)},fromAscii:function(e,t){t=void 0===t?32:t;for(var n=this.toHex(e);n.length<2*t;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(e){return new a(e,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(e){return new a(e,i)}},on:function(e,t,n){return void 0===g._events[e]&&(g._events[e]={}),g._events[e][t]=n,this},off:function(e,t){return void 0!==g._events[e]&&delete g._events[e][t],this},trigger:function(e,t,n){var r,o=g._events[e];o&&o[t]&&(r=o[t])(n)}},m=g.eth;f(m,c()),v(m,u()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,d()),i={changed:"shh_changed"},f(i,p()),s=function(){var e,t;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,e=this,(t=function(){e.provider&&e.provider.poll&&e.polls.forEach(function(t){t.data._id=e.id,e.id++,e.provider.poll(t.data,t.id)}),setTimeout(t,12e3)})()},s.prototype.send=function(e,t){e._id=this.id,t&&(g._callbacks[e._id]=t),e.args=e.args||[],this.id++,void 0!==this.provider?this.provider.send(e):(console.warn("provider is not set"),this.queued.push(e))},s.prototype.set=function(e){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=e,this.ready=!0},s.prototype.sendQueued=function(){for(var e=0;this.queued.length;e++)this.send(this.queued[e])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(e,t){this.provider&&this.provider.poll&&this.polls.push({data:e,id:t})},s.prototype.stopPolling=function(e){var t,n;for(t=this.polls.length;t--;)n=this.polls[t],n.id===e&&this.polls.splice(t,1)},g.provider=new s,g.setProvider=function(e){e.onmessage=r,g.provider.set(e),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(e,t){this.impl=t,this.callbacks=[];var n=this;this.promise=t.newFilter(e),this.promise.then(function(e){n.id=e,g.on(t.changed,e,n.trigger.bind(n)),g.provider.startPolling({call:t.changed,args:[e]},e)})},a.prototype.arrived=function(e){this.changed(e)},a.prototype.changed=function(e){var t=this;this.promise.then(function(){t.callbacks.push(e)})},a.prototype.trigger=function(e){for(var t=0;tr&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},toDecimal:function(t){return parseInt(t,16)},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(t){return new a(t,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(t){return new a(t,i)}},on:function(t,e,n){return void 0===m._events[t]&&(m._events[t]={}),m._events[t][e]=n,this},off:function(t,e){return void 0!==m._events[t]&&delete m._events[t][e],this},trigger:function(t,e,n){var r,o=m._events[t];o&&o[e]&&(r=o[e])(n)}};v(m.eth,c()),g(m.eth,l()),v(m.db,h()),v(m.shh,p()),o={changed:"eth_changed"},v(o,d()),i={changed:"shh_changed"},v(i,f()),s=function(){var t,e;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,t=this,(e=function(){t.provider&&t.provider.poll&&t.polls.forEach(function(e){e.data._id=t.id,t.id++,t.provider.poll(e.data,e.id)}),setTimeout(e,12e3)})()},s.prototype.send=function(t,e){t._id=this.id,e&&(m._callbacks[t._id]=e),t.args=t.args||[],this.id++,void 0!==this.provider?this.provider.send(t):(console.warn("provider is not set"),this.queued.push(t))},s.prototype.set=function(t){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=t,this.ready=!0},s.prototype.sendQueued=function(){for(var t=0;this.queued.length;t++)this.send(this.queued[t])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(t,e){this.provider&&this.provider.poll&&this.polls.push({data:t,id:e})},s.prototype.stopPolling=function(t){var e,n;for(e=this.polls.length;e--;)n=this.polls[e],n.id===t&&this.polls.splice(e,1)},m.provider=new s,m.setProvider=function(t){t.onmessage=r,m.provider.set(t),m.provider.sendQueued()},m.haveProvider=function(){return!!m.provider.provider},a=function(t,e){this.impl=e,this.callbacks=[];var n=this;this.promise=e.newFilter(t),this.promise.then(function(t){n.id=t,m.on(e.changed,t,n.trigger.bind(n)),m.provider.startPolling({call:e.changed,args:[t]},t)})},a.prototype.arrived=function(t){this.changed(t)},a.prototype.changed=function(t){var e=this;this.promise.then(function(){e.callbacks.push(t)})},a.prototype.trigger=function(t){for(var e=0;e + + + + + + + + +

contract

+
+
+ +
+ +
+ + + diff --git a/example/index.html b/example/index.html index 4847f68c0..d0bf094ef 100644 --- a/example/index.html +++ b/example/index.html @@ -30,7 +30,7 @@ -

balance

+

coinbase balance

diff --git a/index.js b/index.js index 3197d0de6..4cf36348f 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,5 @@ web3.providers.WebSocketProvider = require('./lib/websocket'); web3.providers.HttpRpcProvider = require('./lib/httprpc'); web3.providers.QtProvider = require('./lib/qt'); web3.providers.AutoProvider = require('./lib/autoprovider'); -web3.contract = require('./lib/abi'); module.exports = web3; diff --git a/index_qt.js b/index_qt.js index 596695374..df66321b0 100644 --- a/index_qt.js +++ b/index_qt.js @@ -1,5 +1,4 @@ var web3 = require('./lib/main'); web3.providers.QtProvider = require('./lib/qt'); -web3.abi = require('./lib/abi'); module.exports = web3; diff --git a/lib/abi.js b/lib/abi.js index 1e3759918..3df0fe684 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -1,3 +1,24 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file abi.js + * @authors: + * Marek Kotewicz + * @date 2014 + */ var findIndex = function (array, callback) { var end = false; @@ -71,7 +92,8 @@ var toAbiInput = function (json, methodName, params) { for (var i = 0; i < method.inputs.length; i++) { var found = false; for (var j = 0; j < inputTypes.length && !found; j++) { - found = inputTypes[j](method.inputs[i].type, params[i]); + var val = parseInt(params[i]).toString(16); + found = inputTypes[j](method.inputs[i].type, val); } if (!found) { console.error('unsupported json type: ' + method.inputs[i].type); @@ -148,17 +170,31 @@ var fromAbiOutput = function (json, methodName, output) { return result; }; -var load = function (json) { - var contract = {}; +var inputParser = function (json) { + var parser = {}; json.forEach(function (method) { - contract[method.name] = function () { + parser[method.name] = function () { var params = Array.prototype.slice.call(arguments); return toAbiInput(json, method.name, params); }; }); - return contract; + return parser; }; -module.exports = load; +var outputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + parser[method.name] = function (output) { + return fromAbiOutput(json, method.name, output); + }; + }); + + return parser; +}; + +module.exports = { + inputParser: inputParser, + outputParser: outputParser +}; diff --git a/lib/main.js b/lib/main.js index e2caf6bc3..7990691de 100644 --- a/lib/main.js +++ b/lib/main.js @@ -22,6 +22,8 @@ * @date 2014 */ +var abi = require('./abi'); + function flattenPromise (obj) { if (obj instanceof Promise) { return Promise.resolve(obj); @@ -292,9 +294,8 @@ var web3 = { } }; -var eth = web3.eth; -setupMethods(eth, ethMethods()); -setupProperties(eth, ethProperties()); +setupMethods(web3.eth, ethMethods()); +setupProperties(web3.eth, ethProperties()); setupMethods(web3.db, dbMethods()); setupMethods(web3.shh, shhMethods()); @@ -454,5 +455,40 @@ function messageHandler(data) { } } +web3.contract = function (address, desc) { + var inputParser = abi.inputParser(desc); + var outputParser = abi.outputParser(desc); + + var contract = {}; + + desc.forEach(function (method) { + contract[method.name] = function () { + var params = Array.prototype.slice.call(arguments); + var parsed = inputParser[method.name].apply(null, params); + + var onSuccess = function (result) { + return outputParser[method.name](result); + }; + + return { + call: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.call(extra).then(onSuccess); + }, + transact: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.transact(extra).then(onSuccess); + } + }; + }; + }); + + return contract; +}; + module.exports = web3; From aa7fc792062ebdd52c97fac20e14ad6a46bf4886 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Fri, 14 Nov 2014 14:39:06 +0100 Subject: [PATCH 343/588] 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 344/588] 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 345/588] 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 6b8b1259e2e1a21c19198eb82582a7aafc29b12b Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 14 Nov 2014 17:08:29 +0100 Subject: [PATCH 346/588] Revert "Run JSHint on all code using Travis CI" --- .travis.yml | 7 ------- README.md | 2 -- httprpc.js | 8 ++++---- main.js | 26 +++++++++++++++----------- qt.js | 2 +- websocket.js | 2 +- 6 files changed, 21 insertions(+), 26 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 294073ce0..000000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: node_js -node_js: - - "0.11" -install: - - "npm install jshint" -script: - - "jshint *.js" diff --git a/README.md b/README.md index 7ff5cbb88..86e2969be 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Ethereum JavaScript API -[![Build Status](https://travis-ci.org/ethereum/ethereum.js.svg?branch=master)](https://travis-ci.org/ethereum/ethereum.js) - This is the Ethereum compatible JavaScript API using `Promise`s which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. diff --git a/httprpc.js b/httprpc.js index f7f870d9d..085b4693d 100644 --- a/httprpc.js +++ b/httprpc.js @@ -10,8 +10,8 @@ method: object.call, params: object.args, id: object._id - }; - } + } + }; function formatJsonRpcMessage(message) { var object = JSON.parse(message); @@ -20,7 +20,7 @@ _id: object.id, data: object.result }; - } + }; HttpRpcProvider.prototype.sendRequest = function (payload, cb) { var data = formatJsonRpcObject(payload); @@ -32,7 +32,7 @@ if (request.readyState === 4 && cb) { cb(request); } - }; + } }; HttpRpcProvider.prototype.send = function (payload) { diff --git a/main.js b/main.js index 320c4e1a2..1f609220b 100644 --- a/main.js +++ b/main.js @@ -1,6 +1,6 @@ (function(window) { function isPromise(o) { - return o instanceof Promise; + return o instanceof Promise } function flattenPromise (obj) { @@ -40,7 +40,7 @@ } return Promise.resolve(obj); - } + }; var ethMethods = function () { var blockCall = function (args) { @@ -171,7 +171,7 @@ }).catch(function (err) { console.error(err); }); - }; + } } Object.defineProperty(obj, property.name, proto); }); @@ -196,8 +196,8 @@ var str = ""; var i = 0, l = hex.length; for(; i < l; i+=2) { - var code = hex.charCodeAt(i); - if(code === 0) { + var code = hex.charCodeAt(i) + if(code == 0) { break; } @@ -216,18 +216,22 @@ var hex = this.toHex(str); while(hex.length < pad*2) hex += "00"; - return hex; + return hex }, eth: { + prototype: Object(), watch: function (params) { return new Filter(params, ethWatch); }, }, - db: {}, + db: { + prototype: Object() + }, shh: { + prototype: Object(), watch: function (params) { return new Filter(params, shhWatch); } @@ -239,7 +243,7 @@ } web3._events[event][id] = cb; - return this; + return this }, off: function(event, id) { @@ -247,7 +251,7 @@ delete web3._events[event][id]; } - return this; + return this }, trigger: function(event, id, data) { @@ -372,7 +376,7 @@ Filter.prototype.arrived = function(callback) { this.changed(callback); - }; + } Filter.prototype.changed = function(callback) { var self = this; @@ -412,7 +416,7 @@ if(data._id) { var cb = web3._callbacks[data._id]; if (cb) { - cb.call(this, data.data); + cb.call(this, data.data) delete web3._callbacks[data._id]; } } diff --git a/qt.js b/qt.js index 2f532f942..644c37737 100644 --- a/qt.js +++ b/qt.js @@ -7,7 +7,7 @@ self.handlers.forEach(function (handler) { handler.call(self, JSON.parse(message.data)); }); - }; + } }; QtProvider.prototype.send = function(payload) { diff --git a/websocket.js b/websocket.js index 63855ade1..732a086f2 100644 --- a/websocket.js +++ b/websocket.js @@ -11,7 +11,7 @@ var self = this; this.ws.onmessage = function(event) { for(var i = 0; i < self.handlers.length; i++) { - self.handlers[i].call(self, JSON.parse(event.data), event); + self.handlers[i].call(self, JSON.parse(event.data), event) } }; From 08f2dde45aa6fa977f49bdbdc30543b6c0e894a0 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 14 Nov 2014 14:00:19 -0500 Subject: [PATCH 347/588] Enable JSHint linting --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 148e4e797..fafacbd5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,5 +4,8 @@ node_js: - "0.10" before_script: - npm install + - npm install jshint +script: + - "jshint *.js lib" after_script: - - npm run-script gulp \ No newline at end of file + - npm run-script gulp From 27a8799e4809325bb2d7dbc7480a3de0f9d684d6 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 17 Nov 2014 15:46:46 +0100 Subject: [PATCH 348/588] added eth_serpent, contract separated to another file --- dist/ethereum.js | 14 +++++----- dist/ethereum.js.map | 8 +++--- dist/ethereum.min.js | 2 +- index.js | 1 + index_qt.js | 1 + lib/contract.js | 63 ++++++++++++++++++++++++++++++++++++++++++++ lib/main.js | 40 ++-------------------------- 7 files changed, 81 insertions(+), 48 deletions(-) create mode 100644 lib/contract.js diff --git a/dist/ethereum.js b/dist/ethereum.js index cdf76aff2..f98e67ea3 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -3,16 +3,18 @@ var findIndex=function(array,callback){for(var end=!1,i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ir&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},toDecimal:function(t){return parseInt(t,16)},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(t){return new a(t,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(t){return new a(t,i)}},on:function(t,e,n){return void 0===m._events[t]&&(m._events[t]={}),m._events[t][e]=n,this},off:function(t,e){return void 0!==m._events[t]&&delete m._events[t][e],this},trigger:function(t,e,n){var r,o=m._events[t];o&&o[e]&&(r=o[e])(n)}};v(m.eth,c()),g(m.eth,l()),v(m.db,h()),v(m.shh,p()),o={changed:"eth_changed"},v(o,d()),i={changed:"shh_changed"},v(i,f()),s=function(){var t,e;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,t=this,(e=function(){t.provider&&t.provider.poll&&t.polls.forEach(function(e){e.data._id=t.id,t.id++,t.provider.poll(e.data,e.id)}),setTimeout(e,12e3)})()},s.prototype.send=function(t,e){t._id=this.id,e&&(m._callbacks[t._id]=e),t.args=t.args||[],this.id++,void 0!==this.provider?this.provider.send(t):(console.warn("provider is not set"),this.queued.push(t))},s.prototype.set=function(t){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=t,this.ready=!0},s.prototype.sendQueued=function(){for(var t=0;this.queued.length;t++)this.send(this.queued[t])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(t,e){this.provider&&this.provider.poll&&this.polls.push({data:t,id:e})},s.prototype.stopPolling=function(t){var e,n;for(e=this.polls.length;e--;)n=this.polls[e],n.id===t&&this.polls.splice(e,1)},m.provider=new s,m.setProvider=function(t){t.onmessage=r,m.provider.set(t),m.provider.sendQueued()},m.haveProvider=function(){return!!m.provider.provider},a=function(t,e){this.impl=e,this.callbacks=[];var n=this;this.promise=e.newFilter(t),this.promise.then(function(t){n.id=t,m.on(e.changed,t,n.trigger.bind(n)),m.provider.startPolling({call:e.changed,args:[t]},t)})},a.prototype.arrived=function(t){this.changed(t)},a.prototype.changed=function(t){var e=this;this.promise.then(function(){e.callbacks.push(t)})},a.prototype.trigger=function(t){for(var e=0;er&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},toDecimal:function(t){return parseInt(t,16)},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(t){return new a(t,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(t){return new a(t,i)}},on:function(t,e,n){return void 0===g._events[t]&&(g._events[t]={}),g._events[t][e]=n,this},off:function(t,e){return void 0!==g._events[t]&&delete g._events[t][e],this},trigger:function(t,e,n){var r,o=g._events[t];o&&o[e]&&(r=o[e])(n)}};f(g.eth,u()),v(g.eth,c()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,p()),i={changed:"shh_changed"},f(i,d()),s=function(){var t,e;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,t=this,(e=function(){t.provider&&t.provider.poll&&t.polls.forEach(function(e){e.data._id=t.id,t.id++,t.provider.poll(e.data,e.id)}),setTimeout(e,12e3)})()},s.prototype.send=function(t,e){t._id=this.id,e&&(g._callbacks[t._id]=e),t.args=t.args||[],this.id++,void 0!==this.provider?this.provider.send(t):(console.warn("provider is not set"),this.queued.push(t))},s.prototype.set=function(t){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=t,this.ready=!0},s.prototype.sendQueued=function(){for(var t=0;this.queued.length;t++)this.send(this.queued[t])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(t,e){this.provider&&this.provider.poll&&this.polls.push({data:t,id:e})},s.prototype.stopPolling=function(t){var e,n;for(e=this.polls.length;e--;)n=this.polls[e],n.id===t&&this.polls.splice(e,1)},g.provider=new s,g.setProvider=function(t){t.onmessage=r,g.provider.set(t),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(t,e){this.impl=e,this.callbacks=[];var n=this;this.promise=e.newFilter(t),this.promise.then(function(t){n.id=t,g.on(e.changed,t,n.trigger.bind(n)),g.provider.startPolling({call:e.changed,args:[t]},t)})},a.prototype.arrived=function(t){this.changed(t)},a.prototype.changed=function(t){var e=this;this.promise.then(function(){e.callbacks.push(t)})},a.prototype.trigger=function(t){for(var e=0;e. +*/ +/** @file contract.js + * @authors: + * Marek Kotewicz + * @date 2014 + */ + +if (process.env.NODE_ENV !== 'build') { + var web3 = require('./web3'); // jshint ignore:line +} +var abi = require('./abi'); + +var contract = function (address, desc) { + var inputParser = abi.inputParser(desc); + var outputParser = abi.outputParser(desc); + + var contract = {}; + + desc.forEach(function (method) { + contract[method.name] = function () { + var params = Array.prototype.slice.call(arguments); + var parsed = inputParser[method.name].apply(null, params); + + var onSuccess = function (result) { + return outputParser[method.name](result); + }; + + return { + call: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.call(extra).then(onSuccess); + }, + transact: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.transact(extra).then(onSuccess); + } + }; + }; + }); + + return contract; +}; + +module.exports = contract; diff --git a/lib/main.js b/lib/main.js index 7990691de..a8848674b 100644 --- a/lib/main.js +++ b/lib/main.js @@ -22,8 +22,6 @@ * @date 2014 */ -var abi = require('./abi'); - function flattenPromise (obj) { if (obj instanceof Promise) { return Promise.resolve(obj); @@ -89,7 +87,8 @@ var ethMethods = function () { { name: 'uncle', call: uncleCall }, { name: 'compilers', call: 'eth_compilers' }, { name: 'lll', call: 'eth_lll' }, - { name: 'solidity', call: 'eth_solidity' } + { name: 'solidity', call: 'eth_solidity' }, + { name: 'serpent', call: 'eth_serpent' } ]; return methods; }; @@ -455,40 +454,5 @@ function messageHandler(data) { } } -web3.contract = function (address, desc) { - var inputParser = abi.inputParser(desc); - var outputParser = abi.outputParser(desc); - - var contract = {}; - - desc.forEach(function (method) { - contract[method.name] = function () { - var params = Array.prototype.slice.call(arguments); - var parsed = inputParser[method.name].apply(null, params); - - var onSuccess = function (result) { - return outputParser[method.name](result); - }; - - return { - call: function (extra) { - extra = extra || {}; - extra.to = address; - extra.data = parsed; - return web3.eth.call(extra).then(onSuccess); - }, - transact: function (extra) { - extra = extra || {}; - extra.to = address; - extra.data = parsed; - return web3.eth.transact(extra).then(onSuccess); - } - }; - }; - }); - - return contract; -}; - module.exports = web3; 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 349/588] 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 1a9624af5146a790f6bc8c5167bf5a6c006a6644 Mon Sep 17 00:00:00 2001 From: Marian Oancea Date: Tue, 18 Nov 2014 09:11:16 +0200 Subject: [PATCH 350/588] Fixed require web3 bug Fixed error "Cannot find module './web3'" in autoprovider.js --- lib/autoprovider.js | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/autoprovider.js b/lib/autoprovider.js index 470861686..735f56349 100644 --- a/lib/autoprovider.js +++ b/lib/autoprovider.js @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file websocket.js +/** @file autoprovider.js * @authors: * Marek Kotewicz * Marian Oancea @@ -28,7 +28,7 @@ */ if (process.env.NODE_ENV !== 'build') { var WebSocket = require('ws'); // jshint ignore:line - var web3 = require('./web3'); // jshint ignore:line + var web3 = require('./main.js'); // jshint ignore:line } var AutoProvider = function (userOptions) { @@ -44,13 +44,13 @@ var AutoProvider = function (userOptions) { this.provider = new web3.providers.QtProvider(); return; } - + userOptions = userOptions || {}; var options = { httprpc: userOptions.httprpc || 'http://localhost:8080', websockets: userOptions.websockets || 'ws://localhost:40404/eth' }; - + var self = this; var closeWithSuccess = function (success) { ws.close(); @@ -71,7 +71,7 @@ var AutoProvider = function (userOptions) { var ws = new WebSocket(options.websockets); ws.onopen = function() { - closeWithSuccess(true); + closeWithSuccess(true); }; ws.onerror = function() { diff --git a/package.json b/package.json index 38465e7bd..868a76b1d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ethereum.js", "namespace": "ethereum", - "version": "0.0.3", + "version": "0.0.4", "description": "Ethereum Compatible JavaScript API", "main": "./index.js", "directories": { From 0d526d66b76fbf7044ce80c64d1dc296308a8786 Mon Sep 17 00:00:00 2001 From: Marian Oancea Date: Tue, 18 Nov 2014 09:23:14 +0200 Subject: [PATCH 351/588] Updated version Changed version from npm in order to publish the update --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 868a76b1d..24141ea2e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ethereum.js", "namespace": "ethereum", - "version": "0.0.4", + "version": "0.0.5", "description": "Ethereum Compatible JavaScript API", "main": "./index.js", "directories": { From b402484e41c9579f33d70f8f8b191ab0074dad62 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 18 Nov 2014 13:59:17 +0100 Subject: [PATCH 352/588] common changes --- dist/ethereum.js | 2 +- dist/ethereum.js.map | 2 +- dist/ethereum.min.js | 2 +- lib/main.js | 9 +++++++-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index f98e67ea3..b64c15b9e 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -7,7 +7,7 @@ var abi,contract;abi=require("./abi"),contract=function(address,desc){var inputP },{"./abi":1}],4:[function(require,module,exports){ function formatJsonRpcObject(object){return{jsonrpc:"2.0",method:object.call,params:object.args,id:object._id}}function formatJsonRpcMessage(message){var object=JSON.parse(message);return{_id:object.id,data:object.result,error:object.error}}var HttpRpcProvider=function(host){this.handlers=[],this.host=host};HttpRpcProvider.prototype.sendRequest=function(payload,cb){var data=formatJsonRpcObject(payload),request=new XMLHttpRequest;request.open("POST",this.host,!0),request.send(JSON.stringify(data)),request.onreadystatechange=function(){4===request.readyState&&cb&&cb(request)}},HttpRpcProvider.prototype.send=function(payload){var self=this;this.sendRequest(payload,function(request){self.handlers.forEach(function(handler){handler.call(self,formatJsonRpcMessage(request.responseText))})})},HttpRpcProvider.prototype.poll=function(payload,id){var self=this;this.sendRequest(payload,function(request){var parsed=JSON.parse(request.responseText);!parsed.error&&(parsed.result instanceof Array?0!==parsed.result.length:parsed.result)&&self.handlers.forEach(function(handler){handler.call(self,{_event:payload.call,_id:id,data:parsed.result})})})},Object.defineProperty(HttpRpcProvider.prototype,"onmessage",{set:function(handler){this.handlers.push(handler)}}),module.exports=HttpRpcProvider; },{}],5:[function(require,module,exports){ -function flattenPromise(obj){return obj instanceof Promise?Promise.resolve(obj):obj instanceof Array?new Promise(function(resolve){var promises=obj.map(function(o){return flattenPromise(o)});return Promise.all(promises).then(function(res){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ir&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},toDecimal:function(t){return parseInt(t,16)},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(t){return new a(t,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(t){return new a(t,i)}},on:function(t,e,n){return void 0===g._events[t]&&(g._events[t]={}),g._events[t][e]=n,this},off:function(t,e){return void 0!==g._events[t]&&delete g._events[t][e],this},trigger:function(t,e,n){var r,o=g._events[t];o&&o[e]&&(r=o[e])(n)}};f(g.eth,u()),v(g.eth,c()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,p()),i={changed:"shh_changed"},f(i,d()),s=function(){var t,e;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,t=this,(e=function(){t.provider&&t.provider.poll&&t.polls.forEach(function(e){e.data._id=t.id,t.id++,t.provider.poll(e.data,e.id)}),setTimeout(e,12e3)})()},s.prototype.send=function(t,e){t._id=this.id,e&&(g._callbacks[t._id]=e),t.args=t.args||[],this.id++,void 0!==this.provider?this.provider.send(t):(console.warn("provider is not set"),this.queued.push(t))},s.prototype.set=function(t){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=t,this.ready=!0},s.prototype.sendQueued=function(){for(var t=0;this.queued.length;t++)this.send(this.queued[t])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(t,e){this.provider&&this.provider.poll&&this.polls.push({data:t,id:e})},s.prototype.stopPolling=function(t){var e,n;for(e=this.polls.length;e--;)n=this.polls[e],n.id===t&&this.polls.splice(e,1)},g.provider=new s,g.setProvider=function(t){t.onmessage=r,g.provider.set(t),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(t,e){this.impl=e,this.callbacks=[];var n=this;this.promise=e.newFilter(t),this.promise.then(function(t){n.id=t,g.on(e.changed,t,n.trigger.bind(n)),g.provider.startPolling({call:e.changed,args:[t]},t)})},a.prototype.arrived=function(t){this.changed(t)},a.prototype.changed=function(t){var e=this;this.promise.then(function(){e.callbacks.push(t)})},a.prototype.trigger=function(t){for(var e=0;er&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},toDecimal:function(t){return parseInt(t,16)},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(t){return new a(t,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(t){return new a(t,i)}},on:function(t,e,n){return void 0===g._events[t]&&(g._events[t]={}),g._events[t][e]=n,this},off:function(t,e){return void 0!==g._events[t]&&delete g._events[t][e],this},trigger:function(t,e,n){var r,o=g._events[t];o&&o[e]&&(r=o[e])(n)}};f(g.eth,u()),v(g.eth,c()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,p()),i={changed:"shh_changed"},f(i,d()),s=function(){var t,e;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,t=this,(e=function(){t.provider&&t.provider.poll&&t.polls.forEach(function(e){e.data._id=t.id,t.id++,t.provider.poll(e.data,e.id)}),setTimeout(e,12e3)})()},s.prototype.send=function(t,e){t._id=this.id,e&&(g._callbacks[t._id]=e),t.args=t.args||[],this.id++,void 0!==this.provider?this.provider.send(t):(console.warn("provider is not set"),this.queued.push(t))},s.prototype.set=function(t){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=t,this.ready=!0},s.prototype.sendQueued=function(){for(var t=0;this.queued.length;t++)this.send(this.queued[t])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(t,e){this.provider&&this.provider.poll&&this.polls.push({data:t,id:e})},s.prototype.stopPolling=function(t){var e,n;for(e=this.polls.length;e--;)n=this.polls[e],n.id===t&&this.polls.splice(e,1)},g.provider=new s,g.setProvider=function(t){t.onmessage=r,g.provider.set(t),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(t,e){this.impl=e,this.callbacks=[];var n=this;this.promise=e.newFilter(t),this.promise.then(function(t){n.id=t,g.on(e.changed,t,n.trigger.bind(n)),g.provider.startPolling({call:e.changed,args:[t]},t)})},a.prototype.arrived=function(t){this.changed(t)},a.prototype.changed=function(t){var e=this;this.promise.then(function(){e.callbacks.push(t)})},a.prototype.trigger=function(t){for(var e=0;e Date: Mon, 24 Nov 2014 22:42:50 +0100 Subject: [PATCH 353/588] 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 354/588] 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 355/588] 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 356/588] 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 357/588] 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 358/588] 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 359/588] 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 360/588] 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 361/588] 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 362/588] 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 363/588] 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 364/588] 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 365/588] 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 366/588] 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 367/588] 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 368/588] 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 369/588] 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 370/588] 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 371/588] 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 372/588] 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 373/588] 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 374/588] 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 375/588] 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 376/588] 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 377/588] 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 378/588] 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 379/588] 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 380/588] 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 381/588] 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 382/588] 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 383/588] 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 384/588] 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 385/588] 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 386/588] 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 387/588] 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 388/588] 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 389/588] 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 390/588] 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 391/588] 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 392/588] 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 393/588] 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 394/588] 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 395/588] 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 396/588] 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 397/588] 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 398/588] 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 399/588] 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 400/588] 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 401/588] 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 402/588] 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 403/588] 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 404/588] 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 405/588] 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 406/588] 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 407/588] 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 408/588] 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 409/588] 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 410/588] 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 411/588] 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 412/588] 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 413/588] 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 414/588] 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 415/588] 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 416/588] 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 417/588] 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 418/588] 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 419/588] 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 420/588] 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 421/588] 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 422/588] 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 423/588] 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 424/588] 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 425/588] 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 426/588] 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 427/588] 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 428/588] 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 429/588] 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 430/588] 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 123098ce79562be0d4ce87e15bcebe6a970f1ff6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 22 Dec 2014 01:13:49 +0100 Subject: [PATCH 431/588] Lots of fixes. --- lib/abi.js | 56 ++++++++++++++++++++++++++-------------- lib/autoprovider.js | 7 +++-- lib/contract.js | 8 +++--- lib/httprpc.js | 6 +++-- lib/main.js | 63 +++++++++++++++++++++++++++++++++------------ lib/websocket.js | 6 +++-- 6 files changed, 102 insertions(+), 44 deletions(-) diff --git a/lib/abi.js b/lib/abi.js index 3df0fe684..2cff503d3 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -17,9 +17,19 @@ /** @file abi.js * @authors: * Marek Kotewicz + * Gav Wood * @date 2014 */ +// TODO: make these be actually accurate instead of falling back onto JS's doubles. +var hexToDec = function (hex) { + return parseInt(hex, 16).toString(); +}; + +var decToHex = function (dec) { + return parseInt(dec).toString(16); +}; + var findIndex = function (array, callback) { var end = false; var i = 0; @@ -35,8 +45,8 @@ var findMethodIndex = function (json, methodName) { }); }; -var padLeft = function (number, n) { - return (new Array(n * 2 - number.toString().length + 1)).join("0") + number; +var padLeft = function (string, chars) { + return Array(chars - string.length + 1).join("0") + string; }; var setupInputTypes = function () { @@ -48,27 +58,34 @@ var setupInputTypes = function () { } var padding = parseInt(type.slice(expected.length)) / 8; - return padLeft(value, padding); + if (typeof value === "number") + value = value.toString(16); + else if (value.indexOf('0x') === 0) + value = value.substr(2); + else + value = (+value).toString(16); + return padLeft(value, padding * 2); }; }; var namedType = function (name, padding, formatter) { return function (type, value) { if (type !== name) { - return false; + return false; } - return padLeft(formatter ? value : formatter(value), padding); + return padLeft(formatter ? formatter(value) : value, padding * 2); }; }; var formatBool = function (value) { - return value ? '1' : '0'; + return value ? '0x1' : '0x0'; }; return [ prefixedType('uint'), prefixedType('int'), + prefixedType('hash'), namedType('address', 20), namedType('bool', 1, formatBool), ]; @@ -79,21 +96,18 @@ var inputTypes = setupInputTypes(); var toAbiInput = function (json, methodName, params) { var bytes = ""; var index = findMethodIndex(json, methodName); - + if (index === -1) { return; } - // it needs to be checked in WebThreeStubServer - // something wrong might be with this additional zero - bytes = bytes + index + 'x' + '0'; + bytes = "0x" + padLeft(index.toString(16), 2); var method = json[index]; - + for (var i = 0; i < method.inputs.length; i++) { var found = false; for (var j = 0; j < inputTypes.length && !found; j++) { - var val = parseInt(params[i]).toString(16); - found = inputTypes[j](method.inputs[i].type, val); + found = inputTypes[j](method.inputs[i].type, params[i]); } if (!found) { console.error('unsupported json type: ' + method.inputs[i].type); @@ -110,7 +124,7 @@ var setupOutputTypes = function () { if (type.indexOf(expected) !== 0) { return -1; } - + var padding = parseInt(type.slice(expected.length)) / 8; return padding * 2; }; @@ -118,12 +132,16 @@ var setupOutputTypes = function () { var namedType = function (name, padding) { return function (type) { - return name === type ? padding * 2: -1; + return name === type ? padding * 2 : -1; }; }; var formatInt = function (value) { - return parseInt(value, 16); + return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value); + }; + + var formatHash = function (value) { + return "0x" + value; }; var formatBool = function (value) { @@ -133,6 +151,7 @@ var setupOutputTypes = function () { return [ { padding: prefixedType('uint'), format: formatInt }, { padding: prefixedType('int'), format: formatInt }, + { padding: prefixedType('hash'), format: formatHash }, { padding: namedType('address', 20) }, { padding: namedType('bool', 1), format: formatBool } ]; @@ -146,7 +165,7 @@ var fromAbiOutput = function (json, methodName, output) { if (index === -1) { return; } - + output = output.slice(2); var result = []; @@ -163,7 +182,7 @@ var fromAbiOutput = function (json, methodName, output) { } var res = output.slice(0, padding); var formatter = outputTypes[j - 1].format; - result.push(formatter ? formatter(res): res); + result.push(formatter ? formatter(res) : ("0x" + res)); output = output.slice(padding); } @@ -197,4 +216,3 @@ module.exports = { inputParser: inputParser, outputParser: outputParser }; - diff --git a/lib/autoprovider.js b/lib/autoprovider.js index 735f56349..bfbc3ab6e 100644 --- a/lib/autoprovider.js +++ b/lib/autoprovider.js @@ -26,10 +26,13 @@ * if not tries to connect over websockets * if it fails, it uses HttpRpcProvider */ -if (process.env.NODE_ENV !== 'build') { + +// TODO: work out which of the following two lines it is supposed to be... +//if (process.env.NODE_ENV !== 'build') { +if ("build" !== 'build') {/* var WebSocket = require('ws'); // jshint ignore:line var web3 = require('./main.js'); // jshint ignore:line -} +*/} var AutoProvider = function (userOptions) { if (web3.haveProvider()) { diff --git a/lib/contract.js b/lib/contract.js index 10ceaf869..17b077484 100644 --- a/lib/contract.js +++ b/lib/contract.js @@ -20,9 +20,11 @@ * @date 2014 */ -if (process.env.NODE_ENV !== 'build') { +// TODO: work out which of the following two lines it is supposed to be... +//if (process.env.NODE_ENV !== 'build') { +if ("build" !== 'build') {/* var web3 = require('./web3'); // jshint ignore:line -} +*/} var abi = require('./abi'); var contract = function (address, desc) { @@ -56,7 +58,7 @@ var contract = function (address, desc) { }; }; }); - + return contract; }; diff --git a/lib/httprpc.js b/lib/httprpc.js index 8141a6bae..ee6b5c307 100644 --- a/lib/httprpc.js +++ b/lib/httprpc.js @@ -21,9 +21,11 @@ * @date 2014 */ -if (process.env.NODE_ENV !== "build") { +// TODO: work out which of the following two lines it is supposed to be... +//if (process.env.NODE_ENV !== 'build') { +if ("build" !== "build") {/* var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line -} +*/} var HttpRpcProvider = function (host) { this.handlers = []; diff --git a/lib/main.js b/lib/main.js index 697cbdbc3..59c60cfa8 100644 --- a/lib/main.js +++ b/lib/main.js @@ -19,6 +19,7 @@ * Jeffrey Wilcke * Marek Kotewicz * Marian Oancea + * Gav Wood * @date 2014 */ @@ -61,17 +62,23 @@ function flattenPromise (obj) { return Promise.resolve(obj); } +var web3Methods = function () { + return [ + { name: 'sha3', call: 'web3_sha3' } + ]; +}; + var ethMethods = function () { var blockCall = function (args) { return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; }; var transactionCall = function (args) { - return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; }; var uncleCall = function (args) { - return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; }; var methods = [ @@ -205,19 +212,20 @@ var setupProperties = function (obj, properties) { }); }; +// TODO: import from a dependency, don't duplicate. +var hexToDec = function (hex) { + return parseInt(hex, 16).toString(); +}; + +var decToHex = function (dec) { + return parseInt(dec).toString(16); +}; + + var web3 = { _callbacks: {}, _events: {}, providers: {}, - toHex: function(str) { - var hex = ""; - for(var i = 0; i < str.length; i++) { - var n = str.charCodeAt(i).toString(16); - hex += n.length < 2 ? '0' + n : n; - } - - return hex; - }, toAscii: function(hex) { // Find termination @@ -237,10 +245,6 @@ var web3 = { return str; }, - toDecimal: function (val) { - return parseInt(val, 16); - }, - fromAscii: function(str, pad) { pad = pad === undefined ? 32 : pad; var hex = this.toHex(str); @@ -249,6 +253,33 @@ var web3 = { return "0x" + hex; }, + toDecimal: function (val) { + return hexToDec(val.substring(2)); + }, + + fromDecimal: function (val) { + return "0x" + decToHex(val); + }, + + toEth: function(str) { + var val = typeof str === "string" ? str.indexOf('0x') == 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; + var unit = 0; + var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ]; + while (val > 3000 && unit < units.length - 1) + { + val /= 1000; + unit++; + } + var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); + while (true) { + var o = s; + s = s.replace(/(\d)(\d\d\d[\.\,])/, function($0, $1, $2) { return $1 + ',' + $2; }); + if (o == s) + break; + } + return s + ' ' + units[unit]; + }, + eth: { prototype: Object(), // jshint ignore:line watch: function (params) { @@ -294,6 +325,7 @@ var web3 = { } }; +setupMethods(web3, web3Methods()); setupMethods(web3.eth, ethMethods()); setupProperties(web3.eth, ethProperties()); setupMethods(web3.db, dbMethods()); @@ -460,4 +492,3 @@ function messageHandler(data) { } module.exports = web3; - diff --git a/lib/websocket.js b/lib/websocket.js index 0c7563062..24a072531 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -22,9 +22,11 @@ * @date 2014 */ -if (process.env.NODE_ENV !== "build") { +// TODO: work out which of the following two lines it is supposed to be... +//if (process.env.NODE_ENV !== 'build') { +if ("build" !== "build") {/* var WebSocket = require('ws'); // jshint ignore:line -} +*/} var WebSocketProvider = function(host) { // onmessage handlers 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 432/588] 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 433/588] 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 434/588] 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 435/588] 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 436/588] 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 437/588] 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 438/588] 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 439/588] 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 440/588] 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 441/588] 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 442/588] 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 443/588] 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 444/588] 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 445/588] 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 446/588] 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 447/588] 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 448/588] 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 1954b878191e08db04188f0934b15ebe8c2c5a84 Mon Sep 17 00:00:00 2001 From: caktux Date: Tue, 30 Dec 2014 11:59:33 -0500 Subject: [PATCH 449/588] bring back toHex --- lib/main.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/main.js b/lib/main.js index 59c60cfa8..b6601132d 100644 --- a/lib/main.js +++ b/lib/main.js @@ -227,6 +227,16 @@ var web3 = { _events: {}, providers: {}, + toHex: function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; + }, + toAscii: function(hex) { // Find termination var str = ""; 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 450/588] 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 451/588] 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 452/588] 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 453/588] 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 454/588] 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 455/588] 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 456/588] 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 457/588] 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 458/588] 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 459/588] 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 460/588] 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 461/588] 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 462/588] 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 463/588] 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 af9242f4cc382a61bea9142ddbd0cec2e1edf08a Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 6 Jan 2015 13:26:51 +0100 Subject: [PATCH 464/588] fixed gulp build --- dist/ethereum.js | 6 +++--- dist/ethereum.js.map | 4 ++-- dist/ethereum.min.js | 2 +- lib/abi.js | 2 +- lib/autoprovider.js | 6 ++---- lib/contract.js | 7 +++---- lib/httprpc.js | 6 ++---- lib/main.js | 10 +++++++--- lib/websocket.js | 6 ++---- 9 files changed, 23 insertions(+), 26 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index b64c15b9e..bce62075b 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -1,5 +1,5 @@ require=(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;oi&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:"eth_changed"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:"shh_changed"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn("provider is not set"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},toDecimal:function(val){return hexToDec(val.substring(2))},fromDecimal:function(val){return"0x"+decToHex(val)},toEth:function(str){for(var s,replaceFunction,o,val="string"==typeof str?0===str.indexOf("0x")?parseInt(str.substr(2),16):parseInt(str):str,unit=0,units=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];val>3e3&&uniti&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},toDecimal:function(val){return parseInt(val,16)},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},eth:{prototype:Object(),watch:function(params){return new Filter(params,ethWatch)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(params){return new Filter(params,shhWatch)}},on:function(event,id,cb){return void 0===web3._events[event]&&(web3._events[event]={}),web3._events[event][id]=cb,this},off:function(event,id){return void 0!==web3._events[event]&&delete web3._events[event][id],this},trigger:function(event,id,data){var cb,callbacks=web3._events[event];callbacks&&callbacks[id]&&(cb=callbacks[id])(data)}};setupMethods(web3.eth,ethMethods()),setupProperties(web3.eth,ethProperties()),setupMethods(web3.db,dbMethods()),setupMethods(web3.shh,shhMethods()),ethWatch={changed:\"eth_changed\"},setupMethods(ethWatch,ethWatchMethods()),shhWatch={changed:\"shh_changed\"},setupMethods(shhWatch,shhWatchMethods()),ProviderManager=function(){var self,poll;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,self=this,(poll=function(){self.provider&&self.provider.poll&&self.polls.forEach(function(data){data.data._id=self.id,self.id++,self.provider.poll(data.data,data.id)}),setTimeout(poll,12e3)})()},ProviderManager.prototype.send=function(data,cb){data._id=this.id,cb&&(web3._callbacks[data._id]=cb),data.args=data.args||[],this.id++,void 0!==this.provider?this.provider.send(data):(console.warn(\"provider is not set\"),this.queued.push(data))},ProviderManager.prototype.set=function(provider){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=provider,this.ready=!0},ProviderManager.prototype.sendQueued=function(){for(var i=0;this.queued.length;i++)this.send(this.queued[i])},ProviderManager.prototype.installed=function(){return void 0!==this.provider},ProviderManager.prototype.startPolling=function(data,pollId){this.provider&&this.provider.poll&&this.polls.push({data:data,id:pollId})},ProviderManager.prototype.stopPolling=function(pollId){var i,poll;for(i=this.polls.length;i--;)poll=this.polls[i],poll.id===pollId&&this.polls.splice(i,1)},web3.provider=new ProviderManager,web3.setProvider=function(provider){provider.onmessage=messageHandler,web3.provider.set(provider),web3.provider.sendQueued()},web3.haveProvider=function(){return!!web3.provider.provider},Filter=function(options,impl){this.impl=impl,this.callbacks=[];var self=this;this.promise=impl.newFilter(options),this.promise.then(function(id){self.id=id,web3.on(impl.changed,id,self.trigger.bind(self)),web3.provider.startPolling({call:impl.changed,args:[id]},id)})},Filter.prototype.arrived=function(callback){this.changed(callback)},Filter.prototype.changed=function(callback){var self=this;this.promise.then(function(id){self.callbacks.push(callback)})},Filter.prototype.trigger=function(messages){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},toDecimal:function(val){return hexToDec(val.substring(2))},fromDecimal:function(val){return\"0x\"+decToHex(val)},toEth:function(str){for(var s,replaceFunction,o,val=\"string\"==typeof str?0===str.indexOf(\"0x\")?parseInt(str.substr(2),16):parseInt(str):str,unit=0,units=[\"wei\",\"Kwei\",\"Mwei\",\"Gwei\",\"szabo\",\"finney\",\"ether\",\"grand\",\"Mether\",\"Gether\",\"Tether\",\"Pether\",\"Eether\",\"Zether\",\"Yether\",\"Nether\",\"Dether\",\"Vether\",\"Uether\"];val>3e3&&unitr&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},toDecimal:function(t){return parseInt(t,16)},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},eth:{prototype:Object(),watch:function(t){return new a(t,o)}},db:{prototype:Object()},shh:{prototype:Object(),watch:function(t){return new a(t,i)}},on:function(t,e,n){return void 0===g._events[t]&&(g._events[t]={}),g._events[t][e]=n,this},off:function(t,e){return void 0!==g._events[t]&&delete g._events[t][e],this},trigger:function(t,e,n){var r,o=g._events[t];o&&o[e]&&(r=o[e])(n)}};f(g.eth,u()),v(g.eth,c()),f(g.db,l()),f(g.shh,h()),o={changed:"eth_changed"},f(o,p()),i={changed:"shh_changed"},f(i,d()),s=function(){var t,e;this.queued=[],this.polls=[],this.ready=!1,this.provider=void 0,this.id=1,t=this,(e=function(){t.provider&&t.provider.poll&&t.polls.forEach(function(e){e.data._id=t.id,t.id++,t.provider.poll(e.data,e.id)}),setTimeout(e,12e3)})()},s.prototype.send=function(t,e){t._id=this.id,e&&(g._callbacks[t._id]=e),t.args=t.args||[],this.id++,void 0!==this.provider?this.provider.send(t):(console.warn("provider is not set"),this.queued.push(t))},s.prototype.set=function(t){void 0!==this.provider&&void 0!==this.provider.unload&&this.provider.unload(),this.provider=t,this.ready=!0},s.prototype.sendQueued=function(){for(var t=0;this.queued.length;t++)this.send(this.queued[t])},s.prototype.installed=function(){return void 0!==this.provider},s.prototype.startPolling=function(t,e){this.provider&&this.provider.poll&&this.polls.push({data:t,id:e})},s.prototype.stopPolling=function(t){var e,n;for(e=this.polls.length;e--;)n=this.polls[e],n.id===t&&this.polls.splice(e,1)},g.provider=new s,g.setProvider=function(t){t.onmessage=r,g.provider.set(t),g.provider.sendQueued()},g.haveProvider=function(){return!!g.provider.provider},a=function(t,e){this.impl=e,this.callbacks=[];var n=this;this.promise=e.newFilter(t),this.promise.then(function(t){n.id=t,g.on(e.changed,t,n.trigger.bind(n)),g.provider.startPolling({call:e.changed,args:[t]},t)})},a.prototype.arrived=function(t){this.changed(t)},a.prototype.changed=function(t){var e=this;this.promise.then(function(){e.callbacks.push(t)})},a.prototype.trigger=function(t){for(var e=0;er&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return m(t.substring(2))},fromDecimal:function(t){return"0x"+b(t)},toEth:function(t){for(var e,n,r,o="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,i=0,s=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];o>3e3&&i 3000 && unit < units.length - 1) @@ -281,10 +281,14 @@ var web3 = { unit++; } var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); + var replaceFunction = function($0, $1, $2) { + return $1 + ',' + $2; + }; + while (true) { var o = s; - s = s.replace(/(\d)(\d\d\d[\.\,])/, function($0, $1, $2) { return $1 + ',' + $2; }); - if (o == s) + s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction); + if (o === s) break; } return s + ' ' + units[unit]; diff --git a/lib/websocket.js b/lib/websocket.js index 24a072531..d50aa1f48 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -22,11 +22,9 @@ * @date 2014 */ -// TODO: work out which of the following two lines it is supposed to be... -//if (process.env.NODE_ENV !== 'build') { -if ("build" !== "build") {/* +if (process.env.NODE_ENV !== 'build') { var WebSocket = require('ws'); // jshint ignore:line -*/} +} var WebSocketProvider = function(host) { // onmessage handlers From 8c1b26889ae90211e01ba2c364aa5d245d6f232f Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 6 Jan 2015 13:27:43 +0100 Subject: [PATCH 465/588] renamed example/index.html -> example/balance.html --- example/{index.html => balance.html} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename example/{index.html => balance.html} (100%) diff --git a/example/index.html b/example/balance.html similarity index 100% rename from example/index.html rename to example/balance.html From a2a77172a688b00e08191fe715c62335120b28ac Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 6 Jan 2015 13:32:04 +0100 Subject: [PATCH 466/588] bring back todos --- lib/autoprovider.js | 1 + lib/contract.js | 1 + lib/httprpc.js | 1 + lib/websocket.js | 1 + 4 files changed, 4 insertions(+) diff --git a/lib/autoprovider.js b/lib/autoprovider.js index 6311d92ff..2f0a3e627 100644 --- a/lib/autoprovider.js +++ b/lib/autoprovider.js @@ -27,6 +27,7 @@ * if it fails, it uses HttpRpcProvider */ +// TODO: is these line is supposed to be here? if (process.env.NODE_ENV !== 'build') { var WebSocket = require('ws'); // jshint ignore:line var web3 = require('./main.js'); // jshint ignore:line diff --git a/lib/contract.js b/lib/contract.js index 7db2ac40e..b10339003 100644 --- a/lib/contract.js +++ b/lib/contract.js @@ -20,6 +20,7 @@ * @date 2014 */ +// TODO: is these line is supposed to be here? if (process.env.NODE_ENV !== 'build') { var web3 = require('./web3'); // jshint ignore:line } diff --git a/lib/httprpc.js b/lib/httprpc.js index 700ce4246..d315201f1 100644 --- a/lib/httprpc.js +++ b/lib/httprpc.js @@ -21,6 +21,7 @@ * @date 2014 */ +// TODO: is these line is supposed to be here? if (process.env.NODE_ENV !== 'build') { var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line } diff --git a/lib/websocket.js b/lib/websocket.js index d50aa1f48..ddb44aed5 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -22,6 +22,7 @@ * @date 2014 */ +// TODO: is these line is supposed to be here? if (process.env.NODE_ENV !== 'build') { var WebSocket = require('ws'); // jshint ignore:line } From b6232cfdd1f23447d900728be0b142d05aca0009 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 6 Jan 2015 13:37:02 +0100 Subject: [PATCH 467/588] fixed tabs --- lib/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/main.js b/lib/main.js index c9bcfe205..b240bdae2 100644 --- a/lib/main.js +++ b/lib/main.js @@ -281,9 +281,9 @@ var web3 = { unit++; } var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); - var replaceFunction = function($0, $1, $2) { - return $1 + ',' + $2; - }; + var replaceFunction = function($0, $1, $2) { + return $1 + ',' + $2; + }; while (true) { var o = s; From 1d139f7a0b54cd3344e32245a06ed29d92f0ae0b Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 6 Jan 2015 18:29:38 +0100 Subject: [PATCH 468/588] solidity string support --- dist/ethereum.js | 2 +- dist/ethereum.js.map | 2 +- dist/ethereum.min.js | 2 +- lib/abi.js | 38 ++++++++++++++++++++++++++++---------- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index bce62075b..710a61883 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -1,5 +1,5 @@ require=(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;or&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return m(t.substring(2))},fromDecimal:function(t){return"0x"+b(t)},toEth:function(t){for(var e,n,r,o="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,i=0,s=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];o>3e3&&ir&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return m(t.substring(2))},fromDecimal:function(t){return"0x"+b(t)},toEth:function(t){for(var e,n,r,o="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,i=0,s=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];o>3e3&&i Date: Tue, 6 Jan 2015 21:50:09 +0100 Subject: [PATCH 469/588] real, ureal paddings and implicit paddings for uint, int and hash --- dist/ethereum.js | 2 +- dist/ethereum.js.map | 2 +- dist/ethereum.min.js | 2 +- lib/abi.js | 61 ++++++++++++++++++++++++++++++++------------ 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index 710a61883..8abe6ad53 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -1,5 +1,5 @@ require=(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;oi;i++)padding+=sizes[i]/8;return padding},setupInputTypes=function(){var prefixedType=function(prefix,calcPadding){return function(type,value){var padding,expected=prefix;return 0!==type.indexOf(expected)?!1:(padding=calcPadding(type,expected),value="number"==typeof value?value.toString(16):"string"==typeof value?web3.toHex(value):0===value.indexOf("0x")?value.substr(2):(+value).toString(16),padLeft(value,2*padding))}},namedType=function(name,padding,formatter){return function(type,value){return type!==name?!1:padLeft(formatter?formatter(value):value,2*padding)}},formatBool=function(value){return value?"0x1":"0x0"};return[prefixedType("uint",calcBitPadding),prefixedType("int",calcBitPadding),prefixedType("hash",calcBitPadding),prefixedType("string",calcBytePadding),prefixedType("real",calcRealPadding),prefixedType("ureal",calcRealPadding),namedType("address",20),namedType("bool",1,formatBool)]},inputTypes=setupInputTypes(),toAbiInput=function(json,methodName,params){var method,i,found,j,bytes="",index=findMethodIndex(json,methodName);if(-1!==index){for(bytes="0x"+padLeft(index.toString(16),2),method=json[index],i=0;ii;i++)padding+=sizes[i]/8;return padding},setupInputTypes=function(){var prefixedType=function(prefix,calcPadding){return function(type,value){var padding,expected=prefix;return 0!==type.indexOf(expected)?!1:(padding=calcPadding(type,expected),value=\"number\"==typeof value?value.toString(16):\"string\"==typeof value?web3.toHex(value):0===value.indexOf(\"0x\")?value.substr(2):(+value).toString(16),padLeft(value,2*padding))}},namedType=function(name,padding,formatter){return function(type,value){return type!==name?!1:padLeft(formatter?formatter(value):value,2*padding)}},formatBool=function(value){return value?\"0x1\":\"0x0\"};return[prefixedType(\"uint\",calcBitPadding),prefixedType(\"int\",calcBitPadding),prefixedType(\"hash\",calcBitPadding),prefixedType(\"string\",calcBytePadding),prefixedType(\"real\",calcRealPadding),prefixedType(\"ureal\",calcRealPadding),namedType(\"address\",20),namedType(\"bool\",1,formatBool)]},inputTypes=setupInputTypes(),toAbiInput=function(json,methodName,params){var method,i,found,j,bytes=\"\",index=findMethodIndex(json,methodName);if(-1!==index){for(bytes=\"0x\"+padLeft(index.toString(16),2),method=json[index],i=0;ir&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return m(t.substring(2))},fromDecimal:function(t){return"0x"+b(t)},toEth:function(t){for(var e,n,r,o="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,i=0,s=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];o>3e3&&io;o++)r+=n[o]/8;return r},l=function(){var t=function(t,e){return function(n,r){var o,i=t;return 0!==n.indexOf(i)?!1:(o=e(n,i),r="number"==typeof r?r.toString(16):"string"==typeof r?web3.toHex(r):0===r.indexOf("0x")?r.substr(2):(+r).toString(16),s(r,2*o))}},e=function(t,e,n){return function(r,o){return r!==t?!1:s(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",u),t("real",c),t("ureal",c),e("address",20),e("bool",1,n)]},h=l(),p=function(t,e,n){var r,o,a,u,c="",l=i(t,e);if(-1!==l){for(c="0x"+s(l.toString(16),2),r=t[l],o=0;or&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return m(t.substring(2))},fromDecimal:function(t){return"0x"+b(t)},toEth:function(t){for(var e,n,r,o="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,i=0,s=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];o>3e3&&i Date: Wed, 7 Jan 2015 12:12:16 +0100 Subject: [PATCH 470/588] 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 471/588] 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 472/588] 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 5208bb32f147bd00ba36ca684faba31c0cc7fc9a Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 7 Jan 2015 14:13:29 +0100 Subject: [PATCH 473/588] gulpfile modifications, default build set to dev --- dist/ethereum.js | 1180 +++++++++++++++++++++++++++++++++++++++++- dist/ethereum.js.map | 18 +- dist/ethereum.min.js | 2 +- gulpfile.js | 81 ++- 4 files changed, 1213 insertions(+), 68 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index 8abe6ad53..e496c30f4 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -1,19 +1,1183 @@ require=(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;oi;i++)padding+=sizes[i]/8;return padding},setupInputTypes=function(){var prefixedType=function(prefix,calcPadding){return function(type,value){var padding,expected=prefix;return 0!==type.indexOf(expected)?!1:(padding=calcPadding(type,expected),value="number"==typeof value?value.toString(16):"string"==typeof value?web3.toHex(value):0===value.indexOf("0x")?value.substr(2):(+value).toString(16),padLeft(value,2*padding))}},namedType=function(name,padding,formatter){return function(type,value){return type!==name?!1:padLeft(formatter?formatter(value):value,2*padding)}},formatBool=function(value){return value?"0x1":"0x0"};return[prefixedType("uint",calcBitPadding),prefixedType("int",calcBitPadding),prefixedType("hash",calcBitPadding),prefixedType("string",calcBytePadding),prefixedType("real",calcRealPadding),prefixedType("ureal",calcRealPadding),namedType("address",20),namedType("bool",1,formatBool)]},inputTypes=setupInputTypes(),toAbiInput=function(json,methodName,params){var method,i,found,j,bytes="",index=findMethodIndex(json,methodName);if(-1!==index){for(bytes="0x"+padLeft(index.toString(16),2),method=json[index],i=0;i. +*/ +/** @file abi.js + * @authors: + * Marek Kotewicz + * Gav Wood + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var web3 = require('./web3'); // jshint ignore:line +*/} + +// TODO: make these be actually accurate instead of falling back onto JS's doubles. +var hexToDec = function (hex) { + return parseInt(hex, 16).toString(); +}; + +var decToHex = function (dec) { + return parseInt(dec).toString(16); +}; + +var findIndex = function (array, callback) { + var end = false; + var i = 0; + for (; i < array.length && !end; i++) { + end = callback(array[i]); + } + return end ? i - 1 : -1; +}; + +var findMethodIndex = function (json, methodName) { + return findIndex(json, function (method) { + return method.name === methodName; + }); +}; + +var padLeft = function (string, chars) { + return new Array(chars - string.length + 1).join("0") + string; +}; + +var calcBitPadding = function (type, expected) { + var value = type.slice(expected.length); + if (value === "") { + return 32; + } + return parseInt(value) / 8; +}; + +var calcBytePadding = function (type, expected) { + var value = type.slice(expected.length); + if (value === "") { + return 32; + } + return parseInt(value); +}; + +var calcRealPadding = function (type, expected) { + var value = type.slice(expected.length); + if (value === "") { + return 32; + } + var sizes = value.split('x'); + for (var padding = 0, i = 0; i < sizes; i++) { + padding += (sizes[i] / 8); + } + return padding; +}; + +var setupInputTypes = function () { + + var prefixedType = function (prefix, calcPadding) { + return function (type, value) { + var expected = prefix; + if (type.indexOf(expected) !== 0) { + return false; + } + + var padding = calcPadding(type, expected); + 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); + }; + }; + + var namedType = function (name, padding, formatter) { + return function (type, value) { + if (type !== name) { + return false; + } + + return padLeft(formatter ? formatter(value) : value, padding * 2); + }; + }; + + var formatBool = function (value) { + return value ? '0x1' : '0x0'; + }; + + return [ + prefixedType('uint', calcBitPadding), + prefixedType('int', calcBitPadding), + prefixedType('hash', calcBitPadding), + prefixedType('string', calcBytePadding), + prefixedType('real', calcRealPadding), + prefixedType('ureal', calcRealPadding), + namedType('address', 20), + namedType('bool', 1, formatBool), + ]; +}; + +var inputTypes = setupInputTypes(); + +var toAbiInput = function (json, methodName, params) { + var bytes = ""; + var index = findMethodIndex(json, methodName); + + if (index === -1) { + return; + } + + bytes = "0x" + padLeft(index.toString(16), 2); + var method = json[index]; + + for (var i = 0; i < method.inputs.length; i++) { + var found = false; + for (var j = 0; j < inputTypes.length && !found; j++) { + found = inputTypes[j](method.inputs[i].type, params[i]); + } + if (!found) { + console.error('unsupported json type: ' + method.inputs[i].type); + } + bytes += found; + } + return bytes; +}; + +var setupOutputTypes = function () { + + var prefixedType = function (prefix, calcPadding) { + return function (type) { + var expected = prefix; + if (type.indexOf(expected) !== 0) { + return -1; + } + + var padding = calcPadding(type, expected); + return padding * 2; + }; + }; + + var namedType = function (name, padding) { + return function (type) { + return name === type ? padding * 2 : -1; + }; + }; + + var formatInt = function (value) { + return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value); + }; + + var formatHash = function (value) { + return "0x" + value; + }; + + var formatBool = function (value) { + return value === '1' ? true : false; + }; + + var formatString = function (value) { + return web3.toAscii(value); + }; + + return [ + { padding: prefixedType('uint', calcBitPadding), format: formatInt }, + { padding: prefixedType('int', calcBitPadding), format: formatInt }, + { padding: prefixedType('hash', calcBitPadding), format: formatHash }, + { padding: prefixedType('string', calcBytePadding), format: formatString }, + { padding: prefixedType('real', calcRealPadding), format: formatInt }, + { padding: prefixedType('ureal', calcRealPadding), format: formatInt }, + { padding: namedType('address', 20) }, + { padding: namedType('bool', 1), format: formatBool } + ]; +}; + +var outputTypes = setupOutputTypes(); + +var fromAbiOutput = function (json, methodName, output) { + var index = findMethodIndex(json, methodName); + + if (index === -1) { + return; + } + + output = output.slice(2); + + var result = []; + var method = json[index]; + for (var i = 0; i < method.outputs.length; i++) { + var padding = -1; + for (var j = 0; j < outputTypes.length && padding === -1; j++) { + padding = outputTypes[j].padding(method.outputs[i].type); + } + + if (padding === -1) { + // not found output parsing + continue; + } + var res = output.slice(0, padding); + var formatter = outputTypes[j - 1].format; + result.push(formatter ? formatter(res) : ("0x" + res)); + output = output.slice(padding); + } + + return result; +}; + +var inputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + parser[method.name] = function () { + var params = Array.prototype.slice.call(arguments); + return toAbiInput(json, method.name, params); + }; + }); + + return parser; +}; + +var outputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + parser[method.name] = function (output) { + return fromAbiOutput(json, method.name, output); + }; + }); + + return parser; +}; + +module.exports = { + inputParser: inputParser, + outputParser: outputParser +}; + },{}],2:[function(require,module,exports){ -var AutoProvider=function(userOptions){var options,self,closeWithSuccess,ws;if(!web3.haveProvider()){if(this.sendQueue=[],this.onmessageQueue=[],navigator.qt)return void(this.provider=new web3.providers.QtProvider);userOptions=userOptions||{},options={httprpc:userOptions.httprpc||"http://localhost:8080",websockets:userOptions.websockets||"ws://localhost:40404/eth"},self=this,closeWithSuccess=function(success){ws.close(),success?self.provider=new web3.providers.WebSocketProvider(options.websockets):(self.provider=new web3.providers.HttpRpcProvider(options.httprpc),self.poll=self.provider.poll.bind(self.provider)),self.sendQueue.forEach(function(payload){self.provider(payload)}),self.onmessageQueue.forEach(function(handler){self.provider.onmessage=handler})},ws=new WebSocket(options.websockets),ws.onopen=function(){closeWithSuccess(!0)},ws.onerror=function(){closeWithSuccess(!1)}}};AutoProvider.prototype.send=function(payload){return this.provider?void this.provider.send(payload):void this.sendQueue.push(payload)},Object.defineProperty(AutoProvider.prototype,"onmessage",{set:function(handler){return this.provider?void(this.provider.onmessage=handler):void this.onmessageQueue.push(handler)}}),module.exports=AutoProvider; +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file autoprovider.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +/* + * @brief if qt object is available, uses QtProvider, + * if not tries to connect over websockets + * if it fails, it uses HttpRpcProvider + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var WebSocket = require('ws'); // jshint ignore:line + var web3 = require('./main.js'); // jshint ignore:line +*/} + +var AutoProvider = function (userOptions) { + if (web3.haveProvider()) { + return; + } + + // before we determine what provider we are, we have to cache request + this.sendQueue = []; + this.onmessageQueue = []; + + if (navigator.qt) { + this.provider = new web3.providers.QtProvider(); + return; + } + + userOptions = userOptions || {}; + var options = { + httprpc: userOptions.httprpc || 'http://localhost:8080', + websockets: userOptions.websockets || 'ws://localhost:40404/eth' + }; + + var self = this; + var closeWithSuccess = function (success) { + ws.close(); + if (success) { + self.provider = new web3.providers.WebSocketProvider(options.websockets); + } else { + self.provider = new web3.providers.HttpRpcProvider(options.httprpc); + self.poll = self.provider.poll.bind(self.provider); + } + self.sendQueue.forEach(function (payload) { + self.provider(payload); + }); + self.onmessageQueue.forEach(function (handler) { + self.provider.onmessage = handler; + }); + }; + + var ws = new WebSocket(options.websockets); + + ws.onopen = function() { + closeWithSuccess(true); + }; + + ws.onerror = function() { + closeWithSuccess(false); + }; +}; + +AutoProvider.prototype.send = function (payload) { + if (this.provider) { + this.provider.send(payload); + return; + } + this.sendQueue.push(payload); +}; + +Object.defineProperty(AutoProvider.prototype, 'onmessage', { + set: function (handler) { + if (this.provider) { + this.provider.onmessage = handler; + return; + } + this.onmessageQueue.push(handler); + } +}); + +module.exports = AutoProvider; + },{}],3:[function(require,module,exports){ -var abi,contract;abi=require("./abi"),contract=function(address,desc){var inputParser=abi.inputParser(desc),outputParser=abi.outputParser(desc),contract={};return desc.forEach(function(method){contract[method.name]=function(){var params=Array.prototype.slice.call(arguments),parsed=inputParser[method.name].apply(null,params),onSuccess=function(result){return outputParser[method.name](result)};return{call:function(extra){return extra=extra||{},extra.to=address,extra.data=parsed,web3.eth.call(extra).then(onSuccess)},transact:function(extra){return extra=extra||{},extra.to=address,extra.data=parsed,web3.eth.transact(extra).then(onSuccess)}}}}),contract},module.exports=contract; +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file contract.js + * @authors: + * Marek Kotewicz + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var web3 = require('./web3'); // jshint ignore:line +*/} + +var abi = require('./abi'); + +var contract = function (address, desc) { + var inputParser = abi.inputParser(desc); + var outputParser = abi.outputParser(desc); + + var contract = {}; + + desc.forEach(function (method) { + contract[method.name] = function () { + var params = Array.prototype.slice.call(arguments); + var parsed = inputParser[method.name].apply(null, params); + + var onSuccess = function (result) { + return outputParser[method.name](result); + }; + + return { + call: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.call(extra).then(onSuccess); + }, + transact: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.transact(extra).then(onSuccess); + } + }; + }; + }); + + return contract; +}; + +module.exports = contract; + },{"./abi":1}],4:[function(require,module,exports){ -function formatJsonRpcObject(object){return{jsonrpc:"2.0",method:object.call,params:object.args,id:object._id}}function formatJsonRpcMessage(message){var object=JSON.parse(message);return{_id:object.id,data:object.result,error:object.error}}var HttpRpcProvider=function(host){this.handlers=[],this.host=host};HttpRpcProvider.prototype.sendRequest=function(payload,cb){var data=formatJsonRpcObject(payload),request=new XMLHttpRequest;request.open("POST",this.host,!0),request.send(JSON.stringify(data)),request.onreadystatechange=function(){4===request.readyState&&cb&&cb(request)}},HttpRpcProvider.prototype.send=function(payload){var self=this;this.sendRequest(payload,function(request){self.handlers.forEach(function(handler){handler.call(self,formatJsonRpcMessage(request.responseText))})})},HttpRpcProvider.prototype.poll=function(payload,id){var self=this;this.sendRequest(payload,function(request){var parsed=JSON.parse(request.responseText);!parsed.error&&(parsed.result instanceof Array?0!==parsed.result.length:parsed.result)&&self.handlers.forEach(function(handler){handler.call(self,{_event:payload.call,_id:id,data:parsed.result})})})},Object.defineProperty(HttpRpcProvider.prototype,"onmessage",{set:function(handler){this.handlers.push(handler)}}),module.exports=HttpRpcProvider; +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file httprpc.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line +*/} + +var HttpRpcProvider = function (host) { + this.handlers = []; + this.host = host; +}; + +function formatJsonRpcObject(object) { + return { + jsonrpc: '2.0', + method: object.call, + params: object.args, + id: object._id + }; +} + +function formatJsonRpcMessage(message) { + var object = JSON.parse(message); + + return { + _id: object.id, + data: object.result, + error: object.error + }; +} + +HttpRpcProvider.prototype.sendRequest = function (payload, cb) { + var data = formatJsonRpcObject(payload); + + var request = new XMLHttpRequest(); + request.open("POST", this.host, true); + request.send(JSON.stringify(data)); + request.onreadystatechange = function () { + if (request.readyState === 4 && cb) { + cb(request); + } + }; +}; + +HttpRpcProvider.prototype.send = function (payload) { + var self = this; + this.sendRequest(payload, function (request) { + self.handlers.forEach(function (handler) { + handler.call(self, formatJsonRpcMessage(request.responseText)); + }); + }); +}; + +HttpRpcProvider.prototype.poll = function (payload, id) { + var self = this; + this.sendRequest(payload, function (request) { + var parsed = JSON.parse(request.responseText); + if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) { + return; + } + self.handlers.forEach(function (handler) { + handler.call(self, {_event: payload.call, _id: id, data: parsed.result}); + }); + }); +}; + +Object.defineProperty(HttpRpcProvider.prototype, "onmessage", { + set: function (handler) { + this.handlers.push(handler); + } +}); + +module.exports = HttpRpcProvider; + },{}],5:[function(require,module,exports){ -function flattenPromise(obj){return obj instanceof Promise?Promise.resolve(obj):obj instanceof Array?new Promise(function(resolve){var promises=obj.map(function(o){return flattenPromise(o)});return Promise.all(promises).then(function(res){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},toDecimal:function(val){return hexToDec(val.substring(2))},fromDecimal:function(val){return"0x"+decToHex(val)},toEth:function(str){for(var s,replaceFunction,o,val="string"==typeof str?0===str.indexOf("0x")?parseInt(str.substr(2),16):parseInt(str):str,unit=0,units=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];val>3e3&&unit. +*/ +/** @file main.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Gav Wood + * @date 2014 + */ + +function flattenPromise (obj) { + if (obj instanceof Promise) { + return Promise.resolve(obj); + } + + if (obj instanceof Array) { + return new Promise(function (resolve) { + var promises = obj.map(function (o) { + return flattenPromise(o); + }); + + return Promise.all(promises).then(function (res) { + for (var i = 0; i < obj.length; i++) { + obj[i] = res[i]; + } + resolve(obj); + }); + }); + } + + if (obj instanceof Object) { + return new Promise(function (resolve) { + var keys = Object.keys(obj); + var promises = keys.map(function (key) { + return flattenPromise(obj[key]); + }); + + return Promise.all(promises).then(function (res) { + for (var i = 0; i < keys.length; i++) { + obj[keys[i]] = res[i]; + } + resolve(obj); + }); + }); + } + + return Promise.resolve(obj); +} + +var web3Methods = function () { + return [ + { name: 'sha3', call: 'web3_sha3' } + ]; +}; + +var ethMethods = function () { + var blockCall = function (args) { + return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; + }; + + var transactionCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; + }; + + var uncleCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; + }; + + var methods = [ + { name: 'balanceAt', call: 'eth_balanceAt' }, + { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'storageAt', call: 'eth_storageAt' }, + { name: 'countAt', call: 'eth_countAt'}, + { name: 'codeAt', call: 'eth_codeAt' }, + { name: 'transact', call: 'eth_transact' }, + { name: 'call', call: 'eth_call' }, + { name: 'block', call: blockCall }, + { name: 'transaction', call: transactionCall }, + { name: 'uncle', call: uncleCall }, + { name: 'compilers', call: 'eth_compilers' }, + { name: 'lll', call: 'eth_lll' }, + { name: 'solidity', call: 'eth_solidity' }, + { name: 'serpent', call: 'eth_serpent' }, + { name: 'logs', call: 'eth_logs' } + ]; + return methods; +}; + +var ethProperties = function () { + return [ + { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, + { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, + { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, + { name: 'gasPrice', getter: 'eth_gasPrice' }, + { name: 'account', getter: 'eth_account' }, + { name: 'accounts', getter: 'eth_accounts' }, + { name: 'peerCount', getter: 'eth_peerCount' }, + { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, + { name: 'number', getter: 'eth_number'} + ]; +}; + +var dbMethods = function () { + return [ + { name: 'put', call: 'db_put' }, + { name: 'get', call: 'db_get' }, + { name: 'putString', call: 'db_putString' }, + { name: 'getString', call: 'db_getString' } + ]; +}; + +var shhMethods = function () { + return [ + { name: 'post', call: 'shh_post' }, + { name: 'newIdentity', call: 'shh_newIdentity' }, + { name: 'haveIdentity', call: 'shh_haveIdentity' }, + { name: 'newGroup', call: 'shh_newGroup' }, + { name: 'addToGroup', call: 'shh_addToGroup' } + ]; +}; + +var ethWatchMethods = function () { + var newFilter = function (args) { + return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; + }; + + return [ + { name: 'newFilter', call: newFilter }, + { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, + { name: 'getMessages', call: 'eth_filterLogs' } + ]; +}; + +var shhWatchMethods = function () { + return [ + { name: 'newFilter', call: 'shh_newFilter' }, + { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, + { name: 'getMessage', call: 'shh_getMessages' } + ]; +}; + +var setupMethods = function (obj, methods) { + methods.forEach(function (method) { + obj[method.name] = function () { + return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) { + var call = typeof method.call === "function" ? method.call(args) : method.call; + return {call: call, args: args}; + }).then(function (request) { + return new Promise(function (resolve, reject) { + web3.provider.send(request, function (err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); + }); + }); + }).catch(function(err) { + console.error(err); + }); + }; + }); +}; + +var setupProperties = function (obj, properties) { + properties.forEach(function (property) { + var proto = {}; + proto.get = function () { + return new Promise(function(resolve, reject) { + web3.provider.send({call: property.getter}, function(err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); + }); + }); + }; + if (property.setter) { + proto.set = function (val) { + return flattenPromise([val]).then(function (args) { + return new Promise(function (resolve) { + web3.provider.send({call: property.setter, args: args}, function (err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); + }); + }); + }).catch(function (err) { + console.error(err); + }); + }; + } + Object.defineProperty(obj, property.name, proto); + }); +}; + +// TODO: import from a dependency, don't duplicate. +var hexToDec = function (hex) { + return parseInt(hex, 16).toString(); +}; + +var decToHex = function (dec) { + return parseInt(dec).toString(16); +}; + + +var web3 = { + _callbacks: {}, + _events: {}, + providers: {}, + + toHex: function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; + }, + + toAscii: function(hex) { + // Find termination + var str = ""; + var i = 0, l = hex.length; + if (hex.substring(0, 2) === '0x') + i = 2; + for(; i < l; i+=2) { + var code = hex.charCodeAt(i); + if(code === 0) { + break; + } + + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + + return str; + }, + + fromAscii: function(str, pad) { + pad = pad === undefined ? 32 : pad; + var hex = this.toHex(str); + while(hex.length < pad*2) + hex += "00"; + return "0x" + hex; + }, + + toDecimal: function (val) { + return hexToDec(val.substring(2)); + }, + + fromDecimal: function (val) { + return "0x" + decToHex(val); + }, + + toEth: function(str) { + var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; + var unit = 0; + var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ]; + while (val > 3000 && unit < units.length - 1) + { + val /= 1000; + unit++; + } + var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); + var replaceFunction = function($0, $1, $2) { + return $1 + ',' + $2; + }; + + while (true) { + var o = s; + s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction); + if (o === s) + break; + } + return s + ' ' + units[unit]; + }, + + eth: { + prototype: Object(), // jshint ignore:line + watch: function (params) { + return new Filter(params, ethWatch); + } + }, + + db: { + prototype: Object() // jshint ignore:line + }, + + shh: { + prototype: Object(), // jshint ignore:line + watch: function (params) { + return new Filter(params, shhWatch); + } + }, + + on: function(event, id, cb) { + if(web3._events[event] === undefined) { + web3._events[event] = {}; + } + + web3._events[event][id] = cb; + return this; + }, + + off: function(event, id) { + if(web3._events[event] !== undefined) { + delete web3._events[event][id]; + } + + return this; + }, + + trigger: function(event, id, data) { + var callbacks = web3._events[event]; + if (!callbacks || !callbacks[id]) { + return; + } + var cb = callbacks[id]; + cb(data); + } +}; + +setupMethods(web3, web3Methods()); +setupMethods(web3.eth, ethMethods()); +setupProperties(web3.eth, ethProperties()); +setupMethods(web3.db, dbMethods()); +setupMethods(web3.shh, shhMethods()); + +var ethWatch = { + changed: 'eth_changed' +}; +setupMethods(ethWatch, ethWatchMethods()); +var shhWatch = { + changed: 'shh_changed' +}; +setupMethods(shhWatch, shhWatchMethods()); + +var ProviderManager = function() { + this.queued = []; + this.polls = []; + this.ready = false; + this.provider = undefined; + this.id = 1; + + var self = this; + var poll = function () { + if (self.provider && self.provider.poll) { + self.polls.forEach(function (data) { + data.data._id = self.id; + self.id++; + self.provider.poll(data.data, data.id); + }); + } + setTimeout(poll, 12000); + }; + poll(); +}; + +ProviderManager.prototype.send = function(data, cb) { + data._id = this.id; + if (cb) { + web3._callbacks[data._id] = cb; + } + + data.args = data.args || []; + this.id++; + + if(this.provider !== undefined) { + this.provider.send(data); + } else { + console.warn("provider is not set"); + this.queued.push(data); + } +}; + +ProviderManager.prototype.set = function(provider) { + if(this.provider !== undefined && this.provider.unload !== undefined) { + this.provider.unload(); + } + + this.provider = provider; + this.ready = true; +}; + +ProviderManager.prototype.sendQueued = function() { + for(var i = 0; this.queued.length; i++) { + // Resend + this.send(this.queued[i]); + } +}; + +ProviderManager.prototype.installed = function() { + return this.provider !== undefined; +}; + +ProviderManager.prototype.startPolling = function (data, pollId) { + if (!this.provider || !this.provider.poll) { + return; + } + this.polls.push({data: data, id: pollId}); +}; + +ProviderManager.prototype.stopPolling = function (pollId) { + for (var i = this.polls.length; i--;) { + var poll = this.polls[i]; + if (poll.id === pollId) { + this.polls.splice(i, 1); + } + } +}; + +web3.provider = new ProviderManager(); + +web3.setProvider = function(provider) { + provider.onmessage = messageHandler; + web3.provider.set(provider); + web3.provider.sendQueued(); +}; + +web3.haveProvider = function() { + return !!web3.provider.provider; +}; + +var Filter = function(options, impl) { + this.impl = impl; + this.callbacks = []; + + var self = this; + this.promise = impl.newFilter(options); + this.promise.then(function (id) { + self.id = id; + web3.on(impl.changed, id, self.trigger.bind(self)); + web3.provider.startPolling({call: impl.changed, args: [id]}, id); + }); +}; + +Filter.prototype.arrived = function(callback) { + this.changed(callback); +}; + +Filter.prototype.changed = function(callback) { + var self = this; + this.promise.then(function(id) { + self.callbacks.push(callback); + }); +}; + +Filter.prototype.trigger = function(messages) { + for(var i = 0; i < this.callbacks.length; i++) { + this.callbacks[i].call(this, messages); + } +}; + +Filter.prototype.uninstall = function() { + var self = this; + this.promise.then(function (id) { + self.impl.uninstallFilter(id); + web3.provider.stopPolling(id); + web3.off(impl.changed, id); + }); +}; + +Filter.prototype.messages = function() { + var self = this; + return this.promise.then(function (id) { + return self.impl.getMessages(id); + }); +}; + +Filter.prototype.logs = function () { + return this.messages(); +}; + +function messageHandler(data) { + if(data._event !== undefined) { + web3.trigger(data._event, data._id, data.data); + return; + } + + if(data._id) { + var cb = web3._callbacks[data._id]; + if (cb) { + cb.call(this, data.error, data.data); + delete web3._callbacks[data._id]; + } + } +} + +module.exports = web3; + },{}],6:[function(require,module,exports){ -var QtProvider=function(){this.handlers=[];var self=this;navigator.qt.onmessage=function(message){self.handlers.forEach(function(handler){handler.call(self,JSON.parse(message.data))})}};QtProvider.prototype.send=function(payload){navigator.qt.postMessage(JSON.stringify(payload))},Object.defineProperty(QtProvider.prototype,"onmessage",{set:function(handler){this.handlers.push(handler)}}),module.exports=QtProvider; +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file qt.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * @date 2014 + */ + +var QtProvider = function() { + this.handlers = []; + + var self = this; + navigator.qt.onmessage = function (message) { + self.handlers.forEach(function (handler) { + handler.call(self, JSON.parse(message.data)); + }); + }; +}; + +QtProvider.prototype.send = function(payload) { + navigator.qt.postMessage(JSON.stringify(payload)); +}; + +Object.defineProperty(QtProvider.prototype, "onmessage", { + set: function(handler) { + this.handlers.push(handler); + } +}); + +module.exports = QtProvider; + },{}],7:[function(require,module,exports){ -var WebSocketProvider=function(host){this.handlers=[],this.queued=[],this.ready=!1,this.ws=new WebSocket(host);var self=this;this.ws.onmessage=function(event){for(var i=0;i. +*/ +/** @file websocket.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var WebSocket = require('ws'); // jshint ignore:line +*/} + +var WebSocketProvider = function(host) { + // onmessage handlers + this.handlers = []; + // queue will be filled with messages if send is invoked before the ws is ready + this.queued = []; + this.ready = false; + + this.ws = new WebSocket(host); + + var self = this; + this.ws.onmessage = function(event) { + for(var i = 0; i < self.handlers.length; i++) { + self.handlers[i].call(self, JSON.parse(event.data), event); + } + }; + + this.ws.onopen = function() { + self.ready = true; + + for(var i = 0; i < self.queued.length; i++) { + // Resend + self.send(self.queued[i]); + } + }; +}; + +WebSocketProvider.prototype.send = function(payload) { + if(this.ready) { + var data = JSON.stringify(payload); + + this.ws.send(data); + } else { + this.queued.push(payload); + } +}; + +WebSocketProvider.prototype.onMessage = function(handler) { + this.handlers.push(handler); +}; + +WebSocketProvider.prototype.unload = function() { + this.ws.close(); +}; +Object.defineProperty(WebSocketProvider.prototype, "onmessage", { + set: function(provider) { this.onMessage(provider); } +}); + +module.exports = WebSocketProvider; + },{}],"web3":[function(require,module,exports){ -var web3=require("./lib/main");web3.providers.WebSocketProvider=require("./lib/websocket"),web3.providers.HttpRpcProvider=require("./lib/httprpc"),web3.providers.QtProvider=require("./lib/qt"),web3.providers.AutoProvider=require("./lib/autoprovider"),web3.contract=require("./lib/contract"),module.exports=web3; +var web3 = require('./lib/main'); +web3.providers.WebSocketProvider = require('./lib/websocket'); +web3.providers.HttpRpcProvider = require('./lib/httprpc'); +web3.providers.QtProvider = require('./lib/qt'); +web3.providers.AutoProvider = require('./lib/autoprovider'); +web3.contract = require('./lib/contract'); + +module.exports = web3; + },{"./lib/autoprovider":2,"./lib/contract":3,"./lib/httprpc":4,"./lib/main":5,"./lib/qt":6,"./lib/websocket":7}]},{},["web3"]) diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index f15143fac..b54a294d7 100644 --- a/dist/ethereum.js.map +++ b/dist/ethereum.js.map @@ -12,18 +12,18 @@ "index.js" ], "names": [], - "mappings": "AAAA;ACAA;;ACAA;;ACAA;;ACAA;;ACAA;;ACAA;;ACAA;;ACAA", + "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;;ACzQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AC7EA;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;oi;i++)padding+=sizes[i]/8;return padding},setupInputTypes=function(){var prefixedType=function(prefix,calcPadding){return function(type,value){var padding,expected=prefix;return 0!==type.indexOf(expected)?!1:(padding=calcPadding(type,expected),value=\"number\"==typeof value?value.toString(16):\"string\"==typeof value?web3.toHex(value):0===value.indexOf(\"0x\")?value.substr(2):(+value).toString(16),padLeft(value,2*padding))}},namedType=function(name,padding,formatter){return function(type,value){return type!==name?!1:padLeft(formatter?formatter(value):value,2*padding)}},formatBool=function(value){return value?\"0x1\":\"0x0\"};return[prefixedType(\"uint\",calcBitPadding),prefixedType(\"int\",calcBitPadding),prefixedType(\"hash\",calcBitPadding),prefixedType(\"string\",calcBytePadding),prefixedType(\"real\",calcRealPadding),prefixedType(\"ureal\",calcRealPadding),namedType(\"address\",20),namedType(\"bool\",1,formatBool)]},inputTypes=setupInputTypes(),toAbiInput=function(json,methodName,params){var method,i,found,j,bytes=\"\",index=findMethodIndex(json,methodName);if(-1!==index){for(bytes=\"0x\"+padLeft(index.toString(16),2),method=json[index],i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},toDecimal:function(val){return hexToDec(val.substring(2))},fromDecimal:function(val){return\"0x\"+decToHex(val)},toEth:function(str){for(var s,replaceFunction,o,val=\"string\"==typeof str?0===str.indexOf(\"0x\")?parseInt(str.substr(2),16):parseInt(str):str,unit=0,units=[\"wei\",\"Kwei\",\"Mwei\",\"Gwei\",\"szabo\",\"finney\",\"ether\",\"grand\",\"Mether\",\"Gether\",\"Tether\",\"Pether\",\"Eether\",\"Zether\",\"Yether\",\"Nether\",\"Dether\",\"Vether\",\"Uether\"];val>3e3&&unit.\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 (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 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 bytes = \"0x\" + padLeft(index.toString(16), 2);\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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser\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('./main.js'); // 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\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 extra.data = parsed;\n return web3.eth.call(extra).then(onSuccess);\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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", + "/*\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 32 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nmodule.exports = web3;\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 qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\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 websocket.js\n * @authors:\n * Jeffrey Wilcke \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 WebSocket = require('ws'); // jshint ignore:line\n*/}\n\nvar WebSocketProvider = function(host) {\n // onmessage handlers\n this.handlers = [];\n // queue will be filled with messages if send is invoked before the ws is ready\n this.queued = [];\n this.ready = false;\n\n this.ws = new WebSocket(host);\n\n var self = this;\n this.ws.onmessage = function(event) {\n for(var i = 0; i < self.handlers.length; i++) {\n self.handlers[i].call(self, JSON.parse(event.data), event);\n }\n };\n\n this.ws.onopen = function() {\n self.ready = true;\n\n for(var i = 0; i < self.queued.length; i++) {\n // Resend\n self.send(self.queued[i]);\n }\n };\n};\n\nWebSocketProvider.prototype.send = function(payload) {\n if(this.ready) {\n var data = JSON.stringify(payload);\n\n this.ws.send(data);\n } else {\n this.queued.push(payload);\n }\n};\n\nWebSocketProvider.prototype.onMessage = function(handler) {\n this.handlers.push(handler);\n};\n\nWebSocketProvider.prototype.unload = function() {\n this.ws.close();\n};\nObject.defineProperty(WebSocketProvider.prototype, \"onmessage\", {\n set: function(provider) { this.onMessage(provider); }\n});\n\nmodule.exports = WebSocketProvider;\n", + "var web3 = require('./lib/main');\nweb3.providers.WebSocketProvider = require('./lib/websocket');\nweb3.providers.HttpRpcProvider = require('./lib/httprpc');\nweb3.providers.QtProvider = require('./lib/qt');\nweb3.providers.AutoProvider = require('./lib/autoprovider');\nweb3.contract = require('./lib/contract');\n\nmodule.exports = web3;\n" ] } \ No newline at end of file diff --git a/dist/ethereum.min.js b/dist/ethereum.min.js index b1ecdfb83..f9eac6a9d 100644 --- a/dist/ethereum.min.js +++ b/dist/ethereum.min.js @@ -1 +1 @@ -require=function t(e,n,r){function o(s,a){if(!n[s]){if(!e[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(i)return i(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[s]={exports:{}};e[s][0].call(l.exports,function(t){var n=e[s][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[s].exports}for(var i="function"==typeof require&&require,s=0;so;o++)r+=n[o]/8;return r},l=function(){var t=function(t,e){return function(n,r){var o,i=t;return 0!==n.indexOf(i)?!1:(o=e(n,i),r="number"==typeof r?r.toString(16):"string"==typeof r?web3.toHex(r):0===r.indexOf("0x")?r.substr(2):(+r).toString(16),s(r,2*o))}},e=function(t,e,n){return function(r,o){return r!==t?!1:s(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",u),t("real",c),t("ureal",c),e("address",20),e("bool",1,n)]},h=l(),p=function(t,e,n){var r,o,a,u,c="",l=i(t,e);if(-1!==l){for(c="0x"+s(l.toString(16),2),r=t[l],o=0;or&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return m(t.substring(2))},fromDecimal:function(t){return"0x"+b(t)},toEth:function(t){for(var e,n,r,o="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,i=0,s=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];o>3e3&&ii;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 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: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="",a=o(t,e);if(-1!==a){r="0x"+i(a.toString(16),2);for(var s=t[a],u=0;un;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?32: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: Wed, 7 Jan 2015 15:08:36 +0100 Subject: [PATCH 474/588] 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 475/588] 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 476/588] 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 477/588] 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 478/588] 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 479/588] 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 480/588] 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 481/588] 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 482/588] 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 483/588] 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 484/588] 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 485/588] 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 486/588] 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 487/588] 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 a8dde1714659d90665e4a891df3134aaaeab3f9c Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 8 Jan 2015 15:11:20 +0100 Subject: [PATCH 488/588] fixes for node.js --- dist/ethereum.js | 102 +++++++++++++++++++-------------------- dist/ethereum.js.map | 12 ++--- dist/ethereum.min.js | 2 +- index.js | 2 +- index_qt.js | 5 -- lib/autoprovider.js | 2 +- lib/contract.js | 2 +- lib/{main.js => web3.js} | 0 8 files changed, 61 insertions(+), 66 deletions(-) delete mode 100644 index_qt.js rename lib/{main.js => web3.js} (100%) diff --git a/dist/ethereum.js b/dist/ethereum.js index e496c30f4..8d1254c87 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -298,7 +298,7 @@ module.exports = { // TODO: is these line is supposed to be here? if ("build" !== 'build') {/* var WebSocket = require('ws'); // jshint ignore:line - var web3 = require('./main.js'); // jshint ignore:line + var web3 = require('./web3'); // jshint ignore:line */} var AutoProvider = function (userOptions) { @@ -394,7 +394,7 @@ module.exports = AutoProvider; // TODO: is these line is supposed to be here? if ("build" !== 'build') {/* - var web3 = require('./web3'); // jshint ignore:line + var web3 = require('./web3'); */} var abi = require('./abi'); @@ -549,6 +549,53 @@ module.exports = HttpRpcProvider; You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ +/** @file qt.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * @date 2014 + */ + +var QtProvider = function() { + this.handlers = []; + + var self = this; + navigator.qt.onmessage = function (message) { + self.handlers.forEach(function (handler) { + handler.call(self, JSON.parse(message.data)); + }); + }; +}; + +QtProvider.prototype.send = function(payload) { + navigator.qt.postMessage(JSON.stringify(payload)); +}; + +Object.defineProperty(QtProvider.prototype, "onmessage", { + set: function(handler) { + this.handlers.push(handler); + } +}); + +module.exports = QtProvider; + +},{}],6:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ /** @file main.js * @authors: * Jeffrey Wilcke @@ -1042,53 +1089,6 @@ function messageHandler(data) { module.exports = web3; -},{}],6:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file qt.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * @date 2014 - */ - -var QtProvider = function() { - this.handlers = []; - - var self = this; - navigator.qt.onmessage = function (message) { - self.handlers.forEach(function (handler) { - handler.call(self, JSON.parse(message.data)); - }); - }; -}; - -QtProvider.prototype.send = function(payload) { - navigator.qt.postMessage(JSON.stringify(payload)); -}; - -Object.defineProperty(QtProvider.prototype, "onmessage", { - set: function(handler) { - this.handlers.push(handler); - } -}); - -module.exports = QtProvider; - },{}],7:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1169,7 +1169,7 @@ Object.defineProperty(WebSocketProvider.prototype, "onmessage", { module.exports = WebSocketProvider; },{}],"web3":[function(require,module,exports){ -var web3 = require('./lib/main'); +var web3 = require('./lib/web3'); web3.providers.WebSocketProvider = require('./lib/websocket'); web3.providers.HttpRpcProvider = require('./lib/httprpc'); web3.providers.QtProvider = require('./lib/qt'); @@ -1178,7 +1178,7 @@ web3.contract = require('./lib/contract'); module.exports = web3; -},{"./lib/autoprovider":2,"./lib/contract":3,"./lib/httprpc":4,"./lib/main":5,"./lib/qt":6,"./lib/websocket":7}]},{},["web3"]) +},{"./lib/autoprovider":2,"./lib/contract":3,"./lib/httprpc":4,"./lib/qt":5,"./lib/web3":6,"./lib/websocket":7}]},{},["web3"]) //# sourceMappingURL=ethereum.js.map \ No newline at end of file diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index b54a294d7..834ce81cd 100644 --- a/dist/ethereum.js.map +++ b/dist/ethereum.js.map @@ -6,24 +6,24 @@ "lib/autoprovider.js", "lib/contract.js", "lib/httprpc.js", - "lib/main.js", "lib/qt.js", + "lib/web3.js", "lib/websocket.js", "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;;ACzQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AC7EA;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;;ACzQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AC5fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;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 (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 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 bytes = \"0x\" + padLeft(index.toString(16), 2);\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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser\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('./main.js'); // 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\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 extra.data = parsed;\n return web3.eth.call(extra).then(onSuccess);\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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 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'); \n*/}\n\nvar abi = require('./abi');\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 extra.data = parsed;\n return web3.eth.call(extra).then(onSuccess);\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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", - "/*\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 32 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nmodule.exports = web3;\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 qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 32 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nmodule.exports = web3;\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 websocket.js\n * @authors:\n * Jeffrey Wilcke \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 WebSocket = require('ws'); // jshint ignore:line\n*/}\n\nvar WebSocketProvider = function(host) {\n // onmessage handlers\n this.handlers = [];\n // queue will be filled with messages if send is invoked before the ws is ready\n this.queued = [];\n this.ready = false;\n\n this.ws = new WebSocket(host);\n\n var self = this;\n this.ws.onmessage = function(event) {\n for(var i = 0; i < self.handlers.length; i++) {\n self.handlers[i].call(self, JSON.parse(event.data), event);\n }\n };\n\n this.ws.onopen = function() {\n self.ready = true;\n\n for(var i = 0; i < self.queued.length; i++) {\n // Resend\n self.send(self.queued[i]);\n }\n };\n};\n\nWebSocketProvider.prototype.send = function(payload) {\n if(this.ready) {\n var data = JSON.stringify(payload);\n\n this.ws.send(data);\n } else {\n this.queued.push(payload);\n }\n};\n\nWebSocketProvider.prototype.onMessage = function(handler) {\n this.handlers.push(handler);\n};\n\nWebSocketProvider.prototype.unload = function() {\n this.ws.close();\n};\nObject.defineProperty(WebSocketProvider.prototype, \"onmessage\", {\n set: function(provider) { this.onMessage(provider); }\n});\n\nmodule.exports = WebSocketProvider;\n", - "var web3 = require('./lib/main');\nweb3.providers.WebSocketProvider = require('./lib/websocket');\nweb3.providers.HttpRpcProvider = require('./lib/httprpc');\nweb3.providers.QtProvider = require('./lib/qt');\nweb3.providers.AutoProvider = require('./lib/autoprovider');\nweb3.contract = require('./lib/contract');\n\nmodule.exports = web3;\n" + "var web3 = require('./lib/web3');\nweb3.providers.WebSocketProvider = require('./lib/websocket');\nweb3.providers.HttpRpcProvider = require('./lib/httprpc');\nweb3.providers.QtProvider = require('./lib/qt');\nweb3.providers.AutoProvider = require('./lib/autoprovider');\nweb3.contract = require('./lib/contract');\n\nmodule.exports = web3;\n" ] } \ No newline at end of file diff --git a/dist/ethereum.min.js b/dist/ethereum.min.js index f9eac6a9d..0ae9610fc 100644 --- a/dist/ethereum.min.js +++ b/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 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: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="",a=o(t,e);if(-1!==a){r="0x"+i(a.toString(16),2);for(var s=t[a],u=0;un;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?32: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,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return 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: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="",a=o(t,e);if(-1!==a){r="0x"+i(a.toString(16),2);for(var s=t[a],u=0;un;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?32: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: Thu, 8 Jan 2015 15:13:43 +0100 Subject: [PATCH 489/588] version upgrade --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 24141ea2e..8f5ba2255 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ethereum.js", "namespace": "ethereum", - "version": "0.0.5", + "version": "0.0.6", "description": "Ethereum Compatible JavaScript API", "main": "./index.js", "directories": { From f9cc09047351ce905d7257a73907398c17603607 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 8 Jan 2015 15:31:46 +0100 Subject: [PATCH 490/588] fixed example --- example/contract.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/contract.html b/example/contract.html index 44f0b03a1..403d8c9d1 100644 --- a/example/contract.html +++ b/example/contract.html @@ -50,7 +50,7 @@ function callExampleContract() { // this should be generated by ethereum - var param = document.getElementById('value').value; + var param = parseInt(document.getElementById('value').value); // call the contract contract.multiply(param).call().then(function(res) { From 807ec60e63e54f648bea47037c307b63d1bc6c04 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 8 Jan 2015 15:43:22 +0100 Subject: [PATCH 491/588] missing jshint ignore --- dist/ethereum.js | 2 +- dist/ethereum.js.map | 2 +- lib/contract.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index 8d1254c87..4f4b5d326 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -394,7 +394,7 @@ module.exports = AutoProvider; // TODO: is these line is supposed to be here? if ("build" !== 'build') {/* - var web3 = require('./web3'); + var web3 = require('./web3'); // jshint ignore:line */} var abi = require('./abi'); diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index 834ce81cd..9886b70ce 100644 --- a/dist/ethereum.js.map +++ b/dist/ethereum.js.map @@ -19,7 +19,7 @@ "(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 (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 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 bytes = \"0x\" + padLeft(index.toString(16), 2);\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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser\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'); \n*/}\n\nvar abi = require('./abi');\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 extra.data = parsed;\n return web3.eth.call(extra).then(onSuccess);\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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 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\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 extra.data = parsed;\n return web3.eth.call(extra).then(onSuccess);\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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", "/*\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 qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 32 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nmodule.exports = web3;\n", diff --git a/lib/contract.js b/lib/contract.js index f64363384..b10339003 100644 --- a/lib/contract.js +++ b/lib/contract.js @@ -22,7 +22,7 @@ // TODO: is these line is supposed to be here? if (process.env.NODE_ENV !== 'build') { - var web3 = require('./web3'); + var web3 = require('./web3'); // jshint ignore:line } var abi = require('./abi'); 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 492/588] 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 9efb644ce414db9a348026ed4315f2a1b56f50a3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 8 Jan 2015 17:02:18 +0100 Subject: [PATCH 493/588] started project model --- mix/AppContext.cpp | 11 ++- mix/AppContext.h | 2 + mix/CMakeLists.txt | 3 + mix/ConstantCompilationControl.cpp | 1 + mix/FileIo.cpp | 68 ++++++++++++++ mix/FileIo.h | 49 ++++++++++ mix/qml.qrc | 17 ++-- mix/qml/MainContent.qml | 10 ++- mix/qml/NewProjectDialog.qml | 92 +++++++++++++++++++ mix/qml/ProjectList.qml | 39 ++++++++ mix/qml/ProjectModel.qml | 140 +++++++++++++++++++++++++++++ mix/qml/StateList.qml | 14 +-- 12 files changed, 431 insertions(+), 15 deletions(-) create mode 100644 mix/FileIo.cpp create mode 100644 mix/FileIo.h create mode 100644 mix/qml/NewProjectDialog.qml create mode 100644 mix/qml/ProjectList.qml create mode 100644 mix/qml/ProjectModel.qml diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index 8eae2b230..65ca4cb20 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -32,8 +32,10 @@ #include #include #include -#include "AppContext.h" #include "CodeModel.h" +#include "FileIo.h" +#include "AppContext.h" + using namespace dev; using namespace dev::eth; @@ -46,8 +48,13 @@ AppContext::AppContext(QQmlApplicationEngine* _engine) m_applicationEngine = _engine; //m_webThree = std::unique_ptr(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"})); m_codeModel = std::unique_ptr(new CodeModel(this)); - m_applicationEngine->rootContext()->setContextProperty("codeModel", m_codeModel.get()); + m_fileIo.reset(new FileIo()); m_applicationEngine->rootContext()->setContextProperty("appContext", this); + qmlRegisterType("org.ethereum.qml", 1, 0, "FileIo"); + qmlRegisterSingletonType(QUrl("qrc:/qml/ProjectModel.qml"), "org.ethereum.qml.ProjectModel", 1, 0, "ProjectModel"); + m_applicationEngine->rootContext()->setContextProperty("codeModel", m_codeModel.get()); + m_applicationEngine->rootContext()->setContextProperty("fileIo", m_fileIo.get()); + } AppContext::~AppContext() diff --git a/mix/AppContext.h b/mix/AppContext.h index a7fa8a017..02d3ef032 100644 --- a/mix/AppContext.h +++ b/mix/AppContext.h @@ -47,6 +47,7 @@ namespace mix { class CodeModel; +class FileIo; /** * @brief Provides access to application scope variable. */ @@ -73,6 +74,7 @@ private: QQmlApplicationEngine* m_applicationEngine; //owned by app std::unique_ptr m_webThree; std::unique_ptr m_codeModel; + std::unique_ptr m_fileIo; public slots: /// Delete the current instance when application quit. diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index 555f6290f..6cef4470c 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -46,3 +46,6 @@ eth_install_executable(${EXECUTABLE} QMLDIR ${CMAKE_CURRENT_SOURCE_DIR}/qml ) +#add qml files to project tree in Qt creator +file(GLOB_RECURSE QMLFILES "qml/*.*") +add_custom_target(dummy SOURCES ${QMLFILES}) diff --git a/mix/ConstantCompilationControl.cpp b/mix/ConstantCompilationControl.cpp index e2d69bf62..c9f21c11b 100644 --- a/mix/ConstantCompilationControl.cpp +++ b/mix/ConstantCompilationControl.cpp @@ -34,6 +34,7 @@ using namespace dev::mix; + ConstantCompilationControl::ConstantCompilationControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::Tab) { connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update); diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp new file mode 100644 index 000000000..2d37422a9 --- /dev/null +++ b/mix/FileIo.cpp @@ -0,0 +1,68 @@ +/* + 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 FileIo.cpp + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#include +#include +#include +#include +#include +#include "FileIo.h" + +using namespace dev::mix; + +void FileIo::makeDir(QString const& _path) +{ + QDir dirPath(_path); + if (!dirPath.exists()) + dirPath.mkpath(dirPath.path()); +} + +QString FileIo::readFile(QString const& _path) +{ + QFile file(_path); + if(file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QTextStream stream(&file); + QString data = stream.readAll(); + return data; + } + else + throw std::runtime_error(tr("Error reading file %1").arg(_path).toStdString()); +} + +void FileIo::writeFile(QString const& _path, QString const& _data) +{ + QFile file(_path); + if(file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + QTextStream stream(&file); + stream << _data; + } + else + throw std::runtime_error(tr("Error writing file %1").arg(_path).toStdString()); +} + +void FileIo::copyFile(QString const& _sourcePath, QString const& _destPath) +{ + if (!QFile::copy(_sourcePath, _destPath)) + throw std::runtime_error(tr("Error copying file %1 to %2").arg(_sourcePath).arg(_destPath).toStdString()); +} diff --git a/mix/FileIo.h b/mix/FileIo.h new file mode 100644 index 000000000..ed1326037 --- /dev/null +++ b/mix/FileIo.h @@ -0,0 +1,49 @@ +/* + 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 FileIo.h + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#pragma once + +#include + +namespace dev +{ +namespace mix +{ + +///File services for QML +class FileIo : public QObject +{ + Q_OBJECT + +public: + /// Create a directory if it does not exist. Throws on failure. + Q_INVOKABLE void makeDir(QString const& _path); + /// Read file contents to a string. Throws on failure. + Q_INVOKABLE QString readFile(QString const& _path); + /// Write contents to a file. Throws on failure. + Q_INVOKABLE void writeFile(QString const& _path, QString const& _data); + /// Copy a file from _sourcePath to _destPath. Throws on failure. + Q_INVOKABLE void copyFile(QString const& _sourcePath, QString const& _destPath); +}; + +} +} diff --git a/mix/qml.qrc b/mix/qml.qrc index 7e731b6f4..a6215b243 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -1,16 +1,19 @@ - qml/BasicContent.qml qml/main.qml - qml/MainContent.qml - qml/TabStyle.qml - qml/Debugger.qml - qml/js/Debugger.js + qml/AlertMessageDialog.qml + qml/BasicContent.qml qml/BasicMessage.qml - qml/TransactionDialog.qml + qml/Debugger.qml + qml/MainContent.qml qml/ModalDialog.qml - qml/AlertMessageDialog.qml + qml/ProjectList.qml qml/StateDialog.qml qml/StateList.qml + qml/TabStyle.qml + qml/TransactionDialog.qml + qml/js/Debugger.js + qml/NewProjectDialog.qml + qml/ProjectModel.qml diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 7f9a27d58..6cd2f5baa 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -20,9 +20,17 @@ Rectangle { SplitView { orientation: Qt.Horizontal anchors.fill: parent + + ProjectList { + anchors.left: parent.left + width: parent.width * 0.2 + height: parent.height + Layout.minimumWidth: 20 + } + SplitView { //anchors.fill: parent - width: parent.width * 0.8 + width: parent.width * 0.6 orientation: Qt.Vertical Rectangle { anchors.top: parent.top diff --git a/mix/qml/NewProjectDialog.qml b/mix/qml/NewProjectDialog.qml new file mode 100644 index 000000000..b0853ba26 --- /dev/null +++ b/mix/qml/NewProjectDialog.qml @@ -0,0 +1,92 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 +import QtQuick.Dialogs 1.2 + +Window { + + modality: Qt.WindowModal + + width: 640 + height: 280 + + visible: false + + property alias projectTitle : titleField.text + property alias projectPath : pathField.text + signal accepted + + function open() { + visible = true; + titleField.focus = true; + } + + function close() { + visible = false; + } + + GridLayout { + id: dialogContent + columns: 2 + anchors.fill: parent + anchors.margins: 10 + rowSpacing: 10 + columnSpacing: 10 + + Label { + text: qsTr("Title") + } + TextField { + id: titleField + focus: true + Layout.fillWidth: true + } + + Label { + text: qsTr("Path") + } + RowLayout { + TextField { + id: pathField + Layout.fillWidth: true + } + Button { + text: qsTr("Browse") + onClicked: createProjectFileDialog.open() + } + } + + RowLayout + { + anchors.bottom: parent.bottom + anchors.right: parent.right; + + Button { + enabled: titleField.text != "" && pathField.text != "" + text: qsTr("Ok"); + onClicked: { + close(); + accepted(); + } + } + Button { + text: qsTr("Cancel"); + onClicked: close(); + } + } + } + + FileDialog { + id: createProjectFileDialog + visible: false + title: qsTr("Please choose a path for the project") + selectFolder: true + onAccepted: { + var u = createProjectFileDialog.fileUrl.toString(); + if (u.indexOf("file://") == 0) + u = u.substring(7, u.length) + pathField.text = u; + } + } +} diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml new file mode 100644 index 000000000..60f1de898 --- /dev/null +++ b/mix/qml/ProjectList.qml @@ -0,0 +1,39 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import org.ethereum.qml.ProjectModel 1.0 + +Item { + ListView { + model: ProjectModel.listModel + delegate: renderDelegate + } + + Component { + id: renderDelegate + Item { + id: wrapperItem + height: 20 + width: parent.width + RowLayout { + anchors.fill: parent + Text { + Layout.fillWidth: true + Layout.fillHeight: true + text: title + font.pointSize: 12 + verticalAlignment: Text.AlignBottom + } + } + } + } + + Action { + id: createProjectAction + text: qsTr("&New project") + shortcut: "Ctrl+N" + enabled: true; + onTriggered: ProjectModel.createProject(); + } +} diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml new file mode 100644 index 000000000..26896ea5f --- /dev/null +++ b/mix/qml/ProjectModel.qml @@ -0,0 +1,140 @@ +pragma Singleton + +import QtQuick 2.0 +import QtQuick.Window 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Dialogs 1.1 +import Qt.labs.settings 1.0 + +Item { + id: projectModel + + signal projectClosed + signal projectLoaded + + property bool isEmpty: projectFile === "" + readonly property string projectFileName: ".mix" + + property bool haveUnsavedChanges: false + property string projectFile: "" + property var projectData: null + property var listModel: projectListModel + + function saveAll() { + saveProject(); + } + + function createProject() { + closeProject(); + newProjectDialog.open(); + } + + function closeProject() { + console.log("closing project"); + if (haveUnsavedChanges) + saveMessageDialog.open(); + else + doCloseProject(); + } + + function saveProject() { + if (!isEmpty) { + var json = JSON.stringify(projectData); + fileIo.writeFile(projectFile, json) + } + } + + function loadProject(path) { + if (!isEmpty) + closeProject(); + console.log("loading project at " + path); + var json = fileIo.readFile(path); + projectData = JSON.parse(json); + projectFile = path; + if (!projectData.files) + projectData.files = []; + + for(var i = 0; i < projectData.files; i++) { + var p = projectData.files[i]; + projectListModel.append({ + path: p, + name: p.substring(p.lastIndexOf("/") + 1, p.length) + }); + } + onProjectLoaded(); + } + + function doCloseProject() { + projectListModel.clear(); + projectFile = ""; + projectData = null; + projectClosed(); + } + + function doCreateProject(title, path) { + if (!isEmpty) + closeProject(); + console.log("creating project " + title + " at " + path); + if (path[path.length - 1] !== "/") + path += "/"; + var dirPath = path + title; + fileIo.makeDir(dirPath); + var projectFile = dirPath + "/" + projectFileName; + fileIo.writeFile(projectFile, ""); + loadProject(projectFile); + } + + NewProjectDialog { + id: newProjectDialog + visible: false + onAccepted: { + var title = newProjectDialog.projectTitle; + var path = newProjectDialog.projectPath; + projectModel.doCreateProject(title, path); + } + } + + MessageDialog { + id: saveMessageDialog + title: qsTr("Project") + text: qsTr("Do you want to save changes?") + standardButtons: StandardButton.Ok | StandardButton.Cancel + icon: StandardIcon.Question + onAccepted: { + projectModel.saveAll(); + projectModel.doCloseProject(); + } + onRejected: { + projectModel.doCloseProject(); + } + } + + ListModel { + id: projectListModel + } + + Component { + id: renderDelegate + Item { + id: wrapperItem + height: 20 + width: parent.width + RowLayout { + anchors.fill: parent + Text { + Layout.fillWidth: true + Layout.fillHeight: true + text: title + font.pointSize: 12 + verticalAlignment: Text.AlignBottom + } + } + } + } + + Settings { + id: projectSettings + property string lastProjectPath; + } +} diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index 152a35671..ceed6513b 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -3,6 +3,7 @@ import QtQuick.Controls.Styles 1.2 import QtQuick.Controls 1.2 import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.1 +import org.ethereum.qml.ProjectModel 1.0 Rectangle { color: "transparent" @@ -15,9 +16,12 @@ Rectangle { property var stateList: [] Connections { - target: appContext + target: ProjectModel + onProjectClosed: { + stateListModel.clear(); + } onProjectLoaded: { - var items = JSON.parse(_json); + var items = target.projectData.states; for(var i = 0; i < items.length; i++) { stateListModel.append(items[i]); stateList.push(items[i]) @@ -82,8 +86,8 @@ Rectangle { } function save() { - var json = JSON.stringify(stateList); - appContext.saveProject(json); + console.log(parent.id); + ProjectModel.saveProject(); } } @@ -124,7 +128,7 @@ Rectangle { Action { id: addStateAction text: "&Add State" - shortcut: "Ctrl+N" + shortcut: "Ctrl+T" enabled: codeModel.hasContract && !debugModel.running; onTriggered: stateListModel.addState(); } From 5518022a5d153ef514338edcb427a90ad066d064 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 8 Jan 2015 19:35:32 +0100 Subject: [PATCH 494/588] mocha test init --- test/methods.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 test/methods.js diff --git a/test/methods.js b/test/methods.js new file mode 100644 index 000000000..54d96b486 --- /dev/null +++ b/test/methods.js @@ -0,0 +1,49 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +var methodExists = function (object, method) { + assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented'); +}; + +var propertyExists = function (object, property) { + assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented'); +}; + +describe('web3', function() { + describe('eth', function() { + it('should have all methods implemented', function() { + methodExists(web3.eth, 'balanceAt'); + methodExists(web3.eth, 'stateAt'); + methodExists(web3.eth, 'storageAt'); + methodExists(web3.eth, 'countAt'); + methodExists(web3.eth, 'codeAt'); + methodExists(web3.eth, 'transact'); + methodExists(web3.eth, 'call'); + methodExists(web3.eth, 'block'); + methodExists(web3.eth, 'transaction'); + methodExists(web3.eth, 'uncle'); + methodExists(web3.eth, 'compilers'); + methodExists(web3.eth, 'lll'); + methodExists(web3.eth, 'solidity'); + methodExists(web3.eth, 'serpent'); + methodExists(web3.eth, 'logs'); + }); + + it('should have all properties implemented', function () { + propertyExists(web3.eth, 'coinbase'); + propertyExists(web3.eth, 'listening'); + propertyExists(web3.eth, 'mining'); + propertyExists(web3.eth, 'gasPrice'); + propertyExists(web3.eth, 'account'); + propertyExists(web3.eth, 'accounts'); + propertyExists(web3.eth, 'peerCount'); + propertyExists(web3.eth, 'defaultBlock'); + propertyExists(web3.eth, 'number'); + }); + }); +}) + + From b6058a837f9a90bd2973e4be54f0eab85e85674e Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 8 Jan 2015 19:59:03 +0100 Subject: [PATCH 495/588] methods existance tests in progress --- test/db.methods.js | 18 ++++++++++++++++ test/eth.methods.js | 42 +++++++++++++++++++++++++++++++++++++ test/methods.js | 49 -------------------------------------------- test/shh.methods.js | 19 +++++++++++++++++ test/utils.js | 15 ++++++++++++++ test/web3.methods.js | 18 ++++++++++++++++ 6 files changed, 112 insertions(+), 49 deletions(-) create mode 100644 test/db.methods.js create mode 100644 test/eth.methods.js delete mode 100644 test/methods.js create mode 100644 test/shh.methods.js create mode 100644 test/utils.js create mode 100644 test/web3.methods.js diff --git a/test/db.methods.js b/test/db.methods.js new file mode 100644 index 000000000..b4abfc4d7 --- /dev/null +++ b/test/db.methods.js @@ -0,0 +1,18 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + describe('db', function() { + it('should have all methods implemented', function() { + u.methodExists(web3.db, 'put'); + u.methodExists(web3.db, 'get'); + u.methodExists(web3.db, 'putString'); + u.methodExists(web3.db, 'getString'); + }); + }); +}); + diff --git a/test/eth.methods.js b/test/eth.methods.js new file mode 100644 index 000000000..7190b27d2 --- /dev/null +++ b/test/eth.methods.js @@ -0,0 +1,42 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + describe('eth', function() { + it('should have all methods implemented', function() { + u.methodExists(web3.eth, 'balanceAt'); + u.methodExists(web3.eth, 'stateAt'); + u.methodExists(web3.eth, 'storageAt'); + u.methodExists(web3.eth, 'countAt'); + u.methodExists(web3.eth, 'codeAt'); + u.methodExists(web3.eth, 'transact'); + u.methodExists(web3.eth, 'call'); + u.methodExists(web3.eth, 'block'); + u.methodExists(web3.eth, 'transaction'); + u.methodExists(web3.eth, 'uncle'); + u.methodExists(web3.eth, 'compilers'); + u.methodExists(web3.eth, 'lll'); + u.methodExists(web3.eth, 'solidity'); + u.methodExists(web3.eth, 'serpent'); + u.methodExists(web3.eth, 'logs'); + }); + + it('should have all properties implemented', function () { + u.propertyExists(web3.eth, 'coinbase'); + u.propertyExists(web3.eth, 'listening'); + u.propertyExists(web3.eth, 'mining'); + u.propertyExists(web3.eth, 'gasPrice'); + u.propertyExists(web3.eth, 'account'); + u.propertyExists(web3.eth, 'accounts'); + u.propertyExists(web3.eth, 'peerCount'); + u.propertyExists(web3.eth, 'defaultBlock'); + u.propertyExists(web3.eth, 'number'); + }); + }); +}); + + diff --git a/test/methods.js b/test/methods.js deleted file mode 100644 index 54d96b486..000000000 --- a/test/methods.js +++ /dev/null @@ -1,49 +0,0 @@ -require('es6-promise').polyfill(); - -var assert = require('assert'); -var web3 = require('../index.js'); -web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider - -var methodExists = function (object, method) { - assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented'); -}; - -var propertyExists = function (object, property) { - assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented'); -}; - -describe('web3', function() { - describe('eth', function() { - it('should have all methods implemented', function() { - methodExists(web3.eth, 'balanceAt'); - methodExists(web3.eth, 'stateAt'); - methodExists(web3.eth, 'storageAt'); - methodExists(web3.eth, 'countAt'); - methodExists(web3.eth, 'codeAt'); - methodExists(web3.eth, 'transact'); - methodExists(web3.eth, 'call'); - methodExists(web3.eth, 'block'); - methodExists(web3.eth, 'transaction'); - methodExists(web3.eth, 'uncle'); - methodExists(web3.eth, 'compilers'); - methodExists(web3.eth, 'lll'); - methodExists(web3.eth, 'solidity'); - methodExists(web3.eth, 'serpent'); - methodExists(web3.eth, 'logs'); - }); - - it('should have all properties implemented', function () { - propertyExists(web3.eth, 'coinbase'); - propertyExists(web3.eth, 'listening'); - propertyExists(web3.eth, 'mining'); - propertyExists(web3.eth, 'gasPrice'); - propertyExists(web3.eth, 'account'); - propertyExists(web3.eth, 'accounts'); - propertyExists(web3.eth, 'peerCount'); - propertyExists(web3.eth, 'defaultBlock'); - propertyExists(web3.eth, 'number'); - }); - }); -}) - - diff --git a/test/shh.methods.js b/test/shh.methods.js new file mode 100644 index 000000000..08f573a3c --- /dev/null +++ b/test/shh.methods.js @@ -0,0 +1,19 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + describe('shh', function() { + it('should have all methods implemented', function() { + u.methodExists(web3.shh, 'post'); + u.methodExists(web3.shh, 'newIdentity'); + u.methodExists(web3.shh, 'haveIdentity'); + u.methodExists(web3.shh, 'newGroup'); + u.methodExists(web3.shh, 'addToGroup'); + }); + }); +}); + diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 000000000..4c508da67 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,15 @@ +var assert = require('assert'); + +var methodExists = function (object, method) { + assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented'); +}; + +var propertyExists = function (object, property) { + assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented'); +}; + +module.exports = { + methodExists: methodExists, + propertyExists: propertyExists +}; + diff --git a/test/web3.methods.js b/test/web3.methods.js new file mode 100644 index 000000000..a7e020978 --- /dev/null +++ b/test/web3.methods.js @@ -0,0 +1,18 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + it('should have all methods implemented', function() { + u.methodExists(web3, 'sha3'); + u.methodExists(web3, 'toAscii'); + u.methodExists(web3, 'fromAscii'); + u.methodExists(web3, 'toFixed'); + u.methodExists(web3, 'fromFixed'); + u.methodExists(web3, 'offset'); + }); +}); + From c397e350f4903b13af901762547fcc4d7905d8cd Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 8 Jan 2015 20:24:30 +0100 Subject: [PATCH 496/588] mocha opts file && init of parser tests --- lib/abi.js | 1 + test/abi.parsers.js | 37 +++++++++++++++++++++++++++++++++++++ test/mocha.opts | 2 ++ 3 files changed, 40 insertions(+) create mode 100644 test/abi.parsers.js create mode 100644 test/mocha.opts diff --git a/lib/abi.js b/lib/abi.js index 5a4d64515..e37f477ee 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -263,3 +263,4 @@ module.exports = { inputParser: inputParser, outputParser: outputParser }; + diff --git a/test/abi.parsers.js b/test/abi.parsers.js new file mode 100644 index 000000000..06a77fb86 --- /dev/null +++ b/test/abi.parsers.js @@ -0,0 +1,37 @@ +var assert = require('assert'); +var abi = require('../lib/abi.js'); + +describe('abi', function() { + describe('inputParser', function() { + it('should parse ...', function() { + + var desc = [{ + "name": "multiply", + "inputs": [ + { + "name": "a", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "d", + "type": "uint256" + } + ] + }]; + + var iParser = abi.inputParser(desc); + assert.equal(iParser.multiply(1), "0x000000000000000000000000000000000000000000000000000000000000000001"); + + }); + }); + + + describe('outputParser', function() { + it('parse ...', function() { + + }); + }); +}); + diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 000000000..b83917bb2 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,2 @@ +--reporter Nyan + 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 497/588] 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 07fba274b1d5da40b0fbe58263d6c3dc5ed6fa6e Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 9 Jan 2015 12:43:45 +0100 Subject: [PATCH 498/588] module var fix --- lib/websocket.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/websocket.js b/lib/websocket.js index ddb44aed5..5b40075e4 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -74,4 +74,5 @@ Object.defineProperty(WebSocketProvider.prototype, "onmessage", { set: function(provider) { this.onMessage(provider); } }); -module.exports = WebSocketProvider; +if (typeof(module) !== "undefined") + module.exports = WebSocketProvider; From c9015e2e04729a06cbcfd650ebfb0c1e71d96ce3 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 9 Jan 2015 12:44:11 +0100 Subject: [PATCH 499/588] module var fix --- lib/web3.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/web3.js b/lib/web3.js index b240bdae2..9a85c4d1b 100644 --- a/lib/web3.js +++ b/lib/web3.js @@ -505,4 +505,5 @@ function messageHandler(data) { } } -module.exports = web3; +if (typeof(module) !== "undefined") + module.exports = web3; From 0538c11576a020a0e7fe19652398547fdad4b84b Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 9 Jan 2015 12:55:04 +0100 Subject: [PATCH 500/588] sha3 method signature --- dist/ethereum.js | 22 ++++++++++++++++++---- dist/ethereum.js.map | 6 +++--- dist/ethereum.min.js | 2 +- lib/abi.js | 16 ++++++++++++++-- lib/contract.js | 6 ++++-- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index 4f4b5d326..c87ebf204 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -141,7 +141,6 @@ var toAbiInput = function (json, methodName, params) { return; } - bytes = "0x" + padLeft(index.toString(16), 2); var method = json[index]; for (var i = 0; i < method.inputs.length; i++) { @@ -260,9 +259,22 @@ var outputParser = function (json) { return parser; }; +var methodSignature = function (json, name) { + var method = json[findMethodIndex(json, name)]; + var result = name + '('; + var inputTypes = method.inputs.map(function (inp) { + return inp.type; + }); + result += inputTypes.join(','); + result += ')'; + + return web3.sha3(result); +}; + module.exports = { inputParser: inputParser, - outputParser: outputParser + outputParser: outputParser, + methodSignature: methodSignature }; },{}],2:[function(require,module,exports){ @@ -418,8 +430,10 @@ var contract = function (address, desc) { call: function (extra) { extra = extra || {}; extra.to = address; - extra.data = parsed; - return web3.eth.call(extra).then(onSuccess); + return abi.methodSignature(desc, method.name).then(function (signature) { + extra.data = signature.slice(0, 10) + parsed; + return web3.eth.call(extra).then(onSuccess); + }); }, transact: function (extra) { extra = extra || {}; diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index 9886b70ce..5a16b7ba5 100644 --- a/dist/ethereum.js.map +++ b/dist/ethereum.js.map @@ -12,14 +12,14 @@ "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;;ACzQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AC5fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;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;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AC5fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;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 (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 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 bytes = \"0x\" + padLeft(index.toString(16), 2);\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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser\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 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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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(result);\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\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\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 extra.data = parsed;\n return web3.eth.call(extra).then(onSuccess);\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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 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\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, 10) + parsed;\n return web3.eth.call(extra).then(onSuccess);\n });\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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", "/*\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 qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 32 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nmodule.exports = web3;\n", diff --git a/dist/ethereum.min.js b/dist/ethereum.min.js index 0ae9610fc..791a0b51b 100644 --- a/dist/ethereum.min.js +++ b/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 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: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="",a=o(t,e);if(-1!==a){r="0x"+i(a.toString(16),2);for(var s=t[a],u=0;un;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?32: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,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return 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: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;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?32: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: Fri, 9 Jan 2015 12:55:46 +0100 Subject: [PATCH 501/588] version upgraded --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8f5ba2255..fc34be487 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ethereum.js", "namespace": "ethereum", - "version": "0.0.6", + "version": "0.0.7", "description": "Ethereum Compatible JavaScript API", "main": "./index.js", "directories": { 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 502/588] 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 503/588] 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 543a87c63f77a61fb91a07515c2f6383b791a27d Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 9 Jan 2015 13:30:14 +0100 Subject: [PATCH 504/588] method signature length defined --- dist/ethereum.js | 11 ++++++++--- dist/ethereum.js.map | 8 ++++---- dist/ethereum.min.js | 2 +- lib/contract.js | 5 ++++- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index c87ebf204..b768f88a4 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -411,6 +411,9 @@ if ("build" !== 'build') {/* var abi = require('./abi'); +// method signature length in bytes +var ETH_METHOD_SIGNATURE_LENGTH = 4; + var contract = function (address, desc) { var inputParser = abi.inputParser(desc); var outputParser = abi.outputParser(desc); @@ -431,7 +434,7 @@ var contract = function (address, desc) { extra = extra || {}; extra.to = address; return abi.methodSignature(desc, method.name).then(function (signature) { - extra.data = signature.slice(0, 10) + parsed; + extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed; return web3.eth.call(extra).then(onSuccess); }); }, @@ -1101,7 +1104,8 @@ function messageHandler(data) { } } -module.exports = web3; +if (typeof(module) !== "undefined") + module.exports = web3; },{}],7:[function(require,module,exports){ /* @@ -1180,7 +1184,8 @@ Object.defineProperty(WebSocketProvider.prototype, "onmessage", { set: function(provider) { this.onMessage(provider); } }); -module.exports = WebSocketProvider; +if (typeof(module) !== "undefined") + module.exports = WebSocketProvider; },{}],"web3":[function(require,module,exports){ var web3 = require('./lib/web3'); diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index 5a16b7ba5..4f4d3e675 100644 --- a/dist/ethereum.js.map +++ b/dist/ethereum.js.map @@ -12,18 +12,18 @@ "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;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AC5fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;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;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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(result);\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\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\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, 10) + parsed;\n return web3.eth.call(extra).then(onSuccess);\n });\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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 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 extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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", "/*\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 qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 32 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nmodule.exports = web3;\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 websocket.js\n * @authors:\n * Jeffrey Wilcke \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 WebSocket = require('ws'); // jshint ignore:line\n*/}\n\nvar WebSocketProvider = function(host) {\n // onmessage handlers\n this.handlers = [];\n // queue will be filled with messages if send is invoked before the ws is ready\n this.queued = [];\n this.ready = false;\n\n this.ws = new WebSocket(host);\n\n var self = this;\n this.ws.onmessage = function(event) {\n for(var i = 0; i < self.handlers.length; i++) {\n self.handlers[i].call(self, JSON.parse(event.data), event);\n }\n };\n\n this.ws.onopen = function() {\n self.ready = true;\n\n for(var i = 0; i < self.queued.length; i++) {\n // Resend\n self.send(self.queued[i]);\n }\n };\n};\n\nWebSocketProvider.prototype.send = function(payload) {\n if(this.ready) {\n var data = JSON.stringify(payload);\n\n this.ws.send(data);\n } else {\n this.queued.push(payload);\n }\n};\n\nWebSocketProvider.prototype.onMessage = function(handler) {\n this.handlers.push(handler);\n};\n\nWebSocketProvider.prototype.unload = function() {\n this.ws.close();\n};\nObject.defineProperty(WebSocketProvider.prototype, \"onmessage\", {\n set: function(provider) { this.onMessage(provider); }\n});\n\nmodule.exports = WebSocketProvider;\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 32 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nif (typeof(module) !== \"undefined\")\n module.exports = web3;\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 websocket.js\n * @authors:\n * Jeffrey Wilcke \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 WebSocket = require('ws'); // jshint ignore:line\n*/}\n\nvar WebSocketProvider = function(host) {\n // onmessage handlers\n this.handlers = [];\n // queue will be filled with messages if send is invoked before the ws is ready\n this.queued = [];\n this.ready = false;\n\n this.ws = new WebSocket(host);\n\n var self = this;\n this.ws.onmessage = function(event) {\n for(var i = 0; i < self.handlers.length; i++) {\n self.handlers[i].call(self, JSON.parse(event.data), event);\n }\n };\n\n this.ws.onopen = function() {\n self.ready = true;\n\n for(var i = 0; i < self.queued.length; i++) {\n // Resend\n self.send(self.queued[i]);\n }\n };\n};\n\nWebSocketProvider.prototype.send = function(payload) {\n if(this.ready) {\n var data = JSON.stringify(payload);\n\n this.ws.send(data);\n } else {\n this.queued.push(payload);\n }\n};\n\nWebSocketProvider.prototype.onMessage = function(handler) {\n this.handlers.push(handler);\n};\n\nWebSocketProvider.prototype.unload = function() {\n this.ws.close();\n};\nObject.defineProperty(WebSocketProvider.prototype, \"onmessage\", {\n set: function(provider) { this.onMessage(provider); }\n});\n\nif (typeof(module) !== \"undefined\")\n module.exports = WebSocketProvider;\n", "var web3 = require('./lib/web3');\nweb3.providers.WebSocketProvider = require('./lib/websocket');\nweb3.providers.HttpRpcProvider = require('./lib/httprpc');\nweb3.providers.QtProvider = require('./lib/qt');\nweb3.providers.AutoProvider = require('./lib/autoprovider');\nweb3.contract = require('./lib/contract');\n\nmodule.exports = web3;\n" ] } \ No newline at end of file diff --git a/dist/ethereum.min.js b/dist/ethereum.min.js index 791a0b51b..cbf0464a4 100644 --- a/dist/ethereum.min.js +++ b/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 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: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;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?32: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,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return 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: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;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?32: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: Fri, 9 Jan 2015 14:03:10 +0100 Subject: [PATCH 505/588] 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 506/588] 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 715e0a4745127beb035cfa1c39cb233244f665d3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 9 Jan 2015 14:34:12 +0100 Subject: [PATCH 507/588] continue project model implementation --- mix/CodeEditorExtensionManager.cpp | 32 +------- mix/CodeEditorExtensionManager.h | 5 -- mix/FileIo.cpp | 29 ++++--- mix/FileIo.h | 20 +++-- mix/MixApplication.cpp | 1 + mix/qml.qrc | 3 + mix/qml/CodeEditor.qml | 81 +++++++++++++++++++ mix/qml/CodeEditorModel.qml | 13 +++ mix/qml/CodeEditorView.qml | 80 +++++++++++++++++++ mix/qml/MainContent.qml | 72 ++--------------- mix/qml/NewProjectDialog.qml | 12 +-- mix/qml/ProjectList.qml | 28 +++++-- mix/qml/ProjectModel.qml | 123 ++++++++++++++++++++--------- mix/qml/StateList.qml | 2 + mix/qml/main.qml | 53 +++++++++++++ 15 files changed, 384 insertions(+), 170 deletions(-) create mode 100644 mix/qml/CodeEditor.qml create mode 100644 mix/qml/CodeEditorModel.qml create mode 100644 mix/qml/CodeEditorView.qml diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index 48c928a1f..14795c223 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -51,15 +51,6 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) if (!_editor) return; - QVariant doc = _editor->property("textDocument"); - if (doc.canConvert()) - { - QQuickTextDocument* qqdoc = doc.value(); - if (qqdoc) - { - m_doc = qqdoc->textDocument(); - } - } } void CodeEditorExtensionManager::initExtensions() @@ -67,7 +58,6 @@ void CodeEditorExtensionManager::initExtensions() std::shared_ptr output = std::make_shared(m_appContext); std::shared_ptr debug = std::make_shared(m_appContext); std::shared_ptr stateList = std::make_shared(m_appContext); - QObject::connect(m_doc, &QTextDocument::contentsChange, this, &CodeEditorExtensionManager::onCodeChange); QObject::connect(debug.get(), &AssemblyDebuggerControl::runFailed, output.get(), &ConstantCompilationControl::displayError); QObject::connect(m_appContext->codeModel(), &CodeModel::compilationComplete, this, &CodeEditorExtensionManager::applyCodeHighlight); @@ -97,35 +87,21 @@ void CodeEditorExtensionManager::initExtension(std::shared_ptr _ext) m_features.append(_ext); } -void CodeEditorExtensionManager::setEditor(QQuickItem* _editor) -{ - this->loadEditor(_editor); - this->initExtensions(); - - auto args = QApplication::arguments(); - if (args.length() > 1) - { - QString path = args[1]; - QFile file(path); - if (file.exists() && file.open(QFile::ReadOnly)) - m_doc->setPlainText(file.readAll()); - } -} - void CodeEditorExtensionManager::onCodeChange() { - m_appContext->codeModel()->updateFormatting(m_doc); //update old formatting - m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); +// m_appContext->codeModel()->updateFormatting(m_doc); //update old formatting +// m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); } void CodeEditorExtensionManager::applyCodeHighlight() { - m_appContext->codeModel()->updateFormatting(m_doc); +// m_appContext->codeModel()->updateFormatting(m_doc); } void CodeEditorExtensionManager::setRightTabView(QQuickItem* _tabView) { m_rightTabView = _tabView; + initExtensions(); //TODO: this is not the right place for it } void CodeEditorExtensionManager::setTabView(QQuickItem* _tabView) diff --git a/mix/CodeEditorExtensionManager.h b/mix/CodeEditorExtensionManager.h index 46ee6569f..e910b62d3 100644 --- a/mix/CodeEditorExtensionManager.h +++ b/mix/CodeEditorExtensionManager.h @@ -43,7 +43,6 @@ class CodeEditorExtensionManager: public QObject { Q_OBJECT - Q_PROPERTY(QQuickItem* editor MEMBER m_editor WRITE setEditor) Q_PROPERTY(QQuickItem* tabView MEMBER m_tabView WRITE setTabView) Q_PROPERTY(QQuickItem* rightTabView MEMBER m_rightTabView WRITE setRightTabView) @@ -54,8 +53,6 @@ public: void initExtensions(); /// Initialize extension. void initExtension(std::shared_ptr); - /// Set current text editor. - void setEditor(QQuickItem*); /// Set current tab view void setTabView(QQuickItem*); /// Set current right tab view. @@ -66,11 +63,9 @@ private slots: void applyCodeHighlight(); private: - QQuickItem* m_editor; QVector> m_features; QQuickItem* m_tabView; QQuickItem* m_rightTabView; - QTextDocument* m_doc; AppContext* m_appContext; void loadEditor(QQuickItem* _editor); }; diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 2d37422a9..4ecbc9c08 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -25,20 +25,23 @@ #include #include #include +#include #include "FileIo.h" using namespace dev::mix; -void FileIo::makeDir(QString const& _path) +void FileIo::makeDir(QString const& _url) { - QDir dirPath(_path); + QUrl url(_url); + QDir dirPath(url.path()); if (!dirPath.exists()) dirPath.mkpath(dirPath.path()); } -QString FileIo::readFile(QString const& _path) +QString FileIo::readFile(QString const& _url) { - QFile file(_path); + QUrl url(_url); + QFile file(url.path()); if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream stream(&file); @@ -46,23 +49,27 @@ QString FileIo::readFile(QString const& _path) return data; } else - throw std::runtime_error(tr("Error reading file %1").arg(_path).toStdString()); + error(tr("Error reading file %1").arg(_url)); + return QString(); } -void FileIo::writeFile(QString const& _path, QString const& _data) +void FileIo::writeFile(QString const& _url, QString const& _data) { - QFile file(_path); + QUrl url(_url); + QFile file(url.path()); if(file.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream stream(&file); stream << _data; } else - throw std::runtime_error(tr("Error writing file %1").arg(_path).toStdString()); + error(tr("Error writing file %1").arg(_url)); } -void FileIo::copyFile(QString const& _sourcePath, QString const& _destPath) +void FileIo::copyFile(QString const& _sourceUrl, QString const& _destUrl) { - if (!QFile::copy(_sourcePath, _destPath)) - throw std::runtime_error(tr("Error copying file %1 to %2").arg(_sourcePath).arg(_destPath).toStdString()); + QUrl sourceUrl(_sourceUrl); + QUrl destUrl(_destUrl); + if (!QFile::copy(sourceUrl.path(), destUrl.path())) + error(tr("Error copying file %1 to %2").arg(_sourceUrl).arg(_destUrl)); } diff --git a/mix/FileIo.h b/mix/FileIo.h index ed1326037..83352476b 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -34,15 +34,19 @@ class FileIo : public QObject { Q_OBJECT +signals: + /// Signalled in case of IO error + void error(QString const& _errorText); + public: - /// Create a directory if it does not exist. Throws on failure. - Q_INVOKABLE void makeDir(QString const& _path); - /// Read file contents to a string. Throws on failure. - Q_INVOKABLE QString readFile(QString const& _path); - /// Write contents to a file. Throws on failure. - Q_INVOKABLE void writeFile(QString const& _path, QString const& _data); - /// Copy a file from _sourcePath to _destPath. Throws on failure. - Q_INVOKABLE void copyFile(QString const& _sourcePath, QString const& _destPath); + /// Create a directory if it does not exist. Signals on failure. + Q_INVOKABLE void makeDir(QString const& _url); + /// Read file contents to a string. Signals on failure. + Q_INVOKABLE QString readFile(QString const& _url); + /// Write contents to a file. Signals on failure. + Q_INVOKABLE void writeFile(QString const& _url, QString const& _data); + /// Copy a file from _sourcePath to _destPath. Signals on failure. + Q_INVOKABLE void copyFile(QString const& _sourceUrl, QString const& _destUrl); }; } diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index 5cf71aa7d..b5226b90c 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -35,6 +35,7 @@ MixApplication::MixApplication(int _argc, char* _argv[]): qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); QObject::connect(this, SIGNAL(lastWindowClosed()), context(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff m_engine->load(QUrl("qrc:/qml/main.qml")); + //m_engine->load(QUrl("qrc:/qml/ProjectModel.qml")); m_appContext->loadProject(); } diff --git a/mix/qml.qrc b/mix/qml.qrc index a6215b243..53a2d1ae7 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -15,5 +15,8 @@ qml/js/Debugger.js qml/NewProjectDialog.qml qml/ProjectModel.qml + qml/CodeEditorModel.qml + qml/CodeEditor.qml + qml/CodeEditorView.qml diff --git a/mix/qml/CodeEditor.qml b/mix/qml/CodeEditor.qml new file mode 100644 index 000000000..77e60ee66 --- /dev/null +++ b/mix/qml/CodeEditor.qml @@ -0,0 +1,81 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.1 + +Component { + Item { + signal editorTextChanged + + function setText(text) { + codeEditor.text = text; + } + + function getText() { + return codeEditor.text; + } + + anchors.fill: parent + id: contentView + width: parent.width + height: parent.height * 0.7 + Rectangle { + id: lineColumn + property int rowHeight: codeEditor.font.pixelSize + 3 + color: "#202020" + width: 50 + height: parent.height + Column { + y: -codeEditor.flickableItem.contentY + 4 + width: parent.width + Repeater { + model: Math.max(codeEditor.lineCount + 2, (lineColumn.height/lineColumn.rowHeight)) + delegate: Text { + id: text + color: codeEditor.textColor + font: codeEditor.font + width: lineColumn.width - 4 + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + height: lineColumn.rowHeight + renderType: Text.NativeRendering + text: index + 1 + } + } + } + } + + TextArea { + id: codeEditor + textColor: "#EEE8D5" + style: TextAreaStyle { + backgroundColor: "#002B36" + } + + anchors.left: lineColumn.right + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + wrapMode: TextEdit.NoWrap + frameVisible: false + + height: parent.height + font.family: "Monospace" + font.pointSize: 12 + width: parent.width + + tabChangesFocus: false + Keys.onPressed: { + if (event.key === Qt.Key_Tab) { + codeEditor.insert(codeEditor.cursorPosition, "\t"); + event.accepted = true; + } + } + onTextChanged: { + editorTextChanged(); + } + + } + } +} diff --git a/mix/qml/CodeEditorModel.qml b/mix/qml/CodeEditorModel.qml new file mode 100644 index 000000000..c696272ce --- /dev/null +++ b/mix/qml/CodeEditorModel.qml @@ -0,0 +1,13 @@ +pragma Singleton + +import QtQuick 2.0 +import QtQuick.Window 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Dialogs 1.1 + +Item { + id: codeEditorModel + + property var codeDocuments: [] +} diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml new file mode 100644 index 000000000..9edc81ed9 --- /dev/null +++ b/mix/qml/CodeEditorView.qml @@ -0,0 +1,80 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import org.ethereum.qml.ProjectModel 1.0 + +Item { + + property string currentDocumentId: "" + + function getDocumentText(documentId) { + for (i = 0; i < editorListModel.count; i++) { + if (editorListModel.get(i).documentId === documentId) { + return editors.itemAt(i).getDocumentText(); + } + } + return ""; + } + + function openDocument(document) { + loadDocument(document); + currentDocumentId = document.documentId; + } + + function loadDocument(document) { + for (var i = 0; i < editorListModel.count; i++) + if (editorListModel.get(i).documentId === document.documentId) + return; //already open + + editorListModel.append(document); + } + + function doLoadDocument(editor, document) { + var data = fileIo.readFile(document.path); + if (document.isContract) + editor.onEditorTextChanged.connect(function() { + codeModel.registerCodeChange(editor.getText()); + }); + editor.setText(data); + } + + Connections { + target: ProjectModel + onDocumentOpen: { + openDocument(document); + } + } + + CodeEditor { + id: codeEditor + } + + Repeater { + id: editors + model: editorListModel + delegate: Loader { + active: false; + asynchronous: true + anchors.fill: parent + sourceComponent: codeEditor + visible: (currentDocumentId === editorListModel.get(index).documentId) + onVisibleChanged: { + loadIfNotLoaded() + } + Component.onCompleted: { + loadIfNotLoaded() + } + onLoaded: { doLoadDocument(item, editorListModel.get(index)) } + + function loadIfNotLoaded () { + if(visible && !active) { + active = true; + } + } + } + } + ListModel { + id: editorListModel + } +} diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 6cd2f5baa..5376be49d 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -22,80 +22,21 @@ Rectangle { anchors.fill: parent ProjectList { - anchors.left: parent.left width: parent.width * 0.2 height: parent.height - Layout.minimumWidth: 20 + Layout.minimumWidth: 200 } SplitView { //anchors.fill: parent width: parent.width * 0.6 orientation: Qt.Vertical - Rectangle { - anchors.top: parent.top - id: contentView - width: parent.width - height: parent.height * 0.7 - - Item { - anchors.fill: parent - Rectangle { - id: lineColumn - property int rowHeight: codeEditor.font.pixelSize + 3 - color: "#202020" - width: 50 - height: parent.height - Column { - y: -codeEditor.flickableItem.contentY + 4 - width: parent.width - Repeater { - model: Math.max(codeEditor.lineCount + 2, (lineColumn.height/lineColumn.rowHeight)) - delegate: Text { - id: text - color: codeEditor.textColor - font: codeEditor.font - width: lineColumn.width - 4 - horizontalAlignment: Text.AlignRight - verticalAlignment: Text.AlignVCenter - height: lineColumn.rowHeight - renderType: Text.NativeRendering - text: index + 1 - } - } - } - } - - TextArea { - id: codeEditor - textColor: "#EEE8D5" - style: TextAreaStyle { - backgroundColor: "#002B36" - } + CodeEditorView { + height: parent.height * 0.7 + anchors.top: parent.top + width: parent.width + } - anchors.left: lineColumn.right - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - wrapMode: TextEdit.NoWrap - frameVisible: false - - height: parent.height - font.family: "Monospace" - font.pointSize: 12 - width: parent.width - //anchors.centerIn: parent - tabChangesFocus: false - Keys.onPressed: { - if (event.key === Qt.Key_Tab) { - codeEditor.insert(codeEditor.cursorPosition, "\t"); - event.accepted = true; - } - } - } - } - - } Rectangle { anchors.bottom: parent.bottom id: contextualView @@ -126,7 +67,6 @@ Rectangle { CodeEditorExtensionManager { tabView: contextualTabs rightTabView: rightPaneTabs - editor: codeEditor } } } diff --git a/mix/qml/NewProjectDialog.qml b/mix/qml/NewProjectDialog.qml index b0853ba26..7bba58418 100644 --- a/mix/qml/NewProjectDialog.qml +++ b/mix/qml/NewProjectDialog.qml @@ -14,7 +14,7 @@ Window { visible: false property alias projectTitle : titleField.text - property alias projectPath : pathField.text + readonly property string projectPath : "file://" + pathField.text signal accepted function open() { @@ -83,10 +83,10 @@ Window { title: qsTr("Please choose a path for the project") selectFolder: true onAccepted: { - var u = createProjectFileDialog.fileUrl.toString(); - if (u.indexOf("file://") == 0) - u = u.substring(7, u.length) - pathField.text = u; - } + var u = createProjectFileDialog.fileUrl.toString(); + if (u.indexOf("file://") == 0) + u = u.substring(7, u.length) + pathField.text = u; + } } } diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index 60f1de898..77810931c 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -6,8 +6,16 @@ import org.ethereum.qml.ProjectModel 1.0 Item { ListView { + id: projectList model: ProjectModel.listModel + anchors.fill: parent delegate: renderDelegate + highlight: Rectangle { + color: "lightsteelblue"; + } + highlightFollowsCurrentItem: true + focus: true + clip: true } Component { @@ -21,19 +29,23 @@ Item { Text { Layout.fillWidth: true Layout.fillHeight: true - text: title + text: name font.pointSize: 12 verticalAlignment: Text.AlignBottom } } + MouseArea { + id: mouseArea + z: 1 + hoverEnabled: false + anchors.fill: parent + + onClicked:{ + projectList.currentIndex = index; + ProjectModel.documentOpen(ProjectModel.listModel.get(index)); + } + } } } - Action { - id: createProjectAction - text: qsTr("&New project") - shortcut: "Ctrl+N" - enabled: true; - onTriggered: ProjectModel.createProject(); - } } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 26896ea5f..f8217353d 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -12,8 +12,9 @@ Item { signal projectClosed signal projectLoaded + signal documentOpen(var document) - property bool isEmpty: projectFile === "" + property bool isEmpty: (projectFile === "") readonly property string projectFileName: ".mix" property bool haveUnsavedChanges: false @@ -30,24 +31,29 @@ Item { newProjectDialog.open(); } + function browseProject() { + openProjectFileDialog.open(); + } + function closeProject() { - console.log("closing project"); - if (haveUnsavedChanges) - saveMessageDialog.open(); - else - doCloseProject(); + if (!isEmpty) { + console.log("closing project"); + if (haveUnsavedChanges) + saveMessageDialog.open(); + else + doCloseProject(); + } } function saveProject() { if (!isEmpty) { var json = JSON.stringify(projectData); - fileIo.writeFile(projectFile, json) + fileIo.writeFile(projectFile, json); } } function loadProject(path) { - if (!isEmpty) - closeProject(); + closeProject(); console.log("loading project at " + path); var json = fileIo.readFile(path); projectData = JSON.parse(json); @@ -55,14 +61,35 @@ Item { if (!projectData.files) projectData.files = []; - for(var i = 0; i < projectData.files; i++) { + for(var i = 0; i < projectData.files.length; i++) { var p = projectData.files[i]; - projectListModel.append({ - path: p, - name: p.substring(p.lastIndexOf("/") + 1, p.length) - }); + addFile(p); } - onProjectLoaded(); + projectSettings.lastProjectPath = projectFile; + projectLoaded(); + } + + function addExistingFile() { + addExistingFileDialog().open(); + } + + function addProjectFiles(files) { + for(var i = 0; i < files.length; i++) + addFile(files[i]); + } + + function addFile(file) { + var p = file; + var fileData = { + contract: false, + path: p, + name: p.substring(p.lastIndexOf("/") + 1, p.length), + documentId: p, + isText: true, + isContract: p.substring(p.length - 4, p.length) === ".sol", + }; + + projectListModel.append(fileData); } function doCloseProject() { @@ -73,25 +100,39 @@ Item { } function doCreateProject(title, path) { - if (!isEmpty) - closeProject(); + closeProject(); console.log("creating project " + title + " at " + path); if (path[path.length - 1] !== "/") path += "/"; var dirPath = path + title; fileIo.makeDir(dirPath); var projectFile = dirPath + "/" + projectFileName; - fileIo.writeFile(projectFile, ""); + + var indexFile = dirPath + "/index.html"; + var contractsFile = dirPath + "/contracts.sol"; + var projectData = { + files: [ indexFile, contractsFile ] + }; + + fileIo.writeFile(indexFile, ""); + fileIo.writeFile(contractsFile, "contract MyContract {}"); + var json = JSON.stringify(projectData); + fileIo.writeFile(projectFile, json); loadProject(projectFile); } + Component.onCompleted: { + if (projectSettings.lastProjectPath) + loadProject(projectSettings.lastProjectPath) + } + NewProjectDialog { id: newProjectDialog visible: false onAccepted: { var title = newProjectDialog.projectTitle; var path = newProjectDialog.projectPath; - projectModel.doCreateProject(title, path); + doCreateProject(title, path); } } @@ -114,27 +155,33 @@ Item { id: projectListModel } - Component { - id: renderDelegate - Item { - id: wrapperItem - height: 20 - width: parent.width - RowLayout { - anchors.fill: parent - Text { - Layout.fillWidth: true - Layout.fillHeight: true - text: title - font.pointSize: 12 - verticalAlignment: Text.AlignBottom - } - } - } - } - Settings { id: projectSettings property string lastProjectPath; } + + FileDialog { + id: openProjectFileDialog + visible: false + title: qsTr("Open a project") + selectFolder: true + onAccepted: { + var path = openProjectFileDialog.fileUrl.toString(); + path += "/" + projectFileName; + loadProject(path); + } + } + + FileDialog { + id: addExistingFileDialog + visible: false + title: qsTr("Add a file") + selectFolder: false + onAccepted: { + var paths = openProjectFileDialog.fileUrls; + addProjectFiles(paths); + } + } + + } diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index ceed6513b..67d81747a 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -21,6 +21,8 @@ Rectangle { stateListModel.clear(); } onProjectLoaded: { + if (!target.projectData.states) + target.projectData.states = []; var items = target.projectData.states; for(var i = 0; i < items.length; i++) { stateListModel.append(items[i]); diff --git a/mix/qml/main.qml b/mix/qml/main.qml index bba7c9088..290649048 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -5,6 +5,7 @@ import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.1 import CodeEditorExtensionManager 1.0 +import org.ethereum.qml.ProjectModel 1.0 ApplicationWindow { id: mainApplication @@ -18,6 +19,12 @@ ApplicationWindow { menuBar: MenuBar { Menu { title: qsTr("File") + MenuItem { action: createProjectAction } + MenuItem { action: openProjectAction } + MenuItem { action: addExistingFileAction } + MenuItem { action: addNewJsFileAction } + MenuItem { action: addNewHtmlFileAction } + MenuItem { action: addNewContractAction } MenuItem { text: qsTr("Exit") onTriggered: Qt.quit(); @@ -62,5 +69,51 @@ ApplicationWindow { onTriggered: debugModel.resetState(); } + Action { + id: createProjectAction + text: qsTr("&New project") + shortcut: "Ctrl+N" + enabled: true; + onTriggered: ProjectModel.createProject(); + } + + Action { + id: openProjectAction + text: qsTr("&Open project") + shortcut: "Ctrl+O" + enabled: true; + onTriggered: ProjectModel.browseProject(); + } + + Action { + id: addNewJsFileAction + text: qsTr("New JavaScript file") + shortcut: "Ctrl+Alt+J" + enabled: !ProjectModel.isEmpty + onTriggered: ProjectModel.addJsFile(); + } + Action { + id: addNewHtmlFileAction + text: qsTr("New HTML file") + shortcut: "Ctrl+Alt+H" + enabled: !ProjectModel.isEmpty + onTriggered: ProjectModel.addHtmlFile(); + } + + Action { + id: addNewContractAction + text: qsTr("New contract") + shortcut: "Ctrl+Alt+C" + enabled: !ProjectModel.isEmpty + onTriggered: ProjectModel.addContract(); + } + + Action { + id: addExistingFileAction + text: qsTr("Add existing file") + shortcut: "Ctrl+Alt+A" + enabled: !ProjectModel.isEmpty + onTriggered: ProjectModel.addExistingFile(); + } } 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 508/588] 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 509/588] 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 510/588] 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 511/588] 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 0933a79ab84c0a99ede790ec19ba44439aa1aff3 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 9 Jan 2015 16:38:26 +0100 Subject: [PATCH 512/588] missing fromAscii --- dist/ethereum.js | 3 ++- dist/ethereum.js.map | 4 ++-- dist/ethereum.min.js | 2 +- lib/abi.js | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index b768f88a4..3e5bd3beb 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -268,7 +268,8 @@ var methodSignature = function (json, name) { result += inputTypes.join(','); result += ')'; - return web3.sha3(result); + return web3.sha3(web3.fromAscii(result)); + //return web3.sha3(result); }; module.exports = { diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index 4f4d3e675..c22c91db6 100644 --- a/dist/ethereum.js.map +++ b/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;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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(result);\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\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 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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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 //return web3.sha3(result);\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\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 extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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/dist/ethereum.min.js b/dist/ethereum.min.js index cbf0464a4..08ae29388 100644 --- a/dist/ethereum.min.js +++ b/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 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: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;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?32: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,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return 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: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;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?32: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: Fri, 9 Jan 2015 16:40:55 +0100 Subject: [PATCH 513/588] rerun gulp --- dist/ethereum.js | 1 - dist/ethereum.js.map | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index 3e5bd3beb..30684dbf4 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -269,7 +269,6 @@ var methodSignature = function (json, name) { result += ')'; return web3.sha3(web3.fromAscii(result)); - //return web3.sha3(result); }; module.exports = { diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index c22c91db6..db5f7342c 100644 --- a/dist/ethereum.js.map +++ b/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;;ACtRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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 //return web3.sha3(result);\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n methodSignature: methodSignature\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 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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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 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 extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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", 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 514/588] 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 515/588] 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 47687cf085196e2e4fa7ec42ff426f241dae10c5 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 9 Jan 2015 17:27:56 +0100 Subject: [PATCH 516/588] default padding changed to 0 --- dist/ethereum.js | 2 +- dist/ethereum.js.map | 2 +- dist/ethereum.min.js | 2 +- lib/web3.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index 30684dbf4..26de2c02e 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -855,7 +855,7 @@ var web3 = { }, fromAscii: function(str, pad) { - pad = pad === undefined ? 32 : pad; + pad = pad === undefined ? 0 : pad; var hex = this.toHex(str); while(hex.length < pad*2) hex += "00"; diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index db5f7342c..bb29b435d 100644 --- a/dist/ethereum.js.map +++ b/dist/ethereum.js.map @@ -22,7 +22,7 @@ "/*\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 extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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", "/*\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 qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 32 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nif (typeof(module) !== \"undefined\")\n module.exports = web3;\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nif (typeof(module) !== \"undefined\")\n module.exports = web3;\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 websocket.js\n * @authors:\n * Jeffrey Wilcke \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 WebSocket = require('ws'); // jshint ignore:line\n*/}\n\nvar WebSocketProvider = function(host) {\n // onmessage handlers\n this.handlers = [];\n // queue will be filled with messages if send is invoked before the ws is ready\n this.queued = [];\n this.ready = false;\n\n this.ws = new WebSocket(host);\n\n var self = this;\n this.ws.onmessage = function(event) {\n for(var i = 0; i < self.handlers.length; i++) {\n self.handlers[i].call(self, JSON.parse(event.data), event);\n }\n };\n\n this.ws.onopen = function() {\n self.ready = true;\n\n for(var i = 0; i < self.queued.length; i++) {\n // Resend\n self.send(self.queued[i]);\n }\n };\n};\n\nWebSocketProvider.prototype.send = function(payload) {\n if(this.ready) {\n var data = JSON.stringify(payload);\n\n this.ws.send(data);\n } else {\n this.queued.push(payload);\n }\n};\n\nWebSocketProvider.prototype.onMessage = function(handler) {\n this.handlers.push(handler);\n};\n\nWebSocketProvider.prototype.unload = function() {\n this.ws.close();\n};\nObject.defineProperty(WebSocketProvider.prototype, \"onmessage\", {\n set: function(provider) { this.onMessage(provider); }\n});\n\nif (typeof(module) !== \"undefined\")\n module.exports = WebSocketProvider;\n", "var web3 = require('./lib/web3');\nweb3.providers.WebSocketProvider = require('./lib/websocket');\nweb3.providers.HttpRpcProvider = require('./lib/httprpc');\nweb3.providers.QtProvider = require('./lib/qt');\nweb3.providers.AutoProvider = require('./lib/autoprovider');\nweb3.contract = require('./lib/contract');\n\nmodule.exports = web3;\n" ] diff --git a/dist/ethereum.min.js b/dist/ethereum.min.js index 08ae29388..a0054b65e 100644 --- a/dist/ethereum.min.js +++ b/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 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: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;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?32: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,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return 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: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;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: Fri, 9 Jan 2015 00:58:32 +0100 Subject: [PATCH 517/588] Padding for ABI types. --- libsolidity/Compiler.cpp | 13 +-- libsolidity/CompilerUtils.cpp | 19 ++-- libsolidity/CompilerUtils.h | 15 +++- libsolidity/ExpressionCompiler.cpp | 27 +++--- libsolidity/ExpressionCompiler.h | 6 +- libsolidity/Types.h | 3 +- test/SolidityEndToEndTest.cpp | 135 ++++++++++++++--------------- test/solidityExecutionFramework.h | 41 ++++++--- 8 files changed, 143 insertions(+), 116 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 4e5b7f558..c7d063eab 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -95,7 +95,7 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor) // copy constructor arguments from code to memory and then to stack, they are supplied after the actual program unsigned argumentSize = 0; for (ASTPointer const& var: _constructor.getParameters()) - argumentSize += var->getType()->getCalldataEncodedSize(); + argumentSize += CompilerUtils::getPaddedSize(var->getType()->getCalldataEncodedSize()); if (argumentSize > 0) { m_context << u256(argumentSize); @@ -159,9 +159,9 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(var->getLocation()) << errinfo_comment("Type " + var->getType()->toString() + " not yet supported.")); - bool leftAligned = var->getType()->getCategory() == Type::Category::STRING; - CompilerUtils(m_context).loadFromMemory(dataOffset, numBytes, leftAligned, !_fromMemory); - dataOffset += numBytes; + bool const leftAligned = var->getType()->getCategory() == Type::Category::STRING; + bool const padToWords = true; + dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, numBytes, leftAligned, !_fromMemory, padToWords); } return dataOffset; } @@ -181,10 +181,11 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function) << errinfo_sourceLocation(parameters[i]->getLocation()) << errinfo_comment("Type " + paramType.toString() + " not yet supported.")); CompilerUtils(m_context).copyToStackTop(stackDepth, paramType); + ExpressionCompiler::appendTypeConversion(m_context, paramType, paramType, true); bool const leftAligned = paramType.getCategory() == Type::Category::STRING; - CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned); + bool const padToWords = true; + dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned, padToWords); stackDepth -= paramType.getSizeOnStack(); - dataOffset += numBytes; } // note that the stack is not cleaned up here m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN; diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index a5254b421..3101c1b44 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -33,17 +33,21 @@ namespace solidity const unsigned int CompilerUtils::dataStartOffset = 4; -void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, bool _fromCalldata) +unsigned CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, + bool _fromCalldata, bool _padToWordBoundaries) { if (_bytes == 0) { m_context << u256(0); - return; + return 0; } eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD; solAssert(_bytes <= 32, "Memory load of more than 32 bytes requested."); - if (_bytes == 32) + if (_bytes == 32 || _padToWordBoundaries) + { m_context << u256(_offset) << load; + return 32; + } else { // load data and add leading or trailing zeros by dividing/multiplying depending on alignment @@ -54,21 +58,24 @@ void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _left m_context << u256(_offset) << load << eth::Instruction::DIV; if (_leftAligned) m_context << eth::Instruction::MUL; + return _bytes; } } -void CompilerUtils::storeInMemory(unsigned _offset, unsigned _bytes, bool _leftAligned) +unsigned CompilerUtils::storeInMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, + bool _padToWordBoundaries) { if (_bytes == 0) { m_context << eth::Instruction::POP; - return; + return 0; } solAssert(_bytes <= 32, "Memory store of more than 32 bytes requested."); - if (_bytes != 32 && !_leftAligned) + if (_bytes != 32 && !_leftAligned && !_padToWordBoundaries) // shift the value accordingly before storing m_context << (u256(1) << ((32 - _bytes) * 8)) << eth::Instruction::MUL; m_context << u256(_offset) << eth::Instruction::MSTORE; + return _padToWordBoundaries ? 32 : _bytes; } void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index 6bd8d3155..b5a695282 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -40,12 +40,23 @@ public: /// @param _bytes number of bytes to load /// @param _leftAligned if true, store left aligned on stack (otherwise right aligned) /// @param _fromCalldata if true, load from calldata, not from memory - void loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false, bool _fromCalldata = false); + /// @param _padToWordBoundaries if true, assume the data is padded to word (32 byte) boundaries + /// @returns the number of bytes consumed in memory (can be different from _bytes if + /// _padToWordBoundaries is true) + unsigned loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false, + bool _fromCalldata = false, bool _padToWordBoundaries = false); /// Stores data from stack in memory. /// @param _offset offset in memory /// @param _bytes number of bytes to store /// @param _leftAligned if true, data is left aligned on stack (otherwise right aligned) - void storeInMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false); + /// @param _padToWordBoundaries if true, pad the data to word (32 byte) boundaries + /// @returns the number of bytes written to memory (can be different from _bytes if + /// _padToWordBoundaries is true) + unsigned storeInMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false, + bool _padToWordBoundaries = false); + /// @returns _size rounded up to the next multiple of 32 (the number of bytes occupied in the + /// padded calldata) + static unsigned getPaddedSize(unsigned _size) { return ((_size + 31) / 32) * 32; } /// Moves the value that is at the top of the stack to a stack variable. void moveToStackVariable(VariableDeclaration const& _variable); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 5667098db..b12b8e675 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -41,11 +41,11 @@ void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression _expression.accept(compiler); } -void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, - Type const& _typeOnStack, Type const& _targetType) +void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, + Type const& _targetType, bool _cleanupNeeded) { ExpressionCompiler compiler(_context); - compiler.appendTypeConversion(_typeOnStack, _targetType); + compiler.appendTypeConversion(_typeOnStack, _targetType, _cleanupNeeded); } bool ExpressionCompiler::visit(Assignment const& _assignment) @@ -295,7 +295,6 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) FunctionCallOptions options; options.bare = true; options.obtainAddress = [&]() { m_context << contractAddress; }; - options.packDensely = false; appendExternalFunctionCall(function, arguments, options); break; } @@ -327,15 +326,15 @@ bool ExpressionCompiler::visit(NewExpression const& _newExpression) for (unsigned i = 0; i < arguments.size(); ++i) { arguments[i]->accept(*this); - appendTypeConversion(*arguments[i]->getType(), *types[i]); + appendTypeConversion(*arguments[i]->getType(), *types[i], true); unsigned const numBytes = types[i]->getCalldataEncodedSize(); if (numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(arguments[i]->getLocation()) << errinfo_comment("Type " + types[i]->toString() + " not yet supported.")); bool const leftAligned = types[i]->getCategory() == Type::Category::STRING; - CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned); - dataOffset += numBytes; + bool const padToWords = true; + dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned, padToWords); } // size, offset, endowment m_context << u256(dataOffset) << u256(0) << u256(0) << eth::Instruction::CREATE; @@ -634,22 +633,20 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio { _arguments[i]->accept(*this); Type const& type = *_functionType.getParameterTypes()[i]; - appendTypeConversion(*_arguments[i]->getType(), type); - unsigned const numBytes = _options.packDensely ? type.getCalldataEncodedSize() : 32; + appendTypeConversion(*_arguments[i]->getType(), type, true); + unsigned const numBytes = type.getCalldataEncodedSize(); if (numBytes == 0 || numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_arguments[i]->getLocation()) << errinfo_comment("Type " + type.toString() + " not yet supported.")); bool const leftAligned = type.getCategory() == Type::Category::STRING; - CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned); - dataOffset += numBytes; + bool const padToWords = true; + dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned, padToWords); } //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : _functionType.getReturnParameterTypes().front().get(); - unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0; - if (!_options.packDensely && retSize > 0) - retSize = 32; + 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) @@ -666,7 +663,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio if (retSize > 0) { bool const leftAligned = firstType->getCategory() == Type::Category::STRING; - CompilerUtils(m_context).loadFromMemory(0, retSize, leftAligned); + CompilerUtils(m_context).loadFromMemory(0, retSize, leftAligned, false, true); } } diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index abd7f7750..98f58c854 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -51,7 +51,8 @@ public: static void compileExpression(CompilerContext& _context, Expression const& _expression, bool _optimize = false); /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. - static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType); + static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, + Type const& _targetType, bool _cleanupNeeded = false); private: explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false): @@ -96,9 +97,6 @@ private: std::function obtainValue; /// If true, do not prepend function index to call data bool bare = false; - /// If false, use calling convention that all arguments and return values are packed as - /// 32 byte values with padding. - bool packDensely = true; }; /// Appends code to call a function of the given type with the given arguments. diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 8c800fa0d..69f69ef61 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -115,7 +115,8 @@ public: virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); } /// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding - /// is not a simple big-endian encoding or the type cannot be stored on the stack. + /// is not a simple big-endian encoding or the type cannot be stored in calldata. + /// Note that irrespective of this size, each calldata element is padded to a multiple of 32 bytes. virtual unsigned getCalldataEncodedSize() const { return 0; } /// @returns number of bytes required to hold this value in storage. /// For dynamically "allocated" types, it returns the size of the statically allocated head, diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index bc184dfca..7ed7ad594 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -331,10 +331,23 @@ BOOST_AUTO_TEST_CASE(packing_unpacking_types) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("run(bool,uint32,uint64)", fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) + BOOST_CHECK(callContractFunction("run(bool,uint32,uint64)", true, fromHex("0f0f0f0f"), fromHex("f0f0f0f0f0f0f0f0")) == fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f")); } +BOOST_AUTO_TEST_CASE(packing_signed_types) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(int8 y) {\n" + " uint8 x = 0xfa;\n" + " return int8(x);\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("run()") + == fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa")); +} + BOOST_AUTO_TEST_CASE(multiple_return_values) { char const* sourceCode = "contract test {\n" @@ -343,8 +356,7 @@ BOOST_AUTO_TEST_CASE(multiple_return_values) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("run(bool,uint256)", bytes(1, 1) + toBigEndian(u256(0xcd))) - == toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0))); + BOOST_CHECK(callContractFunction("run(bool,uint256)", true, 0xcd) == encodeArgs(0xcd, true, 0)); } BOOST_AUTO_TEST_CASE(short_circuiting) @@ -450,20 +462,8 @@ BOOST_AUTO_TEST_CASE(strings) " }\n" "}\n"; compileAndRun(sourceCode); - bytes expectation(32, 0); - expectation[0] = byte('a'); - expectation[1] = byte('b'); - expectation[2] = byte('c'); - expectation[3] = byte(0); - expectation[4] = byte(0xff); - expectation[5] = byte('_'); - expectation[6] = byte('_'); - BOOST_CHECK(callContractFunction("fixed()", bytes()) == expectation); - expectation = bytes(17, 0); - expectation[0] = 0; - expectation[1] = 2; - expectation[16] = 1; - BOOST_CHECK(callContractFunction("pipeThrough(string2,bool)", bytes({0x00, 0x02, 0x01})) == expectation); + BOOST_CHECK(callContractFunction("fixed()") == encodeArgs(string("abc\0\xff__", 7))); + BOOST_CHECK(callContractFunction("pipeThrough(string2,bool)", string("\0\x02", 2), true) == encodeArgs(string("\0\x2", 2), true)); } BOOST_AUTO_TEST_CASE(empty_string_on_stack) @@ -477,7 +477,7 @@ BOOST_AUTO_TEST_CASE(empty_string_on_stack) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("run(string0,uint8)", bytes(1, 0x02)) == bytes({0x00, 0x02, 0x61/*'a'*/, 0x62/*'b'*/, 0x63/*'c'*/, 0x00})); + BOOST_CHECK(callContractFunction("run(string0,uint8)", string(), byte(0x02)) == encodeArgs(0x2, string(""), string("abc\0"))); } BOOST_AUTO_TEST_CASE(state_smoke_test) @@ -495,14 +495,14 @@ BOOST_AUTO_TEST_CASE(state_smoke_test) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x00)) == toBigEndian(u256(0))); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x01)) == toBigEndian(u256(0))); - BOOST_CHECK(callContractFunction("set(uint8,uint256)", bytes(1, 0x00) + toBigEndian(u256(0x1234))) == bytes()); - BOOST_CHECK(callContractFunction("set(uint8,uint256)", bytes(1, 0x01) + toBigEndian(u256(0x8765))) == bytes()); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x00)) == toBigEndian(u256(0x1234))); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x01)) == toBigEndian(u256(0x8765))); - BOOST_CHECK(callContractFunction("set(uint8,uint256)", bytes(1, 0x00) + toBigEndian(u256(0x3))) == bytes()); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x00)) == toBigEndian(u256(0x3))); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x00)) == encodeArgs(0)); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x01)) == encodeArgs(0)); + BOOST_CHECK(callContractFunction("set(uint8,uint256)", byte(0x00), 0x1234) == encodeArgs()); + BOOST_CHECK(callContractFunction("set(uint8,uint256)", byte(0x01), 0x8765) == encodeArgs()); + BOOST_CHECK(callContractFunction("get(uint8)", byte( 0x00)) == encodeArgs(0x1234)); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x01)) == encodeArgs(0x8765)); + BOOST_CHECK(callContractFunction("set(uint8,uint256)", byte(0x00), 0x3) == encodeArgs()); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x00)) == encodeArgs(0x3)); } BOOST_AUTO_TEST_CASE(compound_assign) @@ -553,22 +553,21 @@ BOOST_AUTO_TEST_CASE(simple_mapping) "}"; compileAndRun(sourceCode); - // msvc seems to have problems with initializer-list, when there is only 1 param in the list - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x00)) == bytes(1, 0x00)); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x01)) == bytes(1, 0x00)); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0xa7)) == bytes(1, 0x00)); - callContractFunction("set(uint8,uint8)", bytes({0x01, 0xa1})); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x00)) == bytes(1, 0x00)); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x01)) == bytes(1, 0xa1)); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0xa7)) == bytes(1, 0x00)); - callContractFunction("set(uint8,uint8)", bytes({0x00, 0xef})); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x00)) == bytes(1, 0xef)); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x01)) == bytes(1, 0xa1)); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0xa7)) == bytes(1, 0x00)); - callContractFunction("set(uint8,uint8)", bytes({0x01, 0x05})); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x00)) == bytes(1, 0xef)); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0x01)) == bytes(1, 0x05)); - BOOST_CHECK(callContractFunction("get(uint8)", bytes(1, 0xa7)) == bytes(1, 0x00)); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0)) == encodeArgs(byte(0x00))); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x01)) == encodeArgs(byte(0x00))); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0xa7)) == encodeArgs(byte(0x00))); + callContractFunction("set(uint8,uint8)", byte(0x01), byte(0xa1)); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x00)) == encodeArgs(byte(0x00))); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x01)) == encodeArgs(byte(0xa1))); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0xa7)) == encodeArgs(byte(0x00))); + callContractFunction("set(uint8,uint8)", byte(0x00), byte(0xef)); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x00)) == encodeArgs(byte(0xef))); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x01)) == encodeArgs(byte(0xa1))); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0xa7)) == encodeArgs(byte(0x00))); + callContractFunction("set(uint8,uint8)", byte(0x01), byte(0x05)); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x00)) == encodeArgs(byte(0xef))); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0x01)) == encodeArgs(byte(0x05))); + BOOST_CHECK(callContractFunction("get(uint8)", byte(0xa7)) == encodeArgs(byte(0x00))); } BOOST_AUTO_TEST_CASE(mapping_state) @@ -736,9 +735,9 @@ BOOST_AUTO_TEST_CASE(structs) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("check()") == bytes(1, 0x00)); + BOOST_CHECK(callContractFunction("check()") == encodeArgs(false)); BOOST_CHECK(callContractFunction("set()") == bytes()); - BOOST_CHECK(callContractFunction("check()") == bytes(1, 0x01)); + BOOST_CHECK(callContractFunction("check()") == encodeArgs(true)); } BOOST_AUTO_TEST_CASE(struct_reference) @@ -764,9 +763,9 @@ BOOST_AUTO_TEST_CASE(struct_reference) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("check()") == bytes(1, 0x00)); + BOOST_CHECK(callContractFunction("check()") == encodeArgs(false)); BOOST_CHECK(callContractFunction("set()") == bytes()); - BOOST_CHECK(callContractFunction("check()") == bytes(1, 0x01)); + BOOST_CHECK(callContractFunction("check()") == encodeArgs(true)); } BOOST_AUTO_TEST_CASE(constructor) @@ -799,7 +798,7 @@ BOOST_AUTO_TEST_CASE(balance) " }\n" "}\n"; compileAndRun(sourceCode, 23); - BOOST_CHECK(callContractFunction("getBalance()") == toBigEndian(u256(23))); + BOOST_CHECK(callContractFunction("getBalance()") == encodeArgs(23)); } BOOST_AUTO_TEST_CASE(blockchain) @@ -812,7 +811,7 @@ BOOST_AUTO_TEST_CASE(blockchain) " }\n" "}\n"; compileAndRun(sourceCode, 27); - BOOST_CHECK(callContractFunction("someInfo()", bytes{0}, u256(28)) == toBigEndian(u256(28)) + bytes(20, 0) + toBigEndian(u256(1))); + BOOST_CHECK(callContractFunctionWithValue("someInfo()", 28) == encodeArgs(28, 0, 1)); } BOOST_AUTO_TEST_CASE(function_types) @@ -831,8 +830,8 @@ BOOST_AUTO_TEST_CASE(function_types) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("a(bool)", bytes{0}) == toBigEndian(u256(11))); - BOOST_CHECK(callContractFunction("a(bool)", bytes{1}) == toBigEndian(u256(12))); + BOOST_CHECK(callContractFunction("a(bool)", false) == encodeArgs(11)); + BOOST_CHECK(callContractFunction("a(bool)", true) == encodeArgs(12)); } BOOST_AUTO_TEST_CASE(send_ether) @@ -846,7 +845,7 @@ BOOST_AUTO_TEST_CASE(send_ether) u256 amount(130); compileAndRun(sourceCode, amount + 1); u160 address(23); - BOOST_CHECK(callContractFunction("a(address,uint256)", address, amount) == toBigEndian(u256(1))); + BOOST_CHECK(callContractFunction("a(address,uint256)", address, amount) == encodeArgs(1)); BOOST_CHECK_EQUAL(m_state.balance(address), amount); } @@ -1031,7 +1030,7 @@ BOOST_AUTO_TEST_CASE(ecrecover) u256 r("0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f"); u256 s("0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549"); u160 addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); - BOOST_CHECK(callContractFunction("a(hash256,uint8,hash256,hash256)", h, v, r, s) == toBigEndian(addr)); + BOOST_CHECK(callContractFunction("a(hash256,uint8,hash256,hash256)", h, v, r, s) == encodeArgs(addr)); } BOOST_AUTO_TEST_CASE(inter_contract_calls) @@ -1058,10 +1057,10 @@ BOOST_AUTO_TEST_CASE(inter_contract_calls) u160 const helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == toBigEndian(helperAddress)); + BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); u256 a(3456789); u256 b("0x282837623374623234aa74"); - BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == toBigEndian(a * b)); + BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == encodeArgs(a * b)); } BOOST_AUTO_TEST_CASE(inter_contract_calls_with_complex_parameters) @@ -1088,11 +1087,11 @@ BOOST_AUTO_TEST_CASE(inter_contract_calls_with_complex_parameters) u160 const helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == toBigEndian(helperAddress)); + BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); u256 a(3456789); u256 b("0x282837623374623234aa74"); - BOOST_REQUIRE(callContractFunction("callHelper(uint256,bool,uint256)", a, true, b) == toBigEndian(a * 3)); - BOOST_REQUIRE(callContractFunction("callHelper(uint256,bool,uint256)", a, false, b) == toBigEndian(b * 3)); + BOOST_REQUIRE(callContractFunction("callHelper(uint256,bool,uint256)", a, true, b) == encodeArgs(a * 3)); + BOOST_REQUIRE(callContractFunction("callHelper(uint256,bool,uint256)", a, false, b) == encodeArgs(b * 3)); } BOOST_AUTO_TEST_CASE(inter_contract_calls_accessing_this) @@ -1119,8 +1118,8 @@ BOOST_AUTO_TEST_CASE(inter_contract_calls_accessing_this) u160 const helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == toBigEndian(helperAddress)); - BOOST_REQUIRE(callContractFunction("callHelper()") == toBigEndian(helperAddress)); + BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); + BOOST_REQUIRE(callContractFunction("callHelper()") == encodeArgs(helperAddress)); } BOOST_AUTO_TEST_CASE(calls_to_this) @@ -1150,10 +1149,10 @@ BOOST_AUTO_TEST_CASE(calls_to_this) u160 const helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == toBigEndian(helperAddress)); + BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); u256 a(3456789); u256 b("0x282837623374623234aa74"); - BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == toBigEndian(a * b + 10)); + BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == encodeArgs(a * b + 10)); } BOOST_AUTO_TEST_CASE(inter_contract_calls_with_local_vars) @@ -1185,10 +1184,10 @@ BOOST_AUTO_TEST_CASE(inter_contract_calls_with_local_vars) u160 const helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == toBigEndian(helperAddress)); + BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); u256 a(3456789); u256 b("0x282837623374623234aa74"); - BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == toBigEndian(a * b + 9)); + BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == encodeArgs(a * b + 9)); } BOOST_AUTO_TEST_CASE(strings_in_calls) @@ -1215,8 +1214,8 @@ BOOST_AUTO_TEST_CASE(strings_in_calls) u160 const helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == toBigEndian(helperAddress)); - BOOST_CHECK(callContractFunction("callHelper(string2,bool)", bytes({0, 'a', 1})) == bytes({0, 'a', 0, 0, 0})); + BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); + BOOST_CHECK(callContractFunction("callHelper(string2,bool)", string("\0a", 2), true) == encodeArgs(string("\0a\0\0\0", 5))); } BOOST_AUTO_TEST_CASE(constructor_arguments) @@ -1241,8 +1240,8 @@ BOOST_AUTO_TEST_CASE(constructor_arguments) function getName() returns (string3 ret) { return h.getName(); } })"; compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("getFlag()") == bytes({byte(0x01)})); - BOOST_REQUIRE(callContractFunction("getName()") == bytes({'a', 'b', 'c'})); + BOOST_REQUIRE(callContractFunction("getFlag()") == encodeArgs(true)); + BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc")); } BOOST_AUTO_TEST_CASE(functions_called_by_constructor) @@ -1259,7 +1258,7 @@ BOOST_AUTO_TEST_CASE(functions_called_by_constructor) function setName(string3 _name) { name = _name; } })"; compileAndRun(sourceCode); - BOOST_REQUIRE(callContractFunction("getName()") == bytes({'a', 'b', 'c'})); + BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc")); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/solidityExecutionFramework.h b/test/solidityExecutionFramework.h index 5ef23fdb1..8d3c7e77c 100644 --- a/test/solidityExecutionFramework.h +++ b/test/solidityExecutionFramework.h @@ -32,9 +32,6 @@ namespace dev { -/// Provides additional overloads for toBigEndian to encode arguments and return values. -inline bytes toBigEndian(byte _value) { return bytes({_value}); } -inline bytes toBigEndian(bool _value) { return bytes({byte(_value)}); } namespace solidity { @@ -56,18 +53,20 @@ public: return m_output; } - bytes const& callContractFunction(std::string _sig, bytes const& _data = bytes(), - u256 const& _value = 0) + template + bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, + Args const&... _arguments) { + FixedHash<4> hash(dev::sha3(_sig)); - sendMessage(hash.asBytes() + _data, false, _value); + sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); return m_output; } template bytes const& callContractFunction(std::string _sig, Args const&... _arguments) { - return callContractFunction(_sig, argsToBigEndian(_arguments...)); + return callContractFunctionWithValue(_sig, 0, _arguments...); } template @@ -89,19 +88,33 @@ public: bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match." "\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult) + - "\nArgument: " + toHex(toBigEndian(argument))); + "\nArgument: " + toHex(encode(argument))); } } -private: - template - bytes argsToBigEndian(FirstArg const& _firstArg, Args const&... _followingArgs) const + static bytes encode(bool _value) { return encode(byte(_value)); } + static bytes encode(int _value) { return encode(u256(_value)); } + static bytes encode(char const* _value) { return encode(std::string(_value)); } + static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } + static bytes encode(u256 const& _value) { return toBigEndian(_value); } + static bytes encode(bytes const& _value, bool _padLeft = true) { - return toBigEndian(_firstArg) + argsToBigEndian(_followingArgs...); + bytes padding = bytes((32 - _value.size() % 32) % 32, 0); + return _padLeft ? padding + _value : _value + padding; } + static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } - bytes argsToBigEndian() const { return bytes(); } + template + static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) + { + return encode(_firstArg) + encodeArgs(_followingArgs...); + } + static bytes encodeArgs() + { + return bytes(); + } +private: template auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) -> typename std::enable_if::value, bytes>::type @@ -113,7 +126,7 @@ private: auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) -> typename std::enable_if::value, bytes>::type { - return toBigEndian(_cppFunction(_arguments...)); + return encode(_cppFunction(_arguments...)); } void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) From d9334abe89649cce0bb5407ace652a401865a653 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 7 Jan 2015 23:45:26 +0100 Subject: [PATCH 518/588] Correct type conversions. --- libsolidity/ExpressionCompiler.cpp | 47 +++++++++++++++++++++--------- test/SolidityEndToEndTest.cpp | 15 ++++++++++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 5667098db..33c10aa36 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -194,13 +194,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) solAssert(_functionCall.getArguments().size() == 1, ""); Expression const& firstArgument = *_functionCall.getArguments().front(); firstArgument.accept(*this); - if (firstArgument.getType()->getCategory() == Type::Category::CONTRACT && - _functionCall.getType()->getCategory() == Type::Category::INTEGER) - { - // explicit type conversion contract -> address, nothing to do. - } - else - appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); + appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); } else { @@ -250,13 +244,17 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) FunctionCallOptions options; options.bare = true; options.obtainAddress = [&]() { _functionCall.getExpression().accept(*this); }; - options.obtainValue = [&]() { arguments.front()->accept(*this); }; + options.obtainValue = [&]() + { + arguments.front()->accept(*this); + appendTypeConversion(*arguments.front()->getType(), + *function.getParameterTypes().front(), true); + }; appendExternalFunctionCall(FunctionType({}, {}, Location::EXTERNAL), {}, options); break; } case Location::SUICIDE: arguments.front()->accept(*this); - //@todo might not be necessary appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); m_context << eth::Instruction::SUICIDE; break; @@ -362,6 +360,8 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) break; case Type::Category::CONTRACT: { + appendTypeConversion(*_memberAccess.getExpression().getType(), + IntegerType(0, IntegerType::Modifier::ADDRESS), true); ContractType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); m_context << type.getFunctionIdentifier(member); break; @@ -592,15 +592,36 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con return; Type::Category stackTypeCategory = _typeOnStack.getCategory(); Type::Category targetTypeCategory = _targetType.getCategory(); - if (stackTypeCategory == Type::Category::INTEGER) + if (stackTypeCategory == Type::Category::INTEGER || stackTypeCategory == Type::Category::CONTRACT || + stackTypeCategory == Type::Category::INTEGER_CONSTANT) { solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, ""); - appendHighBitsCleanup(dynamic_cast(_typeOnStack)); + IntegerType addressType(0, IntegerType::Modifier::ADDRESS); + IntegerType const& targetType = targetTypeCategory == Type::Category::INTEGER + ? dynamic_cast(_targetType) : addressType; + if (stackTypeCategory == Type::Category::INTEGER_CONSTANT) + { + IntegerConstantType const& constType = dynamic_cast(_typeOnStack); + // We know that the stack is clean, we only have to clean for a narrowing conversion + // where cleanup is forced. + if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded) + appendHighBitsCleanup(targetType); + } + else + { + IntegerType const& typeOnStack = stackTypeCategory == Type::Category::INTEGER + ? dynamic_cast(_typeOnStack) : addressType; + // Widening: clean up according to source type width + // Non-widening and force: clean up according to target type bits + if (targetType.getNumBits() > typeOnStack.getNumBits()) + appendHighBitsCleanup(typeOnStack); + else if (_cleanupNeeded) + appendHighBitsCleanup(targetType); + } } - else if (stackTypeCategory == Type::Category::INTEGER_CONSTANT) - solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, ""); else if (stackTypeCategory == Type::Category::STRING) { + solAssert(targetTypeCategory == Type::Category::STRING, ""); // nothing to do, strings are high-order-bit-aligned //@todo clear lower-order bytes if we allow explicit conversion to shorter strings } diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index bc184dfca..baad4b42d 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -835,6 +835,21 @@ BOOST_AUTO_TEST_CASE(function_types) BOOST_CHECK(callContractFunction("a(bool)", bytes{1}) == toBigEndian(u256(12))); } +BOOST_AUTO_TEST_CASE(type_conversions_cleanup) +{ + // 22-byte integer converted to a contract (i.e. address, 20 bytes), converted to a 32 byte + // integer should drop the first two bytes + char const* sourceCode = R"( + contract Test { + function test() returns (uint ret) { return uint(address(Test(address(0x11223344556677889900112233445566778899001122)))); } + })"; + compileAndRun(sourceCode); + BOOST_REQUIRE(callContractFunction(0) == bytes({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, + 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22})); +} + + BOOST_AUTO_TEST_CASE(send_ether) { char const* sourceCode = "contract test {\n" From 08f556cd5a392e34551f468fa064771e8a09fbf3 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 7 Jan 2015 22:54:56 +0100 Subject: [PATCH 519/588] Contracts are Addresses. --- libsolidity/ExpressionCompiler.cpp | 20 ++++++++++++-------- libsolidity/Types.cpp | 15 +++++++++++---- libsolidity/Types.h | 9 +++++++-- test/SolidityEndToEndTest.cpp | 24 +++++++++++++++++++++--- 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 33c10aa36..e882c198f 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -345,6 +345,18 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) ASTString const& member = _memberAccess.getMemberName(); switch (_memberAccess.getExpression().getType()->getCategory()) { + case Type::Category::CONTRACT: + { + ContractType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); + u256 identifier = type.getFunctionIdentifier(member); + if (identifier != Invalid256) + { + appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::ADDRESS), true); + m_context << identifier; + break; + } + // fall-through to "integer" otherwise (address) + } case Type::Category::INTEGER: if (member == "balance") { @@ -358,14 +370,6 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); break; - case Type::Category::CONTRACT: - { - appendTypeConversion(*_memberAccess.getExpression().getType(), - IntegerType(0, IntegerType::Modifier::ADDRESS), true); - ContractType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); - m_context << type.getFunctionIdentifier(member); - break; - } case Type::Category::MAGIC: // we can ignore the kind of magic and only look at the name of the member if (member == "coinbase") diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index da042edb4..eda022ccb 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -424,15 +424,20 @@ TypePointer BoolType::binaryOperatorResult(Token::Value _operator, TypePointer c return TypePointer(); } -bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const +bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const { - if (isImplicitlyConvertibleTo(_convertTo)) + if (*this == _convertTo) return true; if (_convertTo.getCategory() == Category::INTEGER) return dynamic_cast(_convertTo).isAddress(); return false; } +bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const +{ + return isImplicitlyConvertibleTo(_convertTo) || _convertTo.getCategory() == Category::INTEGER; +} + bool ContractType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) @@ -459,7 +464,9 @@ MemberList const& ContractType::getMembers() const // We need to lazy-initialize it because of recursive references. if (!m_members) { - map> members; + // All address members and all interface functions + map> members(IntegerType::AddressMemberList.begin(), + IntegerType::AddressMemberList.end()); for (auto const& it: m_contract.getInterfaceFunctions()) members[it.second->getName()] = make_shared(*it.second, false); m_members.reset(new MemberList(members)); @@ -487,7 +494,7 @@ u256 ContractType::getFunctionIdentifier(string const& _functionName) const if (it->second->getName() == _functionName) return FixedHash<4>::Arith(it->first); - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Index of non-existing contract function requested.")); + return Invalid256; } bool StructType::operator==(Type const& _other) const diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 8c800fa0d..9f1c35842 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -179,10 +179,11 @@ public: bool isAddress() const { return m_modifier == Modifier::ADDRESS; } int isSigned() const { return m_modifier == Modifier::SIGNED; } + static const MemberList AddressMemberList; + private: int m_bits; Modifier m_modifier; - static const MemberList AddressMemberList; }; /** @@ -278,7 +279,9 @@ class ContractType: public Type public: virtual Category getCategory() const override { return Category::CONTRACT; } ContractType(ContractDefinition const& _contract): m_contract(_contract) {} - /// Contracts can be converted to themselves and to addresses. + /// Contracts can be implicitly converted to super classes and to addresses. + virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; + /// Contracts can be converted to themselves and to integers. virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool operator==(Type const& _other) const override; virtual u256 getStorageSize() const override; @@ -291,6 +294,8 @@ public: /// is not used, as this type cannot be the type of a variable or expression. std::shared_ptr const& getConstructorType() const; + /// @returns the identifier of the function with the given name or Invalid256 if such a name does + /// not exist. u256 getFunctionIdentifier(std::string const& _functionName) const; private: diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index baad4b42d..9f2e0d429 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -844,9 +844,9 @@ BOOST_AUTO_TEST_CASE(type_conversions_cleanup) function test() returns (uint ret) { return uint(address(Test(address(0x11223344556677889900112233445566778899001122)))); } })"; compileAndRun(sourceCode); - BOOST_REQUIRE(callContractFunction(0) == bytes({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, - 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22})); + BOOST_REQUIRE(callContractFunction("test()") == bytes({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, + 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22})); } @@ -1277,6 +1277,24 @@ BOOST_AUTO_TEST_CASE(functions_called_by_constructor) BOOST_REQUIRE(callContractFunction("getName()") == bytes({'a', 'b', 'c'})); } +BOOST_AUTO_TEST_CASE(contracts_as_addresses) +{ + char const* sourceCode = R"( + contract helper { + } + contract test { + helper h; + function test() { h = new helper(); h.send(5); } + function getBalance() returns (uint256 myBalance, uint256 helperBalance) { + myBalance = this.balance; + helperBalance = h.balance; + } + } + )"; + compileAndRun(sourceCode, 20); + BOOST_REQUIRE(callContractFunction("getBalance()") == toBigEndian(u256(20 - 5)) + toBigEndian(u256(5))); +} + BOOST_AUTO_TEST_SUITE_END() } From 1e3929d5adaa2340cc6b47b541526fad9fadceb0 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 9 Jan 2015 21:36:25 +0100 Subject: [PATCH 520/588] Coding style: Prefix for const variables. --- libsolidity/Compiler.cpp | 31 +++++++-------- libsolidity/ExpressionCompiler.cpp | 62 +++++++++++++++--------------- test/SolidityEndToEndTest.cpp | 38 +++++++++--------- 3 files changed, 67 insertions(+), 64 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index c7d063eab..782a7efe2 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -154,14 +154,15 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b //@todo this can be done more efficiently, saving some CALLDATALOAD calls for (ASTPointer const& var: _function.getParameters()) { - unsigned const numBytes = var->getType()->getCalldataEncodedSize(); - if (numBytes > 32) + unsigned const c_numBytes = var->getType()->getCalldataEncodedSize(); + if (c_numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(var->getLocation()) << errinfo_comment("Type " + var->getType()->toString() + " not yet supported.")); - bool const leftAligned = var->getType()->getCategory() == Type::Category::STRING; - bool const padToWords = true; - dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, numBytes, leftAligned, !_fromMemory, padToWords); + bool const c_leftAligned = var->getType()->getCategory() == Type::Category::STRING; + bool const c_padToWords = true; + dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, c_numBytes, c_leftAligned, + !_fromMemory, c_padToWords); } return dataOffset; } @@ -182,9 +183,9 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function) << errinfo_comment("Type " + paramType.toString() + " not yet supported.")); CompilerUtils(m_context).copyToStackTop(stackDepth, paramType); ExpressionCompiler::appendTypeConversion(m_context, paramType, paramType, true); - bool const leftAligned = paramType.getCategory() == Type::Category::STRING; - bool const padToWords = true; - dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned, padToWords); + bool const c_leftAligned = paramType.getCategory() == Type::Category::STRING; + bool const c_padToWords = true; + dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, c_leftAligned, c_padToWords); stackDepth -= paramType.getSizeOnStack(); } // note that the stack is not cleaned up here @@ -231,16 +232,16 @@ bool Compiler::visit(FunctionDefinition const& _function) // Note that the fact that the return arguments are of increasing index is vital for this // algorithm to work. - unsigned const argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters()); - unsigned const returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters()); - unsigned const localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables()); + unsigned const c_argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters()); + unsigned const c_returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters()); + unsigned const c_localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables()); vector stackLayout; - stackLayout.push_back(returnValuesSize); // target of return address - stackLayout += vector(argumentsSize, -1); // discard all arguments - for (unsigned i = 0; i < returnValuesSize; ++i) + stackLayout.push_back(c_returnValuesSize); // target of return address + stackLayout += vector(c_argumentsSize, -1); // discard all arguments + for (unsigned i = 0; i < c_returnValuesSize; ++i) stackLayout.push_back(i); - stackLayout += vector(localVariablesSize, -1); + stackLayout += vector(c_localVariablesSize, -1); while (stackLayout.back() != int(stackLayout.size() - 1)) if (stackLayout.back() < 0) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index b12b8e675..1ce5ca5bd 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -144,23 +144,23 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) Expression const& leftExpression = _binaryOperation.getLeftExpression(); Expression const& rightExpression = _binaryOperation.getRightExpression(); Type const& commonType = _binaryOperation.getCommonType(); - Token::Value const op = _binaryOperation.getOperator(); + Token::Value const c_op = _binaryOperation.getOperator(); - if (op == Token::AND || op == Token::OR) // special case: short-circuiting + if (c_op == Token::AND || c_op == Token::OR) // special case: short-circuiting appendAndOrOperatorCode(_binaryOperation); else if (commonType.getCategory() == Type::Category::INTEGER_CONSTANT) m_context << commonType.literalValue(nullptr); else { bool cleanupNeeded = commonType.getCategory() == Type::Category::INTEGER && - (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD); + (Token::isCompareOp(c_op) || c_op == Token::DIV || c_op == Token::MOD); // for commutative operators, push the literal as late as possible to allow improved optimization auto isLiteral = [](Expression const& _e) { return dynamic_cast(&_e) || _e.getType()->getCategory() == Type::Category::INTEGER_CONSTANT; }; - bool swap = m_optimize && Token::isCommutativeOp(op) && isLiteral(rightExpression) && !isLiteral(leftExpression); + bool swap = m_optimize && Token::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression); if (swap) { leftExpression.accept(*this); @@ -175,10 +175,10 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) leftExpression.accept(*this); appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); } - if (Token::isCompareOp(op)) - appendCompareOperatorCode(op, commonType); + if (Token::isCompareOp(c_op)) + appendCompareOperatorCode(c_op, commonType); else - appendOrdinaryBinaryOperatorCode(op, commonType); + appendOrdinaryBinaryOperatorCode(c_op, commonType); } // do not visit the child nodes, we already did that explicitly @@ -327,14 +327,15 @@ bool ExpressionCompiler::visit(NewExpression const& _newExpression) { arguments[i]->accept(*this); appendTypeConversion(*arguments[i]->getType(), *types[i], true); - unsigned const numBytes = types[i]->getCalldataEncodedSize(); - if (numBytes > 32) + 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 leftAligned = types[i]->getCategory() == Type::Category::STRING; - bool const padToWords = true; - dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned, padToWords); + 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; @@ -462,12 +463,12 @@ void ExpressionCompiler::endVisit(Literal const& _literal) void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryOperation) { - Token::Value const op = _binaryOperation.getOperator(); - solAssert(op == Token::OR || op == Token::AND, ""); + Token::Value const c_op = _binaryOperation.getOperator(); + solAssert(c_op == Token::OR || c_op == Token::AND, ""); _binaryOperation.getLeftExpression().accept(*this); m_context << eth::Instruction::DUP1; - if (op == Token::AND) + if (c_op == Token::AND) m_context << eth::Instruction::ISZERO; eth::AssemblyItem endLabel = m_context.appendConditionalJump(); m_context << eth::Instruction::POP; @@ -486,23 +487,23 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type else { IntegerType const& type = dynamic_cast(_type); - bool const isSigned = type.isSigned(); + bool const c_isSigned = type.isSigned(); switch (_operator) { case Token::GTE: - m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) + m_context << (c_isSigned ? eth::Instruction::SLT : eth::Instruction::LT) << eth::Instruction::ISZERO; break; case Token::LTE: - m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT) + m_context << (c_isSigned ? eth::Instruction::SGT : eth::Instruction::GT) << eth::Instruction::ISZERO; break; case Token::GT: - m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); + m_context << (c_isSigned ? eth::Instruction::SGT : eth::Instruction::GT); break; case Token::LT: - m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); + m_context << (c_isSigned ? eth::Instruction::SLT : eth::Instruction::LT); break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); @@ -525,7 +526,7 @@ void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) { IntegerType const& type = dynamic_cast(_type); - bool const isSigned = type.isSigned(); + bool const c_isSigned = type.isSigned(); switch (_operator) { @@ -539,10 +540,10 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty m_context << eth::Instruction::MUL; break; case Token::DIV: - m_context << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); + m_context << (c_isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); break; case Token::MOD: - m_context << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); + m_context << (c_isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); @@ -634,14 +635,15 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio _arguments[i]->accept(*this); Type const& type = *_functionType.getParameterTypes()[i]; appendTypeConversion(*_arguments[i]->getType(), type, true); - unsigned const numBytes = type.getCalldataEncodedSize(); - if (numBytes == 0 || numBytes > 32) + 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 leftAligned = type.getCategory() == Type::Category::STRING; - bool const padToWords = true; - dataOffset += CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned, padToWords); + 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); } //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : @@ -662,8 +664,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio if (retSize > 0) { - bool const leftAligned = firstType->getCategory() == Type::Category::STRING; - CompilerUtils(m_context).loadFromMemory(0, retSize, leftAligned, false, true); + bool const c_leftAligned = firstType->getCategory() == Type::Category::STRING; + CompilerUtils(m_context).loadFromMemory(0, retSize, c_leftAligned, false, true); } } diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 7ed7ad594..0ba3c137c 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -1054,10 +1054,10 @@ BOOST_AUTO_TEST_CASE(inter_contract_calls) } })"; compileAndRun(sourceCode, 0, "Helper"); - u160 const helperAddress = m_contractAddress; + u160 const c_helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); + BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes()); + BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress)); u256 a(3456789); u256 b("0x282837623374623234aa74"); BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == encodeArgs(a * b)); @@ -1084,10 +1084,10 @@ BOOST_AUTO_TEST_CASE(inter_contract_calls_with_complex_parameters) } })"; compileAndRun(sourceCode, 0, "Helper"); - u160 const helperAddress = m_contractAddress; + u160 const c_helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); + BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes()); + BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress)); u256 a(3456789); u256 b("0x282837623374623234aa74"); BOOST_REQUIRE(callContractFunction("callHelper(uint256,bool,uint256)", a, true, b) == encodeArgs(a * 3)); @@ -1115,11 +1115,11 @@ BOOST_AUTO_TEST_CASE(inter_contract_calls_accessing_this) } })"; compileAndRun(sourceCode, 0, "Helper"); - u160 const helperAddress = m_contractAddress; + u160 const c_helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); - BOOST_REQUIRE(callContractFunction("callHelper()") == encodeArgs(helperAddress)); + BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes()); + BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress)); + BOOST_REQUIRE(callContractFunction("callHelper()") == encodeArgs(c_helperAddress)); } BOOST_AUTO_TEST_CASE(calls_to_this) @@ -1146,10 +1146,10 @@ BOOST_AUTO_TEST_CASE(calls_to_this) } })"; compileAndRun(sourceCode, 0, "Helper"); - u160 const helperAddress = m_contractAddress; + u160 const c_helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); + BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes()); + BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress)); u256 a(3456789); u256 b("0x282837623374623234aa74"); BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == encodeArgs(a * b + 10)); @@ -1181,10 +1181,10 @@ BOOST_AUTO_TEST_CASE(inter_contract_calls_with_local_vars) } })"; compileAndRun(sourceCode, 0, "Helper"); - u160 const helperAddress = m_contractAddress; + u160 const c_helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); + BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes()); + BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress)); u256 a(3456789); u256 b("0x282837623374623234aa74"); BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == encodeArgs(a * b + 9)); @@ -1211,10 +1211,10 @@ BOOST_AUTO_TEST_CASE(strings_in_calls) } })"; compileAndRun(sourceCode, 0, "Helper"); - u160 const helperAddress = m_contractAddress; + u160 const c_helperAddress = m_contractAddress; compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("setHelper(address)", helperAddress) == bytes()); - BOOST_REQUIRE(callContractFunction("getHelper()", helperAddress) == encodeArgs(helperAddress)); + BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes()); + BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress)); BOOST_CHECK(callContractFunction("callHelper(string2,bool)", string("\0a", 2), true) == encodeArgs(string("\0a\0\0\0", 5))); } From a4a2e8c252ba54534e4f21b04b246a86a7d6de63 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 10 Jan 2015 12:42:23 +0100 Subject: [PATCH 521/588] continue project model implementation --- mix/MixApplication.cpp | 2 +- mix/qml.qrc | 2 +- mix/qml/CodeEditorModel.qml | 13 ---- mix/qml/CodeEditorView.qml | 17 ++++- mix/qml/ProjectList.qml | 47 +++++++++--- mix/qml/ProjectModel.qml | 130 ++++++--------------------------- mix/qml/js/ProjectModel.js | 142 ++++++++++++++++++++++++++++++++++++ mix/qml/main.qml | 29 +++++++- 8 files changed, 239 insertions(+), 143 deletions(-) delete mode 100644 mix/qml/CodeEditorModel.qml create mode 100644 mix/qml/js/ProjectModel.js diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index b5226b90c..1a55b1e47 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -33,7 +33,7 @@ MixApplication::MixApplication(int _argc, char* _argv[]): QApplication(_argc, _argv), m_engine(new QQmlApplicationEngine()), m_appContext(new AppContext(m_engine.get())) { qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); - QObject::connect(this, SIGNAL(lastWindowClosed()), context(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff + //QObject::connect(this, SIGNAL(lastWindowClosed()), context(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff m_engine->load(QUrl("qrc:/qml/main.qml")); //m_engine->load(QUrl("qrc:/qml/ProjectModel.qml")); m_appContext->loadProject(); diff --git a/mix/qml.qrc b/mix/qml.qrc index 53a2d1ae7..0e25de765 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -15,8 +15,8 @@ qml/js/Debugger.js qml/NewProjectDialog.qml qml/ProjectModel.qml - qml/CodeEditorModel.qml qml/CodeEditor.qml qml/CodeEditorView.qml + qml/js/ProjectModel.js diff --git a/mix/qml/CodeEditorModel.qml b/mix/qml/CodeEditorModel.qml deleted file mode 100644 index c696272ce..000000000 --- a/mix/qml/CodeEditorModel.qml +++ /dev/null @@ -1,13 +0,0 @@ -pragma Singleton - -import QtQuick 2.0 -import QtQuick.Window 2.0 -import QtQuick.Layouts 1.0 -import QtQuick.Controls 1.0 -import QtQuick.Dialogs 1.1 - -Item { - id: codeEditorModel - - property var codeDocuments: [] -} diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 9edc81ed9..45d2cfb2a 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -11,7 +11,7 @@ Item { function getDocumentText(documentId) { for (i = 0; i < editorListModel.count; i++) { if (editorListModel.get(i).documentId === documentId) { - return editors.itemAt(i).getDocumentText(); + return editors.itemAt(i).getText(); } } return ""; @@ -41,9 +41,20 @@ Item { Connections { target: ProjectModel - onDocumentOpen: { + onDocumentOpened: { openDocument(document); } + onProjectSaved: { + for (var i = 0; i < editorListModel.count; i++) + fileIo.writeFile(editorListModel.get(i).path, editors.itemAt(i).item.getText()); + } + onProjectClosed: { + for (var i = 0; i < editorListModel.count; i++) { + editors.itemAt(i).visible = false; + } + editorListModel.clear(); + currentDocumentId = ""; + } } CodeEditor { @@ -58,7 +69,7 @@ Item { asynchronous: true anchors.fill: parent sourceComponent: codeEditor - visible: (currentDocumentId === editorListModel.get(index).documentId) + visible: (index >= 0 && index < editorListModel.count && currentDocumentId === editorListModel.get(index).documentId) onVisibleChanged: { loadIfNotLoaded() } diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index 77810931c..1f578fc6a 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -5,19 +5,36 @@ import QtQuick.Controls 1.0 import org.ethereum.qml.ProjectModel 1.0 Item { - ListView { - id: projectList - model: ProjectModel.listModel + + ColumnLayout { anchors.fill: parent - delegate: renderDelegate - highlight: Rectangle { - color: "lightsteelblue"; + Text { + Layout.fillWidth: true + color: "blue" + text: ProjectModel.projectData ? ProjectModel.projectData.title : "" + horizontalAlignment: Text.AlignHCenter + visible: !ProjectModel.isEmpty; } - highlightFollowsCurrentItem: true - focus: true - clip: true - } + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + id: projectList + model: ProjectModel.listModel + + delegate: renderDelegate + highlight: Rectangle { + color: "lightsteelblue"; + } + highlightFollowsCurrentItem: true + focus: true + clip: true + onCurrentIndexChanged: { + if (currentIndex >= 0 && currentIndex < ProjectModel.listModel.count) + ProjectModel.openDocument(ProjectModel.listModel.get(currentIndex).documentId); + } + } + } Component { id: renderDelegate Item { @@ -42,10 +59,16 @@ Item { onClicked:{ projectList.currentIndex = index; - ProjectModel.documentOpen(ProjectModel.listModel.get(index)); + } + } + + Connections { + target: ProjectModel + onProjectLoaded: { + projectList.currentIndex = 0; } } } } - } + diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index f8217353d..976f70316 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -7,119 +7,33 @@ import QtQuick.Controls 1.0 import QtQuick.Dialogs 1.1 import Qt.labs.settings 1.0 +import "js/ProjectModel.js" as ProjectModelCode + Item { id: projectModel signal projectClosed signal projectLoaded - signal documentOpen(var document) + signal documentOpened(var document) + signal projectSaved - property bool isEmpty: (projectFile === "") + property bool isEmpty: (projectData === null) readonly property string projectFileName: ".mix" property bool haveUnsavedChanges: false - property string projectFile: "" + property string projectPath: "" property var projectData: null property var listModel: projectListModel - function saveAll() { - saveProject(); - } - - function createProject() { - closeProject(); - newProjectDialog.open(); - } - - function browseProject() { - openProjectFileDialog.open(); - } - - function closeProject() { - if (!isEmpty) { - console.log("closing project"); - if (haveUnsavedChanges) - saveMessageDialog.open(); - else - doCloseProject(); - } - } - - function saveProject() { - if (!isEmpty) { - var json = JSON.stringify(projectData); - fileIo.writeFile(projectFile, json); - } - } - - function loadProject(path) { - closeProject(); - console.log("loading project at " + path); - var json = fileIo.readFile(path); - projectData = JSON.parse(json); - projectFile = path; - if (!projectData.files) - projectData.files = []; - - for(var i = 0; i < projectData.files.length; i++) { - var p = projectData.files[i]; - addFile(p); - } - projectSettings.lastProjectPath = projectFile; - projectLoaded(); - } - - function addExistingFile() { - addExistingFileDialog().open(); - } - - function addProjectFiles(files) { - for(var i = 0; i < files.length; i++) - addFile(files[i]); - } - - function addFile(file) { - var p = file; - var fileData = { - contract: false, - path: p, - name: p.substring(p.lastIndexOf("/") + 1, p.length), - documentId: p, - isText: true, - isContract: p.substring(p.length - 4, p.length) === ".sol", - }; - - projectListModel.append(fileData); - } - - function doCloseProject() { - projectListModel.clear(); - projectFile = ""; - projectData = null; - projectClosed(); - } - - function doCreateProject(title, path) { - closeProject(); - console.log("creating project " + title + " at " + path); - if (path[path.length - 1] !== "/") - path += "/"; - var dirPath = path + title; - fileIo.makeDir(dirPath); - var projectFile = dirPath + "/" + projectFileName; - - var indexFile = dirPath + "/index.html"; - var contractsFile = dirPath + "/contracts.sol"; - var projectData = { - files: [ indexFile, contractsFile ] - }; - - fileIo.writeFile(indexFile, ""); - fileIo.writeFile(contractsFile, "contract MyContract {}"); - var json = JSON.stringify(projectData); - fileIo.writeFile(projectFile, json); - loadProject(projectFile); - } + //interface + function saveAll() { ProjectModelCode.saveAll(); } + function createProject() { ProjectModelCode.createProject(); } + function browseProject() { ProjectModelCode.browseProject(); } + function closeProject() { ProjectModelCode.closeProject(); } + function saveProject() { ProjectModelCode.saveProject(); } + function loadProject(path) { ProjectModelCode.loadProject(path); } + function addExistingFile() { ProjectModelCode.addExistingFile(); } + function openDocument(documentId) { ProjectModelCode.openDocument(documentId); } Component.onCompleted: { if (projectSettings.lastProjectPath) @@ -132,7 +46,7 @@ Item { onAccepted: { var title = newProjectDialog.projectTitle; var path = newProjectDialog.projectPath; - doCreateProject(title, path); + ProjectModelCode.doCreateProject(title, path); } } @@ -144,10 +58,10 @@ Item { icon: StandardIcon.Question onAccepted: { projectModel.saveAll(); - projectModel.doCloseProject(); + ProjectModelCode.doCloseProject(); } onRejected: { - projectModel.doCloseProject(); + ProjectModelCode.doCloseProject(); } } @@ -167,8 +81,8 @@ Item { selectFolder: true onAccepted: { var path = openProjectFileDialog.fileUrl.toString(); - path += "/" + projectFileName; - loadProject(path); + path += "/"; + loadProject(path); } } @@ -179,9 +93,7 @@ Item { selectFolder: false onAccepted: { var paths = openProjectFileDialog.fileUrls; - addProjectFiles(paths); + ProjectModelCode.doAddExistingFiles(paths); } } - - } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js new file mode 100644 index 000000000..7bcfb5cd7 --- /dev/null +++ b/mix/qml/js/ProjectModel.js @@ -0,0 +1,142 @@ +/* + 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 ProjectModel.js + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +function saveAll() { + saveProject(); + projectSaved(); +} + +function createProject() { + newProjectDialog.open(); +} + +function browseProject() { + openProjectFileDialog.open(); +} + +function closeProject() { + if (!isEmpty) { + if (haveUnsavedChanges) + saveMessageDialog.open(); + else + doCloseProject(); + } +} + +function saveProject() { + if (!isEmpty) { + var json = JSON.stringify(projectData); + var projectFile = projectPath + projectFileName; + fileIo.writeFile(projectFile, json); + } +} + +function loadProject(path) { + closeProject(); + console.log("loading project at " + path); + var projectFile = path + projectFileName; + var json = fileIo.readFile(projectFile); + projectData = JSON.parse(json); + if (!projectData.title) { + var parts = path.split("/"); + projectData.title = parts[parts.length - 2]; + } + projectPath = path; + if (!projectData.files) + projectData.files = []; + + for(var i = 0; i < projectData.files.length; i++) { + addFile(projectData.files[i]); + } + projectSettings.lastProjectPath = path; + projectLoaded(); +} + +function addExistingFile() { + addExistingFileDialog().open(); +} + +function addProjectFiles(files) { + for(var i = 0; i < files.length; i++) + addFile(files[i]); +} + +function addFile(fileName) { + var p = projectPath + fileName; + var fileData = { + contract: false, + path: p, + name: fileName, + documentId: fileName, + isText: true, + isContract: fileName.substring(fileName.length - 4, fileName.length) === ".sol", + }; + + projectListModel.append(fileData); +} + +function openDocument(documentId) { + for (var i = 0; i < projectListModel.count; i++) + if (projectListModel.get(i).documentId === documentId) + documentOpened(projectListModel.get(i)); +} + +function doCloseProject() { + console.log("closing project"); + projectListModel.clear(); + projectPath = ""; + projectData = null; + projectClosed(); +} + +function doCreateProject(title, path) { + closeProject(); + console.log("creating project " + title + " at " + path); + if (path[path.length - 1] !== "/") + path += "/"; + var dirPath = path + title + "/"; + fileIo.makeDir(dirPath); + var projectFile = dirPath + projectFileName; + + var indexFile = dirPath + "index.html"; + var contractsFile = dirPath + "contracts.sol"; + var projectData = { + title: title, + files: [ "contracts.sol", "index.html" ] + }; + + fileIo.writeFile(indexFile, ""); + fileIo.writeFile(contractsFile, "contract MyContract {}"); + var json = JSON.stringify(projectData); + fileIo.writeFile(projectFile, json); + loadProject(dirPath); +} + +function doAddExistingFiles(files) { + for(var i = 0; i < files.length; i++) { + var sourcePath = files[i]; + var sourceFileName = sourcePath.substring(sourcePath.lastIndexOf("/") + 1, sourcePath.length); + var destPath = projectPath + sourceFileName; + fileIo.copyFile(sourcePath, destPath); + addFile(sourceFileName); + } +} diff --git a/mix/qml/main.qml b/mix/qml/main.qml index c6cec939d..4bea535c2 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -21,14 +21,12 @@ ApplicationWindow { title: qsTr("File") MenuItem { action: createProjectAction } MenuItem { action: openProjectAction } + MenuItem { action: saveAllFilesAction } MenuItem { action: addExistingFileAction } MenuItem { action: addNewJsFileAction } MenuItem { action: addNewHtmlFileAction } MenuItem { action: addNewContractAction } - MenuItem { - text: qsTr("Exit") - onTriggered: Qt.quit(); - } + MenuItem { action: exitAppAction } } Menu { title: qsTr("Debug") @@ -54,6 +52,13 @@ ApplicationWindow { id: messageDialog } + Action { + id: exitAppAction + text: qsTr("Exit") + shortcut: "Ctrl+Q" + onTriggered: Qt.quit(); + } + Action { id: debugRunAction text: "&Run" @@ -116,4 +121,20 @@ ApplicationWindow { enabled: !ProjectModel.isEmpty onTriggered: ProjectModel.addExistingFile(); } + + Action { + id: saveAllFilesAction + text: qsTr("Save all") + shortcut: "Ctrl+S" + enabled: !ProjectModel.isEmpty + onTriggered: ProjectModel.saveAll(); + } + + Action { + id: closeProjectAction + text: qsTr("Close project") + shortcut: "Ctrl+W" + enabled: !ProjectModel.isEmpty + onTriggered: ProjectModel.closeProject(); + } } 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 522/588] 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 7eef69445f85fdeabf0fd6cd18f8c1aac91f3664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Sun, 11 Jan 2015 01:24:22 +0100 Subject: [PATCH 523/588] Add preprocessor definitions required by LLVM --- evmjit/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index 222fa5b72..18601b921 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/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 588114f54dffdfec7b592e4eddfca9f70c42b77e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 11 Jan 2015 12:47:39 +0100 Subject: [PATCH 524/588] Allow JITEVM to be enabled from AZ. --- alethzero/Main.ui | 12 + alethzero/MainWin.cpp | 9 + alethzero/MainWin.h | 1 + libevm/VM.cpp | 760 +++++++++++++++++++++++++++++++++++++++++ libevm/VM.h | 761 ------------------------------------------ 5 files changed, 782 insertions(+), 761 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index e5e5a9f56..2ce00b0e3 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -173,6 +173,7 @@ + @@ -2055,6 +2056,17 @@ font-size: 14pt
Clear Pe&nd&ing + + + true + + + false + + + Use &LLVM-EVM + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e15d08ab8..8be46e7ca 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -644,6 +645,7 @@ void Main::writeSettings() s.setValue("url", ui->urlEdit->text()); s.setValue("privateChain", m_privateChain); s.setValue("verbosity", ui->verbosity->value()); + s.setValue("jitvm", ui->jitvm->isChecked()); bytes d = m_webThree->saveNodes(); if (d.size()) @@ -718,6 +720,7 @@ void Main::readSettings(bool _skipGeometry) m_privateChain = s.value("privateChain", "").toString(); ui->usePrivate->setChecked(m_privateChain.size()); ui->verbosity->setValue(s.value("verbosity", 1).toInt()); + ui->jitvm->setChecked(s.value("jitvm", true).toBool()); ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html on_urlEdit_returnPressed(); @@ -817,6 +820,12 @@ void Main::on_usePrivate_triggered() on_killBlockchain_triggered(); } +void Main::on_jitvm_triggered() +{ + bool jit = ui->jitvm->isChecked(); + VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); +} + void Main::on_urlEdit_returnPressed() { QString s = ui->urlEdit->text(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index bb79e59ef..5a331df7d 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -156,6 +156,7 @@ private slots: void on_importKeyFile_triggered(); void on_post_clicked(); void on_newIdentity_triggered(); + void on_jitvm_triggered(); void refreshWhisper(); void refreshBlockChain(); diff --git a/libevm/VM.cpp b/libevm/VM.cpp index b8452e4f5..4307d9da0 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -31,3 +31,763 @@ void VM::reset(u256 _gas) noexcept m_curPC = 0; m_jumpDests.clear(); } + +bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +{ + auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; + + if (m_jumpDests.empty()) + for (unsigned i = 0; i < _ext.code.size(); ++i) + if (_ext.code[i] == (byte)Instruction::JUMPDEST) + m_jumpDests.insert(i); + else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32) + i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1; + u256 nextPC = m_curPC + 1; + auto osteps = _steps; + for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1) + { + // INSTRUCTION... + Instruction inst = (Instruction)_ext.getCode(m_curPC); + + // FEES... + bigint runGas = c_stepGas; + bigint newTempSize = m_temp.size(); + bigint copySize = 0; + + auto onOperation = [&]() + { + if (_onOp) + _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); + }; + // should work, but just seems to result in immediate errorless exit on initial execution. yeah. weird. + //m_onFail = std::function(onOperation); + + switch (inst) + { + case Instruction::STOP: + runGas = 0; + break; + + case Instruction::SUICIDE: + require(1); + runGas = 0; + break; + + case Instruction::SSTORE: + require(2); + if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2]) + runGas = c_sstoreSetGas; + else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2]) + { + runGas = 0; + _ext.sub.refunds += c_sstoreRefundGas; + } + else + runGas = c_sstoreResetGas; + break; + + case Instruction::SLOAD: + require(1); + runGas = c_sloadGas; + break; + + // These all operate on memory and therefore potentially expand it: + case Instruction::MSTORE: + require(2); + newTempSize = (bigint)m_stack.back() + 32; + break; + case Instruction::MSTORE8: + require(2); + newTempSize = (bigint)m_stack.back() + 1; + break; + case Instruction::MLOAD: + require(1); + newTempSize = (bigint)m_stack.back() + 32; + break; + case Instruction::RETURN: + require(2); + newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); + break; + case Instruction::SHA3: + require(2); + runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; + newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); + break; + case Instruction::CALLDATACOPY: + require(3); + copySize = m_stack[m_stack.size() - 3]; + newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); + break; + case Instruction::CODECOPY: + require(3); + copySize = m_stack[m_stack.size() - 3]; + newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); + break; + case Instruction::EXTCODECOPY: + require(4); + copySize = m_stack[m_stack.size() - 4]; + newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]); + break; + + case Instruction::BALANCE: + require(1); + runGas = c_balanceGas; + break; + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0; + require(n + 2); + runGas = c_logGas + c_logTopicGas * n + (bigint)c_logDataGas * m_stack[m_stack.size() - 2]; + newTempSize = memNeed(m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]); + break; + } + + case Instruction::CALL: + case Instruction::CALLCODE: + require(7); + runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1]; + newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5])); + break; + + case Instruction::CREATE: + { + require(3); + newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]); + runGas = c_createGas; + break; + } + case Instruction::EXP: + { + require(2); + auto expon = m_stack[m_stack.size() - 2]; + runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8)); + break; + } + + case Instruction::BLOCKHASH: + require(1); + break; + + case Instruction::PC: + case Instruction::MSIZE: + case Instruction::GAS: + case Instruction::JUMPDEST: + case Instruction::ADDRESS: + case Instruction::ORIGIN: + case Instruction::CALLER: + 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: + 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: + break; + case Instruction::NOT: + case Instruction::ISZERO: + case Instruction::CALLDATALOAD: + case Instruction::EXTCODESIZE: + case Instruction::POP: + case Instruction::JUMP: + require(1); + break; + case Instruction::ADD: + case Instruction::MUL: + case Instruction::SUB: + case Instruction::DIV: + case Instruction::SDIV: + case Instruction::MOD: + case Instruction::SMOD: + case Instruction::LT: + case Instruction::GT: + case Instruction::SLT: + case Instruction::SGT: + case Instruction::EQ: + case Instruction::AND: + case Instruction::OR: + case Instruction::XOR: + case Instruction::BYTE: + case Instruction::JUMPI: + case Instruction::SIGNEXTEND: + require(2); + break; + case Instruction::ADDMOD: + case Instruction::MULMOD: + require(3); + 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: + require(1 + (int)inst - (int)Instruction::DUP1); + 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: + require((int)inst - (int)Instruction::SWAP1 + 2); + break; + default: + BOOST_THROW_EXCEPTION(BadInstruction()); + } + + newTempSize = (newTempSize + 31) / 32 * 32; + if (newTempSize > m_temp.size()) + runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; + runGas += c_copyGas * (copySize + 31) / 32; + + onOperation(); +// if (_onOp) +// _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); + + if (m_gas < runGas) + { + // Out of gas! + m_gas = 0; + BOOST_THROW_EXCEPTION(OutOfGas()); + } + + m_gas = (u256)((bigint)m_gas - runGas); + + if (newTempSize > m_temp.size()) + m_temp.resize((size_t)newTempSize); + + // EXECUTE... + switch (inst) + { + case Instruction::ADD: + //pops two items and pushes S[-1] + S[-2] mod 2^256. + m_stack[m_stack.size() - 2] += m_stack.back(); + m_stack.pop_back(); + break; + case Instruction::MUL: + //pops two items and pushes S[-1] * S[-2] mod 2^256. + m_stack[m_stack.size() - 2] *= m_stack.back(); + m_stack.pop_back(); + break; + case Instruction::SUB: + m_stack[m_stack.size() - 2] = m_stack.back() - m_stack[m_stack.size() - 2]; + m_stack.pop_back(); + break; + case Instruction::DIV: + m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() / m_stack[m_stack.size() - 2] : 0; + m_stack.pop_back(); + break; + case Instruction::SDIV: + m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0; + m_stack.pop_back(); + break; + case Instruction::MOD: + m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() % m_stack[m_stack.size() - 2] : 0; + m_stack.pop_back(); + break; + case Instruction::SMOD: + m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0; + m_stack.pop_back(); + break; + case Instruction::EXP: + { + auto base = m_stack.back(); + auto expon = m_stack[m_stack.size() - 2]; + m_stack.pop_back(); + m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256); + break; + } + case Instruction::NOT: + m_stack.back() = ~m_stack.back(); + break; + case Instruction::LT: + m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0; + m_stack.pop_back(); + break; + case Instruction::GT: + m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0; + m_stack.pop_back(); + break; + case Instruction::SLT: + m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; + m_stack.pop_back(); + break; + case Instruction::SGT: + m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; + m_stack.pop_back(); + break; + case Instruction::EQ: + m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0; + m_stack.pop_back(); + break; + case Instruction::ISZERO: + m_stack.back() = m_stack.back() ? 0 : 1; + break; + case Instruction::AND: + m_stack[m_stack.size() - 2] = m_stack.back() & m_stack[m_stack.size() - 2]; + m_stack.pop_back(); + break; + case Instruction::OR: + m_stack[m_stack.size() - 2] = m_stack.back() | m_stack[m_stack.size() - 2]; + m_stack.pop_back(); + break; + case Instruction::XOR: + m_stack[m_stack.size() - 2] = m_stack.back() ^ m_stack[m_stack.size() - 2]; + m_stack.pop_back(); + break; + case Instruction::BYTE: + m_stack[m_stack.size() - 2] = m_stack.back() < 32 ? (m_stack[m_stack.size() - 2] >> (unsigned)(8 * (31 - m_stack.back()))) & 0xff : 0; + 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.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.pop_back(); + m_stack.pop_back(); + break; + case Instruction::SIGNEXTEND: + if (m_stack.back() < 31) + { + unsigned const testBit(m_stack.back() * 8 + 7); + u256& number = m_stack[m_stack.size() - 2]; + u256 mask = ((u256(1) << testBit) - 1); + if (boost::multiprecision::bit_test(number, testBit)) + number |= ~mask; + else + number &= mask; + } + m_stack.pop_back(); + break; + case Instruction::SHA3: + { + unsigned inOff = (unsigned)m_stack.back(); + m_stack.pop_back(); + unsigned inSize = (unsigned)m_stack.back(); + m_stack.pop_back(); + m_stack.push_back(sha3(bytesConstRef(m_temp.data() + inOff, inSize))); + break; + } + case Instruction::ADDRESS: + m_stack.push_back(fromAddress(_ext.myAddress)); + break; + case Instruction::ORIGIN: + m_stack.push_back(fromAddress(_ext.origin)); + break; + case Instruction::BALANCE: + { + m_stack.back() = _ext.balance(asAddress(m_stack.back())); + break; + } + case Instruction::CALLER: + m_stack.push_back(fromAddress(_ext.caller)); + break; + case Instruction::CALLVALUE: + m_stack.push_back(_ext.value); + break; + case Instruction::CALLDATALOAD: + { + if ((unsigned)m_stack.back() + (uint64_t)31 < _ext.data.size()) + m_stack.back() = (u256)*(h256 const*)(_ext.data.data() + (unsigned)m_stack.back()); + else + { + h256 r; + for (uint64_t i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + (uint64_t)32, j = 0; i < e; ++i, ++j) + r[j] = i < _ext.data.size() ? _ext.data[i] : 0; + m_stack.back() = (u256)r; + } + break; + } + case Instruction::CALLDATASIZE: + m_stack.push_back(_ext.data.size()); + break; + case Instruction::CODESIZE: + m_stack.push_back(_ext.code.size()); + break; + case Instruction::EXTCODESIZE: + m_stack.back() = _ext.codeAt(asAddress(m_stack.back())).size(); + break; + case Instruction::CALLDATACOPY: + case Instruction::CODECOPY: + case Instruction::EXTCODECOPY: + { + Address a; + if (inst == Instruction::EXTCODECOPY) + { + a = asAddress(m_stack.back()); + m_stack.pop_back(); + } + unsigned offset = (unsigned)m_stack.back(); + m_stack.pop_back(); + u256 index = m_stack.back(); + m_stack.pop_back(); + unsigned size = (unsigned)m_stack.back(); + m_stack.pop_back(); + unsigned sizeToBeCopied; + switch(inst) + { + case Instruction::CALLDATACOPY: + sizeToBeCopied = index + (bigint)size > (u256)_ext.data.size() ? (u256)_ext.data.size() < index ? 0 : _ext.data.size() - (unsigned)index : size; + memcpy(m_temp.data() + offset, _ext.data.data() + (unsigned)index, sizeToBeCopied); + break; + case Instruction::CODECOPY: + sizeToBeCopied = index + (bigint)size > (u256)_ext.code.size() ? (u256)_ext.code.size() < index ? 0 : _ext.code.size() - (unsigned)index : size; + memcpy(m_temp.data() + offset, _ext.code.data() + (unsigned)index, sizeToBeCopied); + break; + case Instruction::EXTCODECOPY: + sizeToBeCopied = index + (bigint)size > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < index ? 0 : _ext.codeAt(a).size() - (unsigned)index : size; + memcpy(m_temp.data() + offset, _ext.codeAt(a).data() + (unsigned)index, sizeToBeCopied); + break; + default: + // this is unreachable, but if someone introduces a bug in the future, he may get here. + assert(false); + BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("CALLDATACOPY, CODECOPY or EXTCODECOPY instruction requested.")); + break; + } + memset(m_temp.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied); + break; + } + case Instruction::GASPRICE: + m_stack.push_back(_ext.gasPrice); + break; + case Instruction::BLOCKHASH: + m_stack.back() = (u256)_ext.blockhash(m_stack.back()); + break; + case Instruction::COINBASE: + m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); + break; + case Instruction::TIMESTAMP: + m_stack.push_back(_ext.currentBlock.timestamp); + break; + case Instruction::NUMBER: + m_stack.push_back(_ext.currentBlock.number); + break; + case Instruction::DIFFICULTY: + m_stack.push_back(_ext.currentBlock.difficulty); + break; + case Instruction::GASLIMIT: + m_stack.push_back(1000000); + 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: + { + int i = (int)inst - (int)Instruction::PUSH1 + 1; + nextPC = m_curPC + 1; + m_stack.push_back(0); + for (; i--; nextPC++) + m_stack.back() = (m_stack.back() << 8) | _ext.getCode(nextPC); + break; + } + case Instruction::POP: + m_stack.pop_back(); + 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 n = 1 + (int)inst - (int)Instruction::DUP1; + m_stack.push_back(m_stack[m_stack.size() - n]); + 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: + { + unsigned n = (int)inst - (int)Instruction::SWAP1 + 2; + auto d = m_stack.back(); + m_stack.back() = m_stack[m_stack.size() - n]; + m_stack[m_stack.size() - n] = d; + break; + } + case Instruction::MLOAD: + { + m_stack.back() = (u256)*(h256 const*)(m_temp.data() + (unsigned)m_stack.back()); + break; + } + case Instruction::MSTORE: + { + *(h256*)&m_temp[(unsigned)m_stack.back()] = (h256)m_stack[m_stack.size() - 2]; + m_stack.pop_back(); + m_stack.pop_back(); + break; + } + case Instruction::MSTORE8: + { + m_temp[(unsigned)m_stack.back()] = (byte)(m_stack[m_stack.size() - 2] & 0xff); + m_stack.pop_back(); + m_stack.pop_back(); + break; + } + case Instruction::SLOAD: + m_stack.back() = _ext.store(m_stack.back()); + break; + case Instruction::SSTORE: + _ext.setStore(m_stack.back(), m_stack[m_stack.size() - 2]); + m_stack.pop_back(); + m_stack.pop_back(); + break; + case Instruction::JUMP: + nextPC = m_stack.back(); + if (!m_jumpDests.count(nextPC)) + BOOST_THROW_EXCEPTION(BadJumpDestination()); + m_stack.pop_back(); + break; + case Instruction::JUMPI: + if (m_stack[m_stack.size() - 2]) + { + nextPC = m_stack.back(); + if (!m_jumpDests.count(nextPC)) + BOOST_THROW_EXCEPTION(BadJumpDestination()); + } + m_stack.pop_back(); + m_stack.pop_back(); + break; + case Instruction::PC: + m_stack.push_back(m_curPC); + break; + case Instruction::MSIZE: + m_stack.push_back(m_temp.size()); + break; + case Instruction::GAS: + m_stack.push_back(m_gas); + break; + case Instruction::JUMPDEST: + break; +/* case Instruction::LOG0: + _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + break; + case Instruction::LOG1: + _ext.log({m_stack[m_stack.size() - 1]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 2], (unsigned)m_stack[m_stack.size() - 3])); + break; + case Instruction::LOG2: + _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 3], (unsigned)m_stack[m_stack.size() - 4])); + break; + case Instruction::LOG3: + _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 4], (unsigned)m_stack[m_stack.size() - 5])); + break; + case Instruction::LOG4: + _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 5], (unsigned)m_stack[m_stack.size() - 6])); + break;*/ + case Instruction::LOG0: + _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + m_stack.pop_back(); + m_stack.pop_back(); + break; + case Instruction::LOG1: + _ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + break; + case Instruction::LOG2: + _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + break; + case Instruction::LOG3: + _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + break; + case Instruction::LOG4: + _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + m_stack.pop_back(); + break; + case Instruction::CREATE: + { + u256 endowment = m_stack.back(); + m_stack.pop_back(); + unsigned initOff = (unsigned)m_stack.back(); + m_stack.pop_back(); + unsigned initSize = (unsigned)m_stack.back(); + m_stack.pop_back(); + + if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024) + { + _ext.subBalance(endowment); + m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); + } + else + m_stack.push_back(0); + break; + } + case Instruction::CALL: + case Instruction::CALLCODE: + { + u256 gas = m_stack.back(); + m_stack.pop_back(); + Address receiveAddress = asAddress(m_stack.back()); + m_stack.pop_back(); + u256 value = m_stack.back(); + m_stack.pop_back(); + + unsigned inOff = (unsigned)m_stack.back(); + m_stack.pop_back(); + unsigned inSize = (unsigned)m_stack.back(); + m_stack.pop_back(); + unsigned outOff = (unsigned)m_stack.back(); + m_stack.pop_back(); + unsigned outSize = (unsigned)m_stack.back(); + m_stack.pop_back(); + + if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024) + { + _ext.subBalance(value); + m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, {}, receiveAddress)); + } + else + m_stack.push_back(0); + + m_gas += gas; + break; + } + case Instruction::RETURN: + { + unsigned b = (unsigned)m_stack.back(); + m_stack.pop_back(); + unsigned s = (unsigned)m_stack.back(); + m_stack.pop_back(); + + return bytesConstRef(m_temp.data() + b, s); + } + case Instruction::SUICIDE: + { + Address dest = asAddress(m_stack.back()); + _ext.suicide(dest); + // ...follow through to... + } + case Instruction::STOP: + return bytesConstRef(); + } + } + if (_steps == (uint64_t)-1) + BOOST_THROW_EXCEPTION(StepsDone()); + return bytesConstRef(); +} diff --git a/libevm/VM.h b/libevm/VM.h index 377effe11..ecf5de292 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -77,766 +77,5 @@ private: std::function m_onFail; }; -// TODO: Move it to cpp file. Not done to make review easier. -inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) -{ - auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; - - if (m_jumpDests.empty()) - for (unsigned i = 0; i < _ext.code.size(); ++i) - if (_ext.code[i] == (byte)Instruction::JUMPDEST) - m_jumpDests.insert(i); - else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32) - i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1; - u256 nextPC = m_curPC + 1; - auto osteps = _steps; - for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1) - { - // INSTRUCTION... - Instruction inst = (Instruction)_ext.getCode(m_curPC); - - // FEES... - bigint runGas = c_stepGas; - bigint newTempSize = m_temp.size(); - bigint copySize = 0; - - auto onOperation = [&]() - { - if (_onOp) - _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); - }; - // should work, but just seems to result in immediate errorless exit on initial execution. yeah. weird. - //m_onFail = std::function(onOperation); - - switch (inst) - { - case Instruction::STOP: - runGas = 0; - break; - - case Instruction::SUICIDE: - require(1); - runGas = 0; - break; - - case Instruction::SSTORE: - require(2); - if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2]) - runGas = c_sstoreSetGas; - else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2]) - { - runGas = 0; - _ext.sub.refunds += c_sstoreRefundGas; - } - else - runGas = c_sstoreResetGas; - break; - - case Instruction::SLOAD: - require(1); - runGas = c_sloadGas; - break; - - // These all operate on memory and therefore potentially expand it: - case Instruction::MSTORE: - require(2); - newTempSize = (bigint)m_stack.back() + 32; - break; - case Instruction::MSTORE8: - require(2); - newTempSize = (bigint)m_stack.back() + 1; - break; - case Instruction::MLOAD: - require(1); - newTempSize = (bigint)m_stack.back() + 32; - break; - case Instruction::RETURN: - require(2); - newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); - break; - case Instruction::SHA3: - require(2); - runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas; - newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]); - break; - case Instruction::CALLDATACOPY: - require(3); - copySize = m_stack[m_stack.size() - 3]; - newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); - break; - case Instruction::CODECOPY: - require(3); - copySize = m_stack[m_stack.size() - 3]; - newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); - break; - case Instruction::EXTCODECOPY: - require(4); - copySize = m_stack[m_stack.size() - 4]; - newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]); - break; - - case Instruction::BALANCE: - require(1); - runGas = c_balanceGas; - break; - case Instruction::LOG0: - case Instruction::LOG1: - case Instruction::LOG2: - case Instruction::LOG3: - case Instruction::LOG4: - { - unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0; - require(n + 2); - runGas = c_logGas + c_logTopicGas * n + (bigint)c_logDataGas * m_stack[m_stack.size() - 2]; - newTempSize = memNeed(m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]); - break; - } - - case Instruction::CALL: - case Instruction::CALLCODE: - require(7); - runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1]; - newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5])); - break; - - case Instruction::CREATE: - { - require(3); - newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]); - runGas = c_createGas; - break; - } - case Instruction::EXP: - { - require(2); - auto expon = m_stack[m_stack.size() - 2]; - runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8)); - break; - } - - case Instruction::BLOCKHASH: - require(1); - break; - - case Instruction::PC: - case Instruction::MSIZE: - case Instruction::GAS: - case Instruction::JUMPDEST: - case Instruction::ADDRESS: - case Instruction::ORIGIN: - case Instruction::CALLER: - 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: - 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: - break; - case Instruction::NOT: - case Instruction::ISZERO: - case Instruction::CALLDATALOAD: - case Instruction::EXTCODESIZE: - case Instruction::POP: - case Instruction::JUMP: - require(1); - break; - case Instruction::ADD: - case Instruction::MUL: - case Instruction::SUB: - case Instruction::DIV: - case Instruction::SDIV: - case Instruction::MOD: - case Instruction::SMOD: - case Instruction::LT: - case Instruction::GT: - case Instruction::SLT: - case Instruction::SGT: - case Instruction::EQ: - case Instruction::AND: - case Instruction::OR: - case Instruction::XOR: - case Instruction::BYTE: - case Instruction::JUMPI: - case Instruction::SIGNEXTEND: - require(2); - break; - case Instruction::ADDMOD: - case Instruction::MULMOD: - require(3); - 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: - require(1 + (int)inst - (int)Instruction::DUP1); - 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: - require((int)inst - (int)Instruction::SWAP1 + 2); - break; - default: - BOOST_THROW_EXCEPTION(BadInstruction()); - } - - newTempSize = (newTempSize + 31) / 32 * 32; - if (newTempSize > m_temp.size()) - runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; - runGas += c_copyGas * (copySize + 31) / 32; - - onOperation(); -// if (_onOp) -// _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); - - if (m_gas < runGas) - { - // Out of gas! - m_gas = 0; - BOOST_THROW_EXCEPTION(OutOfGas()); - } - - m_gas = (u256)((bigint)m_gas - runGas); - - if (newTempSize > m_temp.size()) - m_temp.resize((size_t)newTempSize); - - // EXECUTE... - switch (inst) - { - case Instruction::ADD: - //pops two items and pushes S[-1] + S[-2] mod 2^256. - m_stack[m_stack.size() - 2] += m_stack.back(); - m_stack.pop_back(); - break; - case Instruction::MUL: - //pops two items and pushes S[-1] * S[-2] mod 2^256. - m_stack[m_stack.size() - 2] *= m_stack.back(); - m_stack.pop_back(); - break; - case Instruction::SUB: - m_stack[m_stack.size() - 2] = m_stack.back() - m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - break; - case Instruction::DIV: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() / m_stack[m_stack.size() - 2] : 0; - m_stack.pop_back(); - break; - case Instruction::SDIV: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0; - m_stack.pop_back(); - break; - case Instruction::MOD: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? m_stack.back() % m_stack[m_stack.size() - 2] : 0; - m_stack.pop_back(); - break; - case Instruction::SMOD: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0; - m_stack.pop_back(); - break; - case Instruction::EXP: - { - auto base = m_stack.back(); - auto expon = m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256); - break; - } - case Instruction::NOT: - m_stack.back() = ~m_stack.back(); - break; - case Instruction::LT: - m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::GT: - m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::SLT: - m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::SGT: - m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::EQ: - m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0; - m_stack.pop_back(); - break; - case Instruction::ISZERO: - m_stack.back() = m_stack.back() ? 0 : 1; - break; - case Instruction::AND: - m_stack[m_stack.size() - 2] = m_stack.back() & m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - break; - case Instruction::OR: - m_stack[m_stack.size() - 2] = m_stack.back() | m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - break; - case Instruction::XOR: - m_stack[m_stack.size() - 2] = m_stack.back() ^ m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - break; - case Instruction::BYTE: - m_stack[m_stack.size() - 2] = m_stack.back() < 32 ? (m_stack[m_stack.size() - 2] >> (unsigned)(8 * (31 - m_stack.back()))) & 0xff : 0; - 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.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.pop_back(); - m_stack.pop_back(); - break; - case Instruction::SIGNEXTEND: - if (m_stack.back() < 31) - { - unsigned const testBit(m_stack.back() * 8 + 7); - u256& number = m_stack[m_stack.size() - 2]; - u256 mask = ((u256(1) << testBit) - 1); - if (boost::multiprecision::bit_test(number, testBit)) - number |= ~mask; - else - number &= mask; - } - m_stack.pop_back(); - break; - case Instruction::SHA3: - { - unsigned inOff = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned inSize = (unsigned)m_stack.back(); - m_stack.pop_back(); - m_stack.push_back(sha3(bytesConstRef(m_temp.data() + inOff, inSize))); - break; - } - case Instruction::ADDRESS: - m_stack.push_back(fromAddress(_ext.myAddress)); - break; - case Instruction::ORIGIN: - m_stack.push_back(fromAddress(_ext.origin)); - break; - case Instruction::BALANCE: - { - m_stack.back() = _ext.balance(asAddress(m_stack.back())); - break; - } - case Instruction::CALLER: - m_stack.push_back(fromAddress(_ext.caller)); - break; - case Instruction::CALLVALUE: - m_stack.push_back(_ext.value); - break; - case Instruction::CALLDATALOAD: - { - if ((unsigned)m_stack.back() + (uint64_t)31 < _ext.data.size()) - m_stack.back() = (u256)*(h256 const*)(_ext.data.data() + (unsigned)m_stack.back()); - else - { - h256 r; - for (uint64_t i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + (uint64_t)32, j = 0; i < e; ++i, ++j) - r[j] = i < _ext.data.size() ? _ext.data[i] : 0; - m_stack.back() = (u256)r; - } - break; - } - case Instruction::CALLDATASIZE: - m_stack.push_back(_ext.data.size()); - break; - case Instruction::CODESIZE: - m_stack.push_back(_ext.code.size()); - break; - case Instruction::EXTCODESIZE: - m_stack.back() = _ext.codeAt(asAddress(m_stack.back())).size(); - break; - case Instruction::CALLDATACOPY: - case Instruction::CODECOPY: - case Instruction::EXTCODECOPY: - { - Address a; - if (inst == Instruction::EXTCODECOPY) - { - a = asAddress(m_stack.back()); - m_stack.pop_back(); - } - unsigned offset = (unsigned)m_stack.back(); - m_stack.pop_back(); - u256 index = m_stack.back(); - m_stack.pop_back(); - unsigned size = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned sizeToBeCopied; - switch(inst) - { - case Instruction::CALLDATACOPY: - sizeToBeCopied = index + (bigint)size > (u256)_ext.data.size() ? (u256)_ext.data.size() < index ? 0 : _ext.data.size() - (unsigned)index : size; - memcpy(m_temp.data() + offset, _ext.data.data() + (unsigned)index, sizeToBeCopied); - break; - case Instruction::CODECOPY: - sizeToBeCopied = index + (bigint)size > (u256)_ext.code.size() ? (u256)_ext.code.size() < index ? 0 : _ext.code.size() - (unsigned)index : size; - memcpy(m_temp.data() + offset, _ext.code.data() + (unsigned)index, sizeToBeCopied); - break; - case Instruction::EXTCODECOPY: - sizeToBeCopied = index + (bigint)size > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < index ? 0 : _ext.codeAt(a).size() - (unsigned)index : size; - memcpy(m_temp.data() + offset, _ext.codeAt(a).data() + (unsigned)index, sizeToBeCopied); - break; - default: - // this is unreachable, but if someone introduces a bug in the future, he may get here. - assert(false); - BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("CALLDATACOPY, CODECOPY or EXTCODECOPY instruction requested.")); - break; - } - memset(m_temp.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied); - break; - } - case Instruction::GASPRICE: - m_stack.push_back(_ext.gasPrice); - break; - case Instruction::BLOCKHASH: - m_stack.back() = (u256)_ext.blockhash(m_stack.back()); - break; - case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); - break; - case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); - break; - case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); - break; - case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); - break; - case Instruction::GASLIMIT: - m_stack.push_back(1000000); - 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: - { - int i = (int)inst - (int)Instruction::PUSH1 + 1; - nextPC = m_curPC + 1; - m_stack.push_back(0); - for (; i--; nextPC++) - m_stack.back() = (m_stack.back() << 8) | _ext.getCode(nextPC); - break; - } - case Instruction::POP: - m_stack.pop_back(); - 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 n = 1 + (int)inst - (int)Instruction::DUP1; - m_stack.push_back(m_stack[m_stack.size() - n]); - 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: - { - unsigned n = (int)inst - (int)Instruction::SWAP1 + 2; - auto d = m_stack.back(); - m_stack.back() = m_stack[m_stack.size() - n]; - m_stack[m_stack.size() - n] = d; - break; - } - case Instruction::MLOAD: - { - m_stack.back() = (u256)*(h256 const*)(m_temp.data() + (unsigned)m_stack.back()); - break; - } - case Instruction::MSTORE: - { - *(h256*)&m_temp[(unsigned)m_stack.back()] = (h256)m_stack[m_stack.size() - 2]; - m_stack.pop_back(); - m_stack.pop_back(); - break; - } - case Instruction::MSTORE8: - { - m_temp[(unsigned)m_stack.back()] = (byte)(m_stack[m_stack.size() - 2] & 0xff); - m_stack.pop_back(); - m_stack.pop_back(); - break; - } - case Instruction::SLOAD: - m_stack.back() = _ext.store(m_stack.back()); - break; - case Instruction::SSTORE: - _ext.setStore(m_stack.back(), m_stack[m_stack.size() - 2]); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::JUMP: - nextPC = m_stack.back(); - if (!m_jumpDests.count(nextPC)) - BOOST_THROW_EXCEPTION(BadJumpDestination()); - m_stack.pop_back(); - break; - case Instruction::JUMPI: - if (m_stack[m_stack.size() - 2]) - { - nextPC = m_stack.back(); - if (!m_jumpDests.count(nextPC)) - BOOST_THROW_EXCEPTION(BadJumpDestination()); - } - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::PC: - m_stack.push_back(m_curPC); - break; - case Instruction::MSIZE: - m_stack.push_back(m_temp.size()); - break; - case Instruction::GAS: - m_stack.push_back(m_gas); - break; - case Instruction::JUMPDEST: - break; -/* case Instruction::LOG0: - _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - break; - case Instruction::LOG1: - _ext.log({m_stack[m_stack.size() - 1]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 2], (unsigned)m_stack[m_stack.size() - 3])); - break; - case Instruction::LOG2: - _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 3], (unsigned)m_stack[m_stack.size() - 4])); - break; - case Instruction::LOG3: - _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 4], (unsigned)m_stack[m_stack.size() - 5])); - break; - case Instruction::LOG4: - _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 5], (unsigned)m_stack[m_stack.size() - 6])); - break;*/ - case Instruction::LOG0: - _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::LOG1: - _ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::LOG2: - _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::LOG3: - _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::LOG4: - _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - m_stack.pop_back(); - break; - case Instruction::CREATE: - { - u256 endowment = m_stack.back(); - m_stack.pop_back(); - unsigned initOff = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned initSize = (unsigned)m_stack.back(); - m_stack.pop_back(); - - if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024) - { - _ext.subBalance(endowment); - m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); - } - else - m_stack.push_back(0); - break; - } - case Instruction::CALL: - case Instruction::CALLCODE: - { - u256 gas = m_stack.back(); - m_stack.pop_back(); - Address receiveAddress = asAddress(m_stack.back()); - m_stack.pop_back(); - u256 value = m_stack.back(); - m_stack.pop_back(); - - unsigned inOff = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned inSize = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned outOff = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned outSize = (unsigned)m_stack.back(); - m_stack.pop_back(); - - if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024) - { - _ext.subBalance(value); - m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, {}, receiveAddress)); - } - else - m_stack.push_back(0); - - m_gas += gas; - break; - } - case Instruction::RETURN: - { - unsigned b = (unsigned)m_stack.back(); - m_stack.pop_back(); - unsigned s = (unsigned)m_stack.back(); - m_stack.pop_back(); - - return bytesConstRef(m_temp.data() + b, s); - } - case Instruction::SUICIDE: - { - Address dest = asAddress(m_stack.back()); - _ext.suicide(dest); - // ...follow through to... - } - case Instruction::STOP: - return bytesConstRef(); - } - } - if (_steps == (uint64_t)-1) - BOOST_THROW_EXCEPTION(StepsDone()); - return bytesConstRef(); -} - } } From 23c82cccac0068842d5c114a04f16fcdb34ca8d1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 11 Jan 2015 15:27:57 +0100 Subject: [PATCH 525/588] Removed dependency on WebThreeDirect form Web3Server Mix Client Model --- libdevcore/Exceptions.h | 2 + libweb3jsonrpc/WebThreeStubServer.cpp | 637 +-------------------- libweb3jsonrpc/WebThreeStubServer.h | 105 +--- libweb3jsonrpc/WebThreeStubServerBase.cpp | 664 ++++++++++++++++++++++ libweb3jsonrpc/WebThreeStubServerBase.h | 138 +++++ libwebthree/WebThree.h | 72 ++- mix/AppContext.cpp | 39 +- mix/AppContext.h | 12 +- mix/AssemblyDebuggerControl.cpp | 169 +----- mix/AssemblyDebuggerControl.h | 42 +- mix/AssemblyDebuggerModel.cpp | 119 ---- mix/AssemblyDebuggerModel.h | 76 --- mix/ClientModel.cpp | 222 ++++++++ mix/ClientModel.h | 113 ++++ mix/CodeEditorExtensionManager.cpp | 3 +- mix/CodeModel.cpp | 2 +- mix/CodeModel.h | 8 +- mix/ConstantCompilationControl.cpp | 2 +- mix/ContractCallDataEncoder.cpp | 5 +- mix/ContractCallDataEncoder.h | 8 +- mix/DebuggingStateWrapper.h | 40 +- mix/FileIo.cpp | 5 + mix/FileIo.h | 4 + mix/MixApplication.cpp | 5 +- mix/MixClient.cpp | 336 +++++++++++ mix/MixClient.h | 125 ++++ mix/QFunctionDefinition.cpp | 4 +- mix/QFunctionDefinition.h | 3 + mix/Web3Server.cpp | 55 ++ mix/Web3Server.h | 56 ++ mix/qml.qrc | 1 + mix/qml/CodeEditorView.qml | 2 +- mix/qml/ProjectModel.qml | 11 +- mix/qml/StateDialog.qml | 2 +- mix/qml/StateList.qml | 8 +- mix/qml/WebPreview.qml | 81 +++ mix/qml/js/ProjectModel.js | 2 +- mix/qml/main.qml | 6 +- 38 files changed, 1947 insertions(+), 1237 deletions(-) create mode 100644 libweb3jsonrpc/WebThreeStubServerBase.cpp create mode 100644 libweb3jsonrpc/WebThreeStubServerBase.h delete mode 100644 mix/AssemblyDebuggerModel.cpp delete mode 100644 mix/AssemblyDebuggerModel.h create mode 100644 mix/ClientModel.cpp create mode 100644 mix/ClientModel.h create mode 100644 mix/MixClient.cpp create mode 100644 mix/MixClient.h create mode 100644 mix/Web3Server.cpp create mode 100644 mix/Web3Server.h create mode 100644 mix/qml/WebPreview.qml diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 5d03c195f..061f181b3 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include #include "CommonData.h" @@ -40,6 +41,7 @@ struct NoNetworking: virtual Exception {}; struct NoUPnPDevice: virtual Exception {}; struct RootNotFound: virtual Exception {}; struct FileError: virtual Exception {}; +struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): m_f("Interface " + _f + " not supported.") {} virtual const char* what() const noexcept { return m_f.c_str(); } private: std::string m_f; }; // error information to be added to exceptions typedef boost::error_info errinfo_invalidSymbol; diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 874c14331..f728a29f5 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -21,198 +21,19 @@ * @date 2014 */ -#include -#include -#include -#include "WebThreeStubServer.h" -#include -#include -#include -#include -#include #include +#include #include -#include -#include -#include +#include "WebThreeStubServer.h" using namespace std; using namespace dev; using namespace dev::eth; -static Json::Value toJson(dev::eth::BlockInfo const& _bi) -{ - Json::Value res; - res["hash"] = boost::lexical_cast(_bi.hash); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); - res["difficulty"] = toJS(_bi.difficulty); - res["number"] = (int)_bi.number; - res["gasLimit"] = (int)_bi.gasLimit; - res["timestamp"] = (int)_bi.timestamp; - res["extraData"] = jsFromBinary(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); - return res; -} - -static Json::Value toJson(dev::eth::Transaction const& _t) -{ - Json::Value res; - res["hash"] = toJS(_t.sha3()); - res["input"] = jsFromBinary(_t.data()); - res["to"] = toJS(_t.receiveAddress()); - res["from"] = toJS(_t.sender()); - res["gas"] = (int)_t.gas(); - res["gasPrice"] = toJS(_t.gasPrice()); - res["nonce"] = toJS(_t.nonce()); - res["value"] = toJS(_t.value()); - return res; -} - -static Json::Value toJson(dev::eth::LogEntry const& _e) -{ - Json::Value res; - - res["data"] = jsFromBinary(_e.data); - res["address"] = toJS(_e.address); - for (auto const& t: _e.topics) - res["topics"].append(toJS(t)); - return res; -} - -static Json::Value toJson(dev::eth::LogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7. -{ - Json::Value res; - for (dev::eth::LogEntry const& e: _es) - res.append(toJson(e)); - return res; -} - -static Json::Value toJson(std::map const& _storage) -{ - Json::Value res(Json::objectValue); - for (auto i: _storage) - res[toJS(i.first)] = toJS(i.second); - return res; -} - -static dev::eth::LogFilter toLogFilter(Json::Value const& _json) // commented to avoid warning. Uncomment once in use @ PoC-7. -{ - dev::eth::LogFilter filter; - if (!_json.isObject() || _json.empty()) - return filter; - - if (_json["earliest"].isInt()) - filter.withEarliest(_json["earliest"].asInt()); - if (_json["latest"].isInt()) - filter.withLatest(_json["lastest"].asInt()); - if (_json["max"].isInt()) - filter.withMax(_json["max"].asInt()); - if (_json["skip"].isInt()) - filter.withSkip(_json["skip"].asInt()); - if (!_json["address"].empty()) - { - if (_json["address"].isArray()) - { - for (auto i : _json["address"]) - if (i.isString()) - filter.address(jsToAddress(i.asString())); - } - else if (_json["address"].isString()) - filter.address(jsToAddress(_json["address"].asString())); - } - if (!_json["topics"].empty()) - { - if (_json["topics"].isArray()) - { - for (auto i: _json["topics"]) - if (i.isString()) - filter.topic(jsToU256(i.asString())); - } - else if(_json["topics"].isString()) - filter.topic(jsToU256(_json["topics"].asString())); - } - return filter; -} - -static shh::Message toMessage(Json::Value const& _json) -{ - shh::Message ret; - if (_json["from"].isString()) - ret.setFrom(jsToPublic(_json["from"].asString())); - if (_json["to"].isString()) - ret.setTo(jsToPublic(_json["to"].asString())); - if (_json["payload"].isString()) - ret.setPayload(jsToBytes(_json["payload"].asString())); - return ret; -} - -static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) -{ - unsigned ttl = 50; - unsigned workToProve = 50; - shh::BuildTopic bt; - - if (_json["ttl"].isInt()) - ttl = _json["ttl"].asInt(); - if (_json["workToProve"].isInt()) - workToProve = _json["workToProve"].asInt(); - if (!_json["topic"].empty()) - { - if (_json["topic"].isString()) - bt.shift(jsToBytes(_json["topic"].asString())); - else if (_json["topic"].isArray()) - for (auto i: _json["topic"]) - if (i.isString()) - bt.shift(jsToBytes(i.asString())); - } - return _m.seal(_from, bt, ttl, workToProve); -} - -static pair toWatch(Json::Value const& _json) -{ - shh::BuildTopicMask bt; - Public to; - - if (_json["to"].isString()) - to = jsToPublic(_json["to"].asString()); - - if (!_json["topic"].empty()) - { - if (_json["topic"].isString()) - bt.shift(jsToBytes(_json["topic"].asString())); - else if (_json["topic"].isArray()) - for (auto i: _json["topic"]) - if (i.isString()) - bt.shift(jsToBytes(i.asString())); - } - return make_pair(bt.toTopicMask(), to); -} - -static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) -{ - Json::Value res; - res["hash"] = toJS(_h); - res["expiry"] = (int)_e.expiry(); - res["sent"] = (int)_e.sent(); - res["ttl"] = (int)_e.ttl(); - res["workProved"] = (int)_e.workProved(); - for (auto const& t: _e.topics()) - res["topics"].append(toJS(t)); - res["payload"] = toJS(_m.payload()); - res["from"] = toJS(_m.from()); - res["to"] = toJS(_m.to()); - return res; -} - WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, std::vector const& _accounts): - AbstractWebThreeStubServer(_conn), + WebThreeStubServerBase(_conn, _accounts), m_web3(_web3) { - setAccounts(_accounts); auto path = getDataDir() + "/.web3"; boost::filesystem::create_directories(path); ldb::Options o; @@ -220,181 +41,27 @@ WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, ldb::DB::Open(o, path, &m_db); } -void WebThreeStubServer::setAccounts(std::vector const& _accounts) -{ - m_accounts.clear(); - for (auto i: _accounts) - m_accounts[i.address()] = i.secret(); -} - -void WebThreeStubServer::setIdentities(std::vector const& _ids) -{ - m_ids.clear(); - for (auto i: _ids) - m_ids[i.pub()] = i.secret(); -} - -dev::eth::Interface* WebThreeStubServer::client() const +dev::eth::Interface* WebThreeStubServer::client() { return m_web3.ethereum(); } -std::shared_ptr WebThreeStubServer::face() const +std::shared_ptr WebThreeStubServer::face() { return m_web3.whisper(); } -std::string WebThreeStubServer::web3_sha3(std::string const& _param1) -{ - return toJS(sha3(jsToBytes(_param1))); -} - -Json::Value WebThreeStubServer::eth_accounts() -{ - Json::Value ret(Json::arrayValue); - for (auto i: m_accounts) - ret.append(toJS(i.first)); - return ret; -} - -std::string WebThreeStubServer::shh_addToGroup(std::string const& _group, std::string const& _who) -{ - (void)_group; - (void)_who; - return ""; -} - -std::string WebThreeStubServer::eth_balanceAt(string const& _address) -{ - return toJS(client()->balanceAt(jsToAddress(_address), client()->getDefault())); -} - -Json::Value WebThreeStubServer::eth_blockByHash(std::string const& _hash) -{ - return toJson(client()->blockInfo(jsToFixed<32>(_hash))); -} - -Json::Value WebThreeStubServer::eth_blockByNumber(int const& _number) -{ - return toJson(client()->blockInfo(client()->hashFromNumber(_number))); -} - -static TransactionSkeleton toTransaction(Json::Value const& _json) -{ - TransactionSkeleton ret; - if (!_json.isObject() || _json.empty()) - return ret; - - if (_json["from"].isString()) - ret.from = jsToAddress(_json["from"].asString()); - if (_json["to"].isString()) - ret.to = jsToAddress(_json["to"].asString()); - if (!_json["value"].empty()) - { - if (_json["value"].isString()) - ret.value = jsToU256(_json["value"].asString()); - else if (_json["value"].isInt()) - ret.value = u256(_json["value"].asInt()); - } - if (!_json["gas"].empty()) - { - if (_json["gas"].isString()) - ret.gas = jsToU256(_json["gas"].asString()); - else if (_json["gas"].isInt()) - ret.gas = u256(_json["gas"].asInt()); - } - if (!_json["gasPrice"].empty()) - { - if (_json["gasPrice"].isString()) - ret.gasPrice = jsToU256(_json["gasPrice"].asString()); - else if (_json["gasPrice"].isInt()) - ret.gas = u256(_json["gas"].asInt()); - } - if (!_json["data"].empty()) - { - if (_json["data"].isString()) // ethereum.js has preconstructed the data array - ret.data = jsToBytes(_json["data"].asString()); - else if (_json["data"].isArray()) // old style: array of 32-byte-padded values. TODO: remove PoC-8 - for (auto i: _json["data"]) - dev::operator +=(ret.data, padded(jsToBytes(i.asString()), 32)); - } - - if (_json["code"].isString()) - ret.data = jsToBytes(_json["code"].asString()); - return ret; -} - -std::string WebThreeStubServer::eth_call(Json::Value const& _json) -{ - std::string ret; - TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) - { - auto b = m_accounts.begin()->first; - for (auto a: m_accounts) - if (client()->balanceAt(a.first) > client()->balanceAt(b)) - b = a.first; - t.from = b; - } - if (!m_accounts.count(t.from)) - return ret; - if (!t.gasPrice) - t.gasPrice = 10 * dev::eth::szabo; - if (!t.gas) - t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - ret = toJS(client()->call(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice)); - return ret; -} - -bool WebThreeStubServer::eth_changed(int const& _id) -{ - return client()->checkWatch(_id); -} - -std::string WebThreeStubServer::eth_codeAt(string const& _address) +dev::WebThreeNetworkFace* WebThreeStubServer::network() { - return jsFromBinary(client()->codeAt(jsToAddress(_address), client()->getDefault())); + return &m_web3; } -std::string WebThreeStubServer::eth_coinbase() +dev::WebThreeStubDatabaseFace* WebThreeStubServer::db() { - return toJS(client()->address()); + return this; } -double WebThreeStubServer::eth_countAt(string const& _address) -{ - return (double)(uint64_t)client()->countAt(jsToAddress(_address), client()->getDefault()); -} - -int WebThreeStubServer::eth_defaultBlock() -{ - return client()->getDefault(); -} - -std::string WebThreeStubServer::eth_gasPrice() -{ - return toJS(10 * dev::eth::szabo); -} - -std::string WebThreeStubServer::db_get(std::string const& _name, std::string const& _key) -{ - bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); - string ret; - m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); - return toJS(dev::asBytes(ret)); -} - -Json::Value WebThreeStubServer::eth_filterLogs(int const& _id) -{ - return toJson(client()->logs(_id)); -} - -Json::Value WebThreeStubServer::eth_logs(Json::Value const& _json) -{ - return toJson(client()->logs(toLogFilter(_json))); -} - -std::string WebThreeStubServer::db_getString(std::string const& _name, std::string const& _key) +std::string WebThreeStubServer::get(std::string const& _name, std::string const& _key) { bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); string ret; @@ -402,289 +69,9 @@ std::string WebThreeStubServer::db_getString(std::string const& _name, std::stri return ret; } -bool WebThreeStubServer::shh_haveIdentity(std::string const& _id) -{ - return m_ids.count(jsToPublic(_id)) > 0; -} - -bool WebThreeStubServer::eth_listening() -{ - return m_web3.isNetworkStarted(); -} - -bool WebThreeStubServer::eth_mining() -{ - return client()->isMining(); -} - -int WebThreeStubServer::eth_newFilter(Json::Value const& _json) -{ - unsigned ret = -1; - ret = client()->installWatch(toLogFilter(_json)); - return ret; -} - -int WebThreeStubServer::eth_newFilterString(std::string const& _filter) -{ - unsigned ret = -1; - if (_filter.compare("chain") == 0) - ret = client()->installWatch(dev::eth::ChainChangedFilter); - else if (_filter.compare("pending") == 0) - ret = client()->installWatch(dev::eth::PendingChangedFilter); - return ret; -} - -std::string WebThreeStubServer::shh_newGroup(std::string const& _id, std::string const& _who) -{ - (void)_id; - (void)_who; - return ""; -} - -std::string WebThreeStubServer::shh_newIdentity() -{ -// cnote << this << m_ids; - KeyPair kp = KeyPair::create(); - m_ids[kp.pub()] = kp.secret(); - return toJS(kp.pub()); -} - -Json::Value WebThreeStubServer::eth_compilers() -{ - Json::Value ret(Json::arrayValue); - ret.append("lll"); - ret.append("solidity"); - ret.append("serpent"); - return ret; -} - -std::string WebThreeStubServer::eth_lll(std::string const& _code) -{ - string res; - vector errors; - res = toJS(dev::eth::compileLLL(_code, true, &errors)); - cwarn << "LLL compilation errors: " << errors; - return res; -} - -std::string WebThreeStubServer::eth_serpent(std::string const& _code) -{ - string res; - try - { - res = toJS(dev::asBytes(::compile(_code))); - } - catch (string err) - { - cwarn << "Solidity compilation error: " << err; - } - catch (...) - { - cwarn << "Uncought serpent compilation exception"; - } - return res; -} - -std::string WebThreeStubServer::eth_solidity(std::string const& _code) -{ - string res; - dev::solidity::CompilerStack compiler; - try - { - res = toJS(compiler.compile(_code, true)); - } - catch (dev::Exception const& exception) - { - ostringstream error; - solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler); - cwarn << "Solidity compilation error: " << error.str(); - } - catch (...) - { - cwarn << "Uncought solidity compilation exception"; - } - return res; -} - -int WebThreeStubServer::eth_number() -{ - return client()->number() + 1; -} - -int WebThreeStubServer::eth_peerCount() -{ - return m_web3.peerCount(); -} - -bool WebThreeStubServer::shh_post(Json::Value const& _json) -{ - shh::Message m = toMessage(_json); - Secret from; - - if (m.from() && m_ids.count(m.from())) - { - cwarn << "Silently signing message from identity" << m.from().abridged() << ": User validation hook goes here."; - // TODO: insert validification hook here. - from = m_ids[m.from()]; - } - - face()->inject(toSealed(_json, m, from)); - return true; -} - -bool WebThreeStubServer::db_put(std::string const& _name, std::string const& _key, std::string const& _value) +void WebThreeStubServer::put(std::string const& _name, std::string const& _key, std::string const& _value) { bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); - bytes v = jsToBytes(_value); - m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); - return true; -} - -bool WebThreeStubServer::db_putString(std::string const& _name, std::string const& _key, std::string const& _value) -{ - bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); - string v = _value; - m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); - return true; -} - -bool WebThreeStubServer::eth_setCoinbase(std::string const& _address) -{ - client()->setAddress(jsToAddress(_address)); - return true; -} - -bool WebThreeStubServer::eth_setDefaultBlock(int const& _block) -{ - client()->setDefault(_block); - return true; -} - -bool WebThreeStubServer::eth_setListening(bool const& _listening) -{ - if (_listening) - m_web3.startNetwork(); - else - m_web3.stopNetwork(); - return true; -} - -bool WebThreeStubServer::eth_setMining(bool const& _mining) -{ - if (_mining) - client()->startMining(); - else - client()->stopMining(); - return true; -} - -Json::Value WebThreeStubServer::shh_changed(int const& _id) -{ - Json::Value ret(Json::arrayValue); - auto pub = m_shhWatches[_id]; - if (!pub || m_ids.count(pub)) - for (h256 const& h: face()->checkWatch(_id)) - { - auto e = face()->envelope(h); - shh::Message m; - if (pub) - { - cwarn << "Silently decrypting message from identity" << pub.abridged() << ": User validation hook goes here."; - m = e.open(m_ids[pub]); - if (!m) - continue; - } - else - m = e.open(); - ret.append(toJson(h, e, m)); - } - - return ret; -} - -int WebThreeStubServer::shh_newFilter(Json::Value const& _json) -{ - auto w = toWatch(_json); - auto ret = face()->installWatch(w.first); - m_shhWatches.insert(make_pair(ret, w.second)); - return ret; -} - -bool WebThreeStubServer::shh_uninstallFilter(int const& _id) -{ - face()->uninstallWatch(_id); - return true; -} - -std::string WebThreeStubServer::eth_stateAt(string const& _address, string const& _storage) -{ - return toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), client()->getDefault())); -} - -Json::Value WebThreeStubServer::eth_storageAt(string const& _address) -{ - return toJson(client()->storageAt(jsToAddress(_address))); -} - -std::string WebThreeStubServer::eth_transact(Json::Value const& _json) -{ - std::string ret; - TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) - { - auto b = m_accounts.begin()->first; - for (auto a: m_accounts) - if (client()->balanceAt(a.first) > client()->balanceAt(b)) - b = a.first; - t.from = b; - } - if (!m_accounts.count(t.from)) - return ret; - if (!t.gasPrice) - t.gasPrice = 10 * dev::eth::szabo; - if (!t.gas) - t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - if (authenticate(t)) - { - if (t.to) - // TODO: from qethereum, insert validification hook here. - client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); - else - ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); - client()->flushTransactions(); - } - return ret; -} - -bool WebThreeStubServer::authenticate(TransactionSkeleton const& _t) const -{ - cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; - return true; -} - -Json::Value WebThreeStubServer::eth_transactionByHash(std::string const& _hash, int const& _i) -{ - return toJson(client()->transaction(jsToFixed<32>(_hash), _i)); -} - -Json::Value WebThreeStubServer::eth_transactionByNumber(int const& _number, int const& _i) -{ - return toJson(client()->transaction(client()->hashFromNumber(_number), _i)); -} - -Json::Value WebThreeStubServer::eth_uncleByHash(std::string const& _hash, int const& _i) -{ - return toJson(client()->uncle(jsToFixed<32>(_hash), _i)); -} - -Json::Value WebThreeStubServer::eth_uncleByNumber(int const& _number, int const& _i) -{ - return toJson(client()->uncle(client()->hashFromNumber(_number), _i)); -} - -bool WebThreeStubServer::eth_uninstallFilter(int const& _id) -{ - client()->uninstallWatch(_id); - return true; + m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)_value.data(), _value.size())); } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 0f81fce9d..b76fc17e9 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -28,111 +28,32 @@ #include #pragma warning(pop) -#include -#include -#include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include "abstractwebthreestubserver.h" -#pragma GCC diagnostic pop - -namespace ldb = leveldb; +#include "WebThreeStubServerBase.h" namespace dev { class WebThreeDirect; -class KeyPair; -class TransactionSkeleton; -namespace eth -{ -class Interface; -} -namespace shh -{ -class Interface; -} } /** - * @brief JSON-RPC api implementation - * @todo filters should work on unsigned instead of int - * unsigned are not supported in json-rpc-cpp and there are bugs with double in json-rpc-cpp version 0.2.1 - * @todo split these up according to subprotocol (eth, shh, db, p2p, web3) and make it /very/ clear about how to add other subprotocols. - * @todo modularise everything so additional subprotocols don't need to change this file. + * @brief JSON-RPC api implementation for WebThreeDirect */ -class WebThreeStubServer: public AbstractWebThreeStubServer +class WebThreeStubServer: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace { public: WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); - virtual std::string web3_sha3(std::string const& _param1); - virtual Json::Value eth_accounts(); - virtual std::string eth_balanceAt(std::string const& _address); - virtual Json::Value eth_blockByHash(std::string const& _hash); - virtual Json::Value eth_blockByNumber(int const& _number); - virtual std::string eth_call(Json::Value const& _json); - virtual bool eth_changed(int const& _id); - virtual std::string eth_codeAt(std::string const& _address); - virtual std::string eth_coinbase(); - virtual Json::Value eth_compilers(); - virtual double eth_countAt(std::string const& _address); - virtual int eth_defaultBlock(); - virtual std::string eth_gasPrice(); - virtual Json::Value eth_filterLogs(int const& _id); - virtual Json::Value eth_logs(Json::Value const& _json); - virtual bool eth_listening(); - virtual bool eth_mining(); - virtual int eth_newFilter(Json::Value const& _json); - virtual int eth_newFilterString(std::string const& _filter); - virtual int eth_number(); - virtual int eth_peerCount(); - virtual bool eth_setCoinbase(std::string const& _address); - virtual bool eth_setDefaultBlock(int const& _block); - virtual bool eth_setListening(bool const& _listening); - virtual std::string eth_lll(std::string const& _s); - virtual std::string eth_serpent(std::string const& _s); - virtual bool eth_setMining(bool const& _mining); - virtual std::string eth_solidity(std::string const& _code); - virtual std::string eth_stateAt(std::string const& _address, std::string const& _storage); - virtual Json::Value eth_storageAt(std::string const& _address); - virtual std::string eth_transact(Json::Value const& _json); - virtual Json::Value eth_transactionByHash(std::string const& _hash, int const& _i); - virtual Json::Value eth_transactionByNumber(int const& _number, int const& _i); - virtual Json::Value eth_uncleByHash(std::string const& _hash, int const& _i); - virtual Json::Value eth_uncleByNumber(int const& _number, int const& _i); - virtual bool eth_uninstallFilter(int const& _id); - - virtual std::string db_get(std::string const& _name, std::string const& _key); - virtual std::string db_getString(std::string const& _name, std::string const& _key); - virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value); - virtual bool db_putString(std::string const& _name, std::string const& _key, std::string const& _value); - - virtual std::string shh_addToGroup(std::string const& _group, std::string const& _who); - virtual Json::Value shh_changed(int const& _id); - virtual bool shh_haveIdentity(std::string const& _id); - virtual int shh_newFilter(Json::Value const& _json); - virtual std::string shh_newGroup(std::string const& _id, std::string const& _who); - virtual std::string shh_newIdentity(); - virtual bool shh_post(Json::Value const& _json); - virtual bool shh_uninstallFilter(int const& _id); - - void setAccounts(std::vector const& _accounts); - void setIdentities(std::vector const& _ids); - std::map const& ids() const { return m_ids; } - -protected: - virtual bool authenticate(dev::TransactionSkeleton const& _t) const; +private: + dev::eth::Interface* client() override; + std::shared_ptr face() override; + dev::WebThreeNetworkFace* network() override; + dev::WebThreeStubDatabaseFace* db() override; + std::string get(std::string const& _name, std::string const& _key) override; + void put(std::string const& _name, std::string const& _key, std::string const& _value) override; private: - dev::eth::Interface* client() const; - std::shared_ptr face() const; dev::WebThreeDirect& m_web3; - std::map m_accounts; - - ldb::ReadOptions m_readOptions; - ldb::WriteOptions m_writeOptions; - ldb::DB* m_db; - - std::map m_ids; - std::map m_shhWatches; + leveldb::ReadOptions m_readOptions; + leveldb::WriteOptions m_writeOptions; + leveldb::DB* m_db; }; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp new file mode 100644 index 000000000..565db9555 --- /dev/null +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -0,0 +1,664 @@ +/* + 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 WebThreeStubServerBase.cpp + * @authors: + * Gav Wood + * Marek Kotewicz + * @date 2014 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "WebThreeStubServerBase.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +static Json::Value toJson(dev::eth::BlockInfo const& _bi) +{ + Json::Value res; + res["hash"] = boost::lexical_cast(_bi.hash); + res["parentHash"] = toJS(_bi.parentHash); + res["sha3Uncles"] = toJS(_bi.sha3Uncles); + res["miner"] = toJS(_bi.coinbaseAddress); + res["stateRoot"] = toJS(_bi.stateRoot); + res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["difficulty"] = toJS(_bi.difficulty); + res["number"] = (int)_bi.number; + res["gasLimit"] = (int)_bi.gasLimit; + res["timestamp"] = (int)_bi.timestamp; + res["extraData"] = jsFromBinary(_bi.extraData); + res["nonce"] = toJS(_bi.nonce); + return res; +} + +static Json::Value toJson(dev::eth::Transaction const& _t) +{ + Json::Value res; + res["hash"] = toJS(_t.sha3()); + res["input"] = jsFromBinary(_t.data()); + res["to"] = toJS(_t.receiveAddress()); + res["from"] = toJS(_t.sender()); + res["gas"] = (int)_t.gas(); + res["gasPrice"] = toJS(_t.gasPrice()); + res["nonce"] = toJS(_t.nonce()); + res["value"] = toJS(_t.value()); + return res; +} + +static Json::Value toJson(dev::eth::LogEntry const& _e) +{ + Json::Value res; + + res["data"] = jsFromBinary(_e.data); + res["address"] = toJS(_e.address); + for (auto const& t: _e.topics) + res["topics"].append(toJS(t)); + return res; +} + +static Json::Value toJson(dev::eth::LogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7. +{ + Json::Value res; + for (dev::eth::LogEntry const& e: _es) + res.append(toJson(e)); + return res; +} + +static Json::Value toJson(std::map const& _storage) +{ + Json::Value res(Json::objectValue); + for (auto i: _storage) + res[toJS(i.first)] = toJS(i.second); + return res; +} + +static dev::eth::LogFilter toLogFilter(Json::Value const& _json) // commented to avoid warning. Uncomment once in use @ PoC-7. +{ + dev::eth::LogFilter filter; + if (!_json.isObject() || _json.empty()) + return filter; + + if (_json["earliest"].isInt()) + filter.withEarliest(_json["earliest"].asInt()); + if (_json["latest"].isInt()) + filter.withLatest(_json["lastest"].asInt()); + if (_json["max"].isInt()) + filter.withMax(_json["max"].asInt()); + if (_json["skip"].isInt()) + filter.withSkip(_json["skip"].asInt()); + if (!_json["address"].empty()) + { + if (_json["address"].isArray()) + { + for (auto i : _json["address"]) + if (i.isString()) + filter.address(jsToAddress(i.asString())); + } + else if (_json["address"].isString()) + filter.address(jsToAddress(_json["address"].asString())); + } + if (!_json["topics"].empty()) + { + if (_json["topics"].isArray()) + { + for (auto i: _json["topics"]) + if (i.isString()) + filter.topic(jsToU256(i.asString())); + } + else if(_json["topics"].isString()) + filter.topic(jsToU256(_json["topics"].asString())); + } + return filter; +} + +static shh::Message toMessage(Json::Value const& _json) +{ + shh::Message ret; + if (_json["from"].isString()) + ret.setFrom(jsToPublic(_json["from"].asString())); + if (_json["to"].isString()) + ret.setTo(jsToPublic(_json["to"].asString())); + if (_json["payload"].isString()) + ret.setPayload(jsToBytes(_json["payload"].asString())); + return ret; +} + +static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) +{ + unsigned ttl = 50; + unsigned workToProve = 50; + shh::BuildTopic bt; + + if (_json["ttl"].isInt()) + ttl = _json["ttl"].asInt(); + if (_json["workToProve"].isInt()) + workToProve = _json["workToProve"].asInt(); + if (!_json["topic"].empty()) + { + if (_json["topic"].isString()) + bt.shift(jsToBytes(_json["topic"].asString())); + else if (_json["topic"].isArray()) + for (auto i: _json["topic"]) + if (i.isString()) + bt.shift(jsToBytes(i.asString())); + } + return _m.seal(_from, bt, ttl, workToProve); +} + +static pair toWatch(Json::Value const& _json) +{ + shh::BuildTopicMask bt; + Public to; + + if (_json["to"].isString()) + to = jsToPublic(_json["to"].asString()); + + if (!_json["topic"].empty()) + { + if (_json["topic"].isString()) + bt.shift(jsToBytes(_json["topic"].asString())); + else if (_json["topic"].isArray()) + for (auto i: _json["topic"]) + if (i.isString()) + bt.shift(jsToBytes(i.asString())); + } + return make_pair(bt.toTopicMask(), to); +} + +static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) +{ + Json::Value res; + res["hash"] = toJS(_h); + res["expiry"] = (int)_e.expiry(); + res["sent"] = (int)_e.sent(); + res["ttl"] = (int)_e.ttl(); + res["workProved"] = (int)_e.workProved(); + for (auto const& t: _e.topics()) + res["topics"].append(toJS(t)); + res["payload"] = toJS(_m.payload()); + res["from"] = toJS(_m.from()); + res["to"] = toJS(_m.to()); + return res; +} + +WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): + AbstractWebThreeStubServer(_conn) +{ + setAccounts(_accounts); +} + +void WebThreeStubServerBase::setAccounts(std::vector const& _accounts) +{ + m_accounts.clear(); + for (auto i: _accounts) + m_accounts[i.address()] = i.secret(); +} + +void WebThreeStubServerBase::setIdentities(std::vector const& _ids) +{ + m_ids.clear(); + for (auto i: _ids) + m_ids[i.pub()] = i.secret(); +} + +std::string WebThreeStubServerBase::web3_sha3(std::string const& _param1) +{ + return toJS(sha3(jsToBytes(_param1))); +} + +Json::Value WebThreeStubServerBase::eth_accounts() +{ + Json::Value ret(Json::arrayValue); + for (auto i: m_accounts) + ret.append(toJS(i.first)); + return ret; +} + +std::string WebThreeStubServerBase::shh_addToGroup(std::string const& _group, std::string const& _who) +{ + (void)_group; + (void)_who; + return ""; +} + +std::string WebThreeStubServerBase::eth_balanceAt(string const& _address) +{ + return toJS(client()->balanceAt(jsToAddress(_address), client()->getDefault())); +} + +Json::Value WebThreeStubServerBase::eth_blockByHash(std::string const& _hash) +{ + return toJson(client()->blockInfo(jsToFixed<32>(_hash))); +} + +Json::Value WebThreeStubServerBase::eth_blockByNumber(int const& _number) +{ + return toJson(client()->blockInfo(client()->hashFromNumber(_number))); +} + +static TransactionSkeleton toTransaction(Json::Value const& _json) +{ + TransactionSkeleton ret; + if (!_json.isObject() || _json.empty()) + return ret; + + if (_json["from"].isString()) + ret.from = jsToAddress(_json["from"].asString()); + if (_json["to"].isString()) + ret.to = jsToAddress(_json["to"].asString()); + if (!_json["value"].empty()) + { + if (_json["value"].isString()) + ret.value = jsToU256(_json["value"].asString()); + else if (_json["value"].isInt()) + ret.value = u256(_json["value"].asInt()); + } + if (!_json["gas"].empty()) + { + if (_json["gas"].isString()) + ret.gas = jsToU256(_json["gas"].asString()); + else if (_json["gas"].isInt()) + ret.gas = u256(_json["gas"].asInt()); + } + if (!_json["gasPrice"].empty()) + { + if (_json["gasPrice"].isString()) + ret.gasPrice = jsToU256(_json["gasPrice"].asString()); + else if (_json["gasPrice"].isInt()) + ret.gas = u256(_json["gas"].asInt()); + } + if (!_json["data"].empty()) + { + if (_json["data"].isString()) // ethereum.js has preconstructed the data array + ret.data = jsToBytes(_json["data"].asString()); + else if (_json["data"].isArray()) // old style: array of 32-byte-padded values. TODO: remove PoC-8 + for (auto i: _json["data"]) + dev::operator +=(ret.data, padded(jsToBytes(i.asString()), 32)); + } + + if (_json["code"].isString()) + ret.data = jsToBytes(_json["code"].asString()); + return ret; +} + +std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) +{ + std::string ret; + TransactionSkeleton t = toTransaction(_json); + if (!t.from && m_accounts.size()) + { + auto b = m_accounts.begin()->first; + for (auto a: m_accounts) + if (client()->balanceAt(a.first) > client()->balanceAt(b)) + b = a.first; + t.from = b; + } + if (!m_accounts.count(t.from)) + return ret; + if (!t.gasPrice) + t.gasPrice = 10 * dev::eth::szabo; + if (!t.gas) + t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + ret = toJS(client()->call(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice)); + return ret; +} + +bool WebThreeStubServerBase::eth_changed(int const& _id) +{ + return client()->checkWatch(_id); +} + +std::string WebThreeStubServerBase::eth_codeAt(string const& _address) +{ + return jsFromBinary(client()->codeAt(jsToAddress(_address), client()->getDefault())); +} + +std::string WebThreeStubServerBase::eth_coinbase() +{ + return toJS(client()->address()); +} + +double WebThreeStubServerBase::eth_countAt(string const& _address) +{ + return (double)(uint64_t)client()->countAt(jsToAddress(_address), client()->getDefault()); +} + +int WebThreeStubServerBase::eth_defaultBlock() +{ + return client()->getDefault(); +} + +std::string WebThreeStubServerBase::eth_gasPrice() +{ + return toJS(10 * dev::eth::szabo); +} + +std::string WebThreeStubServerBase::db_get(std::string const& _name, std::string const& _key) +{ + string ret = db()->get(_name, _key); + return toJS(dev::asBytes(ret)); +} + +Json::Value WebThreeStubServerBase::eth_filterLogs(int const& _id) +{ + return toJson(client()->logs(_id)); +} + +Json::Value WebThreeStubServerBase::eth_logs(Json::Value const& _json) +{ + return toJson(client()->logs(toLogFilter(_json))); +} + +std::string WebThreeStubServerBase::db_getString(std::string const& _name, std::string const& _key) +{ + return db()->get(_name, _key);; +} + +bool WebThreeStubServerBase::shh_haveIdentity(std::string const& _id) +{ + return m_ids.count(jsToPublic(_id)) > 0; +} + +bool WebThreeStubServerBase::eth_listening() +{ + return network()->isNetworkStarted(); +} + +bool WebThreeStubServerBase::eth_mining() +{ + return client()->isMining(); +} + +int WebThreeStubServerBase::eth_newFilter(Json::Value const& _json) +{ + unsigned ret = -1; + ret = client()->installWatch(toLogFilter(_json)); + return ret; +} + +int WebThreeStubServerBase::eth_newFilterString(std::string const& _filter) +{ + unsigned ret = -1; + if (_filter.compare("chain") == 0) + ret = client()->installWatch(dev::eth::ChainChangedFilter); + else if (_filter.compare("pending") == 0) + ret = client()->installWatch(dev::eth::PendingChangedFilter); + return ret; +} + +std::string WebThreeStubServerBase::shh_newGroup(std::string const& _id, std::string const& _who) +{ + (void)_id; + (void)_who; + return ""; +} + +std::string WebThreeStubServerBase::shh_newIdentity() +{ +// cnote << this << m_ids; + KeyPair kp = KeyPair::create(); + m_ids[kp.pub()] = kp.secret(); + return toJS(kp.pub()); +} + +Json::Value WebThreeStubServerBase::eth_compilers() +{ + Json::Value ret(Json::arrayValue); + ret.append("lll"); + ret.append("solidity"); + ret.append("serpent"); + return ret; +} + +std::string WebThreeStubServerBase::eth_lll(std::string const& _code) +{ + string res; + vector errors; + res = toJS(dev::eth::compileLLL(_code, true, &errors)); + cwarn << "LLL compilation errors: " << errors; + return res; +} + +std::string WebThreeStubServerBase::eth_serpent(std::string const& _code) +{ + string res; + try + { + res = toJS(dev::asBytes(::compile(_code))); + } + catch (string err) + { + cwarn << "Solidity compilation error: " << err; + } + catch (...) + { + cwarn << "Uncought serpent compilation exception"; + } + return res; +} + +std::string WebThreeStubServerBase::eth_solidity(std::string const& _code) +{ + string res; + dev::solidity::CompilerStack compiler; + try + { + res = toJS(compiler.compile(_code, true)); + } + catch (dev::Exception const& exception) + { + ostringstream error; + solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler); + cwarn << "Solidity compilation error: " << error.str(); + } + catch (...) + { + cwarn << "Uncought solidity compilation exception"; + } + return res; +} + +int WebThreeStubServerBase::eth_number() +{ + return client()->number() + 1; +} + +int WebThreeStubServerBase::eth_peerCount() +{ + return network()->peerCount(); +} + +bool WebThreeStubServerBase::shh_post(Json::Value const& _json) +{ + shh::Message m = toMessage(_json); + Secret from; + + if (m.from() && m_ids.count(m.from())) + { + cwarn << "Silently signing message from identity" << m.from().abridged() << ": User validation hook goes here."; + // TODO: insert validification hook here. + from = m_ids[m.from()]; + } + + face()->inject(toSealed(_json, m, from)); + return true; +} + +bool WebThreeStubServerBase::db_put(std::string const& _name, std::string const& _key, std::string const& _value) +{ + string v = asString(jsToBytes(_value)); + db()->put(_name, _key, v); + return true; +} + +bool WebThreeStubServerBase::db_putString(std::string const& _name, std::string const& _key, std::string const& _value) +{ + db()->put(_name, _key,_value); + return true; +} + +bool WebThreeStubServerBase::eth_setCoinbase(std::string const& _address) +{ + client()->setAddress(jsToAddress(_address)); + return true; +} + +bool WebThreeStubServerBase::eth_setDefaultBlock(int const& _block) +{ + client()->setDefault(_block); + return true; +} + +bool WebThreeStubServerBase::eth_setListening(bool const& _listening) +{ + if (_listening) + network()->startNetwork(); + else + network()->stopNetwork(); + return true; +} + +bool WebThreeStubServerBase::eth_setMining(bool const& _mining) +{ + if (_mining) + client()->startMining(); + else + client()->stopMining(); + return true; +} + +Json::Value WebThreeStubServerBase::shh_changed(int const& _id) +{ + Json::Value ret(Json::arrayValue); + auto pub = m_shhWatches[_id]; + if (!pub || m_ids.count(pub)) + for (h256 const& h: face()->checkWatch(_id)) + { + auto e = face()->envelope(h); + shh::Message m; + if (pub) + { + cwarn << "Silently decrypting message from identity" << pub.abridged() << ": User validation hook goes here."; + m = e.open(m_ids[pub]); + if (!m) + continue; + } + else + m = e.open(); + ret.append(toJson(h, e, m)); + } + + return ret; +} + +int WebThreeStubServerBase::shh_newFilter(Json::Value const& _json) +{ + auto w = toWatch(_json); + auto ret = face()->installWatch(w.first); + m_shhWatches.insert(make_pair(ret, w.second)); + return ret; +} + +bool WebThreeStubServerBase::shh_uninstallFilter(int const& _id) +{ + face()->uninstallWatch(_id); + return true; +} + +std::string WebThreeStubServerBase::eth_stateAt(string const& _address, string const& _storage) +{ + return toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), client()->getDefault())); +} + +Json::Value WebThreeStubServerBase::eth_storageAt(string const& _address) +{ + return toJson(client()->storageAt(jsToAddress(_address))); +} + +std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) +{ + std::string ret; + TransactionSkeleton t = toTransaction(_json); + if (!t.from && m_accounts.size()) + { + auto b = m_accounts.begin()->first; + for (auto a: m_accounts) + if (client()->balanceAt(a.first) > client()->balanceAt(b)) + b = a.first; + t.from = b; + } + if (!m_accounts.count(t.from)) + return ret; + if (!t.gasPrice) + t.gasPrice = 10 * dev::eth::szabo; + if (!t.gas) + t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + if (authenticate(t)) + { + if (t.to) + // TODO: from qethereum, insert validification hook here. + client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); + else + ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); + client()->flushTransactions(); + } + return ret; +} + +bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t) const +{ + cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; + return true; +} + +Json::Value WebThreeStubServerBase::eth_transactionByHash(std::string const& _hash, int const& _i) +{ + return toJson(client()->transaction(jsToFixed<32>(_hash), _i)); +} + +Json::Value WebThreeStubServerBase::eth_transactionByNumber(int const& _number, int const& _i) +{ + return toJson(client()->transaction(client()->hashFromNumber(_number), _i)); +} + +Json::Value WebThreeStubServerBase::eth_uncleByHash(std::string const& _hash, int const& _i) +{ + return toJson(client()->uncle(jsToFixed<32>(_hash), _i)); +} + +Json::Value WebThreeStubServerBase::eth_uncleByNumber(int const& _number, int const& _i) +{ + return toJson(client()->uncle(client()->hashFromNumber(_number), _i)); +} + +bool WebThreeStubServerBase::eth_uninstallFilter(int const& _id) +{ + client()->uninstallWatch(_id); + return true; +} + diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h new file mode 100644 index 000000000..6868207a6 --- /dev/null +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -0,0 +1,138 @@ +/* + 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 WebThreeStubServer.h + * @authors: + * Gav Wood + * Marek Kotewicz + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include "abstractwebthreestubserver.h" +#pragma GCC diagnostic pop + + +namespace dev +{ +class WebThreeNetworkFace; +class KeyPair; +class TransactionSkeleton; +namespace eth +{ +class Interface; +} +namespace shh +{ +class Interface; +} + +class WebThreeStubDatabaseFace +{ +public: + virtual std::string get(std::string const& _name, std::string const& _key) = 0; + virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) = 0; +}; + +/** + * @brief JSON-RPC api implementation + * @todo filters should work on unsigned instead of int + * unsigned are not supported in json-rpc-cpp and there are bugs with double in json-rpc-cpp version 0.2.1 + * @todo split these up according to subprotocol (eth, shh, db, p2p, web3) and make it /very/ clear about how to add other subprotocols. + * @todo modularise everything so additional subprotocols don't need to change this file. + */ +class WebThreeStubServerBase: public AbstractWebThreeStubServer +{ +public: + WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts); + + virtual std::string web3_sha3(std::string const& _param1); + virtual Json::Value eth_accounts(); + virtual std::string eth_balanceAt(std::string const& _address); + virtual Json::Value eth_blockByHash(std::string const& _hash); + virtual Json::Value eth_blockByNumber(int const& _number); + virtual std::string eth_call(Json::Value const& _json); + virtual bool eth_changed(int const& _id); + virtual std::string eth_codeAt(std::string const& _address); + virtual std::string eth_coinbase(); + virtual Json::Value eth_compilers(); + virtual double eth_countAt(std::string const& _address); + virtual int eth_defaultBlock(); + virtual std::string eth_gasPrice(); + virtual Json::Value eth_filterLogs(int const& _id); + virtual Json::Value eth_logs(Json::Value const& _json); + virtual bool eth_listening(); + virtual bool eth_mining(); + virtual int eth_newFilter(Json::Value const& _json); + virtual int eth_newFilterString(std::string const& _filter); + virtual int eth_number(); + virtual int eth_peerCount(); + virtual bool eth_setCoinbase(std::string const& _address); + virtual bool eth_setDefaultBlock(int const& _block); + virtual bool eth_setListening(bool const& _listening); + virtual std::string eth_lll(std::string const& _s); + virtual std::string eth_serpent(std::string const& _s); + virtual bool eth_setMining(bool const& _mining); + virtual std::string eth_solidity(std::string const& _code); + virtual std::string eth_stateAt(std::string const& _address, std::string const& _storage); + virtual Json::Value eth_storageAt(std::string const& _address); + virtual std::string eth_transact(Json::Value const& _json); + virtual Json::Value eth_transactionByHash(std::string const& _hash, int const& _i); + virtual Json::Value eth_transactionByNumber(int const& _number, int const& _i); + virtual Json::Value eth_uncleByHash(std::string const& _hash, int const& _i); + virtual Json::Value eth_uncleByNumber(int const& _number, int const& _i); + virtual bool eth_uninstallFilter(int const& _id); + + virtual std::string db_get(std::string const& _name, std::string const& _key); + virtual std::string db_getString(std::string const& _name, std::string const& _key); + virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value); + virtual bool db_putString(std::string const& _name, std::string const& _key, std::string const& _value); + + virtual std::string shh_addToGroup(std::string const& _group, std::string const& _who); + virtual Json::Value shh_changed(int const& _id); + virtual bool shh_haveIdentity(std::string const& _id); + virtual int shh_newFilter(Json::Value const& _json); + virtual std::string shh_newGroup(std::string const& _id, std::string const& _who); + virtual std::string shh_newIdentity(); + virtual bool shh_post(Json::Value const& _json); + virtual bool shh_uninstallFilter(int const& _id); + + void setAccounts(std::vector const& _accounts); + void setIdentities(std::vector const& _ids); + std::map const& ids() const { return m_ids; } + +protected: + virtual bool authenticate(dev::TransactionSkeleton const& _t) const; + +protected: + virtual dev::eth::Interface* client() = 0; + virtual std::shared_ptr face() = 0; + virtual dev::WebThreeNetworkFace* network() = 0; + virtual dev::WebThreeStubDatabaseFace* db() = 0; + + std::map m_accounts; + + std::map m_ids; + std::map m_shhWatches; +}; + +} //namespace dev diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index ec7bf2406..682fdc0b6 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -38,8 +38,6 @@ namespace dev { -class InterfaceNotSupported: public Exception { public: InterfaceNotSupported(std::string _f): m_f(_f) {} virtual const char* what() const noexcept { return ("Interface " + m_f + " not supported.").c_str(); } private: std::string m_f; }; - enum WorkState { Active = 0, @@ -51,6 +49,48 @@ namespace eth { class Interface; } namespace shh { class Interface; } namespace bzz { class Interface; } + +class WebThreeNetworkFace +{ +public: + /// Get information on the current peer set. + virtual std::vector peers() = 0; + + /// Same as peers().size(), but more efficient. + virtual size_t peerCount() const = 0; + + /// Connect to a particular peer. + virtual void connect(std::string const& _seedHost, unsigned short _port) = 0; + + /// Save peers + virtual dev::bytes saveNodes() = 0; + + /// Restore peers + virtual void restoreNodes(bytesConstRef _saved) = 0; + + /// Sets the ideal number of peers. + virtual void setIdealPeerCount(size_t _n) = 0; + + virtual bool haveNetwork() const = 0; + + virtual void setNetworkPreferences(p2p::NetworkPreferences const& _n) = 0; + + virtual p2p::NodeId id() const = 0; + + /// Gets the nodes. + virtual p2p::Nodes nodes() const = 0; + + /// Start the network subsystem. + virtual void startNetwork() = 0; + + /// Stop the network subsystem. + virtual void stopNetwork() = 0; + + /// Is network working? there may not be any peers yet. + virtual bool isNetworkStarted() const = 0; +}; + + /** * @brief Main API hub for interfacing with Web 3 components. This doesn't do any local multiplexing, so you can only have one * running on any given machine for the provided DB path. @@ -61,7 +101,7 @@ namespace bzz { class Interface; } * * Provides a baseline for the multiplexed multi-protocol session class, WebThree. */ -class WebThreeDirect +class WebThreeDirect : public WebThreeNetworkFace { public: /// Constructor for private instance. If there is already another process on the machine using @a _dbPath, then this will throw an exception. @@ -84,40 +124,40 @@ public: // Network stuff: /// Get information on the current peer set. - std::vector peers(); + std::vector peers() override; /// Same as peers().size(), but more efficient. - size_t peerCount() const; + size_t peerCount() const override; /// Connect to a particular peer. - void connect(std::string const& _seedHost, unsigned short _port = 30303); + void connect(std::string const& _seedHost, unsigned short _port = 30303) override; /// Save peers - dev::bytes saveNodes(); + dev::bytes saveNodes() override; /// Restore peers - void restoreNodes(bytesConstRef _saved); + void restoreNodes(bytesConstRef _saved) override; /// Sets the ideal number of peers. - void setIdealPeerCount(size_t _n); + void setIdealPeerCount(size_t _n) override; - bool haveNetwork() const { return m_net.isStarted(); } + bool haveNetwork() const override { return m_net.isStarted(); } - void setNetworkPreferences(p2p::NetworkPreferences const& _n); + void setNetworkPreferences(p2p::NetworkPreferences const& _n) override; - p2p::NodeId id() const { return m_net.id(); } + p2p::NodeId id() const override { return m_net.id(); } /// Gets the nodes. - p2p::Nodes nodes() const { return m_net.nodes(); } + p2p::Nodes nodes() const override { return m_net.nodes(); } /// Start the network subsystem. - void startNetwork() { m_net.start(); } + void startNetwork() override { m_net.start(); } /// Stop the network subsystem. - void stopNetwork() { m_net.stop(); } + void stopNetwork() override { m_net.stop(); } /// Is network working? there may not be any peers yet. - bool isNetworkStarted() { return m_net.isStarted(); } + bool isNetworkStarted() const override { return m_net.isStarted(); } private: std::string m_clientVersion; ///< Our end-application client's name/version. diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index 049cb04ea..4bede3c49 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -27,13 +27,10 @@ #include #include #include -#include -#include -#include -#include #include #include "CodeModel.h" #include "FileIo.h" +#include "ClientModel.h" #include "AppContext.h" @@ -47,7 +44,8 @@ AppContext::AppContext(QQmlApplicationEngine* _engine) { m_applicationEngine = _engine; //m_webThree = std::unique_ptr(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"})); - m_codeModel = std::unique_ptr(new CodeModel(this)); + m_codeModel.reset(new CodeModel(this)); + m_clientModel.reset(new ClientModel(this)); m_fileIo.reset(new FileIo()); m_applicationEngine->rootContext()->setContextProperty("appContext", this); qmlRegisterType("org.ethereum.qml", 1, 0, "FileIo"); @@ -61,21 +59,6 @@ AppContext::~AppContext() { } -void AppContext::loadProject() -{ - QString path = QStandardPaths::locate(QStandardPaths::DataLocation, c_projectFileName); - if (!path.isEmpty()) - { - QFile file(path); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - QTextStream stream(&file); - QString json = stream.readAll(); - emit projectLoaded(json); - } - } -} - QQmlApplicationEngine* AppContext::appEngine() { return m_applicationEngine; @@ -93,19 +76,3 @@ void AppContext::displayMessageDialog(QString _title, QString _message) dialogWin->findChild("messageContent", Qt::FindChildrenRecursively)->setProperty("text", _message); QMetaObject::invokeMethod(dialogWin, "open"); } - -void AppContext::saveProject(QString const& _json) -{ - QDir dirPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation)); - QString path = QDir(dirPath).filePath(c_projectFileName); - if (!path.isEmpty()) - { - dirPath.mkpath(dirPath.path()); - QFile file(path); - if (file.open(QIODevice::WriteOnly | QIODevice::Text)) - { - QTextStream stream(&file); - stream << _json; - } - } -} diff --git a/mix/AppContext.h b/mix/AppContext.h index 3db3414d9..dec3b319e 100644 --- a/mix/AppContext.h +++ b/mix/AppContext.h @@ -47,6 +47,7 @@ namespace mix { class CodeModel; +class ClientModel; class FileIo; /** * @brief Provides access to application scope variable. @@ -63,24 +64,25 @@ public: QQmlApplicationEngine* appEngine(); /// Get code model CodeModel* codeModel() { return m_codeModel.get(); } + /// Get client model + ClientModel* clientModel() { return m_clientModel.get(); } /// Display an alert message. void displayMessageDialog(QString _title, QString _message); - /// Load project settings - void loadProject(); + signals: - void projectLoaded(QString const& _json); + /// Triggered once components have been loaded + void appLoaded(); private: QQmlApplicationEngine* m_applicationEngine; //owned by app std::unique_ptr m_webThree; std::unique_ptr m_codeModel; + std::unique_ptr m_clientModel; std::unique_ptr m_fileIo; public slots: /// Delete the current instance when application quit. void quitApplication() {} - /// Write json to a settings file - void saveProject(QString const& _json); }; } diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index 136353dc6..b503757d0 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -17,53 +17,19 @@ * display opcode debugging. */ -#include #include #include #include -#include -#include -#include -#include "AssemblyDebuggerModel.h" -#include "AssemblyDebuggerControl.h" #include "AppContext.h" -#include "DebuggingStateWrapper.h" -#include "QContractDefinition.h" -#include "QVariableDeclaration.h" -#include "ContractCallDataEncoder.h" -#include "CodeModel.h" +#include "ClientModel.h" +#include "AssemblyDebuggerControl.h" -using namespace dev::eth; using namespace dev::mix; -/// @todo Move this to QML -dev::u256 fromQString(QString const& _s) -{ - return dev::jsToU256(_s.toStdString()); -} - -/// @todo Move this to QML -QString toQString(dev::u256 _value) -{ - std::ostringstream s; - s << _value; - return QString::fromStdString(s.str()); -} - AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): - Extension(_context, ExtensionDisplayBehavior::ModalDialog), m_running(false) + Extension(_context, ExtensionDisplayBehavior::ModalDialog) { - qRegisterMetaType("QVariableDefinition*"); - qRegisterMetaType("QVariableDefinitionList*"); - qRegisterMetaType>("QList"); - qRegisterMetaType>("QList"); - qRegisterMetaType("QVariableDeclaration*"); - qRegisterMetaType("AssemblyDebuggerData"); - - connect(this, &AssemblyDebuggerControl::dataAvailable, this, &AssemblyDebuggerControl::showDebugger, Qt::QueuedConnection); - m_modelDebugger = std::unique_ptr(new AssemblyDebuggerModel); - - _context->appEngine()->rootContext()->setContextProperty("debugModel", this); + connect(_context->clientModel(), &ClientModel::showDebuggerWindow, this, &AssemblyDebuggerControl::showDebugger, Qt::QueuedConnection); } QString AssemblyDebuggerControl::contentUrl() const @@ -80,132 +46,7 @@ void AssemblyDebuggerControl::start() const { } -void AssemblyDebuggerControl::debugDeployment() -{ - executeSequence(std::vector(), 0); -} - -void AssemblyDebuggerControl::debugState(QVariantMap _state) -{ - u256 balance = fromQString(_state.value("balance").toString()); - QVariantList transactions = _state.value("transactions").toList(); - - std::vector transactionSequence; - - for (auto const& t: transactions) - { - QVariantMap transaction = t.toMap(); - - QString functionId = transaction.value("functionId").toString(); - u256 value = fromQString(transaction.value("value").toString()); - u256 gas = fromQString(transaction.value("gas").toString()); - u256 gasPrice = fromQString(transaction.value("gasPrice").toString()); - QVariantMap params = transaction.value("parameters").toMap(); - TransactionSettings transactionSettings(functionId, value, gas, gasPrice); - - for (auto p = params.cbegin(); p != params.cend(); ++p) - transactionSettings.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString()))); - - transactionSequence.push_back(transactionSettings); - } - executeSequence(transactionSequence, balance); -} - -void AssemblyDebuggerControl::executeSequence(std::vector const& _sequence, u256 _balance) -{ - if (m_running) - throw (std::logic_error("debugging already running")); - auto compilerRes = m_ctx->codeModel()->code(); - std::shared_ptr contractDef = compilerRes->sharedContract(); - m_running = true; - - emit runStarted(); - emit stateChanged(); - - //run sequence - QtConcurrent::run([=]() - { - try - { - bytes contractCode = compilerRes->bytes(); - std::vector transactonData; - QFunctionDefinition* f; - ContractCallDataEncoder c; - //encode data for all transactions - for (auto const& t: _sequence) - { - f = nullptr; - for (int tf = 0; tf < contractDef->functionsList().size(); tf++) - { - if (contractDef->functionsList().at(tf)->name() == t.functionId) - { - f = contractDef->functionsList().at(tf); - break; - } - } - if (!f) - throw std::runtime_error("function " + t.functionId.toStdString() + " not found"); - - c.encode(f->index()); - for (int p = 0; p < f->parametersList().size(); p++) - { - QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(p); - u256 value = 0; - auto v = t.parameterValues.find(var->name()); - if (v != t.parameterValues.cend()) - value = v->second; - c.encode(var, value); - } - transactonData.emplace_back(c.encodedData()); - } - - //run contract creation first - m_modelDebugger->resetState(_balance); - DebuggingContent debuggingContent = m_modelDebugger->deployContract(contractCode); - Address address = debuggingContent.contractAddress; - for (unsigned i = 0; i < _sequence.size(); ++i) - debuggingContent = m_modelDebugger->callContract(address, transactonData.at(i), _sequence.at(i)); - - if (f) - debuggingContent.returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue); - - //we need to wrap states in a QObject before sending to QML. - QList wStates; - for (int i = 0; i < debuggingContent.machineStates.size(); i++) - { - QPointer s(new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes())); - s->setState(debuggingContent.machineStates.at(i)); - wStates.append(s); - } - //collect states for last transaction - AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode); - emit dataAvailable(debuggingContent.returnParameters, wStates, code); - emit runComplete(); - } - catch(boost::exception const&) - { - emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); - } - - catch(std::exception const& e) - { - emit runFailed(e.what()); - } - m_running = false; - emit stateChanged(); - }); -} - -void AssemblyDebuggerControl::showDebugger(QList const& _returnParam, QList const& _wStates, AssemblyDebuggerData const& _code) +void AssemblyDebuggerControl::showDebugger() { - m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates)); - m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code))); - m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code))); - m_appEngine->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam))); this->addContentOn(this); } - -void AssemblyDebuggerControl::showDebugError(QString const& _error) -{ - m_ctx->displayMessageDialog(QApplication::tr("Debugger"), _error); -} diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index b4dff38f5..dbe9b0676 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -20,14 +20,7 @@ #pragma once #include -#include #include "Extension.h" -#include "AssemblyDebuggerModel.h" - -using AssemblyDebuggerData = std::tuple, dev::mix::QQMLMap*>; - -Q_DECLARE_METATYPE(AssemblyDebuggerData) -Q_DECLARE_METATYPE(dev::mix::DebuggingContent) class AppContext; @@ -37,7 +30,7 @@ namespace mix { /** - * @brief Extension which display transaction creation or transaction call debugging. handle: F5 to deploy contract, F6 to reset state. + * @brief Extension which display transaction creation or transaction call debugging. */ class AssemblyDebuggerControl: public Extension { @@ -50,40 +43,9 @@ public: QString title() const override; QString contentUrl() const override; - Q_PROPERTY(bool running MEMBER m_running NOTIFY stateChanged) - -private: - void executeSequence(std::vector const& _sequence, u256 _balance); - - std::unique_ptr m_modelDebugger; - std::atomic m_running; - -public slots: - /// Run the contract constructor and show debugger window. - void debugDeployment(); - /// Setup state, run transaction sequence, show debugger for the last transaction - /// @param _state JS object with state configuration - void debugState(QVariantMap _state); - private slots: /// Update UI with machine states result. Display a modal dialog. - void showDebugger(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); - /// Update UI with transaction run error. - void showDebugError(QString const& _error); - -signals: - /// Transaction execution started - void runStarted(); - /// Transaction execution completed successfully - void runComplete(); - /// Transaction execution completed with error - /// @param _message Error message - void runFailed(QString const& _message); - /// Execution state changed - void stateChanged(); - - /// Emited when machine states are available. - void dataAvailable(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); + void showDebugger(); }; } diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp deleted file mode 100644 index e822d0a3f..000000000 --- a/mix/AssemblyDebuggerModel.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - 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 AssemblyDebuggerModel.cpp - * @author Yann yann@ethdev.com - * @date 2014 - * used as a model to debug contract assembly code. - */ - -#include -#include -#include -#include -#include -#include -#include "AssemblyDebuggerModel.h" -#include "AppContext.h" -#include "DebuggingStateWrapper.h" - -using namespace std; -using namespace dev; -using namespace dev::eth; - -namespace dev -{ -namespace mix -{ - -AssemblyDebuggerModel::AssemblyDebuggerModel(): - m_userAccount(KeyPair::create()) -{ - resetState(10000000 * ether); -} - -DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction) -{ - QList machineStates; - eth::Executive execution(m_executiveState, LastHashes(), 0); - execution.setup(_rawTransaction); - std::vector levels; - bytes code; - bytesConstRef data; - bool firstIteration = true; - auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) - { - VM& vm = *(VM*)voidVM; - ExtVM const& ext = *(ExtVM const*)voidExt; - - if (firstIteration) - { - code = ext.code; - data = ext.data; - firstIteration = false; - } - - if (levels.size() < ext.depth) - levels.push_back(&machineStates.back()); - else - levels.resize(ext.depth); - - machineStates.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), - vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); - }; - - execution.go(onOp); - execution.finalize(); - - DebuggingContent d; - d.returnValue = execution.out().toVector(); - d.machineStates = machineStates; - d.executionCode = code; - d.executionData = data; - d.contentAvailable = true; - d.message = "ok"; - return d; -} - -DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code) -{ - u256 gasPrice = 10000000000000; - u256 gas = 1000000; - u256 amount = 100; - Transaction _tr(amount, gasPrice, min(gas, m_executiveState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); - bytes b = _tr.rlp(); - dev::bytesConstRef bytesRef = &b; - DebuggingContent d = executeTransaction(bytesRef); - h256 th = sha3(rlpList(_tr.sender(), _tr.nonce())); - d.contractAddress = right160(th); - return d; -} - -DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) -{ - Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_executiveState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); - bytes b = tr.rlp(); - dev::bytesConstRef bytesRef = &b; - DebuggingContent d = executeTransaction(bytesRef); - d.contractAddress = tr.receiveAddress(); - return d; -} - -void AssemblyDebuggerModel::resetState(u256 _balance) -{ - m_executiveState = eth::State(Address(), m_overlayDB, BaseState::Empty); - m_executiveState.addBalance(m_userAccount.address(), _balance); -} - -} -} diff --git a/mix/AssemblyDebuggerModel.h b/mix/AssemblyDebuggerModel.h deleted file mode 100644 index c12e711c6..000000000 --- a/mix/AssemblyDebuggerModel.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - 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 AssemblyDebuggerModel.h - * @author Yann yann@ethdev.com - * @date 2014 - * Used as a model to debug contract assembly code. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include "DebuggingStateWrapper.h" - -namespace dev -{ -namespace mix -{ - -/// Backend transaction config class -struct TransactionSettings -{ - TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): - functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} - - /// Contract function name - QString functionId; - /// Transaction value - u256 value; - /// Gas - u256 gas; - /// Gas price - u256 gasPrice; - /// Mapping from contract function parameter name to value - std::map parameterValues; -}; - - -/** - * @brief Long-life object for managing all executions. - */ -class AssemblyDebuggerModel -{ -public: - AssemblyDebuggerModel(); - /// Call function in a already deployed contract. - DebuggingContent callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); - /// Deploy the contract described by _code. - DebuggingContent deployContract(bytes const& _code); - /// Reset state to the empty state with given balance. - void resetState(u256 _balance); - -private: - KeyPair m_userAccount; - OverlayDB m_overlayDB; - eth::State m_executiveState; - DebuggingContent executeTransaction(dev::bytesConstRef const& _rawTransaction); -}; - -} -} diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp new file mode 100644 index 000000000..6859b0279 --- /dev/null +++ b/mix/ClientModel.cpp @@ -0,0 +1,222 @@ +/* + 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 ClientModel.cpp + * @author Yann yann@ethdev.com + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#include +#include +#include +#include +#include +#include +#include "ClientModel.h" +#include "AppContext.h" +#include "DebuggingStateWrapper.h" +#include "QContractDefinition.h" +#include "QVariableDeclaration.h" +#include "ContractCallDataEncoder.h" +#include "CodeModel.h" +#include "ClientModel.h" + +using namespace dev::eth; +using namespace dev::mix; + +/// @todo Move this to QML +dev::u256 fromQString(QString const& _s) +{ + return dev::jsToU256(_s.toStdString()); +} + +/// @todo Move this to QML +QString toQString(dev::u256 _value) +{ + std::ostringstream s; + s << _value; + return QString::fromStdString(s.str()); +} + +ClientModel::ClientModel(AppContext* _context): + m_context(_context), m_running(false) +{ + qRegisterMetaType("QVariableDefinition*"); + qRegisterMetaType("QVariableDefinitionList*"); + qRegisterMetaType>("QList"); + qRegisterMetaType>("QList"); + qRegisterMetaType("QVariableDeclaration*"); + qRegisterMetaType("AssemblyDebuggerData"); + + connect(this, &ClientModel::dataAvailable, this, &ClientModel::showDebugger, Qt::QueuedConnection); + m_client.reset(new MixClient()); + + _context->appEngine()->rootContext()->setContextProperty("clientModel", this); +} + +void ClientModel::debugDeployment() +{ + executeSequence(std::vector(), 10000000 * ether); +} + +void ClientModel::debugState(QVariantMap _state) +{ + u256 balance = fromQString(_state.value("balance").toString()); + QVariantList transactions = _state.value("transactions").toList(); + + std::vector transactionSequence; + + for (auto const& t: transactions) + { + QVariantMap transaction = t.toMap(); + + QString functionId = transaction.value("functionId").toString(); + u256 value = fromQString(transaction.value("value").toString()); + u256 gas = fromQString(transaction.value("gas").toString()); + u256 gasPrice = fromQString(transaction.value("gasPrice").toString()); + QVariantMap params = transaction.value("parameters").toMap(); + TransactionSettings transactionSettings(functionId, value, gas, gasPrice); + + for (auto p = params.cbegin(); p != params.cend(); ++p) + transactionSettings.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString()))); + + transactionSequence.push_back(transactionSettings); + } + executeSequence(transactionSequence, balance); +} + +void ClientModel::executeSequence(std::vector const& _sequence, u256 _balance) +{ + if (m_running) + throw (std::logic_error("debugging already running")); + auto compilerRes = m_context->codeModel()->code(); + std::shared_ptr contractDef = compilerRes->sharedContract(); + m_running = true; + + emit runStarted(); + emit stateChanged(); + + //run sequence + QtConcurrent::run([=]() + { + try + { + bytes contractCode = compilerRes->bytes(); + std::vector transactonData; + QFunctionDefinition* f; + ContractCallDataEncoder c; + //encode data for all transactions + for (auto const& t: _sequence) + { + f = nullptr; + for (int tf = 0; tf < contractDef->functionsList().size(); tf++) + { + if (contractDef->functionsList().at(tf)->name() == t.functionId) + { + f = contractDef->functionsList().at(tf); + break; + } + } + if (!f) + throw std::runtime_error("function " + t.functionId.toStdString() + " not found"); + + c.encode(f); + for (int p = 0; p < f->parametersList().size(); p++) + { + QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(p); + u256 value = 0; + auto v = t.parameterValues.find(var->name()); + if (v != t.parameterValues.cend()) + value = v->second; + c.encode(var, value); + } + transactonData.emplace_back(c.encodedData()); + } + + //run contract creation first + m_client->resetState(_balance); + ExecutionResult debuggingContent = deployContract(contractCode); + Address address = debuggingContent.contractAddress; + for (unsigned i = 0; i < _sequence.size(); ++i) + debuggingContent = callContract(address, transactonData.at(i), _sequence.at(i)); + + QList returnParameters; + + if (f) + returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue); + + //we need to wrap states in a QObject before sending to QML. + QList wStates; + for (unsigned i = 0; i < debuggingContent.machineStates.size(); i++) + { + QPointer s(new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes())); + s->setState(debuggingContent.machineStates[i]); + wStates.append(s); + } + //collect states for last transaction + AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode); + emit dataAvailable(returnParameters, wStates, code); + emit runComplete(); + } + catch(boost::exception const&) + { + emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); + } + + catch(std::exception const& e) + { + emit runFailed(e.what()); + } + m_running = false; + emit stateChanged(); + }); +} + +void ClientModel::showDebugger(QList const& _returnParam, QList const& _wStates, AssemblyDebuggerData const& _code) +{ + m_context->appEngine()->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates)); + m_context->appEngine()->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code))); + m_context->appEngine()->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code))); + m_context->appEngine()->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam))); + showDebuggerWindow(); +} + +void ClientModel::showDebugError(QString const& _error) +{ + //TODO: change that to a signal + m_context->displayMessageDialog(tr("Debugger"), _error); +} + +ExecutionResult ClientModel::deployContract(bytes const& _code) +{ + u256 gasPrice = 10000000000000; + u256 gas = 125000; + u256 amount = 100; + + Address contractAddress = m_client->transact(m_client->userAccount().secret(), amount, _code, gas, gasPrice); + ExecutionResult r = m_client->lastExecutionResult(); + r.contractAddress = contractAddress; + return r; +} + +ExecutionResult ClientModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) +{ + //bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; + m_client->transact(m_client->userAccount().secret(), _tr.value, _contract, _data, _tr.gas, _tr.gasPrice); + ExecutionResult r = m_client->lastExecutionResult(); + r.contractAddress = _contract; + return r; +} + diff --git a/mix/ClientModel.h b/mix/ClientModel.h new file mode 100644 index 000000000..509a5995b --- /dev/null +++ b/mix/ClientModel.h @@ -0,0 +1,113 @@ +/* + 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 ClientModel.h + * @author Yann yann@ethdev.com + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#pragma once + +#include +#include "DebuggingStateWrapper.h" +#include "MixClient.h" + +using AssemblyDebuggerData = std::tuple, dev::mix::QQMLMap*>; + +Q_DECLARE_METATYPE(AssemblyDebuggerData) +Q_DECLARE_METATYPE(dev::mix::ExecutionResult) + +namespace dev +{ +namespace mix +{ + +class AppContext; + +/// Backend transaction config class +struct TransactionSettings +{ + TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): + functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} + + /// Contract function name + QString functionId; + /// Transaction value + u256 value; + /// Gas + u256 gas; + /// Gas price + u256 gasPrice; + /// Mapping from contract function parameter name to value + std::map parameterValues; +}; + + +/** + * @brief Ethereum state control + */ +class ClientModel: public QObject +{ + Q_OBJECT + +public: + ClientModel(AppContext* _context); + + Q_PROPERTY(bool running MEMBER m_running NOTIFY stateChanged) + +public slots: + /// Run the contract constructor and show debugger window. + void debugDeployment(); + /// Setup state, run transaction sequence, show debugger for the last transaction + /// @param _state JS object with state configuration + void debugState(QVariantMap _state); + +private slots: + /// Update UI with machine states result. Display a modal dialog. + void showDebugger(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); + /// Update UI with transaction run error. + void showDebugError(QString const& _error); + +signals: + /// Transaction execution started + void runStarted(); + /// Transaction execution completed successfully + void runComplete(); + /// Transaction execution completed with error + /// @param _message Error message + void runFailed(QString const& _message); + /// Execution state changed + void stateChanged(); + /// Show debugger window request + void showDebuggerWindow(); + + /// Emited when machine states are available. + void dataAvailable(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); + +private: + void executeSequence(std::vector const& _sequence, u256 _balance); + ExecutionResult deployContract(bytes const& _code); + ExecutionResult callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); + + AppContext* m_context; + std::atomic m_running; + std::unique_ptr m_client; +}; + +} +} diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index 14795c223..f5ceb333e 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -31,6 +31,7 @@ #include "AppContext.h" #include "MixApplication.h" #include "CodeModel.h" +#include "ClientModel.h" #include "CodeHighlighter.h" #include "CodeEditorExtensionManager.h" @@ -58,7 +59,7 @@ void CodeEditorExtensionManager::initExtensions() std::shared_ptr output = std::make_shared(m_appContext); std::shared_ptr debug = std::make_shared(m_appContext); std::shared_ptr stateList = std::make_shared(m_appContext); - QObject::connect(debug.get(), &AssemblyDebuggerControl::runFailed, output.get(), &ConstantCompilationControl::displayError); + QObject::connect(m_appContext->clientModel(), &ClientModel::runFailed, output.get(), &ConstantCompilationControl::displayError); QObject::connect(m_appContext->codeModel(), &CodeModel::compilationComplete, this, &CodeEditorExtensionManager::applyCodeHighlight); initExtension(output); diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 7d8b0442a..87152360e 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -162,7 +162,7 @@ void CodeModel::onCompilationComplete(CompilationResult*_newResult) m_result.reset(_newResult); emit compilationComplete(); emit stateChanged(); - if (m_result->successfull()) + if (m_result->successful()) emit codeChanged(); } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index c66703b22..e1a2a0fbd 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -69,7 +69,7 @@ class CompilationResult: public QObject public: /// Empty compilation result constructor CompilationResult(); - /// Successfull compilation result constructor + /// Successful compilation result constructor CompilationResult(solidity::CompilerStack const& _compiler); /// Failed compilation result constructor CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage); @@ -78,9 +78,9 @@ public: QContractDefinition* contract() { return m_contract.get(); } /// @returns contract definition std::shared_ptr sharedContract() { return m_contract; } - /// Indicates if the compilation was successfull - bool successfull() const { return m_successful; } - /// @returns compiler error message in case of unsuccessfull compilation + /// Indicates if the compilation was successful + bool successful() const { return m_successful; } + /// @returns compiler error message in case of unsuccessful compilation QString compilerMessage() const { return m_compilerMessage; } /// @returns contract bytecode dev::bytes const& bytes() const { return m_bytes; } diff --git a/mix/ConstantCompilationControl.cpp b/mix/ConstantCompilationControl.cpp index c9f21c11b..6352f070d 100644 --- a/mix/ConstantCompilationControl.cpp +++ b/mix/ConstantCompilationControl.cpp @@ -61,7 +61,7 @@ void ConstantCompilationControl::update() QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - if (result->successfull()) + if (result->successful()) { status->setProperty("text", "succeeded"); status->setProperty("color", "green"); diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 757f7243c..f2cd5d587 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -27,6 +27,7 @@ #include #include "QVariableDeclaration.h" #include "QVariableDefinition.h" +#include "QFunctionDefinition.h" #include "ContractCallDataEncoder.h" using namespace dev; using namespace dev::solidity; @@ -37,9 +38,9 @@ bytes ContractCallDataEncoder::encodedData() return m_encodedData; } -void ContractCallDataEncoder::encode(int _functionIndex) +void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) { - bytes i = jsToBytes(std::to_string(_functionIndex)); + bytes i = _function->hash().asBytes(); m_encodedData.insert(m_encodedData.end(), i.begin(), i.end()); } diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index fd67a7b7a..49410a7cd 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -30,6 +30,10 @@ namespace dev namespace mix { +class QFunctionDefinition; +class QVariableDeclaration; +class QVariableDefinition; + /** * @brief Encode/Decode data to be sent to a transaction or to be displayed in a view. */ @@ -43,8 +47,8 @@ public: void encode(QVariableDeclaration const* _dec, u256 _value); /// Encode variable in order to be sent as parameter. void encode(QVariableDeclaration const* _dec, bool _value); - /// Encode index of the function to call. - void encode(int _functionIndex); + /// Encode hash of the function to call. + void encode(QFunctionDefinition const* _function); /// Decode variable in order to be sent to QML view. QList decode(QList _dec, bytes _value); /// Get all encoded data encoded by encode function. diff --git a/mix/DebuggingStateWrapper.h b/mix/DebuggingStateWrapper.h index bf3efe34d..6d1ce4220 100644 --- a/mix/DebuggingStateWrapper.h +++ b/mix/DebuggingStateWrapper.h @@ -28,45 +28,13 @@ #include #include #include "QVariableDefinition.h" +#include "MixClient.h" namespace dev { namespace mix { -/** - * @brief Store information about a machine state. - */ -struct DebuggingState -{ - uint64_t steps; - dev::Address cur; - dev::u256 curPC; - dev::eth::Instruction inst; - dev::bigint newMemSize; - dev::u256 gas; - dev::u256s stack; - dev::bytes memory; - dev::bigint gasCost; - std::map storage; - std::vector levels; -}; - -/** - * @brief Store information about a machine states. - */ -struct DebuggingContent -{ - QList machineStates; - bytes executionCode; - bytesConstRef executionData; - Address contractAddress; - bool contentAvailable; - QString message; - bytes returnValue; - QList returnParameters; -}; - /** * @brief Contains the line nb of the assembly code and the corresponding index in the code bytes array. */ @@ -151,14 +119,14 @@ public: /// Get all previous steps. QStringList levels(); /// Get the current processed machine state. - DebuggingState state() { return m_state; } + MachineState state() { return m_state; } /// Set the current processed machine state. - void setState(DebuggingState _state) { m_state = _state; } + void setState(MachineState _state) { m_state = _state; } /// Convert all machine state in human readable code. static std::tuple, QQMLMap*> getHumanReadableCode(bytes const& _code); private: - DebuggingState m_state; + MachineState m_state; bytes m_code; bytes m_data; }; diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 4ecbc9c08..a91dfc167 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -73,3 +73,8 @@ void FileIo::copyFile(QString const& _sourceUrl, QString const& _destUrl) if (!QFile::copy(sourceUrl.path(), destUrl.path())) error(tr("Error copying file %1 to %2").arg(_sourceUrl).arg(_destUrl)); } + +QString FileIo::getHomePath() const +{ + return QDir::homePath(); +} diff --git a/mix/FileIo.h b/mix/FileIo.h index 83352476b..3c251cfbc 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -33,6 +33,7 @@ namespace mix class FileIo : public QObject { Q_OBJECT + Q_PROPERTY(QString homePath READ getHomePath CONSTANT); signals: /// Signalled in case of IO error @@ -47,6 +48,9 @@ public: Q_INVOKABLE void writeFile(QString const& _url, QString const& _data); /// Copy a file from _sourcePath to _destPath. Signals on failure. Q_INVOKABLE void copyFile(QString const& _sourceUrl, QString const& _destUrl); + +private: + QString getHomePath() const; }; } diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index 1a55b1e47..2cdc4b30d 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -33,10 +33,9 @@ MixApplication::MixApplication(int _argc, char* _argv[]): QApplication(_argc, _argv), m_engine(new QQmlApplicationEngine()), m_appContext(new AppContext(m_engine.get())) { qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); - //QObject::connect(this, SIGNAL(lastWindowClosed()), context(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff + QObject::connect(this, SIGNAL(lastWindowClosed()), context(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff m_engine->load(QUrl("qrc:/qml/main.qml")); - //m_engine->load(QUrl("qrc:/qml/ProjectModel.qml")); - m_appContext->loadProject(); + m_appContext->appLoaded(); } MixApplication::~MixApplication() diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp new file mode 100644 index 000000000..5d635ce1f --- /dev/null +++ b/mix/MixClient.cpp @@ -0,0 +1,336 @@ +/* + 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 MixClient.cpp + * @author Yann yann@ethdev.com + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "MixClient.h" + +using namespace dev; +using namespace dev::eth; +using namespace dev::mix; + +MixClient::MixClient(): + m_userAccount(KeyPair::create()) +{ + resetState(10000000 * ether); +} + +void MixClient::resetState(u256 _balance) +{ + WriteGuard l(x_state); + m_state = eth::State(Address(), m_stateDB, BaseState::Empty); + m_state.addBalance(m_userAccount.address(), _balance); +} + +void MixClient::executeTransaction(bytesConstRef _rlp, State& _state) +{ + Executive execution(_state, LastHashes(), 0); + execution.setup(_rlp); + bytes code; + bytesConstRef data; + bool firstIteration = true; + std::vector machineStates; + std::vector levels; + auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) + { + VM& vm = *(VM*)voidVM; + ExtVM const& ext = *(ExtVM const*)voidExt; + + if (firstIteration) + { + code = ext.code; + data = ext.data; + firstIteration = false; + } + + if (levels.size() < ext.depth) + levels.push_back(&machineStates.back()); + else + levels.resize(ext.depth); + + machineStates.push_back(MachineState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), + vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); + }; + + execution.go(onOp); + execution.finalize(); + + ExecutionResult d; + d.returnValue = execution.out().toVector(); + d.machineStates = machineStates; + d.executionCode = code; + d.executionData = data; + d.contentAvailable = true; + d.message = "ok"; + m_lastExecutionResult = d; +} + +void MixClient::validateBlock(int _block) const +{ + //TODO: throw exception here if _block != 0 + (void)_block; +} + +void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +{ + WriteGuard l(x_state); + u256 n = m_state.transactionsFrom(toAddress(_secret)); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + bytes rlp = t.rlp(); + executeTransaction(&rlp, m_state); +} + +Address MixClient::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +{ + WriteGuard l(x_state); + u256 n = m_state.transactionsFrom(toAddress(_secret)); + eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); + bytes rlp = t.rlp(); + executeTransaction(&rlp, m_state); + return right160(sha3(rlpList(t.sender(), t.nonce()))); +} + +void MixClient::inject(bytesConstRef _rlp) +{ + WriteGuard l(x_state); + executeTransaction(_rlp, m_state); +} + +void MixClient::flushTransactions() +{ +} + +bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +{ + bytes out; + u256 n; + State temp; + { + ReadGuard lr(x_state); + temp = m_state; + n = temp.transactionsFrom(toAddress(_secret)); + } + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + bytes rlp = t.rlp(); + WriteGuard lw(x_state); //TODO: lock is required only for last executoin state + executeTransaction(&rlp, temp); + return m_lastExecutionResult.returnValue; +} + +u256 MixClient::balanceAt(Address _a, int _block) const +{ + validateBlock(_block); + ReadGuard l(x_state); + return m_state.balance(_a); +} + +u256 MixClient::countAt(Address _a, int _block) const +{ + validateBlock(_block); + ReadGuard l(x_state); + return m_state.transactionsFrom(_a); +} + +u256 MixClient::stateAt(Address _a, u256 _l, int _block) const +{ + validateBlock(_block); + ReadGuard l(x_state); + return m_state.storage(_a, _l); +} + +bytes MixClient::codeAt(Address _a, int _block) const +{ + validateBlock(_block); + ReadGuard l(x_state); + return m_state.code(_a); +} + +std::map MixClient::storageAt(Address _a, int _block) const +{ + validateBlock(_block); + ReadGuard l(x_state); + return m_state.storage(_a); +} + +eth::LogEntries MixClient::logs(unsigned _watchId) const +{ + (void)_watchId; + return LogEntries(); +} + +eth::LogEntries MixClient::logs(eth::LogFilter const& _filter) const +{ + (void)_filter; + return LogEntries(); +} + +unsigned MixClient::installWatch(eth::LogFilter const& _filter) +{ + (void)_filter; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::installWatch")); +} + +unsigned MixClient::installWatch(h256 _filterId) +{ + (void)_filterId; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::installWatch")); +} + +void MixClient::uninstallWatch(unsigned _watchId) +{ + (void)_watchId; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::uninstallWatch")); +} + +bool MixClient::peekWatch(unsigned _watchId) const +{ + (void)_watchId; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::peekWatch")); +} + +bool MixClient::checkWatch(unsigned _watchId) +{ + (void)_watchId; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::checkWatch")); +} + +h256 MixClient::hashFromNumber(unsigned _number) const +{ + (void)_number; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::hashFromNumber")); +} + +eth::BlockInfo MixClient::blockInfo(h256 _hash) const +{ + (void)_hash; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::blockInfo")); +} + +eth::BlockDetails MixClient::blockDetails(h256 _hash) const +{ + (void)_hash; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::blockDetails")); +} + +eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const +{ + (void)_blockHash; + (void)_i; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::transaction")); +} + +eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const +{ + (void)_blockHash; + (void)_i; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::uncle")); +} + +unsigned MixClient::number() const +{ + return 0; +} + +eth::Transactions MixClient::pending() const +{ + return eth::Transactions(); +} + +eth::StateDiff MixClient::diff(unsigned _txi, h256 _block) const +{ + (void)_txi; + (void)_block; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::diff")); +} + +eth::StateDiff MixClient::diff(unsigned _txi, int _block) const +{ + (void)_txi; + (void)_block; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::diff")); +} + +Addresses MixClient::addresses(int _block) const +{ + validateBlock(_block); + ReadGuard l(x_state); + Addresses ret; + for (auto const& i: m_state.addresses()) + ret.push_back(i.first); + return ret; +} + +u256 MixClient::gasLimitRemaining() const +{ + ReadGuard l(x_state); + return m_state.gasLimitRemaining(); +} + +void MixClient::setAddress(Address _us) +{ + WriteGuard l(x_state); + m_state.setAddress(_us); +} + +Address MixClient::address() const +{ + ReadGuard l(x_state); + return m_state.address(); +} + +void MixClient::setMiningThreads(unsigned _threads) +{ + (void)_threads; + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::setMiningThreads")); +} + +unsigned MixClient::miningThreads() const +{ + return 0; +} + +void MixClient::startMining() +{ + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::startMining")); +} + +void MixClient::stopMining() +{ + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::stopMining")); +} + +bool MixClient::isMining() +{ + return false; +} + +eth::MineProgress MixClient::miningProgress() const +{ + return eth::MineProgress(); +} diff --git a/mix/MixClient.h b/mix/MixClient.h new file mode 100644 index 000000000..4cbaad6e8 --- /dev/null +++ b/mix/MixClient.h @@ -0,0 +1,125 @@ +/* + 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 MixClient.h + * @author Yann yann@ethdev.com + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#pragma once + +#include + +namespace dev +{ +namespace mix +{ + +/** + * @brief Store information about a machine state. + */ +struct MachineState +{ + uint64_t steps; + dev::Address cur; + dev::u256 curPC; + dev::eth::Instruction inst; + dev::bigint newMemSize; + dev::u256 gas; + dev::u256s stack; + dev::bytes memory; + dev::bigint gasCost; + std::map storage; + std::vector levels; +}; + +/** + * @brief Store information about a machine states. + */ +struct ExecutionResult +{ + std::vector machineStates; + bytes executionCode; + bytesConstRef executionData; + Address contractAddress; + bool contentAvailable; + std::string message; + bytes returnValue; +}; + +class MixClient: public dev::eth::Interface +{ +public: + MixClient(); + /// Reset state to the empty state with given balance. + void resetState(u256 _balance); + const KeyPair& userAccount() const { return m_userAccount; } + const ExecutionResult lastExecutionResult() const { ReadGuard l(x_state); return m_lastExecutionResult; } + + //dev::eth::Interface + void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; + Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override; + void inject(bytesConstRef _rlp) override; + void flushTransactions() override; + bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; + u256 balanceAt(Address _a, int _block) const override; + u256 countAt(Address _a, int _block) const override; + u256 stateAt(Address _a, u256 _l, int _block) const override; + bytes codeAt(Address _a, int _block) const override; + std::map storageAt(Address _a, int _block) const override; + eth::LogEntries logs(unsigned _watchId) const override; + eth::LogEntries logs(eth::LogFilter const& _filter) const override; + unsigned installWatch(eth::LogFilter const& _filter) override; + unsigned installWatch(h256 _filterId) override; + void uninstallWatch(unsigned _watchId) override; + bool peekWatch(unsigned _watchId) const override; + bool checkWatch(unsigned _watchId) override; + h256 hashFromNumber(unsigned _number) const override; + eth::BlockInfo blockInfo(h256 _hash) const override; + eth::BlockDetails blockDetails(h256 _hash) const override; + eth::Transaction transaction(h256 _blockHash, unsigned _i) const override; + eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override; + unsigned number() const override; + eth::Transactions pending() const override; + eth::StateDiff diff(unsigned _txi, h256 _block) const override; + eth::StateDiff diff(unsigned _txi, int _block) const override; + Addresses addresses(int _block) const override; + u256 gasLimitRemaining() const override; + void setAddress(Address _us) override; + Address address() const override; + void setMiningThreads(unsigned _threads) override; + unsigned miningThreads() const override; + void startMining() override; + void stopMining() override; + bool isMining() override; + eth::MineProgress miningProgress() const override; + +private: + void executeTransaction(bytesConstRef _rlp, eth::State& _state); + void validateBlock(int _block) const; + + KeyPair m_userAccount; + eth::State m_state; + OverlayDB m_stateDB; + mutable boost::shared_mutex x_state; + ExecutionResult m_lastExecutionResult; +}; + +} + +} diff --git a/mix/QFunctionDefinition.cpp b/mix/QFunctionDefinition.cpp index 7149809af..97ce0ff58 100644 --- a/mix/QFunctionDefinition.cpp +++ b/mix/QFunctionDefinition.cpp @@ -20,12 +20,14 @@ */ #include +#include #include "QVariableDeclaration.h" #include "QFunctionDefinition.h" + using namespace dev::solidity; using namespace dev::mix; -QFunctionDefinition::QFunctionDefinition(dev::solidity::FunctionDefinition const* _f, int _index): QBasicNodeDefinition(_f), m_index(_index) +QFunctionDefinition::QFunctionDefinition(dev::solidity::FunctionDefinition const* _f, int _index): QBasicNodeDefinition(_f), m_index(_index), m_hash(dev::sha3(_f->getCanonicalSignature())) { std::vector> parameters = _f->getParameterList().getParameters(); for (unsigned i = 0; i < parameters.size(); i++) diff --git a/mix/QFunctionDefinition.h b/mix/QFunctionDefinition.h index b2d0cd0b7..7f606c8a1 100644 --- a/mix/QFunctionDefinition.h +++ b/mix/QFunctionDefinition.h @@ -49,9 +49,12 @@ public: QList returnParameters() const { return m_returnParameters; } /// Get the index of this function on the contract ABI. int index() const { return m_index; } + /// Get the hash of this function declaration on the contract ABI. + FixedHash<4> hash() const { return m_hash; } private: int m_index; + FixedHash<4> m_hash; QList m_parameters; QList m_returnParameters; void initQParameters(); diff --git a/mix/Web3Server.cpp b/mix/Web3Server.cpp new file mode 100644 index 000000000..469ca907d --- /dev/null +++ b/mix/Web3Server.cpp @@ -0,0 +1,55 @@ +/* + 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 Web3Server.h.cpp + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + + +#include +#include "Web3Server.h" + +using namespace dev::mix; + +Web3Server::Web3Server(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts, dev::eth::Interface* _client): + WebThreeStubServerBase(_conn, _accounts), + m_client(_client) +{ +} + +std::shared_ptr Web3Server::face() +{ + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::shh::Interface")); +} + +dev::WebThreeNetworkFace* Web3Server::network() +{ + BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::WebThreeNetworkFace")); +} + +std::string Web3Server::get(std::string const& _name, std::string const& _key) +{ + std::string k(_name + "/" + _key); + return m_db[k]; +} + +void Web3Server::put(std::string const& _name, std::string const& _key, std::string const& _value) +{ + std::string k(_name + "/" + _key); + m_db[k] = _value; +} diff --git a/mix/Web3Server.h b/mix/Web3Server.h new file mode 100644 index 000000000..c603b48a2 --- /dev/null +++ b/mix/Web3Server.h @@ -0,0 +1,56 @@ +/* + 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 Web3Server.h + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#pragma once + +#include +#include +#include + +namespace dev +{ + +namespace mix +{ + +class Web3Server: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace +{ +public: + Web3Server(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts, dev::eth::Interface* _client); + +private: + dev::eth::Interface* client() override { return m_client; } + std::shared_ptr face() override; + dev::WebThreeNetworkFace* network() override; + dev::WebThreeStubDatabaseFace* db() override { return this; } + + std::string get(std::string const& _name, std::string const& _key) override; + void put(std::string const& _name, std::string const& _key, std::string const& _value) override; + +private: + dev::eth::Interface* m_client; + std::map m_db; +}; + +} + +} diff --git a/mix/qml.qrc b/mix/qml.qrc index 0e25de765..28b82865f 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -18,5 +18,6 @@ qml/CodeEditor.qml qml/CodeEditorView.qml qml/js/ProjectModel.js + qml/WebPreview.qml diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 45d2cfb2a..4e95bd49c 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -44,7 +44,7 @@ Item { onDocumentOpened: { openDocument(document); } - onProjectSaved: { + onProjectSaving: { for (var i = 0; i < editorListModel.count; i++) fileIo.writeFile(editorListModel.get(i).path, editors.itemAt(i).item.getText()); } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 976f70316..cc5ecccd9 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -15,7 +15,7 @@ Item { signal projectClosed signal projectLoaded signal documentOpened(var document) - signal projectSaved + signal projectSaving(var projectData) property bool isEmpty: (projectData === null) readonly property string projectFileName: ".mix" @@ -35,9 +35,12 @@ Item { function addExistingFile() { ProjectModelCode.addExistingFile(); } function openDocument(documentId) { ProjectModelCode.openDocument(documentId); } - Component.onCompleted: { - if (projectSettings.lastProjectPath) - loadProject(projectSettings.lastProjectPath) + Connections { + target: appContext + onAppLoaded: { + if (projectSettings.lastProjectPath) + loadProject(projectSettings.lastProjectPath) + } } NewProjectDialog { diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index 862e6f854..208c766f9 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -122,7 +122,7 @@ Window { var item = { value: "0", functionId: "", - gas: "1000000000000", + gas: "125000", gasPrice: "100000" }; diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index de59fec4a..12f0318d1 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -29,6 +29,9 @@ Rectangle { stateList.push(items[i]) } } + onProjectSaving: { + projectData.states = stateList; + } } ListView { @@ -78,7 +81,7 @@ Rectangle { function runState(index) { var item = stateList[index]; - debugModel.debugState(item); + clientModel.debugState(item); } function deleteState(index) { @@ -88,7 +91,6 @@ Rectangle { } function save() { - console.log(parent.id); ProjectModel.saveProject(); } } @@ -131,7 +133,7 @@ Rectangle { id: addStateAction text: "&Add State" shortcut: "Ctrl+T" - enabled: codeModel.hasContract && !debugModel.running; + enabled: codeModel.hasContract && !clientModel.running; onTriggered: stateListModel.addState(); } } diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml new file mode 100644 index 000000000..77e60ee66 --- /dev/null +++ b/mix/qml/WebPreview.qml @@ -0,0 +1,81 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.1 + +Component { + Item { + signal editorTextChanged + + function setText(text) { + codeEditor.text = text; + } + + function getText() { + return codeEditor.text; + } + + anchors.fill: parent + id: contentView + width: parent.width + height: parent.height * 0.7 + Rectangle { + id: lineColumn + property int rowHeight: codeEditor.font.pixelSize + 3 + color: "#202020" + width: 50 + height: parent.height + Column { + y: -codeEditor.flickableItem.contentY + 4 + width: parent.width + Repeater { + model: Math.max(codeEditor.lineCount + 2, (lineColumn.height/lineColumn.rowHeight)) + delegate: Text { + id: text + color: codeEditor.textColor + font: codeEditor.font + width: lineColumn.width - 4 + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + height: lineColumn.rowHeight + renderType: Text.NativeRendering + text: index + 1 + } + } + } + } + + TextArea { + id: codeEditor + textColor: "#EEE8D5" + style: TextAreaStyle { + backgroundColor: "#002B36" + } + + anchors.left: lineColumn.right + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + wrapMode: TextEdit.NoWrap + frameVisible: false + + height: parent.height + font.family: "Monospace" + font.pointSize: 12 + width: parent.width + + tabChangesFocus: false + Keys.onPressed: { + if (event.key === Qt.Key_Tab) { + codeEditor.insert(codeEditor.cursorPosition, "\t"); + event.accepted = true; + } + } + onTextChanged: { + editorTextChanged(); + } + + } + } +} diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 7bcfb5cd7..a547457b0 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -22,7 +22,6 @@ function saveAll() { saveProject(); - projectSaved(); } function createProject() { @@ -44,6 +43,7 @@ function closeProject() { function saveProject() { if (!isEmpty) { + projectSaving(projectData); var json = JSON.stringify(projectData); var projectFile = projectPath + projectFileName; fileIo.writeFile(projectFile, json); diff --git a/mix/qml/main.qml b/mix/qml/main.qml index 4bea535c2..f59c5874c 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -63,15 +63,15 @@ ApplicationWindow { id: debugRunAction text: "&Run" shortcut: "F5" - enabled: codeModel.hasContract && !debugModel.running; - onTriggered: debugModel.debugDeployment(); + enabled: codeModel.hasContract && !clientModel.running; + onTriggered: clientModel.debugDeployment(); } Action { id: debugResetStateAction text: "Reset &State" shortcut: "F6" - onTriggered: debugModel.resetState(); + onTriggered: clientModel.resetState(); } Action { From c34b0c67a1670cf1d22f3887f12a0fef0f523421 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 11 Jan 2015 16:23:06 +0100 Subject: [PATCH 526/588] Update README.md --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 865b62c6b..72d3cab8e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,22 @@ which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Ge +## Requirements + +* Node.js +* npm +* gulp (build) +* mocha (tests) + +```bash +sudo apt-get update +sudo apt-get install nodejs +sudo apt-get install npm +sudo apt-get install nodejs-legacy +sudo npm install -g gulp +sudo npm install -g mocha +``` + ## Installation ### Node.js @@ -76,4 +92,4 @@ ethereum -ws -loglevel=4 [dep-image]: https://david-dm.org/ethereum/ethereum.js.svg [dep-url]: https://david-dm.org/ethereum/ethereum.js [dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg -[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies \ No newline at end of file +[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies From 6188e64473ce3acecf48891880b00ffc91e0c222 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 11 Jan 2015 16:25:41 +0100 Subject: [PATCH 527/588] Update README.md --- README.md | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 72d3cab8e..babec3069 100644 --- a/README.md +++ b/README.md @@ -7,22 +7,6 @@ which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Ge -## Requirements - -* Node.js -* npm -* gulp (build) -* mocha (tests) - -```bash -sudo apt-get update -sudo apt-get install nodejs -sudo apt-get install npm -sudo apt-get install nodejs-legacy -sudo npm install -g gulp -sudo npm install -g mocha -``` - ## Installation ### Node.js @@ -66,13 +50,37 @@ web3.eth.coinbase.then(function(result){ For another example see `example/index.html`. +## Contribute! + +### Requirements + +* Node.js +* npm +* gulp (build) +* mocha (tests) + +```bash +sudo apt-get update +sudo apt-get install nodejs +sudo apt-get install npm +sudo apt-get install nodejs-legacy +sudo npm install -g gulp +sudo npm install -g mocha +``` + ## Building -* `gulp build` +```bash +gulp +``` ### Testing +```bash +mocha +``` + **Please note this repo is in it's early stage.** If you'd like to run a WebSocket ethereum node check out From 15c229300c2fecdf3966e7e23d0afcbb7b3d9788 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 11 Jan 2015 16:36:07 +0100 Subject: [PATCH 528/588] updated package json --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index fc34be487..6d032d72d 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "jshint": ">=2.5.0", "uglifyify": "^2.6.0", "unreachable-branch-transform": "^0.1.0", - "vinyl-source-stream": "^1.0.0" + "vinyl-source-stream": "^1.0.0", + "mocha": ">=2.1.0" }, "scripts": { "build": "gulp", From a4e6f0b3c63214fc3b3dd67d26c6bc23c3d81e48 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 11 Jan 2015 16:40:09 +0100 Subject: [PATCH 529/588] fixed travis.yml && added nmp test script --- .travis.yml | 4 +++- dist/ethereum.js | 1 + dist/ethereum.js.map | 4 ++-- package.json | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index fafacbd5a..83b21d840 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,6 @@ before_script: script: - "jshint *.js lib" after_script: - - npm run-script gulp + - npm run-script build + - npm test + diff --git a/dist/ethereum.js b/dist/ethereum.js index 30684dbf4..e4a89450e 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -277,6 +277,7 @@ module.exports = { methodSignature: methodSignature }; + },{}],2:[function(require,module,exports){ /* This file is part of ethereum.js. diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index db5f7342c..9b66ec4a5 100644 --- a/dist/ethereum.js.map +++ b/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;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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 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 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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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 extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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/package.json b/package.json index 6d032d72d..b4f180d10 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "scripts": { "build": "gulp", "watch": "gulp watch", - "lint": "gulp lint" + "lint": "gulp lint", + "test": "mocha" }, "repository": { "type": "git", From e778e127d6b4ab9e8efb514966975b96b85e7dd6 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 11 Jan 2015 17:04:30 +0100 Subject: [PATCH 530/588] spec reporter instead of nyan --- test/mocha.opts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mocha.opts b/test/mocha.opts index b83917bb2..b2db8d5a7 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,2 +1,2 @@ ---reporter Nyan +--reporter Spec From b915c7a87069e43b82c43535a0e3b0b8bc4761a1 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 11 Jan 2015 17:13:32 +0100 Subject: [PATCH 531/588] updated readme --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index babec3069..aff8b2c08 100644 --- a/README.md +++ b/README.md @@ -64,21 +64,19 @@ sudo apt-get update sudo apt-get install nodejs sudo apt-get install npm sudo apt-get install nodejs-legacy -sudo npm install -g gulp -sudo npm install -g mocha ``` ## Building ```bash -gulp +npm run-script build ``` ### Testing ```bash -mocha +npm test ``` **Please note this repo is in it's early stage.** From ab745d3b0eb89d67db1ed953020c665be3d072ed Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 11 Jan 2015 17:23:03 +0100 Subject: [PATCH 532/588] updated readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aff8b2c08..f18d382bd 100644 --- a/README.md +++ b/README.md @@ -68,14 +68,14 @@ sudo apt-get install nodejs-legacy ## Building -```bash +```bash (gulp) npm run-script build ``` ### Testing -```bash +```bash (mocha) npm test ``` From 23a739f0cb4fcf107bee49caab04305cc488eb3a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 11 Jan 2015 18:15:35 +0100 Subject: [PATCH 533/588] Various fixes to ethereum.js and client web API stuff. --- libethereum/Client.h | 8 ++++---- libjsqrc/ethereumjs/dist/ethereum.js | 6 ++++-- libjsqrc/ethereumjs/dist/ethereum.js.map | 4 ++-- libjsqrc/ethereumjs/dist/ethereum.min.js | 2 +- libjsqrc/ethereumjs/lib/contract.js | 6 ++++-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libethereum/Client.h b/libethereum/Client.h index efe076dab..992ceb524 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -108,9 +108,9 @@ struct WorkChannel: public LogChannel { static const char* name() { return "-W-" #define cworkout dev::LogOutputStream() template struct ABISerialiser {}; -template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { return _t.asBytes(); } }; +template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { static_assert(N < 32, "Parameter sizes must be at most 32 bytes."); return bytes(32 - N, 0) + _t.asBytes(); } }; template <> struct ABISerialiser { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } }; -template <> struct ABISerialiser { static bytes serialise(u160 const& _t) { return h160(_t).asBytes(); } }; +template <> struct ABISerialiser { static bytes serialise(u160 const& _t) { return bytes(12, 0) + h160(_t).asBytes(); } }; template <> struct ABISerialiser { static bytes serialise(string32 const& _t) { return bytesConstRef((byte const*)_t.data(), 32).toBytes(); } }; inline bytes abiInAux() { return {}; } @@ -125,9 +125,9 @@ template bytes abiIn(std::string _id, T const& ... _t) } template struct ABIDeserialiser {}; -template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { FixedHash ret; io_t.cropped(0, N).populate(ret.ref()); return ret; } }; +template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { static_assert(N < 32, "Parameter sizes must be at most 32 bytes."); FixedHash ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; -template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(0, 20)); io_t = io_t.cropped(20); return ret; } }; +template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; template T abiOut(bytes const& _data) diff --git a/libjsqrc/ethereumjs/dist/ethereum.js b/libjsqrc/ethereumjs/dist/ethereum.js index c1883d156..a7c6c8624 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js +++ b/libjsqrc/ethereumjs/dist/ethereum.js @@ -453,8 +453,10 @@ var contract = function (address, desc) { transact: function (extra) { extra = extra || {}; extra.to = address; - extra.data = parsed; - return web3.eth.transact(extra).then(onSuccess); + return abi.methodSignature(desc, method.name).then(function (signature) { + extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed; + return web3.eth.transact(extra).then(onSuccess); + }); } }; }; diff --git a/libjsqrc/ethereumjs/dist/ethereum.js.map b/libjsqrc/ethereumjs/dist/ethereum.js.map index 80efb9bc8..c30b17fcc 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js.map +++ b/libjsqrc/ethereumjs/dist/ethereum.js.map @@ -12,14 +12,14 @@ "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;;ACjSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACjSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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 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 extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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 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", "/*\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 qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\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 main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nif (typeof(module) !== \"undefined\")\n module.exports = web3;\n", diff --git a/libjsqrc/ethereumjs/dist/ethereum.min.js b/libjsqrc/ethereumjs/dist/ethereum.min.js index 8f4427d05..1d909e464 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,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&&n Date: Sun, 11 Jan 2015 18:16:50 +0100 Subject: [PATCH 534/588] Squashed 'libjsqrc/ethereumjs/' changes from 47687cf..ab745d3 ab745d3 updated readme b915c7a updated readme 6c26255 Merge branch 'tests' into develop e2c4525 Merge branch 'master' into develop e778e12 spec reporter instead of nyan a4e6f0b fixed travis.yml && added nmp test script 048e777 Merge branch 'master' into tests 15c2293 updated package json 24814a4 Merge branch 'master' of https://github.com/ethereum/ethereum.js 6188e64 Update README.md c34b0c6 Update README.md 29c60c0 Merge branch 'develop' into tests b3eda29 Merge branch 'master' into tests c397e35 mocha opts file && init of parser tests b6058a8 methods existance tests in progress 5518022 mocha test init git-subtree-dir: libjsqrc/ethereumjs git-subtree-split: ab745d3b0eb89d67db1ed953020c665be3d072ed --- .travis.yml | 4 +++- README.md | 26 ++++++++++++++++++++++++-- dist/ethereum.js | 1 + dist/ethereum.js.map | 4 ++-- lib/abi.js | 1 + package.json | 6 ++++-- test/abi.parsers.js | 37 +++++++++++++++++++++++++++++++++++++ test/db.methods.js | 18 ++++++++++++++++++ test/eth.methods.js | 42 ++++++++++++++++++++++++++++++++++++++++++ test/mocha.opts | 2 ++ test/shh.methods.js | 19 +++++++++++++++++++ test/utils.js | 15 +++++++++++++++ test/web3.methods.js | 18 ++++++++++++++++++ 13 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 test/abi.parsers.js create mode 100644 test/db.methods.js create mode 100644 test/eth.methods.js create mode 100644 test/mocha.opts create mode 100644 test/shh.methods.js create mode 100644 test/utils.js create mode 100644 test/web3.methods.js diff --git a/.travis.yml b/.travis.yml index fafacbd5a..83b21d840 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,6 @@ before_script: script: - "jshint *.js lib" after_script: - - npm run-script gulp + - npm run-script build + - npm test + diff --git a/README.md b/README.md index 865b62c6b..f18d382bd 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,35 @@ web3.eth.coinbase.then(function(result){ For another example see `example/index.html`. +## Contribute! + +### Requirements + +* Node.js +* npm +* gulp (build) +* mocha (tests) + +```bash +sudo apt-get update +sudo apt-get install nodejs +sudo apt-get install npm +sudo apt-get install nodejs-legacy +``` + ## Building -* `gulp build` +```bash (gulp) +npm run-script build +``` ### Testing +```bash (mocha) +npm test +``` + **Please note this repo is in it's early stage.** If you'd like to run a WebSocket ethereum node check out @@ -76,4 +98,4 @@ ethereum -ws -loglevel=4 [dep-image]: https://david-dm.org/ethereum/ethereum.js.svg [dep-url]: https://david-dm.org/ethereum/ethereum.js [dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg -[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies \ No newline at end of file +[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies diff --git a/dist/ethereum.js b/dist/ethereum.js index 26de2c02e..cf2492997 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -277,6 +277,7 @@ module.exports = { methodSignature: methodSignature }; + },{}],2:[function(require,module,exports){ /* This file is part of ethereum.js. diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index bb29b435d..e875a0408 100644 --- a/dist/ethereum.js.map +++ b/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;;ACrRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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 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 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 (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 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 return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\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 extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\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/lib/abi.js b/lib/abi.js index 99d2ba932..86cd99cf4 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -275,3 +275,4 @@ module.exports = { outputParser: outputParser, methodSignature: methodSignature }; + diff --git a/package.json b/package.json index fc34be487..b4f180d10 100644 --- a/package.json +++ b/package.json @@ -25,12 +25,14 @@ "jshint": ">=2.5.0", "uglifyify": "^2.6.0", "unreachable-branch-transform": "^0.1.0", - "vinyl-source-stream": "^1.0.0" + "vinyl-source-stream": "^1.0.0", + "mocha": ">=2.1.0" }, "scripts": { "build": "gulp", "watch": "gulp watch", - "lint": "gulp lint" + "lint": "gulp lint", + "test": "mocha" }, "repository": { "type": "git", diff --git a/test/abi.parsers.js b/test/abi.parsers.js new file mode 100644 index 000000000..06a77fb86 --- /dev/null +++ b/test/abi.parsers.js @@ -0,0 +1,37 @@ +var assert = require('assert'); +var abi = require('../lib/abi.js'); + +describe('abi', function() { + describe('inputParser', function() { + it('should parse ...', function() { + + var desc = [{ + "name": "multiply", + "inputs": [ + { + "name": "a", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "d", + "type": "uint256" + } + ] + }]; + + var iParser = abi.inputParser(desc); + assert.equal(iParser.multiply(1), "0x000000000000000000000000000000000000000000000000000000000000000001"); + + }); + }); + + + describe('outputParser', function() { + it('parse ...', function() { + + }); + }); +}); + diff --git a/test/db.methods.js b/test/db.methods.js new file mode 100644 index 000000000..b4abfc4d7 --- /dev/null +++ b/test/db.methods.js @@ -0,0 +1,18 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + describe('db', function() { + it('should have all methods implemented', function() { + u.methodExists(web3.db, 'put'); + u.methodExists(web3.db, 'get'); + u.methodExists(web3.db, 'putString'); + u.methodExists(web3.db, 'getString'); + }); + }); +}); + diff --git a/test/eth.methods.js b/test/eth.methods.js new file mode 100644 index 000000000..7190b27d2 --- /dev/null +++ b/test/eth.methods.js @@ -0,0 +1,42 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + describe('eth', function() { + it('should have all methods implemented', function() { + u.methodExists(web3.eth, 'balanceAt'); + u.methodExists(web3.eth, 'stateAt'); + u.methodExists(web3.eth, 'storageAt'); + u.methodExists(web3.eth, 'countAt'); + u.methodExists(web3.eth, 'codeAt'); + u.methodExists(web3.eth, 'transact'); + u.methodExists(web3.eth, 'call'); + u.methodExists(web3.eth, 'block'); + u.methodExists(web3.eth, 'transaction'); + u.methodExists(web3.eth, 'uncle'); + u.methodExists(web3.eth, 'compilers'); + u.methodExists(web3.eth, 'lll'); + u.methodExists(web3.eth, 'solidity'); + u.methodExists(web3.eth, 'serpent'); + u.methodExists(web3.eth, 'logs'); + }); + + it('should have all properties implemented', function () { + u.propertyExists(web3.eth, 'coinbase'); + u.propertyExists(web3.eth, 'listening'); + u.propertyExists(web3.eth, 'mining'); + u.propertyExists(web3.eth, 'gasPrice'); + u.propertyExists(web3.eth, 'account'); + u.propertyExists(web3.eth, 'accounts'); + u.propertyExists(web3.eth, 'peerCount'); + u.propertyExists(web3.eth, 'defaultBlock'); + u.propertyExists(web3.eth, 'number'); + }); + }); +}); + + diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 000000000..b2db8d5a7 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,2 @@ +--reporter Spec + diff --git a/test/shh.methods.js b/test/shh.methods.js new file mode 100644 index 000000000..08f573a3c --- /dev/null +++ b/test/shh.methods.js @@ -0,0 +1,19 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + describe('shh', function() { + it('should have all methods implemented', function() { + u.methodExists(web3.shh, 'post'); + u.methodExists(web3.shh, 'newIdentity'); + u.methodExists(web3.shh, 'haveIdentity'); + u.methodExists(web3.shh, 'newGroup'); + u.methodExists(web3.shh, 'addToGroup'); + }); + }); +}); + diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 000000000..4c508da67 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,15 @@ +var assert = require('assert'); + +var methodExists = function (object, method) { + assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented'); +}; + +var propertyExists = function (object, property) { + assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented'); +}; + +module.exports = { + methodExists: methodExists, + propertyExists: propertyExists +}; + diff --git a/test/web3.methods.js b/test/web3.methods.js new file mode 100644 index 000000000..a7e020978 --- /dev/null +++ b/test/web3.methods.js @@ -0,0 +1,18 @@ +require('es6-promise').polyfill(); + +var assert = require('assert'); +var web3 = require('../index.js'); +var u = require('./utils.js'); +web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider + +describe('web3', function() { + it('should have all methods implemented', function() { + u.methodExists(web3, 'sha3'); + u.methodExists(web3, 'toAscii'); + u.methodExists(web3, 'fromAscii'); + u.methodExists(web3, 'toFixed'); + u.methodExists(web3, 'fromFixed'); + u.methodExists(web3, 'offset'); + }); +}); + From 84962d313650f10d33222384c16c30820ee5ceff Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 11 Jan 2015 18:59:15 +0100 Subject: [PATCH 535/588] Minor fixes. --- CMakeLists.txt | 1 + libethereum/Client.h | 6 +++--- libethereum/Utility.cpp | 17 ++++++++++------- libjsqrc/js.qrc | 12 ++++++------ libqethereum/QEthereum.h | 2 +- libweb3jsonrpc/WebThreeStubServer.cpp | 4 ++-- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3a5702f1..221087884 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ endfunction() function(createBuildInfo) # Set build platform; to be written to BuildInfo.h + set(ETH_BUILD_PLATFORM ${TARGET_PLATFORM}) if (CMAKE_COMPILER_IS_MINGW) set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/mingw") elseif (CMAKE_COMPILER_IS_MSYS) diff --git a/libethereum/Client.h b/libethereum/Client.h index 992ceb524..e83858323 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -108,7 +108,7 @@ struct WorkChannel: public LogChannel { static const char* name() { return "-W-" #define cworkout dev::LogOutputStream() template struct ABISerialiser {}; -template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { static_assert(N < 32, "Parameter sizes must be at most 32 bytes."); return bytes(32 - N, 0) + _t.asBytes(); } }; +template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { static_assert(N <= 32, "Cannot serialise hash > 32 bytes."); static_assert(N > 0, "Cannot serialise zero-length hash."); return bytes(32 - N, 0) + _t.asBytes(); } }; template <> struct ABISerialiser { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } }; template <> struct ABISerialiser { static bytes serialise(u160 const& _t) { return bytes(12, 0) + h160(_t).asBytes(); } }; template <> struct ABISerialiser { static bytes serialise(string32 const& _t) { return bytesConstRef((byte const*)_t.data(), 32).toBytes(); } }; @@ -125,9 +125,9 @@ template bytes abiIn(std::string _id, T const& ... _t) } template struct ABIDeserialiser {}; -template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { static_assert(N < 32, "Parameter sizes must be at most 32 bytes."); FixedHash ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; +template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; -template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; template T abiOut(bytes const& _data) diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index b6653fe39..31c5e278a 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -23,6 +23,7 @@ #include #include +#include using namespace std; using namespace dev; using namespace dev::eth; @@ -32,7 +33,7 @@ bytes dev::eth::parseData(string const& _args) bytes m_data; boost::smatch what; - static const boost::regex r("(@|\\$)?\"([^\"]*)\"(\\s.*)?"); + static const boost::regex r("(!|#|@|\\$)?\"([^\"]*)\"(\\s.*)?"); static const boost::regex d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?"); static const boost::regex h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?"); @@ -67,13 +68,15 @@ bytes dev::eth::parseData(string const& _args) } else if (boost::regex_match(s, what, r)) { - for (auto i: (string)what[2]) - m_data.push_back((byte)i); - if (what[1] != "$") - for (int i = what[2].length(); i < 32; ++i) - m_data.push_back(0); + bytes d = asBytes(what[2]); + if (what[1] == "!") + m_data += FixedHash<4>(sha3(d)).asBytes(); + else if (what[1] == "#") + m_data += sha3(d).asBytes(); + else if (what[1] == "$") + m_data += d + bytes{0}; else - m_data.push_back(0); + m_data += d + bytes(32 - what[2].length() % 32, 0); s = what[3]; } else diff --git a/libjsqrc/js.qrc b/libjsqrc/js.qrc index eee8f6652..896ab472f 100644 --- a/libjsqrc/js.qrc +++ b/libjsqrc/js.qrc @@ -1,7 +1,7 @@ - - - es6-promise-2.0.0.js - setup.js - ethereumjs/dist/ethereum.js - + + + es6-promise-2.0.0.js + setup.js + ethereumjs/dist/ethereum.js + diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 657986b36..49df0f703 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -85,7 +85,7 @@ private: _frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \ _frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \ - _frame->evaluateJavaScript(contentsOfQResource(":/js/ethereum.js")); \ + _frame->evaluateJavaScript(contentsOfQResource(":/js/webthree.js")); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/setup.js")); \ } diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 874c14331..1fb284aaa 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -634,7 +634,7 @@ std::string WebThreeStubServer::eth_transact(Json::Value const& _json) { auto b = m_accounts.begin()->first; for (auto a: m_accounts) - if (client()->balanceAt(a.first) > client()->balanceAt(b)) + if (client()->balanceAt(a.first, 0) > client()->balanceAt(b, 0)) b = a.first; t.from = b; } @@ -643,7 +643,7 @@ std::string WebThreeStubServer::eth_transact(Json::Value const& _json) if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) - t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from, 0) / t.gasPrice); if (authenticate(t)) { if (t.to) From 2ae6a42e25dc3bc52093fe160c1d69c86c0bc9f8 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 11 Jan 2015 19:22:58 +0100 Subject: [PATCH 536/588] Additional commands for project model --- mix/ContractCallDataEncoder.cpp | 2 +- mix/FileIo.cpp | 15 ++++++ mix/FileIo.h | 6 ++- mix/qml/NewProjectDialog.qml | 3 +- mix/qml/ProjectList.qml | 65 ++++++++++++++++++++++-- mix/qml/ProjectModel.qml | 9 +++- mix/qml/js/ProjectModel.js | 88 ++++++++++++++++++++++++++++----- mix/qml/main.qml | 13 +++-- 8 files changed, 176 insertions(+), 25 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index f2cd5d587..0e628c3c0 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -92,7 +92,7 @@ int ContractCallDataEncoder::padding(QString type) else if (type.indexOf("bool") != -1) return 1; else if ((type.indexOf("address") != -1)) - return 20; + return 32; else return 0; } diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index a91dfc167..7eaa0ca7b 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -78,3 +78,18 @@ QString FileIo::getHomePath() const { return QDir::homePath(); } + +void FileIo::moveFile(QString const& _sourceUrl, QString const& _destUrl) +{ + QUrl sourceUrl(_sourceUrl); + QUrl destUrl(_destUrl); + if (!QFile::rename(sourceUrl.path(), destUrl.path())) + error(tr("Error moving file %1 to %2").arg(_sourceUrl).arg(_destUrl)); +} + +bool FileIo::fileExists(QString const& _url) +{ + QUrl url(_url); + QFile file(url.path()); + return file.exists(); +} diff --git a/mix/FileIo.h b/mix/FileIo.h index 3c251cfbc..e635ffa25 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -33,7 +33,7 @@ namespace mix class FileIo : public QObject { Q_OBJECT - Q_PROPERTY(QString homePath READ getHomePath CONSTANT); + Q_PROPERTY(QString homePath READ getHomePath CONSTANT) signals: /// Signalled in case of IO error @@ -48,6 +48,10 @@ public: Q_INVOKABLE void writeFile(QString const& _url, QString const& _data); /// Copy a file from _sourcePath to _destPath. Signals on failure. Q_INVOKABLE void copyFile(QString const& _sourceUrl, QString const& _destUrl); + /// Move (rename) a file from _sourcePath to _destPath. Signals on failure. + Q_INVOKABLE void moveFile(QString const& _sourceUrl, QString const& _destUrl); + /// Check if file exists + Q_INVOKABLE bool fileExists(QString const& _url); private: QString getHomePath() const; diff --git a/mix/qml/NewProjectDialog.qml b/mix/qml/NewProjectDialog.qml index 7bba58418..be9880457 100644 --- a/mix/qml/NewProjectDialog.qml +++ b/mix/qml/NewProjectDialog.qml @@ -9,7 +9,7 @@ Window { modality: Qt.WindowModal width: 640 - height: 280 + height: 120 visible: false @@ -89,4 +89,5 @@ Window { pathField.text = u; } } + Component.onCompleted: pathField.text = fileIo.homePath } diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index 1f578fc6a..077aae28e 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -5,7 +5,7 @@ import QtQuick.Controls 1.0 import org.ethereum.qml.ProjectModel 1.0 Item { - + property bool renameMode: false; ColumnLayout { anchors.fill: parent Text { @@ -16,9 +16,10 @@ Item { visible: !ProjectModel.isEmpty; } ListView { + id: projectList Layout.fillWidth: true Layout.fillHeight: true - id: projectList + model: ProjectModel.listModel delegate: renderDelegate @@ -34,6 +35,21 @@ Item { ProjectModel.openDocument(ProjectModel.listModel.get(currentIndex).documentId); } } + Menu { + id: contextMenu + MenuItem { + text: qsTr("Rename") + onTriggered: { + renameMode = true; + } + } + MenuItem { + text: qsTr("Delete") + onTriggered: { + ProjectModel.removeDocument(projectList.model.get(projectList.currentIndex).documentId); + } + } + } } Component { id: renderDelegate @@ -43,7 +59,9 @@ Item { width: parent.width RowLayout { anchors.fill: parent + visible: !(index === projectList.currentIndex) || !renameMode Text { + id: nameText Layout.fillWidth: true Layout.fillHeight: true text: name @@ -51,17 +69,56 @@ Item { verticalAlignment: Text.AlignBottom } } + + TextInput { + id: textInput + text: nameText.text + visible: (index === projectList.currentIndex) && renameMode + MouseArea { + id: textMouseArea + anchors.fill: parent + hoverEnabled: true + z:2 + onClicked: { + console.log("clicked"); + textInput.forceActiveFocus(); + } + } + + onVisibleChanged: { + if (visible) { + selectAll(); + forceActiveFocus(); + } + } + + onAccepted: close(true); + onCursorVisibleChanged: { + if (!cursorVisible) + close(false); + } + onFocusChanged: { + if (!focus) + close(false); + } + function close(accept) { + renameMode = false; + if (accept) + ProjectModel.renameDocument(projectList.model.get(projectList.currentIndex).documentId, textInput.text); + } + } MouseArea { id: mouseArea z: 1 hoverEnabled: false anchors.fill: parent - + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked:{ projectList.currentIndex = index; + if (mouse.button === Qt.RightButton && !projectList.model.get(index).isContract) + contextMenu.popup(); } } - Connections { target: ProjectModel onProjectLoaded: { diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index cc5ecccd9..5337e2780 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -15,6 +15,8 @@ Item { signal projectClosed signal projectLoaded signal documentOpened(var document) + signal documentRemoved(var documentId) + signal documentUpdated(var documentId) //renamed signal projectSaving(var projectData) property bool isEmpty: (projectData === null) @@ -33,7 +35,12 @@ Item { function saveProject() { ProjectModelCode.saveProject(); } function loadProject(path) { ProjectModelCode.loadProject(path); } function addExistingFile() { ProjectModelCode.addExistingFile(); } + function newHtmlFile() { ProjectModelCode.newHtmlFile(); } + function newJsFile() { ProjectModelCode.newJsFile(); } + //function newContract() { ProjectModelCode.newContract(); } function openDocument(documentId) { ProjectModelCode.openDocument(documentId); } + function renameDocument(documentId, newName) { ProjectModelCode.renameDocument(documentId, newName); } + function removeDocument(documentId) { ProjectModelCode.removeDocument(documentId); } Connections { target: appContext @@ -95,7 +102,7 @@ Item { title: qsTr("Add a file") selectFolder: false onAccepted: { - var paths = openProjectFileDialog.fileUrls; + var paths = addExistingFileDialog.fileUrls; ProjectModelCode.doAddExistingFiles(paths); } } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index a547457b0..7cf2b3018 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -72,7 +72,7 @@ function loadProject(path) { } function addExistingFile() { - addExistingFileDialog().open(); + addExistingFileDialog.open(); } function addProjectFiles(files) { @@ -82,22 +82,31 @@ function addProjectFiles(files) { function addFile(fileName) { var p = projectPath + fileName; + var extension = fileName.substring(fileName.length - 4, fileName.length); + var isContract = extension === ".sol"; var fileData = { contract: false, path: p, - name: fileName, + name: isContract ? "Contract" : fileName, documentId: fileName, - isText: true, - isContract: fileName.substring(fileName.length - 4, fileName.length) === ".sol", + isText: isContract || extension === ".html" || extension === ".js", + isContract: fileData, }; projectListModel.append(fileData); } -function openDocument(documentId) { +function findDocument(documentId) +{ for (var i = 0; i < projectListModel.count; i++) if (projectListModel.get(i).documentId === documentId) - documentOpened(projectListModel.get(i)); + return i; + console.error("Cant find document " + documentId); + return -1; +} + +function openDocument(documentId) { + documentOpened(projectListModel.get(findDocument(documentId))); } function doCloseProject() { @@ -117,15 +126,15 @@ function doCreateProject(title, path) { fileIo.makeDir(dirPath); var projectFile = dirPath + projectFileName; - var indexFile = dirPath + "index.html"; - var contractsFile = dirPath + "contracts.sol"; + var indexFile = "index.html"; + var contractsFile = "contracts.sol"; var projectData = { title: title, - files: [ "contracts.sol", "index.html" ] + files: [ indexFile, contractsFile ] }; - - fileIo.writeFile(indexFile, ""); - fileIo.writeFile(contractsFile, "contract MyContract {}"); + //TODO: copy from template + fileIo.writeFile(dirPath + indexFile, ""); + fileIo.writeFile(dirPath + contractsFile, "contract MyContract {\n }\n"); var json = JSON.stringify(projectData); fileIo.writeFile(projectFile, json); loadProject(dirPath); @@ -134,9 +143,62 @@ function doCreateProject(title, path) { function doAddExistingFiles(files) { for(var i = 0; i < files.length; i++) { var sourcePath = files[i]; + console.log(sourcePath); var sourceFileName = sourcePath.substring(sourcePath.lastIndexOf("/") + 1, sourcePath.length); + console.log(sourceFileName); var destPath = projectPath + sourceFileName; - fileIo.copyFile(sourcePath, destPath); + console.log(destPath); + if (sourcePath !== destPath) + fileIo.copyFile(sourcePath, destPath); addFile(sourceFileName); } } + +function renameDocument(documentId, newName) { + var i = findDocument(documentId); + var document = projectListModel.get(i); + if (!document.isContract) { + var sourcePath = document.path; + var destPath = projectPath + newName; + fileIo.moveFile(sourcePath, destPath); + document.path = destPath; + document.name = newName; + projectListModel.set(i, document); + documentUpdated(documentId); + } +} + +function removeDocument(documentId) { + var i = findDocument(documentId); + var document = projectListModel.get(i); + if (!document.isContract) { + projectListModel.remove(i); + documentUpdated(documentId); + } +} + +function newHtmlFile() { + createAndAddFile("page", "html", "\n"); +} + +function newJsFile() { + createAndAddFile("script", "js", "function foo() {\n}\n"); +} + +function createAndAddFile(name, extension, content) { + var fileName = generateFileName(name, extension); + var filePath = projectPath + fileName; + fileIo.writeFile(filePath, content); + addFile(fileName); +} + +function generateFileName(name, extension) { + var i = 1; + do { + var fileName = name + i + "." + extension; + var filePath = projectPath + fileName; + i++; + } while (fileIo.fileExists(filePath)); + return fileName +} + diff --git a/mix/qml/main.qml b/mix/qml/main.qml index f59c5874c..94d061639 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -21,11 +21,16 @@ ApplicationWindow { title: qsTr("File") MenuItem { action: createProjectAction } MenuItem { action: openProjectAction } + MenuSeparator {} MenuItem { action: saveAllFilesAction } + MenuSeparator {} MenuItem { action: addExistingFileAction } MenuItem { action: addNewJsFileAction } MenuItem { action: addNewHtmlFileAction } - MenuItem { action: addNewContractAction } + MenuSeparator {} + //MenuItem { action: addNewContractAction } + MenuItem { action: closeProjectAction } + MenuSeparator {} MenuItem { action: exitAppAction } } Menu { @@ -95,7 +100,7 @@ ApplicationWindow { text: qsTr("New JavaScript file") shortcut: "Ctrl+Alt+J" enabled: !ProjectModel.isEmpty - onTriggered: ProjectModel.addJsFile(); + onTriggered: ProjectModel.newJsFile(); } Action { @@ -103,7 +108,7 @@ ApplicationWindow { text: qsTr("New HTML file") shortcut: "Ctrl+Alt+H" enabled: !ProjectModel.isEmpty - onTriggered: ProjectModel.addHtmlFile(); + onTriggered: ProjectModel.newHtmlFile(); } Action { @@ -111,7 +116,7 @@ ApplicationWindow { text: qsTr("New contract") shortcut: "Ctrl+Alt+C" enabled: !ProjectModel.isEmpty - onTriggered: ProjectModel.addContract(); + onTriggered: ProjectModel.newContract(); } Action { From aa389db06fb5ba3beb64b788dc753fb0c8b3cf69 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 11 Jan 2015 19:50:22 +0100 Subject: [PATCH 537/588] style fixed --- mix/FileIo.cpp | 4 ++-- mix/FileIo.h | 2 +- mix/qml/NewProjectDialog.qml | 4 ++-- mix/qml/StateDialog.qml | 4 ++-- mix/qml/TransactionDialog.qml | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 7eaa0ca7b..fed9909e6 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -42,7 +42,7 @@ QString FileIo::readFile(QString const& _url) { QUrl url(_url); QFile file(url.path()); - if(file.open(QIODevice::ReadOnly | QIODevice::Text)) + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream stream(&file); QString data = stream.readAll(); @@ -57,7 +57,7 @@ void FileIo::writeFile(QString const& _url, QString const& _data) { QUrl url(_url); QFile file(url.path()); - if(file.open(QIODevice::WriteOnly | QIODevice::Text)) + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream stream(&file); stream << _data; diff --git a/mix/FileIo.h b/mix/FileIo.h index e635ffa25..08d49e099 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -30,7 +30,7 @@ namespace mix { ///File services for QML -class FileIo : public QObject +class FileIo: public QObject { Q_OBJECT Q_PROPERTY(QString homePath READ getHomePath CONSTANT) diff --git a/mix/qml/NewProjectDialog.qml b/mix/qml/NewProjectDialog.qml index be9880457..406dc02b2 100644 --- a/mix/qml/NewProjectDialog.qml +++ b/mix/qml/NewProjectDialog.qml @@ -13,8 +13,8 @@ Window { visible: false - property alias projectTitle : titleField.text - readonly property string projectPath : "file://" + pathField.text + property alias projectTitle: titleField.text + readonly property string projectPath: "file://" + pathField.text signal accepted function open() { diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index 208c766f9..cde7cb3ef 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -11,8 +11,8 @@ Window { visible: false - property alias stateTitle : titleField.text - property alias stateBalance : balanceField.text + property alias stateTitle: titleField.text + property alias stateBalance: balanceField.text property int stateIndex property var stateTransactions: [] signal accepted diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 54528f97f..3a32e2af5 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -10,11 +10,11 @@ Window { visible: false property int transactionIndex - property alias transactionParams : paramsModel; - property alias gas : gasField.text; - property alias gasPrice : gasPriceField.text; - property alias transactionValue : valueField.text; - property alias functionId : functionComboBox.currentText; + property alias transactionParams: paramsModel; + property alias gas: gasField.text; + property alias gasPrice: gasPriceField.text; + property alias transactionValue: valueField.text; + property alias functionId: functionComboBox.currentText; property var itemParams; signal accepted; From 6e4d57817a20d66e1b6fd96966739e138dec9161 Mon Sep 17 00:00:00 2001 From: "U-SVZ13\\Arkady" Date: Sun, 11 Jan 2015 20:07:59 +0100 Subject: [PATCH 538/588] fixed msvc build --- libweb3jsonrpc/WebThreeStubServerBase.h | 2 +- mix/AppContext.cpp | 3 +-- mix/ClientModel.cpp | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 6868207a6..8648665be 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -121,7 +121,7 @@ public: std::map const& ids() const { return m_ids; } protected: - virtual bool authenticate(dev::TransactionSkeleton const& _t) const; + virtual bool authenticate(dev::TransactionSkeleton const& _t) const = 0; protected: virtual dev::eth::Interface* client() = 0; diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index 4bede3c49..4c8e61510 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -27,12 +27,11 @@ #include #include #include -#include #include "CodeModel.h" #include "FileIo.h" #include "ClientModel.h" #include "AppContext.h" - +#include using namespace dev; using namespace dev::eth; diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 6859b0279..9a90d52e3 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -33,6 +33,7 @@ #include "CodeModel.h" #include "ClientModel.h" +using namespace dev; using namespace dev::eth; using namespace dev::mix; From eaa4312f3fccc90defd1f49b86f71fb9fb5ec9c3 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 11 Jan 2015 20:14:42 +0100 Subject: [PATCH 539/588] compiling ethereum.js is part of the cmake --- cmake/EthDependencies.cmake | 9 +++++++++ libjsqrc/CMakeLists.txt | 10 ++++++++++ libjsqrc/compilejs.sh | 7 +++++++ 3 files changed, 26 insertions(+) create mode 100644 libjsqrc/compilejs.sh diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 136c86799..05389f24c 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -113,6 +113,15 @@ if (NOT HEADLESS) message(" - macdeployqt path: ${MACDEPLOYQT_APP}") endif() +# TODO check node && npm version + find_program(ETH_NODE node) + string(REGEX REPLACE "node" "" ETH_NODE_DIRECTORY ${ETH_NODE}) + message(" - nodejs location : ${ETH_NODE}") + + find_program(ETH_NPM npm) + message(" - npm location : ${ETH_NPM}") + string(REGEX REPLACE "npm" "" ETH_NPM_DIRECTORY ${ETH_NPM}) + endif() #HEADLESS # use multithreaded boost libraries, with -mt suffix diff --git a/libjsqrc/CMakeLists.txt b/libjsqrc/CMakeLists.txt index a6dbf023b..2635bc558 100644 --- a/libjsqrc/CMakeLists.txt +++ b/libjsqrc/CMakeLists.txt @@ -12,4 +12,14 @@ qt5_add_resources(JSQRC js.qrc) add_library(jsqrc STATIC ${JSQRC}) target_link_libraries(jsqrc Qt5::Core) +if (ETH_NODE AND ETH_NPM) + add_custom_target(ethereumjs) + add_custom_command(TARGET ethereumjs + POST_BUILD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND bash compilejs.sh ${ETH_NPM_DIRECTORY} ${ETH_NODE_DIRECTORY} + ) + add_dependencies(jsqrc ethereumjs) +endif() + install( TARGETS jsqrc ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) diff --git a/libjsqrc/compilejs.sh b/libjsqrc/compilejs.sh new file mode 100644 index 000000000..ba99e2415 --- /dev/null +++ b/libjsqrc/compilejs.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cd ethereumjs +export PATH=$PATH:$1:$2 +npm install +npm run-script build + From 88b338a42eab2c05f209f9cfbe6157bcc0049eb0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 11 Jan 2015 20:38:47 +0100 Subject: [PATCH 540/588] Make network work again. --- libethereum/EthereumPeer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 0901766bf..95e1aadda 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -317,6 +317,8 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) disable("Blacklisted client version."); else if (host()->isBanned(session()->id())) disable("Peer banned for previous bad behaviour."); + else + transition(Asking::Nothing); break; } case GetTransactionsPacket: break; // DEPRECATED. From 89031ff6382353afb889ef8520b0e59ff1c6c203 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 11 Jan 2015 20:39:06 +0100 Subject: [PATCH 541/588] Various fixes for the JS API. --- libdevcrypto/Common.cpp | 3 ++- libdevcrypto/CryptoPP.cpp | 17 +++++++++-------- libethereum/Client.cpp | 25 +++++++++++++------------ libethereum/Client.h | 12 ++++++------ libethereum/Interface.h | 7 +++---- libevm/ExtVMFace.h | 10 ++++++++++ libweb3jsonrpc/WebThreeStubServer.cpp | 7 ++++--- 7 files changed, 47 insertions(+), 34 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index f4803bd52..adcf70b61 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "SHA3.h" #include "FileSystem.h" #include "CryptoPP.h" @@ -139,7 +140,7 @@ h256 Nonce::get(bool _commit) static h256 s_seed; static string s_seedFile(getDataDir() + "/seed"); static mutex s_x; - lock_guard l(s_x); + Guard l(s_x); if (!s_seed) { static Nonce s_nonce; diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index d73e3fa43..acd59184f 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -20,6 +20,7 @@ */ #include "CryptoPP.h" +#include using namespace std; using namespace dev; @@ -40,7 +41,7 @@ void Secp256k1::encrypt(Public const& _k, bytes& io_cipher) ciphertext.resize(e.CiphertextLength(plen)); { - lock_guard l(x_rng); + Guard l(x_rng); e.Encrypt(m_rng, io_cipher.data(), plen, ciphertext.data()); } @@ -65,7 +66,7 @@ void Secp256k1::decrypt(Secret const& _k, bytes& io_text) DecodingResult r; { - lock_guard l(x_rng); + Guard l(x_rng); r = d.Decrypt(m_rng, io_text.data(), clen, plain.data()); } @@ -99,7 +100,7 @@ Signature Secp256k1::sign(Secret const& _key, h256 const& _hash) ECP::Point rp; Integer r; { - lock_guard l(x_params); + Guard l(x_params); rp = m_params.ExponentiateBase(k); r = m_params.ConvertElementToInteger(rp); } @@ -149,7 +150,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Element x; { - lock_guard l(x_curve); + Guard l(x_curve); m_curve.DecodePoint(x, encodedpoint, 33); if (!m_curve.VerifyPoint(x)) return recovered; @@ -158,7 +159,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) // if (_signature[64] & 2) // { // r += m_q; -// lock_guard l(x_params); +// Guard l(x_params); // if (r >= m_params.GetMaxExponent()) // return recovered; // } @@ -171,7 +172,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Point p; byte recoveredbytes[65]; { - lock_guard l(x_curve); + Guard l(x_curve); // todo: make generator member p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator()); m_curve.EncodePoint(recoveredbytes, p, false); @@ -210,7 +211,7 @@ void Secp256k1::exportPublicKey(CryptoPP::DL_PublicKey_EC const& bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); { - lock_guard l(x_params); + Guard l(x_params); m_params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); } @@ -223,7 +224,7 @@ void Secp256k1::exponentToPublic(Integer const& _e, Public& o_p) CryptoPP::DL_PublicKey_EC pk; { - lock_guard l(x_params); + Guard l(x_params); pk.Initialize(m_params, m_params.ExponentiateBase(_e)); } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index d539239ad..e4ff27990 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -185,7 +185,7 @@ unsigned Client::installWatch(h256 _h) unsigned Client::installWatch(LogFilter const& _f) { - lock_guard l(m_filterLock); + Guard l(m_filterLock); h256 h = _f.sha3(); @@ -199,7 +199,7 @@ void Client::uninstallWatch(unsigned _i) { cwatch << "XXX" << _i; - lock_guard l(m_filterLock); + Guard l(m_filterLock); auto it = m_watches.find(_i); if (it == m_watches.end()) @@ -215,7 +215,7 @@ void Client::uninstallWatch(unsigned _i) void Client::noteChanged(h256Set const& _filters) { - lock_guard l(m_filterLock); + Guard l(m_filterLock); for (auto& i: m_watches) if (_filters.count(i.second.id)) { @@ -227,7 +227,7 @@ void Client::noteChanged(h256Set const& _filters) void Client::appendFromNewPending(LogBloom _bloom, h256Set& o_changed) const { // TODO: more precise check on whether the txs match. - lock_guard l(m_filterLock); + Guard l(m_filterLock); for (pair const& i: m_filters) if ((unsigned)i.second.filter.latest() > m_bc.number() && i.second.filter.matches(_bloom)) o_changed.insert(i.first); @@ -238,7 +238,7 @@ void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const // TODO: more precise check on whether the txs match. auto d = m_bc.info(_block); - lock_guard l(m_filterLock); + Guard l(m_filterLock); for (pair const& i: m_filters) if ((unsigned)i.second.filter.latest() >= d.number && (unsigned)i.second.filter.earliest() <= d.number && i.second.filter.matches(d.logBloom)) o_changed.insert(i.first); @@ -592,16 +592,16 @@ BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const return BlockInfo::fromHeader(b[2][_i].data()); } -LogEntries Client::logs(LogFilter const& _f) const +LocalisedLogEntries Client::logs(LogFilter const& _f) const { - LogEntries ret; - unsigned begin = min(m_bc.number(), (unsigned)_f.latest()); - unsigned end = min(begin, (unsigned)_f.earliest()); + LocalisedLogEntries ret; + unsigned begin = min(m_bc.number() + 1, (unsigned)_f.latest()); + unsigned end = min(m_bc.number(), min(begin, (unsigned)_f.earliest())); unsigned m = _f.max(); unsigned s = _f.skip(); // Handle pending transactions differently as they're not on the block chain. - if (begin == m_bc.number()) + if (begin > m_bc.number()) { ReadGuard l(x_stateDB); for (unsigned i = 0; i < m_postMine.pending().size(); ++i) @@ -615,9 +615,10 @@ LogEntries Client::logs(LogFilter const& _f) const if (s) s--; else - ret.insert(ret.begin(), le[j]); + ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin)); } } + begin = m_bc.number(); } #if ETH_DEBUG @@ -649,7 +650,7 @@ LogEntries Client::logs(LogFilter const& _f) const if (s) s--; else - ret.insert(ret.begin(), le[j]); + ret.insert(ret.begin(), LocalisedLogEntry(le[j], n)); } } } diff --git a/libethereum/Client.h b/libethereum/Client.h index e83858323..a4d04f54d 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -188,11 +188,11 @@ public: virtual unsigned installWatch(LogFilter const& _filter); virtual unsigned installWatch(h256 _filterId); virtual void uninstallWatch(unsigned _watchId); - virtual bool peekWatch(unsigned _watchId) const { std::lock_guard l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } } - virtual bool checkWatch(unsigned _watchId) { std::lock_guard l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; } + virtual bool peekWatch(unsigned _watchId) const { Guard l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } } + virtual bool checkWatch(unsigned _watchId) { Guard l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; } - virtual LogEntries logs(unsigned _watchId) const { try { std::lock_guard l(m_filterLock); return logs(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return LogEntries(); } } - virtual LogEntries logs(LogFilter const& _filter) const; + virtual LocalisedLogEntries logs(unsigned _watchId) const { try { Guard l(m_filterLock); return logs(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return LocalisedLogEntries(); } } + virtual LocalisedLogEntries logs(LogFilter const& _filter) const; // [EXTRA API]: @@ -313,7 +313,7 @@ private: TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). - mutable boost::shared_mutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine. + mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine. OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it. State m_preMine; ///< The present state of the client. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). @@ -321,7 +321,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. std::vector m_miners; - mutable boost::shared_mutex x_miners; + mutable SharedMutex x_miners; bool m_paranoia = false; ///< Should we be paranoid about our state? bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping. bool m_forceMining = false; ///< Mine even when there are no transactions pending? diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 28ac26819..c8fe4a2e0 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -86,8 +86,8 @@ public: // [LOGS API] - virtual LogEntries logs(unsigned _watchId) const = 0; - virtual LogEntries logs(LogFilter const& _filter) const = 0; + virtual LocalisedLogEntries logs(unsigned _watchId) const = 0; + virtual LocalisedLogEntries logs(LogFilter const& _filter) const = 0; /// Install, uninstall and query watches. virtual unsigned installWatch(LogFilter const& _filter) = 0; @@ -180,8 +180,7 @@ public: bool check() { return m_c ? m_c->checkWatch(m_id) : false; } bool peek() { return m_c ? m_c->peekWatch(m_id) : false; } -// PastMessages messages() const { return m_c->messages(m_id); } - LogEntries logs() const { return m_c->logs(m_id); } + LocalisedLogEntries logs() const { return m_c->logs(m_id); } private: Interface* m_c = nullptr; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 84cfe0a94..13e8712b8 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -60,6 +60,16 @@ struct LogEntry using LogEntries = std::vector; +struct LocalisedLogEntry: public LogEntry +{ + LocalisedLogEntry() {} + LocalisedLogEntry(LogEntry const& _le, unsigned _number): LogEntry(_le), number(_number) {} + + unsigned number = 0; +}; + +using LocalisedLogEntries = std::vector; + inline LogBloom bloom(LogEntries const& _logs) { LogBloom ret; diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 1fb284aaa..52c29c140 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -72,7 +72,7 @@ static Json::Value toJson(dev::eth::Transaction const& _t) return res; } -static Json::Value toJson(dev::eth::LogEntry const& _e) +static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) { Json::Value res; @@ -80,13 +80,14 @@ static Json::Value toJson(dev::eth::LogEntry const& _e) res["address"] = toJS(_e.address); for (auto const& t: _e.topics) res["topics"].append(toJS(t)); + res["number"] = _e.number; return res; } -static Json::Value toJson(dev::eth::LogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7. +static Json::Value toJson(dev::eth::LocalisedLogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7. { Json::Value res; - for (dev::eth::LogEntry const& e: _es) + for (dev::eth::LocalisedLogEntry const& e: _es) res.append(toJson(e)); return res; } From 12f6768abe1476507dc7da4935b4f83c9d956b13 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 11 Jan 2015 21:01:55 +0100 Subject: [PATCH 542/588] Remove NodeMode from ethereum. --- alethzero/MainWin.cpp | 2 -- eth/main.cpp | 6 ++++++ libethereum/Client.h | 6 ------ libp2p/Host.cpp | 2 +- neth/main.cpp | 6 ++++++ 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index a03c7908f..7039070a1 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1811,8 +1811,6 @@ void Main::on_net_triggered() web3()->setClientVersion(n); if (ui->net->isChecked()) { - // TODO: alter network stuff? - //ui->port->value(), string(), 0, NodeMode::Full, ui->idealPeers->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0 web3()->setIdealPeerCount(ui->idealPeers->value()); web3()->setNetworkPreferences(netPrefs()); ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0); diff --git a/eth/main.cpp b/eth/main.cpp index a0a605193..dfe020763 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -180,6 +180,12 @@ void sighandler(int) g_exit = true; } +enum class NodeMode +{ + PeerServer, + Full +}; + int main(int argc, char** argv) { unsigned short listenPort = 30303; diff --git a/libethereum/Client.h b/libethereum/Client.h index a4d04f54d..0c9c25fb1 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -57,12 +57,6 @@ enum ClientWorkState Deleted }; -enum class NodeMode -{ - PeerServer, - Full -}; - class VersionChecker { public: diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index d1c3cd19b..4be6f228f 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -558,7 +558,7 @@ void Host::prunePeers() for (auto i: m_peers) if (!dc.count(i.first)) if (auto p = i.second.lock()) - if (/*(m_mode != NodeMode::Host || p->m_caps != 0x01) &&*/ chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers. + if (chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers. { ++agedPeers; if ((!worst || p->rating() < worst->rating() || (p->rating() == worst->rating() && p->m_connect > worst->m_connect))) // kill older ones diff --git a/neth/main.cpp b/neth/main.cpp index 0b48edc11..1252b205b 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -292,6 +292,12 @@ int nc_window_streambuf::sync() vector form_dialog(vector _sfields, vector _lfields, vector _bfields, int _cols, int _rows, string _post_form); +enum class NodeMode +{ + PeerServer, + Full +}; + int main(int argc, char** argv) { unsigned short listenPort = 30303; From 134e81919cc741e70baab3e5735fcfdbe8e58922 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 11 Jan 2015 21:22:34 +0100 Subject: [PATCH 543/588] order of status message --- cmake/EthDependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 05389f24c..9b00a182f 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -119,8 +119,8 @@ if (NOT HEADLESS) message(" - nodejs location : ${ETH_NODE}") find_program(ETH_NPM npm) - message(" - npm location : ${ETH_NPM}") string(REGEX REPLACE "npm" "" ETH_NPM_DIRECTORY ${ETH_NPM}) + message(" - npm location : ${ETH_NPM}") endif() #HEADLESS From e6ca33f814149a35cb2ece9c01046b1c2f1cd152 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 11 Jan 2015 23:26:37 +0100 Subject: [PATCH 544/588] API change: eth.watches will give you the log entries that are new as an arg. --- alethzero/MainWin.cpp | 25 +++--- alethzero/MainWin.h | 8 +- libethereum/Client.cpp | 99 ++++++++++++++++----- libethereum/Client.h | 11 +-- libethereum/Interface.h | 8 +- libethereum/LogFilter.cpp | 17 ++-- libethereum/State.cpp | 6 +- libethereum/State.h | 4 +- libweb3jsonrpc/WebThreeStubServer.cpp | 4 +- libweb3jsonrpc/WebThreeStubServer.h | 2 +- libweb3jsonrpc/abstractwebthreestubserver.h | 4 +- libweb3jsonrpc/spec.json | 2 +- third/MainWin.cpp | 23 ++--- third/MainWin.h | 8 +- 14 files changed, 145 insertions(+), 76 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 7039070a1..01b112b50 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -244,14 +244,14 @@ void Main::onKeysChanged() installBalancesWatch(); } -unsigned Main::installWatch(dev::eth::LogFilter const& _tf, std::function const& _f) +unsigned Main::installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf); m_handlers[ret] = _f; return ret; } -unsigned Main::installWatch(dev::h256 _tf, std::function const& _f) +unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf); m_handlers[ret] = _f; @@ -266,10 +266,10 @@ void Main::uninstallWatch(unsigned _w) void Main::installWatches() { - installWatch(dev::eth::LogFilter().address(c_newConfig), [=]() { installNameRegWatch(); }); - installWatch(dev::eth::LogFilter().address(c_newConfig), [=]() { installCurrenciesWatch(); }); - installWatch(dev::eth::PendingChangedFilter, [=](){ onNewPending(); }); - installWatch(dev::eth::ChainChangedFilter, [=](){ onNewBlock(); }); + installWatch(dev::eth::LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installNameRegWatch(); }); + installWatch(dev::eth::LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installCurrenciesWatch(); }); + installWatch(dev::eth::PendingChangedFilter, [=](LocalisedLogEntries const&){ onNewPending(); }); + installWatch(dev::eth::ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); }); } Address Main::getNameReg() const @@ -285,13 +285,13 @@ Address Main::getCurrencies() const void Main::installNameRegWatch() { uninstallWatch(m_nameRegFilter); - m_nameRegFilter = installWatch(dev::eth::LogFilter().address((u160)getNameReg()), [=](){ onNameRegChange(); }); + m_nameRegFilter = installWatch(dev::eth::LogFilter().address((u160)getNameReg()), [=](LocalisedLogEntries const&){ onNameRegChange(); }); } void Main::installCurrenciesWatch() { uninstallWatch(m_currenciesFilter); - m_currenciesFilter = installWatch(dev::eth::LogFilter().address((u160)getCurrencies()), [=](){ onCurrenciesChange(); }); + m_currenciesFilter = installWatch(dev::eth::LogFilter().address((u160)getCurrencies()), [=](LocalisedLogEntries const&){ onCurrenciesChange(); }); } void Main::installBalancesWatch() @@ -309,7 +309,7 @@ void Main::installBalancesWatch() tf.address(c).topic(h256(i.address(), h256::AlignRight)); uninstallWatch(m_balancesFilter); - m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); }); + m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); }); } void Main::onNameRegChange() @@ -1171,8 +1171,11 @@ void Main::timerEvent(QTimerEvent*) m_qweb->poll(); for (auto const& i: m_handlers) - if (ethereum()->checkWatch(i.first)) - i.second(); + { + auto ls = ethereum()->checkWatch(i.first); + if (ls.size()) + i.second(ls); + } } string Main::renderDiff(dev::eth::StateDiff const& _d) const diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 5a331df7d..52a71102d 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -66,6 +66,8 @@ struct WorldState std::vector levels; }; +using WatchHandler = std::function; + class Main : public QMainWindow { Q_OBJECT @@ -195,8 +197,8 @@ private: dev::u256 value() const; dev::u256 gasPrice() const; - unsigned installWatch(dev::eth::LogFilter const& _tf, std::function const& _f); - unsigned installWatch(dev::h256 _tf, std::function const& _f); + unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f); + unsigned installWatch(dev::h256 _tf, WatchHandler const& _f); void uninstallWatch(unsigned _w); void keysChanged(); @@ -229,7 +231,7 @@ private: std::unique_ptr m_webThree; - std::map> m_handlers; + std::map m_handlers; unsigned m_nameRegFilter = (unsigned)-1; unsigned m_currenciesFilter = (unsigned)-1; unsigned m_balancesFilter = (unsigned)-1; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index e4ff27990..c963ee401 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -177,21 +177,29 @@ void Client::clearPending() unsigned Client::installWatch(h256 _h) { - auto ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0; - m_watches[ret] = ClientWatch(_h); - cwatch << "+++" << ret << _h; + unsigned ret; + { + Guard l(m_filterLock); + ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0; + m_watches[ret] = ClientWatch(_h); + cwatch << "+++" << ret << _h; + } + auto ch = logs(ret); + { + Guard l(m_filterLock); + swap(m_watches[ret].changes, ch); + } return ret; } unsigned Client::installWatch(LogFilter const& _f) { - Guard l(m_filterLock); - h256 h = _f.sha3(); - - if (!m_filters.count(h)) - m_filters.insert(make_pair(h, _f)); - + { + Guard l(m_filterLock); + if (!m_filters.count(h)) + m_filters.insert(make_pair(h, _f)); + } return installWatch(h); } @@ -216,32 +224,81 @@ void Client::uninstallWatch(unsigned _i) void Client::noteChanged(h256Set const& _filters) { Guard l(m_filterLock); + // accrue all changes left in each filter into the watches. for (auto& i: m_watches) if (_filters.count(i.second.id)) { // cwatch << "!!!" << i.first << i.second.id; - i.second.changes++; + try { + i.second.changes += m_filters.at(i.second.id).changes; + } catch(...){} } + // clear the filters now. + for (auto& i: m_filters) + i.second.changes.clear(); } -void Client::appendFromNewPending(LogBloom _bloom, h256Set& o_changed) const +LocalisedLogEntries Client::peekWatch(unsigned _watchId) const +{ + Guard l(m_filterLock); + + try { + return m_watches.at(_watchId).changes; + } catch (...) {} + return LocalisedLogEntries(); +} + +LocalisedLogEntries Client::checkWatch(unsigned _watchId) { - // TODO: more precise check on whether the txs match. Guard l(m_filterLock); - for (pair const& i: m_filters) - if ((unsigned)i.second.filter.latest() > m_bc.number() && i.second.filter.matches(_bloom)) - o_changed.insert(i.first); + LocalisedLogEntries ret; + + try { + std::swap(ret, m_watches.at(_watchId).changes); + } catch (...) {} + + return ret; +} + +void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed) +{ + Guard l(m_filterLock); + for (pair& i: m_filters) + if ((unsigned)i.second.filter.latest() > m_bc.number()) + { + // acceptable number. + auto m = i.second.filter.matches(_receipt); + if (m.size()) + { + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1)); + io_changed.insert(i.first); + } + } } -void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const +void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed) { // TODO: more precise check on whether the txs match. auto d = m_bc.info(_block); + auto br = m_bc.receipts(_block); Guard l(m_filterLock); - for (pair const& i: m_filters) + for (pair& i: m_filters) if ((unsigned)i.second.filter.latest() >= d.number && (unsigned)i.second.filter.earliest() <= d.number && i.second.filter.matches(d.logBloom)) - o_changed.insert(i.first); + // acceptable number & looks like block may contain a matching log entry. + for (TransactionReceipt const& tr: br.receipts) + { + auto m = i.second.filter.matches(tr); + if (m.size()) + { + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l, (unsigned)d.number)); + io_changed.insert(i.first); + } + } } void Client::setForceMining(bool _enable) @@ -468,10 +525,10 @@ void Client::doWork() // returns h256s as blooms, once for each transaction. cwork << "postSTATE <== TQ"; - h512s newPendingBlooms = m_postMine.sync(m_bc, m_tq); - if (newPendingBlooms.size()) + TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq); + if (newPendingReceipts.size()) { - for (auto i: newPendingBlooms) + for (auto i: newPendingReceipts) appendFromNewPending(i, changeds); changeds.insert(PendingChangedFilter); diff --git a/libethereum/Client.h b/libethereum/Client.h index 0c9c25fb1..d0dce4cc1 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -78,6 +78,7 @@ struct InstalledFilter LogFilter filter; unsigned refCount = 1; + LocalisedLogEntries changes; }; static const h256 PendingChangedFilter = u256(0); @@ -89,7 +90,7 @@ struct ClientWatch explicit ClientWatch(h256 _id): id(_id) {} h256 id; - unsigned changes = 1; + LocalisedLogEntries changes; }; struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; }; @@ -182,8 +183,8 @@ public: virtual unsigned installWatch(LogFilter const& _filter); virtual unsigned installWatch(h256 _filterId); virtual void uninstallWatch(unsigned _watchId); - virtual bool peekWatch(unsigned _watchId) const { Guard l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } } - virtual bool checkWatch(unsigned _watchId) { Guard l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; } + virtual LocalisedLogEntries peekWatch(unsigned _watchId) const; + virtual LocalisedLogEntries checkWatch(unsigned _watchId); virtual LocalisedLogEntries logs(unsigned _watchId) const { try { Guard l(m_filterLock); return logs(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return LocalisedLogEntries(); } } virtual LocalisedLogEntries logs(LogFilter const& _filter) const; @@ -286,11 +287,11 @@ private: /// Collate the changed filters for the bloom filter of the given pending transaction. /// Insert any filters that are activated into @a o_changed. - void appendFromNewPending(LogBloom _pendingTransactionBloom, h256Set& o_changed) const; + void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed); /// Collate the changed filters for the hash of the given block. /// Insert any filters that are activated into @a o_changed. - void appendFromNewBlock(h256 _blockHash, h256Set& o_changed) const; + void appendFromNewBlock(h256 const& _blockHash, h256Set& io_changed); /// Record that the set of filters @a _filters have changed. /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. diff --git a/libethereum/Interface.h b/libethereum/Interface.h index c8fe4a2e0..35cd59663 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -93,8 +93,8 @@ public: virtual unsigned installWatch(LogFilter const& _filter) = 0; virtual unsigned installWatch(h256 _filterId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0; - virtual bool peekWatch(unsigned _watchId) const = 0; - virtual bool checkWatch(unsigned _watchId) = 0; + virtual LocalisedLogEntries peekWatch(unsigned _watchId) const = 0; + virtual LocalisedLogEntries checkWatch(unsigned _watchId) = 0; // [BLOCK QUERY API] @@ -178,8 +178,8 @@ public: Watch(Interface& _c, LogFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {} ~Watch() { if (m_c) m_c->uninstallWatch(m_id); } - bool check() { return m_c ? m_c->checkWatch(m_id) : false; } - bool peek() { return m_c ? m_c->peekWatch(m_id) : false; } + LocalisedLogEntries check() { return m_c ? m_c->checkWatch(m_id) : LocalisedLogEntries(); } + LocalisedLogEntries peek() { return m_c ? m_c->peekWatch(m_id) : LocalisedLogEntries(); } LocalisedLogEntries logs() const { return m_c->logs(m_id); } private: diff --git a/libethereum/LogFilter.cpp b/libethereum/LogFilter.cpp index 81cb439ba..eca428cfa 100644 --- a/libethereum/LogFilter.cpp +++ b/libethereum/LogFilter.cpp @@ -68,14 +68,15 @@ bool LogFilter::matches(State const& _s, unsigned _i) const LogEntries LogFilter::matches(TransactionReceipt const& _m) const { LogEntries ret; - for (LogEntry const& e: _m.log()) - { - if (!m_addresses.empty() && !m_addresses.count(e.address)) - continue; - for (auto const& t: m_topics) - if (!std::count(e.topics.begin(), e.topics.end(), t)) + if (matches(_m.bloom())) + for (LogEntry const& e: _m.log()) + { + if (!m_addresses.empty() && !m_addresses.count(e.address)) continue; - ret.push_back(e); - } + for (auto const& t: m_topics) + if (!std::count(e.topics.begin(), e.topics.end(), t)) + continue; + ret.push_back(e); + } return ret; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index e0705859f..3c59bf415 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -412,10 +412,10 @@ bool State::cull(TransactionQueue& _tq) const return ret; } -h512s State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged) +TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged) { // TRANSACTIONS - h512s ret; + TransactionReceipts ret; auto ts = _tq.transactions(); auto lh = getLastHashes(_bc); @@ -432,7 +432,7 @@ h512s State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transact uncommitToMine(); // boost::timer t; execute(lh, i.second); - ret.push_back(m_receipts.back().bloom()); + ret.push_back(m_receipts.back()); _tq.noteGood(i); ++goodTxs; // cnote << "TX took:" << t.elapsed() * 1000; diff --git a/libethereum/State.h b/libethereum/State.h index 921c82bb9..e7e1bbfab 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -140,10 +140,10 @@ public: // TODO: Cleaner interface. /// Sync our transactions, killing those from the queue that we have and assimilating those that we don't. - /// @returns a list of bloom filters one for each transaction placed from the queue into the state. + /// @returns a list of receipts one for each transaction placed from the queue into the state. /// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue /// changed and the pointer is non-null - h512s sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr); + TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr); /// Like sync but only operate on _tq, killing the invalid/old ones. bool cull(TransactionQueue& _tq) const; diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 52c29c140..8f548e29a 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -347,9 +347,9 @@ std::string WebThreeStubServer::eth_call(Json::Value const& _json) return ret; } -bool WebThreeStubServer::eth_changed(int const& _id) +Json::Value WebThreeStubServer::eth_changed(int const& _id) { - return client()->checkWatch(_id); + return toJson(client()->checkWatch(_id)); } std::string WebThreeStubServer::eth_codeAt(string const& _address) diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 0f81fce9d..fe232d8b9 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -71,7 +71,7 @@ public: virtual Json::Value eth_blockByHash(std::string const& _hash); virtual Json::Value eth_blockByNumber(int const& _number); virtual std::string eth_call(Json::Value const& _json); - virtual bool eth_changed(int const& _id); + virtual Json::Value eth_changed(int const& _id); virtual std::string eth_codeAt(std::string const& _address); virtual std::string eth_coinbase(); virtual Json::Value eth_compilers(); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 779d8bec3..15c53e0fa 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -45,7 +45,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(new jsonrpc::Procedure("eth_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_newFilterString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newFilterStringI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uninstallFilterI); - this->bindAndAddMethod(new jsonrpc::Procedure("eth_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_changedI); + this->bindAndAddMethod(new jsonrpc::Procedure("eth_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_changedI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_filterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_filterLogsI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI); this->bindAndAddMethod(new jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI); @@ -287,7 +287,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer const& _f) +unsigned Main::installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf); m_handlers[ret] = _f; return ret; } -unsigned Main::installWatch(dev::h256 _tf, std::function const& _f) +unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf); m_handlers[ret] = _f; @@ -198,21 +198,21 @@ unsigned Main::installWatch(dev::h256 _tf, std::function const& _f) void Main::installWatches() { - installWatch(dev::eth::LogFilter().topic((u256)(u160)c_config).topic((u256)0), [=](){ installNameRegWatch(); }); - installWatch(dev::eth::LogFilter().topic((u256)(u160)c_config).topic((u256)1), [=](){ installCurrenciesWatch(); }); - installWatch(dev::eth::ChainChangedFilter, [=](){ onNewBlock(); }); + installWatch(dev::eth::LogFilter().topic((u256)(u160)c_config).topic((u256)0), [=](LocalisedLogEntries const&){ installNameRegWatch(); }); + installWatch(dev::eth::LogFilter().topic((u256)(u160)c_config).topic((u256)1), [=](LocalisedLogEntries const&){ installCurrenciesWatch(); }); + installWatch(dev::eth::ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); }); } void Main::installNameRegWatch() { ethereum()->uninstallWatch(m_nameRegFilter); - m_nameRegFilter = installWatch(dev::eth::LogFilter().topic(ethereum()->stateAt(c_config, 0)), [=](){ onNameRegChange(); }); + m_nameRegFilter = installWatch(dev::eth::LogFilter().topic(ethereum()->stateAt(c_config, 0)), [=](LocalisedLogEntries const&){ onNameRegChange(); }); } void Main::installCurrenciesWatch() { ethereum()->uninstallWatch(m_currenciesFilter); - m_currenciesFilter = installWatch(dev::eth::LogFilter().topic(ethereum()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); }); + m_currenciesFilter = installWatch(dev::eth::LogFilter().topic(ethereum()->stateAt(c_config, 1)), [=](LocalisedLogEntries const&){ onCurrenciesChange(); }); } void Main::installBalancesWatch() @@ -228,7 +228,7 @@ void Main::installBalancesWatch() tf.address(c).topic((u256)(u160)i.address()); ethereum()->uninstallWatch(m_balancesFilter); - m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); }); + m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); }); } void Main::onNameRegChange() @@ -536,8 +536,11 @@ void Main::timerEvent(QTimerEvent*) m_qweb->poll(); for (auto const& i: m_handlers) - if (ethereum()->checkWatch(i.first)) - i.second(); + { + auto ls = ethereum()->checkWatch(i.first); + if (ls.size()) + i.second(ls); + } } void Main::ourAccountsRowsMoved() diff --git a/third/MainWin.h b/third/MainWin.h index 478fb6fb6..3b4acc3a8 100644 --- a/third/MainWin.h +++ b/third/MainWin.h @@ -50,6 +50,8 @@ class WhisperHost; class QQuickView; class WebThreeStubServer; +using WatchHandler = std::function; + class Main : public QMainWindow { Q_OBJECT @@ -95,8 +97,8 @@ private: void readSettings(bool _skipGeometry = false); void writeSettings(); - unsigned installWatch(dev::eth::LogFilter const& _tf, std::function const& _f); - unsigned installWatch(dev::h256 _tf, std::function const& _f); + unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f); + unsigned installWatch(dev::h256 _tf, WatchHandler const& _f); void onNewBlock(); void onNameRegChange(); @@ -124,7 +126,7 @@ private: QList m_myKeys; QList m_myIdentities; - std::map> m_handlers; + std::map m_handlers; unsigned m_nameRegFilter = (unsigned)-1; unsigned m_currenciesFilter = (unsigned)-1; unsigned m_balancesFilter = (unsigned)-1; From 7deff572b68aa031622cde0ed15c8ca2a515c606 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 11 Jan 2015 23:30:16 +0100 Subject: [PATCH 545/588] New PoC-8 standard services. --- standard.js | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 standard.js diff --git a/standard.js b/standard.js new file mode 100644 index 000000000..74ebc74ad --- /dev/null +++ b/standard.js @@ -0,0 +1,61 @@ +var compile = function(name) { return web3.eth.solidity(env.contents("../../dapp-bin/" + name + "/" + name + ".sol")); }; +var create = function(code) { return web3.eth.transact({ 'code': code }); }; +var send = function(from, val, to) { return web3.eth.transact({ 'from': from, 'value': val, 'to': to }); }; +var initService = function(name, dep) { return dep.then(function(){ return compile(name).then(create); }); }; + +var addrConfig = compile("config").then(create); +var addrNameReg = initService("namereg", addrConfig); + +var abiNameReg = [{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":false,"inputs":[],"name":"kill","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]}]; +var regName = function(account, name) { return web3.contract(addrNameReg, abiNameReg).register(name).transact({'from': account, 'gas': 10000}); }; +/* +var coins = initService("coins", 1, nameReg); +var coin = initService("coin", 2, coins); +var approve = function(account, approvedAddress) { web3.eth.transact({ 'from': account, 'to': coin, 'gas': '10000', 'data': [ web3.fromAscii('approve'), approvedAddress ] }); }; +var exchange = initService("exchange", 3, coin); +var offer = function(account, haveCoin, haveVal, wantCoin, wantVal) { web3.eth.transact({ 'from': account, 'to': exchange, 'gas': '10000', 'data': [web3.fromAscii('new'), haveCoin, haveVal, wantCoin, wantVal] }); }; +*/ +addrConfig.then(function() { + env.note("config ready"); + web3.eth.accounts.then(function(accounts) + { + env.note("accounts ready"); + var funded = send(accounts[0], '100000000000000000000', accounts[1]); + funded.then(function(){ + env.note("second account funded"); + regName(accounts[1], 'Gav Would'); + }); + regName(accounts[0], 'Gav'); + // TODO: once we have the exchange. +// approve(accounts[0], exchange).then(function(){ offer(accounts[0], coin, '5000', '0', '5000000000000000000'); }); +// funded.then(function(){ approve(accounts[1], exchange); }); + + // TODO: once we have a new implementation of DNSReg. + // env.note('Register gav.eth...') + // eth.transact({ 'to': dnsReg, 'data': [web3.fromAscii('register'), web3.fromAscii('gav'), web3.fromAscii('opensecrecy.com')] }); + }); +}); + +// TODO +/* +var nameRegJeff; + +env.note('Create NameRegJeff...') +eth.transact({ 'code': nameRegCode }, function(a) { nameRegJeff = a; }); + +env.note('Register NameRegJeff...') +eth.transact({ 'to': config, 'data': ['4', nameRegJeff] }); + +var dnsRegCode = '0x60006000546000600053602001546000600053604001546020604060206020600073661005d2720d855f1d9976f88bb10c1a3398c77f6103e8f17f7265676973746572000000000000000000000000000000000000000000000000600053606001600060200201547f446e735265670000000000000000000000000000000000000000000000000000600053606001600160200201546000600060006000604060606000600053604001536103e8f1327f6f776e65720000000000000000000000000000000000000000000000000000005761011663000000e46000396101166000f20060006000547f72656769737465720000000000000000000000000000000000000000000000006000602002350e0f630000006d596000600160200235560e0f630000006c59600032560e0f0f6300000057596000325657600260200235600160200235576001602002353257007f64657265676973746572000000000000000000000000000000000000000000006000602002350e0f63000000b95960016020023532560e0f63000000b959600032576000600160200235577f6b696c6c000000000000000000000000000000000000000000000000000000006000602002350e0f630000011559327f6f776e6572000000000000000000000000000000000000000000000000000000560e0f63000001155932ff00'; + +var dnsReg; +env.note('Create DnsReg...') +eth.transact({ 'code': dnsRegCode }, function(a) { dnsReg = a; }); + +env.note('DnsReg at address ' + dnsReg) + +env.note('Register DnsReg...') +eth.transact({ 'to': config, 'data': ['4', dnsReg] }); +*/ + +// env.load('/home/gav/Eth/cpp-ethereum/stdserv.js') From a0de919f65a7b6e47a8c4afcaf7fa550a4c8346f Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 11:35:54 +0100 Subject: [PATCH 546/588] 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 81dbf3ec5f9fabcd2f1912c69841bbf85c935ffd Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 12 Jan 2015 11:48:24 +0100 Subject: [PATCH 547/588] fix for eth_changed --- libqethereum/QEthereum.cpp | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index daf773a22..44e882178 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -134,24 +134,7 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo) if (!_addInfo.compare("internal")) return; - if (!_addInfo.compare("eth_changed")) - { - QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array(); - for (int i = 0; i < resultsArray.size(); i++) - { - QJsonObject elem = resultsArray[i].toObject(); - if (elem.contains("result") && elem["result"].toBool() == true) - { - QJsonObject res; - res["_event"] = _addInfo; - res["_id"] = (int)m_watches[i]; // we can do that couse poll is synchronous - response(QString::fromUtf8(QJsonDocument(res).toJson())); - } - } - return; - } - - if (!_addInfo.compare("shh_changed")) + if (!_addInfo.compare("shh_changed") || !_addInfo.compare("eth_changed")) { QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array(); for (int i = 0; i < resultsArray.size(); i++) @@ -161,13 +144,18 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo) { QJsonObject res; res["_event"] = _addInfo; - res["_id"] = (int)m_shhWatches[i]; + + if (!_addInfo.compare("shh_changed")) + res["_id"] = (int)m_shhWatches[i]; // we can do that couse poll is synchronous + else + res["_id"] = (int)m_watches[i]; + res["data"] = elem["result"].toArray(); response(QString::fromUtf8(QJsonDocument(res).toJson())); } } } - + QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); if ((!_addInfo.compare("eth_newFilter") || !_addInfo.compare("eth_newFilterString")) && f.contains("result")) From 389b0973c4ef343faf3b35fec4d7859ad0a5c4e1 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 12:46:40 +0100 Subject: [PATCH 548/588] 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 5e0b71730c9d691b5fb994ce95ef670918c0d1d5 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 12 Jan 2015 12:46:52 +0100 Subject: [PATCH 549/588] More convenient function type construction. --- libsolidity/ExpressionCompiler.cpp | 2 +- libsolidity/GlobalContext.cpp | 45 +++++++----------------------- libsolidity/Scanner.cpp | 20 +------------ libsolidity/Token.cpp | 17 +++++++++++ libsolidity/Token.h | 2 ++ libsolidity/Types.cpp | 29 ++++++++++--------- libsolidity/Types.h | 6 ++++ 7 files changed, 53 insertions(+), 68 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 4fdea3326..1c02f4f32 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -250,7 +250,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); }; - appendExternalFunctionCall(FunctionType({}, {}, Location::EXTERNAL), {}, options); + appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, Location::EXTERNAL), {}, options); break; } case Location::SUICIDE: diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index 633331a90..26a52fd10 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -34,54 +34,29 @@ namespace solidity { GlobalContext::GlobalContext(): -// TODO: make this cleaner. m_magicVariables(vector>{make_shared("block", make_shared(MagicType::Kind::BLOCK)), make_shared("msg", make_shared(MagicType::Kind::MSG)), make_shared("tx", make_shared(MagicType::Kind::TX)), make_shared("suicide", - make_shared(TypePointers({std::make_shared(0, - IntegerType::Modifier::ADDRESS)}), - TypePointers(), - FunctionType::Location::SUICIDE)), + make_shared(vector{"address"}, vector{}, FunctionType::Location::SUICIDE)), make_shared("sha3", - make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - FunctionType::Location::SHA3)), + make_shared(vector{"hash"}, vector{"hash"}, FunctionType::Location::SHA3)), make_shared("log0", - make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers(), - FunctionType::Location::LOG0)), + make_shared(vector{"hash"},vector{}, FunctionType::Location::LOG0)), make_shared("log1", - make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers(), - FunctionType::Location::LOG1)), + make_shared(vector{"hash", "hash"},vector{}, FunctionType::Location::LOG1)), make_shared("log2", - make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers(), - FunctionType::Location::LOG2)), + make_shared(vector{"hash", "hash", "hash"},vector{}, FunctionType::Location::LOG2)), make_shared("log3", - make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers(), - FunctionType::Location::LOG3)), + make_shared(vector{"hash", "hash", "hash", "hash"},vector{}, FunctionType::Location::LOG3)), make_shared("log4", - make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH), std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers(), - FunctionType::Location::LOG4)), + make_shared(vector{"hash", "hash", "hash", "hash", "hash"},vector{}, FunctionType::Location::LOG4)), make_shared("sha256", - make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - FunctionType::Location::SHA256)), + make_shared(vector{"hash"}, vector{"hash"}, FunctionType::Location::SHA256)), make_shared("ecrecover", - make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), - std::make_shared(8, IntegerType::Modifier::HASH), - std::make_shared(256, IntegerType::Modifier::HASH), - std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(0, IntegerType::Modifier::ADDRESS)}), - FunctionType::Location::ECRECOVER)), + make_shared(vector{"hash", "hash8", "hash", "hash"}, vector{"address"}, FunctionType::Location::ECRECOVER)), make_shared("ripemd160", - make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(160, IntegerType::Modifier::HASH)}), - FunctionType::Location::RIPEMD160))}) + make_shared(vector{"hash"}, vector{"hash160"}, FunctionType::Location::RIPEMD160))}) { } diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 6e3d04bc5..b283ca10e 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -700,24 +700,6 @@ Token::Value Scanner::scanNumber(char _charSeen) return Token::NUMBER; } - -// ---------------------------------------------------------------------------- -// Keyword Matcher - - -static Token::Value keywordOrIdentifierToken(string const& _input) -{ - // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored - // and keywords to be put inside the keywords variable. -#define KEYWORD(name, string, precedence) {string, Token::name}, -#define TOKEN(name, string, precedence) - static const map keywords({TOKEN_LIST(TOKEN, KEYWORD)}); -#undef KEYWORD -#undef TOKEN - auto it = keywords.find(_input); - return it == keywords.end() ? Token::IDENTIFIER : it->second; -} - Token::Value Scanner::scanIdentifierOrKeyword() { solAssert(isIdentifierStart(m_char), ""); @@ -727,7 +709,7 @@ Token::Value Scanner::scanIdentifierOrKeyword() while (isIdentifierPart(m_char)) addLiteralCharAndAdvance(); literal.complete(); - return keywordOrIdentifierToken(m_nextToken.literal); + return Token::fromIdentifierOrKeyword(m_nextToken.literal); } char CharStream::advanceAndGet(size_t _chars) diff --git a/libsolidity/Token.cpp b/libsolidity/Token.cpp index 093bd9c1d..7dc56c327 100644 --- a/libsolidity/Token.cpp +++ b/libsolidity/Token.cpp @@ -40,8 +40,11 @@ // You should have received a copy of the GNU General Public License // along with cpp-ethereum. If not, see . +#include #include +using namespace std; + namespace dev { namespace solidity @@ -77,6 +80,20 @@ char const Token::m_tokenType[] = { TOKEN_LIST(KT, KK) }; + +Token::Value Token::fromIdentifierOrKeyword(const std::string& _name) +{ + // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored + // and keywords to be put inside the keywords variable. +#define KEYWORD(name, string, precedence) {string, Token::name}, +#define TOKEN(name, string, precedence) + static const map keywords({TOKEN_LIST(TOKEN, KEYWORD)}); +#undef KEYWORD +#undef TOKEN + auto it = keywords.find(_name); + return it == keywords.end() ? Token::IDENTIFIER : it->second; +} + #undef KT #undef KK diff --git a/libsolidity/Token.h b/libsolidity/Token.h index f2ffd076a..2d4441d08 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -386,6 +386,8 @@ public: return m_precedence[tok]; } + static Token::Value fromIdentifierOrKeyword(std::string const& _name); + private: static char const* const m_name[NUM_TOKENS]; static char const* const m_string[NUM_TOKENS]; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index eda022ccb..b3eae2025 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -35,7 +35,7 @@ namespace solidity shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) { - solAssert(Token::isElementaryTypeName(_typeToken), ""); + solAssert(Token::isElementaryTypeName(_typeToken), "Elementary type name expected."); if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) { @@ -204,18 +204,12 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe } const MemberList IntegerType::AddressMemberList = - MemberList({{"balance", - make_shared(256)}, - {"callstring32", - make_shared(TypePointers({make_shared(32)}), - TypePointers(), FunctionType::Location::BARE)}, - {"callstring32string32", - make_shared(TypePointers({make_shared(32), - make_shared(32)}), - TypePointers(), FunctionType::Location::BARE)}, - {"send", - make_shared(TypePointers({make_shared(256)}), - TypePointers(), FunctionType::Location::SEND)}}); + MemberList({{"balance", make_shared(256)}, + {"callstring32", make_shared(vector{"string32"}, + vector{}, FunctionType::Location::BARE)}, + {"callstring32string32", make_shared(vector{"string32", "string32"}, + vector{}, FunctionType::Location::BARE)}, + {"send", make_shared(vector{"uint"}, vector{}, FunctionType::Location::SEND)}}); shared_ptr IntegerConstantType::fromLiteral(string const& _literal) { @@ -625,6 +619,15 @@ string FunctionType::getCanonicalSignature() const return ret + ")"; } +TypePointers FunctionType::parseElementaryTypeVector(vector const& _types) +{ + TypePointers pointers; + pointers.reserve(_types.size()); + for (string const& type: _types) + pointers.push_back(Type::fromElementaryTypeName(Token::fromIdentifierOrKeyword(type))); + return pointers; +} + bool MappingType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 335c58a31..031d45ea5 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -352,6 +352,10 @@ public: virtual Category getCategory() const override { return Category::FUNCTION; } explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); + FunctionType(std::vector const& _parameterTypes, + std::vector const& _returnParameterTypes, + Location _location = Location::INTERNAL): + FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), _location) {} FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, Location _location = Location::INTERNAL): m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), @@ -371,6 +375,8 @@ public: std::string getCanonicalSignature() const; private: + static TypePointers parseElementaryTypeVector(std::vector const& _types); + TypePointers m_parameterTypes; TypePointers m_returnParameterTypes; Location m_location; From 8d85b1035e72c4223869a66438e2cf3cc58f56f8 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 12 Jan 2015 12:59:43 +0100 Subject: [PATCH 550/588] renamed qethereum -> qwebthree, fixed #414 --- CMakeLists.txt | 2 +- alethzero/CMakeLists.txt | 2 +- alethzero/MainWin.h | 2 +- {libqethereum => libqwebthree}/CMakeLists.txt | 2 +- libqethereum/QEthereum.cpp => libqwebthree/QWebThree.cpp | 4 ++-- libqethereum/QEthereum.h => libqwebthree/QWebThree.h | 2 +- mix/CMakeLists.txt | 2 +- third/CMakeLists.txt | 2 +- third/MainWin.h | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) rename {libqethereum => libqwebthree}/CMakeLists.txt (98%) rename libqethereum/QEthereum.cpp => libqwebthree/QWebThree.cpp (99%) rename libqethereum/QEthereum.h => libqwebthree/QWebThree.h (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 221087884..6e5be63eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,7 @@ endif () if (NOT HEADLESS) add_subdirectory(libjsqrc) - add_subdirectory(libqethereum) + add_subdirectory(libqwebthree) add_subdirectory(alethzero) add_subdirectory(third) add_subdirectory(mix) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 8c8a37a42..219a8cb99 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -34,7 +34,7 @@ add_dependencies(${EXECUTABLE} BuildInfo.h) target_link_libraries(${EXECUTABLE} Qt5::Core) target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} qethereum) +target_link_libraries(${EXECUTABLE} qwebthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} ethcore) diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 52a71102d..18cf5113b 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include namespace Ui { diff --git a/libqethereum/CMakeLists.txt b/libqwebthree/CMakeLists.txt similarity index 98% rename from libqethereum/CMakeLists.txt rename to libqwebthree/CMakeLists.txt index 683bfec56..4de131ead 100644 --- a/libqethereum/CMakeLists.txt +++ b/libqwebthree/CMakeLists.txt @@ -15,7 +15,7 @@ aux_source_directory(. SRC_LIST) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(..) -set(EXECUTABLE qethereum) +set(EXECUTABLE qwebthree) file(GLOB HEADERS "*.h") diff --git a/libqethereum/QEthereum.cpp b/libqwebthree/QWebThree.cpp similarity index 99% rename from libqethereum/QEthereum.cpp rename to libqwebthree/QWebThree.cpp index daf773a22..6d47d0bd4 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqwebthree/QWebThree.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file QEthereum.cpp +/** @file QWebThree.cpp * @authors: * Gav Wood * Marek Kotewicz @@ -22,7 +22,7 @@ */ #include -#include "QEthereum.h" +#include "QWebThree.h" using namespace std; diff --git a/libqethereum/QEthereum.h b/libqwebthree/QWebThree.h similarity index 99% rename from libqethereum/QEthereum.h rename to libqwebthree/QWebThree.h index 49df0f703..b223d45d0 100644 --- a/libqethereum/QEthereum.h +++ b/libqwebthree/QWebThree.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file QEthereum.h +/** @file QWebThree.h * @authors: * Gav Wood * Marek Kotewicz diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index 555f6290f..e13504ece 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -27,7 +27,7 @@ eth_add_executable(${EXECUTABLE} target_link_libraries(${EXECUTABLE} Qt5::Core) target_link_libraries(${EXECUTABLE} Qt5::Gui) target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} qethereum) +target_link_libraries(${EXECUTABLE} qwebthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} ethcore) diff --git a/third/CMakeLists.txt b/third/CMakeLists.txt index c9c95cf33..4b83b4fa5 100644 --- a/third/CMakeLists.txt +++ b/third/CMakeLists.txt @@ -33,7 +33,7 @@ add_dependencies(${EXECUTABLE} BuildInfo.h) target_link_libraries(${EXECUTABLE} Qt5::Core) target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} qethereum) +target_link_libraries(${EXECUTABLE} qwebthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} ethcore) diff --git a/third/MainWin.h b/third/MainWin.h index 3b4acc3a8..0bd75d5de 100644 --- a/third/MainWin.h +++ b/third/MainWin.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include namespace Ui { class Main; From 4f52200c7e514b8022b823d3c45af91aa1ea06c5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 12 Jan 2015 13:13:45 +0100 Subject: [PATCH 551/588] fixed style and build --- libweb3jsonrpc/WebThreeStubServerBase.h | 2 +- mix/ClientModel.cpp | 1 - mix/CodeEditorExtensionManager.cpp | 10 ++-------- mix/CodeEditorExtensionManager.h | 1 - mix/ContractCallDataEncoder.cpp | 4 ++-- 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 451e2f9ee..168ab288a 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -121,7 +121,7 @@ public: std::map const& ids() const { return m_ids; } protected: - virtual bool authenticate(dev::TransactionSkeleton const& _t) const = 0; + virtual bool authenticate(dev::TransactionSkeleton const& _t) const; protected: virtual dev::eth::Interface* client() = 0; diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 9a90d52e3..bcbed1fac 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -214,7 +214,6 @@ ExecutionResult ClientModel::deployContract(bytes const& _code) ExecutionResult ClientModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) { - //bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; m_client->transact(m_client->userAccount().secret(), _tr.value, _contract, _data, _tr.gas, _tr.gasPrice); ExecutionResult r = m_client->lastExecutionResult(); r.contractAddress = _contract; diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index f5ceb333e..a123c3b7a 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -88,21 +88,15 @@ void CodeEditorExtensionManager::initExtension(std::shared_ptr _ext) m_features.append(_ext); } -void CodeEditorExtensionManager::onCodeChange() -{ -// m_appContext->codeModel()->updateFormatting(m_doc); //update old formatting -// m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); -} - void CodeEditorExtensionManager::applyCodeHighlight() { -// m_appContext->codeModel()->updateFormatting(m_doc); + //TODO: reimplement } void CodeEditorExtensionManager::setRightTabView(QQuickItem* _tabView) { m_rightTabView = _tabView; - initExtensions(); //TODO: this is not the right place for it + initExtensions(); //TODO: move this to a proper place } void CodeEditorExtensionManager::setTabView(QQuickItem* _tabView) diff --git a/mix/CodeEditorExtensionManager.h b/mix/CodeEditorExtensionManager.h index e910b62d3..2f2a315b9 100644 --- a/mix/CodeEditorExtensionManager.h +++ b/mix/CodeEditorExtensionManager.h @@ -59,7 +59,6 @@ public: void setRightTabView(QQuickItem*); private slots: - void onCodeChange(); void applyCodeHighlight(); private: diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 0e628c3c0..7a38db22b 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -40,8 +40,8 @@ bytes ContractCallDataEncoder::encodedData() void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) { - bytes i = _function->hash().asBytes(); - m_encodedData.insert(m_encodedData.end(), i.begin(), i.end()); + bytes hash = _function->hash().asBytes(); + m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end()); } void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, bool _value) From 18f7839fd599f33fc39eaf550d5f031f9afb3235 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 12 Jan 2015 13:29:16 +0100 Subject: [PATCH 552/588] Define strings = vector --- libdevcore/Common.h | 3 +++ libsolidity/GlobalContext.cpp | 20 ++++++++++---------- libsolidity/Types.cpp | 12 ++++++------ libsolidity/Types.h | 8 ++++---- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 0967596e2..9fefea45a 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -80,6 +80,9 @@ using StringMap = std::map; using u256Map = std::map; using HexMap = std::map; +// String types. +using strings = std::vector; + // Fixed-length string types. using string32 = std::array; diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index 26a52fd10..92ca9548a 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -38,25 +38,25 @@ m_magicVariables(vector>{make_shared< make_shared("msg", make_shared(MagicType::Kind::MSG)), make_shared("tx", make_shared(MagicType::Kind::TX)), make_shared("suicide", - make_shared(vector{"address"}, vector{}, FunctionType::Location::SUICIDE)), + make_shared(strings{"address"}, strings{}, FunctionType::Location::SUICIDE)), make_shared("sha3", - make_shared(vector{"hash"}, vector{"hash"}, FunctionType::Location::SHA3)), + make_shared(strings{"hash"}, strings{"hash"}, FunctionType::Location::SHA3)), make_shared("log0", - make_shared(vector{"hash"},vector{}, FunctionType::Location::LOG0)), + make_shared(strings{"hash"},strings{}, FunctionType::Location::LOG0)), make_shared("log1", - make_shared(vector{"hash", "hash"},vector{}, FunctionType::Location::LOG1)), + make_shared(strings{"hash", "hash"},strings{}, FunctionType::Location::LOG1)), make_shared("log2", - make_shared(vector{"hash", "hash", "hash"},vector{}, FunctionType::Location::LOG2)), + make_shared(strings{"hash", "hash", "hash"},strings{}, FunctionType::Location::LOG2)), make_shared("log3", - make_shared(vector{"hash", "hash", "hash", "hash"},vector{}, FunctionType::Location::LOG3)), + make_shared(strings{"hash", "hash", "hash", "hash"},strings{}, FunctionType::Location::LOG3)), make_shared("log4", - make_shared(vector{"hash", "hash", "hash", "hash", "hash"},vector{}, FunctionType::Location::LOG4)), + make_shared(strings{"hash", "hash", "hash", "hash", "hash"},strings{}, FunctionType::Location::LOG4)), make_shared("sha256", - make_shared(vector{"hash"}, vector{"hash"}, FunctionType::Location::SHA256)), + make_shared(strings{"hash"}, strings{"hash"}, FunctionType::Location::SHA256)), make_shared("ecrecover", - make_shared(vector{"hash", "hash8", "hash", "hash"}, vector{"address"}, FunctionType::Location::ECRECOVER)), + make_shared(strings{"hash", "hash8", "hash", "hash"}, strings{"address"}, FunctionType::Location::ECRECOVER)), make_shared("ripemd160", - make_shared(vector{"hash"}, vector{"hash160"}, FunctionType::Location::RIPEMD160))}) + make_shared(strings{"hash"}, strings{"hash160"}, FunctionType::Location::RIPEMD160))}) { } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index b3eae2025..7ca1dc6d5 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -205,11 +205,11 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe const MemberList IntegerType::AddressMemberList = MemberList({{"balance", make_shared(256)}, - {"callstring32", make_shared(vector{"string32"}, - vector{}, FunctionType::Location::BARE)}, - {"callstring32string32", make_shared(vector{"string32", "string32"}, - vector{}, FunctionType::Location::BARE)}, - {"send", make_shared(vector{"uint"}, vector{}, FunctionType::Location::SEND)}}); + {"callstring32", make_shared(strings{"string32"}, strings{}, + FunctionType::Location::BARE)}, + {"callstring32string32", make_shared(strings{"string32", "string32"}, + strings{}, FunctionType::Location::BARE)}, + {"send", make_shared(strings{"uint"}, strings{}, FunctionType::Location::SEND)}}); shared_ptr IntegerConstantType::fromLiteral(string const& _literal) { @@ -619,7 +619,7 @@ string FunctionType::getCanonicalSignature() const return ret + ")"; } -TypePointers FunctionType::parseElementaryTypeVector(vector const& _types) +TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) { TypePointers pointers; pointers.reserve(_types.size()); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 031d45ea5..deabe1160 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -352,10 +352,10 @@ public: virtual Category getCategory() const override { return Category::FUNCTION; } explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); - FunctionType(std::vector const& _parameterTypes, - std::vector const& _returnParameterTypes, + FunctionType(strings const& _parameterTypes, strings const& _returnParameterTypes, Location _location = Location::INTERNAL): - FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), _location) {} + FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), + _location) {} FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, Location _location = Location::INTERNAL): m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), @@ -375,7 +375,7 @@ public: std::string getCanonicalSignature() const; private: - static TypePointers parseElementaryTypeVector(std::vector const& _types); + static TypePointers parseElementaryTypeVector(strings const& _types); TypePointers m_parameterTypes; TypePointers m_returnParameterTypes; From 28aefa7ddb042e9c33b0997a45ba6ea9b5d2dfaa Mon Sep 17 00:00:00 2001 From: "U-SVZ13\\Arkady" Date: Mon, 12 Jan 2015 13:32:53 +0100 Subject: [PATCH 553/588] fixed msvc build --- libweb3jsonrpc/WebThreeStubServerBase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 168ab288a..24a6a9962 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -36,7 +36,7 @@ namespace dev { class WebThreeNetworkFace; class KeyPair; -class TransactionSkeleton; +struct TransactionSkeleton; namespace eth { class Interface; 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 554/588] 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 5a44a670aa7a272c440ee85361589c9c8023c9f8 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 12 Jan 2015 15:29:44 +0100 Subject: [PATCH 555/588] Fixing bug where empty tagless docstring in Natspec would result in infinite loop --- libsolidity/InterfaceHandler.cpp | 7 ++++++- test/SolidityNatspecJSON.cpp | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 4ce6e989a..a5c6f4a1d 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -349,8 +349,13 @@ void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _ } else if (m_lastTag != DocTagType::NONE) // continuation of the previous tag currPos = appendDocTag(currPos, end, _owner); - else if (currPos != end) // skip the line if a newline was found + else if (currPos != end) + { + if (nlPos == end) //end of text + return; + // else skip the line if a newline was found currPos = nlPos + 1; + } } } diff --git a/test/SolidityNatspecJSON.cpp b/test/SolidityNatspecJSON.cpp index f6a33247a..7edb97a7b 100644 --- a/test/SolidityNatspecJSON.cpp +++ b/test/SolidityNatspecJSON.cpp @@ -510,6 +510,19 @@ BOOST_AUTO_TEST_CASE(dev_title_at_function_error) BOOST_CHECK_THROW(checkNatspec(sourceCode, natspec, false), DocstringParsingError); } +// test for bug where having no tags in docstring would cause infinite loop +BOOST_AUTO_TEST_CASE(natspec_no_tags) +{ + char const* sourceCode = "contract test {\n" + " /// I do something awesome\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{\"methods\": {}}"; + + checkNatspec(sourceCode, natspec, false); +} + BOOST_AUTO_TEST_SUITE_END() } From 070d1d800c8f830f095b0c1fd099f17e09865446 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 15:42:28 +0100 Subject: [PATCH 556/588] 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 557/588] 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 558/588] 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 559/588] 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 560/588] 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 b0c94c62e3eb1bbc1dbecb1f05116e9afaf601ae Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 12 Jan 2015 17:17:05 +0100 Subject: [PATCH 561/588] 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 562/588] 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 563/588] 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 564/588] 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 565/588] 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 566/588] 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 567/588] 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 568/588] 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 569/588] 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 570/588] 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 571/588] 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 572/588] 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 573/588] 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 574/588] 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 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 575/588] 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 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 576/588] 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 577/588] 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 607c71e785b78306455d8ac0047ea499736fc2ba Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 13 Jan 2015 17:58:14 +0100 Subject: [PATCH 578/588] 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 579/588] 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 580/588] 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 581/588] 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 5ff846e1c76347f1b309f7aecb23f9bf9cb85949 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 14 Jan 2015 09:39:21 +0100 Subject: [PATCH 582/588] 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 e16d88c894aca5aae90bfc094906d2c138534296 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 14 Jan 2015 10:16:58 +0100 Subject: [PATCH 583/588] 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 584/588] 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 585/588] 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 586/588] 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 587/588] 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 588/588] 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; };