//===--- EvalEmitter.cpp - Instruction emitter for the VM -------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "EvalEmitter.h" #include "ByteCodeGenError.h" #include "Context.h" #include "IntegralAP.h" #include "Interp.h" #include "Opcode.h" #include "clang/AST/DeclCXX.h" using namespace clang; using namespace clang::interp; EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk, APValue &Result) : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) { // Create a dummy frame for the interpreter which does not have locals. S.Current = new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr()); } EvalEmitter::~EvalEmitter() { for (auto &[K, V] : Locals) { Block *B = reinterpret_cast(V.get()); if (B->isInitialized()) B->invokeDtor(); } } EvaluationResult EvalEmitter::interpretExpr(const Expr *E) { EvalResult.setSource(E); if (!this->visitExpr(E)) EvalResult.setInvalid(); return std::move(this->EvalResult); } EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD) { EvalResult.setSource(VD); if (!this->visitDecl(VD)) EvalResult.setInvalid(); return std::move(this->EvalResult); } void EvalEmitter::emitLabel(LabelTy Label) { CurrentLabel = Label; } EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } Scope::Local EvalEmitter::createLocal(Descriptor *D) { // Allocate memory for a local. auto Memory = std::make_unique(sizeof(Block) + D->getAllocSize()); auto *B = new (Memory.get()) Block(D, /*isStatic=*/false); B->invokeCtor(); // Initialize local variable inline descriptor. InlineDescriptor &Desc = *reinterpret_cast(B->rawData()); Desc.Desc = D; Desc.Offset = sizeof(InlineDescriptor); Desc.IsActive = true; Desc.IsBase = false; Desc.IsFieldMutable = false; Desc.IsConst = false; Desc.IsInitialized = false; // Register the local. unsigned Off = Locals.size(); Locals.insert({Off, std::move(Memory)}); return {Off, D}; } bool EvalEmitter::jumpTrue(const LabelTy &Label) { if (isActive()) { if (S.Stk.pop()) ActiveLabel = Label; } return true; } bool EvalEmitter::jumpFalse(const LabelTy &Label) { if (isActive()) { if (!S.Stk.pop()) ActiveLabel = Label; } return true; } bool EvalEmitter::jump(const LabelTy &Label) { if (isActive()) CurrentLabel = ActiveLabel = Label; return true; } bool EvalEmitter::fallthrough(const LabelTy &Label) { if (isActive()) ActiveLabel = Label; CurrentLabel = Label; return true; } template bool EvalEmitter::emitRet(const SourceInfo &Info) { if (!isActive()) return true; using T = typename PrimConv::T; EvalResult.setValue(S.Stk.pop().toAPValue()); return true; } template <> bool EvalEmitter::emitRet(const SourceInfo &Info) { if (!isActive()) return true; EvalResult.setPointer(S.Stk.pop()); return true; } template <> bool EvalEmitter::emitRet(const SourceInfo &Info) { if (!isActive()) return true; EvalResult.setFunctionPointer(S.Stk.pop()); return true; } bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { EvalResult.setValid(); return true; } bool EvalEmitter::emitRetValue(const SourceInfo &Info) { const auto &Ptr = S.Stk.pop(); if (std::optional APV = Ptr.toRValue(S.getCtx())) { EvalResult.setValue(*APV); return true; } EvalResult.setInvalid(); return false; } bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) { if (!isActive()) return true; Block *B = getLocal(I); S.Stk.push(B, sizeof(InlineDescriptor)); return true; } template bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) { if (!isActive()) return true; using T = typename PrimConv::T; Block *B = getLocal(I); S.Stk.push(*reinterpret_cast(B->data())); return true; } template bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) { if (!isActive()) return true; using T = typename PrimConv::T; Block *B = getLocal(I); *reinterpret_cast(B->data()) = S.Stk.pop(); InlineDescriptor &Desc = *reinterpret_cast(B->rawData()); Desc.IsInitialized = true; return true; } bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) { if (!isActive()) return true; for (auto &Local : Descriptors[I]) { Block *B = getLocal(Local.Offset); S.deallocate(B); } return true; } //===----------------------------------------------------------------------===// // Opcode evaluators //===----------------------------------------------------------------------===// #define GET_EVAL_IMPL #include "Opcodes.inc" #undef GET_EVAL_IMPL