/ libevmjit / GasMeter.cpp
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  }