Browse Source

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

cl-refactor
artur-zawlocki 10 years ago
parent
commit
dd357f29c7
  1. 131
      libevmjit/Compiler.cpp
  2. 2
      libevmjit/Compiler.h
  3. 16
      libevmjit/CompilerHelper.cpp
  4. 20
      libevmjit/CompilerHelper.h
  5. 6
      libevmjit/ExecutionEngine.cpp
  6. 200
      libevmjit/Ext.cpp
  7. 24
      libevmjit/Ext.h
  8. 21
      libevmjit/GasMeter.cpp
  9. 8
      libevmjit/GasMeter.h
  10. 68
      libevmjit/Memory.cpp
  11. 7
      libevmjit/Memory.h
  12. 151
      libevmjit/Runtime.cpp
  13. 64
      libevmjit/Runtime.h
  14. 44
      libevmjit/Stack.cpp
  15. 4
      libevmjit/Stack.h
  16. 4
      libevmjit/Type.cpp
  17. 2
      libevmjit/Type.h

131
libevmjit/Compiler.cpp

@ -22,6 +22,7 @@
#include "GasMeter.h"
#include "Utils.h"
#include "Endianness.h"
#include "Runtime.h"
namespace dev
{
@ -168,7 +169,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
auto module = std::make_unique<llvm::Module>("main", m_builder.getContext());
// Create main function
m_mainFunc = llvm::Function::Create(llvm::FunctionType::get(Type::MainReturn, false), llvm::Function::ExternalLinkage, "main", module.get());
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());
// Create the basic blocks.
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc);
@ -177,10 +180,11 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
createBasicBlocks(bytecode);
// Init runtime structures.
GasMeter gasMeter(m_builder);
Memory memory(m_builder, gasMeter);
Ext ext(m_builder);
Stack stack(m_builder);
RuntimeManager runtimeManager(m_builder);
GasMeter gasMeter(m_builder, runtimeManager);
Memory memory(m_builder, gasMeter, runtimeManager);
Ext ext(runtimeManager);
Stack stack(m_builder, runtimeManager);
m_builder.CreateBr(basicBlocks.begin()->second);
@ -190,7 +194,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
auto iterCopy = basicBlockPairIt;
++iterCopy;
auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock);
compileBasicBlock(basicBlock, bytecode, runtimeManager, memory, ext, gasMeter, nextBasicBlock);
}
// Code for special blocks:
@ -276,7 +280,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
}
void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock)
void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock)
{
m_builder.SetInsertPoint(basicBlock.llvm());
auto& stack = basicBlock.localStack();
@ -683,57 +687,29 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
}
case Instruction::GAS:
{
stack.push(gasMeter.getGas());
break;
}
case Instruction::ADDRESS:
{
auto value = ext.address();
stack.push(value);
break;
}
case Instruction::BALANCE:
{
auto address = stack.pop();
auto value = ext.balance(address);
stack.push(value);
break;
}
case Instruction::CALLER:
{
auto value = ext.caller();
stack.push(value);
break;
}
case Instruction::ORIGIN:
{
auto value = ext.origin();
stack.push(value);
break;
}
case Instruction::CALLVALUE:
{
auto value = ext.callvalue();
stack.push(value);
break;
}
case Instruction::CALLDATASIZE:
case Instruction::CODESIZE:
case Instruction::GASPRICE:
case Instruction::PREVHASH:
case Instruction::COINBASE:
case Instruction::TIMESTAMP:
case Instruction::NUMBER:
case Instruction::DIFFICULTY:
case Instruction::GASLIMIT:
{
auto value = ext.calldatasize();
stack.push(value);
// Pushes an element of runtime data on stack
stack.push(_runtimeManager.get(inst));
break;
}
case Instruction::CODESIZE:
case Instruction::BALANCE:
{
auto value = ext.codesize();
auto address = stack.pop();
auto value = ext.balance(address);
stack.push(value);
break;
}
@ -752,8 +728,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
auto srcIdx = stack.pop();
auto reqBytes = stack.pop();
auto srcPtr = ext.calldata();
auto srcSize = ext.calldatasize();
auto srcPtr = _runtimeManager.getCallData();
auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize);
memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes);
break;
@ -765,8 +741,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
auto srcIdx = stack.pop();
auto reqBytes = stack.pop();
auto srcPtr = ext.code(); // TODO: Code & its size are constants, feature #80814234
auto srcSize = ext.codesize();
auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234
auto srcSize = _runtimeManager.get(RuntimeData::CodeSize);
memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes);
break;
@ -794,55 +770,6 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
break;
}
case Instruction::GASPRICE:
{
auto value = ext.gasprice();
stack.push(value);
break;
}
case Instruction::PREVHASH:
{
auto value = ext.prevhash();
stack.push(value);
break;
}
case Instruction::COINBASE:
{
auto value = ext.coinbase();
stack.push(value);
break;
}
case Instruction::TIMESTAMP:
{
auto value = ext.timestamp();
stack.push(value);
break;
}
case Instruction::NUMBER:
{
auto value = ext.number();
stack.push(value);
break;
}
case Instruction::DIFFICULTY:
{
auto value = ext.difficulty();
stack.push(value);
break;
}
case Instruction::GASLIMIT:
{
auto value = ext.gaslimit();
stack.push(value);
break;
}
case Instruction::CREATE:
{
auto endowment = stack.pop();
@ -877,7 +804,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
auto receiveAddress = codeAddress;
if (inst == Instruction::CALLCODE)
receiveAddress = ext.address();
receiveAddress = _runtimeManager.get(RuntimeData::Address);
auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress);
gasMeter.giveBack(gas);

2
libevmjit/Compiler.h

@ -31,7 +31,7 @@ private:
void createBasicBlocks(bytesConstRef bytecode);
void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class RuntimeManager& _runtimeManager, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
void removeDeadBlocks();

16
libevmjit/CompilerHelper.cpp

@ -3,6 +3,8 @@
#include <llvm/IR/Function.h>
#include "Runtime.h"
namespace dev
{
namespace eth
@ -21,6 +23,20 @@ llvm::Module* CompilerHelper::getModule()
return m_builder.GetInsertBlock()->getParent()->getParent();
}
llvm::Function* CompilerHelper::getMainFunction()
{
assert(m_builder.GetInsertBlock());
auto mainFunc = m_builder.GetInsertBlock()->getParent();
assert(mainFunc && mainFunc->getName() == "main");
return mainFunc;
}
RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager):
CompilerHelper(_runtimeManager.getBuilder()),
m_runtimeManager(_runtimeManager)
{}
}
}
}

20
libevmjit/CompilerHelper.h

@ -10,6 +10,7 @@ namespace eth
{
namespace jit
{
class RuntimeManager;
/// Base class for compiler helpers like Memory, GasMeter, etc.
class CompilerHelper
@ -23,8 +24,27 @@ protected:
/// Reference to the IR module being compiled
llvm::Module* getModule();
/// Reference to the main module function
llvm::Function* getMainFunction();
/// Reference to parent compiler IR builder
llvm::IRBuilder<>& m_builder;
llvm::IRBuilder<>& getBuilder() { return m_builder; }
friend class RuntimeHelper;
};
/// Compiler helper that depends on runtime data
class RuntimeHelper : public CompilerHelper
{
protected:
RuntimeHelper(RuntimeManager& _runtimeManager);
RuntimeManager& getRuntimeManager() { return m_runtimeManager; }
private:
RuntimeManager& m_runtimeManager;
};

6
libevmjit/ExecutionEngine.cpp

@ -117,7 +117,7 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtV
auto executionStartTime = std::chrono::high_resolution_clock::now();
rt_jmpBuf = &buf;
auto result = exec->runFunction(entryFunc, {});
auto result = exec->runFunction(entryFunc, {{}, llvm::GenericValue(runtime.getDataPtr())});
returnCode = static_cast<ReturnCode>(result.IntVal.getZExtValue());
auto executionEndTime = std::chrono::high_resolution_clock::now();
@ -130,13 +130,13 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtV
returnCode = static_cast<ReturnCode>(r);
// Return remaining gas
_gas = returnCode == ReturnCode::OutOfGas ? 0 : Runtime::getGas();
_gas = returnCode == ReturnCode::OutOfGas ? 0 : runtime.getGas();
std::cout << "Max stack size: " << Stack::maxStackSize << std::endl;
if (returnCode == ReturnCode::Return)
{
returnData = Memory::getReturnData().toVector(); // TODO: It might be better to place is in Runtime interface
returnData = runtime.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)

200
libevmjit/Ext.cpp

@ -8,10 +8,9 @@
#include <libdevcrypto/SHA3.h>
#include "Runtime.h"
#include "Type.h"
#include "Endianness.h"
using namespace llvm;
namespace dev
{
namespace eth
@ -27,27 +26,14 @@ inline u256 fromAddress(Address _a)
struct ExtData
{
i256 address;
i256 caller;
i256 origin;
i256 callvalue;
i256 calldatasize;
i256 gasprice;
i256 prevhash;
i256 coinbase;
i256 timestamp;
i256 number;
i256 difficulty;
i256 gaslimit;
i256 codesize;
const byte* calldata;
const byte* code;
};
Ext::Ext(llvm::IRBuilder<>& _builder):
CompilerHelper(_builder)
Ext::Ext(RuntimeManager& _runtimeManager):
RuntimeHelper(_runtimeManager)
{
auto&& ctx = _builder.getContext();
auto&& ctx = m_builder.getContext();
auto module = getModule();
auto i256Ty = m_builder.getIntNTy(256);
@ -64,52 +50,27 @@ Ext::Ext(llvm::IRBuilder<>& _builder):
m_arg7 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg7");
m_arg8 = m_builder.CreateAlloca(i256Ty, nullptr, "ext.arg8");
Type* elements[] = {
i256Ty, // i256 address;
i256Ty, // i256 caller;
i256Ty, // i256 origin;
i256Ty, // i256 callvalue;
i256Ty, // i256 calldatasize;
i256Ty, // i256 gasprice;
i256Ty, // i256 prevhash;
i256Ty, // i256 coinbase;
i256Ty, // i256 timestamp;
i256Ty, // i256 number;
i256Ty, // i256 difficulty;
i256Ty, // i256 gaslimit;
i256Ty, // i256 codesize
i8PtrTy, // byte* calldata
i8PtrTy, // byte* code
};
auto extDataTy = StructType::create(elements, "ext.Data");
m_data = m_builder.CreateAlloca(extDataTy, nullptr, "ext.data");
using llvm::types::i;
using Linkage = llvm::GlobalValue::LinkageTypes;
m_init = Function::Create(FunctionType::get(m_builder.getVoidTy(), extDataTy->getPointerTo(), false), Linkage::ExternalLinkage, "ext_init", module);
m_store = Function::Create(TypeBuilder<void(i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module);
m_setStore = Function::Create(TypeBuilder<void(i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module);
m_calldataload = Function::Create(TypeBuilder<void(i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_calldataload", module);
m_balance = Function::Create(TypeBuilder<void(i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_balance", module);
m_suicide = Function::Create(TypeBuilder<void(i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_suicide", module);
m_create = Function::Create(TypeBuilder<void(i<256>*, i<256>*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_create", module);
Type* args[] = {i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy, i256PtrTy};
m_call = Function::Create(FunctionType::get(m_builder.getVoidTy(), args, false), Linkage::ExternalLinkage, "ext_call", module);
m_bswap = Intrinsic::getDeclaration(module, Intrinsic::bswap, i256Ty);
m_sha3 = Function::Create(TypeBuilder<void(i<256>*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_sha3", module);
m_exp = Function::Create(TypeBuilder<void(i<256>*, i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_exp", module);
m_codeAt = Function::Create(TypeBuilder<i<8>*(i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codeAt", module);
m_codesizeAt = Function::Create(TypeBuilder<void(i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_codesizeAt", module);
m_builder.CreateCall(m_init, m_data);
llvm::Type* argsTypes[] = {Type::RuntimePtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr};
m_store = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_store", module);
m_setStore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_setStore", module);
m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_calldataload", module);
m_balance = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_balance", module);
m_suicide = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_suicide", module);
m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 5}, false), Linkage::ExternalLinkage, "ext_create", module);
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_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module);
}
llvm::Value* Ext::store(llvm::Value* _index)
{
m_builder.CreateStore(_index, m_args[0]);
m_builder.CreateCall(m_store, m_args); // Uses native endianness
m_builder.CreateCall3(m_store, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); // Uses native endianness
return m_builder.CreateLoad(m_args[1]);
}
@ -117,62 +78,40 @@ void Ext::setStore(llvm::Value* _index, llvm::Value* _value)
{
m_builder.CreateStore(_index, m_args[0]);
m_builder.CreateStore(_value, m_args[1]);
m_builder.CreateCall(m_setStore, m_args); // Uses native endianness
}
Value* Ext::getDataElem(unsigned _index, const Twine& _name)
{
auto valuePtr = m_builder.CreateStructGEP(m_data, _index, _name);
return m_builder.CreateLoad(valuePtr);
m_builder.CreateCall3(m_setStore, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]); // Uses native endianness
}
Value* Ext::address() { return getDataElem(0, "address"); }
Value* Ext::caller() { return getDataElem(1, "caller"); }
Value* Ext::origin() { return getDataElem(2, "origin"); }
Value* Ext::callvalue() { return getDataElem(3, "callvalue"); }
Value* Ext::calldatasize() { return getDataElem(4, "calldatasize"); }
Value* Ext::gasprice() { return getDataElem(5, "gasprice"); }
Value* Ext::prevhash() { return getDataElem(6, "prevhash"); }
Value* Ext::coinbase() { return getDataElem(7, "coinbase"); }
Value* Ext::timestamp() { return getDataElem(8, "timestamp"); }
Value* Ext::number() { return getDataElem(9, "number"); }
Value* Ext::difficulty() { return getDataElem(10, "difficulty"); }
Value* Ext::gaslimit() { return getDataElem(11, "gaslimit"); }
Value* Ext::codesize() { return getDataElem(12, "codesize"); }
Value* Ext::calldata() { return getDataElem(13, "calldata"); }
Value* Ext::code() { return getDataElem(14, "code"); }
Value* Ext::calldataload(Value* _index)
llvm::Value* Ext::calldataload(llvm::Value* _index)
{
m_builder.CreateStore(_index, m_args[0]);
m_builder.CreateCall(m_calldataload, m_args);
m_builder.CreateCall3(m_calldataload, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]);
auto ret = m_builder.CreateLoad(m_args[1]);
return Endianness::toNative(m_builder, ret);
}
Value* Ext::balance(Value* _address)
llvm::Value* Ext::balance(llvm::Value* _address)
{
auto address = Endianness::toBE(m_builder, _address);
m_builder.CreateStore(address, m_args[0]);
m_builder.CreateCall(m_balance, m_args);
m_builder.CreateCall3(m_balance, getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]);
return m_builder.CreateLoad(m_args[1]);
}
void Ext::suicide(Value* _address)
void Ext::suicide(llvm::Value* _address)
{
auto address = Endianness::toBE(m_builder, _address);
m_builder.CreateStore(address, m_args[0]);
m_builder.CreateCall(m_suicide, m_args[0]);
m_builder.CreateCall2(m_suicide, getRuntimeManager().getRuntimePtr(), m_args[0]);
}
Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize)
llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize)
{
m_builder.CreateStore(_endowment, m_args[0]);
m_builder.CreateStore(_initOff, m_arg2);
m_builder.CreateStore(_initSize, m_arg3);
Value* args[] = {m_args[0], m_arg2, m_arg3, m_args[1]};
llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_arg3, m_args[1]};
m_builder.CreateCall(m_create, args);
Value* address = m_builder.CreateLoad(m_args[1]);
llvm::Value* address = m_builder.CreateLoad(m_args[1]);
address = Endianness::toNative(m_builder, address);
return address;
}
@ -190,7 +129,7 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V
auto codeAddress = Endianness::toBE(m_builder, _codeAddress);
m_builder.CreateStore(codeAddress, m_arg8);
llvm::Value* args[] = {m_args[0], m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_args[1]};
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);
_gas = m_builder.CreateLoad(m_args[0]); // Return gas
return m_builder.CreateLoad(m_args[1]);
@ -200,9 +139,9 @@ 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[] = {m_args[0], m_arg2, m_args[1]};
llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]};
m_builder.CreateCall(m_sha3, args);
Value* hash = m_builder.CreateLoad(m_args[1]);
llvm::Value* hash = m_builder.CreateLoad(m_args[1]);
hash = Endianness::toNative(m_builder, hash);
return hash;
}
@ -211,7 +150,7 @@ llvm::Value* Ext::exp(llvm::Value* _left, llvm::Value* _right)
{
m_builder.CreateStore(_left, m_args[0]);
m_builder.CreateStore(_right, m_arg2);
llvm::Value* args[] = {m_args[0], m_arg2, m_args[1]};
llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_arg2, m_args[1]};
m_builder.CreateCall(m_exp, args);
return m_builder.CreateLoad(m_args[1]);
}
@ -220,14 +159,14 @@ llvm::Value* Ext::codeAt(llvm::Value* _addr)
{
auto addr = Endianness::toBE(m_builder, _addr);
m_builder.CreateStore(addr, m_args[0]);
return m_builder.CreateCall(m_codeAt, m_args[0]);
return m_builder.CreateCall2(m_codeAt, getRuntimeManager().getRuntimePtr(), m_args[0]);
}
llvm::Value* Ext::codesizeAt(llvm::Value* _addr)
{
auto addr = Endianness::toBE(m_builder, _addr);
m_builder.CreateStore(addr, m_args[0]);
llvm::Value* args[] = {m_args[0], m_args[1]};
llvm::Value* args[] = {getRuntimeManager().getRuntimePtr(), m_args[0], m_args[1]};
m_builder.CreateCall(m_codesizeAt, args);
return m_builder.CreateLoad(m_args[1]);
}
@ -240,64 +179,44 @@ extern "C"
using namespace dev::eth::jit;
EXPORT void ext_init(ExtData* _extData)
{
auto&& ext = Runtime::getExt();
_extData->address = eth2llvm(fromAddress(ext.myAddress));
_extData->caller = eth2llvm(fromAddress(ext.caller));
_extData->origin = eth2llvm(fromAddress(ext.origin));
_extData->callvalue = eth2llvm(ext.value);
_extData->gasprice = eth2llvm(ext.gasPrice);
_extData->calldatasize = eth2llvm(ext.data.size());
_extData->prevhash = eth2llvm(ext.previousBlock.hash);
_extData->coinbase = eth2llvm(fromAddress(ext.currentBlock.coinbaseAddress));
_extData->timestamp = eth2llvm(ext.currentBlock.timestamp);
_extData->number = eth2llvm(ext.currentBlock.number);
_extData->difficulty = eth2llvm(ext.currentBlock.difficulty);
_extData->gaslimit = eth2llvm(ext.currentBlock.gasLimit);
_extData->codesize = eth2llvm(ext.code.size());
_extData->calldata = ext.data.data();
_extData->code = ext.code.data();
}
EXPORT void ext_store(i256* _index, i256* _value)
EXPORT void ext_store(Runtime* _rt, i256* _index, i256* _value)
{
auto index = llvm2eth(*_index);
auto value = Runtime::getExt().store(index); // Interface uses native endianness
auto value = _rt->getExt().store(index); // Interface uses native endianness
*_value = eth2llvm(value);
}
EXPORT void ext_setStore(i256* _index, i256* _value)
EXPORT void ext_setStore(Runtime* _rt, i256* _index, i256* _value)
{
auto index = llvm2eth(*_index);
auto value = llvm2eth(*_value);
Runtime::getExt().setStore(index, value); // Interface uses native endianness
_rt->getExt().setStore(index, value); // Interface uses native endianness
}
EXPORT void ext_calldataload(i256* _index, i256* _value)
EXPORT void ext_calldataload(Runtime* _rt, i256* _index, i256* _value)
{
auto index = static_cast<size_t>(llvm2eth(*_index));
assert(index + 31 > index); // TODO: Handle large index
auto b = reinterpret_cast<byte*>(_value);
for (size_t i = index, j = 0; i <= index + 31; ++i, ++j)
b[j] = i < Runtime::getExt().data.size() ? Runtime::getExt().data[i] : 0; // Keep Big Endian
b[j] = i < _rt->getExt().data.size() ? _rt->getExt().data[i] : 0; // Keep Big Endian
// TODO: It all can be done by adding padding to data or by using min() algorithm without branch
}
EXPORT void ext_balance(h256* _address, i256* _value)
EXPORT void ext_balance(Runtime* _rt, h256* _address, i256* _value)
{
auto u = Runtime::getExt().balance(right160(*_address));
auto u = _rt->getExt().balance(right160(*_address));
*_value = eth2llvm(u);
}
EXPORT void ext_suicide(h256* _address)
EXPORT void ext_suicide(Runtime* _rt, h256* _address)
{
Runtime::getExt().suicide(right160(*_address));
_rt->getExt().suicide(right160(*_address));
}
EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256* _address)
EXPORT void ext_create(Runtime* _rt, i256* _endowment, i256* _initOff, i256* _initSize, h256* _address)
{
auto&& ext = Runtime::getExt();
auto&& ext = _rt->getExt();
auto endowment = llvm2eth(*_endowment);
if (ext.balance(ext.myAddress) >= endowment)
@ -306,7 +225,8 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256*
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);
//auto&& initRef = bytesConstRef(Runtime::getMemory().data() + initOff, initSize);
bytesConstRef initRef;
OnOpFunc onOp{}; // TODO: Handle that thing
h256 address = ext.create(endowment, &gas, initRef, onOp);
*_address = address;
@ -317,9 +237,9 @@ EXPORT void ext_create(i256* _endowment, i256* _initOff, i256* _initSize, h256*
EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* _ret)
EXPORT void ext_call(Runtime* _rt, i256* _gas, h256* _receiveAddress, i256* _value, i256* _inOff, i256* _inSize, i256* _outOff, i256* _outSize, h256* _codeAddress, i256* _ret)
{
auto&& ext = Runtime::getExt();
auto&& ext = _rt->getExt();
auto value = llvm2eth(*_value);
auto ret = false;
@ -332,8 +252,8 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO
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(); //Runtime::getMemory().data() + inOff, inSize);
auto&& outRef = bytesConstRef(); // Runtime::getMemory().data() + outOff, outSize);
OnOpFunc onOp{}; // TODO: Handle that thing
auto codeAddress = right160(*_codeAddress);
ret = ext.call(receiveAddress, value, inRef, &gas, outRef, onOp, {}, codeAddress);
@ -343,16 +263,16 @@ EXPORT void ext_call(i256* _gas, h256* _receiveAddress, i256* _value, i256* _inO
_ret->a = ret ? 1 : 0;
}
EXPORT void ext_sha3(i256* _inOff, i256* _inSize, i256* _ret)
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(); // Runtime::getMemory().data() + inOff, inSize);
auto hash = sha3(dataRef);
*_ret = *reinterpret_cast<i256*>(&hash);
}
EXPORT void ext_exp(i256* _left, i256* _right, i256* _ret)
EXPORT void ext_exp(Runtime* _rt, i256* _left, i256* _right, i256* _ret)
{
bigint left = llvm2eth(*_left);
bigint right = llvm2eth(*_right);
@ -360,17 +280,17 @@ EXPORT void ext_exp(i256* _left, i256* _right, i256* _ret)
*_ret = eth2llvm(ret);
}
EXPORT unsigned char* ext_codeAt(h256* _addr256)
EXPORT unsigned char* ext_codeAt(Runtime* _rt, h256* _addr256) //FIXME: Check endianess
{
auto&& ext = Runtime::getExt();
auto&& ext = _rt->getExt();
auto addr = right160(*_addr256);
auto& code = ext.codeAt(addr);
return const_cast<unsigned char*>(code.data());
}
EXPORT void ext_codesizeAt(h256* _addr256, i256* _ret)
EXPORT void ext_codesizeAt(Runtime* _rt, h256* _addr256, i256* _ret) //FIXME: Check endianess
{
auto&& ext = Runtime::getExt();
auto&& ext = _rt->getExt();
auto addr = right160(*_addr256);
auto& code = ext.codeAt(addr);
*_ret = eth2llvm(u256(code.size()));

24
libevmjit/Ext.h

@ -12,30 +12,14 @@ namespace eth
namespace jit
{
class Ext : public CompilerHelper
class Ext : public RuntimeHelper
{
public:
Ext(llvm::IRBuilder<>& _builder);
Ext(RuntimeManager& _runtimeManager);
llvm::Value* store(llvm::Value* _index);
void setStore(llvm::Value* _index, llvm::Value* _value);
llvm::Value* address();
llvm::Value* caller();
llvm::Value* origin();
llvm::Value* callvalue();
llvm::Value* calldatasize();
llvm::Value* gasprice();
llvm::Value* prevhash();
llvm::Value* coinbase();
llvm::Value* timestamp();
llvm::Value* number();
llvm::Value* difficulty();
llvm::Value* gaslimit();
llvm::Value* codesize();
llvm::Value* calldata();
llvm::Value* code();
llvm::Value* balance(llvm::Value* _address);
void suicide(llvm::Value* _address);
llvm::Value* calldataload(llvm::Value* _index);
@ -47,8 +31,6 @@ public:
llvm::Value* codeAt(llvm::Value* _addr);
llvm::Value* codesizeAt(llvm::Value* _addr);
private:
llvm::Value* getDataElem(unsigned _index, const llvm::Twine& _name = "");
private:
llvm::Value* m_args[2];
@ -60,7 +42,6 @@ private:
llvm::Value* m_arg7;
llvm::Value* m_arg8;
llvm::Value* m_data;
llvm::Function* m_init;
llvm::Function* m_store;
llvm::Function* m_setStore;
llvm::Function* m_calldataload;
@ -68,7 +49,6 @@ private:
llvm::Function* m_suicide;
llvm::Function* m_create;
llvm::Function* m_call;
llvm::Function* m_bswap;
llvm::Function* m_sha3;
llvm::Function* m_exp;
llvm::Function* m_codeAt;

21
libevmjit/GasMeter.cpp

@ -10,6 +10,7 @@
#include "Type.h"
#include "Ext.h"
#include "Runtime.h"
namespace dev
{
@ -79,12 +80,11 @@ bool isCostBlockEnd(Instruction _inst)
}
GasMeter::GasMeter(llvm::IRBuilder<>& _builder) :
CompilerHelper(_builder)
GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) :
CompilerHelper(_builder),
m_runtimeManager(_runtimeManager)
{
auto module = getModule();
m_gas = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas");
m_gas->setUnnamedAddr(true); // Address is not important
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", module);
InsertPointGuard guard(m_builder);
@ -96,7 +96,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder) :
m_builder.SetInsertPoint(checkBB);
llvm::Value* cost = m_gasCheckFunc->arg_begin();
cost->setName("cost");
llvm::Value* gas = m_builder.CreateLoad(m_gas, "gas");
auto gas = m_runtimeManager.getGas();
auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas");
m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);
@ -111,7 +111,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder) :
m_builder.SetInsertPoint(updateBB);
gas = m_builder.CreateSub(gas, cost);
m_builder.CreateStore(gas, m_gas);
m_runtimeManager.setGas(gas);
m_builder.CreateRetVoid();
}
@ -153,9 +153,7 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu
void GasMeter::giveBack(llvm::Value* _gas)
{
llvm::Value* gasCounter = m_builder.CreateLoad(m_gas, "gas");
gasCounter = m_builder.CreateAdd(gasCounter, _gas);
m_builder.CreateStore(gasCounter, m_gas);
m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas));
}
void GasMeter::commitCostBlock(llvm::Value* _additionalCost)
@ -191,11 +189,6 @@ void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilde
_builder.CreateCall(m_gasCheckFunc, cost);
}
llvm::Value* GasMeter::getGas()
{
return m_builder.CreateLoad(m_gas, "gas");
}
}
}
}

8
libevmjit/GasMeter.h

@ -11,11 +11,12 @@ namespace eth
{
namespace jit
{
class RuntimeManager;
class GasMeter : public CompilerHelper
{
public:
GasMeter(llvm::IRBuilder<>& _builder);
GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager);
/// Count step cost of instruction
void count(Instruction _inst);
@ -33,16 +34,15 @@ public:
/// Generate code that checks the cost of additional memory used by program
void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder);
llvm::Value* getGas();
private:
/// Cumulative gas cost of a block of instructions
/// @TODO Handle overflow
uint64_t m_blockCost = 0;
llvm::CallInst* m_checkCall = nullptr;
llvm::GlobalVariable* m_gas;
llvm::Function* m_gasCheckFunc;
RuntimeManager& m_runtimeManager;
};
}

68
libevmjit/Memory.cpp

@ -15,6 +15,7 @@
#include "Runtime.h"
#include "GasMeter.h"
#include "Endianness.h"
#include "Runtime.h"
namespace dev
{
@ -23,7 +24,7 @@ namespace eth
namespace jit
{
Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter):
Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter, RuntimeManager& _runtimeManager):
CompilerHelper(_builder)
{
auto module = getModule();
@ -45,18 +46,19 @@ Memory::Memory(llvm::IRBuilder<>& _builder, GasMeter& _gasMeter):
m_returnDataSize = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize");
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);
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;
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(_gasMeter);
m_require = createRequireFunc(_gasMeter, _runtimeManager);
m_loadWord = createFunc(false, Type::i256, _gasMeter);
m_storeWord = createFunc(true, Type::i256, _gasMeter);
m_storeByte = createFunc(true, Type::Byte, _gasMeter);
}
llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter)
llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager)
{
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
@ -83,7 +85,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter)
_gasMeter.checkMemory(newWords, m_builder);
// Resize
m_builder.CreateStore(sizeRequired, m_size);
auto newData = m_builder.CreateCall(m_resize, m_size, "newData");
auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData");
m_builder.CreateStore(newData, m_data);
m_builder.CreateBr(returnBB);
@ -232,48 +234,36 @@ extern "C"
using namespace dev::eth::jit;
EXPORT i256 mem_returnDataOffset;
EXPORT i256 mem_returnDataSize;
EXPORT uint8_t* mem_resize(i256* _size)
EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size)
{
auto size = _size->a; // Trunc to 64-bit
auto& memory = Runtime::getMemory();
auto& memory = _rt->getMemory();
memory.resize(size);
return memory.data();
}
EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end)
{
if (_end == 0)
_end = Runtime::getMemory().size();
std::cerr << "MEMORY: active size: " << std::dec
<< Runtime::getMemory().size() / 32 << " words\n";
std::cerr << "MEMORY: dump from " << std::dec
<< _begin << " to " << _end << ":";
if (_end <= _begin)
return;
_begin = _begin / 16 * 16;
for (size_t i = _begin; i < _end; i++)
{
if ((i - _begin) % 16 == 0)
std::cerr << '\n' << std::dec << i << ": ";
auto b = Runtime::getMemory()[i];
std::cerr << std::hex << std::setw(2) << static_cast<int>(b) << ' ';
}
std::cerr << std::endl;
//if (_end == 0)
// _end = Runtime::getMemory().size();
//std::cerr << "MEMORY: active size: " << std::dec
// << Runtime::getMemory().size() / 32 << " words\n";
//std::cerr << "MEMORY: dump from " << std::dec
// << _begin << " to " << _end << ":";
//if (_end <= _begin)
// return;
//_begin = _begin / 16 * 16;
//for (size_t i = _begin; i < _end; i++)
//{
// if ((i - _begin) % 16 == 0)
// std::cerr << '\n' << std::dec << i << ": ";
// auto b = Runtime::getMemory()[i];
// std::cerr << std::hex << std::setw(2) << static_cast<int>(b) << ' ';
//}
//std::cerr << std::endl;
}
} // extern "C"
dev::bytesConstRef dev::eth::jit::Memory::getReturnData()
{
// TODO: Handle large indexes
auto offset = static_cast<size_t>(llvm2eth(mem_returnDataOffset));
auto size = static_cast<size_t>(llvm2eth(mem_returnDataSize));
auto& memory = Runtime::getMemory();
return {memory.data() + offset, size};
}

7
libevmjit/Memory.h

@ -10,11 +10,12 @@ namespace eth
{
namespace jit
{
class RuntimeManager;
class Memory : public CompilerHelper
{
public:
Memory(llvm::IRBuilder<>& _builder, class GasMeter& _gasMeter);
Memory(llvm::IRBuilder<>& _builder, class GasMeter& _gasMeter, RuntimeManager& _runtimeManager);
llvm::Value* loadWord(llvm::Value* _addr);
void storeWord(llvm::Value* _addr, llvm::Value* _word);
@ -31,13 +32,13 @@ public:
void require(llvm::Value* _offset, llvm::Value* _size);
void registerReturnData(llvm::Value* _index, llvm::Value* _size);
static bytesConstRef getReturnData();
bytesConstRef getReturnData();
void dump(uint64_t _begin, uint64_t _end = 0);
private:
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter);
llvm::Function* createRequireFunc(GasMeter& _gasMeter);
llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager);
private:
llvm::GlobalVariable* m_data;

151
libevmjit/Runtime.cpp

@ -1,6 +1,9 @@
#include "Runtime.h"
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <libevm/VM.h>
#include "Type.h"
@ -12,19 +15,70 @@ namespace eth
namespace jit
{
static Runtime* g_runtime;
llvm::StructType* RuntimeData::getType()
{
static llvm::StructType* type = nullptr;
if (!type)
{
llvm::Type* elems[] =
{
llvm::ArrayType::get(Type::i256, _size),
Type::BytePtr,
Type::BytePtr
};
type = llvm::StructType::create(elems, "RuntimeData");
}
return type;
}
extern "C"
namespace
{
llvm::Twine getName(RuntimeData::Index _index)
{
EXPORT i256 gas;
switch (_index)
{
default: return "data";
case RuntimeData::Gas: return "gas";
case RuntimeData::Address: return "address";
case RuntimeData::Caller: return "caller";
case RuntimeData::Origin: return "origin";
case RuntimeData::CallValue: return "callvalue";
case RuntimeData::CallDataSize: return "calldatasize";
case RuntimeData::GasPrice: return "gasprice";
case RuntimeData::PrevHash: return "prevhash";
case RuntimeData::CoinBase: return "coinbase";
case RuntimeData::TimeStamp: return "timestamp";
case RuntimeData::Number: return "number";
case RuntimeData::Difficulty: return "difficulty";
case RuntimeData::GasLimit: return "gaslimit";
case RuntimeData::CodeSize: return "codesize";
}
}
}
static Runtime* g_runtime; // FIXME: Remove
Runtime::Runtime(u256 _gas, ExtVMFace& _ext):
m_ext(_ext)
{
assert(!g_runtime);
g_runtime = this;
gas = eth2llvm(_gas);
set(RuntimeData::Gas, _gas);
set(RuntimeData::Address, fromAddress(_ext.myAddress));
set(RuntimeData::Caller, fromAddress(_ext.caller));
set(RuntimeData::Origin, fromAddress(_ext.origin));
set(RuntimeData::CallValue, _ext.value);
set(RuntimeData::CallDataSize, _ext.data.size());
set(RuntimeData::GasPrice, _ext.gasPrice);
set(RuntimeData::PrevHash, _ext.previousBlock.hash);
set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress));
set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp);
set(RuntimeData::Number, _ext.currentBlock.number);
set(RuntimeData::Difficulty, _ext.currentBlock.difficulty);
set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit);
set(RuntimeData::CodeSize, _ext.code.size()); // TODO: Use constant
m_data.callData = _ext.data.data();
m_data.code = _ext.code.data();
}
Runtime::~Runtime()
@ -32,24 +86,97 @@ Runtime::~Runtime()
g_runtime = nullptr;
}
StackImpl& Runtime::getStack()
void Runtime::set(RuntimeData::Index _index, u256 _value)
{
m_data.elems[_index] = eth2llvm(_value);
}
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));
return {m_memory.data() + offset, size};
}
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");
// Export data
auto mainFunc = getMainFunction();
llvm::Value* dataPtr = &mainFunc->getArgumentList().back();
m_builder.CreateStore(dataPtr, m_dataPtr);
}
llvm::Value* RuntimeManager::getRuntimePtr()
{
// TODO: If in main function - get it from param
return m_builder.CreateLoad(m_dataPtr);
}
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));
}
llvm::Value* RuntimeManager::get(Instruction _inst)
{
switch (_inst)
{
default: assert(false); return nullptr;
case Instruction::GAS: return get(RuntimeData::Gas);
case Instruction::ADDRESS: return get(RuntimeData::Address);
case Instruction::CALLER: return get(RuntimeData::Caller);
case Instruction::ORIGIN: return get(RuntimeData::Origin);
case Instruction::CALLVALUE: return get(RuntimeData::CallValue);
case Instruction::CALLDATASIZE: return get(RuntimeData::CallDataSize);
case Instruction::GASPRICE: return get(RuntimeData::GasPrice);
case Instruction::PREVHASH: return get(RuntimeData::PrevHash);
case Instruction::COINBASE: return get(RuntimeData::CoinBase);
case Instruction::TIMESTAMP: return get(RuntimeData::TimeStamp);
case Instruction::NUMBER: return get(RuntimeData::Number);
case Instruction::DIFFICULTY: return get(RuntimeData::Difficulty);
case Instruction::GASLIMIT: return get(RuntimeData::GasLimit);
case Instruction::CODESIZE: return get(RuntimeData::CodeSize);
}
}
llvm::Value* RuntimeManager::getCallData()
{
return g_runtime->m_stack;
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 1, "calldataPtr");
return getBuilder().CreateLoad(ptr, "calldata");
}
MemoryImpl& Runtime::getMemory()
llvm::Value* RuntimeManager::getCode()
{
return g_runtime->m_memory;
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "codePtr");
return getBuilder().CreateLoad(ptr, "code");
}
ExtVMFace& Runtime::getExt()
llvm::Value* RuntimeManager::getGas()
{
return g_runtime->m_ext;
return get(RuntimeData::Gas);
}
u256 Runtime::getGas()
void RuntimeManager::setGas(llvm::Value* _gas)
{
return llvm2eth(gas);
llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(RuntimeData::Gas)};
auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, "gasPtr");
m_builder.CreateStore(_gas, ptr);
}
}

64
libevmjit/Runtime.h

@ -5,6 +5,7 @@
#include <libevm/ExtVMFace.h>
#include "CompilerHelper.h"
#include "Utils.h"
@ -21,6 +22,35 @@ namespace eth
namespace jit
{
struct RuntimeData
{
enum Index: unsigned
{
Gas,
Address,
Caller,
Origin,
CallValue,
CallDataSize,
GasPrice,
PrevHash,
CoinBase,
TimeStamp,
Number,
Difficulty,
GasLimit,
CodeSize,
_size
};
i256 elems[_size];
byte const* callData;
byte const* code;
static llvm::StructType* getType();
};
using StackImpl = std::vector<i256>;
using MemoryImpl = bytes;
@ -33,17 +63,43 @@ public:
Runtime(const Runtime&) = delete;
void operator=(const Runtime&) = delete;
static StackImpl& getStack();
static MemoryImpl& getMemory();
static ExtVMFace& getExt();
static u256 getGas();
RuntimeData* getDataPtr() { return &m_data; }
StackImpl& getStack() { return m_stack; }
MemoryImpl& getMemory() { return m_memory; }
ExtVMFace& getExt() { return m_ext; }
u256 getGas() const;
bytesConstRef getReturnData() const;
private:
void set(RuntimeData::Index _index, u256 _value);
/// @internal Must be the first element to asure Runtime* === RuntimeData*
RuntimeData m_data;
StackImpl m_stack;
MemoryImpl m_memory;
ExtVMFace& m_ext;
};
class RuntimeManager: public CompilerHelper
{
public:
RuntimeManager(llvm::IRBuilder<>& _builder);
llvm::Value* getRuntimePtr();
llvm::Value* get(RuntimeData::Index _index);
llvm::Value* get(Instruction _inst);
llvm::Value* getGas(); // TODO: Remove
llvm::Value* getCallData();
llvm::Value* getCode();
void setGas(llvm::Value* _gas);
private:
llvm::GlobalVariable* m_dataPtr;
};
}
}
}

44
libevmjit/Stack.cpp

@ -14,8 +14,9 @@ namespace eth
namespace jit
{
Stack::Stack(llvm::IRBuilder<>& _builder)
: CompilerHelper(_builder)
Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
: CompilerHelper(_builder),
m_runtimeManager(_runtimeManager)
{
m_arg = m_builder.CreateAlloca(Type::i256, nullptr, "stack.arg");
@ -23,11 +24,16 @@ Stack::Stack(llvm::IRBuilder<>& _builder)
using Linkage = GlobalValue::LinkageTypes;
auto module = getModule();
m_push = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::WordPtr, false), Linkage::ExternalLinkage, "stack_push", module);
m_pop = Function::Create(FunctionType::get(m_builder.getVoidTy(), Type::Size, false), Linkage::ExternalLinkage, "stack_pop", module);
llvm::Type* getSetArgTypes[] = {Type::Size, Type::WordPtr};
m_get = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef<llvm::Type*>(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_get", module);
m_set = Function::Create(FunctionType::get(m_builder.getVoidTy(), ArrayRef<llvm::Type*>(getSetArgTypes), false), Linkage::ExternalLinkage, "stack_set", module);
llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr};
m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module);
llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size};
m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module);
llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr};
m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module);
m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module);
}
Stack::~Stack()
@ -35,25 +41,25 @@ Stack::~Stack()
llvm::Value* Stack::get(size_t _index)
{
m_builder.CreateCall2(m_get, llvm::ConstantInt::get(Type::Size, _index, false), m_arg);
m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg);
return m_builder.CreateLoad(m_arg);
}
void Stack::set(size_t _index, llvm::Value* _value)
{
m_builder.CreateStore(_value, m_arg);
m_builder.CreateCall2(m_set, llvm::ConstantInt::get(Type::Size, _index, false), m_arg);
m_builder.CreateCall3(m_set, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg);
}
void Stack::pop(size_t _count)
{
m_builder.CreateCall(m_pop, llvm::ConstantInt::get(Type::Size, _count, false));
m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false));
}
void Stack::push(llvm::Value* _value)
{
m_builder.CreateStore(_value, m_arg);
m_builder.CreateCall(m_push, m_arg);
m_builder.CreateCall2(m_push, m_runtimeManager.getRuntimePtr(), m_arg);
}
@ -70,27 +76,27 @@ using namespace dev::eth::jit;
extern std::jmp_buf* rt_jmpBuf;
EXPORT void stack_pop(uint64_t _count)
EXPORT void stack_pop(Runtime* _rt, uint64_t _count)
{
auto& stack = Runtime::getStack();
auto& stack = _rt->getStack();
if (stack.size() < _count)
longjmp(*rt_jmpBuf, static_cast<uint64_t>(ReturnCode::StackTooSmall));
stack.erase(stack.end() - _count, stack.end());
}
EXPORT void stack_push(i256* _word)
EXPORT void stack_push(Runtime* _rt, i256* _word)
{
auto& stack = Runtime::getStack();
auto& stack = _rt->getStack();
stack.push_back(*_word);
if (stack.size() > Stack::maxStackSize)
Stack::maxStackSize = stack.size();
}
EXPORT void stack_get(uint64_t _index, i256* _ret)
EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* _ret)
{
auto& stack = Runtime::getStack();
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));
@ -98,9 +104,9 @@ EXPORT void stack_get(uint64_t _index, i256* _ret)
*_ret = *(stack.rbegin() + _index);
}
EXPORT void stack_set(uint64_t _index, i256* _word)
EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256* _word)
{
auto& stack = Runtime::getStack();
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));

4
libevmjit/Stack.h

@ -10,12 +10,13 @@ namespace eth
{
namespace jit
{
class RuntimeManager;
class Stack : public CompilerHelper
{
public:
Stack(llvm::IRBuilder<>& builder);
Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager);
virtual ~Stack();
llvm::Value* get(size_t _index);
@ -26,6 +27,7 @@ public:
static size_t maxStackSize;
private:
RuntimeManager& m_runtimeManager;
llvm::Function* m_push;
llvm::Function* m_pop;

4
libevmjit/Type.cpp

@ -3,6 +3,8 @@
#include <llvm/IR/DerivedTypes.h>
#include "Runtime.h"
namespace dev
{
namespace eth
@ -18,6 +20,7 @@ llvm::IntegerType* Type::Byte;
llvm::PointerType* Type::BytePtr;
llvm::Type* Type::Void;
llvm::IntegerType* Type::MainReturn;
llvm::PointerType* Type::RuntimePtr;
void Type::init(llvm::LLVMContext& _context)
{
@ -30,6 +33,7 @@ void Type::init(llvm::LLVMContext& _context)
BytePtr = Byte->getPointerTo();
Void = llvm::Type::getVoidTy(_context);
MainReturn = llvm::Type::getInt32Ty(_context);
RuntimePtr = RuntimeData::getType()->getPointerTo();
}
llvm::ConstantInt* Constant::get(uint64_t _n)

2
libevmjit/Type.h

@ -30,6 +30,8 @@ struct Type
/// Main function return type
static llvm::IntegerType* MainReturn;
static llvm::PointerType* RuntimePtr;
static void init(llvm::LLVMContext& _context);
};

Loading…
Cancel
Save