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 "clang/AST/DeclCXX.h" 14 15 using namespace clang; 16 using namespace clang::interp; 17 18 EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent, 19 InterpStack &Stk) 20 : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) { 21 // Create a dummy frame for the interpreter which does not have locals. 22 S.Current = 23 new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr(), 0); 24 } 25 26 EvalEmitter::~EvalEmitter() { 27 for (auto &[K, V] : Locals) { 28 Block *B = reinterpret_cast<Block *>(V.get()); 29 if (B->isInitialized()) 30 B->invokeDtor(); 31 } 32 } 33 34 /// Clean up all our resources. This needs to done in failed evaluations before 35 /// we call InterpStack::clear(), because there might be a Pointer on the stack 36 /// pointing into a Block in the EvalEmitter. 37 void EvalEmitter::cleanup() { S.cleanup(); } 38 39 EvaluationResult EvalEmitter::interpretExpr(const Expr *E, 40 bool ConvertResultToRValue, 41 bool DestroyToplevelScope) { 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, DestroyToplevelScope)) { 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) { CurrentLabel = Label; } 80 81 EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } 82 83 Scope::Local EvalEmitter::createLocal(Descriptor *D) { 84 // Allocate memory for a local. 85 auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize()); 86 auto *B = new (Memory.get()) Block(Ctx.getEvalID(), D, /*isStatic=*/false); 87 B->invokeCtor(); 88 89 // Initialize local variable inline descriptor. 90 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData()); 91 Desc.Desc = D; 92 Desc.Offset = sizeof(InlineDescriptor); 93 Desc.IsActive = true; 94 Desc.IsBase = false; 95 Desc.IsFieldMutable = false; 96 Desc.IsConst = false; 97 Desc.IsInitialized = false; 98 99 // Register the local. 100 unsigned Off = Locals.size(); 101 Locals.insert({Off, std::move(Memory)}); 102 return {Off, D}; 103 } 104 105 bool EvalEmitter::jumpTrue(const LabelTy &Label) { 106 if (isActive()) { 107 if (S.Stk.pop<bool>()) 108 ActiveLabel = Label; 109 } 110 return true; 111 } 112 113 bool EvalEmitter::jumpFalse(const LabelTy &Label) { 114 if (isActive()) { 115 if (!S.Stk.pop<bool>()) 116 ActiveLabel = Label; 117 } 118 return true; 119 } 120 121 bool EvalEmitter::jump(const LabelTy &Label) { 122 if (isActive()) 123 CurrentLabel = ActiveLabel = Label; 124 return true; 125 } 126 127 bool EvalEmitter::fallthrough(const LabelTy &Label) { 128 if (isActive()) 129 ActiveLabel = Label; 130 CurrentLabel = Label; 131 return true; 132 } 133 134 template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) { 135 if (!isActive()) 136 return true; 137 138 using T = typename PrimConv<OpType>::T; 139 EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext())); 140 return true; 141 } 142 143 template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) { 144 if (!isActive()) 145 return true; 146 147 const Pointer &Ptr = S.Stk.pop<Pointer>(); 148 149 if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info)) 150 return false; 151 if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr)) 152 return false; 153 154 // Implicitly convert lvalue to rvalue, if requested. 155 if (ConvertResultToRValue) { 156 if (!Ptr.isZero() && !Ptr.isDereferencable()) 157 return false; 158 159 if (S.getLangOpts().CPlusPlus11 && Ptr.isBlockPointer() && 160 !CheckFinalLoad(S, OpPC, Ptr)) { 161 return false; 162 } 163 164 // Never allow reading from a non-const pointer, unless the memory 165 // has been created in this evaluation. 166 if (!Ptr.isZero() && !Ptr.isConst() && Ptr.isBlockPointer() && 167 Ptr.block()->getEvalID() != Ctx.getEvalID()) 168 return false; 169 170 if (std::optional<APValue> V = 171 Ptr.toRValue(Ctx, EvalResult.getSourceType())) { 172 EvalResult.setValue(*V); 173 } else { 174 return false; 175 } 176 } else { 177 EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext())); 178 } 179 180 return true; 181 } 182 template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) { 183 if (!isActive()) 184 return true; 185 186 // Function pointers cannot be converted to rvalues. 187 EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>()); 188 return true; 189 } 190 191 bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { 192 EvalResult.setValid(); 193 return true; 194 } 195 196 bool EvalEmitter::emitRetValue(const SourceInfo &Info) { 197 const auto &Ptr = S.Stk.pop<Pointer>(); 198 199 if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info)) 200 return false; 201 if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr)) 202 return false; 203 204 if (std::optional<APValue> APV = 205 Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) { 206 EvalResult.setValue(*APV); 207 return true; 208 } 209 210 EvalResult.setInvalid(); 211 return false; 212 } 213 214 bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) { 215 if (!isActive()) 216 return true; 217 218 Block *B = getLocal(I); 219 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor)); 220 return true; 221 } 222 223 template <PrimType OpType> 224 bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) { 225 if (!isActive()) 226 return true; 227 228 using T = typename PrimConv<OpType>::T; 229 230 Block *B = getLocal(I); 231 S.Stk.push<T>(*reinterpret_cast<T *>(B->data())); 232 return true; 233 } 234 235 template <PrimType OpType> 236 bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) { 237 if (!isActive()) 238 return true; 239 240 using T = typename PrimConv<OpType>::T; 241 242 Block *B = getLocal(I); 243 *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>(); 244 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData()); 245 Desc.IsInitialized = true; 246 247 return true; 248 } 249 250 bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) { 251 if (!isActive()) 252 return true; 253 254 for (auto &Local : Descriptors[I]) { 255 Block *B = getLocal(Local.Offset); 256 S.deallocate(B); 257 } 258 259 return true; 260 } 261 262 /// Global temporaries (LifetimeExtendedTemporary) carry their value 263 /// around as an APValue, which codegen accesses. 264 /// We set their value once when creating them, but we don't update it 265 /// afterwards when code changes it later. 266 /// This is what we do here. 267 void EvalEmitter::updateGlobalTemporaries() { 268 for (const auto &[E, Temp] : S.SeenGlobalTemporaries) { 269 if (std::optional<unsigned> GlobalIndex = P.getGlobal(E)) { 270 const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex); 271 APValue *Cached = Temp->getOrCreateValue(true); 272 273 if (std::optional<PrimType> T = Ctx.classify(E->getType())) { 274 TYPE_SWITCH( 275 *T, { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); }); 276 } else { 277 if (std::optional<APValue> APV = 278 Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType())) 279 *Cached = *APV; 280 } 281 } 282 } 283 S.SeenGlobalTemporaries.clear(); 284 } 285 286 //===----------------------------------------------------------------------===// 287 // Opcode evaluators 288 //===----------------------------------------------------------------------===// 289 290 #define GET_EVAL_IMPL 291 #include "Opcodes.inc" 292 #undef GET_EVAL_IMPL 293