Browse Source

Free memory allocated for dynamic stack

cl-refactor
Paweł Bylica 10 years ago
parent
commit
681ba24d33
  1. 23
      evmjit/libevmjit/Compiler.cpp
  2. 4
      evmjit/libevmjit/Compiler.h
  3. 10
      evmjit/libevmjit/RuntimeManager.cpp
  4. 7
      evmjit/libevmjit/RuntimeManager.h
  5. 62
      evmjit/libevmjit/Stack.cpp
  6. 4
      evmjit/libevmjit/Stack.h

23
evmjit/libevmjit/Compiler.cpp

@ -90,7 +90,7 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn
} }
} }
llvm::BasicBlock* Compiler::getJumpTableBlock() llvm::BasicBlock* Compiler::getJumpTableBlock(RuntimeManager& _runtimeManager)
{ {
if (!m_jumpTableBlock) if (!m_jumpTableBlock)
{ {
@ -98,7 +98,7 @@ llvm::BasicBlock* Compiler::getJumpTableBlock()
InsertPointGuard g{m_builder}; InsertPointGuard g{m_builder};
m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
auto dest = m_builder.CreatePHI(Type::Word, 8, "target"); auto dest = m_builder.CreatePHI(Type::Word, 8, "target");
auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock(_runtimeManager));
for (auto&& p : m_basicBlocks) for (auto&& p : m_basicBlocks)
{ {
if (p.second.isJumpDest()) if (p.second.isJumpDest())
@ -108,14 +108,14 @@ llvm::BasicBlock* Compiler::getJumpTableBlock()
return m_jumpTableBlock->llvm(); return m_jumpTableBlock->llvm();
} }
llvm::BasicBlock* Compiler::getBadJumpBlock() llvm::BasicBlock* Compiler::getBadJumpBlock(RuntimeManager& _runtimeManager)
{ {
if (!m_badJumpBlock) if (!m_badJumpBlock)
{ {
m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true)); m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true));
InsertPointGuard g{m_builder}; InsertPointGuard g{m_builder};
m_builder.SetInsertPoint(m_badJumpBlock->llvm()); m_builder.SetInsertPoint(m_badJumpBlock->llvm());
m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); _runtimeManager.exit(ReturnCode::BadJumpDestination);
} }
return m_badJumpBlock->llvm(); return m_badJumpBlock->llvm();
} }
@ -155,6 +155,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
Memory memory(runtimeManager, gasMeter); Memory memory(runtimeManager, gasMeter);
Ext ext(runtimeManager, memory); Ext ext(runtimeManager, memory);
Stack stack(m_builder, runtimeManager); Stack stack(m_builder, runtimeManager);
runtimeManager.setStack(stack); // Runtime Manager will free stack memory
Arith256 arith(m_builder); Arith256 arith(m_builder);
// TODO: Create Stop basic block on demand // TODO: Create Stop basic block on demand
@ -177,10 +178,10 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
// Code for special blocks: // Code for special blocks:
// TODO: move to separate function. // TODO: move to separate function.
m_builder.SetInsertPoint(m_stopBB); m_builder.SetInsertPoint(m_stopBB);
m_builder.CreateRet(Constant::get(ReturnCode::Stop)); runtimeManager.exit(ReturnCode::Stop);
m_builder.SetInsertPoint(abortBB); m_builder.SetInsertPoint(abortBB);
m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); runtimeManager.exit(ReturnCode::OutOfGas);
removeDeadBlocks(); removeDeadBlocks();
@ -589,7 +590,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
auto&& c = constant->getValue(); auto&& c = constant->getValue();
auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1; auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1;
auto it = m_basicBlocks.find(targetIdx); auto it = m_basicBlocks.find(targetIdx);
targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(); targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(_runtimeManager);
} }
// TODO: Improve; check for constants // TODO: Improve; check for constants
@ -602,7 +603,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
else else
{ {
_basicBlock.setJumpTarget(target); _basicBlock.setJumpTarget(target);
m_builder.CreateBr(getJumpTableBlock()); m_builder.CreateBr(getJumpTableBlock(_runtimeManager));
} }
} }
else // JUMPI else // JUMPI
@ -618,7 +619,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
else else
{ {
_basicBlock.setJumpTarget(target); _basicBlock.setJumpTarget(target);
m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); m_builder.CreateCondBr(cond, getJumpTableBlock(_runtimeManager), _nextBasicBlock);
} }
} }
break; break;
@ -795,14 +796,14 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
_memory.require(index, size); _memory.require(index, size);
_runtimeManager.registerReturnData(index, size); _runtimeManager.registerReturnData(index, size);
m_builder.CreateRet(Constant::get(ReturnCode::Return)); _runtimeManager.exit(ReturnCode::Return);
break; break;
} }
case Instruction::SUICIDE: case Instruction::SUICIDE:
{ {
_runtimeManager.registerSuicide(stack.pop()); _runtimeManager.registerSuicide(stack.pop());
m_builder.CreateRet(Constant::get(ReturnCode::Suicide)); _runtimeManager.exit(ReturnCode::Suicide);
break; break;
} }

4
evmjit/libevmjit/Compiler.h

@ -38,9 +38,9 @@ private:
void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock);
llvm::BasicBlock* getJumpTableBlock(); llvm::BasicBlock* getJumpTableBlock(RuntimeManager& _runtimeManager);
llvm::BasicBlock* getBadJumpBlock(); llvm::BasicBlock* getBadJumpBlock(RuntimeManager& _runtimeManager);
void removeDeadBlocks(); void removeDeadBlocks();

10
evmjit/libevmjit/RuntimeManager.cpp

@ -4,6 +4,8 @@
#include <llvm/IR/IntrinsicInst.h> #include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h" #include "preprocessor/llvm_includes_end.h"
#include "Stack.h"
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -165,6 +167,14 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress)
set(RuntimeData::SuicideDestAddress, _balanceAddress); set(RuntimeData::SuicideDestAddress, _balanceAddress);
} }
void RuntimeManager::exit(ReturnCode _returnCode)
{
if (m_stack)
m_stack->free();
m_builder.CreateRet(Constant::get(_returnCode));
}
void RuntimeManager::abort(llvm::Value* _jmpBuf) void RuntimeManager::abort(llvm::Value* _jmpBuf)
{ {
auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);

7
evmjit/libevmjit/RuntimeManager.h

@ -11,6 +11,7 @@ namespace eth
{ {
namespace jit namespace jit
{ {
class Stack;
class RuntimeManager: public CompilerHelper class RuntimeManager: public CompilerHelper
{ {
@ -35,9 +36,13 @@ public:
void registerReturnData(llvm::Value* _index, llvm::Value* _size); void registerReturnData(llvm::Value* _index, llvm::Value* _size);
void registerSuicide(llvm::Value* _balanceAddress); void registerSuicide(llvm::Value* _balanceAddress);
void exit(ReturnCode _returnCode);
void abort(llvm::Value* _jmpBuf); void abort(llvm::Value* _jmpBuf);
void abort() { abort(getJmpBufExt()); } void abort() { abort(getJmpBufExt()); }
void setStack(Stack& _stack) { m_stack = &_stack; }
static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeType();
static llvm::StructType* getRuntimeDataType(); static llvm::StructType* getRuntimeDataType();
@ -53,6 +58,8 @@ private:
code_iterator m_codeBegin = {}; code_iterator m_codeBegin = {};
code_iterator m_codeEnd = {}; code_iterator m_codeEnd = {};
Stack* m_stack = nullptr;
}; };
} }

62
evmjit/libevmjit/Stack.cpp

@ -8,6 +8,7 @@
#include "Runtime.h" #include "Runtime.h"
#include <iostream> #include <iostream>
#include <set>
namespace dev namespace dev
{ {
@ -35,7 +36,7 @@ llvm::Function* Array::createArrayPushFunc()
func->setDoesNotCapture(1); func->setDoesNotCapture(1);
llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size}; llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size};
auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "realloc", getModule()); auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule());
reallocFunc->setDoesNotThrow(); reallocFunc->setDoesNotThrow();
reallocFunc->setDoesNotAlias(0); reallocFunc->setDoesNotAlias(0);
reallocFunc->setDoesNotCapture(1); reallocFunc->setDoesNotCapture(1);
@ -130,11 +131,35 @@ llvm::Function* Array::createArrayGetFunc()
return func; 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());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::BytePtr, false), llvm::Function::ExternalLinkage, "ext_free", getModule());
freeFunc->setDoesNotThrow();
freeFunc->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem");
m_builder.CreateCall(freeFunc, mem);
m_builder.CreateRetVoid();
return func;
}
Array::Array(llvm::IRBuilder<>& _builder, char const* _name) : Array::Array(llvm::IRBuilder<>& _builder, char const* _name) :
CompilerHelper(_builder), CompilerHelper(_builder),
m_pushFunc([this](){ return createArrayPushFunc(); }), m_pushFunc([this](){ return createArrayPushFunc(); }),
m_setFunc([this](){ return createArraySetFunc(); }), m_setFunc([this](){ return createArraySetFunc(); }),
m_getFunc([this](){ return createArrayGetFunc(); }) m_getFunc([this](){ return createArrayGetFunc(); }),
m_freeFunc([this](){ return createFreeFunc(); })
{ {
llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size}; llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size};
static auto arrayTy = llvm::StructType::create(elementTys, "Array"); static auto arrayTy = llvm::StructType::create(elementTys, "Array");
@ -319,6 +344,22 @@ void Stack::push(llvm::Value* _value)
} }
} }
namespace
{
struct AllocatedMemoryWatchdog
{
std::set<void*> allocatedMemory;
~AllocatedMemoryWatchdog()
{
if (!allocatedMemory.empty())
std::cerr << allocatedMemory.size() << " MEM LEAKS!" << std::endl;
}
};
AllocatedMemoryWatchdog watchdog;
}
extern "C" extern "C"
{ {
using namespace dev::eth::jit; using namespace dev::eth::jit;
@ -349,9 +390,24 @@ extern "C"
{ {
//std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl; //std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl;
auto newData = std::realloc(_data, _size); auto newData = std::realloc(_data, _size);
//std::cerr << "REALLOC: " << _data << " -> " << newData << " [" << _size << "]" << std::endl; if (_data != newData)
{
std::cerr << "REALLOC: " << _data << " -> " << newData << " [" << _size << "]" << std::endl;
watchdog.allocatedMemory.erase(_data);
watchdog.allocatedMemory.insert(newData);
}
return newData; return newData;
} }
EXPORT void ext_free(void* _data)
{
std::free(_data);
if (_data)
{
std::cerr << "FREE : " << _data << std::endl;
watchdog.allocatedMemory.erase(_data);
}
}
} // extern "C" } // extern "C"

4
evmjit/libevmjit/Stack.h

@ -38,6 +38,7 @@ public:
llvm::Value* get(llvm::Value* _index) { return m_getFunc.call(m_builder, {m_array, _index}); } llvm::Value* get(llvm::Value* _index) { return m_getFunc.call(m_builder, {m_array, _index}); }
void pop(llvm::Value* _count); void pop(llvm::Value* _count);
llvm::Value* size(); llvm::Value* size();
void free() { m_freeFunc.call(m_builder, {m_array}); }
llvm::Value* getPointerTo() const { return m_array; } llvm::Value* getPointerTo() const { return m_array; }
@ -47,10 +48,12 @@ private:
LazyFunction m_pushFunc; LazyFunction m_pushFunc;
LazyFunction m_setFunc; LazyFunction m_setFunc;
LazyFunction m_getFunc; LazyFunction m_getFunc;
LazyFunction m_freeFunc;
llvm::Function* createArrayPushFunc(); llvm::Function* createArrayPushFunc();
llvm::Function* createArraySetFunc(); llvm::Function* createArraySetFunc();
llvm::Function* createArrayGetFunc(); llvm::Function* createArrayGetFunc();
llvm::Function* createFreeFunc();
}; };
class Stack : public CompilerHelper class Stack : public CompilerHelper
@ -62,6 +65,7 @@ public:
void set(size_t _index, llvm::Value* _value); void set(size_t _index, llvm::Value* _value);
void pop(size_t _count); void pop(size_t _count);
void push(llvm::Value* _value); void push(llvm::Value* _value);
void free() { m_stack.free(); }
private: private:
llvm::Function* getPopFunc(); llvm::Function* getPopFunc();

Loading…
Cancel
Save