mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 12:16:44 +00:00
Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc
This commit is contained in:
commit
727691f83a
7 changed files with 89 additions and 15 deletions
|
|
@ -609,6 +609,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
{
|
{
|
||||||
auto index = stack.pop();
|
auto index = stack.pop();
|
||||||
auto value = stack.pop();
|
auto value = stack.pop();
|
||||||
|
gasMeter.countSStore(ext, index, value);
|
||||||
ext.setStore(index, value);
|
ext.setStore(index, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -689,8 +690,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
|
|
||||||
case Instruction::GAS:
|
case Instruction::GAS:
|
||||||
{
|
{
|
||||||
auto value = builder.CreateLoad(gasMeter.getLLVMGasVar());
|
stack.push(gasMeter.getGas());
|
||||||
stack.push(value);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
#include <llvm/Support/PrettyStackTrace.h>
|
#include <llvm/Support/PrettyStackTrace.h>
|
||||||
#include <llvm/Support/Host.h>
|
#include <llvm/Support/Host.h>
|
||||||
|
|
||||||
|
#include <libevm/VM.h>
|
||||||
|
|
||||||
#include "Runtime.h"
|
#include "Runtime.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Type.h"
|
#include "Type.h"
|
||||||
|
|
@ -89,7 +91,7 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
|
||||||
ext->code = decltype(ext->code)(fakecode, 8);
|
ext->code = decltype(ext->code)(fakecode, 8);
|
||||||
|
|
||||||
// Init runtime
|
// Init runtime
|
||||||
uint64_t gas = 1000000;
|
uint64_t gas = 100;
|
||||||
Runtime runtime(gas, std::move(ext));
|
Runtime runtime(gas, std::move(ext));
|
||||||
|
|
||||||
auto entryFunc = module->getFunction("main");
|
auto entryFunc = module->getFunction("main");
|
||||||
|
|
@ -99,9 +101,20 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ReturnCode returnCode;
|
||||||
|
try
|
||||||
|
{
|
||||||
auto result = exec->runFunction(entryFunc, {});
|
auto result = exec->runFunction(entryFunc, {});
|
||||||
|
returnCode = static_cast<ReturnCode>(result.IntVal.getZExtValue());
|
||||||
|
}
|
||||||
|
catch (const dev::eth::OutOfGas&)
|
||||||
|
{
|
||||||
|
returnCode = ReturnCode::OutOfGas;
|
||||||
|
}
|
||||||
|
|
||||||
gas = static_cast<decltype(gas)>(Runtime::getGas());
|
gas = static_cast<decltype(gas)>(Runtime::getGas());
|
||||||
auto returnCode = static_cast<ReturnCode>(result.IntVal.getZExtValue());
|
|
||||||
if (returnCode == ReturnCode::Return)
|
if (returnCode == ReturnCode::Return)
|
||||||
{
|
{
|
||||||
auto&& returnData = Memory::getReturnData(); // TODO: It might be better to place is in Runtime interface
|
auto&& returnData = Memory::getReturnData(); // TODO: It might be better to place is in Runtime interface
|
||||||
|
|
@ -110,10 +123,8 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
|
||||||
for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it)
|
for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it)
|
||||||
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " ";
|
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " ";
|
||||||
std::cout << "]\n";
|
std::cout << "]\n";
|
||||||
|
|
||||||
return 10;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return static_cast<int>(returnCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "Type.h"
|
#include "Type.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
#include "Ext.h"
|
||||||
|
|
||||||
namespace evmcc
|
namespace evmcc
|
||||||
{
|
{
|
||||||
|
|
@ -82,11 +83,27 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module):
|
||||||
m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "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
|
||||||
|
|
||||||
|
m_rtExit = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::MainReturn, false), llvm::Function::ExternalLinkage, "rt_exit", _module);
|
||||||
|
|
||||||
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", _module);
|
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", _module);
|
||||||
InsertPointGuard guard(m_builder);
|
InsertPointGuard guard(m_builder);
|
||||||
m_builder.SetInsertPoint(llvm::BasicBlock::Create(_builder.getContext(), {}, m_gasCheckFunc));
|
|
||||||
|
auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "check", m_gasCheckFunc);
|
||||||
|
auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "outOfGas", m_gasCheckFunc);
|
||||||
|
auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "update", m_gasCheckFunc);
|
||||||
|
|
||||||
|
m_builder.SetInsertPoint(checkBB);
|
||||||
llvm::Value* cost = m_gasCheckFunc->arg_begin();
|
llvm::Value* cost = m_gasCheckFunc->arg_begin();
|
||||||
llvm::Value* gas = m_builder.CreateLoad(m_gas);
|
cost->setName("cost");
|
||||||
|
llvm::Value* gas = m_builder.CreateLoad(m_gas, "gas");
|
||||||
|
auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas");
|
||||||
|
m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);
|
||||||
|
|
||||||
|
m_builder.SetInsertPoint(outOfGasBB);
|
||||||
|
m_builder.CreateCall(m_rtExit, Constant::get(ReturnCode::OutOfGas));
|
||||||
|
m_builder.CreateRetVoid();
|
||||||
|
|
||||||
|
m_builder.SetInsertPoint(updateBB);
|
||||||
gas = m_builder.CreateSub(gas, cost);
|
gas = m_builder.CreateSub(gas, cost);
|
||||||
m_builder.CreateStore(gas, m_gas);
|
m_builder.CreateStore(gas, m_gas);
|
||||||
m_builder.CreateRetVoid();
|
m_builder.CreateRetVoid();
|
||||||
|
|
@ -100,12 +117,34 @@ void GasMeter::count(Instruction _inst)
|
||||||
m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256));
|
m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::i256));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_inst != Instruction::SSTORE) // Handle cost of SSTORE separately in countSStore()
|
||||||
m_blockCost += getStepCost(_inst);
|
m_blockCost += getStepCost(_inst);
|
||||||
|
|
||||||
if (isCostBlockEnd(_inst))
|
if (isCostBlockEnd(_inst))
|
||||||
commitCostBlock();
|
commitCostBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue)
|
||||||
|
{
|
||||||
|
assert(!m_checkCall); // Everything should've been commited before
|
||||||
|
|
||||||
|
static const auto sstoreCost = static_cast<uint64_t>(c_sstoreGas);
|
||||||
|
|
||||||
|
// [ADD] if oldValue == 0 and newValue != 0 => 2*cost
|
||||||
|
// [DEL] if oldValue != 0 and newValue == 0 => 0
|
||||||
|
|
||||||
|
auto oldValue = _ext.store(_index);
|
||||||
|
auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero");
|
||||||
|
auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero");
|
||||||
|
auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero");
|
||||||
|
auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
|
||||||
|
auto isAdd = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isAdd");
|
||||||
|
auto isDel = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDel");
|
||||||
|
auto cost = m_builder.CreateSelect(isAdd, Constant::get(2 * sstoreCost), Constant::get(sstoreCost), "cost");
|
||||||
|
cost = m_builder.CreateSelect(isDel, Constant::get(0), cost, "cost");
|
||||||
|
m_builder.CreateCall(m_gasCheckFunc, cost);
|
||||||
|
}
|
||||||
|
|
||||||
void GasMeter::giveBack(llvm::Value* _gas)
|
void GasMeter::giveBack(llvm::Value* _gas)
|
||||||
{
|
{
|
||||||
llvm::Value* gasCounter = m_builder.CreateLoad(m_gas, "gas");
|
llvm::Value* gasCounter = m_builder.CreateLoad(m_gas, "gas");
|
||||||
|
|
@ -144,9 +183,9 @@ void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilde
|
||||||
_builder.CreateCall(m_gasCheckFunc, cost);
|
_builder.CreateCall(m_gasCheckFunc, cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::GlobalVariable* GasMeter::getLLVMGasVar()
|
llvm::Value* GasMeter::getGas()
|
||||||
{
|
{
|
||||||
return m_gas;
|
return m_builder.CreateLoad(m_gas, "gas");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ public:
|
||||||
/// Count step cost of instruction
|
/// Count step cost of instruction
|
||||||
void count(dev::eth::Instruction _inst);
|
void count(dev::eth::Instruction _inst);
|
||||||
|
|
||||||
|
/// Calculate & count gas cost for SSTORE instruction
|
||||||
|
void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue);
|
||||||
|
|
||||||
/// Finalize cost-block by checking gas needed for the block before the block
|
/// Finalize cost-block by checking gas needed for the block before the block
|
||||||
/// @param _additionalCost adds additional cost to cost-block before commit
|
/// @param _additionalCost adds additional cost to cost-block before commit
|
||||||
void commitCostBlock(llvm::Value* _additionalCost = nullptr);
|
void commitCostBlock(llvm::Value* _additionalCost = nullptr);
|
||||||
|
|
@ -29,7 +32,7 @@ public:
|
||||||
/// 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, llvm::IRBuilder<>& _builder);
|
void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder);
|
||||||
|
|
||||||
llvm::GlobalVariable* getLLVMGasVar();
|
llvm::Value* getGas();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Cumulative gas cost of a block of instructions
|
/// Cumulative gas cost of a block of instructions
|
||||||
|
|
@ -38,6 +41,7 @@ private:
|
||||||
llvm::IRBuilder<>& m_builder;
|
llvm::IRBuilder<>& m_builder;
|
||||||
llvm::CallInst* m_checkCall = nullptr;
|
llvm::CallInst* m_checkCall = nullptr;
|
||||||
llvm::GlobalVariable* m_gas;
|
llvm::GlobalVariable* m_gas;
|
||||||
|
llvm::Function* m_rtExit;
|
||||||
llvm::Function* m_gasCheckFunc;
|
llvm::Function* m_gasCheckFunc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga
|
||||||
m_returnDataSize->setUnnamedAddr(true); // Address is not important
|
m_returnDataSize->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);
|
||||||
|
llvm::AttrBuilder attrBuilder;
|
||||||
|
attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
|
||||||
|
m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder));
|
||||||
|
|
||||||
m_require = createRequireFunc(_module, _gasMeter);
|
m_require = createRequireFunc(_module, _gasMeter);
|
||||||
m_loadWord = createFunc(false, Type::i256, _module, _gasMeter);
|
m_loadWord = createFunc(false, Type::i256, _module, _gasMeter);
|
||||||
m_storeWord = createFunc(true, Type::i256, _module, _gasMeter);
|
m_storeWord = createFunc(true, Type::i256, _module, _gasMeter);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,27 @@
|
||||||
|
|
||||||
#include "Runtime.h"
|
#include "Runtime.h"
|
||||||
|
|
||||||
|
#include <libevm/VM.h>
|
||||||
|
|
||||||
|
#include "Type.h"
|
||||||
|
|
||||||
namespace evmcc
|
namespace evmcc
|
||||||
{
|
{
|
||||||
|
|
||||||
static Runtime* g_runtime;
|
static Runtime* g_runtime;
|
||||||
|
|
||||||
extern "C" { EXPORT i256 gas; }
|
extern "C"
|
||||||
|
{
|
||||||
|
EXPORT i256 gas;
|
||||||
|
|
||||||
|
EXPORT void rt_exit(int32_t _returnCode)
|
||||||
|
{
|
||||||
|
auto returnCode = static_cast<ReturnCode>(_returnCode);
|
||||||
|
if (returnCode == ReturnCode::OutOfGas)
|
||||||
|
BOOST_THROW_EXCEPTION(dev::eth::OutOfGas());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Runtime::Runtime(dev::u256 _gas, std::unique_ptr<dev::eth::ExtVMFace> _ext):
|
Runtime::Runtime(dev::u256 _gas, std::unique_ptr<dev::eth::ExtVMFace> _ext):
|
||||||
m_ext(std::move(_ext))
|
m_ext(std::move(_ext))
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ enum class ReturnCode
|
||||||
Suicide = 2,
|
Suicide = 2,
|
||||||
|
|
||||||
BadJumpDestination = 101,
|
BadJumpDestination = 101,
|
||||||
|
OutOfGas = 102,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Constant
|
struct Constant
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue