mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc
This commit is contained in:
commit
b01a75af0b
61 changed files with 158 additions and 97 deletions
|
|
@ -1 +0,0 @@
|
|||
600160805460006080530b6016596003608054601b586002608054
|
||||
|
|
@ -12,9 +12,8 @@
|
|||
#include <libdevcore/Common.h>
|
||||
#include <libdevcore/CommonIO.h>
|
||||
#include <libevmface/Instruction.h>
|
||||
|
||||
#include "Compiler.h"
|
||||
#include "ExecutionEngine.h"
|
||||
#include <libevmjit/Compiler.h>
|
||||
#include <libevmjit/ExecutionEngine.h>
|
||||
|
||||
|
||||
void show_usage()
|
||||
|
|
@ -95,7 +94,7 @@ int main(int argc, char** argv)
|
|||
if (opt_compile)
|
||||
{
|
||||
auto compiler = eth::jit::Compiler();
|
||||
auto module = compiler.compile(bytecode);
|
||||
auto module = compiler.compile({bytecode.data(), bytecode.size()});
|
||||
llvm::raw_os_ostream out(std::cout);
|
||||
module->print(out, nullptr);
|
||||
|
||||
|
|
@ -111,9 +110,10 @@ int main(int argc, char** argv)
|
|||
if (opt_interpret)
|
||||
{
|
||||
auto engine = eth::jit::ExecutionEngine();
|
||||
auto module = eth::jit::Compiler().compile(bytecode);
|
||||
auto module = eth::jit::Compiler().compile({bytecode.data(), bytecode.size()});
|
||||
module->dump();
|
||||
auto result = engine.run(std::move(module));
|
||||
u256 gas = 10000;
|
||||
auto result = engine.run(std::move(module), gas);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
.code:
|
||||
PUSH 1
|
||||
PUSH 128
|
||||
MSTORE
|
||||
PUSH 0
|
||||
PUSH 128
|
||||
MLOAD
|
||||
GT
|
||||
PUSH [tag0]
|
||||
JUMPI
|
||||
PUSH 3
|
||||
PUSH 128
|
||||
MSTORE
|
||||
PUSH [tag1]
|
||||
JUMP
|
||||
tag0:
|
||||
PUSH 2
|
||||
PUSH 128
|
||||
MSTORE
|
||||
tag1:
|
||||
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
[i] 1
|
||||
|
||||
( if (> @i 0) [i] 2 [i] 3 )
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ Compiler::Compiler():
|
|||
Type::init(m_builder.getContext());
|
||||
}
|
||||
|
||||
void Compiler::createBasicBlocks(const bytes& bytecode)
|
||||
void Compiler::createBasicBlocks(bytesConstRef bytecode)
|
||||
{
|
||||
std::set<ProgramCounter> splitPoints; // Sorted collections of instruction indices where basic blocks start/end
|
||||
splitPoints.insert(0); // First basic block
|
||||
|
|
@ -38,9 +38,9 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
|
|||
std::vector<ProgramCounter> indirectJumpTargets;
|
||||
boost::dynamic_bitset<> validJumpTargets(bytecode.size());
|
||||
|
||||
for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr)
|
||||
for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr)
|
||||
{
|
||||
ProgramCounter currentPC = curr - bytecode.cbegin();
|
||||
ProgramCounter currentPC = curr - bytecode.begin();
|
||||
validJumpTargets[currentPC] = 1;
|
||||
|
||||
auto inst = static_cast<Instruction>(*curr);
|
||||
|
|
@ -51,7 +51,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
|
|||
{
|
||||
auto numBytes = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::PUSH1) + 1;
|
||||
auto next = curr + numBytes + 1;
|
||||
if (next >= bytecode.cend())
|
||||
if (next >= bytecode.end())
|
||||
break;
|
||||
|
||||
auto nextInst = static_cast<Instruction>(*next);
|
||||
|
|
@ -67,12 +67,10 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
|
|||
}
|
||||
|
||||
// Create a block for the JUMP target.
|
||||
ProgramCounter targetPC = val.convert_to<ProgramCounter>();
|
||||
if (targetPC > bytecode.size())
|
||||
targetPC = bytecode.size();
|
||||
ProgramCounter targetPC = val < bytecode.size() ? val.convert_to<ProgramCounter>() : bytecode.size();
|
||||
splitPoints.insert(targetPC);
|
||||
|
||||
ProgramCounter jumpPC = (next - bytecode.cbegin());
|
||||
ProgramCounter jumpPC = (next - bytecode.begin());
|
||||
directJumpTargets[jumpPC] = targetPC;
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +93,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
|
|||
case Instruction::SUICIDE:
|
||||
{
|
||||
// Create a basic block starting at the following instruction.
|
||||
if (curr + 1 < bytecode.cend())
|
||||
if (curr + 1 < bytecode.end())
|
||||
{
|
||||
splitPoints.insert(currentPC + 1);
|
||||
}
|
||||
|
|
@ -130,16 +128,23 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
|
|||
|
||||
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it)
|
||||
{
|
||||
if (it->second >= bytecode.size())
|
||||
{
|
||||
// Jumping out of code means STOP
|
||||
m_directJumpTargets[it->first] = m_stopBB;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto blockIter = basicBlocks.find(it->second);
|
||||
if (blockIter != basicBlocks.end())
|
||||
{
|
||||
m_directJumpTargets[it->first] = &(blockIter->second);
|
||||
m_directJumpTargets[it->first] = blockIter->second.llvm();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Bad JUMP at PC " << it->first
|
||||
<< ": " << it->second << " is not a valid PC\n";
|
||||
m_directJumpTargets[it->first] = m_badJumpBlock.get();
|
||||
m_directJumpTargets[it->first] = m_badJumpBlock->llvm();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +154,7 @@ void Compiler::createBasicBlocks(const bytes& bytecode)
|
|||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<llvm::Module> Compiler::compile(const bytes& bytecode)
|
||||
std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
|
||||
{
|
||||
auto module = std::make_unique<llvm::Module>("main", m_builder.getContext());
|
||||
|
||||
|
|
@ -214,7 +219,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const bytes& bytecode)
|
|||
}
|
||||
|
||||
|
||||
void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock)
|
||||
void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock)
|
||||
{
|
||||
auto& stack = basicBlock.getStack();
|
||||
m_builder.SetInsertPoint(basicBlock.llvm());
|
||||
|
|
@ -567,7 +572,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode,
|
|||
// 1. this is not the first instruction in the block
|
||||
// 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH)
|
||||
// Otherwise generate a indirect jump (a switch).
|
||||
BasicBlock* targetBlock = nullptr;
|
||||
llvm::BasicBlock* targetBlock = nullptr;
|
||||
if (currentPC != basicBlock.begin())
|
||||
{
|
||||
auto pairIter = m_directJumpTargets.find(currentPC);
|
||||
|
|
@ -584,7 +589,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode,
|
|||
// The target address is computed at compile time,
|
||||
// just pop it without looking...
|
||||
stack.pop();
|
||||
m_builder.CreateBr(targetBlock->llvm());
|
||||
m_builder.CreateBr(targetBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -606,7 +611,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode,
|
|||
if (targetBlock)
|
||||
{
|
||||
stack.pop();
|
||||
m_builder.CreateCondBr(cond, targetBlock->llvm(), nextBasicBlock);
|
||||
m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -923,10 +928,18 @@ void Compiler::linkBasicBlocks()
|
|||
for (auto it = llvm::po_ext_begin(bb.second.llvm(), visitSet),
|
||||
end = llvm::po_ext_end(bb.second.llvm(), visitSet); it != end; ++it)
|
||||
{
|
||||
std::cerr << it->getName().str() << std::endl;
|
||||
// TODO: Use logger
|
||||
//std::cerr << it->getName().str() << std::endl;
|
||||
completePhiNodes(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove jump table block if not predecessors
|
||||
if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm()))
|
||||
{
|
||||
m_jumpTableBlock->llvm()->eraseFromParent();
|
||||
m_jumpTableBlock.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Compiler::dumpBasicBlockGraph(std::ostream& out)
|
||||
|
|
@ -22,16 +22,16 @@ public:
|
|||
|
||||
Compiler();
|
||||
|
||||
std::unique_ptr<llvm::Module> compile(const bytes& bytecode);
|
||||
std::unique_ptr<llvm::Module> compile(bytesConstRef bytecode);
|
||||
|
||||
void dumpBasicBlockGraph(std::ostream& out);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void createBasicBlocks(const bytes& bytecode);
|
||||
void createBasicBlocks(bytesConstRef bytecode);
|
||||
|
||||
void compileBasicBlock(BasicBlock& basicBlock, const bytes& bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
|
||||
void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
|
||||
|
||||
void linkBasicBlocks();
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ private:
|
|||
/**
|
||||
* Maps a pc at which there is a JUMP or JUMPI to the target block of the jump.
|
||||
*/
|
||||
std::map<ProgramCounter, BasicBlock*> m_directJumpTargets;
|
||||
std::map<ProgramCounter, llvm::BasicBlock*> m_directJumpTargets;
|
||||
|
||||
/**
|
||||
* A list of possible blocks to which there may be indirect jumps.
|
||||
|
|
@ -36,7 +36,7 @@ ExecutionEngine::ExecutionEngine()
|
|||
extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; }
|
||||
|
||||
|
||||
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
|
||||
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtVMFace* _ext)
|
||||
{
|
||||
auto module = _module.get(); // Keep ownership of the module in _module
|
||||
|
||||
|
|
@ -81,26 +81,28 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
|
|||
exec->finalizeObject();
|
||||
|
||||
// Create fake ExtVM interface
|
||||
auto ext = std::make_unique<ExtVMFace>();
|
||||
ext->myAddress = Address(1122334455667788);
|
||||
ext->caller = Address(0xfacefacefaceface);
|
||||
ext->origin = Address(101010101010101010);
|
||||
ext->value = 0xabcd;
|
||||
ext->gasPrice = 1002;
|
||||
ext->previousBlock.hash = u256(1003);
|
||||
ext->currentBlock.coinbaseAddress = Address(1004);
|
||||
ext->currentBlock.timestamp = 1005;
|
||||
ext->currentBlock.number = 1006;
|
||||
ext->currentBlock.difficulty = 1007;
|
||||
ext->currentBlock.gasLimit = 1008;
|
||||
if (!_ext)
|
||||
{
|
||||
_ext = new ExtVMFace;
|
||||
_ext->myAddress = Address(1122334455667788);
|
||||
_ext->caller = Address(0xfacefacefaceface);
|
||||
_ext->origin = Address(101010101010101010);
|
||||
_ext->value = 0xabcd;
|
||||
_ext->gasPrice = 1002;
|
||||
_ext->previousBlock.hash = u256(1003);
|
||||
_ext->currentBlock.coinbaseAddress = Address(1004);
|
||||
_ext->currentBlock.timestamp = 1005;
|
||||
_ext->currentBlock.number = 1006;
|
||||
_ext->currentBlock.difficulty = 1007;
|
||||
_ext->currentBlock.gasLimit = 1008;
|
||||
std::string calldata = "Hello the Beautiful World of Ethereum!";
|
||||
ext->data = calldata;
|
||||
_ext->data = calldata;
|
||||
unsigned char fakecode[] = {0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf};
|
||||
ext->code = decltype(ext->code)(fakecode, 8);
|
||||
_ext->code = decltype(_ext->code)(fakecode, 8);
|
||||
}
|
||||
|
||||
// Init runtime
|
||||
uint64_t gas = 100;
|
||||
Runtime runtime(gas, std::move(ext));
|
||||
Runtime runtime(_gas, *_ext);
|
||||
|
||||
auto entryFunc = module->getFunction("main");
|
||||
if (!entryFunc)
|
||||
|
|
@ -121,11 +123,11 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
|
|||
else
|
||||
returnCode = static_cast<ReturnCode>(r);
|
||||
|
||||
gas = static_cast<decltype(gas)>(Runtime::getGas());
|
||||
_gas = Runtime::getGas();
|
||||
|
||||
if (returnCode == ReturnCode::Return)
|
||||
{
|
||||
auto&& returnData = Memory::getReturnData(); // TODO: It might be better to place is in Runtime interface
|
||||
returnData = Memory::getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface
|
||||
|
||||
std::cout << "RETURN [ ";
|
||||
for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it)
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include <libdevcore/Common.h>
|
||||
#include <libevm/ExtVMFace.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
|
|
@ -17,7 +18,9 @@ class ExecutionEngine
|
|||
public:
|
||||
ExecutionEngine();
|
||||
|
||||
int run(std::unique_ptr<llvm::Module> module);
|
||||
int run(std::unique_ptr<llvm::Module> module, u256& _gas, ExtVMFace* _ext = nullptr);
|
||||
|
||||
bytes returnData;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder):
|
|||
m_arg5 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg5");
|
||||
m_arg6 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg6");
|
||||
m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg7");
|
||||
m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8");
|
||||
m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8");
|
||||
|
||||
Type* elements[] = {
|
||||
i256Ty, // i256 address;
|
||||
|
|
@ -30,26 +30,26 @@ uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure
|
|||
return 0;
|
||||
|
||||
case Instruction::SSTORE:
|
||||
return static_cast<uint64_t>(c_sstoreGas);
|
||||
return static_cast<uint64_t>(FeeStructure::c_sstoreGas);
|
||||
|
||||
case Instruction::SLOAD:
|
||||
return static_cast<uint64_t>(c_sloadGas);
|
||||
return static_cast<uint64_t>(FeeStructure::c_sloadGas);
|
||||
|
||||
case Instruction::SHA3:
|
||||
return static_cast<uint64_t>(c_sha3Gas);
|
||||
return static_cast<uint64_t>(FeeStructure::c_sha3Gas);
|
||||
|
||||
case Instruction::BALANCE:
|
||||
return static_cast<uint64_t>(c_sha3Gas);
|
||||
return static_cast<uint64_t>(FeeStructure::c_sha3Gas);
|
||||
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
return static_cast<uint64_t>(c_callGas);
|
||||
return static_cast<uint64_t>(FeeStructure::c_callGas);
|
||||
|
||||
case Instruction::CREATE:
|
||||
return static_cast<uint64_t>(c_createGas);
|
||||
return static_cast<uint64_t>(FeeStructure::c_createGas);
|
||||
|
||||
default: // Assumes instruction code is valid
|
||||
return static_cast<uint64_t>(c_stepGas);
|
||||
return static_cast<uint64_t>(FeeStructure::c_stepGas);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu
|
|||
{
|
||||
assert(!m_checkCall); // Everything should've been commited before
|
||||
|
||||
static const auto sstoreCost = static_cast<uint64_t>(c_sstoreGas);
|
||||
static const auto sstoreCost = static_cast<uint64_t>(FeeStructure::c_sstoreGas);
|
||||
|
||||
// [ADD] if oldValue == 0 and newValue != 0 => 2*cost
|
||||
// [DEL] if oldValue != 0 and newValue == 0 => 0
|
||||
|
|
@ -165,19 +165,21 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
|
|||
// If any uncommited block
|
||||
if (m_checkCall)
|
||||
{
|
||||
if (m_blockCost == 0 && !_additionalCost) // Do not check 0
|
||||
if (m_blockCost == 0) // Do not check 0
|
||||
{
|
||||
m_checkCall->eraseFromParent(); // Remove the gas check call
|
||||
m_checkCall = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::Value* cost = Constant::get(m_blockCost);
|
||||
if (_additionalCost)
|
||||
cost = m_builder.CreateAdd(cost, _additionalCost);
|
||||
|
||||
m_checkCall->setArgOperand(0, cost); // Update block cost in gas check call
|
||||
m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call
|
||||
m_checkCall = nullptr; // End cost-block
|
||||
m_blockCost = 0;
|
||||
|
||||
if (_additionalCost)
|
||||
{
|
||||
m_builder.CreateCall(m_gasCheckFunc, _additionalCost);
|
||||
}
|
||||
}
|
||||
assert(m_blockCost == 0);
|
||||
}
|
||||
|
|
@ -185,7 +187,7 @@ void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
|
|||
void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder)
|
||||
{
|
||||
// Memory uses other builder, but that can be changes later
|
||||
auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast<uint64_t>(c_memoryGas)), "memcost");
|
||||
auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast<uint64_t>(FeeStructure::c_memoryGas)), "memcost");
|
||||
_builder.CreateCall(m_gasCheckFunc, cost);
|
||||
}
|
||||
|
||||
|
|
@ -19,8 +19,8 @@ extern "C"
|
|||
EXPORT i256 gas;
|
||||
}
|
||||
|
||||
Runtime::Runtime(u256 _gas, std::unique_ptr<ExtVMFace> _ext):
|
||||
m_ext(std::move(_ext))
|
||||
Runtime::Runtime(u256 _gas, ExtVMFace& _ext):
|
||||
m_ext(_ext)
|
||||
{
|
||||
assert(!g_runtime);
|
||||
g_runtime = this;
|
||||
|
|
@ -44,7 +44,7 @@ MemoryImpl& Runtime::getMemory()
|
|||
|
||||
ExtVMFace& Runtime::getExt()
|
||||
{
|
||||
return *g_runtime->m_ext;
|
||||
return g_runtime->m_ext;
|
||||
}
|
||||
|
||||
u256 Runtime::getGas()
|
||||
|
|
@ -27,7 +27,7 @@ using MemoryImpl = bytes;
|
|||
class Runtime
|
||||
{
|
||||
public:
|
||||
Runtime(u256 _gas, std::unique_ptr<ExtVMFace> _ext);
|
||||
Runtime(u256 _gas, ExtVMFace& _ext);
|
||||
~Runtime();
|
||||
|
||||
Runtime(const Runtime&) = delete;
|
||||
|
|
@ -41,7 +41,7 @@ public:
|
|||
private:
|
||||
StackImpl m_stack;
|
||||
MemoryImpl m_memory;
|
||||
std::unique_ptr<ExtVMFace> m_ext;
|
||||
ExtVMFace& m_ext;
|
||||
};
|
||||
|
||||
}
|
||||
36
libevmjit/VM.cpp
Normal file
36
libevmjit/VM.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
#include "VM.h"
|
||||
|
||||
#include <libevm/VM.h>
|
||||
|
||||
#include "ExecutionEngine.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace eth
|
||||
{
|
||||
namespace jit
|
||||
{
|
||||
|
||||
bytes VM::go(ExtVMFace& _ext)
|
||||
{
|
||||
auto module = Compiler().compile(_ext.code);
|
||||
|
||||
ExecutionEngine engine;
|
||||
auto exitCode = engine.run(std::move(module), m_gas, &_ext);
|
||||
|
||||
switch (exitCode)
|
||||
{
|
||||
case 101:
|
||||
BOOST_THROW_EXCEPTION(BadJumpDestination());
|
||||
case 102:
|
||||
BOOST_THROW_EXCEPTION(OutOfGas());
|
||||
}
|
||||
|
||||
return std::move(engine.returnData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
32
libevmjit/VM.h
Normal file
32
libevmjit/VM.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <libdevcore/Common.h>
|
||||
#include <libevm/ExtVMFace.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace eth
|
||||
{
|
||||
namespace jit
|
||||
{
|
||||
|
||||
class VM
|
||||
{
|
||||
public:
|
||||
/// Construct VM object.
|
||||
explicit VM(u256 _gas = 0): m_gas(_gas) {}
|
||||
|
||||
void reset(u256 _gas = 0) { m_gas = _gas; }
|
||||
|
||||
bytes go(ExtVMFace& _ext);
|
||||
|
||||
u256 gas() const { return m_gas; }
|
||||
|
||||
private:
|
||||
u256 m_gas = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue