From 0a642457f7c821f0ae5f233f518fe749f521faee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 17:53:06 +0100 Subject: [PATCH 1/4] Fix checking memory requirements with size 0 --- libevmjit/Memory.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 18d53e63e..116840684 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -60,12 +60,18 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _ auto size = offset->getNextNode(); size->setName("size"); + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); InsertPointGuard guard(m_builder); // Restores insert point at function exit + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + // BB "Check" m_builder.SetInsertPoint(checkBB); auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); From b37ce8e9727683b8c7afb84520f42a908318f8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 17 Dec 2014 17:54:51 +0100 Subject: [PATCH 2/4] Gas counting for CREATE instruction --- libevmjit-cpp/Env.cpp | 5 +++-- libevmjit/Compiler.cpp | 6 +++++- libevmjit/Ext.cpp | 10 ++++++---- libevmjit/Ext.h | 2 +- libevmjit/GasMeter.cpp | 3 +-- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index def2e5693..ca3ed2b92 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -47,7 +47,7 @@ extern "C" _env->suicide(right160(*_address)); } - EXPORT void env_create(ExtVMFace* _env, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { assert(_env->depth < 1024); // TODO: Handle call depth @@ -56,9 +56,10 @@ extern "C" if (_env->balance(_env->myAddress) >= endowment) { _env->subBalance(endowment); - u256 gas; // TODO: Handle gas + auto gas = llvm2eth(*io_gas); OnOpFunc onOp {}; // TODO: Handle that thing h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); + *io_gas = eth2llvm(gas); *o_address = address; } else diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 3a0d8d034..80bd647ad 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -741,7 +741,11 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto initSize = stack.pop(); _memory.require(initOff, initSize); - auto address = _ext.create(endowment, initOff, initSize); + _gasMeter.commitCostBlock(); + + auto gas = _runtimeManager.getGas(); + auto address = _ext.create(gas, endowment, initOff, initSize); + _runtimeManager.setGas(gas); stack.push(address); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 3955d21cd..139255a6a 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -52,7 +52,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); - llvm::Type* createArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr}; + llvm::Type* createArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr}; m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, createArgsTypes, false), Linkage::ExternalLinkage, "env_create", module); llvm::Type* callArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr}; @@ -106,12 +106,14 @@ void Ext::suicide(llvm::Value* _address) m_builder.CreateCall2(m_suicide, getRuntimeManager().getEnv(), m_args[0]); } -llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - m_builder.CreateStore(_endowment, m_args[0]); + m_builder.CreateStore(_gas, m_args[0]); + m_builder.CreateStore(_endowment, m_arg2); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(m_create, getRuntimeManager().getEnv(), m_args[0], begin, size, m_args[1]); + createCall(m_create, getRuntimeManager().getEnv(), m_args[0], m_arg2, begin, size, m_args[1]); + _gas = m_builder.CreateLoad(m_args[0]); // Return gas llvm::Value* address = m_builder.CreateLoad(m_args[1]); address = Endianness::toNative(m_builder, address); return address; diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 21e67ba88..b68e09c03 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -29,7 +29,7 @@ public: llvm::Value* balance(llvm::Value* _address); void suicide(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); - llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 3eb16899a..ce53bfc26 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -83,7 +83,7 @@ bool isCostBlockEnd(Instruction _inst) // Basic block terminators like STOP are not needed on the list // as cost will be commited at the end of basic block - // CALL & CALLCODE are commited manually + // CALL, CALLCODE & CREATE are commited manually switch (_inst) { @@ -94,7 +94,6 @@ bool isCostBlockEnd(Instruction _inst) case Instruction::MSTORE8: case Instruction::SSTORE: case Instruction::GAS: - case Instruction::CREATE: return true; default: From bd85efa299e661228a1ac6283b5fad14e09f88d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Dec 2014 13:00:59 +0100 Subject: [PATCH 3/4] Execution Engine cleanups --- libevmjit/ExecutionEngine.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index fd217e4ee..022fe9f0e 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -53,15 +53,11 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa static const auto program = "EVM JIT"; llvm::PrettyStackTraceProgram X(1, &program); - llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); - llvm::InitializeNativeTargetAsmParser(); llvm::EngineBuilder builder(module); builder.setEngineKind(llvm::EngineKind::JIT); builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); builder.setOptLevel(llvm::CodeGenOpt::None); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); @@ -74,7 +70,6 @@ ReturnCode ExecutionEngine::run(std::unique_ptr _module, RuntimeDa if (!exec.engine) return ReturnCode::LLVMConfigError; _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager // TODO: Finalization not needed when llvm::ExecutionEngine::getFunctionAddress used //auto finalizationStartTime = std::chrono::high_resolution_clock::now(); From 2332595c9c0d315dc9ecde22d236ae477b931863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Dec 2014 13:01:45 +0100 Subject: [PATCH 4/4] Change the name of a module to some hash (for caching) --- libevmjit/Compiler.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 80bd647ad..20b17e9fe 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -1,6 +1,7 @@ #include "Compiler.h" +#include #include #include @@ -153,8 +154,13 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) std::unique_ptr Compiler::compile(bytes const& _bytecode) { + // TODO: Better hash of code needed, probably SHA3 + std::string code{reinterpret_cast(_bytecode.data()), _bytecode.size()}; + auto hash = std::hash{}(code); + auto strHash = std::to_string(hash); + auto compilationStartTime = std::chrono::high_resolution_clock::now(); - auto module = std::unique_ptr(new llvm::Module("main", m_builder.getContext())); + auto module = std::unique_ptr(new llvm::Module(strHash, m_builder.getContext())); // Create main function auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, Type::RuntimePtr, false);