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) switch (inst)
{ {
default: // Assumes instruction code is valid
return 1;
case Instruction::STOP: case Instruction::STOP:
case Instruction::SUICIDE: case Instruction::SUICIDE:
case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore()
return 0; return 0;
case Instruction::EXP: return c_expGas;
case Instruction::SLOAD: return c_sloadGas; case Instruction::SLOAD: return c_sloadGas;
case Instruction::SHA3: return c_sha3Gas; 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); auto numTopics = static_cast<uint64_t>(inst) - static_cast<uint64_t>(Instruction::LOG0);
return c_logGas + numTopics * c_logTopicGas; return c_logGas + numTopics * c_logTopicGas;
} }
default: // Assumes instruction code is valid
return 1;
} }
} }
@ -144,6 +146,11 @@ void GasMeter::count(Instruction _inst)
commitCostBlock(); commitCostBlock();
} }
void GasMeter::count(llvm::Value* _cost)
{
createCall(m_gasCheckFunc, _cost);
}
void GasMeter::countExp(llvm::Value* _exponent) void GasMeter::countExp(llvm::Value* _exponent)
{ {
// Additional cost is 1 per significant byte of 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 lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
auto sigBits = m_builder.CreateSub(Constant::get(256), lz); 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 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) 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 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, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost");
cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost");
createCall(m_gasCheckFunc, cost); count(cost);
} }
void GasMeter::countLogData(llvm::Value* _dataLength) void GasMeter::countLogData(llvm::Value* _dataLength)
{ {
assert(m_checkCall); assert(m_checkCall);
assert(m_blockCost > 0); // LOGn instruction is already counted assert(m_blockCost > 0); // LOGn instruction is already counted
auto cost = m_builder.CreateMul(_dataLength, Constant::get(c_logDataGas), "logdata_cost"); static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter.");
commitCostBlock(cost); commitCostBlock(_dataLength); // TODO: commit is not necessary
} }
void GasMeter::giveBack(llvm::Value* _gas) void GasMeter::giveBack(llvm::Value* _gas)
@ -207,17 +214,21 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
m_blockCost = 0; m_blockCost = 0;
if (_additionalCost) if (_additionalCost)
{ count(_additionalCost);
m_builder.CreateCall(m_gasCheckFunc, _additionalCost);
}
} }
assert(m_blockCost == 0); 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"); static_assert(c_copyGas == 1, "Copy gas cost has changed. Update GasMeter.");
m_builder.CreateCall(m_gasCheckFunc, cost); count(_copyWords);
} }
} }

8
libevmjit/GasMeter.h

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

10
libevmjit/Memory.cpp

@ -24,7 +24,8 @@ namespace jit
{ {
Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
RuntimeHelper(_runtimeManager) RuntimeHelper(_runtimeManager),
m_gasMeter(_gasMeter)
{ {
auto module = getModule(); auto module = getModule();
llvm::Type* argTypes[] = {Type::Word, Type::Word}; 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"); 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 words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k
auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
_gasMeter.checkMemory(newWords); _gasMeter.countMemory(newWords);
// Resize // Resize
m_builder.CreateStore(sizeRequired, m_size); m_builder.CreateStore(sizeRequired, m_size);
auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData"); 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); 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 srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx");
auto memPtr = getData(); auto memPtr = getData();

5
libevmjit/Memory.h

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

Loading…
Cancel
Save