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 "ByteCodeGenError.h" 11 #include "Context.h" 12 #include "IntegralAP.h" 13 #include "Interp.h" 14 #include "Opcode.h" 15 #include "clang/AST/DeclCXX.h" 16 17 using namespace clang; 18 using namespace clang::interp; 19 20 EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent, 21 InterpStack &Stk, APValue &Result) 22 : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) { 23 // Create a dummy frame for the interpreter which does not have locals. 24 S.Current = 25 new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr()); 26 } 27 28 EvalEmitter::~EvalEmitter() { 29 for (auto &[K, V] : Locals) { 30 Block *B = reinterpret_cast<Block *>(V.get()); 31 if (B->isInitialized()) 32 B->invokeDtor(); 33 } 34 } 35 36 EvaluationResult EvalEmitter::interpretExpr(const Expr *E) { 37 EvalResult.setSource(E); 38 39 if (!this->visitExpr(E)) 40 EvalResult.setInvalid(); 41 42 return std::move(this->EvalResult); 43 } 44 45 EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD) { 46 EvalResult.setSource(VD); 47 48 if (!this->visitDecl(VD)) 49 EvalResult.setInvalid(); 50 51 return std::move(this->EvalResult); 52 } 53 54 void EvalEmitter::emitLabel(LabelTy Label) { 55 CurrentLabel = Label; 56 } 57 58 EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } 59 60 Scope::Local EvalEmitter::createLocal(Descriptor *D) { 61 // Allocate memory for a local. 62 auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize()); 63 auto *B = new (Memory.get()) Block(D, /*isStatic=*/false); 64 B->invokeCtor(); 65 66 // Initialize local variable inline descriptor. 67 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData()); 68 Desc.Desc = D; 69 Desc.Offset = sizeof(InlineDescriptor); 70 Desc.IsActive = true; 71 Desc.IsBase = false; 72 Desc.IsFieldMutable = false; 73 Desc.IsConst = false; 74 Desc.IsInitialized = false; 75 76 // Register the local. 77 unsigned Off = Locals.size(); 78 Locals.insert({Off, std::move(Memory)}); 79 return {Off, D}; 80 } 81 82 bool EvalEmitter::jumpTrue(const LabelTy &Label) { 83 if (isActive()) { 84 if (S.Stk.pop<bool>()) 85 ActiveLabel = Label; 86 } 87 return true; 88 } 89 90 bool EvalEmitter::jumpFalse(const LabelTy &Label) { 91 if (isActive()) { 92 if (!S.Stk.pop<bool>()) 93 ActiveLabel = Label; 94 } 95 return true; 96 } 97 98 bool EvalEmitter::jump(const LabelTy &Label) { 99 if (isActive()) 100 CurrentLabel = ActiveLabel = Label; 101 return true; 102 } 103 104 bool EvalEmitter::fallthrough(const LabelTy &Label) { 105 if (isActive()) 106 ActiveLabel = Label; 107 CurrentLabel = Label; 108 return true; 109 } 110 111 template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) { 112 if (!isActive()) 113 return true; 114 using T = typename PrimConv<OpType>::T; 115 EvalResult.setValue(S.Stk.pop<T>().toAPValue()); 116 return true; 117 } 118 119 template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) { 120 if (!isActive()) 121 return true; 122 EvalResult.setPointer(S.Stk.pop<Pointer>()); 123 return true; 124 } 125 template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) { 126 if (!isActive()) 127 return true; 128 EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>()); 129 return true; 130 } 131 132 bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { 133 EvalResult.setValid(); 134 return true; 135 } 136 137 bool EvalEmitter::emitRetValue(const SourceInfo &Info) { 138 const auto &Ptr = S.Stk.pop<Pointer>(); 139 if (std::optional<APValue> APV = Ptr.toRValue(S.getCtx())) { 140 EvalResult.setValue(*APV); 141 return true; 142 } 143 144 EvalResult.setInvalid(); 145 return false; 146 } 147 148 bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) { 149 if (!isActive()) 150 return true; 151 152 Block *B = getLocal(I); 153 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor)); 154 return true; 155 } 156 157 template <PrimType OpType> 158 bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) { 159 if (!isActive()) 160 return true; 161 162 using T = typename PrimConv<OpType>::T; 163 164 Block *B = getLocal(I); 165 S.Stk.push<T>(*reinterpret_cast<T *>(B->data())); 166 return true; 167 } 168 169 template <PrimType OpType> 170 bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) { 171 if (!isActive()) 172 return true; 173 174 using T = typename PrimConv<OpType>::T; 175 176 Block *B = getLocal(I); 177 *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>(); 178 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData()); 179 Desc.IsInitialized = true; 180 181 return true; 182 } 183 184 bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) { 185 if (!isActive()) 186 return true; 187 188 for (auto &Local : Descriptors[I]) { 189 Block *B = getLocal(Local.Offset); 190 S.deallocate(B); 191 } 192 193 return true; 194 } 195 196 //===----------------------------------------------------------------------===// 197 // Opcode evaluators 198 //===----------------------------------------------------------------------===// 199 200 #define GET_EVAL_IMPL 201 #include "Opcodes.inc" 202 #undef GET_EVAL_IMPL 203