1a07aba5dSTimm Baeder //===--- ByteCodeEmitter.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 "ByteCodeEmitter.h" 10a07aba5dSTimm Baeder #include "Context.h" 11a07aba5dSTimm Baeder #include "Floating.h" 12a07aba5dSTimm Baeder #include "IntegralAP.h" 13a07aba5dSTimm Baeder #include "Opcode.h" 14a07aba5dSTimm Baeder #include "Program.h" 15a07aba5dSTimm Baeder #include "clang/AST/ASTLambda.h" 16a07aba5dSTimm Baeder #include "clang/AST/Attr.h" 17a07aba5dSTimm Baeder #include "clang/AST/DeclCXX.h" 18a07aba5dSTimm Baeder #include <type_traits> 19a07aba5dSTimm Baeder 20a07aba5dSTimm Baeder using namespace clang; 21a07aba5dSTimm Baeder using namespace clang::interp; 22a07aba5dSTimm Baeder 23a07aba5dSTimm Baeder Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { 24a07aba5dSTimm Baeder 25a07aba5dSTimm Baeder // Manually created functions that haven't been assigned proper 26a07aba5dSTimm Baeder // parameters yet. 27a07aba5dSTimm Baeder if (!FuncDecl->param_empty() && !FuncDecl->param_begin()) 28a07aba5dSTimm Baeder return nullptr; 29a07aba5dSTimm Baeder 30a07aba5dSTimm Baeder bool IsLambdaStaticInvoker = false; 31a07aba5dSTimm Baeder if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl); 32a07aba5dSTimm Baeder MD && MD->isLambdaStaticInvoker()) { 33a07aba5dSTimm Baeder // For a lambda static invoker, we might have to pick a specialized 34a07aba5dSTimm Baeder // version if the lambda is generic. In that case, the picked function 35a07aba5dSTimm Baeder // will *NOT* be a static invoker anymore. However, it will still 36a07aba5dSTimm Baeder // be a non-static member function, this (usually) requiring an 37a07aba5dSTimm Baeder // instance pointer. We suppress that later in this function. 38a07aba5dSTimm Baeder IsLambdaStaticInvoker = true; 39a07aba5dSTimm Baeder 40a07aba5dSTimm Baeder const CXXRecordDecl *ClosureClass = MD->getParent(); 41a07aba5dSTimm Baeder assert(ClosureClass->captures_begin() == ClosureClass->captures_end()); 42a07aba5dSTimm Baeder if (ClosureClass->isGenericLambda()) { 43a07aba5dSTimm Baeder const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator(); 44a07aba5dSTimm Baeder assert(MD->isFunctionTemplateSpecialization() && 45a07aba5dSTimm Baeder "A generic lambda's static-invoker function must be a " 46a07aba5dSTimm Baeder "template specialization"); 47a07aba5dSTimm Baeder const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs(); 48a07aba5dSTimm Baeder FunctionTemplateDecl *CallOpTemplate = 49a07aba5dSTimm Baeder LambdaCallOp->getDescribedFunctionTemplate(); 50a07aba5dSTimm Baeder void *InsertPos = nullptr; 51a07aba5dSTimm Baeder const FunctionDecl *CorrespondingCallOpSpecialization = 52a07aba5dSTimm Baeder CallOpTemplate->findSpecialization(TAL->asArray(), InsertPos); 53a07aba5dSTimm Baeder assert(CorrespondingCallOpSpecialization); 54a07aba5dSTimm Baeder FuncDecl = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization); 55a07aba5dSTimm Baeder } 56a07aba5dSTimm Baeder } 57a07aba5dSTimm Baeder 58a07aba5dSTimm Baeder // Set up argument indices. 59a07aba5dSTimm Baeder unsigned ParamOffset = 0; 60a07aba5dSTimm Baeder SmallVector<PrimType, 8> ParamTypes; 61a07aba5dSTimm Baeder SmallVector<unsigned, 8> ParamOffsets; 62a07aba5dSTimm Baeder llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors; 63a07aba5dSTimm Baeder 64a07aba5dSTimm Baeder // If the return is not a primitive, a pointer to the storage where the 65a07aba5dSTimm Baeder // value is initialized in is passed as the first argument. See 'RVO' 66a07aba5dSTimm Baeder // elsewhere in the code. 67a07aba5dSTimm Baeder QualType Ty = FuncDecl->getReturnType(); 68a07aba5dSTimm Baeder bool HasRVO = false; 69a07aba5dSTimm Baeder if (!Ty->isVoidType() && !Ctx.classify(Ty)) { 70a07aba5dSTimm Baeder HasRVO = true; 71a07aba5dSTimm Baeder ParamTypes.push_back(PT_Ptr); 72a07aba5dSTimm Baeder ParamOffsets.push_back(ParamOffset); 73a07aba5dSTimm Baeder ParamOffset += align(primSize(PT_Ptr)); 74a07aba5dSTimm Baeder } 75a07aba5dSTimm Baeder 76a07aba5dSTimm Baeder // If the function decl is a member decl, the next parameter is 77a07aba5dSTimm Baeder // the 'this' pointer. This parameter is pop()ed from the 78a07aba5dSTimm Baeder // InterpStack when calling the function. 79a07aba5dSTimm Baeder bool HasThisPointer = false; 80a07aba5dSTimm Baeder if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) { 81a07aba5dSTimm Baeder if (!IsLambdaStaticInvoker) { 82a07aba5dSTimm Baeder HasThisPointer = MD->isInstance(); 83a07aba5dSTimm Baeder if (MD->isImplicitObjectMemberFunction()) { 84a07aba5dSTimm Baeder ParamTypes.push_back(PT_Ptr); 85a07aba5dSTimm Baeder ParamOffsets.push_back(ParamOffset); 86a07aba5dSTimm Baeder ParamOffset += align(primSize(PT_Ptr)); 87a07aba5dSTimm Baeder } 88a07aba5dSTimm Baeder } 89a07aba5dSTimm Baeder 90a07aba5dSTimm Baeder // Set up lambda capture to closure record field mapping. 91a07aba5dSTimm Baeder if (isLambdaCallOperator(MD)) { 92a07aba5dSTimm Baeder // The parent record needs to be complete, we need to know about all 93a07aba5dSTimm Baeder // the lambda captures. 94a07aba5dSTimm Baeder if (!MD->getParent()->isCompleteDefinition()) 95a07aba5dSTimm Baeder return nullptr; 96a07aba5dSTimm Baeder 97a07aba5dSTimm Baeder const Record *R = P.getOrCreateRecord(MD->getParent()); 98a07aba5dSTimm Baeder llvm::DenseMap<const ValueDecl *, FieldDecl *> LC; 99a07aba5dSTimm Baeder FieldDecl *LTC; 100a07aba5dSTimm Baeder 101a07aba5dSTimm Baeder MD->getParent()->getCaptureFields(LC, LTC); 102a07aba5dSTimm Baeder 103a07aba5dSTimm Baeder for (auto Cap : LC) { 104a07aba5dSTimm Baeder // Static lambdas cannot have any captures. If this one does, 105a07aba5dSTimm Baeder // it has already been diagnosed and we can only ignore it. 106a07aba5dSTimm Baeder if (MD->isStatic()) 107a07aba5dSTimm Baeder return nullptr; 108a07aba5dSTimm Baeder 109a07aba5dSTimm Baeder unsigned Offset = R->getField(Cap.second)->Offset; 110a07aba5dSTimm Baeder this->LambdaCaptures[Cap.first] = { 111a07aba5dSTimm Baeder Offset, Cap.second->getType()->isReferenceType()}; 112a07aba5dSTimm Baeder } 113a07aba5dSTimm Baeder if (LTC) { 114a07aba5dSTimm Baeder QualType CaptureType = R->getField(LTC)->Decl->getType(); 115a07aba5dSTimm Baeder this->LambdaThisCapture = {R->getField(LTC)->Offset, 116a07aba5dSTimm Baeder CaptureType->isReferenceType() || 117a07aba5dSTimm Baeder CaptureType->isPointerType()}; 118a07aba5dSTimm Baeder } 119a07aba5dSTimm Baeder } 120a07aba5dSTimm Baeder } 121a07aba5dSTimm Baeder 122a07aba5dSTimm Baeder // Assign descriptors to all parameters. 123a07aba5dSTimm Baeder // Composite objects are lowered to pointers. 124a07aba5dSTimm Baeder for (const ParmVarDecl *PD : FuncDecl->parameters()) { 125a07aba5dSTimm Baeder std::optional<PrimType> T = Ctx.classify(PD->getType()); 126a07aba5dSTimm Baeder PrimType PT = T.value_or(PT_Ptr); 127a07aba5dSTimm Baeder Descriptor *Desc = P.createDescriptor(PD, PT); 128a07aba5dSTimm Baeder ParamDescriptors.insert({ParamOffset, {PT, Desc}}); 129a07aba5dSTimm Baeder Params.insert({PD, {ParamOffset, T != std::nullopt}}); 130a07aba5dSTimm Baeder ParamOffsets.push_back(ParamOffset); 131a07aba5dSTimm Baeder ParamOffset += align(primSize(PT)); 132a07aba5dSTimm Baeder ParamTypes.push_back(PT); 133a07aba5dSTimm Baeder } 134a07aba5dSTimm Baeder 135a07aba5dSTimm Baeder // Create a handle over the emitted code. 136a07aba5dSTimm Baeder Function *Func = P.getFunction(FuncDecl); 137a07aba5dSTimm Baeder if (!Func) { 1383745a2e8STimm Baeder unsigned BuiltinID = FuncDecl->getBuiltinID(); 139a07aba5dSTimm Baeder Func = 140a07aba5dSTimm Baeder P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes), 141a07aba5dSTimm Baeder std::move(ParamDescriptors), std::move(ParamOffsets), 1423745a2e8STimm Baeder HasThisPointer, HasRVO, BuiltinID); 143a07aba5dSTimm Baeder } 144a07aba5dSTimm Baeder 145a07aba5dSTimm Baeder assert(Func); 146a07aba5dSTimm Baeder // For not-yet-defined functions, we only create a Function instance and 147a07aba5dSTimm Baeder // compile their body later. 148a07aba5dSTimm Baeder if (!FuncDecl->isDefined() || 149a07aba5dSTimm Baeder (FuncDecl->willHaveBody() && !FuncDecl->hasBody())) { 150a07aba5dSTimm Baeder Func->setDefined(false); 151a07aba5dSTimm Baeder return Func; 152a07aba5dSTimm Baeder } 153a07aba5dSTimm Baeder 154a07aba5dSTimm Baeder Func->setDefined(true); 155a07aba5dSTimm Baeder 156a07aba5dSTimm Baeder // Lambda static invokers are a special case that we emit custom code for. 157a07aba5dSTimm Baeder bool IsEligibleForCompilation = false; 158a07aba5dSTimm Baeder if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) 159a07aba5dSTimm Baeder IsEligibleForCompilation = MD->isLambdaStaticInvoker(); 160a07aba5dSTimm Baeder if (!IsEligibleForCompilation) 161a07aba5dSTimm Baeder IsEligibleForCompilation = 162a07aba5dSTimm Baeder FuncDecl->isConstexpr() || FuncDecl->hasAttr<MSConstexprAttr>(); 163a07aba5dSTimm Baeder 164a07aba5dSTimm Baeder // Compile the function body. 165a07aba5dSTimm Baeder if (!IsEligibleForCompilation || !visitFunc(FuncDecl)) { 166a07aba5dSTimm Baeder Func->setIsFullyCompiled(true); 167a07aba5dSTimm Baeder return Func; 168a07aba5dSTimm Baeder } 169a07aba5dSTimm Baeder 170a07aba5dSTimm Baeder // Create scopes from descriptors. 171a07aba5dSTimm Baeder llvm::SmallVector<Scope, 2> Scopes; 172a07aba5dSTimm Baeder for (auto &DS : Descriptors) { 173a07aba5dSTimm Baeder Scopes.emplace_back(std::move(DS)); 174a07aba5dSTimm Baeder } 175a07aba5dSTimm Baeder 176a07aba5dSTimm Baeder // Set the function's code. 177a07aba5dSTimm Baeder Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap), 178a07aba5dSTimm Baeder std::move(Scopes), FuncDecl->hasBody()); 179a07aba5dSTimm Baeder Func->setIsFullyCompiled(true); 180a07aba5dSTimm Baeder return Func; 181a07aba5dSTimm Baeder } 182a07aba5dSTimm Baeder 183ca148b21STimm Baeder /// Compile an ObjC block, i.e. ^(){}, that thing. 184ca148b21STimm Baeder /// 185ca148b21STimm Baeder /// FIXME: We do not support calling the block though, so we create a function 186ca148b21STimm Baeder /// here but do not compile any code for it. 187ca148b21STimm Baeder Function *ByteCodeEmitter::compileObjCBlock(const BlockExpr *BE) { 188ca148b21STimm Baeder const BlockDecl *BD = BE->getBlockDecl(); 189ca148b21STimm Baeder // Set up argument indices. 190ca148b21STimm Baeder unsigned ParamOffset = 0; 191ca148b21STimm Baeder SmallVector<PrimType, 8> ParamTypes; 192ca148b21STimm Baeder SmallVector<unsigned, 8> ParamOffsets; 193ca148b21STimm Baeder llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors; 194ca148b21STimm Baeder 195ca148b21STimm Baeder // Assign descriptors to all parameters. 196ca148b21STimm Baeder // Composite objects are lowered to pointers. 197ca148b21STimm Baeder for (const ParmVarDecl *PD : BD->parameters()) { 198ca148b21STimm Baeder std::optional<PrimType> T = Ctx.classify(PD->getType()); 199ca148b21STimm Baeder PrimType PT = T.value_or(PT_Ptr); 200ca148b21STimm Baeder Descriptor *Desc = P.createDescriptor(PD, PT); 201ca148b21STimm Baeder ParamDescriptors.insert({ParamOffset, {PT, Desc}}); 202ca148b21STimm Baeder Params.insert({PD, {ParamOffset, T != std::nullopt}}); 203ca148b21STimm Baeder ParamOffsets.push_back(ParamOffset); 204ca148b21STimm Baeder ParamOffset += align(primSize(PT)); 205ca148b21STimm Baeder ParamTypes.push_back(PT); 206ca148b21STimm Baeder } 207ca148b21STimm Baeder 208ca148b21STimm Baeder if (BD->hasCaptures()) 209ca148b21STimm Baeder return nullptr; 210ca148b21STimm Baeder 211ca148b21STimm Baeder // Create a handle over the emitted code. 212ca148b21STimm Baeder Function *Func = 213ca148b21STimm Baeder P.createFunction(BE, ParamOffset, std::move(ParamTypes), 214ca148b21STimm Baeder std::move(ParamDescriptors), std::move(ParamOffsets), 215ca148b21STimm Baeder /*HasThisPointer=*/false, /*HasRVO=*/false, 216ca148b21STimm Baeder /*IsUnevaluatedBuiltin=*/false); 217ca148b21STimm Baeder 218ca148b21STimm Baeder assert(Func); 219ca148b21STimm Baeder Func->setDefined(true); 220ca148b21STimm Baeder // We don't compile the BlockDecl code at all right now. 221ca148b21STimm Baeder Func->setIsFullyCompiled(true); 222ca148b21STimm Baeder return Func; 223ca148b21STimm Baeder } 224ca148b21STimm Baeder 225a07aba5dSTimm Baeder Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) { 226a07aba5dSTimm Baeder NextLocalOffset += sizeof(Block); 227a07aba5dSTimm Baeder unsigned Location = NextLocalOffset; 228a07aba5dSTimm Baeder NextLocalOffset += align(D->getAllocSize()); 229a07aba5dSTimm Baeder return {Location, D}; 230a07aba5dSTimm Baeder } 231a07aba5dSTimm Baeder 232a07aba5dSTimm Baeder void ByteCodeEmitter::emitLabel(LabelTy Label) { 233a07aba5dSTimm Baeder const size_t Target = Code.size(); 234a07aba5dSTimm Baeder LabelOffsets.insert({Label, Target}); 235a07aba5dSTimm Baeder 236a07aba5dSTimm Baeder if (auto It = LabelRelocs.find(Label); It != LabelRelocs.end()) { 237a07aba5dSTimm Baeder for (unsigned Reloc : It->second) { 238a07aba5dSTimm Baeder using namespace llvm::support; 239a07aba5dSTimm Baeder 240a07aba5dSTimm Baeder // Rewrite the operand of all jumps to this label. 241a07aba5dSTimm Baeder void *Location = Code.data() + Reloc - align(sizeof(int32_t)); 242a07aba5dSTimm Baeder assert(aligned(Location)); 243a07aba5dSTimm Baeder const int32_t Offset = Target - static_cast<int64_t>(Reloc); 244a07aba5dSTimm Baeder endian::write<int32_t, llvm::endianness::native>(Location, Offset); 245a07aba5dSTimm Baeder } 246a07aba5dSTimm Baeder LabelRelocs.erase(It); 247a07aba5dSTimm Baeder } 248a07aba5dSTimm Baeder } 249a07aba5dSTimm Baeder 250a07aba5dSTimm Baeder int32_t ByteCodeEmitter::getOffset(LabelTy Label) { 251a07aba5dSTimm Baeder // Compute the PC offset which the jump is relative to. 252a07aba5dSTimm Baeder const int64_t Position = 253a07aba5dSTimm Baeder Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t)); 254a07aba5dSTimm Baeder assert(aligned(Position)); 255a07aba5dSTimm Baeder 256a07aba5dSTimm Baeder // If target is known, compute jump offset. 257a07aba5dSTimm Baeder if (auto It = LabelOffsets.find(Label); It != LabelOffsets.end()) 258a07aba5dSTimm Baeder return It->second - Position; 259a07aba5dSTimm Baeder 260a07aba5dSTimm Baeder // Otherwise, record relocation and return dummy offset. 261a07aba5dSTimm Baeder LabelRelocs[Label].push_back(Position); 262a07aba5dSTimm Baeder return 0ull; 263a07aba5dSTimm Baeder } 264a07aba5dSTimm Baeder 265a07aba5dSTimm Baeder /// Helper to write bytecode and bail out if 32-bit offsets become invalid. 266a07aba5dSTimm Baeder /// Pointers will be automatically marshalled as 32-bit IDs. 267a07aba5dSTimm Baeder template <typename T> 268a07aba5dSTimm Baeder static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, 269a07aba5dSTimm Baeder bool &Success) { 270a07aba5dSTimm Baeder size_t Size; 271a07aba5dSTimm Baeder 272a07aba5dSTimm Baeder if constexpr (std::is_pointer_v<T>) 273a07aba5dSTimm Baeder Size = sizeof(uint32_t); 274a07aba5dSTimm Baeder else 275a07aba5dSTimm Baeder Size = sizeof(T); 276a07aba5dSTimm Baeder 277a07aba5dSTimm Baeder if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { 278a07aba5dSTimm Baeder Success = false; 279a07aba5dSTimm Baeder return; 280a07aba5dSTimm Baeder } 281a07aba5dSTimm Baeder 282a07aba5dSTimm Baeder // Access must be aligned! 283a07aba5dSTimm Baeder size_t ValPos = align(Code.size()); 284a07aba5dSTimm Baeder Size = align(Size); 285a07aba5dSTimm Baeder assert(aligned(ValPos + Size)); 286a07aba5dSTimm Baeder Code.resize(ValPos + Size); 287a07aba5dSTimm Baeder 288a07aba5dSTimm Baeder if constexpr (!std::is_pointer_v<T>) { 289a07aba5dSTimm Baeder new (Code.data() + ValPos) T(Val); 290a07aba5dSTimm Baeder } else { 291a07aba5dSTimm Baeder uint32_t ID = P.getOrCreateNativePointer(Val); 292a07aba5dSTimm Baeder new (Code.data() + ValPos) uint32_t(ID); 293a07aba5dSTimm Baeder } 294a07aba5dSTimm Baeder } 295a07aba5dSTimm Baeder 296a07aba5dSTimm Baeder /// Emits a serializable value. These usually (potentially) contain 297a07aba5dSTimm Baeder /// heap-allocated memory and aren't trivially copyable. 298a07aba5dSTimm Baeder template <typename T> 299a07aba5dSTimm Baeder static void emitSerialized(std::vector<std::byte> &Code, const T &Val, 300a07aba5dSTimm Baeder bool &Success) { 301a07aba5dSTimm Baeder size_t Size = Val.bytesToSerialize(); 302a07aba5dSTimm Baeder 303a07aba5dSTimm Baeder if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { 304a07aba5dSTimm Baeder Success = false; 305a07aba5dSTimm Baeder return; 306a07aba5dSTimm Baeder } 307a07aba5dSTimm Baeder 308a07aba5dSTimm Baeder // Access must be aligned! 309a07aba5dSTimm Baeder size_t ValPos = align(Code.size()); 310a07aba5dSTimm Baeder Size = align(Size); 311a07aba5dSTimm Baeder assert(aligned(ValPos + Size)); 312a07aba5dSTimm Baeder Code.resize(ValPos + Size); 313a07aba5dSTimm Baeder 314a07aba5dSTimm Baeder Val.serialize(Code.data() + ValPos); 315a07aba5dSTimm Baeder } 316a07aba5dSTimm Baeder 317a07aba5dSTimm Baeder template <> 318a07aba5dSTimm Baeder void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val, 319a07aba5dSTimm Baeder bool &Success) { 320a07aba5dSTimm Baeder emitSerialized(Code, Val, Success); 321a07aba5dSTimm Baeder } 322a07aba5dSTimm Baeder 323a07aba5dSTimm Baeder template <> 324a07aba5dSTimm Baeder void emit(Program &P, std::vector<std::byte> &Code, 325a07aba5dSTimm Baeder const IntegralAP<false> &Val, bool &Success) { 326a07aba5dSTimm Baeder emitSerialized(Code, Val, Success); 327a07aba5dSTimm Baeder } 328a07aba5dSTimm Baeder 329a07aba5dSTimm Baeder template <> 330a07aba5dSTimm Baeder void emit(Program &P, std::vector<std::byte> &Code, const IntegralAP<true> &Val, 331a07aba5dSTimm Baeder bool &Success) { 332a07aba5dSTimm Baeder emitSerialized(Code, Val, Success); 333a07aba5dSTimm Baeder } 334a07aba5dSTimm Baeder 335*b5c9cba3STimm Baeder template <> 336*b5c9cba3STimm Baeder void emit(Program &P, std::vector<std::byte> &Code, const FixedPoint &Val, 337*b5c9cba3STimm Baeder bool &Success) { 338*b5c9cba3STimm Baeder emitSerialized(Code, Val, Success); 339*b5c9cba3STimm Baeder } 340*b5c9cba3STimm Baeder 341a07aba5dSTimm Baeder template <typename... Tys> 342a07aba5dSTimm Baeder bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &...Args, 343a07aba5dSTimm Baeder const SourceInfo &SI) { 344a07aba5dSTimm Baeder bool Success = true; 345a07aba5dSTimm Baeder 346a07aba5dSTimm Baeder // The opcode is followed by arguments. The source info is 347a07aba5dSTimm Baeder // attached to the address after the opcode. 348a07aba5dSTimm Baeder emit(P, Code, Op, Success); 349a07aba5dSTimm Baeder if (SI) 350a07aba5dSTimm Baeder SrcMap.emplace_back(Code.size(), SI); 351a07aba5dSTimm Baeder 352a07aba5dSTimm Baeder (..., emit(P, Code, Args, Success)); 353a07aba5dSTimm Baeder return Success; 354a07aba5dSTimm Baeder } 355a07aba5dSTimm Baeder 356a07aba5dSTimm Baeder bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) { 357a07aba5dSTimm Baeder return emitJt(getOffset(Label), SourceInfo{}); 358a07aba5dSTimm Baeder } 359a07aba5dSTimm Baeder 360a07aba5dSTimm Baeder bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) { 361a07aba5dSTimm Baeder return emitJf(getOffset(Label), SourceInfo{}); 362a07aba5dSTimm Baeder } 363a07aba5dSTimm Baeder 364a07aba5dSTimm Baeder bool ByteCodeEmitter::jump(const LabelTy &Label) { 365a07aba5dSTimm Baeder return emitJmp(getOffset(Label), SourceInfo{}); 366a07aba5dSTimm Baeder } 367a07aba5dSTimm Baeder 368a07aba5dSTimm Baeder bool ByteCodeEmitter::fallthrough(const LabelTy &Label) { 369a07aba5dSTimm Baeder emitLabel(Label); 370a07aba5dSTimm Baeder return true; 371a07aba5dSTimm Baeder } 372a07aba5dSTimm Baeder 373a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 374a07aba5dSTimm Baeder // Opcode emitters 375a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 376a07aba5dSTimm Baeder 377a07aba5dSTimm Baeder #define GET_LINK_IMPL 378a07aba5dSTimm Baeder #include "Opcodes.inc" 379a07aba5dSTimm Baeder #undef GET_LINK_IMPL 380