From 6d337d274aa308b4e76bfb2b8b274021a6aa1679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 26 Feb 2015 14:59:57 +0100 Subject: [PATCH] Using Array as a second memory --- libevmjit/Array.cpp | 85 +++++++++++++++++++++++++++++++---- libevmjit/Array.h | 21 ++++++--- libevmjit/ExecutionEngine.cpp | 5 +++ libevmjit/Memory.cpp | 29 ++++++++---- libevmjit/Runtime.h | 1 + 5 files changed, 117 insertions(+), 24 deletions(-) diff --git a/libevmjit/Array.cpp b/libevmjit/Array.cpp index b44e4e174..1c0fff098 100644 --- a/libevmjit/Array.cpp +++ b/libevmjit/Array.cpp @@ -1,6 +1,7 @@ #include "Array.h" #include "preprocessor/llvm_includes_start.h" +#include #include #include "preprocessor/llvm_includes_end.h" @@ -20,12 +21,12 @@ namespace jit static const auto c_reallocStep = 1; static const auto c_reallocMultipier = 2; -llvm::Value* LazyFunction::call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args) +llvm::Value* LazyFunction::call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args, llvm::Twine const& _name) { if (!m_func) m_func = m_creator(); - return _builder.CreateCall(m_func, {_args.begin(), _args.size()}); + return _builder.CreateCall(m_func, {_args.begin(), _args.size()}, _name); } llvm::Function* Array::createArrayPushFunc() @@ -35,12 +36,6 @@ llvm::Function* Array::createArrayPushFunc() func->setDoesNotThrow(); func->setDoesNotCapture(1); - llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size}; - auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule()); - reallocFunc->setDoesNotThrow(); - reallocFunc->setDoesNotAlias(0); - reallocFunc->setDoesNotCapture(1); - auto arrayPtr = &func->getArgumentList().front(); arrayPtr->setName("arrayPtr"); auto value = arrayPtr->getNextNode(); @@ -66,7 +61,7 @@ llvm::Function* Array::createArrayPushFunc() //newCap = m_builder.CreateNUWMul(newCap, m_builder.getInt64(c_reallocMultipier)); auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32 auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes"); - auto newBytes = m_builder.CreateCall2(reallocFunc, bytes, reallocSize, "newBytes"); + auto newBytes = m_reallocFunc.call(m_builder, {bytes, reallocSize}, "newBytes"); auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData"); m_builder.CreateStore(newData, dataPtr); m_builder.CreateStore(newCap, capPtr); @@ -131,6 +126,28 @@ llvm::Function* Array::createArrayGetFunc() return func; } +llvm::Function* Array::createGetPtrFunc() +{ + llvm::Type* argTypes[] = {m_array->getType(), Type::Size}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::PrivateLinkage, "array.getPtr", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto index = arrayPtr->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto bytePtr = m_builder.CreateGEP(data, index, "bytePtr"); + auto wordPtr = m_builder.CreateBitCast(bytePtr, Type::WordPtr, "wordPtr"); + m_builder.CreateRet(wordPtr); + return func; +} + llvm::Function* Array::createFreeFunc() { auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, m_array->getType(), false), llvm::Function::PrivateLinkage, "array.free", getModule()); @@ -154,6 +171,49 @@ llvm::Function* Array::createFreeFunc() return func; } +llvm::Function* Array::getReallocFunc() +{ + if (auto func = getModule()->getFunction("ext_realloc")) + return func; + + llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size}; + auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule()); + reallocFunc->setDoesNotThrow(); + reallocFunc->setDoesNotAlias(0); + reallocFunc->setDoesNotCapture(1); + return reallocFunc; +} + +llvm::Function* Array::createExtendFunc() +{ + llvm::Type* argTypes[] = {m_array->getType(), Type::Size}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.extend", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto newSize = arrayPtr->getNextNode(); + newSize->setName("newSize"); + + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array + auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr"); + auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto size = m_builder.CreateLoad(sizePtr, "size"); + auto extSize = m_builder.CreateNUWSub(newSize, size, "extSize"); + auto newData = m_reallocFunc.call(m_builder, {data, newSize}, "newData"); // TODO: Check realloc result for null + auto extPtr = m_builder.CreateGEP(newData, size, "extPtr"); + m_builder.CreateMemSet(extPtr, m_builder.getInt8(0), extSize, 16); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateStore(newSize, sizePtr); + m_builder.CreateStore(newSize, capPtr); + m_builder.CreateRetVoid(); + return func; +} + llvm::Type* Array::getType() { llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size}; @@ -196,6 +256,13 @@ llvm::Value* Array::size() return m_builder.CreateLoad(sizePtr, "array.size"); } +void Array::extend(llvm::Value* _arrayPtr, llvm::Value* _size) +{ + assert(_arrayPtr->getType() == m_array->getType()); + assert(_size->getType() == Type::Size); + m_extendFunc.call(m_builder, {_arrayPtr, _size}); +} + } } } diff --git a/libevmjit/Array.h b/libevmjit/Array.h index 0cd7abb17..cab81943a 100644 --- a/libevmjit/Array.h +++ b/libevmjit/Array.h @@ -20,7 +20,7 @@ public: m_creator(_creator) {} - llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args); + llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args, llvm::Twine const& _name = {}); private: llvm::Function* m_func = nullptr; @@ -40,6 +40,9 @@ public: llvm::Value* size(); void free() { m_freeFunc.call(m_builder, {m_array}); } + void extend(llvm::Value* _arrayPtr, llvm::Value* _size); + llvm::Value* getPtr(llvm::Value* _arrayPtr, llvm::Value* _index) { return m_getPtrFunc.call(m_builder, {_arrayPtr, _index}); } + llvm::Value* getPointerTo() const { return m_array; } static llvm::Type* getType(); @@ -47,15 +50,21 @@ public: private: llvm::Value* m_array = nullptr; - LazyFunction m_pushFunc; - LazyFunction m_setFunc; - LazyFunction m_getFunc; - LazyFunction m_freeFunc; - llvm::Function* createArrayPushFunc(); llvm::Function* createArraySetFunc(); llvm::Function* createArrayGetFunc(); + llvm::Function* createGetPtrFunc(); llvm::Function* createFreeFunc(); + llvm::Function* createExtendFunc(); + llvm::Function* getReallocFunc(); + + LazyFunction m_pushFunc = {[this](){ return createArrayPushFunc(); }}; // TODO: If works on MSVC, remove form initialization list + LazyFunction m_setFunc; + LazyFunction m_getPtrFunc = {[this](){ return createGetPtrFunc(); }}; + LazyFunction m_getFunc; + LazyFunction m_freeFunc; + LazyFunction m_extendFunc = {[this](){ return createExtendFunc(); }}; + LazyFunction m_reallocFunc = {[this](){ return getReallocFunc(); }}; }; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index dd8fb7e62..8d091c6f9 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -160,6 +160,11 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) if (g_stats) statsCollector.stats.push_back(std::move(listener)); + if (runtime.m_memData) + { + std::cerr << "MEM: " << (size_t) runtime.m_memData << " [" << runtime.m_memSize << ", " << runtime.m_memCap << "}\n"; + } + return returnCode; } diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index db4c36c70..a90b20032 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -87,6 +87,8 @@ llvm::Function* Memory::getRequireFunc() auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData"); auto dataPtr = m_builder.CreateStructGEP(rtPtr, 2); m_builder.CreateStore(newData, dataPtr); + auto extendSize = m_builder.CreateTrunc(sizeRequired, Type::Size, "extendSize"); + m_memory.extend(mem, extendSize); m_builder.CreateBr(returnBB); // BB "Return" @@ -100,8 +102,8 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType) { auto isWord = _valueType == Type::Word; - llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; - llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType, Array::getType()->getPointerTo()}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word, Array::getType()->getPointerTo()}; auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); @@ -119,15 +121,24 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType) ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); if (_isStore) { - llvm::Value* value = index->getNextNode(); - value->setName("value"); - if (isWord) - value = Endianness::toBE(m_builder, value); + auto valueArg = index->getNextNode(); + valueArg->setName("value"); + auto mem = valueArg->getNextNode(); + mem->setName("mem"); + auto value = isWord ? Endianness::toBE(m_builder, valueArg) : valueArg; m_builder.CreateStore(value, ptr); + auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size)); + auto valuePtr = m_builder.CreateBitCast(memPtr, _valueType->getPointerTo(), "valuePtr"); + m_builder.CreateStore(value, valuePtr); m_builder.CreateRetVoid(); } else { + auto mem = index->getNextNode(); + mem->setName("mem"); + auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size)); + + llvm::Value* ret = m_builder.CreateLoad(ptr); ret = Endianness::toNative(m_builder, ret); m_builder.CreateRet(ret); @@ -164,20 +175,20 @@ llvm::Function* Memory::getStoreByteFunc() llvm::Value* Memory::loadWord(llvm::Value* _addr) { require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8)); - return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, getRuntimeManager().getMem()}); } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8)); - createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word}); + createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word, getRuntimeManager().getMem()}); } void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) { require(_addr, Constant::get(Type::Byte->getPrimitiveSizeInBits() / 8)); auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte, getRuntimeManager().getMem()}); } llvm::Value* Memory::getData() diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 55b84d575..fb612fb9d 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -27,6 +27,7 @@ private: Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. byte* m_memoryData = nullptr; i256 m_memorySize; +public: byte* m_memData = nullptr; uint64_t m_memSize = 0; uint64_t m_memCap = 0;