Browse Source

Count additional gas cost for memory copies. Some GasMeter improvments.

cl-refactor
Paweł Bylica 10 years ago
parent
commit
76d30b8f9f
  1. 37
      libevmjit/GasMeter.cpp
  2. 8
      libevmjit/GasMeter.h
  3. 10
      libevmjit/Memory.cpp
  4. 5
      libevmjit/Memory.h

37
libevmjit/GasMeter.cpp

@ -43,11 +43,16 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure
{
switch (inst)
{
default: // Assumes instruction code is valid
return 1;
case Instruction::STOP:
case Instruction::SUICIDE:
case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore()
return 0;
case Instruction::EXP: return c_expGas;
case Instruction::SLOAD: return c_sloadGas;
case Instruction::SHA3: return c_sha3Gas;
@ -68,9 +73,6 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure
auto numTopics = static_cast<uint64_t>(inst) - static_cast<uint64_t>(Instruction::LOG0);
return c_logGas + numTopics * c_logTopicGas;
}
default: // Assumes instruction code is valid
return 1;
}
}
@ -144,6 +146,11 @@ void GasMeter::count(Instruction _inst)
commitCostBlock();
}
void GasMeter::count(llvm::Value* _cost)
{
createCall(m_gasCheckFunc, _cost);
}
void GasMeter::countExp(llvm::Value* _exponent)
{
// Additional cost is 1 per significant byte of exponent
@ -156,7 +163,7 @@ void GasMeter::countExp(llvm::Value* _exponent)
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));
createCall(m_gasCheckFunc, sigBytes);
count(sigBytes);
}
void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue)
@ -172,15 +179,15 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu
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");
createCall(m_gasCheckFunc, cost);
count(cost);
}
void GasMeter::countLogData(llvm::Value* _dataLength)
{
assert(m_checkCall);
assert(m_blockCost > 0); // LOGn instruction is already counted
auto cost = m_builder.CreateMul(_dataLength, Constant::get(c_logDataGas), "logdata_cost");
commitCostBlock(cost);
static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter.");
commitCostBlock(_dataLength); // TODO: commit is not necessary
}
void GasMeter::giveBack(llvm::Value* _gas)
@ -207,17 +214,21 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
m_blockCost = 0;
if (_additionalCost)
{
m_builder.CreateCall(m_gasCheckFunc, _additionalCost);
}
count(_additionalCost);
}
assert(m_blockCost == 0);
}
void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords)
void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords)
{
static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter.");
count(_additionalMemoryInWords);
}
void GasMeter::countCopy(llvm::Value* _copyWords)
{
auto cost = m_builder.CreateNUWMul(_additionalMemoryInWords, Constant::get(static_cast<uint64_t>(c_memoryGas)), "memcost");
m_builder.CreateCall(m_gasCheckFunc, cost);
static_assert(c_copyGas == 1, "Copy gas cost has changed. Update GasMeter.");
count(_copyWords);
}
}

8
libevmjit/GasMeter.h

@ -20,6 +20,9 @@ public:
/// Count step cost of instruction
void count(Instruction _inst);
/// Count additional cost
void count(llvm::Value* _cost);
/// Calculate & count gas cost for SSTORE instruction
void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue);
@ -37,7 +40,10 @@ public:
void giveBack(llvm::Value* _gas);
/// Generate code that checks the cost of additional memory used by program
void checkMemory(llvm::Value* _additionalMemoryInWords);
void countMemory(llvm::Value* _additionalMemoryInWords);
/// Count addional gas cost for memory copy
void countCopy(llvm::Value* _copyWords);
private:
/// Cumulative gas cost of a block of instructions

10
libevmjit/Memory.cpp

@ -24,7 +24,8 @@ namespace jit
{
Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
RuntimeHelper(_runtimeManager)
RuntimeHelper(_runtimeManager),
m_gasMeter(_gasMeter)
{
auto module = getModule();
llvm::Type* argTypes[] = {Type::Word, Type::Word};
@ -88,7 +89,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _
sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq");
auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k
auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
_gasMeter.checkMemory(newWords);
_gasMeter.countMemory(newWords);
// Resize
m_builder.CreateStore(sizeRequired, m_size);
auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData");
@ -186,6 +187,11 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value*
require(_destMemIdx, _reqBytes);
// Additional copy cost
// TODO: This round ups to 32 happens in many places
auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32));
m_gasMeter.countCopy(copyWords);
auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx");
auto memPtr = getData();

5
libevmjit/Memory.h

@ -8,11 +8,12 @@ namespace eth
{
namespace jit
{
class GasMeter;
class Memory : public RuntimeHelper
{
public:
Memory(RuntimeManager& _runtimeManager, class GasMeter& _gasMeter);
Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter);
llvm::Value* loadWord(llvm::Value* _addr);
void storeWord(llvm::Value* _addr, llvm::Value* _word);
@ -27,6 +28,8 @@ public:
void require(llvm::Value* _offset, llvm::Value* _size);
private:
GasMeter& m_gasMeter;
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter);
llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager);

Loading…
Cancel
Save