/ libevmjit / RuntimeManager.cpp
RuntimeManager.cpp
  1  #include "RuntimeManager.h"
  2  
  3  #include "preprocessor/llvm_includes_start.h"
  4  #include <llvm/IR/IntrinsicInst.h>
  5  #include <llvm/IR/Module.h>
  6  #include "preprocessor/llvm_includes_end.h"
  7  
  8  #include "Array.h"
  9  #include "Utils.h"
 10  
 11  namespace dev
 12  {
 13  namespace eth
 14  {
 15  namespace jit
 16  {
 17  
 18  llvm::StructType* RuntimeManager::getRuntimeDataType()
 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  			Type::Word,     // adddress
 33  			Type::Word,     // caller
 34  			Type::Size,     // depth
 35  		};
 36  		type = llvm::StructType::create(elems, "RuntimeData");
 37  	}
 38  	return type;
 39  }
 40  
 41  llvm::StructType* RuntimeManager::getRuntimeType()
 42  {
 43  	static llvm::StructType* type = nullptr;
 44  	if (!type)
 45  	{
 46  		llvm::Type* elems[] =
 47  		{
 48  			Type::RuntimeDataPtr,	// data
 49  			Type::EnvPtr,			// Env*
 50  			Array::getType()		// memory
 51  		};
 52  		type = llvm::StructType::create(elems, "Runtime");
 53  	}
 54  	return type;
 55  }
 56  
 57  llvm::StructType* RuntimeManager::getTxContextType()
 58  {
 59  	auto name = "evm.txctx";
 60  	auto type = getModule()->getTypeByName(name);
 61  	if (type)
 62  		return type;
 63  
 64  	auto& ctx = getModule()->getContext();
 65  	auto i256 = llvm::IntegerType::get(ctx, 256);
 66  	auto h160 = llvm::ArrayType::get(llvm::IntegerType::get(ctx, 8), 20);
 67  	auto i64  = llvm::IntegerType::get(ctx, 64);
 68  	return llvm::StructType::create({i256, h160, h160, i64, i64, i64, i256}, name);
 69  }
 70  
 71  llvm::Value* RuntimeManager::getTxContextItem(unsigned _index)
 72  {
 73  	auto call = m_builder.CreateCall(m_loadTxCtxFn, {m_txCtxLoaded, m_txCtx, m_envPtr});
 74  	call->setCallingConv(llvm::CallingConv::Fast);
 75  	auto ptr = m_builder.CreateStructGEP(getTxContextType(), m_txCtx, _index);
 76  	if (_index == 1 || _index == 2)
 77  	{
 78  		// In struct addresses are represented as char[20] to fix alignment
 79  		// issues (i160 has alignment of 8). Here we convert them back to i160.
 80  		ptr = m_builder.CreateBitCast(ptr, m_builder.getIntNTy(160)->getPointerTo());
 81  	}
 82  	return m_builder.CreateLoad(ptr);
 83  }
 84  
 85  namespace
 86  {
 87  llvm::Twine getName(RuntimeData::Index _index)
 88  {
 89  	switch (_index)
 90  	{
 91  	default:						return "";
 92  	case RuntimeData::Gas:			return "msg.gas";
 93  	case RuntimeData::GasPrice:		return "tx.gasprice";
 94  	case RuntimeData::CallData:		return "msg.data.ptr";
 95  	case RuntimeData::CallDataSize:	return "msg.data.size";
 96  	case RuntimeData::Value:		return "msg.value";
 97  	case RuntimeData::Code:			return "code.ptr";
 98  	case RuntimeData::CodeSize:		return "code.size";
 99  	case RuntimeData::Address:		return "msg.address";
100  	case RuntimeData::Sender:		return "msg.sender";
101  	case RuntimeData::Depth:		return "msg.depth";
102  	}
103  }
104  }
105  
106  RuntimeManager::RuntimeManager(IRBuilder& _builder, code_iterator _codeBegin, code_iterator _codeEnd):
107  	CompilerHelper(_builder),
108  	m_codeBegin(_codeBegin),
109  	m_codeEnd(_codeEnd)
110  {
111  	m_txCtxLoaded = m_builder.CreateAlloca(m_builder.getInt1Ty(), nullptr, "txctx.loaded");
112  	m_builder.CreateStore(m_builder.getInt1(false), m_txCtxLoaded);
113  	m_txCtx = m_builder.CreateAlloca(getTxContextType(), nullptr, "txctx");
114  
115  	auto getTxCtxFnTy = llvm::FunctionType::get(Type::Void, {m_txCtx->getType(), Type::EnvPtr}, false);
116  	auto getTxCtxFn = llvm::Function::Create(getTxCtxFnTy, llvm::Function::ExternalLinkage, "evm.get_tx_context", getModule());
117  	auto loadTxCtxFnTy = llvm::FunctionType::get(Type::Void, {m_txCtxLoaded->getType(), m_txCtx->getType(), Type::EnvPtr}, false);
118  	m_loadTxCtxFn = llvm::Function::Create(loadTxCtxFnTy, llvm::Function::PrivateLinkage, "loadTxCtx", getModule());
119  	m_loadTxCtxFn->setCallingConv(llvm::CallingConv::Fast);
120  	auto checkBB = llvm::BasicBlock::Create(m_loadTxCtxFn->getContext(), "Check", m_loadTxCtxFn);
121  	auto loadBB = llvm::BasicBlock::Create(m_loadTxCtxFn->getContext(), "Load", m_loadTxCtxFn);
122  	auto exitBB = llvm::BasicBlock::Create(m_loadTxCtxFn->getContext(), "Exit", m_loadTxCtxFn);
123  
124  	auto iter = m_loadTxCtxFn->arg_begin();
125  	llvm::Argument* flag = &(*iter++);
126  	flag->setName("flag");
127  	llvm::Argument* txCtx = &(*iter++);
128  	txCtx->setName("txctx");
129  	llvm::Argument* env = &(*iter);
130  	env->setName("env");
131  
132  	auto b = IRBuilder{checkBB};
133  	auto f = b.CreateLoad(flag);
134  	b.CreateCondBr(f, exitBB, loadBB);
135  	b.SetInsertPoint(loadBB);
136  	b.CreateStore(b.getInt1(true), flag);
137  	b.CreateCall(getTxCtxFn, {txCtx, env});
138  	b.CreateBr(exitBB);
139  	b.SetInsertPoint(exitBB);
140  	b.CreateRetVoid();
141  
142  	// Unpack data
143  	auto rtPtr = getRuntimePtr();
144  	m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 0), "dataPtr");
145  	assert(m_dataPtr->getType() == Type::RuntimeDataPtr);
146  	m_memPtr = m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 2, "mem");
147  	assert(m_memPtr->getType() == Array::getType()->getPointerTo());
148  	m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 1), "env");
149  	assert(m_envPtr->getType() == Type::EnvPtr);
150  
151  	auto mallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, {Type::Size}, false), llvm::Function::ExternalLinkage, "malloc", getModule());
152  	mallocFunc->setDoesNotThrow();
153  	mallocFunc->addAttribute(0, llvm::Attribute::NoAlias);
154  
155  	m_stackBase = m_builder.CreateCall(mallocFunc, m_builder.getInt64(Type::Word->getPrimitiveSizeInBits() / 8 * stackSizeLimit), "stack.base"); // TODO: Use Type::SizeT type
156  	m_stackSize = m_builder.CreateAlloca(Type::Size, nullptr, "stack.size");
157  	m_builder.CreateStore(m_builder.getInt64(0), m_stackSize);
158  
159  	auto data = m_builder.CreateLoad(m_dataPtr, "data");
160  	for (unsigned i = 0; i < m_dataElts.size(); ++i)
161  		m_dataElts[i] = m_builder.CreateExtractValue(data, i, getName(RuntimeData::Index(i)));
162  
163  	m_gasPtr = m_builder.CreateAlloca(Type::Gas, nullptr, "gas.ptr");
164  	m_builder.CreateStore(m_dataElts[RuntimeData::Index::Gas], m_gasPtr);
165  
166  	m_returnBufDataPtr = m_builder.CreateAlloca(Type::BytePtr, nullptr, "returndata.ptr");
167  	m_returnBufSizePtr = m_builder.CreateAlloca(Type::Size, nullptr, "returndatasize.ptr");
168  	resetReturnBuf();
169  
170  	m_exitBB = llvm::BasicBlock::Create(m_builder.getContext(), "Exit", getMainFunction());
171  	InsertPointGuard guard{m_builder};
172  	m_builder.SetInsertPoint(m_exitBB);
173  	auto retPhi = m_builder.CreatePHI(Type::MainReturn, 16, "ret");
174  	auto freeFunc = getModule()->getFunction("free");
175  	if (!freeFunc)
176  	{
177  		freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::WordPtr, false), llvm::Function::ExternalLinkage, "free", getModule());
178  		freeFunc->setDoesNotThrow();
179  		freeFunc->addAttribute(1, llvm::Attribute::NoCapture);
180  	}
181  	m_builder.CreateCall(freeFunc, {m_stackBase});
182  	auto extGasPtr = m_builder.CreateStructGEP(getRuntimeDataType(), getDataPtr(), RuntimeData::Index::Gas, "msg.gas.ptr");
183  	m_builder.CreateStore(getGas(), extGasPtr);
184  	m_builder.CreateRet(retPhi);
185  }
186  
187  llvm::Value* RuntimeManager::getRuntimePtr()
188  {
189  	// Expect first argument of a function to be a pointer to Runtime
190  	auto func = m_builder.GetInsertBlock()->getParent();
191  	auto rtPtr = func->args().begin();
192  	assert(rtPtr->getType() == Type::RuntimePtr);
193  	return rtPtr;
194  }
195  
196  llvm::Value* RuntimeManager::getDataPtr()
197  {
198  	if (getMainFunction())
199  		return m_dataPtr;
200  
201  	auto rtPtr = getRuntimePtr();
202  	auto dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 0), "data");
203  	assert(dataPtr->getType() == getRuntimeDataType()->getPointerTo());
204  	return dataPtr;
205  }
206  
207  llvm::Value* RuntimeManager::getEnvPtr()
208  {
209  	assert(getMainFunction());	// Available only in main function
210  	return m_envPtr;
211  }
212  
213  llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index)
214  {
215  	auto ptr = m_builder.CreateStructGEP(getRuntimeDataType(), getDataPtr(), _index);
216  	assert(getRuntimeDataType()->getElementType(_index)->getPointerTo() == ptr->getType());
217  	return ptr;
218  }
219  
220  llvm::Value* RuntimeManager::getAddress()
221  {
222  	return m_dataElts[RuntimeData::Address];
223  }
224  
225  llvm::Value* RuntimeManager::getSender()
226  {
227  	return m_dataElts[RuntimeData::Sender];
228  }
229  
230  llvm::Value* RuntimeManager::getValue()
231  {
232  	return m_dataElts[RuntimeData::Value];
233  }
234  
235  llvm::Value* RuntimeManager::getDepth()
236  {
237  	return m_dataElts[RuntimeData::Depth];
238  }
239  
240  void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value)
241  {
242  	auto ptr = getPtr(_index);
243  	assert(ptr->getType() == _value->getType()->getPointerTo());
244  	m_builder.CreateStore(_value, ptr);
245  }
246  
247  void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size)
248  {
249  	auto memPtr = m_builder.CreateBitCast(getMem(), Type::BytePtr->getPointerTo());
250  	auto mem = m_builder.CreateLoad(memPtr, "memory");
251  	auto returnDataPtr = m_builder.CreateGEP(mem, _offset);
252  	set(RuntimeData::ReturnData, returnDataPtr);
253  
254  	auto size64 = m_builder.CreateTrunc(_size, Type::Size);
255  	set(RuntimeData::ReturnDataSize, size64);
256  }
257  
258  void RuntimeManager::exit(ReturnCode _returnCode)
259  {
260  	m_builder.CreateBr(m_exitBB);
261  	auto retPhi = llvm::cast<llvm::PHINode>(&m_exitBB->front());
262  	retPhi->addIncoming(Constant::get(_returnCode), m_builder.GetInsertBlock());
263  }
264  
265  void RuntimeManager::abort(llvm::Value* _jmpBuf)
266  {
267  	auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);
268  	m_builder.CreateCall(longjmp, {_jmpBuf});
269  }
270  
271  void RuntimeManager::resetReturnBuf()
272  {
273  	m_builder.CreateStore(m_builder.getInt64(0), m_returnBufSizePtr);
274  }
275  
276  llvm::Value* RuntimeManager::getCallData()
277  {
278  	return m_dataElts[RuntimeData::CallData];
279  }
280  
281  llvm::Value* RuntimeManager::getCode()
282  {
283  	// OPT Check what is faster
284  	//return get(RuntimeData::Code);
285  	if (!m_codePtr)
286  		m_codePtr = m_builder.CreateGlobalStringPtr({reinterpret_cast<char const*>(m_codeBegin), static_cast<size_t>(m_codeEnd - m_codeBegin)}, "code");
287  	return m_codePtr;
288  }
289  
290  llvm::Value* RuntimeManager::getCodeSize()
291  {
292  	return Constant::get(m_codeEnd - m_codeBegin);
293  }
294  
295  llvm::Value* RuntimeManager::getCallDataSize()
296  {
297  	auto value = m_dataElts[RuntimeData::CallDataSize];
298  	assert(value->getType() == Type::Size);
299  	return m_builder.CreateZExt(value, Type::Word);
300  }
301  
302  llvm::Value* RuntimeManager::getGas()
303  {
304  	return m_builder.CreateLoad(getGasPtr(), "gas");
305  }
306  
307  llvm::Value* RuntimeManager::getGasPtr()
308  {
309  	assert(getMainFunction());
310  	return m_gasPtr;
311  }
312  
313  llvm::Value* RuntimeManager::getMem()
314  {
315  	assert(getMainFunction());
316  	return m_memPtr;
317  }
318  
319  void RuntimeManager::setGas(llvm::Value* _gas)
320  {
321  	assert(_gas->getType() == Type::Gas);
322  	m_builder.CreateStore(_gas, getGasPtr());
323  }
324  
325  }
326  }
327  }