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