Paweł Bylica
10 years ago
11 changed files with 265 additions and 208 deletions
@ -0,0 +1,51 @@ |
|||
|
|||
#pragma once |
|||
|
|||
#include <csetjmp> |
|||
|
|||
#include "Utils.h" |
|||
|
|||
|
|||
namespace dev |
|||
{ |
|||
namespace eth |
|||
{ |
|||
namespace jit |
|||
{ |
|||
|
|||
using jmpBufRef = decltype(&jmp_buf{}[0]); |
|||
|
|||
struct RuntimeData |
|||
{ |
|||
enum Index |
|||
{ |
|||
Gas, |
|||
Address, |
|||
Caller, |
|||
Origin, |
|||
CallValue, |
|||
CallDataSize, |
|||
GasPrice, |
|||
PrevHash, |
|||
CoinBase, |
|||
TimeStamp, |
|||
Number, |
|||
Difficulty, |
|||
GasLimit, |
|||
CodeSize, |
|||
|
|||
_size, |
|||
|
|||
ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference
|
|||
ReturnDataSize = CallDataSize |
|||
}; |
|||
|
|||
i256 elems[_size]; |
|||
byte const* callData; |
|||
byte const* code; |
|||
jmpBufRef jmpBuf; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
} |
@ -0,0 +1,159 @@ |
|||
|
|||
#include "RuntimeManager.h" |
|||
|
|||
#include <llvm/IR/GlobalVariable.h> |
|||
#include <llvm/IR/Function.h> |
|||
#include <llvm/IR/IntrinsicInst.h> |
|||
|
|||
#include "RuntimeData.h" |
|||
#include "Instruction.h" |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace eth |
|||
{ |
|||
namespace jit |
|||
{ |
|||
|
|||
llvm::StructType* RuntimeManager::getRuntimeDataType() |
|||
{ |
|||
static llvm::StructType* type = nullptr; |
|||
if (!type) |
|||
{ |
|||
llvm::Type* elems[] = |
|||
{ |
|||
llvm::ArrayType::get(Type::Word, RuntimeData::_size), |
|||
Type::BytePtr, |
|||
Type::BytePtr, |
|||
Type::BytePtr |
|||
}; |
|||
type = llvm::StructType::create(elems, "Runtime"); |
|||
} |
|||
return type; |
|||
} |
|||
|
|||
namespace |
|||
{ |
|||
llvm::Twine getName(RuntimeData::Index _index) |
|||
{ |
|||
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"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
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"); |
|||
m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); |
|||
|
|||
// Export data
|
|||
auto mainFunc = getMainFunction(); |
|||
llvm::Value* dataPtr = &mainFunc->getArgumentList().back(); |
|||
m_builder.CreateStore(dataPtr, m_dataPtr); |
|||
} |
|||
|
|||
llvm::Value* RuntimeManager::getRuntimePtr() |
|||
{ |
|||
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) |
|||
{ |
|||
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) |
|||
{ |
|||
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() |
|||
{ |
|||
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 1, "calldataPtr"); |
|||
return getBuilder().CreateLoad(ptr, "calldata"); |
|||
} |
|||
|
|||
llvm::Value* RuntimeManager::getCode() |
|||
{ |
|||
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "codePtr"); |
|||
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); |
|||
} |
|||
|
|||
void RuntimeManager::setGas(llvm::Value* _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); |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
#pragma once |
|||
|
|||
#include "CompilerHelper.h" |
|||
#include "Type.h" |
|||
#include "RuntimeData.h" |
|||
#include "Instruction.h" |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace eth |
|||
{ |
|||
namespace jit |
|||
{ |
|||
|
|||
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); |
|||
|
|||
void registerReturnData(llvm::Value* _index, llvm::Value* _size); |
|||
|
|||
void raiseException(ReturnCode _returnCode); |
|||
|
|||
static llvm::StructType* getRuntimeDataType(); |
|||
|
|||
private: |
|||
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; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue