diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 2ee349a9e..8035a4fad 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -190,10 +190,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) IRBuilder<> builder(context); // Create main function - const auto i32Ty = builder.getInt32Ty(); - //Type* retTypeElems[] = {i32Ty, i32Ty}; - //auto retType = StructType::create(retTypeElems, "MemRef", true); - m_mainFunc = Function::Create(FunctionType::get(builder.getInt64Ty(), false), Function::ExternalLinkage, "main", module.get()); + m_mainFunc = Function::Create(FunctionType::get(Type::MainReturn, false), Function::ExternalLinkage, "main", module.get()); // Create the basic blocks. auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc); @@ -797,13 +794,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto index = stack.pop(); auto size = stack.pop(); - auto ret = builder.CreateTrunc(index, builder.getInt64Ty()); - ret = builder.CreateShl(ret, 32); - size = builder.CreateTrunc(size, i32Ty); - size = builder.CreateZExt(size, builder.getInt64Ty()); - ret = builder.CreateOr(ret, size); + memory.registerReturnData(index, size); - builder.CreateRet(ret); + builder.CreateRet(Constant::get(ReturnCode::Return)); break; } @@ -815,7 +808,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } case Instruction::STOP: { - builder.CreateRet(builder.getInt64(0)); + builder.CreateRet(Constant::get(ReturnCode::Stop)); break; } @@ -847,11 +840,11 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Note: Right now the codegen for special blocks depends only on createBasicBlock(), // not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks(). builder.SetInsertPoint(m_finalBlock->llvm()); - builder.CreateRet(builder.getInt64(0)); + builder.CreateRet(Constant::get(ReturnCode::Stop)); // TODO: throw an exception or something builder.SetInsertPoint(m_badJumpBlock->llvm()); - builder.CreateRet(builder.getInt64(0)); + builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index be45ff838..31c87d19b 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -14,6 +14,8 @@ #include #include "Runtime.h" +#include "Memory.h" +#include "Type.h" namespace evmcc { @@ -97,13 +99,13 @@ int ExecutionEngine::run(std::unique_ptr _module) auto result = exec->runFunction(entryFunc, {}); gas = static_cast(Runtime::getGas()); - if (auto intResult = result.IntVal.getZExtValue()) + auto returnCode = static_cast(result.IntVal.getZExtValue()); + if (returnCode == ReturnCode::Return) { - auto index = intResult >> 32; - auto size = 0xFFFFFFFF & intResult; + auto&& returnData = Memory::getReturnData(); std::cout << "RETURN [ "; - for (dev::bytes::const_iterator it = Runtime::getMemory().cbegin() + index, end = it + size; it != end; ++it) + for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; std::cout << "]\n"; diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 8625d7b5b..e585a9406 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -21,20 +21,8 @@ namespace evmcc Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter): m_builder(_builder) { - auto voidTy = m_builder.getVoidTy(); auto i64Ty = m_builder.getInt64Ty(); - - 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 argTypes = {i64Ty, i64Ty}; + llvm::Type* argTypes[] = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_memory_dump", _module); @@ -45,6 +33,12 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, m_builder.getIntN(256, 0), "mem.size"); 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_loadWord = createFunc(false, Type::i256, _module, _gasMeter); m_storeWord = createFunc(true, Type::i256, _module, _gasMeter); @@ -137,6 +131,12 @@ llvm::Value* Memory::getSize() return m_builder.CreateLoad(m_size); } +void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) +{ + m_builder.CreateStore(_index, m_returnDataOffset); + m_builder.CreateStore(_size, m_returnDataSize); +} + void Memory::dump(uint64_t _begin, uint64_t _end) { if (getenv("EVMCC_DEBUG_MEMORY") == nullptr) @@ -155,6 +155,9 @@ extern "C" { using namespace evmcc; +EXPORT i256 mem_returnDataOffset; +EXPORT i256 mem_returnDataSize; + EXPORT uint8_t* mem_resize(i256* _size) { auto size = _size->a; // Trunc to 64-bit @@ -163,37 +166,13 @@ EXPORT uint8_t* mem_resize(i256* _size) 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) { if (_end == 0) _end = Runtime::getMemory().size(); 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 << _begin << " to " << _end << ":"; if (_end <= _begin) @@ -212,3 +191,12 @@ EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) } } // extern "C" + +dev::bytesConstRef evmcc::Memory::getReturnData() +{ + // TODO: Handle large indexes + auto offset = static_cast(llvm2eth(mem_returnDataOffset)); + auto size = static_cast(llvm2eth(mem_returnDataSize)); + auto& memory = Runtime::getMemory(); + return {memory.data() + offset, size}; +} diff --git a/evmcc/Memory.h b/evmcc/Memory.h index ed7273c5c..c01bd6ef8 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -20,6 +20,9 @@ public: void storeByte(llvm::Value* _addr, llvm::Value* _byte); llvm::Value* getSize(); + void registerReturnData(llvm::Value* _index, llvm::Value* _size); + static dev::bytesConstRef getReturnData(); + void dump(uint64_t _begin, uint64_t _end = 0); private: @@ -31,14 +34,16 @@ private: llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_size; + /// @TODO: m_data and m_size could be used + llvm::GlobalVariable* m_returnDataOffset; + llvm::GlobalVariable* m_returnDataSize; + llvm::Function* m_loadWord; llvm::Function* m_storeWord; llvm::Function* m_storeByte; llvm::Function* m_resize; - llvm::Function* m_memRequire; llvm::Function* m_memDump; - llvm::Function* m_memSize; }; }