Fabcoin Core  0.16.2
P2P Digital Currency
RuntimeManager.cpp
Go to the documentation of this file.
1 #include "RuntimeManager.h"
2 
4 #include <llvm/IR/IntrinsicInst.h>
5 #include <llvm/IR/Module.h>
7 
8 #include "Array.h"
9 #include "Utils.h"
10 
11 namespace dev
12 {
13 namespace eth
14 {
15 namespace jit
16 {
17 
19 {
20  static llvm::StructType* type = nullptr;
21  if (!type)
22  {
23  llvm::Type* elems[] =
24  {
25  Type::Size, // gas
26  Type::Size, // gasPrice
27  Type::BytePtr, // callData
28  Type::Size, // callDataSize
29  Type::Word, // apparentValue
30  Type::BytePtr, // code
31  Type::Size, // codeSize
32  };
33  type = llvm::StructType::create(elems, "RuntimeData");
34  }
35  return type;
36 }
37 
38 llvm::StructType* RuntimeManager::getRuntimeType()
39 {
40  static llvm::StructType* type = nullptr;
41  if (!type)
42  {
43  llvm::Type* elems[] =
44  {
45  Type::RuntimeDataPtr, // data
46  Type::EnvPtr, // Env*
47  Array::getType() // memory
48  };
49  type = llvm::StructType::create(elems, "Runtime");
50  }
51  return type;
52 }
53 
54 namespace
55 {
56 llvm::Twine getName(RuntimeData::Index _index)
57 {
58  switch (_index)
59  {
60  default: return "";
61  case RuntimeData::Gas: return "msg.gas";
62  case RuntimeData::GasPrice: return "tx.gasprice";
63  case RuntimeData::CallData: return "msg.data.ptr";
64  case RuntimeData::CallDataSize: return "msg.data.size";
65  case RuntimeData::ApparentCallValue: return "msg.value";
66  case RuntimeData::Code: return "code.ptr";
67  case RuntimeData::CodeSize: return "code.size";
68  }
69 }
70 }
71 
73  CompilerHelper(_builder),
74  m_codeBegin(_codeBegin),
75  m_codeEnd(_codeEnd)
76 {
77  // Unpack data
78  auto rtPtr = getRuntimePtr();
79  m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 0), "dataPtr");
80  assert(m_dataPtr->getType() == Type::RuntimeDataPtr);
81  m_memPtr = m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 2, "mem");
82  assert(m_memPtr->getType() == Array::getType()->getPointerTo());
83  m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 1), "env");
84  assert(m_envPtr->getType() == Type::EnvPtr);
85 
86  auto mallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, {Type::Size}, false), llvm::Function::ExternalLinkage, "malloc", getModule());
87  mallocFunc->setDoesNotThrow();
88  mallocFunc->setDoesNotAlias(0);
89 
90  m_stackBase = m_builder.CreateCall(mallocFunc, m_builder.getInt64(Type::Word->getPrimitiveSizeInBits() / 8 * stackSizeLimit), "stack.base"); // TODO: Use Type::SizeT type
91  m_stackSize = m_builder.CreateAlloca(Type::Size, nullptr, "stack.size");
92  m_builder.CreateStore(m_builder.getInt64(0), m_stackSize);
93 
94  auto data = m_builder.CreateLoad(m_dataPtr, "data");
95  for (unsigned i = 0; i < m_dataElts.size(); ++i)
96  m_dataElts[i] = m_builder.CreateExtractValue(data, i, getName(RuntimeData::Index(i)));
97 
98  m_gasPtr = m_builder.CreateAlloca(Type::Gas, nullptr, "gas.ptr");
99  m_builder.CreateStore(m_dataElts[RuntimeData::Index::Gas], m_gasPtr);
100 
101  m_exitBB = llvm::BasicBlock::Create(m_builder.getContext(), "Exit", getMainFunction());
103  m_builder.SetInsertPoint(m_exitBB);
104  auto retPhi = m_builder.CreatePHI(Type::MainReturn, 16, "ret");
105  auto freeFunc = getModule()->getFunction("free");
106  if (!freeFunc)
107  {
108  freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::WordPtr, false), llvm::Function::ExternalLinkage, "free", getModule());
109  freeFunc->setDoesNotThrow();
110  freeFunc->setDoesNotCapture(1);
111  }
112  m_builder.CreateCall(freeFunc, {m_stackBase});
113  auto extGasPtr = m_builder.CreateStructGEP(getRuntimeDataType(), getDataPtr(), RuntimeData::Index::Gas, "msg.gas.ptr");
114  m_builder.CreateStore(getGas(), extGasPtr);
115  m_builder.CreateRet(retPhi);
116 }
117 
119 {
120  // Expect first argument of a function to be a pointer to Runtime
121  auto func = m_builder.GetInsertBlock()->getParent();
122  auto rtPtr = &func->getArgumentList().front();
123  assert(rtPtr->getType() == Type::RuntimePtr);
124  return rtPtr;
125 }
126 
128 {
129  if (getMainFunction())
130  return m_dataPtr;
131 
132  auto rtPtr = getRuntimePtr();
133  auto dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 0), "data");
134  assert(dataPtr->getType() == getRuntimeDataType()->getPointerTo());
135  return dataPtr;
136 }
137 
139 {
140  assert(getMainFunction()); // Available only in main function
141  return m_envPtr;
142 }
143 
145 {
146  auto ptr = m_builder.CreateStructGEP(getRuntimeDataType(), getDataPtr(), _index);
147  assert(getRuntimeDataType()->getElementType(_index)->getPointerTo() == ptr->getType());
148  return ptr;
149 }
150 
152 {
154 }
155 
157 {
158  auto ptr = getPtr(_index);
159  assert(ptr->getType() == _value->getType()->getPointerTo());
160  m_builder.CreateStore(_value, ptr);
161 }
162 
164 {
165  auto memPtr = m_builder.CreateBitCast(getMem(), Type::BytePtr->getPointerTo());
166  auto mem = m_builder.CreateLoad(memPtr, "memory");
167  auto returnDataPtr = m_builder.CreateGEP(mem, _offset);
168  set(RuntimeData::ReturnData, returnDataPtr);
169 
170  auto size64 = m_builder.CreateTrunc(_size, Type::Size);
171  set(RuntimeData::ReturnDataSize, size64);
172 }
173 
175 {
176  m_builder.CreateBr(m_exitBB);
177  auto retPhi = llvm::cast<llvm::PHINode>(&m_exitBB->front());
178  retPhi->addIncoming(Constant::get(_returnCode), m_builder.GetInsertBlock());
179 }
180 
182 {
183  auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);
184  m_builder.CreateCall(longjmp, {_jmpBuf});
185 }
186 
188 {
190 }
191 
193 {
194  // OPT Check what is faster
195  //return get(RuntimeData::Code);
196  if (!m_codePtr)
197  m_codePtr = m_builder.CreateGlobalStringPtr({reinterpret_cast<char const*>(m_codeBegin), static_cast<size_t>(m_codeEnd - m_codeBegin)}, "code");
198  return m_codePtr;
199 }
200 
202 {
204 }
205 
207 {
209  assert(value->getType() == Type::Size);
210  return m_builder.CreateZExt(value, Type::Word);
211 }
212 
214 {
215  return m_builder.CreateLoad(getGasPtr(), "gas");
216 }
217 
219 {
221  return m_gasPtr;
222 }
223 
225 {
227  return m_memPtr;
228 }
229 
231 {
232  assert(_gas->getType() == Type::Gas);
233  m_builder.CreateStore(_gas, getGasPtr());
234 }
235 
236 }
237 }
238 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
void setGas(llvm::Value *_gas)
llvm::Module * getModule()
Reference to the IR module being compiled.
Return data pointer (set only in case of RETURN)
Definition: JIT.h:39
void set(RuntimeData::Index _index, llvm::Value *_value)
void registerReturnData(llvm::Value *_index, llvm::Value *_size)
static llvm::Type * Void
Definition: Type.h:32
static llvm::PointerType * RuntimePtr
Definition: Type.h:39
assert(len-trim+(2 *lenIndices)<=WIDTH)
static llvm::Type * getType()
Definition: Array.cpp:217
static llvm::PointerType * WordPtr
Definition: Type.h:22
llvm::Value * getPtr(RuntimeData::Index _index)
Return data size (set only in case of RETURN)
Definition: JIT.h:40
byte const * code_iterator
Definition: Common.h:11
static llvm::StructType * getRuntimeType()
Base class for compiler helpers like Memory, GasMeter, etc.
RuntimeManager(IRBuilder &_builder, code_iterator _codeBegin, code_iterator _codeEnd)
static llvm::PointerType * BytePtr
Definition: Type.h:30
static llvm::StructType * getRuntimeDataType()
Config::Value_type Value
static llvm::IntegerType * Word
Definition: Type.h:21
static llvm::ConstantInt * get(int64_t _n)
Returns word-size constant.
Definition: Type.cpp:55
static llvm::IntegerType * MainReturn
Main function return type.
Definition: Type.h:35
void exit(ReturnCode _returnCode)
llvm::Function * getMainFunction()
Reference to the main module function.
static llvm::PointerType * RuntimeDataPtr
Definition: Type.h:38
void abort(llvm::Value *_jmpBuf)
ReturnCode
Definition: JIT.h:86
static const size_t stackSizeLimit
PlatformStyle::TableColorType type
Definition: rpcconsole.cpp:61
std::array< llvm::Value *, RuntimeData::numElements > m_dataElts
static llvm::IntegerType * Size
Definition: Type.h:25
IRBuilder & m_builder
Reference to parent compiler IR builder.
llvm::IRBuilder<> IRBuilder
static llvm::IntegerType * Gas
Definition: Type.h:26
uint8_t const * data
Definition: sha3.h:19
static llvm::PointerType * EnvPtr
Definition: Type.h:37
llvm::BasicBlock * m_exitBB