Browse Source

Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop

cl-refactor
Gav Wood 10 years ago
parent
commit
5dde4216a1
  1. 1
      .gitignore
  2. 4
      CMakeLists.txt
  3. 1
      evmjit/.gitignore
  4. 24
      evmjit/CMakeLists.txt
  5. 2
      evmjit/libevmjit-cpp/Env.cpp
  6. 8
      evmjit/libevmjit/BasicBlock.h
  7. 11
      evmjit/libevmjit/CMakeLists.txt
  8. 14
      evmjit/libevmjit/Cache.cpp
  9. 29
      evmjit/libevmjit/Compiler.cpp
  10. 34
      evmjit/libevmjit/ExecutionEngine.cpp
  11. 11
      evmjit/libevmjit/Ext.cpp
  12. 2
      evmjit/libevmjit/Runtime.h
  13. 34
      evmjit/libevmjit/interface.cpp
  14. 24
      evmjit/libevmjit/interface.h

1
.gitignore

@ -65,7 +65,6 @@ DerivedData
project.pbxproj
evmjit
doc/html
*.autosave
node_modules/

4
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()

1
evmjit/.gitignore

@ -0,0 +1 @@
/build/

24
evmjit/CMakeLists.txt

@ -4,8 +4,18 @@ 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 -fPIC")
endif()
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
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}")
@ -18,11 +28,19 @@ 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)
link_directories(/usr/lib/llvm-3.5/lib)
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()

2
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);

8
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; }
@ -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;
};
}

11
evmjit/libevmjit/CMakeLists.txt

@ -2,23 +2,24 @@ 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()
add_library(${TARGET_NAME} ${SOURCES} ${HEADERS})
add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS})
set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs")
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${LLVM_LIBS})
target_link_libraries(${TARGET_NAME} PRIVATE ${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})

14
evmjit/libevmjit/Cache.cpp

@ -36,6 +36,20 @@ std::unique_ptr<llvm::Module> 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))

29
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<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
removeDeadBlocks();
// Link jump table target index
if (m_jumpTableBlock)
{
auto phi = llvm::cast<llvm::PHINode>(&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)
@ -394,7 +414,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));
@ -564,7 +585,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
}
else
{
stack.push(target);
_basicBlock.setJumpTarget(target);
m_builder.CreateBr(getJumpTableBlock());
}
}
@ -580,7 +601,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
}
else
{
stack.push(target);
_basicBlock.setJumpTarget(target);
m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock);
}
}

34
evmjit/libevmjit/ExecutionEngine.cpp

@ -19,7 +19,12 @@
#include "Compiler.h"
#include "Cache.h"
extern "C" void env_sha3(dev::eth::jit::byte const* _begin, uint64_t _size, std::array<dev::eth::jit::byte, 32>* o_hash);
#if defined(NDEBUG)
#define DEBUG_ENV_OPTION(name) false
#else
#include <cstdlib>
#define DEBUG_ENV_OPTION(name) (std::getenv(#name) != nullptr)
#endif
namespace dev
{
@ -49,14 +54,17 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime)
std::string codeHash(bytes const& _code)
{
std::array<dev::eth::jit::byte, 32> 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<decltype(i)>::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);
}
}
@ -64,6 +72,8 @@ std::string codeHash(bytes const& _code)
ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env)
{
static std::unique_ptr<llvm::ExecutionEngine> 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<llvm::Module> 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<llvm::SectionMemoryManager> 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)

11
evmjit/libevmjit/Ext.cpp

@ -5,9 +5,6 @@
#include <llvm/IR/TypeBuilder.h>
#include <llvm/IR/IntrinsicInst.h>
//#include <libdevcrypto/SHA3.h>
//#include <libevm/FeeStructure.h>
#include "RuntimeManager.h"
#include "Memory.h"
#include "Type.h"
@ -23,12 +20,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");
}
@ -74,7 +68,6 @@ llvm::Value* Ext::getArgAlloca()
getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI());
a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg");
}
return a;
}

2
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; }

34
evmjit/libevmjit/interface.cpp

@ -0,0 +1,34 @@
#include "interface.h"
#include <cstdio>
#include "ExecutionEngine.h"
extern "C"
{
evmjit_result evmjit_run(void* _data, void* _env)
{
using namespace dev::eth::jit;
auto data = static_cast<RuntimeData*>(_data);
ExecutionEngine engine;
auto codePtr = data->code;
auto codeSize = data->elems[RuntimeData::CodeSize].a;
bytes bytecode;
bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize);
auto returnCode = engine.run(bytecode, data, static_cast<Env*>(_env));
evmjit_result result = {static_cast<int32_t>(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;
}
}

24
evmjit/libevmjit/interface.c → evmjit/libevmjit/interface.h

@ -1,5 +1,20 @@
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
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;
@ -9,6 +24,11 @@ typedef int evm_jit_return_code;
// Host-endian 256-bit integer type
typedef struct i256 i256;
struct i256
{
char b[33];
};
// Big-endian right aligned 256-bit hash
typedef struct h256 h256;
@ -28,3 +48,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
Loading…
Cancel
Save