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