mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 14:16:44 +00:00
Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc
Conflicts: test/vm.cpp
This commit is contained in:
commit
a3871e5137
15 changed files with 120 additions and 107 deletions
1
evmcc/test/except/badinst1.evm
Normal file
1
evmcc/test/except/badinst1.evm
Normal file
|
|
@ -0,0 +1 @@
|
|||
4a
|
||||
|
|
@ -176,6 +176,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
|
|||
llvm::Type* mainFuncArgTypes[] = {m_builder.getInt32Ty(), Type::RuntimePtr}; // There must be int in first place because LLVM does not support other signatures
|
||||
auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, mainFuncArgTypes, false);
|
||||
m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, "main", module.get());
|
||||
m_mainFunc->arg_begin()->getNextNode()->setName("rt");
|
||||
|
||||
// Create the basic blocks.
|
||||
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc);
|
||||
|
|
@ -186,7 +187,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
|
|||
// Init runtime structures.
|
||||
RuntimeManager runtimeManager(m_builder);
|
||||
GasMeter gasMeter(m_builder, runtimeManager);
|
||||
Memory memory(m_builder, gasMeter, runtimeManager);
|
||||
Memory memory(runtimeManager, gasMeter);
|
||||
Ext ext(runtimeManager);
|
||||
Stack stack(m_builder, runtimeManager);
|
||||
Arith256 arith(m_builder);
|
||||
|
|
@ -371,14 +372,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
|
|||
break;
|
||||
}
|
||||
|
||||
case Instruction::NEG:
|
||||
/*case Instruction::NEG:
|
||||
{
|
||||
auto top = stack.pop();
|
||||
auto zero = Constant::get(0);
|
||||
auto res = m_builder.CreateSub(zero, top);
|
||||
stack.push(res);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
case Instruction::LT:
|
||||
{
|
||||
|
|
@ -796,7 +797,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
|
|||
auto index = stack.pop();
|
||||
auto size = stack.pop();
|
||||
|
||||
memory.registerReturnData(index, size);
|
||||
memory.require(index, size);
|
||||
_runtimeManager.registerReturnData(index, size);
|
||||
|
||||
m_builder.CreateRet(Constant::get(ReturnCode::Return));
|
||||
break;
|
||||
|
|
@ -814,6 +816,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
|
|||
break;
|
||||
}
|
||||
|
||||
default: // Invalid instruction - runtime exception
|
||||
{
|
||||
_runtimeManager.raiseException(ReturnCode::BadInstruction);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@ llvm::Function* CompilerHelper::getMainFunction()
|
|||
{
|
||||
assert(m_builder.GetInsertBlock());
|
||||
auto mainFunc = m_builder.GetInsertBlock()->getParent();
|
||||
assert(mainFunc && mainFunc->getName() == "main");
|
||||
assert(mainFunc);
|
||||
if (mainFunc->getName() == "main")
|
||||
return mainFunc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,13 @@ protected:
|
|||
llvm::IRBuilder<>& m_builder;
|
||||
llvm::IRBuilder<>& getBuilder() { return m_builder; }
|
||||
|
||||
template<typename ..._Args>
|
||||
llvm::CallInst* createCall(llvm::Function* _func, _Args*... _args)
|
||||
{
|
||||
llvm::Value* args[] = {_args...};
|
||||
return getBuilder().CreateCall(_func, args);
|
||||
}
|
||||
|
||||
friend class RuntimeHelper;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@ ExecutionEngine::ExecutionEngine()
|
|||
|
||||
}
|
||||
|
||||
extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; }
|
||||
|
||||
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtVMFace* _ext)
|
||||
{
|
||||
auto module = _module.get(); // Keep ownership of the module in _module
|
||||
|
|
@ -102,21 +100,19 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtV
|
|||
_ext->code = decltype(_ext->code)(fakecode, 8);
|
||||
}
|
||||
|
||||
// Init runtime
|
||||
Runtime runtime(_gas, *_ext);
|
||||
|
||||
auto entryFunc = module->getFunction("main");
|
||||
if (!entryFunc)
|
||||
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found"));
|
||||
|
||||
ReturnCode returnCode;
|
||||
std::jmp_buf buf;
|
||||
Runtime runtime(_gas, *_ext, buf);
|
||||
auto r = setjmp(buf);
|
||||
if (r == 0)
|
||||
{
|
||||
|
||||
auto executionStartTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
rt_jmpBuf = &buf;
|
||||
auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(runtime.getDataPtr())});
|
||||
returnCode = static_cast<ReturnCode>(result.IntVal.getZExtValue());
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ Ext::Ext(RuntimeManager& _runtimeManager):
|
|||
m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), Linkage::ExternalLinkage, "ext_call", module);
|
||||
m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_sha3", module);
|
||||
m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module);
|
||||
m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), Linkage::ExternalLinkage, "ext_codeAt", module);
|
||||
m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_codeAt", module);
|
||||
m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module);
|
||||
}
|
||||
|
||||
|
|
@ -109,8 +109,7 @@ llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::V
|
|||
m_builder.CreateStore(_endowment, m_args[0]);
|
||||
m_builder.CreateStore(_initOff, m_arg2);
|
||||
m_builder.CreateStore(_initSize, m_arg3);
|
||||
llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_args[1]};
|
||||
m_builder.CreateCall(m_create, args);
|
||||
createCall(m_create, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_args[1]);
|
||||
llvm::Value* address = m_builder.CreateLoad(m_args[1]);
|
||||
address = Endianness::toNative(m_builder, address);
|
||||
return address;
|
||||
|
|
@ -128,9 +127,7 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V
|
|||
m_builder.CreateStore(_outSize, m_arg7);
|
||||
auto codeAddress = Endianness::toBE(m_builder, _codeAddress);
|
||||
m_builder.CreateStore(codeAddress, m_arg8);
|
||||
|
||||
llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]};
|
||||
m_builder.CreateCall(m_call, args);
|
||||
createCall(m_call, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]);
|
||||
_gas = m_builder.CreateLoad(m_args[0]); // Return gas
|
||||
return m_builder.CreateLoad(m_args[1]);
|
||||
}
|
||||
|
|
@ -139,8 +136,7 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize)
|
|||
{
|
||||
m_builder.CreateStore(_inOff, m_args[0]);
|
||||
m_builder.CreateStore(_inSize, m_arg2);
|
||||
llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]};
|
||||
m_builder.CreateCall(m_sha3, args);
|
||||
createCall(m_sha3, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]);
|
||||
llvm::Value* hash = m_builder.CreateLoad(m_args[1]);
|
||||
hash = Endianness::toNative(m_builder, hash);
|
||||
return hash;
|
||||
|
|
@ -148,10 +144,10 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize)
|
|||
|
||||
llvm::Value* Ext::exp(llvm::Value* _left, llvm::Value* _right)
|
||||
{
|
||||
// TODO: Move ext to Arith256
|
||||
m_builder.CreateStore(_left, m_args[0]);
|
||||
m_builder.CreateStore(_right, m_arg2);
|
||||
llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]};
|
||||
m_builder.CreateCall(m_exp, args);
|
||||
createCall(m_exp, getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]);
|
||||
return m_builder.CreateLoad(m_args[1]);
|
||||
}
|
||||
|
||||
|
|
@ -166,8 +162,7 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr)
|
|||
{
|
||||
auto addr = Endianness::toBE(m_builder, _addr);
|
||||
m_builder.CreateStore(addr, m_args[0]);
|
||||
llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]};
|
||||
m_builder.CreateCall(m_codesizeAt, args);
|
||||
createCall(m_codesizeAt, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]);
|
||||
return m_builder.CreateLoad(m_args[1]);
|
||||
}
|
||||
|
||||
|
|
@ -225,10 +220,9 @@ EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _in
|
|||
u256 gas; // TODO: Handle gas
|
||||
auto initOff = static_cast<size_t>(llvm2eth(*_initOff));
|
||||
auto initSize = static_cast<size_t>(llvm2eth(*_initSize));
|
||||
//auto&& initRef = bytesConstRef(Runtime::getMemory().data() + initOff, initSize);
|
||||
bytesConstRef initRef;
|
||||
auto&& initRef = bytesConstRef(_rt->getMemory().data() + initOff, initSize);
|
||||
OnOpFunc onOp{}; // TODO: Handle that thing
|
||||
h256 address = ext.create(endowment, &gas, initRef, onOp);
|
||||
h256 address(ext.create(endowment, &gas, initRef, onOp), h256::AlignRight);
|
||||
*_address = address;
|
||||
}
|
||||
else
|
||||
|
|
@ -252,8 +246,8 @@ EXPORT void ext_call(Runtime* _rt, i256* _gas, h256* _receiveAddress, i256* _val
|
|||
auto inSize = static_cast<size_t>(llvm2eth(*_inSize));
|
||||
auto outOff = static_cast<size_t>(llvm2eth(*_outOff));
|
||||
auto outSize = static_cast<size_t>(llvm2eth(*_outSize));
|
||||
auto&& inRef = bytesConstRef(); //Runtime::getMemory().data() + inOff, inSize);
|
||||
auto&& outRef = bytesConstRef(); // Runtime::getMemory().data() + outOff, outSize);
|
||||
auto&& inRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize);
|
||||
auto&& outRef = bytesConstRef(_rt->getMemory().data() + outOff, outSize);
|
||||
OnOpFunc onOp{}; // TODO: Handle that thing
|
||||
auto codeAddress = right160(*_codeAddress);
|
||||
ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress);
|
||||
|
|
@ -267,7 +261,7 @@ EXPORT void ext_sha3(Runtime* _rt, i256* _inOff, i256* _inSize, i256* _ret)
|
|||
{
|
||||
auto inOff = static_cast<size_t>(llvm2eth(*_inOff));
|
||||
auto inSize = static_cast<size_t>(llvm2eth(*_inSize));
|
||||
auto dataRef = bytesConstRef(); // Runtime::getMemory().data() + inOff, inSize);
|
||||
auto dataRef = bytesConstRef(_rt->getMemory().data() + inOff, inSize);
|
||||
auto hash = sha3(dataRef);
|
||||
*_ret = *reinterpret_cast<i256*>(&hash);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ 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>(c_sstoreResetGas); // FIXME: Check store gas
|
||||
|
||||
case Instruction::SLOAD:
|
||||
return static_cast<uint64_t>(c_sloadGas);
|
||||
|
|
@ -101,12 +101,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
|
|||
m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);
|
||||
|
||||
m_builder.SetInsertPoint(outOfGasBB);
|
||||
|
||||
//auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp);
|
||||
auto extJmpBuf = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "rt_jmpBuf");
|
||||
llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()};
|
||||
auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", module);
|
||||
m_builder.CreateCall2(longjmpNative, m_builder.CreateLoad(extJmpBuf), Constant::get(ReturnCode::OutOfGas));
|
||||
_runtimeManager.raiseException(ReturnCode::OutOfGas);
|
||||
m_builder.CreateUnreachable();
|
||||
|
||||
m_builder.SetInsertPoint(updateBB);
|
||||
|
|
@ -134,7 +129,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>(c_sstoreResetGas); // FIXME: Check store gas
|
||||
|
||||
// [ADD] if oldValue == 0 and newValue != 0 => 2*cost
|
||||
// [DEL] if oldValue != 0 and newValue == 0 => 0
|
||||
|
|
@ -148,7 +143,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu
|
|||
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);
|
||||
createCall(m_gasCheckFunc, cost);
|
||||
}
|
||||
|
||||
void GasMeter::giveBack(llvm::Value* _gas)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace jit
|
|||
{
|
||||
class RuntimeManager;
|
||||
|
||||
class GasMeter : public CompilerHelper
|
||||
class GasMeter : public CompilerHelper // TODO: Use RuntimeHelper
|
||||
{
|
||||
public:
|
||||
GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager);
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ namespace eth
|
|||
namespace jit
|
||||
{
|
||||
|
||||
Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter, RuntimeManager& _runtimeManager):
|
||||
CompilerHelper(_builder)
|
||||
Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
|
||||
RuntimeHelper(_runtimeManager)
|
||||
{
|
||||
auto module = getModule();
|
||||
auto i64Ty = m_builder.getInt64Ty();
|
||||
|
|
@ -40,12 +40,6 @@ Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter, RuntimeManager&
|
|||
m_size = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size");
|
||||
m_size->setUnnamedAddr(true); // Address is not important
|
||||
|
||||
m_returnDataOffset = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset");
|
||||
m_returnDataOffset->setUnnamedAddr(true); // Address is not important
|
||||
|
||||
m_returnDataSize = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize");
|
||||
m_returnDataSize->setUnnamedAddr(true); // Address is not important
|
||||
|
||||
llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr};
|
||||
m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module);
|
||||
llvm::AttrBuilder attrBuilder;
|
||||
|
|
@ -180,14 +174,6 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size)
|
|||
require(sizeRequired);
|
||||
}
|
||||
|
||||
void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size)
|
||||
{
|
||||
require(_index, _size); // Make sure that memory is allocated and count gas
|
||||
|
||||
m_builder.CreateStore(_index, m_returnDataOffset);
|
||||
m_builder.CreateStore(_size, m_returnDataSize);
|
||||
}
|
||||
|
||||
void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
|
||||
llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,12 +10,11 @@ namespace eth
|
|||
{
|
||||
namespace jit
|
||||
{
|
||||
class RuntimeManager;
|
||||
|
||||
class Memory : public CompilerHelper
|
||||
class Memory : public RuntimeHelper
|
||||
{
|
||||
public:
|
||||
Memory(llvm::IRBuilder<>& _builder, class GasMeter& _gasMeter, RuntimeManager& _runtimeManager);
|
||||
Memory(RuntimeManager& _runtimeManager, class GasMeter& _gasMeter);
|
||||
|
||||
llvm::Value* loadWord(llvm::Value* _addr);
|
||||
void storeWord(llvm::Value* _addr, llvm::Value* _word);
|
||||
|
|
@ -31,9 +30,6 @@ public:
|
|||
/// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory.
|
||||
void require(llvm::Value* _offset, llvm::Value* _size);
|
||||
|
||||
void registerReturnData(llvm::Value* _index, llvm::Value* _size);
|
||||
bytesConstRef getReturnData();
|
||||
|
||||
void dump(uint64_t _begin, uint64_t _end = 0);
|
||||
|
||||
private:
|
||||
|
|
@ -44,10 +40,6 @@ private:
|
|||
llvm::GlobalVariable* m_data;
|
||||
llvm::GlobalVariable* m_size;
|
||||
|
||||
/// @TODO: m_data and m_size could be used
|
||||
llvm::GlobalVariable* m_returnDataOffset;
|
||||
llvm::GlobalVariable* m_returnDataSize;
|
||||
|
||||
llvm::Function* m_resize;
|
||||
llvm::Function* m_require;
|
||||
llvm::Function* m_loadWord;
|
||||
|
|
|
|||
|
|
@ -24,9 +24,10 @@ llvm::StructType* RuntimeData::getType()
|
|||
{
|
||||
llvm::ArrayType::get(Type::i256, _size),
|
||||
Type::BytePtr,
|
||||
Type::BytePtr,
|
||||
Type::BytePtr
|
||||
};
|
||||
type = llvm::StructType::create(elems, "RuntimeData");
|
||||
type = llvm::StructType::create(elems, "Runtime");
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
|
@ -56,13 +57,9 @@ llvm::Twine getName(RuntimeData::Index _index)
|
|||
}
|
||||
}
|
||||
|
||||
static Runtime* g_runtime; // FIXME: Remove
|
||||
|
||||
Runtime::Runtime(u256 _gas, ExtVMFace& _ext):
|
||||
Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf):
|
||||
m_ext(_ext)
|
||||
{
|
||||
assert(!g_runtime);
|
||||
g_runtime = this;
|
||||
set(RuntimeData::Gas, _gas);
|
||||
set(RuntimeData::Address, fromAddress(_ext.myAddress));
|
||||
set(RuntimeData::Caller, fromAddress(_ext.caller));
|
||||
|
|
@ -79,11 +76,7 @@ Runtime::Runtime(u256 _gas, ExtVMFace& _ext):
|
|||
set(RuntimeData::CodeSize, _ext.code.size()); // TODO: Use constant
|
||||
m_data.callData = _ext.data.data();
|
||||
m_data.code = _ext.code.data();
|
||||
}
|
||||
|
||||
Runtime::~Runtime()
|
||||
{
|
||||
g_runtime = nullptr;
|
||||
m_data.jmpBuf = _jmpBuf;
|
||||
}
|
||||
|
||||
void Runtime::set(RuntimeData::Index _index, u256 _value)
|
||||
|
|
@ -96,16 +89,14 @@ u256 Runtime::getGas() const
|
|||
return llvm2eth(m_data.elems[RuntimeData::Gas]);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
EXPORT i256 mem_returnDataOffset; // FIXME: Dis-globalize
|
||||
EXPORT i256 mem_returnDataSize;
|
||||
}
|
||||
|
||||
bytesConstRef Runtime::getReturnData() const
|
||||
{
|
||||
// TODO: Handle large indexes
|
||||
auto offset = static_cast<size_t>(llvm2eth(mem_returnDataOffset));
|
||||
auto size = static_cast<size_t>(llvm2eth(mem_returnDataSize));
|
||||
auto offset = static_cast<size_t>(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset]));
|
||||
auto size = static_cast<size_t>(llvm2eth(m_data.elems[RuntimeData::ReturnDataSize]));
|
||||
|
||||
assert(offset + size <= m_memory.size());
|
||||
// TODO: Handle invalid data access by returning empty ref
|
||||
return {m_memory.data() + offset, size};
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +104,8 @@ bytesConstRef Runtime::getReturnData() const
|
|||
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder)
|
||||
{
|
||||
m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt");
|
||||
llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()};
|
||||
m_longjmp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", getModule());
|
||||
|
||||
// Export data
|
||||
auto mainFunc = getMainFunction();
|
||||
|
|
@ -122,15 +115,36 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_bui
|
|||
|
||||
llvm::Value* RuntimeManager::getRuntimePtr()
|
||||
{
|
||||
// TODO: If in main function - get it from param
|
||||
return m_builder.CreateLoad(m_dataPtr);
|
||||
if (auto mainFunc = getMainFunction())
|
||||
return mainFunc->arg_begin()->getNextNode(); // Runtime is the second parameter of main function
|
||||
return m_builder.CreateLoad(m_dataPtr, "rt");
|
||||
}
|
||||
|
||||
llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index)
|
||||
{
|
||||
llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)};
|
||||
return m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr");
|
||||
}
|
||||
|
||||
llvm::Value* RuntimeManager::get(RuntimeData::Index _index)
|
||||
{
|
||||
llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)};
|
||||
auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr");
|
||||
return m_builder.CreateLoad(ptr, getName(_index));
|
||||
return m_builder.CreateLoad(getPtr(_index), getName(_index));
|
||||
}
|
||||
|
||||
void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value)
|
||||
{
|
||||
m_builder.CreateStore(_value, getPtr(_index));
|
||||
}
|
||||
|
||||
void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size)
|
||||
{
|
||||
set(RuntimeData::ReturnDataOffset, _offset);
|
||||
set(RuntimeData::ReturnDataSize, _size);
|
||||
}
|
||||
|
||||
void RuntimeManager::raiseException(ReturnCode _returnCode)
|
||||
{
|
||||
m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode));
|
||||
}
|
||||
|
||||
llvm::Value* RuntimeManager::get(Instruction _inst)
|
||||
|
|
@ -167,6 +181,12 @@ llvm::Value* RuntimeManager::getCode()
|
|||
return getBuilder().CreateLoad(ptr, "code");
|
||||
}
|
||||
|
||||
llvm::Value* RuntimeManager::getJmpBuf()
|
||||
{
|
||||
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 3, "jmpbufPtr");
|
||||
return getBuilder().CreateLoad(ptr, "jmpbuf");
|
||||
}
|
||||
|
||||
llvm::Value* RuntimeManager::getGas()
|
||||
{
|
||||
return get(RuntimeData::Gas);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "CompilerHelper.h"
|
||||
#include "Utils.h"
|
||||
#include "Type.h"
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
|
@ -41,12 +42,16 @@ struct RuntimeData
|
|||
GasLimit,
|
||||
CodeSize,
|
||||
|
||||
_size
|
||||
_size,
|
||||
|
||||
ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference
|
||||
ReturnDataSize = CallDataSize
|
||||
};
|
||||
|
||||
i256 elems[_size];
|
||||
byte const* callData;
|
||||
byte const* code;
|
||||
decltype(&jmp_buf{}[0]) jmpBuf;
|
||||
|
||||
static llvm::StructType* getType();
|
||||
};
|
||||
|
|
@ -57,8 +62,7 @@ using MemoryImpl = bytes;
|
|||
class Runtime
|
||||
{
|
||||
public:
|
||||
Runtime(u256 _gas, ExtVMFace& _ext);
|
||||
~Runtime();
|
||||
Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf);
|
||||
|
||||
Runtime(const Runtime&) = delete;
|
||||
void operator=(const Runtime&) = delete;
|
||||
|
|
@ -71,6 +75,7 @@ public:
|
|||
|
||||
u256 getGas() const;
|
||||
bytesConstRef getReturnData() const;
|
||||
decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; }
|
||||
|
||||
private:
|
||||
void set(RuntimeData::Index _index, u256 _value);
|
||||
|
|
@ -96,8 +101,17 @@ public:
|
|||
llvm::Value* getCode();
|
||||
void setGas(llvm::Value* _gas);
|
||||
|
||||
void registerReturnData(llvm::Value* _index, llvm::Value* _size);
|
||||
|
||||
void raiseException(ReturnCode _returnCode);
|
||||
|
||||
private:
|
||||
llvm::GlobalVariable* m_dataPtr;
|
||||
llvm::Value* getPtr(RuntimeData::Index _index);
|
||||
void set(RuntimeData::Index _index, llvm::Value* _value);
|
||||
llvm::Value* getJmpBuf();
|
||||
|
||||
llvm::GlobalVariable* m_dataPtr = nullptr;
|
||||
llvm::Function* m_longjmp = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,13 +74,11 @@ extern "C"
|
|||
|
||||
using namespace dev::eth::jit;
|
||||
|
||||
extern std::jmp_buf* rt_jmpBuf;
|
||||
|
||||
EXPORT void stack_pop(Runtime* _rt, uint64_t _count)
|
||||
{
|
||||
auto& stack = _rt->getStack();
|
||||
if (stack.size() < _count)
|
||||
longjmp(*rt_jmpBuf, static_cast<uint64_t>(ReturnCode::StackTooSmall));
|
||||
longjmp(_rt->getJmpBuf(), static_cast<uint64_t>(ReturnCode::StackTooSmall));
|
||||
|
||||
stack.erase(stack.end() - _count, stack.end());
|
||||
}
|
||||
|
|
@ -99,7 +97,7 @@ EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* _ret)
|
|||
auto& stack = _rt->getStack();
|
||||
// TODO: encode _index and stack size in the return code
|
||||
if (stack.size() <= _index)
|
||||
longjmp(*rt_jmpBuf, static_cast<uint64_t>(ReturnCode::StackTooSmall));
|
||||
longjmp(_rt->getJmpBuf(), static_cast<uint64_t>(ReturnCode::StackTooSmall));
|
||||
|
||||
*_ret = *(stack.rbegin() + _index);
|
||||
}
|
||||
|
|
@ -109,7 +107,7 @@ EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256* _word)
|
|||
auto& stack = _rt->getStack();
|
||||
// TODO: encode _index and stack size in the return code
|
||||
if (stack.size() <= _index)
|
||||
longjmp(*rt_jmpBuf, static_cast<uint64_t>(ReturnCode::StackTooSmall));
|
||||
longjmp(_rt->getJmpBuf(), static_cast<uint64_t>(ReturnCode::StackTooSmall));
|
||||
|
||||
*(stack.rbegin() + _index) = *_word;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ enum class ReturnCode
|
|||
|
||||
BadJumpDestination = 101,
|
||||
OutOfGas = 102,
|
||||
StackTooSmall = 103
|
||||
StackTooSmall = 103,
|
||||
BadInstruction = 104,
|
||||
};
|
||||
|
||||
struct Constant
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "ExecutionEngine.h"
|
||||
#include "Compiler.h"
|
||||
#include "Type.h"
|
||||
|
||||
namespace dev
|
||||
{
|
||||
|
|
@ -13,24 +14,23 @@ namespace eth
|
|||
namespace jit
|
||||
{
|
||||
|
||||
bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps)
|
||||
bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
|
||||
{
|
||||
assert(!_onOp); // Parameter ignored
|
||||
assert(_steps == (uint64_t)-1); // Parameter ignored
|
||||
|
||||
auto module = Compiler().compile(_ext.code);
|
||||
|
||||
ExecutionEngine engine;
|
||||
auto exitCode = engine.run(std::move(module), m_gas, &_ext);
|
||||
|
||||
switch (exitCode)
|
||||
switch (static_cast<ReturnCode>(exitCode))
|
||||
{
|
||||
case 101:
|
||||
case ReturnCode::BadJumpDestination:
|
||||
BOOST_THROW_EXCEPTION(BadJumpDestination());
|
||||
case 102:
|
||||
case ReturnCode::OutOfGas:
|
||||
BOOST_THROW_EXCEPTION(OutOfGas());
|
||||
case 103:
|
||||
case ReturnCode::StackTooSmall:
|
||||
BOOST_THROW_EXCEPTION(StackTooSmall(1,0));
|
||||
case ReturnCode::BadInstruction:
|
||||
BOOST_THROW_EXCEPTION(BadInstruction());
|
||||
}
|
||||
|
||||
m_output = std::move(engine.returnData);
|
||||
|
|
|
|||
Loading…
Reference in a new issue