Browse Source

Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc

Conflicts:
	evmcc/Compiler.cpp
cl-refactor
artur-zawlocki 10 years ago
parent
commit
6fff5adfa6
  1. 8
      evmcc/Compiler.cpp
  2. 4
      evmcc/ExecutionEngine.cpp
  3. 6
      evmcc/Ext.cpp
  4. 22
      evmcc/GasMeter.cpp
  5. 11
      evmcc/GasMeter.h
  6. 28
      evmcc/Memory.cpp
  7. 5
      evmcc/Memory.h
  8. 12
      evmcc/Runtime.cpp
  9. 10
      evmcc/Runtime.h

8
evmcc/Compiler.cpp

@ -199,9 +199,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
createBasicBlocks(bytecode); createBasicBlocks(bytecode);
// Init runtime structures. // Init runtime structures.
Memory memory(builder, module.get());
Ext ext(builder, module.get());
GasMeter gasMeter(builder, module.get()); GasMeter gasMeter(builder, module.get());
Memory memory(builder, module.get(), gasMeter);
Ext ext(builder, module.get());
// Jump to first instruction // Jump to first instruction
builder.CreateBr(basicBlocks.begin()->second); builder.CreateBr(basicBlocks.begin()->second);
@ -216,7 +216,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
{ {
auto inst = static_cast<Instruction>(bytecode[currentPC]); auto inst = static_cast<Instruction>(bytecode[currentPC]);
gasMeter.check(inst); gasMeter.count(inst);
switch (inst) switch (inst)
{ {
@ -820,6 +820,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
} }
} }
gasMeter.commitCostBlock();
if (!builder.GetInsertBlock()->getTerminator()) // If block not terminated if (!builder.GetInsertBlock()->getTerminator()) // If block not terminated
{ {
if (basicBlock.end() == bytecode.size()) if (basicBlock.end() == bytecode.size())

4
evmcc/ExecutionEngine.cpp

@ -85,7 +85,8 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
ext->data = calldata; ext->data = calldata;
// Init runtime // Init runtime
Runtime runtime(std::move(ext)); uint64_t gas = 1000000;
Runtime runtime(gas, std::move(ext));
auto entryFunc = module->getFunction("main"); auto entryFunc = module->getFunction("main");
if (!entryFunc) if (!entryFunc)
@ -95,6 +96,7 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
} }
auto result = exec->runFunction(entryFunc, {}); auto result = exec->runFunction(entryFunc, {});
gas = static_cast<decltype(gas)>(Runtime::getGas());
if (auto intResult = result.IntVal.getZExtValue()) if (auto intResult = result.IntVal.getZExtValue())
{ {
auto index = intResult >> 32; auto index = intResult >> 32;

6
evmcc/Ext.cpp

@ -9,12 +9,6 @@
#include "Runtime.h" #include "Runtime.h"
#ifdef _MSC_VER
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
using namespace llvm; using namespace llvm;
using llvm::types::i; using llvm::types::i;
using Linkage = llvm::GlobalValue::LinkageTypes; using Linkage = llvm::GlobalValue::LinkageTypes;

22
evmcc/GasMeter.cpp

@ -81,7 +81,7 @@ bool isCostBlockEnd(Instruction _inst)
GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module):
m_builder(_builder) m_builder(_builder)
{ {
m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::i256), "gas"); m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas");
m_gas->setUnnamedAddr(true); // Address is not important m_gas->setUnnamedAddr(true); // Address is not important
auto pt = m_builder.GetInsertPoint(); auto pt = m_builder.GetInsertPoint();
@ -97,21 +97,37 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module):
m_builder.SetInsertPoint(bb, pt); m_builder.SetInsertPoint(bb, pt);
} }
void GasMeter::check(Instruction _inst) 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 = m_builder.CreateCall(m_gasCheckFunc, m_builder.getIntN(256, 0)); m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256));
} }
m_blockCost += getStepCost(_inst); m_blockCost += getStepCost(_inst);
if (isCostBlockEnd(_inst)) if (isCostBlockEnd(_inst))
commitCostBlock();
}
void GasMeter::commitCostBlock()
{
// If any uncommited block
if (m_checkCall)
{ {
m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call
m_checkCall = nullptr; // End cost-block m_checkCall = nullptr; // End cost-block
m_blockCost = 0;
} }
assert(m_blockCost == 0);
}
void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder)
{
// Memory uses other builder, but that can be changes later
auto cost = _builder.CreateMul(_additionalMemoryInWords, _builder.getIntN(256, static_cast<uint64_t>(c_memoryGas)), "memcost");
_builder.CreateCall(m_gasCheckFunc, cost);
} }
} }

11
evmcc/GasMeter.h

@ -16,14 +16,21 @@ public:
GasMeter(const GasMeter&) = delete; GasMeter(const GasMeter&) = delete;
void operator=(GasMeter) = delete; void operator=(GasMeter) = delete;
void check(dev::eth::Instruction _inst); /// Count step cost of instruction
void count(dev::eth::Instruction _inst);
/// Finalize cost block by checking gas needed for the block before the block
void commitCostBlock();
/// Generate code that checks the cost of additional memory used by program
void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder);
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; uint64_t m_blockCost = 0;
llvm::IRBuilder<>& m_builder; llvm::IRBuilder<>& m_builder;
llvm::CallInst* m_checkCall; llvm::CallInst* m_checkCall = nullptr;
llvm::GlobalVariable* m_gas; llvm::GlobalVariable* m_gas;
llvm::Function* m_gasCheckFunc; llvm::Function* m_gasCheckFunc;
}; };

28
evmcc/Memory.cpp

@ -13,18 +13,13 @@
#include "Type.h" #include "Type.h"
#include "Runtime.h" #include "Runtime.h"
#include "GasMeter.h"
#ifdef _MSC_VER
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
namespace evmcc namespace evmcc
{ {
Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter):
: m_builder(_builder) m_builder(_builder)
{ {
auto voidTy = m_builder.getVoidTy(); auto voidTy = m_builder.getVoidTy();
auto i64Ty = m_builder.getInt64Ty(); auto i64Ty = m_builder.getInt64Ty();
@ -51,12 +46,12 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module)
m_size->setUnnamedAddr(true); // Address is not important m_size->setUnnamedAddr(true); // Address is not important
m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module); m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module);
m_loadWord = createFunc(false, Type::i256, _module); m_loadWord = createFunc(false, Type::i256, _module, _gasMeter);
m_storeWord = createFunc(true, Type::i256, _module); m_storeWord = createFunc(true, Type::i256, _module, _gasMeter);
m_storeByte = createFunc(true, Type::Byte, _module); m_storeByte = createFunc(true, Type::Byte, _module, _gasMeter);
} }
llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::Module* _module) llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::Module* _module, GasMeter& _gasMeter)
{ {
auto isWord = _valueType == Type::i256; auto isWord = _valueType == Type::i256;
@ -69,6 +64,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::
auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func); auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func);
auto accessBB = llvm::BasicBlock::Create(func->getContext(), "access", func); auto accessBB = llvm::BasicBlock::Create(func->getContext(), "access", func);
// BB "check"
llvm::IRBuilder<> builder(checkBB); llvm::IRBuilder<> builder(checkBB);
llvm::Value* index = func->arg_begin(); llvm::Value* index = func->arg_begin();
index->setName("index"); index->setName("index");
@ -78,12 +74,20 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::
auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded"); auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded");
builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights? builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights?
// BB "resize"
builder.SetInsertPoint(resizeBB); builder.SetInsertPoint(resizeBB);
// Check gas first
auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, builder.getIntN(256, 31)), builder.getIntN(256, 32), "wordsRequired");
auto words = builder.CreateUDiv(builder.CreateAdd(size, builder.getIntN(256, 31)), builder.getIntN(256, 32), "words");
auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords");
_gasMeter.checkMemory(newWords, builder);
// Resize
builder.CreateStore(sizeRequired, m_size); builder.CreateStore(sizeRequired, m_size);
auto newData = builder.CreateCall(m_resize, m_size, "newData"); auto newData = builder.CreateCall(m_resize, m_size, "newData");
builder.CreateStore(newData, m_data); builder.CreateStore(newData, m_data);
builder.CreateBr(accessBB); builder.CreateBr(accessBB);
// BB "access"
builder.SetInsertPoint(accessBB); builder.SetInsertPoint(accessBB);
auto data = builder.CreateLoad(m_data, "data"); auto data = builder.CreateLoad(m_data, "data");
auto ptr = builder.CreateGEP(data, index, "ptr"); auto ptr = builder.CreateGEP(data, index, "ptr");

5
evmcc/Memory.h

@ -6,11 +6,12 @@
namespace evmcc namespace evmcc
{ {
class GasMeter;
class Memory class Memory
{ {
public: public:
Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter);
Memory(const Memory&) = delete; Memory(const Memory&) = delete;
void operator=(Memory) = delete; void operator=(Memory) = delete;
@ -22,7 +23,7 @@ public:
void dump(uint64_t _begin, uint64_t _end = 0); void dump(uint64_t _begin, uint64_t _end = 0);
private: private:
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, llvm::Module* _module); llvm::Function* createFunc(bool _isStore, llvm::Type* _type, llvm::Module* _module, GasMeter& _gasMeter);
private: private:
llvm::IRBuilder<>& m_builder; llvm::IRBuilder<>& m_builder;

12
evmcc/Runtime.cpp

@ -6,11 +6,14 @@ namespace evmcc
static Runtime* g_runtime; static Runtime* g_runtime;
Runtime::Runtime(std::unique_ptr<dev::eth::ExtVMFace> _ext) extern "C" { EXPORT i256 gas; }
: m_ext(std::move(_ext))
Runtime::Runtime(dev::u256 _gas, std::unique_ptr<dev::eth::ExtVMFace> _ext):
m_ext(std::move(_ext))
{ {
assert(!g_runtime); assert(!g_runtime);
g_runtime = this; g_runtime = this;
gas = eth2llvm(_gas);
} }
Runtime::~Runtime() Runtime::~Runtime()
@ -33,4 +36,9 @@ dev::eth::ExtVMFace& Runtime::getExt()
return *g_runtime->m_ext; return *g_runtime->m_ext;
} }
dev::u256 Runtime::getGas()
{
return llvm2eth(gas);
}
} }

10
evmcc/Runtime.h

@ -7,6 +7,13 @@
#include "Utils.h" #include "Utils.h"
#ifdef _MSC_VER
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
namespace evmcc namespace evmcc
{ {
@ -16,7 +23,7 @@ using MemoryImpl = dev::bytes;
class Runtime class Runtime
{ {
public: public:
Runtime(std::unique_ptr<dev::eth::ExtVMFace> _ext); Runtime(dev::u256 _gas, std::unique_ptr<dev::eth::ExtVMFace> _ext);
~Runtime(); ~Runtime();
Runtime(const Runtime&) = delete; Runtime(const Runtime&) = delete;
@ -25,6 +32,7 @@ public:
static StackImpl& getStack(); static StackImpl& getStack();
static MemoryImpl& getMemory(); static MemoryImpl& getMemory();
static dev::eth::ExtVMFace& getExt(); static dev::eth::ExtVMFace& getExt();
static dev::u256 getGas();
private: private:
StackImpl m_stack; StackImpl m_stack;

Loading…
Cancel
Save