mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-20 11:46:44 +00:00
Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc
Conflicts: evmcc/Compiler.cpp
This commit is contained in:
commit
e4cf741cfb
9 changed files with 78 additions and 36 deletions
|
|
@ -199,9 +199,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
createBasicBlocks(bytecode);
|
||||
|
||||
// Init runtime structures.
|
||||
Memory memory(builder, module.get());
|
||||
Ext ext(builder, module.get());
|
||||
GasMeter gasMeter(builder, module.get());
|
||||
Memory memory(builder, module.get(), gasMeter);
|
||||
Ext ext(builder, module.get());
|
||||
|
||||
// Jump to first instruction
|
||||
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]);
|
||||
|
||||
gasMeter.check(inst);
|
||||
gasMeter.count(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 (basicBlock.end() == bytecode.size())
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
|
|||
ext->data = calldata;
|
||||
|
||||
// Init runtime
|
||||
Runtime runtime(std::move(ext));
|
||||
uint64_t gas = 1000000;
|
||||
Runtime runtime(gas, std::move(ext));
|
||||
|
||||
auto entryFunc = module->getFunction("main");
|
||||
if (!entryFunc)
|
||||
|
|
@ -95,6 +96,7 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
|
|||
}
|
||||
|
||||
auto result = exec->runFunction(entryFunc, {});
|
||||
gas = static_cast<decltype(gas)>(Runtime::getGas());
|
||||
if (auto intResult = result.IntVal.getZExtValue())
|
||||
{
|
||||
auto index = intResult >> 32;
|
||||
|
|
|
|||
|
|
@ -9,12 +9,6 @@
|
|||
|
||||
#include "Runtime.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
using llvm::types::i;
|
||||
using Linkage = llvm::GlobalValue::LinkageTypes;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ bool isCostBlockEnd(Instruction _inst)
|
|||
GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module):
|
||||
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
|
||||
|
||||
auto pt = m_builder.GetInsertPoint();
|
||||
|
|
@ -97,21 +97,37 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module):
|
|||
m_builder.SetInsertPoint(bb, pt);
|
||||
}
|
||||
|
||||
void GasMeter::check(Instruction _inst)
|
||||
void GasMeter::count(Instruction _inst)
|
||||
{
|
||||
if (!m_checkCall)
|
||||
{
|
||||
// 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);
|
||||
|
||||
if (isCostBlockEnd(_inst))
|
||||
{
|
||||
m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call
|
||||
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 = 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,16 +16,23 @@ public:
|
|||
GasMeter(const 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:
|
||||
/// Cumulative gas cost of a block of instructions
|
||||
/// @TODO Handle overflow
|
||||
uint64_t m_blockCost = 0;
|
||||
llvm::IRBuilder<>& m_builder;
|
||||
llvm::CallInst* m_checkCall;
|
||||
llvm::CallInst* m_checkCall = nullptr;
|
||||
llvm::GlobalVariable* m_gas;
|
||||
llvm::Function* m_gasCheckFunc;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,18 +13,13 @@
|
|||
|
||||
#include "Type.h"
|
||||
#include "Runtime.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
#include "GasMeter.h"
|
||||
|
||||
namespace evmcc
|
||||
{
|
||||
|
||||
Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module)
|
||||
: m_builder(_builder)
|
||||
Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter):
|
||||
m_builder(_builder)
|
||||
{
|
||||
auto voidTy = m_builder.getVoidTy();
|
||||
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_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_storeWord = createFunc(true, Type::i256, _module);
|
||||
m_storeByte = createFunc(true, Type::Byte, _module);
|
||||
m_loadWord = createFunc(false, Type::i256, _module, _gasMeter);
|
||||
m_storeWord = createFunc(true, Type::i256, _module, _gasMeter);
|
||||
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;
|
||||
|
||||
|
|
@ -69,6 +64,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::
|
|||
auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func);
|
||||
auto accessBB = llvm::BasicBlock::Create(func->getContext(), "access", func);
|
||||
|
||||
// BB "check"
|
||||
llvm::IRBuilder<> builder(checkBB);
|
||||
llvm::Value* index = func->arg_begin();
|
||||
index->setName("index");
|
||||
|
|
@ -78,12 +74,20 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::
|
|||
auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded");
|
||||
builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights?
|
||||
|
||||
// BB "resize"
|
||||
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);
|
||||
auto newData = builder.CreateCall(m_resize, m_size, "newData");
|
||||
builder.CreateStore(newData, m_data);
|
||||
builder.CreateBr(accessBB);
|
||||
|
||||
// BB "access"
|
||||
builder.SetInsertPoint(accessBB);
|
||||
auto data = builder.CreateLoad(m_data, "data");
|
||||
auto ptr = builder.CreateGEP(data, index, "ptr");
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
|
||||
namespace evmcc
|
||||
{
|
||||
class GasMeter;
|
||||
|
||||
class Memory
|
||||
{
|
||||
public:
|
||||
Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module);
|
||||
Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter);
|
||||
Memory(const Memory&) = delete;
|
||||
void operator=(Memory) = delete;
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ public:
|
|||
void dump(uint64_t _begin, uint64_t _end = 0);
|
||||
|
||||
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:
|
||||
llvm::IRBuilder<>& m_builder;
|
||||
|
|
|
|||
|
|
@ -6,11 +6,14 @@ namespace evmcc
|
|||
|
||||
static Runtime* g_runtime;
|
||||
|
||||
Runtime::Runtime(std::unique_ptr<dev::eth::ExtVMFace> _ext)
|
||||
: m_ext(std::move(_ext))
|
||||
extern "C" { EXPORT i256 gas; }
|
||||
|
||||
Runtime::Runtime(dev::u256 _gas, std::unique_ptr<dev::eth::ExtVMFace> _ext):
|
||||
m_ext(std::move(_ext))
|
||||
{
|
||||
assert(!g_runtime);
|
||||
g_runtime = this;
|
||||
gas = eth2llvm(_gas);
|
||||
}
|
||||
|
||||
Runtime::~Runtime()
|
||||
|
|
@ -33,4 +36,9 @@ dev::eth::ExtVMFace& Runtime::getExt()
|
|||
return *g_runtime->m_ext;
|
||||
}
|
||||
|
||||
dev::u256 Runtime::getGas()
|
||||
{
|
||||
return llvm2eth(gas);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,6 +7,13 @@
|
|||
|
||||
#include "Utils.h"
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
namespace evmcc
|
||||
{
|
||||
|
||||
|
|
@ -16,7 +23,7 @@ using MemoryImpl = dev::bytes;
|
|||
class Runtime
|
||||
{
|
||||
public:
|
||||
Runtime(std::unique_ptr<dev::eth::ExtVMFace> _ext);
|
||||
Runtime(dev::u256 _gas, std::unique_ptr<dev::eth::ExtVMFace> _ext);
|
||||
~Runtime();
|
||||
|
||||
Runtime(const Runtime&) = delete;
|
||||
|
|
@ -25,6 +32,7 @@ public:
|
|||
static StackImpl& getStack();
|
||||
static MemoryImpl& getMemory();
|
||||
static dev::eth::ExtVMFace& getExt();
|
||||
static dev::u256 getGas();
|
||||
|
||||
private:
|
||||
StackImpl m_stack;
|
||||
|
|
|
|||
Loading…
Reference in a new issue