1 //===--- EvalEmitter.cpp - Instruction emitter for the VM -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "EvalEmitter.h" 10 #include "Context.h" 11 #include "IntegralAP.h" 12 #include "Interp.h" 13 #include "Opcode.h" 14 #include "clang/AST/DeclCXX.h" 15 16 using namespace clang; 17 using namespace clang::interp; 18 19 EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent, 20 InterpStack &Stk) 21 : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) { 22 // Create a dummy frame for the interpreter which does not have locals. 23 S.Current = 24 new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr(), 0); 25 } 26 27 EvalEmitter::~EvalEmitter() { 28 for (auto &[K, V] : Locals) { 29 Block *B = reinterpret_cast<Block *>(V.get()); 30 if (B->isInitialized()) 31 B->invokeDtor(); 32 } 33 } 34 35 /// Clean up all our resources. This needs to done in failed evaluations before 36 /// we call InterpStack::clear(), because there might be a Pointer on the stack 37 /// pointing into a Block in the EvalEmitter. 38 void EvalEmitter::cleanup() { S.cleanup(); } 39 40 EvaluationResult EvalEmitter::interpretExpr(const Expr *E, 41 bool ConvertResultToRValue) { 42 S.setEvalLocation(E->getExprLoc()); 43 this->ConvertResultToRValue = ConvertResultToRValue && !isa<ConstantExpr>(E); 44 this->CheckFullyInitialized = isa<ConstantExpr>(E); 45 EvalResult.setSource(E); 46 47 if (!this->visitExpr(E)) { 48 // EvalResult may already have a result set, but something failed 49 // after that (e.g. evaluating destructors). 50 EvalResult.setInvalid(); 51 } 52 53 return std::move(this->EvalResult); 54 } 55 56 EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, 57 bool CheckFullyInitialized) { 58 this->CheckFullyInitialized = CheckFullyInitialized; 59 S.EvaluatingDecl = VD; 60 EvalResult.setSource(VD); 61 62 if (const Expr *Init = VD->getAnyInitializer()) { 63 QualType T = VD->getType(); 64 this->ConvertResultToRValue = !Init->isGLValue() && !T->isPointerType() && 65 !T->isObjCObjectPointerType(); 66 } else 67 this->ConvertResultToRValue = false; 68 69 EvalResult.setSource(VD); 70 71 if (!this->visitDeclAndReturn(VD, S.inConstantContext())) 72 EvalResult.setInvalid(); 73 74 S.EvaluatingDecl = nullptr; 75 updateGlobalTemporaries(); 76 return std::move(this->EvalResult); 77 } 78 79 void EvalEmitter::emitLabel(LabelTy Label) { 80 CurrentLabel = Label; 81 } 82 83 EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } 84 85 Scope::Local EvalEmitter::createLocal(Descriptor *D) { 86 // Allocate memory for a local. 87 auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize()); 88 auto *B = new (Memory.get()) Block(Ctx.getEvalID(), D, /*isStatic=*/false); 89 B->invokeCtor(); 90 91 // Initialize local variable inline descriptor. 92 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData()); 93 Desc.Desc = D; 94 Desc.Offset = sizeof(InlineDescriptor); 95 Desc.IsActive = true; 96 Desc.IsBase = false; 97 Desc.IsFieldMutable = false; 98 Desc.IsConst = false; 99 Desc.IsInitialized = false; 100 101 // Register the local. 102 unsigned Off = Locals.size(); 103 Locals.insert({Off, std::move(Memory)}); 104 return {Off, D}; 105 } 106 107 bool EvalEmitter::jumpTrue(const LabelTy &Label) { 108 if (isActive()) { 109 if (S.Stk.pop<bool>()) 110 ActiveLabel = Label; 111 } 112 return true; 113 } 114 115 bool EvalEmitter::jumpFalse(const LabelTy &Label) { 116 if (isActive()) { 117 if (!S.Stk.pop<bool>()) 118 ActiveLabel = Label; 119 } 120 return true; 121 } 122 123 bool EvalEmitter::jump(const LabelTy &Label) { 124 if (isActive()) 125 CurrentLabel = ActiveLabel = Label; 126 return true; 127 } 128 129 bool EvalEmitter::fallthrough(const LabelTy &Label) { 130 if (isActive()) 131 ActiveLabel = Label; 132 CurrentLabel = Label; 133 return true; 134 } 135 136 static bool checkReturnState(InterpState &S) { 137 return S.maybeDiagnoseDanglingAllocations(); 138 } 139 140 template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) { 141 if (!isActive()) 142 return true; 143 144 if (!checkReturnState(S)) 145 return false; 146 147 using T = typename PrimConv<OpType>::T; 148 EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext())); 149 return true; 150 } 151 152 template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) { 153 if (!isActive()) 154 return true; 155 156 const Pointer &Ptr = S.Stk.pop<Pointer>(); 157 158 if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info)) 159 return false; 160 if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr)) 161 return false; 162 163 if (!checkReturnState(S)) 164 return false; 165 166 // Implicitly convert lvalue to rvalue, if requested. 167 if (ConvertResultToRValue) { 168 if (!Ptr.isZero() && !Ptr.isDereferencable()) 169 return false; 170 // Never allow reading from a non-const pointer, unless the memory 171 // has been created in this evaluation. 172 if (!Ptr.isZero() && Ptr.isBlockPointer() && 173 Ptr.block()->getEvalID() != Ctx.getEvalID() && 174 (!CheckLoad(S, OpPC, Ptr, AK_Read) || !Ptr.isConst())) 175 return false; 176 177 if (std::optional<APValue> V = 178 Ptr.toRValue(Ctx, EvalResult.getSourceType())) { 179 EvalResult.setValue(*V); 180 } else { 181 return false; 182 } 183 } else { 184 EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext())); 185 } 186 187 return true; 188 } 189 template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) { 190 if (!isActive()) 191 return true; 192 193 if (!checkReturnState(S)) 194 return false; 195 // Function pointers cannot be converted to rvalues. 196 EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>()); 197 return true; 198 } 199 200 bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { 201 if (!checkReturnState(S)) 202 return false; 203 EvalResult.setValid(); 204 return true; 205 } 206 207 bool EvalEmitter::emitRetValue(const SourceInfo &Info) { 208 const auto &Ptr = S.Stk.pop<Pointer>(); 209 210 if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info)) 211 return false; 212 if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr)) 213 return false; 214 215 if (!checkReturnState(S)) 216 return false; 217 218 if (std::optional<APValue> APV = 219 Ptr.toRValue(S.getCtx(), EvalResult.getSourceType())) { 220 EvalResult.setValue(*APV); 221 return true; 222 } 223 224 EvalResult.setInvalid(); 225 return false; 226 } 227 228 bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) { 229 if (!isActive()) 230 return true; 231 232 Block *B = getLocal(I); 233 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor)); 234 return true; 235 } 236 237 template <PrimType OpType> 238 bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) { 239 if (!isActive()) 240 return true; 241 242 using T = typename PrimConv<OpType>::T; 243 244 Block *B = getLocal(I); 245 S.Stk.push<T>(*reinterpret_cast<T *>(B->data())); 246 return true; 247 } 248 249 template <PrimType OpType> 250 bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) { 251 if (!isActive()) 252 return true; 253 254 using T = typename PrimConv<OpType>::T; 255 256 Block *B = getLocal(I); 257 *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>(); 258 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData()); 259 Desc.IsInitialized = true; 260 261 return true; 262 } 263 264 bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) { 265 if (!isActive()) 266 return true; 267 268 for (auto &Local : Descriptors[I]) { 269 Block *B = getLocal(Local.Offset); 270 S.deallocate(B); 271 } 272 273 return true; 274 } 275 276 /// Global temporaries (LifetimeExtendedTemporary) carry their value 277 /// around as an APValue, which codegen accesses. 278 /// We set their value once when creating them, but we don't update it 279 /// afterwards when code changes it later. 280 /// This is what we do here. 281 void EvalEmitter::updateGlobalTemporaries() { 282 for (const auto &[E, Temp] : S.SeenGlobalTemporaries) { 283 if (std::optional<unsigned> GlobalIndex = P.getGlobal(E)) { 284 const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex); 285 APValue *Cached = Temp->getOrCreateValue(true); 286 287 if (std::optional<PrimType> T = Ctx.classify(E->getType())) { 288 TYPE_SWITCH( 289 *T, { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); }); 290 } else { 291 if (std::optional<APValue> APV = 292 Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType())) 293 *Cached = *APV; 294 } 295 } 296 } 297 S.SeenGlobalTemporaries.clear(); 298 } 299 300 //===----------------------------------------------------------------------===// 301 // Opcode evaluators 302 //===----------------------------------------------------------------------===// 303 304 #define GET_EVAL_IMPL 305 #include "Opcodes.inc" 306 #undef GET_EVAL_IMPL 307