diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 8e8641ea3..ab95458e8 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include "preprocessor/llvm_includes_end.h" #include "Instruction.h" @@ -162,8 +161,7 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); - auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0); - m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue); + m_builder.CreateCondBr(normalFlow, firstBB, abortBB, Type::expectTrue); for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) { diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index ca21714e0..92435ba91 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -82,34 +82,36 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) CompilerHelper(_builder), m_runtimeManager(_runtimeManager) { - auto module = getModule(); - - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas}; - m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); - InsertPointGuard guard(m_builder); + llvm::Type* gasCheckArgs[] = {Type::Gas->getPointerTo(), Type::Gas, Type::BytePtr}; + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", getModule()); + m_gasCheckFunc->setDoesNotThrow(); + m_gasCheckFunc->setDoesNotCapture(1); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); - auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); + auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); - auto rt = &m_gasCheckFunc->getArgumentList().front(); - rt->setName("rt"); - auto cost = rt->getNextNode(); + auto gasPtr = &m_gasCheckFunc->getArgumentList().front(); + gasPtr->setName("gasPtr"); + auto cost = gasPtr->getNextNode(); cost->setName("cost"); + auto jmpBuf = cost->getNextNode(); + jmpBuf->setName("jmpBuf"); + InsertPointGuard guard(m_builder); m_builder.SetInsertPoint(checkBB); - auto gas = m_runtimeManager.getGas(); - gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); - auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions - m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); - - m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.abort(); - m_builder.CreateUnreachable(); + auto gas = m_builder.CreateLoad(gasPtr, "gas"); + auto gasUpdated = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); + auto gasOk = m_builder.CreateICmpSGE(gasUpdated, m_builder.getInt64(0), "gasOk"); // gas >= 0, with gas == 0 we can still do 0 cost instructions + m_builder.CreateCondBr(gasOk, updateBB, outOfGasBB, Type::expectTrue); m_builder.SetInsertPoint(updateBB); - m_runtimeManager.setGas(gas); + m_builder.CreateStore(gasUpdated, gasPtr); m_builder.CreateRetVoid(); + + m_builder.SetInsertPoint(outOfGasBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); } void GasMeter::count(Instruction _inst) @@ -117,7 +119,7 @@ void GasMeter::count(Instruction _inst) if (!m_checkCall) { // Create gas check call with mocked block cost at begining of current cost-block - m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getGasPtr(), llvm::UndefValue::get(Type::Gas), m_runtimeManager.getJmpBuf()}); } m_blockCost += getStepCost(_inst); @@ -134,7 +136,7 @@ void GasMeter::count(llvm::Value* _cost) } assert(_cost->getType() == Type::Gas); - createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); + createCall(m_gasCheckFunc, {m_runtimeManager.getGasPtr(), _cost, m_runtimeManager.getJmpBufExt()}); } void GasMeter::countExp(llvm::Value* _exponent) diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index 2f1fb390a..c74460e6a 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -31,6 +31,7 @@ public: llvm::Value* getCodeSize(); llvm::Value* getCallDataSize(); llvm::Value* getJmpBuf() { return m_jmpBuf; } + llvm::Value* getJmpBufExt(); void setGas(llvm::Value* _gas); void registerReturnData(llvm::Value* _index, llvm::Value* _size); @@ -49,7 +50,6 @@ public: private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBufExt(); llvm::Function* m_longjmp = nullptr; llvm::Value* const m_jmpBuf; diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp index 8e2bc13fc..00a143dea 100644 --- a/evmjit/libevmjit/Type.cpp +++ b/evmjit/libevmjit/Type.cpp @@ -1,4 +1,7 @@ #include "Type.h" + +#include + #include "RuntimeManager.h" namespace dev @@ -23,6 +26,7 @@ llvm::PointerType* Type::EnvPtr; llvm::PointerType* Type::RuntimeDataPtr; llvm::PointerType* Type::RuntimePtr; llvm::ConstantInt* Constant::gasMax; +llvm::MDNode* Type::expectTrue; void Type::init(llvm::LLVMContext& _context) { @@ -46,6 +50,8 @@ void Type::init(llvm::LLVMContext& _context) RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits::max()); + + expectTrue = llvm::MDBuilder{_context}.createBranchWeights(1, 0); } } diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index b8a4a09eb..ffacc5407 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -40,6 +40,9 @@ struct Type static llvm::PointerType* RuntimeDataPtr; static llvm::PointerType* RuntimePtr; + // TODO: Redesign static LLVM objects + static llvm::MDNode* expectTrue; + static void init(llvm::LLVMContext& _context); };