From d28139677b9c802009abd16966eb8849f4a01c5c Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Thu, 23 Oct 2014 23:56:56 +0100 Subject: [PATCH] Refactored local stack [#81180320] --- libevmjit/BasicBlock.cpp | 201 +++++++++++++++++++++++++++++----- libevmjit/BasicBlock.h | 70 ++++++++---- libevmjit/Compiler.cpp | 66 +++++++---- libevmjit/Compiler.h | 2 +- libevmjit/ExecutionEngine.cpp | 5 +- libevmjit/Stack.cpp | 65 ++++++++--- libevmjit/Stack.h | 12 +- libevmjit/Type.cpp | 3 + libevmjit/Type.h | 2 + 9 files changed, 342 insertions(+), 84 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 2c5ea7285d..13d66140fe 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -1,8 +1,11 @@ #include "BasicBlock.h" +#include + #include #include +#include #include "Type.h" @@ -15,65 +18,211 @@ namespace jit const char* BasicBlock::NamePrefix = "Instr."; -BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc) : +BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : m_beginInstIdx(_beginInstIdx), m_endInstIdx(_endInstIdx), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)), - m_stack(m_llvmBB) + m_stack(_builder) {} -BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc) : +BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : m_beginInstIdx(0), m_endInstIdx(0), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), - m_stack(m_llvmBB) + m_stack(_builder) {} +BasicBlock::LocalStack::LocalStack(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_initialStack(), + m_currentStack(), + m_tosOffset(0) +{} void BasicBlock::LocalStack::push(llvm::Value* _value) { - assert(_value->getType() == Type::i256); - m_backend.push_back(_value); + m_currentStack.push_back(_value); + m_tosOffset += 1; } llvm::Value* BasicBlock::LocalStack::pop() { - auto top = get(0); - m_backend.pop_back(); - return top; + auto result = get(0); + + if (m_currentStack.size() > 0) + m_currentStack.pop_back(); + + m_tosOffset -= 1; + return result; +} + +/** + * Pushes a copy of _index-th element (tos is 0-th elem). + */ +void BasicBlock::LocalStack::dup(size_t _index) +{ + auto val = get(_index); + push(val); +} + +/** + * Swaps tos with _index-th element (tos is 0-th elem). + * _index must be > 0. + */ +void BasicBlock::LocalStack::swap(size_t _index) +{ + assert(_index > 0); + auto val = get(_index); + auto tos = get(0); + set(_index, tos); + set(0, val); +} + +void BasicBlock::LocalStack::synchronize(Stack& _evmStack) +{ + auto blockTerminator = m_builder.GetInsertBlock()->getTerminator(); + assert(blockTerminator != nullptr); + m_builder.SetInsertPoint(blockTerminator); + + auto currIter = m_currentStack.begin(); + auto endIter = m_currentStack.end(); + + // Update (emit set()) changed values + for (int idx = m_currentStack.size() - 1 - m_tosOffset; + currIter < endIter && idx >= 0; + ++currIter, --idx) + { + assert(static_cast(idx) < m_initialStack.size()); + if (*currIter != m_initialStack[idx]) // value needs update + _evmStack.set(static_cast(idx), *currIter); + } + + if (m_tosOffset < 0) + { + // Pop values + _evmStack.pop(static_cast(-m_tosOffset)); + } + + // Push new values + for ( ; currIter < endIter; ++currIter) + { + assert(*currIter != nullptr); + _evmStack.push(*currIter); + } + + // Emit get() for all (used) values from the initial stack + for (size_t idx = 0; idx < m_initialStack.size(); ++idx) + { + auto val = m_initialStack[idx]; + if (val == nullptr) + continue; + + assert(llvm::isa(val)); + llvm::PHINode* phi = llvm::cast(val); + if (! phi->use_empty()) + { + // Insert call to get() just before the PHI node and replace + // the uses of PHI with the uses of this new instruction. + m_builder.SetInsertPoint(phi); + auto newVal = _evmStack.get(idx); + phi->replaceAllUsesWith(newVal); + } + phi->eraseFromParent(); + } + + // Reset the stack + m_initialStack.erase(m_initialStack.begin(), m_initialStack.end()); + m_currentStack.erase(m_currentStack.begin(), m_currentStack.end()); + m_tosOffset = 0; +} + +std::vector::iterator BasicBlock::LocalStack::getItemIterator(size_t _index) +{ + if (_index < m_currentStack.size()) + return m_currentStack.end() - _index - 1; + + // Need to map more elements from the EVM stack + auto nNewItems = 1 + _index - m_currentStack.size(); + m_currentStack.insert(m_currentStack.begin(), nNewItems, nullptr); + + return m_currentStack.end() - _index - 1; } llvm::Value* BasicBlock::LocalStack::get(size_t _index) -{ - if (_index >= m_backend.size()) +{ + auto itemIter = getItemIterator(_index); + + if (*itemIter == nullptr) { - // Create PHI node for missing values - auto nMissingVals = _index - m_backend.size() + 1; - m_backend.insert(m_backend.begin(), nMissingVals, nullptr); - for (decltype(nMissingVals) i = 0; i < nMissingVals; ++i) + // Need to fetch a new item from the EVM stack + assert(static_cast(_index) >= m_tosOffset); + size_t initialIdx = _index - m_tosOffset; + if (initialIdx >= m_initialStack.size()) { - m_backend[nMissingVals - 1 - i] = m_llvmBB->empty() ? - llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB) : - llvm::PHINode::Create(Type::i256, 0, {}, m_llvmBB->getFirstNonPHI()); - m_numRequiredStackItems += 1; + auto nNewItems = 1 + initialIdx - m_initialStack.size(); + m_initialStack.insert(m_initialStack.end(), nNewItems, nullptr); } + + assert(m_initialStack[initialIdx] == nullptr); + // Create a dummy value. + std::string name = "get_" + boost::lexical_cast(_index); + m_initialStack[initialIdx] = m_builder.CreatePHI(Type::i256, 0, name); + *itemIter = m_initialStack[initialIdx]; } - return *(m_backend.rbegin() + _index); + return *itemIter; } -void BasicBlock::LocalStack::dup(size_t _index) +void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word) { - m_backend.push_back(get(_index)); + auto itemIter = getItemIterator(_index); + *itemIter = _word; } -void BasicBlock::LocalStack::swap(size_t _index) + +void BasicBlock::dump() { - assert(_index != 0); - get(_index); // Create PHI nodes - std::swap(*m_backend.rbegin(), *(m_backend.rbegin() + _index)); + std::cerr << "Initial stack:\n"; + for (auto val : m_stack.m_initialStack) + { + if (val == nullptr) + std::cerr << " ?\n"; + else if (llvm::isa(val)) + val->dump(); + else + { + std::cerr << " "; + val->dump(); + } + } + std::cerr << " ...\n"; + + std::cerr << "Instructions:\n"; + for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) + ins->dump(); + + std::cerr << "Current stack (offset = " + << m_stack.m_tosOffset << "):\n"; + + for (auto val = m_stack.m_currentStack.rbegin(); val != m_stack.m_currentStack.rend(); ++val) + { + if (*val == nullptr) + std::cerr << " ?\n"; + else if (llvm::isa(*val)) + (*val)->dump(); + else + { + std::cerr << " "; + (*val)->dump(); + } + + } + std::cerr << " ...\n----------------------------------------\n"; } + + + } } } diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 51a48c6e07..2723cf9198 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -1,8 +1,11 @@ +#pragma once #include #include +#include "Stack.h" + namespace dev { namespace eth @@ -18,49 +21,72 @@ public: class LocalStack { public: + /// Pushes value on stack void push(llvm::Value* _value); /// Pops and returns top value llvm::Value* pop(); - /// Gets _index'th value from top (counting from 0) - llvm::Value* get(size_t _index); - - /// Duplicates _index'th value on stack. + /// Duplicates _index'th value on stack void dup(size_t _index); /// Swaps _index'th value on stack with a value on stack top. - /// @param _index Index of value to be swaped. Cannot be 0. + /// @param _index Index of value to be swaped. Must be > 0. void swap(size_t _index); - /// Size of the stack - size_t size() const { return m_backend.size(); } - - size_t initialSize() const { return m_numRequiredStackItems; } + /// Synchronize current local stack with the EVM stack. + void synchronize(Stack& _evmStack); private: - // LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB) {} - LocalStack(llvm::BasicBlock* _llvmBB) : m_llvmBB(_llvmBB), m_numRequiredStackItems(0) {} + + LocalStack(llvm::IRBuilder<>& _builder); LocalStack(LocalStack const&) = delete; void operator=(LocalStack const&) = delete; friend BasicBlock; + /// Gets _index'th value from top (counting from 0) + llvm::Value* get(size_t _index); + + /// Sets _index'th value from top (counting from 0) + void set(size_t _index, llvm::Value* _value); + + std::vector::iterator getItemIterator(size_t _index); + private: - std::vector m_backend; - /** Basic block into which phi nodes are inserted */ - llvm::BasicBlock* m_llvmBB; + llvm::IRBuilder<>& m_builder; + + /** + * This stack contains LLVM values that correspond to items found at + * the EVM stack when the current basic block starts executing. + * Location 0 corresponds to the top of the EVM stack, location 1 is + * the item below the top and so on. The stack grows as the code + * accesses more items on the EVM stack but once a value is put on + * the stack, it will never be replaced. + */ + std::vector m_initialStack; + + /** + * This stack tracks the contents of the EVM stack as the current basic + * block executes. It may grow on both sides, as the code pushes items on + * top of the stack or changes existing items. + */ + std::vector m_currentStack; + + /** + * How many items higher is the current stack than the initial one. + * May be negative. + */ + int m_tosOffset; - /** Number of items required on the EVM stack at the beginning of the block */ - size_t m_numRequiredStackItems; }; /// Basic block name prefix. The rest is beging instruction index. static const char* NamePrefix; - explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc); - explicit BasicBlock(std::string _name, llvm::Function* _mainFunc); + explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); + explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); BasicBlock(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete; @@ -68,11 +94,15 @@ public: operator llvm::BasicBlock*() { return m_llvmBB; } llvm::BasicBlock* llvm() { return m_llvmBB; } - LocalStack& getStack() { return m_stack; } - ProgramCounter begin() { return m_beginInstIdx; } ProgramCounter end() { return m_endInstIdx; } + LocalStack& localStack() { return m_stack; } + + /// Prints local stack and block instructions to stderr. + /// Useful for calling in a debugger session. + void dump(); + private: ProgramCounter const m_beginInstIdx; ProgramCounter const m_endInstIdx; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 71661bde92..1b408d6fef 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -123,12 +123,12 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) auto beginInstIdx = *it; ++it; auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size(); - basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc)); + basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); } m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); - m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc); - m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc); + m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc, m_builder); + m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc, m_builder); for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { @@ -186,6 +186,9 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) ++iterCopy; auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock); + if (getenv("EVMCC_DEBUG_BLOCKS")) + basicBlock.dump(); + basicBlock.localStack().synchronize(stack); } // Code for special blocks: @@ -201,9 +204,9 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) { - auto& stack = m_jumpTableBlock->getStack(); + // auto& stack = m_jumpTableBlock->getStack(); - auto dest = stack.pop(); + auto dest = m_jumpTableBlock->localStack().pop(); //m_jumpTableBlock->localGet(0); // stack.pop(); auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), m_indirectJumpTargets.size()); for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) @@ -218,7 +221,8 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) m_builder.CreateBr(m_badJumpBlock->llvm()); } - linkBasicBlocks(stack); + m_jumpTableBlock->localStack().synchronize(stack); + linkBasicBlocks(); return module; } @@ -226,8 +230,8 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) { - auto& stack = basicBlock.getStack(); m_builder.SetInsertPoint(basicBlock.llvm()); + auto& stack = basicBlock.localStack(); for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) { @@ -589,8 +593,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } else { - // FIXME: this get(0) is a temporary workaround to get some of the jump tests running. - stack.get(0); m_builder.CreateBr(m_jumpTableBlock->llvm()); } } @@ -873,7 +875,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, } -void Compiler::linkBasicBlocks(Stack& stack) +void Compiler::linkBasicBlocks() // Stack& stack) { // Remove dead basic blocks auto sthErased = false; @@ -902,13 +904,14 @@ void Compiler::linkBasicBlocks(Stack& stack) m_jumpTableBlock.reset(); } - +/* struct BBInfo { BasicBlock& bblock; std::vector predecessors; size_t inputItems; size_t outputItems; + std::vector phisToRewrite; BBInfo(BasicBlock& _bblock) : bblock(_bblock), @@ -978,7 +981,8 @@ void Compiler::linkBasicBlocks(Stack& stack) } } - std::map phiReplacements; + // std::map phiReplacements; + // std::vector phiNodesToRewrite; // Propagate values between blocks. for (auto& pair : cfg) @@ -1001,13 +1005,14 @@ void Compiler::linkBasicBlocks(Stack& stack) } // Turn the remaining phi nodes into stack.pop's. - m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI())); + // m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI())); for (; llvm::isa(*instrIter); ++instrIter) { auto phi = llvm::cast(instrIter); - auto value = stack.popWord(); + // auto value = stack.popWord(); // Don't delete the phi node yet. It may still be stored in a local stack of some block. - phiReplacements[phi] = value; + // phiReplacements[phi] = value; + bbInfo.phisToRewrite.push_back(phi); } // Emit stack push's at the end of the block, just before the terminator; @@ -1018,11 +1023,33 @@ void Compiler::linkBasicBlocks(Stack& stack) stack.pushWord(bblock.getStack().get(localStackSize - 1 - i)); } - for (auto& entry : phiReplacements) + for (auto& entry : cfg) { - entry.first->replaceAllUsesWith(entry.second); - entry.first->eraseFromParent(); + // Where was the last stack.pop() inserted + auto lastPopIt = entry.first->begin(); + + for (auto phi : entry.second.phisToRewrite) + { + // Insert stack.pop() before the first use of phi, + // then replace all uses of phi with the popped val. + + if (phi->use_begin() == phi->use_end()) + { + // For a phi with no uses, insert pop just after the previous one + } + std::cout << "*** PHI node " << phi->getName().str() << " has no uses!\n"; + } + else + { + assert(llvm::isa(phi->use_begin()->getUser())); + + m_builder.SetInsertPoint(*phi->use_begin()); + auto popVal = stack.popWord(); + phi->replaceAllUsesWith(popVal); + phi->eraseFromParent(); + } } + */ } void Compiler::dumpBasicBlockGraph(std::ostream& out) @@ -1030,7 +1057,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) out << "digraph BB {\n" << " node [shape=record];\n" << " entry [share=record, label=\"entry block\"];\n"; - +/* std::vector blocks; for (auto& pair : this->basicBlocks) blocks.push_back(&pair.second); @@ -1076,6 +1103,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) } out << "}\n"; + */ } } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index ac6277e7bd..9d7b37fbc0 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -33,7 +33,7 @@ private: void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock); - void linkBasicBlocks(class Stack& stack); + void linkBasicBlocks(); //class Stack& stack); llvm::IRBuilder<> m_builder; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 4bcaf2c508..af5f96ac77 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,7 @@ #include "Runtime.h" #include "Memory.h" +#include "Stack.h" #include "Type.h" namespace dev @@ -35,7 +36,6 @@ ExecutionEngine::ExecutionEngine() extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; } - int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtVMFace* _ext) { auto module = _module.get(); // Keep ownership of the module in _module @@ -117,6 +117,8 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV // Return remaining gas _gas = returnCode == ReturnCode::OutOfGas ? 0 : Runtime::getGas(); + std::cout << "Max stack size: " << Stack::maxStackSize << std::endl; + if (returnCode == ReturnCode::Return) { returnData = Memory::getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface @@ -128,6 +130,7 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV } std::cout << "RETURN CODE: " << (int)returnCode << std::endl; + return static_cast(returnCode); } diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index ce7d09471b..89044bea82 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -17,34 +17,48 @@ namespace jit Stack::Stack(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) { - auto i256Ty = m_builder.getIntNTy(256); - auto i256PtrTy = i256Ty->getPointerTo(); - - m_arg = m_builder.CreateAlloca(i256Ty, nullptr, "stack.retVal"); + m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg"); using namespace llvm; using Linkage = GlobalValue::LinkageTypes; auto module = getModule(); - m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_push", module); - m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), i256PtrTy, false), Linkage::ExternalLinkage, "stack_pop", module); + m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::WordPtr, false), Linkage::ExternalLinkage, "stack_push", module); + m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::Size, false), Linkage::ExternalLinkage, "stack_pop", module); + llvm::Type* getSetArgTypes[] = {Type::Size, Type::WordPtr}; + m_get = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_get", module); + m_set = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_set", module); } Stack::~Stack() {} -llvm::Instruction* Stack::popWord() +llvm::Value* Stack::get(size_t _index) { - m_builder.CreateCall(m_pop, m_arg); + m_builder.CreateCall2(m_get, llvm::ConstantInt::get(Type::Size, _index, false), m_arg); return m_builder.CreateLoad(m_arg); } -void Stack::pushWord(llvm::Value* _word) +void Stack::set(size_t _index, llvm::Value* _value) { - m_builder.CreateStore(_word, m_arg); + m_builder.CreateStore(_value, m_arg); + m_builder.CreateCall2(m_set, llvm::ConstantInt::get(Type::Size, _index, false), m_arg); +} + +void Stack::pop(size_t _count) +{ + m_builder.CreateCall(m_pop, llvm::ConstantInt::get(Type::Size, _count, false)); +} + +void Stack::push(llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_arg); m_builder.CreateCall(m_push, m_arg); } + +size_t Stack::maxStackSize = 0; + } } } @@ -56,21 +70,42 @@ using namespace dev::eth::jit; extern std::jmp_buf* rt_jmpBuf; -EXPORT void stack_pop(i256* _ret) +EXPORT void stack_pop(uint64_t _count) { auto& stack = Runtime::getStack(); - if (stack.size() == 0) + if (stack.size() < _count) longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); - assert(stack.size() > 0); - *_ret = stack.back(); - stack.pop_back(); + stack.erase(stack.end() - _count, stack.end()); } EXPORT void stack_push(i256* _word) { auto& stack = Runtime::getStack(); stack.push_back(*_word); + + if (stack.size() > Stack::maxStackSize) + Stack::maxStackSize = stack.size(); +} + +EXPORT void stack_get(uint64_t _index, i256* _ret) +{ + auto& stack = Runtime::getStack(); + // TODO: encode _index and stack size in the return code + if (stack.size() <= _index) + longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + + *_ret = *(stack.rbegin() + _index); +} + +EXPORT void stack_set(uint64_t _index, i256* _word) +{ + auto& stack = Runtime::getStack(); + // TODO: encode _index and stack size in the return code + if (stack.size() <= _index) + longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + + *(stack.rbegin() + _index) = *_word; } } // extern "C" diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index 5e1ac0f39b..2380b2a159 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -14,15 +14,23 @@ namespace jit class Stack : public CompilerHelper { public: + Stack(llvm::IRBuilder<>& builder); virtual ~Stack(); - void pushWord(llvm::Value* _word); - llvm::Instruction* popWord(); + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; private: + llvm::Function* m_push; llvm::Function* m_pop; + llvm::Function* m_get; + llvm::Function* m_set; llvm::Value* m_arg; }; diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 3ef339a1bc..baf458dbd9 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -13,6 +13,7 @@ namespace jit llvm::IntegerType* Type::i256; llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; +llvm::IntegerType* Type::Size; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -23,6 +24,8 @@ void Type::init(llvm::LLVMContext& _context) i256 = llvm::Type::getIntNTy(_context, 256); WordPtr = i256->getPointerTo(); lowPrecision = llvm::Type::getInt64Ty(_context); + // TODO: Size should be architecture-dependent + Size = llvm::Type::getInt64Ty(_context); Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); diff --git a/libevmjit/Type.h b/libevmjit/Type.h index a03bfac381..16a13c3737 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -20,6 +20,8 @@ struct Type /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required static llvm::IntegerType* lowPrecision; + static llvm::IntegerType* Size; + static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr;