diff --git a/evmcc/test/except/badinst1.evm b/evmcc/test/except/badinst1.evm new file mode 100644 index 0000000000..69aadac5e9 --- /dev/null +++ b/evmcc/test/except/badinst1.evm @@ -0,0 +1 @@ +4a diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index d36ee50095..99172fbe9e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -176,6 +176,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, mainFuncArgTypes, false); m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get()); + m_mainFunc->arg_begin()->getNextNode()->setName("rt"); // Create the basic blocks. auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); @@ -186,7 +187,7 @@ std::unique_ptr Compiler::compile(bytesConstRef bytecode) // Init runtime structures. RuntimeManager runtimeManager(m_builder); GasMeter gasMeter(m_builder, runtimeManager); - Memory memory(m_builder, gasMeter, runtimeManager); + Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager); Stack stack(m_builder, runtimeManager); Arith256 arith(m_builder); @@ -371,14 +372,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, break; } - case Instruction::NEG: + /*case Instruction::NEG: { auto top = stack.pop(); auto zero = Constant::get(0); auto res = m_builder.CreateSub(zero, top); stack.push(res); break; - } + }*/ case Instruction::LT: { @@ -796,7 +797,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, auto index = stack.pop(); auto size = stack.pop(); - memory.registerReturnData(index, size); + memory.require(index, size); + _runtimeManager.registerReturnData(index, size); m_builder.CreateRet(Constant::get(ReturnCode::Return)); break; @@ -814,6 +816,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, break; } + default: // Invalid instruction - runtime exception + { + _runtimeManager.raiseException(ReturnCode::BadInstruction); + } + } } diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index c2d612c668..c4835c32e8 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -27,8 +27,10 @@ llvm::Function* CompilerHelper::getMainFunction() { assert(m_builder.GetInsertBlock()); auto mainFunc = m_builder.GetInsertBlock()->getParent(); - assert(mainFunc && mainFunc->getName() == "main"); - return mainFunc; + assert(mainFunc); + if (mainFunc->getName() == "main") + return mainFunc; + return nullptr; } diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index cf83d70cd8..19315fe4a1 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -31,6 +31,13 @@ protected: llvm::IRBuilder<>& m_builder; llvm::IRBuilder<>& getBuilder() { return m_builder; } + template + llvm::CallInst* createCall(llvm::Function* _func, _Args*... _args) + { + llvm::Value* args[] = {_args...}; + return getBuilder().CreateCall(_func, args); + } + friend class RuntimeHelper; }; diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 068237af6e..efa039f2b0 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -35,8 +35,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 @@ -102,21 +100,19 @@ int ExecutionEngine::run(std::unique_ptr _module, u256& _gas, ExtV _ext->code = decltype(_ext->code)(fakecode, 8); } - // Init runtime - Runtime runtime(_gas, *_ext); - auto entryFunc = module->getFunction("main"); if (!entryFunc) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found")); ReturnCode returnCode; std::jmp_buf buf; + Runtime runtime(_gas, *_ext, buf); auto r = setjmp(buf); if (r == 0) { + auto executionStartTime = std::chrono::high_resolution_clock::now(); - rt_jmpBuf = &buf; auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(runtime.getDataPtr())}); returnCode = static_cast(result.IntVal.getZExtValue()); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 170086daed..0da9c8809d 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -63,7 +63,7 @@ Ext::Ext(RuntimeManager& _runtimeManager): m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), Linkage::ExternalLinkage, "ext_call", module); m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_sha3", module); m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module); - m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), Linkage::ExternalLinkage, "ext_codeAt", module); + m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_codeAt", module); m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module); } @@ -109,8 +109,7 @@ llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::V m_builder.CreateStore(_endowment, m_args[0]); m_builder.CreateStore(_initOff, m_arg2); m_builder.CreateStore(_initSize, m_arg3); - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_args[1]}; - m_builder.CreateCall(m_create, args); + createCall(m_create, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_args[1]); llvm::Value* address = m_builder.CreateLoad(m_args[1]); address = Endianness::toNative(m_builder, address); return address; @@ -128,9 +127,7 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V m_builder.CreateStore(_outSize, m_arg7); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); m_builder.CreateStore(codeAddress, m_arg8); - - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]}; - m_builder.CreateCall(m_call, args); + createCall(m_call, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]); _gas = m_builder.CreateLoad(m_args[0]); // Return gas return m_builder.CreateLoad(m_args[1]); } @@ -139,8 +136,7 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) { m_builder.CreateStore(_inOff, m_args[0]); m_builder.CreateStore(_inSize, m_arg2); - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]}; - m_builder.CreateCall(m_sha3, args); + createCall(m_sha3, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]); llvm::Value* hash = m_builder.CreateLoad(m_args[1]); hash = Endianness::toNative(m_builder, hash); return hash; @@ -148,10 +144,10 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) llvm::Value* Ext::exp(llvm::Value* _left, llvm::Value* _right) { + // TODO: Move ext to Arith256 m_builder.CreateStore(_left, m_args[0]); m_builder.CreateStore(_right, m_arg2); - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]}; - m_builder.CreateCall(m_exp, args); + createCall(m_exp, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]); return m_builder.CreateLoad(m_args[1]); } @@ -166,8 +162,7 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); m_builder.CreateStore(addr, m_args[0]); - llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]}; - m_builder.CreateCall(m_codesizeAt, args); + createCall(m_codesizeAt, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); return m_builder.CreateLoad(m_args[1]); } @@ -225,10 +220,9 @@ EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _in u256 gas; // TODO: Handle gas auto initOff = static_cast(llvm2eth(*_initOff)); auto initSize = static_cast(llvm2eth(*_initSize)); - //auto&& initRef = bytesConstRef(Runtime::getMemory().data() + initOff, initSize); - bytesConstRef initRef; + auto&& initRef = bytesConstRef(_rt->getMemory().data() + initOff, initSize); OnOpFunc onOp{}; // TODO: Handle that thing - h256 address = ext.create(endowment, &gas, initRef, onOp); + h256 address(ext.create(endowment, &gas, initRef, onOp), h256::AlignRight); *_address = address; } else @@ -252,8 +246,8 @@ EXPORT void ext_call(Runtime* _rt, i256* _gas, h256* _receiveAddress, i256* _val auto inSize = static_cast(llvm2eth(*_inSize)); auto outOff = static_cast(llvm2eth(*_outOff)); auto outSize = static_cast(llvm2eth(*_outSize)); - auto&& inRef = bytesConstRef(); //Runtime::getMemory().data() + inOff, inSize); - auto&& outRef = bytesConstRef(); // Runtime::getMemory().data() + outOff, outSize); + auto&& inRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); + auto&& outRef = bytesConstRef(_rt->getMemory().data() + outOff, outSize); OnOpFunc onOp{}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress); @@ -267,7 +261,7 @@ EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret) { auto inOff = static_cast(llvm2eth(*_inOff)); auto inSize = static_cast(llvm2eth(*_inSize)); - auto dataRef = bytesConstRef(); // Runtime::getMemory().data() + inOff, inSize); + auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize); auto hash = sha3(dataRef); *_ret = *reinterpret_cast(&hash); } diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 317b204fc0..149944f284 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -31,7 +31,7 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure return 0; case Instruction::SSTORE: - return static_cast(c_sstoreGas); + return static_cast(c_sstoreResetGas); // FIXME: Check store gas case Instruction::SLOAD: return static_cast(c_sloadGas); @@ -101,12 +101,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - - //auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); - auto extJmpBuf = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "rt_jmpBuf"); - llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; - auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", module); - m_builder.CreateCall2(longjmpNative, m_builder.CreateLoad(extJmpBuf), Constant::get(ReturnCode::OutOfGas)); + _runtimeManager.raiseException(ReturnCode::OutOfGas); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); @@ -134,7 +129,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu { assert(!m_checkCall); // Everything should've been commited before - static const auto sstoreCost = static_cast(c_sstoreGas); + static const auto sstoreCost = static_cast(c_sstoreResetGas); // FIXME: Check store gas // [ADD] if oldValue == 0 and newValue != 0 => 2*cost // [DEL] if oldValue != 0 and newValue == 0 => 0 @@ -148,7 +143,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu auto isDel = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDel"); auto cost = m_builder.CreateSelect(isAdd, Constant::get(2 * sstoreCost), Constant::get(sstoreCost), "cost"); cost = m_builder.CreateSelect(isDel, Constant::get(0), cost, "cost"); - m_builder.CreateCall(m_gasCheckFunc, cost); + createCall(m_gasCheckFunc, cost); } void GasMeter::giveBack(llvm::Value* _gas) diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 82007fc002..dcfde92a31 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -13,7 +13,7 @@ namespace jit { class RuntimeManager; -class GasMeter : public CompilerHelper +class GasMeter : public CompilerHelper // TODO: Use RuntimeHelper { public: GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager); diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index fa5a2b0dd6..b7b3d84977 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -24,8 +24,8 @@ namespace eth namespace jit { -Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter, RuntimeManager& _runtimeManager): - CompilerHelper(_builder) +Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): + RuntimeHelper(_runtimeManager) { auto module = getModule(); auto i64Ty = m_builder.getInt64Ty(); @@ -40,12 +40,6 @@ Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter, RuntimeManager& 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_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 - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module); llvm::AttrBuilder attrBuilder; @@ -180,14 +174,6 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) require(sizeRequired); } -void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size) -{ - require(_index, _size); // Make sure that memory is allocated and count gas - - m_builder.CreateStore(_index, m_returnDataOffset); - m_builder.CreateStore(_size, m_returnDataSize); -} - void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, llvm::Value* _destMemIdx, llvm::Value* _reqBytes) { diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index d925382475..d8c1e4b721 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -10,12 +10,11 @@ namespace eth { namespace jit { -class RuntimeManager; -class Memory : public CompilerHelper +class Memory : public RuntimeHelper { public: - Memory(llvm::IRBuilder<>& _builder, class GasMeter& _gasMeter, RuntimeManager& _runtimeManager); + Memory(RuntimeManager& _runtimeManager, class GasMeter& _gasMeter); llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); @@ -31,9 +30,6 @@ public: /// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory. void require(llvm::Value* _offset, llvm::Value* _size); - void registerReturnData(llvm::Value* _index, llvm::Value* _size); - bytesConstRef getReturnData(); - void dump(uint64_t _begin, uint64_t _end = 0); private: @@ -44,10 +40,6 @@ 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_resize; llvm::Function* m_require; llvm::Function* m_loadWord; diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 4b94642932..3efd78a269 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -24,9 +24,10 @@ llvm::StructType* RuntimeData::getType() { llvm::ArrayType::get(Type::i256, _size), Type::BytePtr, + Type::BytePtr, Type::BytePtr }; - type = llvm::StructType::create(elems, "RuntimeData"); + type = llvm::StructType::create(elems, "Runtime"); } return type; } @@ -56,13 +57,9 @@ llvm::Twine getName(RuntimeData::Index _index) } } -static Runtime* g_runtime; // FIXME: Remove - -Runtime::Runtime(u256 _gas, ExtVMFace& _ext): +Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf): m_ext(_ext) { - assert(!g_runtime); - g_runtime = this; set(RuntimeData::Gas, _gas); set(RuntimeData::Address, fromAddress(_ext.myAddress)); set(RuntimeData::Caller, fromAddress(_ext.caller)); @@ -79,11 +76,7 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext): set(RuntimeData::CodeSize, _ext.code.size()); // TODO: Use constant m_data.callData = _ext.data.data(); m_data.code = _ext.code.data(); -} - -Runtime::~Runtime() -{ - g_runtime = nullptr; + m_data.jmpBuf = _jmpBuf; } void Runtime::set(RuntimeData::Index _index, u256 _value) @@ -96,16 +89,14 @@ u256 Runtime::getGas() const return llvm2eth(m_data.elems[RuntimeData::Gas]); } -extern "C" { - EXPORT i256 mem_returnDataOffset; // FIXME: Dis-globalize - EXPORT i256 mem_returnDataSize; -} - bytesConstRef Runtime::getReturnData() const { // TODO: Handle large indexes - auto offset = static_cast(llvm2eth(mem_returnDataOffset)); - auto size = static_cast(llvm2eth(mem_returnDataSize)); + auto offset = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset])); + auto size = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataSize])); + + assert(offset + size <= m_memory.size()); + // TODO: Handle invalid data access by returning empty ref return {m_memory.data() + offset, size}; } @@ -113,6 +104,8 @@ bytesConstRef Runtime::getReturnData() const RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) { m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt"); + llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()}; + m_longjmp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", getModule()); // Export data auto mainFunc = getMainFunction(); @@ -122,15 +115,36 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui llvm::Value* RuntimeManager::getRuntimePtr() { - // TODO: If in main function - get it from param - return m_builder.CreateLoad(m_dataPtr); + if (auto mainFunc = getMainFunction()) + return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function + return m_builder.CreateLoad(m_dataPtr, "rt"); +} + +llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) +{ + llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)}; + return m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr"); } llvm::Value* RuntimeManager::get(RuntimeData::Index _index) { - llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)}; - auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr"); - return m_builder.CreateLoad(ptr, getName(_index)); + return m_builder.CreateLoad(getPtr(_index), getName(_index)); +} + +void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value) +{ + m_builder.CreateStore(_value, getPtr(_index)); +} + +void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size) +{ + set(RuntimeData::ReturnDataOffset, _offset); + set(RuntimeData::ReturnDataSize, _size); +} + +void RuntimeManager::raiseException(ReturnCode _returnCode) +{ + m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); } llvm::Value* RuntimeManager::get(Instruction _inst) @@ -167,6 +181,12 @@ llvm::Value* RuntimeManager::getCode() return getBuilder().CreateLoad(ptr, "code"); } +llvm::Value* RuntimeManager::getJmpBuf() +{ + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 3, "jmpbufPtr"); + return getBuilder().CreateLoad(ptr, "jmpbuf"); +} + llvm::Value* RuntimeManager::getGas() { return get(RuntimeData::Gas); diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index ec912849a2..418652c40f 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -7,6 +7,7 @@ #include "CompilerHelper.h" #include "Utils.h" +#include "Type.h" #ifdef _MSC_VER @@ -41,12 +42,16 @@ struct RuntimeData GasLimit, CodeSize, - _size + _size, + + ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference + ReturnDataSize = CallDataSize }; i256 elems[_size]; byte const* callData; byte const* code; + decltype(&jmp_buf{}[0]) jmpBuf; static llvm::StructType* getType(); }; @@ -57,8 +62,7 @@ using MemoryImpl = bytes; class Runtime { public: - Runtime(u256 _gas, ExtVMFace& _ext); - ~Runtime(); + Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf); Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; @@ -71,6 +75,7 @@ public: u256 getGas() const; bytesConstRef getReturnData() const; + decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; } private: void set(RuntimeData::Index _index, u256 _value); @@ -96,8 +101,17 @@ public: llvm::Value* getCode(); void setGas(llvm::Value* _gas); + void registerReturnData(llvm::Value* _index, llvm::Value* _size); + + void raiseException(ReturnCode _returnCode); + private: - llvm::GlobalVariable* m_dataPtr; + llvm::Value* getPtr(RuntimeData::Index _index); + void set(RuntimeData::Index _index, llvm::Value* _value); + llvm::Value* getJmpBuf(); + + llvm::GlobalVariable* m_dataPtr = nullptr; + llvm::Function* m_longjmp = nullptr; }; } diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 6c287dc6aa..144cd5d542 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -74,13 +74,11 @@ extern "C" using namespace dev::eth::jit; -extern std::jmp_buf* rt_jmpBuf; - EXPORT void stack_pop(Runtime* _rt, uint64_t _count) { auto& stack = _rt->getStack(); if (stack.size() < _count) - longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); stack.erase(stack.end() - _count, stack.end()); } @@ -99,7 +97,7 @@ EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* _ret) auto& stack = _rt->getStack(); // TODO: encode _index and stack size in the return code if (stack.size() <= _index) - longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); *_ret = *(stack.rbegin() + _index); } @@ -109,7 +107,7 @@ EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256* _word) auto& stack = _rt->getStack(); // TODO: encode _index and stack size in the return code if (stack.size() <= _index) - longjmp(*rt_jmpBuf, static_cast(ReturnCode::StackTooSmall)); + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); *(stack.rbegin() + _index) = *_word; } diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 86915cd9ee..b432f08135 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -43,7 +43,8 @@ enum class ReturnCode BadJumpDestination = 101, OutOfGas = 102, - StackTooSmall = 103 + StackTooSmall = 103, + BadInstruction = 104, }; struct Constant diff --git a/libevmjit/VM.cpp b/libevmjit/VM.cpp index 9a76c5bcb8..0907682d22 100644 --- a/libevmjit/VM.cpp +++ b/libevmjit/VM.cpp @@ -5,6 +5,7 @@ #include "ExecutionEngine.h" #include "Compiler.h" +#include "Type.h" namespace dev { @@ -13,24 +14,23 @@ namespace eth namespace jit { -bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) { - assert(!_onOp); // Parameter ignored - assert(_steps == (uint64_t)-1); // Parameter ignored - auto module = Compiler().compile(_ext.code); ExecutionEngine engine; auto exitCode = engine.run(std::move(module), m_gas, &_ext); - switch (exitCode) + switch (static_cast(exitCode)) { - case 101: + case ReturnCode::BadJumpDestination: BOOST_THROW_EXCEPTION(BadJumpDestination()); - case 102: + case ReturnCode::OutOfGas: BOOST_THROW_EXCEPTION(OutOfGas()); - case 103: + case ReturnCode::StackTooSmall: BOOST_THROW_EXCEPTION(StackTooSmall(1,0)); + case ReturnCode::BadInstruction: + BOOST_THROW_EXCEPTION(BadInstruction()); } m_output = std::move(engine.returnData);