Browse Source

Count gas using int64

cl-refactor
Paweł Bylica 10 years ago
parent
commit
407cae129f
  1. 1
      libevmjit/BasicBlock.cpp
  2. 3
      libevmjit/Compiler.cpp
  3. 6
      libevmjit/Ext.cpp
  4. 103
      libevmjit/GasMeter.cpp
  5. 2
      libevmjit/GasMeter.h
  6. 10
      libevmjit/RuntimeManager.cpp

1
libevmjit/BasicBlock.cpp

@ -44,6 +44,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) :
void BasicBlock::LocalStack::push(llvm::Value* _value) void BasicBlock::LocalStack::push(llvm::Value* _value)
{ {
assert(_value->getType() == Type::Word);
m_bblock.m_currentStack.push_back(_value); m_bblock.m_currentStack.push_back(_value);
m_bblock.m_tosOffset += 1; m_bblock.m_tosOffset += 1;
} }

3
libevmjit/Compiler.cpp

@ -630,7 +630,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
case Instruction::GAS: case Instruction::GAS:
{ {
_gasMeter.commitCostBlock(); _gasMeter.commitCostBlock();
stack.push(_runtimeManager.getGas()); stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word));
break; break;
} }
@ -770,6 +770,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
receiveAddress = _runtimeManager.get(RuntimeData::Address); receiveAddress = _runtimeManager.get(RuntimeData::Address);
_gasMeter.count(gas); _gasMeter.count(gas);
// TODO: pass gas to call as int64
auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress);
_gasMeter.giveBack(gas); _gasMeter.giveBack(gas);
stack.push(ret); stack.push(ret);

6
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) 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 ret = getArgAlloca();
auto begin = m_memoryMan.getBytePtr(_initOff); auto begin = m_memoryMan.getBytePtr(_initOff);
auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size");
createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); 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); llvm::Value* address = m_builder.CreateLoad(ret);
address = Endianness::toNative(m_builder, address); address = Endianness::toNative(m_builder, address);
return address; return address;

103
libevmjit/GasMeter.cpp

@ -19,29 +19,29 @@ namespace jit
namespace // Helper functions namespace // Helper functions
{ {
uint64_t const c_stepGas = 1; int64_t const c_stepGas = 1;
uint64_t const c_balanceGas = 20; int64_t const c_balanceGas = 20;
uint64_t const c_sha3Gas = 10; int64_t const c_sha3Gas = 10;
uint64_t const c_sha3WordGas = 10; int64_t const c_sha3WordGas = 10;
uint64_t const c_sloadGas = 20; int64_t const c_sloadGas = 20;
uint64_t const c_sstoreSetGas = 300; int64_t const c_sstoreSetGas = 300;
uint64_t const c_sstoreResetGas = 100; int64_t const c_sstoreResetGas = 100;
uint64_t const c_sstoreRefundGas = 100; int64_t const c_sstoreRefundGas = 100;
uint64_t const c_createGas = 100; int64_t const c_createGas = 100;
uint64_t const c_createDataGas = 5; int64_t const c_createDataGas = 5;
uint64_t const c_callGas = 20; int64_t const c_callGas = 20;
uint64_t const c_expGas = 1; int64_t const c_expGas = 1;
uint64_t const c_expByteGas = 1; int64_t const c_expByteGas = 1;
uint64_t const c_memoryGas = 1; int64_t const c_memoryGas = 1;
uint64_t const c_txDataZeroGas = 1; int64_t const c_txDataZeroGas = 1;
uint64_t const c_txDataNonZeroGas = 5; int64_t const c_txDataNonZeroGas = 5;
uint64_t const c_txGas = 500; int64_t const c_txGas = 500;
uint64_t const c_logGas = 32; int64_t const c_logGas = 32;
uint64_t const c_logDataGas = 1; int64_t const c_logDataGas = 1;
uint64_t const c_logTopicGas = 32; int64_t const c_logTopicGas = 32;
uint64_t const c_copyGas = 1; int64_t const c_copyGas = 1;
uint64_t getStepCost(Instruction inst) int64_t getStepCost(Instruction inst)
{ {
switch (inst) switch (inst)
{ {
@ -72,7 +72,7 @@ uint64_t getStepCost(Instruction inst)
case Instruction::LOG3: case Instruction::LOG3:
case Instruction::LOG4: case Instruction::LOG4:
{ {
auto numTopics = static_cast<uint64_t>(inst) - static_cast<uint64_t>(Instruction::LOG0); auto numTopics = static_cast<int64_t>(inst) - static_cast<int64_t>(Instruction::LOG0);
return c_logGas + numTopics * c_logTopicGas; return c_logGas + numTopics * c_logTopicGas;
} }
} }
@ -86,7 +86,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
{ {
auto module = getModule(); 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); m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module);
InsertPointGuard guard(m_builder); 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 outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc);
auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc);
auto arg = m_gasCheckFunc->arg_begin(); auto rt = &m_gasCheckFunc->getArgumentList().front();
arg->setName("rt"); rt->setName("rt");
++arg; auto cost = rt->getNextNode();
arg->setName("cost"); cost->setName("cost");
auto cost = arg;
m_builder.SetInsertPoint(checkBB); m_builder.SetInsertPoint(checkBB);
auto gas = m_runtimeManager.getGas(); 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.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);
m_builder.SetInsertPoint(outOfGasBB); m_builder.SetInsertPoint(outOfGasBB);
@ -110,7 +110,6 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
m_builder.CreateUnreachable(); m_builder.CreateUnreachable();
m_builder.SetInsertPoint(updateBB); m_builder.SetInsertPoint(updateBB);
gas = m_builder.CreateSub(gas, cost);
m_runtimeManager.setGas(gas); m_runtimeManager.setGas(gas);
m_builder.CreateRetVoid(); m_builder.CreateRetVoid();
} }
@ -120,7 +119,7 @@ void GasMeter::count(Instruction _inst)
if (!m_checkCall) if (!m_checkCall)
{ {
// Create gas check call with mocked block cost at begining of current cost-block // 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); m_blockCost += getStepCost(_inst);
@ -128,6 +127,15 @@ void GasMeter::count(Instruction _inst)
void GasMeter::count(llvm::Value* _cost) 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}); createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost});
} }
@ -137,12 +145,13 @@ void GasMeter::countExp(llvm::Value* _exponent)
// lz - leading zeros // lz - leading zeros
// cost = ((256 - lz) + 7) / 8 // 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 ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word);
auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
auto sigBits = m_builder.CreateSub(Constant::get(256), lz); auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz");
auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); 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); 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 newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert");
auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete");
auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost");
cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost");
count(cost); count(cost);
} }
@ -179,13 +188,13 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength)
auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision);
auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); 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 cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64);
auto cost = getBuilder().CreateZExt(cost64, Type::Word); count(cost64);
count(cost);
} }
void GasMeter::giveBack(llvm::Value* _gas) 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() void GasMeter::commitCostBlock()
@ -200,7 +209,7 @@ void GasMeter::commitCostBlock()
return; 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_checkCall = nullptr; // End cost-block
m_blockCost = 0; m_blockCost = 0;
} }
@ -209,14 +218,8 @@ void GasMeter::commitCostBlock()
void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords)
{ {
assert(_additionalMemoryInWords->getType() == Type::Word);
static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter.");
auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); count(_additionalMemoryInWords);
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);
} }
void GasMeter::countCopy(llvm::Value* _copyWords) void GasMeter::countCopy(llvm::Value* _copyWords)

2
libevmjit/GasMeter.h

@ -50,7 +50,7 @@ public:
private: private:
/// Cumulative gas cost of a block of instructions /// Cumulative gas cost of a block of instructions
/// @TODO Handle overflow /// @TODO Handle overflow
uint64_t m_blockCost = 0; int64_t m_blockCost = 0;
llvm::CallInst* m_checkCall = nullptr; llvm::CallInst* m_checkCall = nullptr;
llvm::Function* m_gasCheckFunc = nullptr; llvm::Function* m_gasCheckFunc = nullptr;

10
libevmjit/RuntimeManager.cpp

@ -216,15 +216,15 @@ llvm::Value* RuntimeManager::getJmpBuf()
llvm::Value* RuntimeManager::getGas() llvm::Value* RuntimeManager::getGas()
{ {
auto value = get(RuntimeData::Gas); auto gas = get(RuntimeData::Gas);
assert(value->getType() == Type::Size); assert(gas->getType() == Type::Gas);
return getBuilder().CreateZExt(value, Type::Word); return gas;
} }
void RuntimeManager::setGas(llvm::Value* _gas) void RuntimeManager::setGas(llvm::Value* _gas)
{ {
auto newGas = getBuilder().CreateTrunc(_gas, Type::Size); assert(_gas->getType() == Type::Gas);
set(RuntimeData::Gas, newGas); set(RuntimeData::Gas, _gas);
} }
} }

Loading…
Cancel
Save