|
@ -21,20 +21,8 @@ namespace evmcc |
|
|
Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter): |
|
|
Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter): |
|
|
m_builder(_builder) |
|
|
m_builder(_builder) |
|
|
{ |
|
|
{ |
|
|
auto voidTy = m_builder.getVoidTy(); |
|
|
|
|
|
auto i64Ty = m_builder.getInt64Ty(); |
|
|
auto i64Ty = m_builder.getInt64Ty(); |
|
|
|
|
|
llvm::Type* argTypes[] = {i64Ty, i64Ty}; |
|
|
auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false); |
|
|
|
|
|
m_memRequire = llvm::Function::Create(memRequireTy, |
|
|
|
|
|
llvm::GlobalValue::LinkageTypes::ExternalLinkage, |
|
|
|
|
|
"evmccrt_memory_require", _module); |
|
|
|
|
|
|
|
|
|
|
|
auto memSizeTy = llvm::FunctionType::get(i64Ty, false); |
|
|
|
|
|
m_memSize = llvm::Function::Create(memSizeTy, |
|
|
|
|
|
llvm::GlobalValue::LinkageTypes::ExternalLinkage, |
|
|
|
|
|
"evmccrt_memory_size", _module); |
|
|
|
|
|
|
|
|
|
|
|
std::vector<llvm::Type*> argTypes = {i64Ty, i64Ty}; |
|
|
|
|
|
auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false); |
|
|
auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false); |
|
|
m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, |
|
|
m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, |
|
|
"evmccrt_memory_dump", _module); |
|
|
"evmccrt_memory_dump", _module); |
|
@ -42,9 +30,15 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga |
|
|
m_data = new llvm::GlobalVariable(*_module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data"); |
|
|
m_data = new llvm::GlobalVariable(*_module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data"); |
|
|
m_data->setUnnamedAddr(true); // Address is not important
|
|
|
m_data->setUnnamedAddr(true); // Address is not important
|
|
|
|
|
|
|
|
|
m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, m_builder.getIntN(256, 0), "mem.size"); |
|
|
m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size"); |
|
|
m_size->setUnnamedAddr(true); // Address is not important
|
|
|
m_size->setUnnamedAddr(true); // Address is not important
|
|
|
|
|
|
|
|
|
|
|
|
m_returnDataOffset = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset"); |
|
|
|
|
|
m_returnDataOffset->setUnnamedAddr(true); // Address is not important
|
|
|
|
|
|
|
|
|
|
|
|
m_returnDataSize = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize"); |
|
|
|
|
|
m_returnDataSize->setUnnamedAddr(true); // Address is not important
|
|
|
|
|
|
|
|
|
m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); |
|
|
m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); |
|
|
m_loadWord = createFunc(false, Type::i256, _module, _gasMeter); |
|
|
m_loadWord = createFunc(false, Type::i256, _module, _gasMeter); |
|
|
m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); |
|
|
m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); |
|
@ -69,7 +63,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: |
|
|
llvm::Value* index = func->arg_begin(); |
|
|
llvm::Value* index = func->arg_begin(); |
|
|
index->setName("index"); |
|
|
index->setName("index"); |
|
|
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; |
|
|
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; |
|
|
auto sizeRequired = builder.CreateAdd(index, builder.getIntN(256, valueSize), "sizeRequired"); |
|
|
auto sizeRequired = builder.CreateAdd(index, Constant::get(valueSize), "sizeRequired"); |
|
|
auto size = builder.CreateLoad(m_size, "size"); |
|
|
auto size = builder.CreateLoad(m_size, "size"); |
|
|
auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); |
|
|
auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); |
|
|
builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights?
|
|
|
builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights?
|
|
@ -77,8 +71,8 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm:: |
|
|
// BB "resize"
|
|
|
// BB "resize"
|
|
|
builder.SetInsertPoint(resizeBB); |
|
|
builder.SetInsertPoint(resizeBB); |
|
|
// Check gas first
|
|
|
// Check gas first
|
|
|
auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, builder.getIntN(256, 31)), builder.getIntN(256, 32), "wordsRequired"); |
|
|
auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired"); |
|
|
auto words = builder.CreateUDiv(builder.CreateAdd(size, builder.getIntN(256, 31)), builder.getIntN(256, 32), "words"); |
|
|
auto words = builder.CreateUDiv(builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words"); |
|
|
auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords"); |
|
|
auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords"); |
|
|
_gasMeter.checkMemory(newWords, builder); |
|
|
_gasMeter.checkMemory(newWords, builder); |
|
|
// Resize
|
|
|
// Resize
|
|
@ -137,6 +131,15 @@ llvm::Value* Memory::getSize() |
|
|
return m_builder.CreateLoad(m_size); |
|
|
return m_builder.CreateLoad(m_size); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) |
|
|
|
|
|
{ |
|
|
|
|
|
auto lastWord = m_builder.CreateAdd(_index, m_builder.CreateSub(_size, Constant::get(32)), "lastWord"); |
|
|
|
|
|
loadWord(lastWord); // Make sure that memory is allocated and count gas
|
|
|
|
|
|
|
|
|
|
|
|
m_builder.CreateStore(_index, m_returnDataOffset); |
|
|
|
|
|
m_builder.CreateStore(_size, m_returnDataSize); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void Memory::dump(uint64_t _begin, uint64_t _end) |
|
|
void Memory::dump(uint64_t _begin, uint64_t _end) |
|
|
{ |
|
|
{ |
|
|
if (getenv("EVMCC_DEBUG_MEMORY") == nullptr) |
|
|
if (getenv("EVMCC_DEBUG_MEMORY") == nullptr) |
|
@ -155,6 +158,9 @@ extern "C" |
|
|
{ |
|
|
{ |
|
|
using namespace evmcc; |
|
|
using namespace evmcc; |
|
|
|
|
|
|
|
|
|
|
|
EXPORT i256 mem_returnDataOffset; |
|
|
|
|
|
EXPORT i256 mem_returnDataSize; |
|
|
|
|
|
|
|
|
EXPORT uint8_t* mem_resize(i256* _size) |
|
|
EXPORT uint8_t* mem_resize(i256* _size) |
|
|
{ |
|
|
{ |
|
|
auto size = _size->a; // Trunc to 64-bit
|
|
|
auto size = _size->a; // Trunc to 64-bit
|
|
@ -163,37 +169,13 @@ EXPORT uint8_t* mem_resize(i256* _size) |
|
|
return memory.data(); |
|
|
return memory.data(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Resizes memory to contain at least _index + 1 bytes and returns the base address.
|
|
|
|
|
|
EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) |
|
|
|
|
|
{ |
|
|
|
|
|
uint64_t requiredSize = (_index / 32 + 1) * 32; |
|
|
|
|
|
auto&& memory = Runtime::getMemory(); |
|
|
|
|
|
|
|
|
|
|
|
if (memory.size() < requiredSize) |
|
|
|
|
|
{ |
|
|
|
|
|
std::cerr << "MEMORY: current size: " << std::dec |
|
|
|
|
|
<< memory.size() << " bytes, required size: " |
|
|
|
|
|
<< requiredSize << " bytes" |
|
|
|
|
|
<< std::endl; |
|
|
|
|
|
|
|
|
|
|
|
memory.resize(requiredSize); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return memory.data(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
EXPORT uint64_t evmccrt_memory_size() |
|
|
|
|
|
{ |
|
|
|
|
|
return Runtime::getMemory().size() / 32; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) |
|
|
EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) |
|
|
{ |
|
|
{ |
|
|
if (_end == 0) |
|
|
if (_end == 0) |
|
|
_end = Runtime::getMemory().size(); |
|
|
_end = Runtime::getMemory().size(); |
|
|
|
|
|
|
|
|
std::cerr << "MEMORY: active size: " << std::dec |
|
|
std::cerr << "MEMORY: active size: " << std::dec |
|
|
<< evmccrt_memory_size() << " words\n"; |
|
|
<< Runtime::getMemory().size() / 32 << " words\n"; |
|
|
std::cerr << "MEMORY: dump from " << std::dec |
|
|
std::cerr << "MEMORY: dump from " << std::dec |
|
|
<< _begin << " to " << _end << ":"; |
|
|
<< _begin << " to " << _end << ":"; |
|
|
if (_end <= _begin) |
|
|
if (_end <= _begin) |
|
@ -212,3 +194,12 @@ EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} // extern "C"
|
|
|
} // extern "C"
|
|
|
|
|
|
|
|
|
|
|
|
dev::bytesConstRef evmcc::Memory::getReturnData() |
|
|
|
|
|
{ |
|
|
|
|
|
// TODO: Handle large indexes
|
|
|
|
|
|
auto offset = static_cast<size_t>(llvm2eth(mem_returnDataOffset)); |
|
|
|
|
|
auto size = static_cast<size_t>(llvm2eth(mem_returnDataSize)); |
|
|
|
|
|
auto& memory = Runtime::getMemory(); |
|
|
|
|
|
return {memory.data() + offset, size}; |
|
|
|
|
|
} |
|
|