From 407cae129f38abcdd1fbdfca366267cc59374c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:08:57 +0100 Subject: [PATCH] Count gas using int64 --- libevmjit/BasicBlock.cpp | 1 + libevmjit/Compiler.cpp | 3 +- libevmjit/Ext.cpp | 6 +- libevmjit/GasMeter.cpp | 103 ++++++++++++++++++----------------- libevmjit/GasMeter.h | 2 +- libevmjit/RuntimeManager.cpp | 10 ++-- 6 files changed, 66 insertions(+), 59 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index d907aada1..c71bae94f 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -44,6 +44,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : void BasicBlock::LocalStack::push(llvm::Value* _value) { + assert(_value->getType() == Type::Word); m_bblock.m_currentStack.push_back(_value); m_bblock.m_tosOffset += 1; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index eddd16492..b6206b8d8 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -630,7 +630,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::GAS: { _gasMeter.commitCostBlock(); - stack.push(_runtimeManager.getGas()); + stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word)); break; } @@ -770,6 +770,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti receiveAddress = _runtimeManager.get(RuntimeData::Address); _gasMeter.count(gas); + // TODO: pass gas to call as int64 auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); _gasMeter.giveBack(gas); stack.push(ret); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 965ef2e06..28e10366c 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -128,12 +128,14 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas = byPtr(_gas); + auto gas256 = m_builder.CreateZExt(_gas, Type::Word, "gas256"); + auto gas = byPtr(gas256); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - _gas = m_builder.CreateLoad(gas); // Return gas + gas256 = m_builder.CreateLoad(gas); // Return gas + _gas = m_builder.CreateTrunc(gas256, Type::Gas); llvm::Value* address = m_builder.CreateLoad(ret); address = Endianness::toNative(m_builder, address); return address; diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index d54eea754..8ac575338 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -19,29 +19,29 @@ namespace jit namespace // Helper functions { -uint64_t const c_stepGas = 1; -uint64_t const c_balanceGas = 20; -uint64_t const c_sha3Gas = 10; -uint64_t const c_sha3WordGas = 10; -uint64_t const c_sloadGas = 20; -uint64_t const c_sstoreSetGas = 300; -uint64_t const c_sstoreResetGas = 100; -uint64_t const c_sstoreRefundGas = 100; -uint64_t const c_createGas = 100; -uint64_t const c_createDataGas = 5; -uint64_t const c_callGas = 20; -uint64_t const c_expGas = 1; -uint64_t const c_expByteGas = 1; -uint64_t const c_memoryGas = 1; -uint64_t const c_txDataZeroGas = 1; -uint64_t const c_txDataNonZeroGas = 5; -uint64_t const c_txGas = 500; -uint64_t const c_logGas = 32; -uint64_t const c_logDataGas = 1; -uint64_t const c_logTopicGas = 32; -uint64_t const c_copyGas = 1; - -uint64_t getStepCost(Instruction inst) +int64_t const c_stepGas = 1; +int64_t const c_balanceGas = 20; +int64_t const c_sha3Gas = 10; +int64_t const c_sha3WordGas = 10; +int64_t const c_sloadGas = 20; +int64_t const c_sstoreSetGas = 300; +int64_t const c_sstoreResetGas = 100; +int64_t const c_sstoreRefundGas = 100; +int64_t const c_createGas = 100; +int64_t const c_createDataGas = 5; +int64_t const c_callGas = 20; +int64_t const c_expGas = 1; +int64_t const c_expByteGas = 1; +int64_t const c_memoryGas = 1; +int64_t const c_txDataZeroGas = 1; +int64_t const c_txDataNonZeroGas = 5; +int64_t const c_txGas = 500; +int64_t const c_logGas = 32; +int64_t const c_logDataGas = 1; +int64_t const c_logTopicGas = 32; +int64_t const c_copyGas = 1; + +int64_t getStepCost(Instruction inst) { switch (inst) { @@ -72,7 +72,7 @@ uint64_t getStepCost(Instruction inst) case Instruction::LOG3: case Instruction::LOG4: { - auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); return c_logGas + numTopics * c_logTopicGas; } } @@ -86,7 +86,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) { auto module = getModule(); - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; + 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); @@ -94,15 +94,15 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - auto arg = m_gasCheckFunc->arg_begin(); - arg->setName("rt"); - ++arg; - arg->setName("cost"); - auto cost = arg; + auto rt = &m_gasCheckFunc->getArgumentList().front(); + rt->setName("rt"); + auto cost = rt->getNextNode(); + cost->setName("cost"); m_builder.SetInsertPoint(checkBB); auto gas = m_runtimeManager.getGas(); - auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); + 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); @@ -110,7 +110,6 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); - gas = m_builder.CreateSub(gas, cost); m_runtimeManager.setGas(gas); m_builder.CreateRetVoid(); } @@ -120,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::Word)}); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); } m_blockCost += getStepCost(_inst); @@ -128,6 +127,15 @@ void GasMeter::count(Instruction _inst) void GasMeter::count(llvm::Value* _cost) { + if (_cost->getType() == Type::Word) + { + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh"); + auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas); + _cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost"); + } + + assert(_cost->getType() == Type::Gas); createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); } @@ -137,12 +145,13 @@ void GasMeter::countExp(llvm::Value* _exponent) // lz - leading zeros // cost = ((256 - lz) + 7) / 8 - // OPT: All calculations can be done on 32/64 bits + // OPT: Can gas update be done in exp algorithm? auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); - auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); - auto sigBits = m_builder.CreateSub(Constant::get(256), lz); - auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); + auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); count(sigBytes); } @@ -155,8 +164,8 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); - auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); - cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); + auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost"); + cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost"); count(cost); } @@ -179,13 +188,13 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); - auto cost = getBuilder().CreateZExt(cost64, Type::Word); - count(cost); + count(cost64); } void GasMeter::giveBack(llvm::Value* _gas) { - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); + assert(_gas->getType() == Type::Word); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), m_builder.CreateTrunc(_gas, Type::Gas))); } void GasMeter::commitCostBlock() @@ -200,7 +209,7 @@ void GasMeter::commitCostBlock() return; } - m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call + m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block m_blockCost = 0; } @@ -209,14 +218,8 @@ void GasMeter::commitCostBlock() void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) { - assert(_additionalMemoryInWords->getType() == Type::Word); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); - auto tooHigh = m_builder.CreateICmpUGT(_additionalMemoryInWords, gasMax256, "tooHigh"); - auto additionalMemoryInWords64 = m_builder.CreateTrunc(_additionalMemoryInWords, Type::Gas); - additionalMemoryInWords64 = m_builder.CreateSelect(tooHigh, Constant::gasMax, additionalMemoryInWords64, "additionalMemoryInWords"); - auto additionalMemoryInWords256 = m_builder.CreateZExt(additionalMemoryInWords64, Type::Word); - count(additionalMemoryInWords256); + count(_additionalMemoryInWords); } void GasMeter::countCopy(llvm::Value* _copyWords) diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 56da6eb9f..27f55253f 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -50,7 +50,7 @@ public: private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow - uint64_t m_blockCost = 0; + int64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; llvm::Function* m_gasCheckFunc = nullptr; diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 408f2dee3..1441f475a 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -216,15 +216,15 @@ llvm::Value* RuntimeManager::getJmpBuf() llvm::Value* RuntimeManager::getGas() { - auto value = get(RuntimeData::Gas); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + auto gas = get(RuntimeData::Gas); + assert(gas->getType() == Type::Gas); + return gas; } void RuntimeManager::setGas(llvm::Value* _gas) { - auto newGas = getBuilder().CreateTrunc(_gas, Type::Size); - set(RuntimeData::Gas, newGas); + assert(_gas->getType() == Type::Gas); + set(RuntimeData::Gas, _gas); } }