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 }