From 2458aaae9fc525daa958a757a922ea662fba9cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 13 Jan 2015 11:51:57 +0100 Subject: [PATCH 01/40] Fix evmjit standalone compilation --- .gitignore | 1 + CMakeLists.txt | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..84c048a73 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 18601b921..856cb56c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,11 @@ project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +else () + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") +endif() + # LLVM if(LLVM_DIR) # local LLVM build find_package(LLVM REQUIRED CONFIG) @@ -18,11 +23,18 @@ else() 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") + add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS) endif() # Boost find_package(Boost REQUIRED) add_subdirectory(libevmjit) -add_subdirectory(libevmjit-cpp) -add_subdirectory(evmcc) + +if(EVMJIT_CPP) + add_subdirectory(libevmjit-cpp) +endif() + +if(EVMJIT_TOOLS) + add_subdirectory(evmcc) +endif() From 92f42e98cf97a9f677f87375536b59baa7777331 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 02/40] Allways generate stack_get() call to detect stack underflow cases --- libevmjit/BasicBlock.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index dda0fbc36..5868c0f43 100644 --- a/libevmjit/BasicBlock.cpp +++ b/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 b1e8299db0f509efbb57d5716e0e6c8e2d6c4051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 13 Jan 2015 17:19:49 +0100 Subject: [PATCH 03/40] Fix some cpptest issues --- libevmjit/BasicBlock.h | 2 +- libevmjit/Runtime.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 7a5364a4e..3591a6f54 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -57,7 +57,7 @@ public: explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); BasicBlock(const BasicBlock&) = delete; - void operator=(const BasicBlock&) = delete; + BasicBlock& operator=(const BasicBlock&) = delete; llvm::BasicBlock* llvm() { return m_llvmBB; } diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 8cc5b7968..f97efa128 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -34,7 +34,7 @@ public: Runtime(RuntimeData* _data, Env* _env); Runtime(const Runtime&) = delete; - void operator=(const Runtime&) = delete; + Runtime& operator=(const Runtime&) = delete; StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } From 5b9777728ef5e7718f19ec70a64b2f5f5bc15393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 13 Jan 2015 17:19:49 +0100 Subject: [PATCH 04/40] Fix some cpptest issues --- evmjit/libevmjit/BasicBlock.h | 2 +- evmjit/libevmjit/Runtime.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index 7a5364a4e..3591a6f54 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -57,7 +57,7 @@ public: explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); BasicBlock(const BasicBlock&) = delete; - void operator=(const BasicBlock&) = delete; + BasicBlock& operator=(const BasicBlock&) = delete; llvm::BasicBlock* llvm() { return m_llvmBB; } diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h index 8cc5b7968..f97efa128 100644 --- a/evmjit/libevmjit/Runtime.h +++ b/evmjit/libevmjit/Runtime.h @@ -34,7 +34,7 @@ public: Runtime(RuntimeData* _data, Env* _env); Runtime(const Runtime&) = delete; - void operator=(const Runtime&) = delete; + Runtime& operator=(const Runtime&) = delete; StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } From 5077ec4624c417ef47828abf50aae8aea39297e1 Mon Sep 17 00:00:00 2001 From: caktux Date: Tue, 13 Jan 2015 12:49:53 -0500 Subject: [PATCH 05/40] apply fix for #597 to neth --- neth/main.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/neth/main.cpp b/neth/main.cpp index 1252b205b..638e9c624 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -379,13 +379,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 1861843a24d1a4aa62e20a3cfdab383131a4ebfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 14 Jan 2015 09:08:17 +0100 Subject: [PATCH 06/40] EVM JIT called from Go, env_sha3 callback works --- libevmjit/CMakeLists.txt | 3 +- libevmjit/ExecutionEngine.cpp | 2 +- libevmjit/interface.cpp | 63 ++++++++++++++++++++++++++ libevmjit/{interface.c => interface.h} | 17 ++++++- 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 libevmjit/interface.cpp rename libevmjit/{interface.c => interface.h} (87%) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 7c35169a7..28b501ee3 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -10,7 +10,8 @@ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) endif () -add_library(${TARGET_NAME} ${SOURCES} ${HEADERS}) +link_directories(/usr/lib/llvm-3.5/lib) +add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 7e99932c3..71142fbee 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -49,7 +49,7 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) std::string codeHash(bytes const& _code) { - std::array binHash; + std::array binHash; env_sha3(_code.data(), _code.size(), &binHash); std::ostringstream os; diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp new file mode 100644 index 000000000..ec7d07b33 --- /dev/null +++ b/libevmjit/interface.cpp @@ -0,0 +1,63 @@ +#include "interface.h" +#include +#include "ExecutionEngine.h" + +extern "C" +{ + +int evmjit_run() +{ + using namespace dev::eth::jit; + + ExecutionEngine engine; + u256 gas = 100000; + + bytes bytecode = { 0x60, 0x01 }; + + // Create random runtime data + RuntimeData data; + data.set(RuntimeData::Gas, gas); + data.set(RuntimeData::Address, 0); + data.set(RuntimeData::Caller, 0); + data.set(RuntimeData::Origin, 0); + data.set(RuntimeData::CallValue, 0xabcd); + data.set(RuntimeData::CallDataSize, 3); + data.set(RuntimeData::GasPrice, 1003); + data.set(RuntimeData::CoinBase, 0); + 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); +} + +// 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*) +{ + printf("EVM JIT create"); + + int* a = nullptr; + *a = 1; + + return nullptr; +} + +evm_jit_return_code evm_jit_execute(evm_jit* _jit); + +void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); + +void evm_jit_destroy(evm_jit* _jit); + +} diff --git a/libevmjit/interface.c b/libevmjit/interface.h similarity index 87% rename from libevmjit/interface.c rename to libevmjit/interface.h index 47589578b..0e3076283 100644 --- a/libevmjit/interface.c +++ b/libevmjit/interface.h @@ -1,4 +1,10 @@ -#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int evmjit_run(); // JIT object opaque type typedef struct evm_jit evm_jit; @@ -9,6 +15,11 @@ typedef int evm_jit_return_code; // Host-endian 256-bit integer type typedef struct i256 i256; +struct h256 +{ + char b[33]; +}; + // Big-endian right aligned 256-bit hash typedef struct h256 h256; @@ -28,3 +39,7 @@ 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); + +#ifdef __cplusplus +} +#endif From 4101e680c814c0faadaa2de1e228e56a6acea3fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 14 Jan 2015 13:49:56 +0100 Subject: [PATCH 07/40] Changes in EVM JIT C interface --- libevmjit/interface.cpp | 38 ++++++++++++-------------------------- libevmjit/interface.h | 4 ++-- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp index ec7d07b33..6a729f3d0 100644 --- a/libevmjit/interface.cpp +++ b/libevmjit/interface.cpp @@ -5,36 +5,22 @@ extern "C" { -int evmjit_run() +int evmjit_run(void* _data, void* _env) { using namespace dev::eth::jit; + auto data = static_cast(_data); + + std::cerr << "GAS: " << data->elems[RuntimeData::Gas].a << "\n"; + ExecutionEngine engine; - u256 gas = 100000; - - bytes bytecode = { 0x60, 0x01 }; - - // Create random runtime data - RuntimeData data; - data.set(RuntimeData::Gas, gas); - data.set(RuntimeData::Address, 0); - data.set(RuntimeData::Caller, 0); - data.set(RuntimeData::Origin, 0); - data.set(RuntimeData::CallValue, 0xabcd); - data.set(RuntimeData::CallDataSize, 3); - data.set(RuntimeData::GasPrice, 1003); - data.set(RuntimeData::CoinBase, 0); - 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); + + auto codePtr = data->code; + auto codeSize = data->elems[RuntimeData::CodeSize].a; + bytes bytecode; + bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); + + auto result = engine.run(bytecode, data, static_cast(_env)); return static_cast(result); } diff --git a/libevmjit/interface.h b/libevmjit/interface.h index 0e3076283..1515fed86 100644 --- a/libevmjit/interface.h +++ b/libevmjit/interface.h @@ -4,7 +4,7 @@ extern "C" { #endif -int evmjit_run(); +int evmjit_run(void* _data, void* _env); // JIT object opaque type typedef struct evm_jit evm_jit; @@ -15,7 +15,7 @@ typedef int evm_jit_return_code; // Host-endian 256-bit integer type typedef struct i256 i256; -struct h256 +struct i256 { char b[33]; }; From 3e166f15fc17c16cf13001e93a184019880dd8b8 Mon Sep 17 00:00:00 2001 From: liana Date: Wed, 14 Jan 2015 13:52:03 +0100 Subject: [PATCH 08/40] - added functionality to set values to 0 when deleting structure(not for mapping) - added unit test Made some changes after Christian`s review on pull request - remove/edit comments - BoolType and ContractType return VoidType after delete - fixed constructor_arguments test - fixed set to 0 when deleting variable from stack - changed test case to test that --- libsolidity/ExpressionCompiler.cpp | 89 ++++++++++++++++++++++-------- libsolidity/ExpressionCompiler.h | 10 ++-- libsolidity/Types.cpp | 27 ++++++--- libsolidity/Types.h | 13 +---- test/SolidityEndToEndTest.cpp | 62 +++++++++++++++++++++ 5 files changed, 155 insertions(+), 46 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 1c02f4f32..c8b7f3508 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -94,13 +94,8 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) m_context << eth::Instruction::NOT; break; case Token::DELETE: // delete - // @todo semantics change for complex types solAssert(m_currentLValue.isValid(), "LValue not retrieved."); - - m_context << u256(0); - if (m_currentLValue.storesReferenceOnStack()) - m_context << eth::Instruction::SWAP1; - m_currentLValue.storeValue(_unaryOperation); + m_currentLValue.setToZero(_unaryOperation); m_currentLValue.reset(); break; case Token::INC: // ++ (pre- or postfix) @@ -696,9 +691,14 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, unsigned _baseStackOffset): - m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset), - m_stackSize(_dataType.getSizeOnStack()) + m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset) { + //@todo change the type cast for arrays + solAssert(_dataType.getStorageSize() <= numeric_limits::max(), "The storage size of " +_dataType.toString() + " should fit in unsigned"); + if (m_type == STORAGE) + m_size = unsigned(_dataType.getStorageSize()); + else + m_size = unsigned(_dataType.getSizeOnStack()); } void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bool _remove) const @@ -711,7 +711,7 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Stack too deep.")); - for (unsigned i = 0; i < m_stackSize; ++i) + for (unsigned i = 0; i < m_size; ++i) *m_context << eth::dupInstruction(stackPos + 1); break; } @@ -720,14 +720,14 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo break; // no distinction between value and reference for non-value types if (!_remove) *m_context << eth::Instruction::DUP1; - if (m_stackSize == 1) + if (m_size == 1) *m_context << eth::Instruction::SLOAD; else - for (unsigned i = 0; i < m_stackSize; ++i) + for (unsigned i = 0; i < m_size; ++i) { *m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1; - if (i + 1 < m_stackSize) - *m_context << u256(1) << eth::Instruction::ADD; + if (i + 1 < m_size) + *m_context << u256(1) << eth::Instruction::ADD; else *m_context << eth::Instruction::POP; } @@ -751,12 +751,12 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool { case STACK: { - unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_stackSize + 1; + unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_size + 1; if (stackDiff > 16) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Stack too deep.")); else if (stackDiff > 0) - for (unsigned i = 0; i < m_stackSize; ++i) + for (unsigned i = 0; i < m_size; ++i) *m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP; if (!_move) retrieveValue(_expression); @@ -768,17 +768,17 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool // stack layout: value value ... value ref if (!_move) // copy values { - if (m_stackSize + 1 > 16) + if (m_size + 1 > 16) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Stack too deep.")); - for (unsigned i = 0; i < m_stackSize; ++i) - *m_context << eth::dupInstruction(m_stackSize + 1) << eth::Instruction::SWAP1; + for (unsigned i = 0; i < m_size; ++i) + *m_context << eth::dupInstruction(m_size + 1) << eth::Instruction::SWAP1; } - if (m_stackSize > 0) // store high index value first - *m_context << u256(m_stackSize - 1) << eth::Instruction::ADD; - for (unsigned i = 0; i < m_stackSize; ++i) + if (m_size > 0) // store high index value first + *m_context << u256(m_size - 1) << eth::Instruction::ADD; + for (unsigned i = 0; i < m_size; ++i) { - if (i + 1 >= m_stackSize) + if (i + 1 >= m_size) *m_context << eth::Instruction::SSTORE; else // v v ... v v r+x @@ -800,6 +800,47 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool } } +void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const +{ + switch (m_type) + { + case STACK: + { + unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); + if (stackDiff > 16) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + else if (stackDiff > 0) + for (unsigned i = 0; i < m_size; ++i) + *m_context << u256(0) << eth::swapInstruction(m_size - i) << eth::Instruction::POP; + break; + } + case LValue::STORAGE: + if (m_size == 0) + *m_context << eth::Instruction::POP; + for (unsigned i = 0; i < m_size; ++i) + { + if (i + 1 >= m_size) + *m_context << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; + else + *m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE + << u256(1) << eth::Instruction::ADD; + } + break; + case LValue::MEMORY: + if (!_expression.getType()->isValueType()) + break; // no distinction between value and reference for non-value types + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Location type not yet implemented.")); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Unsupported location type.")); + break; + } + +} + void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression const& _expression) { if (!_expression.lvalueRequested()) @@ -811,15 +852,17 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration) { - m_stackSize = _identifier.getType()->getSizeOnStack(); if (m_context->isLocalVariable(&_declaration)) { m_type = STACK; + m_size = _identifier.getType()->getSizeOnStack(); m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } else if (m_context->isStateVariable(&_declaration)) { m_type = STORAGE; + solAssert(_identifier.getType()->getStorageSize() <= numeric_limits::max(), "The storage size of " + _identifier.getType()->toString() + " should fit in unsigned"); + m_size = unsigned(_identifier.getType()->getStorageSize()); *m_context << m_context->getStorageLocationOfVariable(_declaration); } else diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 98f58c854..665ee3c9c 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -119,7 +119,7 @@ private: /// Set type according to the declaration and retrieve the reference. /// @a _expression is the current expression void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); - void reset() { m_type = NONE; m_baseStackOffset = 0; } + void reset() { m_type = NONE; m_baseStackOffset = 0; m_size = 0; } bool isValid() const { return m_type != NONE; } bool isInOnStack() const { return m_type == STACK; } @@ -138,7 +138,9 @@ private: /// Also removes the stored value from the stack if @a _move is /// true. @a _expression is the current expression, used for error reporting. void storeValue(Expression const& _expression, bool _move = false) const; - + /// Stores zero in the lvalue. + /// @a _expression is the current expression, used for error reporting. + void setToZero(Expression const& _expression) const; /// Convenience function to convert the stored reference to a value and reset type to NONE if /// the reference was not requested by @a _expression. void retrieveValueIfLValueNotRequested(Expression const& _expression); @@ -149,8 +151,8 @@ private: /// If m_type is STACK, this is base stack offset (@see /// CompilerContext::getBaseStackOffsetOfVariable) of a local variable. unsigned m_baseStackOffset = 0; - /// Size of the value of this lvalue on the stack. - unsigned m_stackSize = 0; + /// Size of the value of this lvalue on the stack or the storage. + unsigned m_size = 0; }; bool m_optimize; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7ca1dc6d5..079e79b8f 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -147,7 +147,7 @@ TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const { // "delete" is ok for all integer types if (_operator == Token::DELETE) - return shared_from_this(); + return make_shared(); // no further unary operators for addresses else if (isAddress()) return TypePointer(); @@ -408,6 +408,13 @@ u256 BoolType::literalValue(Literal const* _literal) const BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal.")); } +TypePointer BoolType::unaryOperatorResult(Token::Value _operator) const +{ + if (_operator == Token::DELETE) + return make_shared(); + return (_operator == Token::NOT) ? shared_from_this() : TypePointer(); +} + TypePointer BoolType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { if (getCategory() != _other->getCategory()) @@ -432,6 +439,11 @@ bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const return isImplicitlyConvertibleTo(_convertTo) || _convertTo.getCategory() == Category::INTEGER; } +TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const +{ + return _operator == Token::DELETE ? make_shared() : TypePointer(); +} + bool ContractType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) @@ -440,14 +452,6 @@ bool ContractType::operator==(Type const& _other) const return other.m_contract == m_contract; } -u256 ContractType::getStorageSize() const -{ - u256 size = 0; - for (ASTPointer const& variable: m_contract.getStateVariables()) - size += variable->getType()->getStorageSize(); - return max(1, size); -} - string ContractType::toString() const { return "contract " + m_contract.getName(); @@ -491,6 +495,11 @@ u256 ContractType::getFunctionIdentifier(string const& _functionName) const return Invalid256; } +TypePointer StructType::unaryOperatorResult(Token::Value _operator) const +{ + return _operator == Token::DELETE ? make_shared() : TypePointer(); +} + bool StructType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 1ccdd706a..3d9b45e2d 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -259,10 +259,7 @@ public: BoolType() {} virtual Category getCategory() const { return Category::BOOL; } virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - virtual TypePointer unaryOperatorResult(Token::Value _operator) const override - { - return (_operator == Token::NOT || _operator == Token::DELETE) ? shared_from_this() : TypePointer(); - } + virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; virtual unsigned getCalldataEncodedSize() const { return 1; } @@ -284,8 +281,8 @@ public: 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 TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(Type const& _other) const override; - virtual u256 getStorageSize() const override; virtual bool isValueType() const override { return true; } virtual std::string toString() const override; @@ -315,11 +312,7 @@ class StructType: public Type public: virtual Category getCategory() const override { return Category::STRUCT; } StructType(StructDefinition const& _struct): m_struct(_struct) {} - virtual TypePointer unaryOperatorResult(Token::Value _operator) const override - { - return _operator == Token::DELETE ? shared_from_this() : TypePointer(); - } - + virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(Type const& _other) const override; virtual u256 getStorageSize() const override; virtual bool canLiveOutsideStorage() const override; diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 9543497a7..a733c2c43 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -772,6 +772,67 @@ BOOST_AUTO_TEST_CASE(struct_reference) BOOST_CHECK(callContractFunction("check()") == encodeArgs(true)); } +BOOST_AUTO_TEST_CASE(deleteStruct) +{ + char const* sourceCode = R"( + contract test { + struct topStruct { + nestedStruct nstr; + emptyStruct empty; + uint topValue; + mapping (uint => uint) topMapping; + } + uint toDelete; + topStruct str; + struct nestedStruct { + uint nestedValue; + mapping (uint => bool) nestedMapping; + } + struct emptyStruct{ + } + function test(){ + toDelete = 5; + str.topValue = 1; + str.topMapping[0] = 1; + str.topMapping[1] = 2; + + str.nstr.nestedValue = 2; + str.nstr.nestedMapping[0] = true; + str.nstr.nestedMapping[1] = false; + uint v = 5; + delete v; + delete str; + delete toDelete; + } + function getToDelete() returns (uint res){ + res = toDelete; + } + function getTopValue() returns(uint topValue){ + topValue = str.topValue; + } + function getNestedValue() returns(uint nestedValue){ + nestedValue = str.nstr.nestedValue; + } + function getTopMapping(uint index) returns(uint ret) { + ret = str.topMapping[index]; + } + function getNestedMapping(uint index) returns(bool ret) { + return str.nstr.nestedMapping[index]; + } + })"; + + compileAndRun(sourceCode); + + BOOST_CHECK(callContractFunction("getToDelete()") == encodeArgs(0)); + BOOST_CHECK(callContractFunction("getTopValue()") == encodeArgs(0)); + BOOST_CHECK(callContractFunction("getNestedValue()") == encodeArgs(0)); + // mapping values should be the same + BOOST_CHECK(callContractFunction("getTopMapping(uint256)", 0) == encodeArgs(1)); + BOOST_CHECK(callContractFunction("getTopMapping(uint256)", 1) == encodeArgs(2)); + BOOST_CHECK(callContractFunction("getNestedMapping(uint256)", 0) == encodeArgs(true)); + BOOST_CHECK(callContractFunction("getNestedMapping(uint256)", 1) == encodeArgs(false)); +} + BOOST_AUTO_TEST_CASE(constructor) { char const* sourceCode = "contract test {\n" @@ -1243,6 +1304,7 @@ BOOST_AUTO_TEST_CASE(constructor_arguments) contract Helper { string3 name; bool flag; + function Helper(string3 x, bool f) { name = x; flag = f; From 313b77fabd7b2f418ec18320b179d82bd06f06b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 15 Jan 2015 14:21:29 +0100 Subject: [PATCH 09/40] Allow undefined symbols in shared library on OSX --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 856cb56c2..acb113207 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,10 @@ else () set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") endif() +if(APPLE) + set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") +endif() + # LLVM if(LLVM_DIR) # local LLVM build find_package(LLVM REQUIRED CONFIG) From 70d02b1d661b4c057f53bb1c5ca563e289c80dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 15 Jan 2015 16:27:57 +0100 Subject: [PATCH 10/40] RETURN implementation: JIT returns data --- libevmjit/interface.cpp | 39 ++++++++++++--------------------------- libevmjit/interface.h | 11 ++++++++++- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp index 6a729f3d0..eef92d00f 100644 --- a/libevmjit/interface.cpp +++ b/libevmjit/interface.cpp @@ -5,14 +5,12 @@ extern "C" { -int evmjit_run(void* _data, void* _env) +evmjit_result evmjit_run(void* _data, void* _env) { using namespace dev::eth::jit; auto data = static_cast(_data); - std::cerr << "GAS: " << data->elems[RuntimeData::Gas].a << "\n"; - ExecutionEngine engine; auto codePtr = data->code; @@ -20,30 +18,17 @@ int evmjit_run(void* _data, void* _env) bytes bytecode; bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); - auto result = engine.run(bytecode, data, static_cast(_env)); - return static_cast(result); -} - -// 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*) -{ - printf("EVM JIT create"); - - int* a = nullptr; - *a = 1; - - return nullptr; + auto returnCode = engine.run(bytecode, data, static_cast(_env)); + evmjit_result result = {static_cast(returnCode), 0, nullptr}; + if (returnCode == ReturnCode::Return && !engine.returnData.empty()) + { + // TODO: Optimized returning data. Allocating memory on client side by callback function might be a good idea + result.returnDataSize = engine.returnData.size(); + result.returnData = std::malloc(result.returnDataSize); + std::memcpy(result.returnData, engine.returnData.data(), result.returnDataSize); + } + + return result; } -evm_jit_return_code evm_jit_execute(evm_jit* _jit); - -void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); - -void evm_jit_destroy(evm_jit* _jit); - } diff --git a/libevmjit/interface.h b/libevmjit/interface.h index 1515fed86..5d9307ab2 100644 --- a/libevmjit/interface.h +++ b/libevmjit/interface.h @@ -1,10 +1,19 @@ #include +#include #ifdef __cplusplus extern "C" { #endif -int evmjit_run(void* _data, void* _env); +typedef struct evmjit_result +{ + int32_t returnCode; + uint64_t returnDataSize; + void* returnData; + +} evmjit_result; + +evmjit_result evmjit_run(void* _data, void* _env); // JIT object opaque type typedef struct evm_jit evm_jit; From ddd1438a2c5d3026c5aacd9204fd29bd1acb95b0 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 5 Jan 2015 15:46:40 +0100 Subject: [PATCH 11/40] Preparing the ground for AST outputing to JSON --- libsolidity/ASTJsonConverter.cpp | 490 +++++++++++++++++++++++++++++++ libsolidity/ASTJsonConverter.h | 127 ++++++++ solc/CommandLineInterface.cpp | 62 +++- solc/CommandLineInterface.h | 1 + 4 files changed, 671 insertions(+), 9 deletions(-) create mode 100644 libsolidity/ASTJsonConverter.cpp create mode 100644 libsolidity/ASTJsonConverter.h diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp new file mode 100644 index 000000000..82495dec0 --- /dev/null +++ b/libsolidity/ASTJsonConverter.cpp @@ -0,0 +1,490 @@ +/* + 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 . +*/ +/** + * @author Lefteris + * @date 2015 + * Converts the AST into json format + */ + +#include +#include + +using namespace std; + +namespace dev +{ +namespace solidity +{ + +void ASTJsonConverter::addJsonNode(string const& _typeName, + initializer_list> _list) +{ + Json::Value node; + Json::Value attrs; + + node["type"] = _typeName; + for (auto &e: _list) + attrs[e.first] = e.second; + node["attributes"] = attrs; + + m_childrenPtr->append(node); +} + +ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast) +{ + Json::Value attrs; + Json::Value children; + + m_astJson["type"] = "root"; + attrs["name"] = "nameoffile"; //TODO + m_astJson["attributes"] = attrs; + m_astJson["children"] = children; + m_childrenPtr = &m_astJson["children"]; +} + +void ASTJsonConverter::print(ostream& _stream) +{ + m_ast->accept(*this); + _stream << m_astJson; +} + + +bool ASTJsonConverter::visit(ImportDirective const& _node) +{ + addJsonNode("import", { make_pair("file", _node.getIdentifier())}); + return goDeeper(); +} + +bool ASTJsonConverter::visit(ContractDefinition const& _node) +{ + // writeLine("ContractDefinition \"" + _node.getName() + "\""); + // printSourcePart(_node); + addJsonNode("contract", { make_pair("name", _node.getName())}); + return goDeeper(); +} + +bool ASTJsonConverter::visit(StructDefinition const& _node) +{ + // writeLine("StructDefinition \"" + _node.getName() + "\""); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(ParameterList const& _node) +{ + // writeLine("ParameterList"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(FunctionDefinition const& _node) +{ + // writeLine("FunctionDefinition \"" + _node.getName() + "\"" + + // (_node.isPublic() ? " - public" : "") + + // (_node.isDeclaredConst() ? " - const" : "")); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(VariableDeclaration const& _node) +{ + // writeLine("VariableDeclaration \"" + _node.getName() + "\""); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(TypeName const& _node) +{ + // writeLine("TypeName"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(ElementaryTypeName const& _node) +{ + // writeLine(string("ElementaryTypeName ") + Token::toString(_node.getTypeName())); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(UserDefinedTypeName const& _node) +{ + // writeLine("UserDefinedTypeName \"" + _node.getName() + "\""); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Mapping const& _node) +{ + // writeLine("Mapping"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Statement const& _node) +{ + // writeLine("Statement"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Block const& _node) +{ + // writeLine("Block"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(IfStatement const& _node) +{ + // writeLine("IfStatement"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(BreakableStatement const& _node) +{ + // writeLine("BreakableStatement"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(WhileStatement const& _node) +{ + // writeLine("WhileStatement"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(ForStatement const& _node) +{ + // writeLine("ForStatement"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Continue const& _node) +{ + // writeLine("Continue"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Break const& _node) +{ + // writeLine("Break"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Return const& _node) +{ + // writeLine("Return"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(VariableDefinition const& _node) +{ + // writeLine("VariableDefinition"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(ExpressionStatement const& _node) +{ + // writeLine("ExpressionStatement"); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Expression const& _node) +{ + // writeLine("Expression"); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Assignment const& _node) +{ + // writeLine(string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator())); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(UnaryOperation const& _node) +{ + // writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + + // ") " + Token::toString(_node.getOperator())); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(BinaryOperation const& _node) +{ + // writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator())); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(FunctionCall const& _node) +{ + // writeLine("FunctionCall"); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(NewExpression const& _node) +{ + // writeLine("NewExpression"); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(MemberAccess const& _node) +{ + // writeLine("MemberAccess to member " + _node.getMemberName()); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(IndexAccess const& _node) +{ + // writeLine("IndexAccess"); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(PrimaryExpression const& _node) +{ + // writeLine("PrimaryExpression"); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Identifier const& _node) +{ + // writeLine(string("Identifier ") + _node.getName()); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) +{ + // writeLine(string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken())); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +bool ASTJsonConverter::visit(Literal const& _node) +{ + // char const* tokenString = Token::toString(_node.getToken()); + // if (!tokenString) + // tokenString = "[no token]"; + // writeLine(string("Literal, token: ") + tokenString + " value: " + _node.getValue()); + // printType(_node); + // printSourcePart(_node); + return goDeeper(); +} + +void ASTJsonConverter::endVisit(ImportDirective const&) +{ + +} + +void ASTJsonConverter::endVisit(ContractDefinition const&) +{ + +} + +void ASTJsonConverter::endVisit(StructDefinition const&) +{ + +} + +void ASTJsonConverter::endVisit(ParameterList const&) +{ + +} + +void ASTJsonConverter::endVisit(FunctionDefinition const&) +{ + +} + +void ASTJsonConverter::endVisit(VariableDeclaration const&) +{ + +} + +void ASTJsonConverter::endVisit(TypeName const&) +{ + +} + +void ASTJsonConverter::endVisit(ElementaryTypeName const&) +{ + +} + +void ASTJsonConverter::endVisit(UserDefinedTypeName const&) +{ + +} + +void ASTJsonConverter::endVisit(Mapping const&) +{ + +} + +void ASTJsonConverter::endVisit(Statement const&) +{ + +} + +void ASTJsonConverter::endVisit(Block const&) +{ + +} + +void ASTJsonConverter::endVisit(IfStatement const&) +{ + +} + +void ASTJsonConverter::endVisit(BreakableStatement const&) +{ + +} + +void ASTJsonConverter::endVisit(WhileStatement const&) +{ + +} + +void ASTJsonConverter::endVisit(ForStatement const&) +{ + +} + +void ASTJsonConverter::endVisit(Continue const&) +{ + +} + +void ASTJsonConverter::endVisit(Break const&) +{ + +} + +void ASTJsonConverter::endVisit(Return const&) +{ + +} + +void ASTJsonConverter::endVisit(VariableDefinition const&) +{ + +} + +void ASTJsonConverter::endVisit(ExpressionStatement const&) +{ + +} + +void ASTJsonConverter::endVisit(Expression const&) +{ + +} + +void ASTJsonConverter::endVisit(Assignment const&) +{ + +} + +void ASTJsonConverter::endVisit(UnaryOperation const&) +{ + +} + +void ASTJsonConverter::endVisit(BinaryOperation const&) +{ + +} + +void ASTJsonConverter::endVisit(FunctionCall const&) +{ + +} + +void ASTJsonConverter::endVisit(NewExpression const&) +{ + +} + +void ASTJsonConverter::endVisit(MemberAccess const&) +{ + +} + +void ASTJsonConverter::endVisit(IndexAccess const&) +{ + +} + +void ASTJsonConverter::endVisit(PrimaryExpression const&) +{ + +} + +void ASTJsonConverter::endVisit(Identifier const&) +{ + +} + +void ASTJsonConverter::endVisit(ElementaryTypeNameExpression const&) +{ + +} + +void ASTJsonConverter::endVisit(Literal const&) +{ + +} + +void ASTJsonConverter::printType(Expression const& _expression) +{ + // if (_expression.getType()) + // *m_ostream << getIndentation() << " Type: " << _expression.getType()->toString() << "\n"; + // else + // *m_ostream << getIndentation() << " Type unknown.\n"; +} + + +} +} diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h new file mode 100644 index 000000000..0c84ee9af --- /dev/null +++ b/libsolidity/ASTJsonConverter.h @@ -0,0 +1,127 @@ +/* + 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 . +*/ +/** + * @author Lefteris + * @date 2015 + * Converts the AST into json format + */ + +#pragma once + +#include +#include +#include + +namespace dev +{ +namespace solidity +{ + +/** + * Converter of the AST into JSON format + */ +class ASTJsonConverter: public ASTConstVisitor +{ +public: + /// Create a converter for the given abstract syntax tree. If the source is specified, + /// the corresponding parts of the source are printed with each node. + ASTJsonConverter(ASTNode const& _ast); + /// Output the json representation of the AST to _stream. + void print(std::ostream& _stream); + + bool visit(ImportDirective const& _node) override; + bool visit(ContractDefinition const& _node) override; + bool visit(StructDefinition const& _node) override; + bool visit(ParameterList const& _node) override; + bool visit(FunctionDefinition const& _node) override; + bool visit(VariableDeclaration const& _node) override; + bool visit(TypeName const& _node) override; + bool visit(ElementaryTypeName const& _node) override; + bool visit(UserDefinedTypeName const& _node) override; + bool visit(Mapping const& _node) override; + bool visit(Statement const& _node) override; + bool visit(Block const& _node) override; + bool visit(IfStatement const& _node) override; + bool visit(BreakableStatement const& _node) override; + bool visit(WhileStatement const& _node) override; + bool visit(ForStatement const& _node) override; + bool visit(Continue const& _node) override; + bool visit(Break const& _node) override; + bool visit(Return const& _node) override; + bool visit(VariableDefinition const& _node) override; + bool visit(ExpressionStatement const& _node) override; + bool visit(Expression const& _node) override; + bool visit(Assignment const& _node) override; + bool visit(UnaryOperation const& _node) override; + bool visit(BinaryOperation const& _node) override; + bool visit(FunctionCall const& _node) override; + bool visit(NewExpression const& _node) override; + bool visit(MemberAccess const& _node) override; + bool visit(IndexAccess const& _node) override; + bool visit(PrimaryExpression const& _node) override; + bool visit(Identifier const& _node) override; + bool visit(ElementaryTypeNameExpression const& _node) override; + bool visit(Literal const& _node) override; + + void endVisit(ImportDirective const&) override; + void endVisit(ContractDefinition const&) override; + void endVisit(StructDefinition const&) override; + void endVisit(ParameterList const&) override; + void endVisit(FunctionDefinition const&) override; + void endVisit(VariableDeclaration const&) override; + void endVisit(TypeName const&) override; + void endVisit(ElementaryTypeName const&) override; + void endVisit(UserDefinedTypeName const&) override; + void endVisit(Mapping const&) override; + void endVisit(Statement const&) override; + void endVisit(Block const&) override; + void endVisit(IfStatement const&) override; + void endVisit(BreakableStatement const&) override; + void endVisit(WhileStatement const&) override; + void endVisit(ForStatement const&) override; + void endVisit(Continue const&) override; + void endVisit(Break const&) override; + void endVisit(Return const&) override; + void endVisit(VariableDefinition const&) override; + void endVisit(ExpressionStatement const&) override; + void endVisit(Expression const&) override; + void endVisit(Assignment const&) override; + void endVisit(UnaryOperation const&) override; + void endVisit(BinaryOperation const&) override; + void endVisit(FunctionCall const&) override; + void endVisit(NewExpression const&) override; + void endVisit(MemberAccess const&) override; + void endVisit(IndexAccess const&) override; + void endVisit(PrimaryExpression const&) override; + void endVisit(Identifier const&) override; + void endVisit(ElementaryTypeNameExpression const&) override; + void endVisit(Literal const&) override; + +private: + void addJsonNode(std::string const& _typeName, + std::initializer_list> _list); + void printType(Expression const& _expression); + bool goDeeper() { return true; } + + Json::Value m_astJson; + Json::Value *m_childrenPtr; + std::string m_source; + ASTNode const* m_ast; +}; + +} +} diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 8c5192abe..7be27297a 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ static string const g_argAbiStr = "json-abi"; static string const g_argSolAbiStr = "sol-abi"; static string const g_argAsmStr = "asm"; static string const g_argAstStr = "ast"; +static string const g_argAstJson = "ast-json"; static string const g_argBinaryStr = "binary"; static string const g_argOpcodesStr = "opcodes"; static string const g_argNatspecDevStr = "natspec-dev"; @@ -75,9 +77,10 @@ static inline bool argToStdout(po::variables_map const& _args, string const& _na static bool needStdout(po::variables_map const& _args) { + return argToStdout(_args, g_argAbiStr) || argToStdout(_args, g_argSolAbiStr) || - argToStdout(_args, g_argNatspecUserStr) || + argToStdout(_args, g_argNatspecUserStr) || argToStdout(_args, g_argAstJson) || argToStdout(_args, g_argNatspecDevStr) || argToStdout(_args, g_argAsmStr) || argToStdout(_args, g_argOpcodesStr) || argToStdout(_args, g_argBinaryStr); } @@ -215,6 +218,8 @@ bool CommandLineInterface::parseArguments(int argc, char** argv) ("input-file", po::value>(), "input file") (g_argAstStr.c_str(), po::value(), "Request to output the AST of the contract. " OUTPUT_TYPE_STR) + (g_argAstJson.c_str(), po::value(), + "Request to output the AST of the contract in JSON format. " OUTPUT_TYPE_STR) (g_argAsmStr.c_str(), po::value(), "Request to output the EVM assembly of the contract. " OUTPUT_TYPE_STR) (g_argOpcodesStr.c_str(), po::value(), @@ -339,20 +344,44 @@ bool CommandLineInterface::processInput() return true; } -void CommandLineInterface::actOnInput() +void CommandLineInterface::handleAst(std::string const& _argStr) { + std::string title; + std::string suffix; + + if (_argStr == g_argAstStr) + { + title = "Syntax trees:"; + suffix = ".ast"; + } + else if (_argStr == g_argAstJson) + { + title = "JSON AST:"; + suffix = ".json"; + } + else + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal argStr for AST")); + // do we need AST output? - if (m_args.count(g_argAstStr)) + if (m_args.count(_argStr)) { - auto choice = m_args[g_argAstStr].as(); + auto choice = m_args[_argStr].as(); if (outputToStdout(choice)) { - cout << "Syntax trees:" << endl << endl; + cout << title << endl << endl; for (auto const& sourceCode: m_sourceCodes) { cout << endl << "======= " << sourceCode.first << " =======" << endl; - ASTPrinter printer(m_compiler.getAST(sourceCode.first), sourceCode.second); - printer.print(cout); + if (_argStr == g_argAstStr) + { + ASTPrinter printer(m_compiler.getAST(sourceCode.first), sourceCode.second); + printer.print(cout); + } + else + { + ASTJsonConverter converter(m_compiler.getAST(sourceCode.first)); + converter.print(cout); + } } } @@ -362,12 +391,27 @@ void CommandLineInterface::actOnInput() { boost::filesystem::path p(sourceCode.first); ofstream outFile(p.stem().string() + ".ast"); - ASTPrinter printer(m_compiler.getAST(sourceCode.first), sourceCode.second); - printer.print(outFile); + if (_argStr == g_argAstStr) + { + ASTPrinter printer(m_compiler.getAST(sourceCode.first), sourceCode.second); + printer.print(outFile); + } + else + { + ASTJsonConverter converter(m_compiler.getAST(sourceCode.first)); + converter.print(outFile); + } outFile.close(); } } } +} + +void CommandLineInterface::actOnInput() +{ + // do we need AST output? + handleAst(g_argAstStr); + handleAst(g_argAstJson); vector contracts = m_compiler.getContractNames(); for (string const& contract: contracts) diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 9dfee7199..2862773ba 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -53,6 +53,7 @@ public: void actOnInput(); private: + void handleAst(std::string const& _argStr); void handleBinary(std::string const& _contract); void handleOpcode(std::string const& _contract); void handleBytecode(std::string const& _contract); From 0642bbbd8c864d96fb4351859f06feb80c4761e6 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 6 Jan 2015 16:50:04 +0100 Subject: [PATCH 12/40] More work on the AST export. Work in progress --- libsolidity/ASTJsonConverter.cpp | 215 ++++++++++++++++++------------- libsolidity/ASTJsonConverter.h | 17 ++- 2 files changed, 136 insertions(+), 96 deletions(-) diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index 82495dec0..3ef6728bb 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -31,7 +31,8 @@ namespace solidity { void ASTJsonConverter::addJsonNode(string const& _typeName, - initializer_list> _list) + initializer_list> _list, + bool _hasChildren = false) { Json::Value node; Json::Value attrs; @@ -41,19 +42,29 @@ void ASTJsonConverter::addJsonNode(string const& _typeName, attrs[e.first] = e.second; node["attributes"] = attrs; - m_childrenPtr->append(node); + m_jsonNodePtrs.top()->append(node); + + if (_hasChildren) { + Json::Value children(Json::arrayValue); + node["children"] = children; + m_jsonNodePtrs.push(&node["children"]); + m_depth ++; + cout << "goDown" << endl; + } } -ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast) +ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast), m_depth(0) { Json::Value attrs; - Json::Value children; + Json::Value children(Json::arrayValue); m_astJson["type"] = "root"; - attrs["name"] = "nameoffile"; //TODO m_astJson["attributes"] = attrs; + attrs["name"] = "nameoffile"; //TODO m_astJson["children"] = children; - m_childrenPtr = &m_astJson["children"]; + // m_jsonNodePtrs.push(&m_astJson["children"]); + m_jsonNodePtrs.push(&m_astJson["children"]); + // m_jsonNodePtrs.push(&children); } void ASTJsonConverter::print(ostream& _stream) @@ -66,215 +77,225 @@ void ASTJsonConverter::print(ostream& _stream) bool ASTJsonConverter::visit(ImportDirective const& _node) { addJsonNode("import", { make_pair("file", _node.getIdentifier())}); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(ContractDefinition const& _node) { - // writeLine("ContractDefinition \"" + _node.getName() + "\""); - // printSourcePart(_node); - addJsonNode("contract", { make_pair("name", _node.getName())}); - return goDeeper(); + addJsonNode("contract", { make_pair("name", _node.getName())}, true); + return true; } bool ASTJsonConverter::visit(StructDefinition const& _node) { - // writeLine("StructDefinition \"" + _node.getName() + "\""); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("struct", { make_pair("name", _node.getName())}, true); + return true; } bool ASTJsonConverter::visit(ParameterList const& _node) { - // writeLine("ParameterList"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("parameter_list", {}, true); + return true; } bool ASTJsonConverter::visit(FunctionDefinition const& _node) { - // writeLine("FunctionDefinition \"" + _node.getName() + "\"" + - // (_node.isPublic() ? " - public" : "") + - // (_node.isDeclaredConst() ? " - const" : "")); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("function", + { make_pair("name", _node.getName()), + make_pair("public", boost::lexical_cast(_node.isPublic())), + make_pair("const", boost::lexical_cast(_node.isDeclaredConst()))}, + true); + return true; } bool ASTJsonConverter::visit(VariableDeclaration const& _node) { - // writeLine("VariableDeclaration \"" + _node.getName() + "\""); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("variable_declaration", + { //make_pair("type", _node.getTypeName()->getName()), + make_pair("name", _node.getName()), + make_pair("local", boost::lexical_cast(_node.isLocalVariable()))}); + return true; } bool ASTJsonConverter::visit(TypeName const& _node) { // writeLine("TypeName"); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(ElementaryTypeName const& _node) { // writeLine(string("ElementaryTypeName ") + Token::toString(_node.getTypeName())); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(UserDefinedTypeName const& _node) { // writeLine("UserDefinedTypeName \"" + _node.getName() + "\""); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(Mapping const& _node) { // writeLine("Mapping"); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(Statement const& _node) { - // writeLine("Statement"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("statement", {}, true); + return true; } bool ASTJsonConverter::visit(Block const& _node) { - // writeLine("Block"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("block", {}, true); + return true; } bool ASTJsonConverter::visit(IfStatement const& _node) { - // writeLine("IfStatement"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("if_statement", {}, true); + return true; } bool ASTJsonConverter::visit(BreakableStatement const& _node) { // writeLine("BreakableStatement"); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(WhileStatement const& _node) { - // writeLine("WhileStatement"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("while_statement", {}, true); + return true; } bool ASTJsonConverter::visit(ForStatement const& _node) { - // writeLine("ForStatement"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("for_statement", {}, true); + return true; } bool ASTJsonConverter::visit(Continue const& _node) { - // writeLine("Continue"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("continue", {}); + return true; } bool ASTJsonConverter::visit(Break const& _node) { - // writeLine("Break"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("break", {}); + return true; } bool ASTJsonConverter::visit(Return const& _node) { - // writeLine("Return"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("return", {});; + return true; } bool ASTJsonConverter::visit(VariableDefinition const& _node) { - // writeLine("VariableDefinition"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("variable_definition", {}, true); + return true; } bool ASTJsonConverter::visit(ExpressionStatement const& _node) { - // writeLine("ExpressionStatement"); - // printSourcePart(_node); - return goDeeper(); + addJsonNode("expression_statement", {}, true); + return true; } bool ASTJsonConverter::visit(Expression const& _node) { + addJsonNode("expression", + { + make_pair("type", _node.getType()->toString()), + make_pair("lvalue", boost::lexical_cast(_node.isLValue())), + make_pair("local_lvalue", boost::lexical_cast(_node.isLocalLValue())), + }, + true); // writeLine("Expression"); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(Assignment const& _node) { + addJsonNode("assignment", {make_pair("operator", Token::toString(_node.getAssignmentOperator()))}, true); // writeLine(string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator())); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(UnaryOperation const& _node) { + addJsonNode("unary_op", + {make_pair("prefix", boost::lexical_cast(_node.isPrefixOperation())), + make_pair("operator", Token::toString(_node.getOperator()))}, + true); + // writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + // ") " + Token::toString(_node.getOperator())); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(BinaryOperation const& _node) { + addJsonNode("binary_op", + {make_pair("operator", Token::toString(_node.getOperator()))}, + true); // writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator())); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(FunctionCall const& _node) { + addJsonNode("function_call", + {make_pair("type_conversion", boost::lexical_cast(_node.isTypeConversion()))}, + true); // writeLine("FunctionCall"); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(NewExpression const& _node) { + addJsonNode("new_expression", {}, true); // writeLine("NewExpression"); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(MemberAccess const& _node) { + addJsonNode("member_access", {make_pair("member_name", _node.getMemberName())}, true); // writeLine("MemberAccess to member " + _node.getMemberName()); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(IndexAccess const& _node) { - // writeLine("IndexAccess"); + addJsonNode("index_access", {}, true); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(PrimaryExpression const& _node) @@ -282,34 +303,43 @@ bool ASTJsonConverter::visit(PrimaryExpression const& _node) // writeLine("PrimaryExpression"); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(Identifier const& _node) { + addJsonNode("identifier", {make_pair("value", _node.getName())}); // writeLine(string("Identifier ") + _node.getName()); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) { + addJsonNode("elementary_typename_expression", + {make_pair("value", Token::toString(_node.getTypeToken()))}); // writeLine(string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken())); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } bool ASTJsonConverter::visit(Literal const& _node) { + char const* tokenString = Token::toString(_node.getToken()); + addJsonNode("literal", + { + make_pair("string", (tokenString) ? tokenString : "null"), + make_pair("value", _node.getValue())}); + // char const* tokenString = Token::toString(_node.getToken()); // if (!tokenString) // tokenString = "[no token]"; // writeLine(string("Literal, token: ") + tokenString + " value: " + _node.getValue()); // printType(_node); // printSourcePart(_node); - return goDeeper(); + return true; } void ASTJsonConverter::endVisit(ImportDirective const&) @@ -319,27 +349,26 @@ void ASTJsonConverter::endVisit(ImportDirective const&) void ASTJsonConverter::endVisit(ContractDefinition const&) { - + goUp(); } void ASTJsonConverter::endVisit(StructDefinition const&) { - + goUp(); } void ASTJsonConverter::endVisit(ParameterList const&) { - + goUp(); } void ASTJsonConverter::endVisit(FunctionDefinition const&) { - + goUp(); } void ASTJsonConverter::endVisit(VariableDeclaration const&) { - } void ASTJsonConverter::endVisit(TypeName const&) @@ -364,17 +393,17 @@ void ASTJsonConverter::endVisit(Mapping const&) void ASTJsonConverter::endVisit(Statement const&) { - + goUp(); } void ASTJsonConverter::endVisit(Block const&) { - + goUp(); } void ASTJsonConverter::endVisit(IfStatement const&) { - + goUp(); } void ASTJsonConverter::endVisit(BreakableStatement const&) @@ -384,12 +413,12 @@ void ASTJsonConverter::endVisit(BreakableStatement const&) void ASTJsonConverter::endVisit(WhileStatement const&) { - + goUp(); } void ASTJsonConverter::endVisit(ForStatement const&) { - + goUp(); } void ASTJsonConverter::endVisit(Continue const&) @@ -409,52 +438,52 @@ void ASTJsonConverter::endVisit(Return const&) void ASTJsonConverter::endVisit(VariableDefinition const&) { - + goUp(); } void ASTJsonConverter::endVisit(ExpressionStatement const&) { - + goUp(); } void ASTJsonConverter::endVisit(Expression const&) { - + goUp(); } void ASTJsonConverter::endVisit(Assignment const&) { - + goUp(); } void ASTJsonConverter::endVisit(UnaryOperation const&) { - + goUp(); } void ASTJsonConverter::endVisit(BinaryOperation const&) { - + goUp(); } void ASTJsonConverter::endVisit(FunctionCall const&) { - + goUp(); } void ASTJsonConverter::endVisit(NewExpression const&) { - + goUp(); } void ASTJsonConverter::endVisit(MemberAccess const&) { - + goUp(); } void ASTJsonConverter::endVisit(IndexAccess const&) { - + goUp(); } void ASTJsonConverter::endVisit(PrimaryExpression const&) diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 0c84ee9af..44bd34617 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -23,7 +23,9 @@ #pragma once #include +#include #include +#include #include namespace dev @@ -113,14 +115,23 @@ public: private: void addJsonNode(std::string const& _typeName, - std::initializer_list> _list); + std::initializer_list> _list, + bool _hasChildren); void printType(Expression const& _expression); - bool goDeeper() { return true; } + inline void goUp() + { + std::cout << "goUp" << std::endl; + m_jsonNodePtrs.pop(); + m_depth--; + if (m_depth < 0) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal error")); + }; Json::Value m_astJson; - Json::Value *m_childrenPtr; + std::stack m_jsonNodePtrs; std::string m_source; ASTNode const* m_ast; + int m_depth; }; } From f91cb0c36832dfa5bbcd388e593cdc76de776efe Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 15:27:31 +0100 Subject: [PATCH 13/40] ASTJSonconverter stack takes objects and not pointers --- libsolidity/ASTJsonConverter.cpp | 8 +++----- libsolidity/ASTJsonConverter.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index 3ef6728bb..0e40713ac 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -42,12 +42,12 @@ void ASTJsonConverter::addJsonNode(string const& _typeName, attrs[e.first] = e.second; node["attributes"] = attrs; - m_jsonNodePtrs.top()->append(node); + m_jsonNodePtrs.top().append(node); if (_hasChildren) { Json::Value children(Json::arrayValue); node["children"] = children; - m_jsonNodePtrs.push(&node["children"]); + m_jsonNodePtrs.push(node["children"]); m_depth ++; cout << "goDown" << endl; } @@ -62,9 +62,7 @@ ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast), m_depth(0 m_astJson["attributes"] = attrs; attrs["name"] = "nameoffile"; //TODO m_astJson["children"] = children; - // m_jsonNodePtrs.push(&m_astJson["children"]); - m_jsonNodePtrs.push(&m_astJson["children"]); - // m_jsonNodePtrs.push(&children); + m_jsonNodePtrs.push(m_astJson["children"]); } void ASTJsonConverter::print(ostream& _stream) diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 44bd34617..6db625fed 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -128,7 +128,7 @@ private: }; Json::Value m_astJson; - std::stack m_jsonNodePtrs; + std::stack m_jsonNodePtrs; std::string m_source; ASTNode const* m_ast; int m_depth; From 50d3825f1f93cff7d8332b67269964eff4eaeaa6 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 15 Jan 2015 16:54:59 +0100 Subject: [PATCH 14/40] Solidity AST Json Exporter - A first version of the exporter is ready with this commit - Further refinement will follow once it gets used --- libsolidity/ASTJsonConverter.cpp | 229 +++++++++++++------------------ libsolidity/ASTJsonConverter.h | 13 +- 2 files changed, 105 insertions(+), 137 deletions(-) diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index 0e40713ac..70821a8f0 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -30,39 +30,50 @@ namespace dev namespace solidity { -void ASTJsonConverter::addJsonNode(string const& _typeName, +void ASTJsonConverter::addKeyValue(Json::Value& _obj, string const& _key, string const& _val) +{ + // special handling for booleans + if (_key == "const" || _key == "public" || _key == "local" || + _key == "lvalue" || _key == "local_lvalue" || _key == "prefix") + _obj[_key] = (_val == "1") ? true : false; + else + // else simply add it as a string + _obj[_key] = _val; +} + +void ASTJsonConverter::addJsonNode(string const& _nodeName, initializer_list> _list, bool _hasChildren = false) { Json::Value node; - Json::Value attrs; - node["type"] = _typeName; - for (auto &e: _list) - attrs[e.first] = e.second; - node["attributes"] = attrs; + node["name"] = _nodeName; + if (_list.size() !=0) + { + Json::Value attrs; + for (auto &e: _list) + addKeyValue(attrs, e.first, e.second); + node["attributes"] = attrs; + } - m_jsonNodePtrs.top().append(node); + (*m_jsonNodePtrs.top()).append(node); - if (_hasChildren) { + if (_hasChildren) + { + Json::Value& addedNode = (*m_jsonNodePtrs.top())[m_jsonNodePtrs.top()->size() - 1]; Json::Value children(Json::arrayValue); - node["children"] = children; - m_jsonNodePtrs.push(node["children"]); - m_depth ++; - cout << "goDown" << endl; + addedNode["children"] = children; + m_jsonNodePtrs.push(&addedNode["children"]); } } -ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast), m_depth(0) +ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast) { - Json::Value attrs; Json::Value children(Json::arrayValue); - m_astJson["type"] = "root"; - m_astJson["attributes"] = attrs; - attrs["name"] = "nameoffile"; //TODO + m_astJson["name"] = "root"; m_astJson["children"] = children; - m_jsonNodePtrs.push(m_astJson["children"]); + m_jsonNodePtrs.push(&m_astJson["children"]); } void ASTJsonConverter::print(ostream& _stream) @@ -74,31 +85,31 @@ void ASTJsonConverter::print(ostream& _stream) bool ASTJsonConverter::visit(ImportDirective const& _node) { - addJsonNode("import", { make_pair("file", _node.getIdentifier())}); + addJsonNode("Import", { make_pair("file", _node.getIdentifier())}); return true; } bool ASTJsonConverter::visit(ContractDefinition const& _node) { - addJsonNode("contract", { make_pair("name", _node.getName())}, true); + addJsonNode("Contract", { make_pair("name", _node.getName())}, true); return true; } bool ASTJsonConverter::visit(StructDefinition const& _node) { - addJsonNode("struct", { make_pair("name", _node.getName())}, true); + addJsonNode("Struct", { make_pair("name", _node.getName())}, true); return true; } -bool ASTJsonConverter::visit(ParameterList const& _node) +bool ASTJsonConverter::visit(ParameterList const&) { - addJsonNode("parameter_list", {}, true); + addJsonNode("ParameterList", {}, true); return true; } bool ASTJsonConverter::visit(FunctionDefinition const& _node) { - addJsonNode("function", + addJsonNode("Function", { make_pair("name", _node.getName()), make_pair("public", boost::lexical_cast(_node.isPublic())), make_pair("const", boost::lexical_cast(_node.isDeclaredConst()))}, @@ -108,235 +119,196 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) bool ASTJsonConverter::visit(VariableDeclaration const& _node) { - addJsonNode("variable_declaration", - { //make_pair("type", _node.getTypeName()->getName()), - make_pair("name", _node.getName()), - make_pair("local", boost::lexical_cast(_node.isLocalVariable()))}); + addJsonNode("VariableDeclaration", + { make_pair("name", _node.getName()), + make_pair("local", boost::lexical_cast(_node.isLocalVariable()))}, + true); return true; } -bool ASTJsonConverter::visit(TypeName const& _node) +bool ASTJsonConverter::visit(TypeName const&) { - // writeLine("TypeName"); - // printSourcePart(_node); return true; } bool ASTJsonConverter::visit(ElementaryTypeName const& _node) { - // writeLine(string("ElementaryTypeName ") + Token::toString(_node.getTypeName())); - // printSourcePart(_node); + addJsonNode("ElementaryTypeName", { make_pair("name", Token::toString(_node.getTypeName())) }); return true; } bool ASTJsonConverter::visit(UserDefinedTypeName const& _node) { - // writeLine("UserDefinedTypeName \"" + _node.getName() + "\""); - // printSourcePart(_node); + addJsonNode("UserDefinedTypeName", { make_pair("name", _node.getName()) }); return true; } -bool ASTJsonConverter::visit(Mapping const& _node) +bool ASTJsonConverter::visit(Mapping const&) { - // writeLine("Mapping"); - // printSourcePart(_node); + addJsonNode("Mapping", {}, true); return true; } -bool ASTJsonConverter::visit(Statement const& _node) +bool ASTJsonConverter::visit(Statement const&) { - addJsonNode("statement", {}, true); + addJsonNode("Statement", {}, true); return true; } -bool ASTJsonConverter::visit(Block const& _node) +bool ASTJsonConverter::visit(Block const&) { - addJsonNode("block", {}, true); + addJsonNode("Block", {}, true); return true; } -bool ASTJsonConverter::visit(IfStatement const& _node) +bool ASTJsonConverter::visit(IfStatement const&) { - addJsonNode("if_statement", {}, true); + addJsonNode("IfStatement", {}, true); return true; } -bool ASTJsonConverter::visit(BreakableStatement const& _node) +bool ASTJsonConverter::visit(BreakableStatement const&) { - // writeLine("BreakableStatement"); - // printSourcePart(_node); return true; } -bool ASTJsonConverter::visit(WhileStatement const& _node) +bool ASTJsonConverter::visit(WhileStatement const&) { - addJsonNode("while_statement", {}, true); + addJsonNode("WhileStatement", {}, true); return true; } -bool ASTJsonConverter::visit(ForStatement const& _node) +bool ASTJsonConverter::visit(ForStatement const&) { - addJsonNode("for_statement", {}, true); + addJsonNode("ForStatement", {}, true); return true; } -bool ASTJsonConverter::visit(Continue const& _node) +bool ASTJsonConverter::visit(Continue const&) { - addJsonNode("continue", {}); + addJsonNode("Continue", {}); return true; } -bool ASTJsonConverter::visit(Break const& _node) +bool ASTJsonConverter::visit(Break const&) { - addJsonNode("break", {}); + addJsonNode("Break", {}); return true; } -bool ASTJsonConverter::visit(Return const& _node) +bool ASTJsonConverter::visit(Return const&) { - addJsonNode("return", {});; + addJsonNode("Return", {}, true);; return true; } -bool ASTJsonConverter::visit(VariableDefinition const& _node) +bool ASTJsonConverter::visit(VariableDefinition const&) { - addJsonNode("variable_definition", {}, true); + addJsonNode("VariableDefinition", {}, true); return true; } -bool ASTJsonConverter::visit(ExpressionStatement const& _node) +bool ASTJsonConverter::visit(ExpressionStatement const&) { - addJsonNode("expression_statement", {}, true); + addJsonNode("ExpressionStatement", {}, true); return true; } bool ASTJsonConverter::visit(Expression const& _node) { - addJsonNode("expression", + addJsonNode("Expression", { - make_pair("type", _node.getType()->toString()), + make_pair("type", getType(_node)), make_pair("lvalue", boost::lexical_cast(_node.isLValue())), - make_pair("local_lvalue", boost::lexical_cast(_node.isLocalLValue())), - }, + make_pair("local_lvalue", boost::lexical_cast(_node.isLocalLValue()))}, true); - // writeLine("Expression"); - // printType(_node); - // printSourcePart(_node); return true; } bool ASTJsonConverter::visit(Assignment const& _node) { - addJsonNode("assignment", {make_pair("operator", Token::toString(_node.getAssignmentOperator()))}, true); - // writeLine(string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator())); - // printType(_node); - // printSourcePart(_node); + addJsonNode("Assignment", + {make_pair("operator", Token::toString(_node.getAssignmentOperator())), + make_pair("type", getType(_node))}, + true); return true; } bool ASTJsonConverter::visit(UnaryOperation const& _node) { - addJsonNode("unary_op", + addJsonNode("UnaryOperation", {make_pair("prefix", boost::lexical_cast(_node.isPrefixOperation())), - make_pair("operator", Token::toString(_node.getOperator()))}, + make_pair("operator", Token::toString(_node.getOperator())), + make_pair("type", getType(_node))}, true); - - // writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + - // ") " + Token::toString(_node.getOperator())); - // printType(_node); - // printSourcePart(_node); return true; } bool ASTJsonConverter::visit(BinaryOperation const& _node) { - addJsonNode("binary_op", - {make_pair("operator", Token::toString(_node.getOperator()))}, + addJsonNode("BinaryOperation", + {make_pair("operator", Token::toString(_node.getOperator())), + make_pair("type", getType(_node))}, true); - // writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator())); - // printType(_node); - // printSourcePart(_node); return true; } bool ASTJsonConverter::visit(FunctionCall const& _node) { - addJsonNode("function_call", - {make_pair("type_conversion", boost::lexical_cast(_node.isTypeConversion()))}, + addJsonNode("FunctionCall", + {make_pair("type_conversion", boost::lexical_cast(_node.isTypeConversion())), + make_pair("type", getType(_node))}, true); - // writeLine("FunctionCall"); - // printType(_node); - // printSourcePart(_node); return true; } bool ASTJsonConverter::visit(NewExpression const& _node) { - addJsonNode("new_expression", {}, true); - // writeLine("NewExpression"); - // printType(_node); - // printSourcePart(_node); + addJsonNode("NewExpression", {make_pair("type", getType(_node))}, true); return true; } bool ASTJsonConverter::visit(MemberAccess const& _node) { - addJsonNode("member_access", {make_pair("member_name", _node.getMemberName())}, true); - // writeLine("MemberAccess to member " + _node.getMemberName()); - // printType(_node); - // printSourcePart(_node); + addJsonNode("MemberAccess", + {make_pair("member_name", _node.getMemberName()), + make_pair("type", getType(_node))}, + true); return true; } bool ASTJsonConverter::visit(IndexAccess const& _node) { - addJsonNode("index_access", {}, true); - // printType(_node); - // printSourcePart(_node); + addJsonNode("IndexAccess", {make_pair("type", getType(_node))}, true); return true; } -bool ASTJsonConverter::visit(PrimaryExpression const& _node) +bool ASTJsonConverter::visit(PrimaryExpression const&) { - // writeLine("PrimaryExpression"); - // printType(_node); - // printSourcePart(_node); return true; } bool ASTJsonConverter::visit(Identifier const& _node) { - addJsonNode("identifier", {make_pair("value", _node.getName())}); - // writeLine(string("Identifier ") + _node.getName()); - // printType(_node); - // printSourcePart(_node); + addJsonNode("Identifier", + {make_pair("value", _node.getName()), make_pair("type", getType(_node))}); return true; } bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) { - addJsonNode("elementary_typename_expression", - {make_pair("value", Token::toString(_node.getTypeToken()))}); - // writeLine(string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken())); - // printType(_node); - // printSourcePart(_node); + addJsonNode("ElementaryTypenameExpression", + {make_pair("value", Token::toString(_node.getTypeToken())), make_pair("type", getType(_node))}); return true; } bool ASTJsonConverter::visit(Literal const& _node) { char const* tokenString = Token::toString(_node.getToken()); - addJsonNode("literal", - { - make_pair("string", (tokenString) ? tokenString : "null"), - make_pair("value", _node.getValue())}); - - // char const* tokenString = Token::toString(_node.getToken()); - // if (!tokenString) - // tokenString = "[no token]"; - // writeLine(string("Literal, token: ") + tokenString + " value: " + _node.getValue()); - // printType(_node); - // printSourcePart(_node); + addJsonNode("Literal", + {make_pair("string", (tokenString) ? tokenString : "null"), + make_pair("value", _node.getValue()), + make_pair("type", getType(_node))}); return true; } @@ -431,7 +403,7 @@ void ASTJsonConverter::endVisit(Break const&) void ASTJsonConverter::endVisit(Return const&) { - + goUp(); } void ASTJsonConverter::endVisit(VariableDefinition const&) @@ -504,12 +476,9 @@ void ASTJsonConverter::endVisit(Literal const&) } -void ASTJsonConverter::printType(Expression const& _expression) +string const ASTJsonConverter::getType(Expression const& _expression) { - // if (_expression.getType()) - // *m_ostream << getIndentation() << " Type: " << _expression.getType()->toString() << "\n"; - // else - // *m_ostream << getIndentation() << " Type unknown.\n"; + return (_expression.getType()) ? _expression.getType()->toString() : "Unknown"; } diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 6db625fed..69030f399 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -114,21 +114,20 @@ public: void endVisit(Literal const&) override; private: - void addJsonNode(std::string const& _typeName, + void addKeyValue(Json::Value& _obj, std::string const& _key, std::string const& _val); + void addJsonNode(std::string const& _nodeName, std::initializer_list> _list, bool _hasChildren); - void printType(Expression const& _expression); + std::string const getType(Expression const& _expression); inline void goUp() { - std::cout << "goUp" << std::endl; - m_jsonNodePtrs.pop(); - m_depth--; - if (m_depth < 0) + if (m_jsonNodePtrs.empty()) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal error")); + m_jsonNodePtrs.pop(); }; Json::Value m_astJson; - std::stack m_jsonNodePtrs; + std::stack m_jsonNodePtrs; std::string m_source; ASTNode const* m_ast; int m_depth; From 2304d6c141002a76aa4b2acb082d39ecbb245878 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 15 Jan 2015 14:27:31 -0500 Subject: [PATCH 15/40] Fix for EVMJIT --- libevmjit/Ext.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index f0767d9e0..7ab6a5504 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -22,9 +22,12 @@ namespace jit Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): RuntimeHelper(_runtimeManager), - m_memoryMan(_memoryMan), + m_memoryMan(_memoryMan) +#ifdef __MSCVER + , m_funcs({}), // The only std::array initialization that works in both Visual Studio & GCC m_argAllocas({}) +#endif { m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); } From 695751672c675d4ed61451cb4ef1e33916c9bb04 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 15 Jan 2015 14:58:00 -0500 Subject: [PATCH 16/40] More consistency! --- libevmjit/Compiler.cpp | 4 ++-- libevmjit/Ext.cpp | 6 +++--- libevmjit/Ext.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index bfcb9cea1..26c78b4ca 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -644,7 +644,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::EXTCODESIZE: { auto addr = stack.pop(); - auto codeRef = _ext.getExtCode(addr); + auto codeRef = _ext.extcode(addr); stack.push(codeRef.size); break; } @@ -682,7 +682,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto codeRef = _ext.getExtCode(addr); + auto codeRef = _ext.extcode(addr); _memory.copyBytes(codeRef.ptr, codeRef.size, srcIdx, destMemIdx, reqBytes); break; diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 7ab6a5504..aae68f43a 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -51,7 +51,7 @@ std::array::value> const& getEnvFuncDescs() 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{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})}, }}; @@ -169,10 +169,10 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) return hash; } -MemoryRef Ext::getExtCode(llvm::Value* _addr) +MemoryRef Ext::extcode(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); - auto code = createCall(EnvFunc::getExtCode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size}); + auto code = createCall(EnvFunc::extcode, {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 86a8a6190..2601d32ab 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -34,7 +34,7 @@ enum class EnvFunc call, log, blockhash, - getExtCode, + extcode, calldataload, // Helper function, not client Env interface _size @@ -55,7 +55,7 @@ public: llvm::Value* blockhash(llvm::Value* _number); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); - MemoryRef getExtCode(llvm::Value* _addr); + MemoryRef extcode(llvm::Value* _addr); void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics); From 5384b92c66ddc5a5b4a83bf028e0b67142c416dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 15 Jan 2015 23:21:55 +0100 Subject: [PATCH 17/40] Make evmjit library installable --- CMakeLists.txt | 4 ++-- libevmjit/CMakeLists.txt | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index acb113207..13f086151 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") else () - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra") endif() if(APPLE) @@ -14,7 +14,7 @@ if(APPLE) endif() # LLVM -if(LLVM_DIR) # local LLVM build +if(LLVM_DIR OR APPLE) # local LLVM build find_package(LLVM REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 28b501ee3..18ee4f7ee 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -2,13 +2,14 @@ set(TARGET_NAME evmjit) file(GLOB SOURCES "*.cpp") file(GLOB HEADERS "*.h") +set(INTERFACE_HEADERS interface.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 () +endif() link_directories(/usr/lib/llvm-3.5/lib) add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) @@ -21,5 +22,5 @@ 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} ) +install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib) +install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) From 271b4ccde44e491f7daae3a097e3345d9a856c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 15 Jan 2015 23:29:19 +0100 Subject: [PATCH 18/40] Avoid hardcoded LLVM library path --- CMakeLists.txt | 1 + libevmjit/CMakeLists.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13f086151..c8897efd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ else() 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") add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS) + link_directories(/usr/lib/llvm-3.5/lib) endif() # Boost diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 18ee4f7ee..01c1e881b 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -11,7 +11,6 @@ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) endif() -link_directories(/usr/lib/llvm-3.5/lib) add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") From 92a88040c83c6ef638a42d80f43fa8a722d01f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 00:32:46 +0100 Subject: [PATCH 19/40] Remove hardcoded LLVM library path and include optional CPP-JIT connector library from evmjit --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f1246e152..9bab77585 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,9 +124,7 @@ include(EthExecutableHelper) createBuildInfo() if (EVMJIT) - # Workaround for Ubuntu broken LLVM package - link_directories(/usr/lib/llvm-3.5/lib) - + set(EVMJIT_CPP TRUE) # include CPP-JIT connector add_subdirectory(evmjit) endif() From 921caaa90e0b1d91eb22f83a8ccbc0b2c050505f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 00:46:20 +0100 Subject: [PATCH 20/40] Enforce -fPIC for archives in evmjit --- evmjit/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index c8897efd9..25c62ff2f 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -6,7 +6,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") else () - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -fPIC") endif() if(APPLE) From 0bac8ec6cedd1c72e8e90ace02008262ce5c9815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 01:11:43 +0100 Subject: [PATCH 21/40] Make evmjit dependency of LLVM private --- evmjit/libevmjit/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt index 01c1e881b..c1acfc409 100644 --- a/evmjit/libevmjit/CMakeLists.txt +++ b/evmjit/libevmjit/CMakeLists.txt @@ -17,7 +17,7 @@ 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}) +target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") From 53e62fefbf4f447e1f79ec1f53ab0bbf99480feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 01:28:26 +0100 Subject: [PATCH 22/40] Do not ignore evmjit --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index b6abc22a3..8d8974809 100644 --- a/.gitignore +++ b/.gitignore @@ -65,7 +65,6 @@ DerivedData project.pbxproj -evmjit doc/html *.autosave node_modules/ From e3b15f48c4f357146c709492cd359b8a5bfb4da3 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 16 Jan 2015 11:44:55 +0100 Subject: [PATCH 23/40] Style fixes and refactoring in ASTJsonConverter --- libsolidity/ASTJsonConverter.cpp | 63 ++++++++++++-------------------- libsolidity/ASTJsonConverter.h | 9 ++--- solc/CommandLineInterface.cpp | 6 +-- 3 files changed, 31 insertions(+), 47 deletions(-) diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index 70821a8f0..04ddee0a7 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -48,15 +48,15 @@ void ASTJsonConverter::addJsonNode(string const& _nodeName, Json::Value node; node["name"] = _nodeName; - if (_list.size() !=0) + if (_list.size() != 0) { Json::Value attrs; - for (auto &e: _list) + for (auto& e: _list) addKeyValue(attrs, e.first, e.second); node["attributes"] = attrs; } - (*m_jsonNodePtrs.top()).append(node); + m_jsonNodePtrs.top()->append(node); if (_hasChildren) { @@ -82,7 +82,6 @@ void ASTJsonConverter::print(ostream& _stream) _stream << m_astJson; } - bool ASTJsonConverter::visit(ImportDirective const& _node) { addJsonNode("Import", { make_pair("file", _node.getIdentifier())}); @@ -91,13 +90,13 @@ bool ASTJsonConverter::visit(ImportDirective const& _node) bool ASTJsonConverter::visit(ContractDefinition const& _node) { - addJsonNode("Contract", { make_pair("name", _node.getName())}, true); + addJsonNode("Contract", { make_pair("name", _node.getName()) }, true); return true; } bool ASTJsonConverter::visit(StructDefinition const& _node) { - addJsonNode("Struct", { make_pair("name", _node.getName())}, true); + addJsonNode("Struct", { make_pair("name", _node.getName()) }, true); return true; } @@ -112,7 +111,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) addJsonNode("Function", { make_pair("name", _node.getName()), make_pair("public", boost::lexical_cast(_node.isPublic())), - make_pair("const", boost::lexical_cast(_node.isDeclaredConst()))}, + make_pair("const", boost::lexical_cast(_node.isDeclaredConst())) }, true); return true; } @@ -217,10 +216,9 @@ bool ASTJsonConverter::visit(ExpressionStatement const&) bool ASTJsonConverter::visit(Expression const& _node) { addJsonNode("Expression", - { - make_pair("type", getType(_node)), + { make_pair("type", getType(_node)), make_pair("lvalue", boost::lexical_cast(_node.isLValue())), - make_pair("local_lvalue", boost::lexical_cast(_node.isLocalLValue()))}, + make_pair("local_lvalue", boost::lexical_cast(_node.isLocalLValue())) }, true); return true; } @@ -228,8 +226,8 @@ bool ASTJsonConverter::visit(Expression const& _node) bool ASTJsonConverter::visit(Assignment const& _node) { addJsonNode("Assignment", - {make_pair("operator", Token::toString(_node.getAssignmentOperator())), - make_pair("type", getType(_node))}, + { make_pair("operator", Token::toString(_node.getAssignmentOperator())), + make_pair("type", getType(_node)) }, true); return true; } @@ -237,9 +235,9 @@ bool ASTJsonConverter::visit(Assignment const& _node) bool ASTJsonConverter::visit(UnaryOperation const& _node) { addJsonNode("UnaryOperation", - {make_pair("prefix", boost::lexical_cast(_node.isPrefixOperation())), + { make_pair("prefix", boost::lexical_cast(_node.isPrefixOperation())), make_pair("operator", Token::toString(_node.getOperator())), - make_pair("type", getType(_node))}, + make_pair("type", getType(_node)) }, true); return true; } @@ -247,7 +245,7 @@ bool ASTJsonConverter::visit(UnaryOperation const& _node) bool ASTJsonConverter::visit(BinaryOperation const& _node) { addJsonNode("BinaryOperation", - {make_pair("operator", Token::toString(_node.getOperator())), + { make_pair("operator", Token::toString(_node.getOperator())), make_pair("type", getType(_node))}, true); return true; @@ -256,30 +254,30 @@ bool ASTJsonConverter::visit(BinaryOperation const& _node) bool ASTJsonConverter::visit(FunctionCall const& _node) { addJsonNode("FunctionCall", - {make_pair("type_conversion", boost::lexical_cast(_node.isTypeConversion())), - make_pair("type", getType(_node))}, + { make_pair("type_conversion", boost::lexical_cast(_node.isTypeConversion())), + make_pair("type", getType(_node)) }, true); return true; } bool ASTJsonConverter::visit(NewExpression const& _node) { - addJsonNode("NewExpression", {make_pair("type", getType(_node))}, true); + addJsonNode("NewExpression", { make_pair("type", getType(_node)) }, true); return true; } bool ASTJsonConverter::visit(MemberAccess const& _node) { addJsonNode("MemberAccess", - {make_pair("member_name", _node.getMemberName()), - make_pair("type", getType(_node))}, + { make_pair("member_name", _node.getMemberName()), + make_pair("type", getType(_node)) }, true); return true; } bool ASTJsonConverter::visit(IndexAccess const& _node) { - addJsonNode("IndexAccess", {make_pair("type", getType(_node))}, true); + addJsonNode("IndexAccess", { make_pair("type", getType(_node)) }, true); return true; } @@ -291,14 +289,14 @@ bool ASTJsonConverter::visit(PrimaryExpression const&) bool ASTJsonConverter::visit(Identifier const& _node) { addJsonNode("Identifier", - {make_pair("value", _node.getName()), make_pair("type", getType(_node))}); + { make_pair("value", _node.getName()), make_pair("type", getType(_node)) }); return true; } bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) { addJsonNode("ElementaryTypenameExpression", - {make_pair("value", Token::toString(_node.getTypeToken())), make_pair("type", getType(_node))}); + { make_pair("value", Token::toString(_node.getTypeToken())), make_pair("type", getType(_node)) }); return true; } @@ -306,15 +304,14 @@ bool ASTJsonConverter::visit(Literal const& _node) { char const* tokenString = Token::toString(_node.getToken()); addJsonNode("Literal", - {make_pair("string", (tokenString) ? tokenString : "null"), + { make_pair("string", (tokenString) ? tokenString : "null"), make_pair("value", _node.getValue()), - make_pair("type", getType(_node))}); + make_pair("type", getType(_node)) }); return true; } void ASTJsonConverter::endVisit(ImportDirective const&) { - } void ASTJsonConverter::endVisit(ContractDefinition const&) @@ -343,22 +340,18 @@ void ASTJsonConverter::endVisit(VariableDeclaration const&) void ASTJsonConverter::endVisit(TypeName const&) { - } void ASTJsonConverter::endVisit(ElementaryTypeName const&) { - } void ASTJsonConverter::endVisit(UserDefinedTypeName const&) { - } void ASTJsonConverter::endVisit(Mapping const&) { - } void ASTJsonConverter::endVisit(Statement const&) @@ -378,7 +371,6 @@ void ASTJsonConverter::endVisit(IfStatement const&) void ASTJsonConverter::endVisit(BreakableStatement const&) { - } void ASTJsonConverter::endVisit(WhileStatement const&) @@ -393,12 +385,10 @@ void ASTJsonConverter::endVisit(ForStatement const&) void ASTJsonConverter::endVisit(Continue const&) { - } void ASTJsonConverter::endVisit(Break const&) { - } void ASTJsonConverter::endVisit(Return const&) @@ -458,29 +448,24 @@ void ASTJsonConverter::endVisit(IndexAccess const&) void ASTJsonConverter::endVisit(PrimaryExpression const&) { - } void ASTJsonConverter::endVisit(Identifier const&) { - } void ASTJsonConverter::endVisit(ElementaryTypeNameExpression const&) { - } void ASTJsonConverter::endVisit(Literal const&) { - } -string const ASTJsonConverter::getType(Expression const& _expression) +string ASTJsonConverter::getType(Expression const& _expression) { return (_expression.getType()) ? _expression.getType()->toString() : "Unknown"; } - } } diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 69030f399..7d9b9bc04 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -26,6 +26,7 @@ #include #include #include +#include #include namespace dev @@ -39,8 +40,7 @@ namespace solidity class ASTJsonConverter: public ASTConstVisitor { public: - /// Create a converter for the given abstract syntax tree. If the source is specified, - /// the corresponding parts of the source are printed with each node. + /// Create a converter to JSON for the given abstract syntax tree. ASTJsonConverter(ASTNode const& _ast); /// Output the json representation of the AST to _stream. void print(std::ostream& _stream); @@ -118,11 +118,10 @@ private: void addJsonNode(std::string const& _nodeName, std::initializer_list> _list, bool _hasChildren); - std::string const getType(Expression const& _expression); + std::string getType(Expression const& _expression); inline void goUp() { - if (m_jsonNodePtrs.empty()) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal error")); + solAssert(!m_jsonNodePtrs.empty(), "Uneven json nodes stack. Internal error."); m_jsonNodePtrs.pop(); }; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 7be27297a..3888f2314 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -344,10 +344,10 @@ bool CommandLineInterface::processInput() return true; } -void CommandLineInterface::handleAst(std::string const& _argStr) +void CommandLineInterface::handleAst(string const& _argStr) { - std::string title; - std::string suffix; + string title; + string suffix; if (_argStr == g_argAstStr) { From 7e91ed4b7dcd9a2c4902232a7ca3e8e2ff4868fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 12:43:24 +0100 Subject: [PATCH 24/40] Correct std::array intialization (again!) --- evmjit/libevmjit/Ext.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index aae68f43a..7d084a450 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -23,12 +23,9 @@ namespace jit Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): RuntimeHelper(_runtimeManager), m_memoryMan(_memoryMan) -#ifdef __MSCVER - , - m_funcs({}), // The only std::array initialization that works in both Visual Studio & GCC - m_argAllocas({}) -#endif { + m_funcs = decltype(m_funcs)(); + m_argAllocas = decltype(m_argAllocas)(); m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); } From 658b8d86d2589c26431e9ae9ad934649abc43a7a Mon Sep 17 00:00:00 2001 From: liana Date: Fri, 16 Jan 2015 12:55:49 +0100 Subject: [PATCH 25/40] Corrected "delete" for local variables i.e. set them to 0 Added test case --- libsolidity/ExpressionCompiler.cpp | 7 ++++--- test/SolidityEndToEndTest.cpp | 33 ++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index c8b7f3508..4eed68ea4 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -810,9 +810,10 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const if (stackDiff > 16) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Stack too deep.")); - else if (stackDiff > 0) - for (unsigned i = 0; i < m_size; ++i) - *m_context << u256(0) << eth::swapInstruction(m_size - i) << eth::Instruction::POP; + solAssert(stackDiff <= m_size, ""); + for (unsigned i = 0; i < m_size; ++i) + *m_context << u256(0) << eth::swapInstruction(stackDiff + (m_size - i) ) << eth::Instruction::POP; + break; } case LValue::STORAGE: diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index a733c2c43..ad537750e 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -799,8 +799,6 @@ BOOST_AUTO_TEST_CASE(deleteStruct) str.nstr.nestedValue = 2; str.nstr.nestedMapping[0] = true; str.nstr.nestedMapping[1] = false; - uint v = 5; - delete v; delete str; delete toDelete; } @@ -833,6 +831,37 @@ BOOST_AUTO_TEST_CASE(deleteStruct) BOOST_CHECK(callContractFunction("getNestedMapping(uint256)", 1) == encodeArgs(false)); } +BOOST_AUTO_TEST_CASE(deleteLocal) +{ + char const* sourceCode = R"( + contract test { + function delLocal() returns (uint res){ + uint v = 5; + delete v; + res = v; + } + })"; + + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("delLocal()") == encodeArgs(0)); +} + +BOOST_AUTO_TEST_CASE(deleteLocals) +{ + char const* sourceCode = R"( + contract test { + function delLocal() returns (uint res){ + uint v = 5; + uint w = 6; + delete v; + res = w; + } + })"; + + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("delLocal()") == encodeArgs(6)); +} + BOOST_AUTO_TEST_CASE(constructor) { char const* sourceCode = "contract test {\n" From 3012ee73b275a924e32f523f0ba5b45f43b16641 Mon Sep 17 00:00:00 2001 From: liana Date: Fri, 16 Jan 2015 13:07:16 +0100 Subject: [PATCH 26/40] removed spaces --- libsolidity/ExpressionCompiler.cpp | 4 ++-- test/SolidityEndToEndTest.cpp | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 4eed68ea4..775d59a37 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -812,8 +812,8 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const << errinfo_comment("Stack too deep.")); solAssert(stackDiff <= m_size, ""); for (unsigned i = 0; i < m_size; ++i) - *m_context << u256(0) << eth::swapInstruction(stackDiff + (m_size - i) ) << eth::Instruction::POP; - + *m_context << u256(0) << eth::swapInstruction(stackDiff + (m_size - i) ) + << eth::Instruction::POP; break; } case LValue::STORAGE: diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index ad537750e..18fb5e29b 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -818,9 +818,7 @@ BOOST_AUTO_TEST_CASE(deleteStruct) return str.nstr.nestedMapping[index]; } })"; - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("getToDelete()") == encodeArgs(0)); BOOST_CHECK(callContractFunction("getTopValue()") == encodeArgs(0)); BOOST_CHECK(callContractFunction("getNestedValue()") == encodeArgs(0)); @@ -841,7 +839,6 @@ BOOST_AUTO_TEST_CASE(deleteLocal) res = v; } })"; - compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("delLocal()") == encodeArgs(0)); } @@ -857,7 +854,6 @@ BOOST_AUTO_TEST_CASE(deleteLocals) res = w; } })"; - compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("delLocal()") == encodeArgs(6)); } From e1bed0638c4f649f101dc8b6fa8794d68bd0fad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 15:54:58 +0100 Subject: [PATCH 27/40] Fix BYTE instruction --- evmjit/libevmjit/Compiler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 26c78b4ca..39d480491 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -394,7 +394,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode value = Endianness::toBE(m_builder, value); auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); - auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); + auto safeByteNum = m_builder.CreateZExt(m_builder.CreateTrunc(byteNum, m_builder.getIntNTy(5)), Type::lowPrecision); // Trim index, large values can crash + auto byte = m_builder.CreateExtractElement(bytes, safeByteNum, "byte"); value = m_builder.CreateZExt(byte, Type::Word); auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); From d70b70a88bd86ef51db9e5bbc630b04ea3860c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 15:56:05 +0100 Subject: [PATCH 28/40] Rename env_getExtCode -> env_extcode according to other renames --- evmjit/libevmjit-cpp/Env.cpp | 2 +- evmjit/libevmjit/Ext.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index 6320aa222..90474c7e4 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -89,7 +89,7 @@ extern "C" *o_hash = hash; } - EXPORT byte const* env_getExtCode(ExtVMFace* _env, h256* _addr256, uint64_t* o_size) + EXPORT byte const* env_extcode(ExtVMFace* _env, h256* _addr256, uint64_t* o_size) { auto addr = right160(*_addr256); auto& code = _env->codeAt(addr); diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index 7d084a450..a37a6fe99 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -5,9 +5,6 @@ #include #include -//#include -//#include - #include "RuntimeManager.h" #include "Memory.h" #include "Type.h" @@ -71,7 +68,6 @@ llvm::Value* Ext::getArgAlloca() getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); } - return a; } From 3feeb190d3a8d65b2819392c8b66bd1cdbced9c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 16:06:35 +0100 Subject: [PATCH 29/40] Environment variable options for EVM JIT: export EVMJIT_CACHE_OFF=1 disables cache export EVMJIT_DUMP_MODULE=1 dumps LLVM module to standard output --- evmjit/libevmjit/ExecutionEngine.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 71142fbee..1f87c8b58 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,14 @@ #include "Compiler.h" #include "Cache.h" +#if defined(NDEBUG) +#define DEBUG_ENV_OPTION(name) false +#else +#include +#define DEBUG_ENV_OPTION(name) (std::getenv(#name) != nullptr) +#endif + + extern "C" void env_sha3(dev::eth::jit::byte const* _begin, uint64_t _size, std::array* o_hash); namespace dev @@ -64,6 +72,8 @@ std::string codeHash(bytes const& _code) ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? + static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE); + static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF); auto mainFuncName = codeHash(_code); EntryFuncPtr entryFuncPtr{}; @@ -74,14 +84,14 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en } 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 (debugDumpModule) + module->dump(); if (!ee) { llvm::InitializeNativeTarget(); @@ -92,7 +102,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::Default); + builder.setOptLevel(llvm::CodeGenOpt::None); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) From 7651909bdff3bf02dac9c5a0fa7766518e1450ac Mon Sep 17 00:00:00 2001 From: liana Date: Fri, 16 Jan 2015 16:26:57 +0100 Subject: [PATCH 30/40] - corrected delete in case we have more than one locals - added a test --- libsolidity/ExpressionCompiler.cpp | 4 ++-- test/SolidityEndToEndTest.cpp | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 775d59a37..b90032daa 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -810,9 +810,9 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const if (stackDiff > 16) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Stack too deep.")); - solAssert(stackDiff <= m_size, ""); + solAssert(stackDiff >= m_size - 1, ""); for (unsigned i = 0; i < m_size; ++i) - *m_context << u256(0) << eth::swapInstruction(stackDiff + (m_size - i) ) + *m_context << u256(0) << eth::swapInstruction(stackDiff + 1 - i) << eth::Instruction::POP; break; } diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 18fb5e29b..eb8b22a97 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -847,15 +847,17 @@ BOOST_AUTO_TEST_CASE(deleteLocals) { char const* sourceCode = R"( contract test { - function delLocal() returns (uint res){ + function delLocal() returns (uint res1, uint res2){ uint v = 5; uint w = 6; + uint x = 7; delete v; - res = w; + res1 = w; + res2 = x; } })"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("delLocal()") == encodeArgs(6)); + BOOST_CHECK(callContractFunction("delLocal()") == encodeArgs(6, 7)); } BOOST_AUTO_TEST_CASE(constructor) From 0edaef0cfd1057c85364c6039a35a9989026cdac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 18:02:36 +0100 Subject: [PATCH 31/40] JUMPI fix: an additional item was left on stack when condition is false --- evmjit/libevmjit/BasicBlock.h | 6 ++++++ evmjit/libevmjit/Compiler.cpp | 26 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index 3591a6f54..cda4f89bd 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -66,6 +66,9 @@ public: bool isJumpDest() const { return m_isJumpDest; } + llvm::Value* getJumpTarget() const { return m_jumpTarget; } + void setJumpTarget(llvm::Value* _jumpTarget) { m_jumpTarget = _jumpTarget; } + LocalStack& localStack() { return m_stack; } /// Optimization: propagates values between local stacks in basic blocks @@ -112,6 +115,9 @@ private: /// Is the basic block a valid jump destination. /// JUMPDEST is the first instruction of the basic block. bool const m_isJumpDest = false; + + /// If block finishes with dynamic jump target index is stored here + llvm::Value* m_jumpTarget = nullptr; }; } diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 39d480491..1d00fd225 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -100,7 +100,7 @@ llvm::BasicBlock* Compiler::getJumpTableBlock() 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 dest = m_builder.CreatePHI(Type::Word, 8, "target"); auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); for (auto&& p : m_basicBlocks) { @@ -165,6 +165,26 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str removeDeadBlocks(); + // Link jump table target index + if (m_jumpTableBlock) + { + auto phi = llvm::cast(&m_jumpTableBlock->llvm()->getInstList().front()); + for (auto predIt = llvm::pred_begin(m_jumpTableBlock->llvm()); predIt != llvm::pred_end(m_jumpTableBlock->llvm()); ++predIt) + { + BasicBlock* pred = nullptr; + for (auto&& p : m_basicBlocks) + { + if (p.second.llvm() == *predIt) + { + pred = &p.second; + break; + } + } + + phi->addIncoming(pred->getJumpTarget(), pred->llvm()); + } + } + dumpCFGifRequired("blocks-init.dot"); if (m_options.optimizeStack) @@ -565,7 +585,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode } else { - stack.push(target); + _basicBlock.setJumpTarget(target); m_builder.CreateBr(getJumpTableBlock()); } } @@ -581,7 +601,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode } else { - stack.push(target); + _basicBlock.setJumpTarget(target); m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); } } From 889dd8b835f88f5128094cdfff48b04885000c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 22:06:07 +0100 Subject: [PATCH 32/40] Remove env_sha3 symbol reference in evmjit shared library to be build with no unresolved symbols --- evmjit/CMakeLists.txt | 9 +++++---- evmjit/libevmjit/ExecutionEngine.cpp | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index 25c62ff2f..519346007 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -4,13 +4,14 @@ project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") -else () +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") +else() set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -fPIC") endif() -if(APPLE) - set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + # Do not allow unresovled symbols in shared library (default on linux) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") endif() # LLVM diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 1f87c8b58..b6b140fd5 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -26,9 +26,6 @@ #define DEBUG_ENV_OPTION(name) (std::getenv(#name) != nullptr) #endif - -extern "C" void env_sha3(dev::eth::jit::byte const* _begin, uint64_t _size, std::array* o_hash); - namespace dev { namespace eth @@ -57,14 +54,17 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) 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(); + uint32_t hash = 0; + for (auto b : _code) + { + hash += b; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return std::to_string(hash); } } From f379b238ee326435aed5a07706b87296b477a05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 16 Jan 2015 22:41:47 +0100 Subject: [PATCH 33/40] Limited old cached objects detection --- evmjit/libevmjit/Cache.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index 0b725bc24..0e6fb517a 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -36,6 +36,20 @@ std::unique_ptr Cache::getObject(std::string const& id) llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); +#if defined(__GNUC__) && !defined(NDEBUG) + llvm::sys::fs::file_status st; + auto err = llvm::sys::fs::status(cachePath.str(), st); + if (err) + return nullptr; + auto mtime = st.getLastModificationTime().toEpochTime(); + + std::tm tm; + strptime(__DATE__ __TIME__, " %b %d %Y %H:%M:%S", &tm); + auto btime = (uint64_t)std::mktime(&tm); + if (btime > mtime) + return nullptr; +#endif + 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)) From e7b40e5bdc3338f5bba7bd61b2866ffb35b0a28b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 16 Jan 2015 18:06:58 -0500 Subject: [PATCH 34/40] Fix whitespace :-/ --- alethzero/MainWin.cpp | 4 ++-- exp/main.cpp | 6 +++--- libethereum/Executive.cpp | 2 +- libethereum/State.cpp | 30 +++++++++++++++--------------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 66c66face..7ed961a77 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -344,8 +344,8 @@ void Main::onNewBlock() refreshBlockChain(); refreshAccounts(); - // We must update balances since we can't filter updates to basic accounts. - refreshBalances(); + // We must update balances since we can't filter updates to basic accounts. + refreshBalances(); } void Main::onNewPending() diff --git a/exp/main.cpp b/exp/main.cpp index d5070f778..80f4fa37d 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -78,7 +78,7 @@ int main() #elif 0 int main() { - KeyPair u = KeyPair::create(); + KeyPair u = KeyPair::create(); KeyPair cb = KeyPair::create(); OverlayDB db; State s(cb.address(), db, BaseState::Empty); @@ -98,8 +98,8 @@ int main() #else int main() { - cnote << KeyPair(Secret("0000000000000000000000000000000000000000000000000000000000000000")).address(); - cnote << KeyPair(Secret("1111111111111111111111111111111111111111111111111111111111111111")).address(); + cnote << KeyPair(Secret("0000000000000000000000000000000000000000000000000000000000000000")).address(); + cnote << KeyPair(Secret("1111111111111111111111111111111111111111111111111111111111111111")).address(); } #endif diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 476f096e2..4eed2b284 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -35,7 +35,7 @@ using namespace dev::eth; Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), - m_lastHashes(_s.getLastHashes(_bc, (unsigned)_s.info().number - 1)), + m_lastHashes(_s.getLastHashes(_bc, (unsigned)_s.info().number - 1)), m_depth(_level) {} diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 7e2429417..72a15b5d7 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -418,7 +418,7 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bo TransactionReceipts ret; auto ts = _tq.transactions(); - auto lh = getLastHashes(_bc, _bc.number()); + auto lh = getLastHashes(_bc, _bc.number()); for (int goodTxs = 1; goodTxs;) { @@ -498,7 +498,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) GenericTrieDB receiptsTrie(&rm); receiptsTrie.init(); - LastHashes lh = getLastHashes(_bc, (unsigned)m_previousBlock.number); + LastHashes lh = getLastHashes(_bc, (unsigned)m_previousBlock.number); // All ok with the block generally. Play back the transactions now... unsigned i = 0; @@ -527,7 +527,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) cwarn << "Bad receipts state root."; cwarn << "Block:" << toHex(_block); cwarn << "Block RLP:" << RLP(_block); - cwarn << "Calculated: " << receiptsTrie.root(); + cwarn << "Calculated: " << receiptsTrie.root(); for (unsigned j = 0; j < i; ++j) { RLPStream k; @@ -539,15 +539,15 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) cwarn << TransactionReceipt(&b); } cwarn << "Recorded: " << m_currentBlock.receiptsRoot; - auto rs = _bc.receipts(bi.hash); - for (unsigned j = 0; j < rs.receipts.size(); ++j) - { - auto b = rs.receipts[j].rlp(); - cwarn << j << ": "; - cwarn << "RLP: " << RLP(b); - cwarn << "Hex: " << toHex(b); - cwarn << rs.receipts[j]; - } + auto rs = _bc.receipts(bi.hash); + for (unsigned j = 0; j < rs.receipts.size(); ++j) + { + auto b = rs.receipts[j].rlp(); + cwarn << j << ": "; + cwarn << "RLP: " << RLP(b); + cwarn << "Hex: " << toHex(b); + cwarn << rs.receipts[j]; + } BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot()); } @@ -1016,7 +1016,7 @@ LastHashes State::getLastHashes(BlockChain const& _bc, unsigned _n) const ret.resize(256); if (c_protocolVersion > 49) { - ret[0] = _bc.numberHash(_n); + ret[0] = _bc.numberHash(_n); for (unsigned i = 1; i < 256; ++i) ret[i] = ret[i - 1] ? _bc.details(ret[i - 1]).parent : h256(); } @@ -1025,12 +1025,12 @@ LastHashes State::getLastHashes(BlockChain const& _bc, unsigned _n) const u256 State::execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output, bool _commit) { - return execute(getLastHashes(_bc, _bc.number()), &_rlp, o_output, _commit); + return execute(getLastHashes(_bc, _bc.number()), &_rlp, o_output, _commit); } u256 State::execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output, bool _commit) { - return execute(getLastHashes(_bc, _bc.number()), _rlp, o_output, _commit); + return execute(getLastHashes(_bc, _bc.number()), _rlp, o_output, _commit); } // TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations. From 14eaec043156dca277b52652ab07d1d9222c907d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 16 Jan 2015 18:31:38 -0500 Subject: [PATCH 35/40] Fix warnings. --- libdevcrypto/CryptoPP.cpp | 2 ++ libethereum/State.h | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index acd59184f..2d0170fb9 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -199,6 +199,8 @@ bool Secp256k1::verifySecret(Secret const& _s, Public& _p) void Secp256k1::agree(Secret const& _s, Public const& _r, h256& o_s) { + (void)o_s; + (void)_s; ECDH::Domain d(m_oid); assert(d.AgreedValueLength() == sizeof(o_s)); byte remote[65] = {0x04}; diff --git a/libethereum/State.h b/libethereum/State.h index 462989e4a..85abd9366 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -147,12 +147,12 @@ public: /// Like sync but only operate on _tq, killing the invalid/old ones. bool cull(TransactionQueue& _tq) const; - LastHashes getLastHashes(BlockChain const& _bc, unsigned _n) const; + LastHashes getLastHashes(BlockChain const& _bc, unsigned _n) const; /// Execute a given transaction. /// This will append @a _t to the transaction list and change the state accordingly. - u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true); - u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true); + u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true); + u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true); u256 execute(LastHashes const& _lh, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(_lh, &_rlp, o_output, _commit); } u256 execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true); From 0ed443c10272d6f7b0c368733ddeaf90ca77f21e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 16 Jan 2015 18:51:10 -0500 Subject: [PATCH 36/40] Fix release builds. --- libethereum/State.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 72a15b5d7..9ed9a3a3a 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -539,7 +539,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) cwarn << TransactionReceipt(&b); } cwarn << "Recorded: " << m_currentBlock.receiptsRoot; - auto rs = _bc.receipts(bi.hash); + auto rs = _bc.receipts(m_currentBlock.hash); for (unsigned j = 0; j < rs.receipts.size(); ++j) { auto b = rs.receipts[j].rlp(); From c572b713df1fba5e2c3d0ffbf3c2fa0f1c15c347 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 17 Jan 2015 09:39:36 -0500 Subject: [PATCH 37/40] Warnings fixes. --- libdevcore/CommonData.h | 4 ++++ libethcore/Exceptions.cpp | 12 ++++-------- libevm/VM.cpp | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 2573995c5..dada9dd5d 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -124,6 +124,10 @@ inline bytes toCompactBigEndian(_T _val, unsigned _min = 0) toBigEndian(_val, ret); return ret; } +inline bytes toCompactBigEndian(byte _val, unsigned _min = 0) +{ + return (_min || _val) ? bytes{ _val } : bytes{}; +} /// Convenience function for toBigEndian. /// @returns a string just big enough to represent @a _val. diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index b0aff4551..b5d01d3fc 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -27,16 +27,12 @@ using namespace std; using namespace dev; using namespace dev::eth; -#if ALL_COMPILERS_ARE_CPP11_COMPLIANT -#define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str(); -#else -#define ETH_RETURN_STRING(S) \ - static boost::thread_specific_ptr s_what; \ - if (!s_what.get()) \ - s_what.reset(new string); \ - *s_what = S; return s_what->c_str(); +#if _MSC_VER +#define thread_local __declspec( thread ) #endif +#define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str(); + const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } const char* InvalidTransactionsHash::what() const noexcept { ETH_RETURN_STRING("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())); } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index aa3caff44..45017db9c 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -38,10 +38,12 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) 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) From d3ade37e63cfe3e55c86387abf8775b929fb1f48 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 17 Jan 2015 09:44:09 -0500 Subject: [PATCH 38/40] Potential workaround for windows build. --- libsolidity/Token.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index e5c61c7e4..9fb86e7f4 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -48,7 +48,8 @@ #include #if defined(DELETE) -#error The macro "DELETE" from windows.h conflicts with this file. Please change the order of includes. +#undef DELETE +//#error The macro "DELETE" from windows.h conflicts with this file. Please change the order of includes. #endif namespace dev From e643fb3039707c29bbdd5a8eb80a57614b911a10 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 17 Jan 2015 10:34:44 -0500 Subject: [PATCH 39/40] Warnings fix. --- libsolidity/ASTJsonConverter.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 7d9b9bc04..cb43c2d9e 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -129,7 +129,6 @@ private: std::stack m_jsonNodePtrs; std::string m_source; ASTNode const* m_ast; - int m_depth; }; } From 565e3f19fff98766360b383ff90b92a96231e94a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 19 Jan 2015 08:43:15 -0800 Subject: [PATCH 40/40] Compile fix for Apple's handicapped clang. --- libdevcore/Exceptions.h | 2 +- libethcore/Exceptions.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 061f181b3..e13d41476 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -31,7 +31,7 @@ namespace dev { // base class for all exceptions -struct Exception: virtual std::exception, virtual boost::exception {}; +struct Exception: virtual std::exception, virtual boost::exception { mutable std::string m_message; }; struct BadHexCharacter: virtual Exception {}; struct RLPException: virtual Exception {}; diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index b5d01d3fc..9b07743c5 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -27,11 +27,14 @@ using namespace std; using namespace dev; using namespace dev::eth; -#if _MSC_VER -#define thread_local __declspec( thread ) -#endif - +#if ALL_COMPILERS_ARE_CPP11 #define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str(); +#elsif USE_BOOST_TLS +static boost::thread_specific_ptr g_exceptionMessage; +#define ETH_RETURN_STRING(S) if (!g_exceptionMessage.get()); g_exceptionMessage.reset(new string); *g_exceptionMessage.get() = S; return g_exceptionMessage.get()->c_str(); +#else +#define ETH_RETURN_STRING(S) m_message = S; return m_message.c_str(); +#endif const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); }