GasMeter.cpp
1 #include "GasMeter.h" 2 3 #include "preprocessor/llvm_includes_start.h" 4 #include <llvm/IR/IntrinsicInst.h> 5 #include "preprocessor/llvm_includes_end.h" 6 7 #include "JIT.h" 8 #include "Ext.h" 9 #include "RuntimeManager.h" 10 11 namespace dev 12 { 13 namespace eth 14 { 15 namespace jit 16 { 17 18 GasMeter::GasMeter(IRBuilder& _builder, RuntimeManager& _runtimeManager, evmc_revision rev): 19 CompilerHelper(_builder), 20 m_runtimeManager(_runtimeManager), 21 m_rev(rev) 22 { 23 llvm::Type* gasCheckArgs[] = {Type::Gas->getPointerTo(), Type::Gas, Type::BytePtr}; 24 m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", getModule()); 25 m_gasCheckFunc->setDoesNotThrow(); 26 m_gasCheckFunc->addAttribute(1, llvm::Attribute::NoCapture); 27 28 auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); 29 auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); 30 auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); 31 32 auto iter = m_gasCheckFunc->arg_begin(); 33 llvm::Argument* gasPtr = &(*iter++); 34 gasPtr->setName("gasPtr"); 35 llvm::Argument* cost = &(*iter++); 36 cost->setName("cost"); 37 llvm::Argument* jmpBuf = &(*iter); 38 jmpBuf->setName("jmpBuf"); 39 40 InsertPointGuard guard(m_builder); 41 m_builder.SetInsertPoint(checkBB); 42 auto gas = m_builder.CreateLoad(gasPtr, "gas"); 43 auto gasUpdated = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); 44 auto gasOk = m_builder.CreateICmpSGE(gasUpdated, m_builder.getInt64(0), "gasOk"); // gas >= 0, with gas == 0 we can still do 0 cost instructions 45 m_builder.CreateCondBr(gasOk, updateBB, outOfGasBB, Type::expectTrue); 46 47 m_builder.SetInsertPoint(updateBB); 48 m_builder.CreateStore(gasUpdated, gasPtr); 49 m_builder.CreateRetVoid(); 50 51 m_builder.SetInsertPoint(outOfGasBB); 52 m_runtimeManager.abort(jmpBuf); 53 m_builder.CreateUnreachable(); 54 } 55 56 void GasMeter::count(Instruction _inst) 57 { 58 if (!m_checkCall) 59 { 60 // Create gas check call with mocked block cost at begining of current cost-block 61 m_checkCall = m_builder.CreateCall(m_gasCheckFunc, {m_runtimeManager.getGasPtr(), llvm::UndefValue::get(Type::Gas), m_runtimeManager.getJmpBuf()}); 62 } 63 64 m_blockCost += getStepCost(_inst); 65 } 66 67 void GasMeter::count(llvm::Value* _cost, llvm::Value* _jmpBuf, llvm::Value* _gasPtr) 68 { 69 if (_cost->getType() == Type::Word) 70 { 71 auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); 72 auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh"); 73 auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas); 74 _cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost"); 75 } 76 77 assert(_cost->getType() == Type::Gas); 78 m_builder.CreateCall(m_gasCheckFunc, {_gasPtr ? _gasPtr : m_runtimeManager.getGasPtr(), _cost, _jmpBuf ? _jmpBuf : m_runtimeManager.getJmpBuf()}); 79 } 80 81 void GasMeter::countExp(llvm::Value* _exponent) 82 { 83 // Additional cost is 1 per significant byte of exponent 84 // lz - leading zeros 85 // cost = ((256 - lz) + 7) / 8 86 87 // OPT: Can gas update be done in exp algorithm? 88 auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); 89 auto lz256 = m_builder.CreateCall(ctlz, {_exponent, m_builder.getInt1(false)}); 90 auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); 91 auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); 92 auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); 93 auto exponentByteCost = m_rev >= EVMC_SPURIOUS_DRAGON ? 50 : JITSchedule::expByteGas::value; 94 count(m_builder.CreateNUWMul(sigBytes, m_builder.getInt64(exponentByteCost))); 95 } 96 97 void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) 98 { 99 auto oldValue = _ext.sload(_index); 100 auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero"); 101 auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); 102 auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); 103 assert(JITSchedule::sstoreResetGas::value == JITSchedule::sstoreClearGas::value && "Update SSTORE gas cost"); 104 auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(JITSchedule::sstoreSetGas::value), m_builder.getInt64(JITSchedule::sstoreResetGas::value), "cost"); 105 count(cost); 106 } 107 108 void GasMeter::countLogData(llvm::Value* _dataLength) 109 { 110 assert(m_checkCall); 111 assert(m_blockCost > 0); // LOGn instruction is already counted 112 assert(JITSchedule::logDataGas::value != 1 && "Log data gas cost has changed. Update GasMeter."); 113 count(m_builder.CreateNUWMul(_dataLength, Constant::get(JITSchedule::logDataGas::value))); // TODO: Use i64 114 } 115 116 void GasMeter::countSha3Data(llvm::Value* _dataLength) 117 { 118 assert(m_checkCall); 119 assert(m_blockCost > 0); // SHA3 instruction is already counted 120 121 // TODO: This round ups to 32 happens in many places 122 assert(JITSchedule::sha3WordGas::value != 1 && "SHA3 data cost has changed. Update GasMeter"); 123 auto dataLength64 = m_builder.CreateTrunc(_dataLength, Type::Gas); 124 auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, m_builder.getInt64(31)), m_builder.getInt64(32)); 125 auto cost64 = m_builder.CreateNUWMul(m_builder.getInt64(JITSchedule::sha3WordGas::value), words64); 126 count(cost64); 127 } 128 129 void GasMeter::giveBack(llvm::Value* _gas) 130 { 131 assert(_gas->getType() == Type::Gas); 132 m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); 133 } 134 135 void GasMeter::commitCostBlock() 136 { 137 // If any uncommited block 138 if (m_checkCall) 139 { 140 if (m_blockCost == 0) // Do not check 0 141 { 142 m_checkCall->eraseFromParent(); // Remove the gas check call 143 m_checkCall = nullptr; 144 return; 145 } 146 147 m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call 148 m_checkCall = nullptr; // End cost-block 149 m_blockCost = 0; 150 } 151 assert(m_blockCost == 0); 152 } 153 154 void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords, llvm::Value* _jmpBuf, llvm::Value* _gasPtr) 155 { 156 assert(JITSchedule::memoryGas::value != 1 && "Memory gas cost has changed. Update GasMeter."); 157 count(_additionalMemoryInWords, _jmpBuf, _gasPtr); 158 } 159 160 void GasMeter::countCopy(llvm::Value* _copyWords) 161 { 162 assert(JITSchedule::copyGas::value != 1 && "Copy gas cost has changed. Update GasMeter."); 163 count(m_builder.CreateNUWMul(_copyWords, m_builder.getInt64(JITSchedule::copyGas::value))); 164 } 165 166 int64_t GasMeter::getStepCost(Instruction inst) const 167 { 168 switch (inst) 169 { 170 // Tier 0 171 case Instruction::STOP: 172 case Instruction::RETURN: 173 case Instruction::REVERT: 174 case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() 175 return JITSchedule::stepGas0::value; 176 177 // Tier 1 178 case Instruction::ADDRESS: 179 case Instruction::ORIGIN: 180 case Instruction::CALLER: 181 case Instruction::CALLVALUE: 182 case Instruction::CALLDATASIZE: 183 case Instruction::RETURNDATASIZE: 184 case Instruction::CODESIZE: 185 case Instruction::GASPRICE: 186 case Instruction::COINBASE: 187 case Instruction::TIMESTAMP: 188 case Instruction::NUMBER: 189 case Instruction::DIFFICULTY: 190 case Instruction::GASLIMIT: 191 case Instruction::POP: 192 case Instruction::PC: 193 case Instruction::MSIZE: 194 case Instruction::GAS: 195 return JITSchedule::stepGas1::value; 196 197 // Tier 2 198 case Instruction::ADD: 199 case Instruction::SUB: 200 case Instruction::LT: 201 case Instruction::GT: 202 case Instruction::SLT: 203 case Instruction::SGT: 204 case Instruction::EQ: 205 case Instruction::ISZERO: 206 case Instruction::AND: 207 case Instruction::OR: 208 case Instruction::XOR: 209 case Instruction::NOT: 210 case Instruction::BYTE: 211 case Instruction::CALLDATALOAD: 212 case Instruction::CALLDATACOPY: 213 case Instruction::RETURNDATACOPY: 214 case Instruction::CODECOPY: 215 case Instruction::MLOAD: 216 case Instruction::MSTORE: 217 case Instruction::MSTORE8: 218 case Instruction::ANY_PUSH: 219 case Instruction::ANY_DUP: 220 case Instruction::ANY_SWAP: 221 return JITSchedule::stepGas2::value; 222 223 // Tier 3 224 case Instruction::MUL: 225 case Instruction::DIV: 226 case Instruction::SDIV: 227 case Instruction::MOD: 228 case Instruction::SMOD: 229 case Instruction::SIGNEXTEND: 230 return JITSchedule::stepGas3::value; 231 232 // Tier 4 233 case Instruction::ADDMOD: 234 case Instruction::MULMOD: 235 case Instruction::JUMP: 236 return JITSchedule::stepGas4::value; 237 238 // Tier 5 239 case Instruction::EXP: 240 case Instruction::JUMPI: 241 return JITSchedule::stepGas5::value; 242 243 // Tier 6 244 case Instruction::BALANCE: 245 return m_rev >= EVMC_TANGERINE_WHISTLE ? 400 : JITSchedule::stepGas6::value; 246 247 case Instruction::EXTCODESIZE: 248 case Instruction::EXTCODECOPY: 249 return m_rev >= EVMC_TANGERINE_WHISTLE ? 700 : JITSchedule::stepGas6::value; 250 251 case Instruction::BLOCKHASH: 252 return m_rev >= EVMC_CONSTANTINOPLE ? 800 : JITSchedule::stepGas6::value; 253 254 case Instruction::SHA3: 255 return JITSchedule::sha3Gas::value; 256 257 case Instruction::SLOAD: 258 return m_rev >= EVMC_TANGERINE_WHISTLE ? 200 : JITSchedule::sloadGas::value; 259 260 case Instruction::JUMPDEST: 261 return JITSchedule::jumpdestGas::value; 262 263 case Instruction::LOG0: 264 case Instruction::LOG1: 265 case Instruction::LOG2: 266 case Instruction::LOG3: 267 case Instruction::LOG4: 268 { 269 auto numTopics = static_cast<int64_t>(inst) - static_cast<int64_t>(Instruction::LOG0); 270 return JITSchedule::logGas::value + numTopics * JITSchedule::logTopicGas::value; 271 } 272 273 case Instruction::CALL: 274 case Instruction::CALLCODE: 275 case Instruction::DELEGATECALL: 276 case Instruction::STATICCALL: 277 return m_rev >= EVMC_TANGERINE_WHISTLE ? 700 : JITSchedule::callGas::value; 278 279 case Instruction::CREATE: 280 return JITSchedule::createGas::value; 281 282 case Instruction::SUICIDE: 283 return m_rev >= EVMC_TANGERINE_WHISTLE ? 5000 : JITSchedule::stepGas0::value; 284 285 default: 286 // For invalid instruction just return 0. 287 return 0; 288 } 289 } 290 291 } 292 } 293 }