30#include "llvm/Support/Compiler.h"
37 if constexpr (std::is_pointer_v<T>) {
38 uint32_t ID = OpPC.
read<uint32_t>();
40 llvm::raw_string_ostream SS(Result);
45 llvm::raw_string_ostream SS(Result);
46 auto Arg = OpPC.
read<
T>();
48 if constexpr (std::is_integral_v<T>) {
49 if constexpr (
sizeof(
T) == 1) {
50 if constexpr (std::is_signed_v<T>)
51 SS <<
static_cast<int32_t
>(Arg);
53 SS << static_cast<uint32_t>(Arg);
68 unsigned BitWidth = llvm::APFloatBase::semanticsSizeInBits(
69 llvm::APFloatBase::EnumToSemantics(Sem));
71 std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
75 OpPC +=
align(Result.bytesToSerialize());
78 llvm::raw_string_ostream SS(S);
79 SS << std::move(Result);
86 uint32_t BitWidth = T::deserializeSize(*OpPC);
88 std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
90 T Result(Memory.get(), BitWidth);
91 T::deserialize(*OpPC, &Result);
93 OpPC +=
align(Result.bytesToSerialize());
96 llvm::raw_string_ostream SS(Str);
97 SS << std::move(Result);
104 uint32_t BitWidth = T::deserializeSize(*OpPC);
106 std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
108 T Result(Memory.get(), BitWidth);
109 T::deserialize(*OpPC, &Result);
111 OpPC +=
align(Result.bytesToSerialize());
114 llvm::raw_string_ostream SS(Str);
115 SS << std::move(Result);
121 OpPC +=
align(F.bytesToSerialize());
124 llvm::raw_string_ostream SS(Result);
130 return Op == OP_Jmp || Op == OP_Jf || Op == OP_Jt;
134 unsigned L = 1u, M = 10u;
135 while (M <= N && ++L != std::numeric_limits<size_t>::digits10 + 1)
142 dump(llvm::errs(), PC);
148 assert(OpPC >= getCodeBegin());
149 assert(OpPC <= getCodeEnd());
152 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_GREEN,
true});
153 OS << getName() <<
" " << (
const void *)
this <<
"\n";
155 OS <<
"frame size: " << getFrameSize() <<
"\n";
156 OS <<
"arg size: " << getArgSize() <<
"\n";
157 OS <<
"rvo: " << hasRVO() <<
"\n";
158 OS <<
"this arg: " << hasThisPointer() <<
"\n";
164 bool CurrentOp =
false;
165 llvm::SmallVector<std::string> Args;
168 auto PrintName = [](
const char *Name) -> std::string {
169 return std::string(Name);
172 llvm::SmallVector<OpText> Code;
173 size_t LongestAddr = 0;
174 size_t LongestOp = 0;
176 for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
177 size_t Addr = PC - Start;
179 auto Op = PC.read<
Opcode>();
182 Text.CurrentOp = (PC == OpPC);
185#include "Opcodes.inc"
188 Code.push_back(
Text);
189 LongestOp = std::max(
Text.Op.size(), LongestOp);
198 llvm::SmallVector<JmpData> Jumps;
199 for (
auto &
Text : Code) {
201 Jumps.push_back({
Text.Addr,
Text.Addr + std::stoi(
Text.Args[0]) +
203 align(
sizeof(int32_t))});
206 llvm::SmallVector<std::string>
Text;
207 Text.reserve(Code.size());
208 size_t LongestLine = 0;
210 for (
const auto &
C : Code) {
212 llvm::raw_string_ostream LS(
Line);
222 LS.indent(LongestOp -
C.Op.size() + 4);
223 for (
auto &Arg :
C.Args) {
227 LongestLine = std::max(
Line.size(), LongestLine);
230 assert(Code.size() ==
Text.size());
232 auto spaces = [](
unsigned N) -> std::string {
234 for (
unsigned I = 0; I != N; ++I)
240 for (
auto &J : Jumps) {
242 bool FoundStart =
false;
243 for (
size_t LineIndex = 0; LineIndex !=
Text.size(); ++LineIndex) {
244 Text[LineIndex] += spaces(LongestLine -
Text[LineIndex].size());
246 if (Code[LineIndex].
Addr == J.From) {
247 Text[LineIndex] +=
" --+";
249 }
else if (Code[LineIndex].
Addr == J.To) {
250 Text[LineIndex] +=
" <-+";
252 }
else if (FoundStart) {
253 Text[LineIndex] +=
" |";
258 bool FoundStart =
false;
259 for (ssize_t LineIndex =
Text.size() - 1; LineIndex >= 0; --LineIndex) {
260 Text[LineIndex] += spaces(LongestLine -
Text[LineIndex].size());
261 if (Code[LineIndex].
Addr == J.From) {
262 Text[LineIndex] +=
" --+";
264 }
else if (Code[LineIndex].
Addr == J.To) {
265 Text[LineIndex] +=
" <-+";
267 }
else if (FoundStart) {
268 Text[LineIndex] +=
" |";
314 llvm_unreachable(
"Unhandled PrimType");
319 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_RED,
true});
320 OS <<
"\n:: Program\n";
324 ColorScope SC(OS,
true, {llvm::raw_ostream::WHITE,
true});
325 OS <<
"Total memory : " << Allocator.getTotalMemory() <<
" bytes\n";
326 OS <<
"Global Variables: " << Globals.size() <<
"\n";
329 for (
const Global *G : Globals) {
330 const Descriptor *Desc = G->block()->getDescriptor();
333 OS << GI <<
": " << (
const void *)G->block() <<
" ";
339 OS << (GP.
isInitialized() ?
"initialized " :
"uninitialized ");
346 if (
const auto *MTE =
347 dyn_cast_if_present<MaterializeTemporaryExpr>(Desc->
asExpr());
348 MTE && MTE->getLifetimeExtendedTemporaryDecl()) {
350 MTE->getLifetimeExtendedTemporaryDecl()->getValue()) {
351 OS <<
" (global temporary value: ";
353 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_MAGENTA,
true});
355 llvm::raw_string_ostream SS(VStr);
356 V->dump(SS, Ctx.getASTContext());
358 for (
unsigned I = 0; I != VStr.size(); ++I) {
374 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_CYAN,
false});
384 ColorScope SC(OS,
true, {llvm::raw_ostream::WHITE,
true});
385 OS <<
"Functions: " << Funcs.size() <<
"\n";
387 for (
const auto &
Func : Funcs) {
390 for (
const auto &Anon : AnonFuncs) {
397 llvm::errs() <<
'\n';
403 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
404 if (
const auto *ND = dyn_cast_if_present<NamedDecl>(
asDecl()))
405 ND->printQualifiedName(OS);
407 OS <<
"Expr " << (
const void *)
asExpr();
412 OS <<
" primitive-array";
414 OS <<
" composite-array";
423 OS <<
" zero-size-array";
425 OS <<
" unknown-size-array";
428 OS <<
" constexpr-unknown";
434 unsigned Spaces =
Indent * 2;
435 llvm::raw_ostream &OS = llvm::errs();
440 OS.indent(Spaces) <<
"Size: " <<
getSize() <<
" bytes\n";
441 OS.indent(Spaces) <<
"AllocSize: " <<
getAllocSize() <<
" bytes\n";
444 OS.indent(Spaces) <<
"Elements: " <<
getNumElems() <<
'\n';
445 unsigned FO = Offset;
448 assert(
ElemDesc->getMetadataSize() == 0);
449 OS.indent(Spaces) <<
"Element " << I <<
" offset: " << FO <<
'\n';
455 OS.indent(Spaces) <<
"Elements: " <<
getNumElems() <<
'\n';
460 OS.indent(Spaces) <<
"Element " << I <<
" offset: " << FO <<
'\n';
466 for (
const Record::Field &F :
ElemRecord->fields()) {
467 OS.indent(Spaces) <<
"- Field " << I <<
": ";
469 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_RED,
true});
470 OS << F.Decl->getName();
472 OS <<
". Offset " << (Offset + F.Offset) <<
"\n";
473 F.Desc->dumpFull(Offset + F.Offset,
Indent + 1);
485 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
486 OS <<
"InlineDescriptor " << (
const void *)
this <<
"\n";
488 OS <<
"Offset: " <<
Offset <<
"\n";
489 OS <<
"IsConst: " <<
IsConst <<
"\n";
491 OS <<
"IsBase: " <<
IsBase <<
"\n";
492 OS <<
"IsActive: " <<
IsActive <<
"\n";
493 OS <<
"InUnion: " <<
InUnion <<
"\n";
507 unsigned Spaces =
Indent * 2;
509 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
514 OS <<
"Frame (Depth: " <<
getDepth() <<
")";
517 OS.indent(Spaces) <<
"Function: " <<
getFunction();
519 OS <<
" (" << F->getName() <<
")";
523 OS.indent(Spaces) <<
"This: " <<
getThis() <<
"\n";
525 OS.indent(Spaces) <<
"This: -\n";
526 if (Func && Func->hasRVO())
527 OS.indent(Spaces) <<
"RVO: " <<
getRVOPtr() <<
"\n";
529 OS.indent(Spaces) <<
"RVO: -\n";
530 OS.indent(Spaces) <<
"Depth: " << Depth <<
"\n";
531 OS.indent(Spaces) <<
"ArgSize: " << ArgSize <<
"\n";
532 OS.indent(Spaces) <<
"Args: " << (
void *)Args <<
"\n";
533 OS.indent(Spaces) <<
"FrameOffset: " << FrameOffset <<
"\n";
534 OS.indent(Spaces) <<
"FrameSize: " << (Func ? Func->getFrameSize() : 0)
542LLVM_DUMP_METHOD
void Record::dump(llvm::raw_ostream &OS,
unsigned Indentation,
543 unsigned Offset)
const {
544 unsigned Indent = Indentation * 2;
547 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
552 for (
const Record::Base &B :
bases()) {
553 OS.indent(
Indent) <<
"- Base " << I <<
". Offset " << (Offset + B.Offset)
555 B.R->dump(OS, Indentation + 1, Offset + B.Offset);
560 for (
const Record::Field &F :
fields()) {
561 OS.indent(
Indent) <<
"- Field " << I <<
": ";
563 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_RED,
true});
564 OS << F.Decl->getName();
566 OS <<
". Offset " << (Offset + F.Offset) <<
"\n";
572 OS.indent(
Indent) <<
"- Virtual Base " << I <<
". Offset "
573 << (Offset + B.Offset) <<
"\n";
574 B.R->dump(OS, Indentation + 1, Offset + B.Offset);
581 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_BLUE,
true});
582 OS <<
"Block " << (
const void *)
this;
587 unsigned NPointers = 0;
588 for (
const Pointer *P = Pointers; P; P = P->asBlockPointer().
Next) {
591 OS <<
" EvalID: " << EvalID <<
'\n';
594 OS << *DeclID <<
'\n';
597 OS <<
" Pointers: " << NPointers <<
"\n";
598 OS <<
" Dead: " <<
isDead() <<
"\n";
599 OS <<
" Static: " << IsStatic <<
"\n";
600 OS <<
" Extern: " <<
isExtern() <<
"\n";
601 OS <<
" Initialized: " << IsInitialized <<
"\n";
602 OS <<
" Weak: " <<
isWeak() <<
"\n";
603 OS <<
" Dummy: " <<
isDummy() <<
'\n';
604 OS <<
" Dynamic: " <<
isDynamic() <<
"\n";
608 auto &OS = llvm::errs();
618 Value.dump(OS, Ctx->getASTContext());
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
std::string printArg< Floating >(Program &P, CodePtr &OpPC)
static const char * primTypeToString(PrimType T)
static size_t getNumDisplayWidth(size_t N)
static bool isJumpOpcode(Opcode Op)
std::string printArg< FixedPoint >(Program &P, CodePtr &OpPC)
static std::string printArg(Program &P, CodePtr &OpPC)
Defines the clang::Expr interface and subclasses for C++ expressions.
#define TYPE_SWITCH(Expr, B)
static bool isInvalid(LocType Loc, bool *Invalid)
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
bool isExtern() const
Checks if the block is extern.
Pointer into the code segment.
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
void dump() const
Dump to stderr.
static FixedPoint deserialize(const std::byte *Buff)
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
static llvm::APFloatBase::Semantics deserializeSemantics(const std::byte *Buff)
static void deserialize(const std::byte *Buff, Floating *Result)
void dump(CodePtr PC={}) const
Dumps the disassembled bytecode to llvm::errs().
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
InterpFrame(InterpState &S)
Bottom Frame.
InterpFrame * Caller
The frame of the previous function.
const Pointer & getThis() const
Returns the 'this' pointer.
const Function * getFunction() const
Returns the current function.
bool hasThisPointer() const
unsigned getDepth() const
const Pointer & getRVOPtr() const
Returns the RVO pointer, if the Function has one.
void describe(llvm::raw_ostream &OS) const override
Describes the frame with arguments for diagnostic purposes.
A pointer to a memory block, live or dead.
bool isInitialized() const
Checks if an object was initialized.
const Block * block() const
The program contains and links the bytecode for all functions.
Pointer getPtrGlobal(unsigned Idx) const
Returns a pointer to a global.
void dump() const
Dumps the disassembled bytecode to llvm::errs().
const void * getNativePointer(unsigned Idx) const
Returns the value of a marshalled native pointer.
std::string getName() const
Returns the name of the underlying declaration.
llvm::iterator_range< const_virtual_iter > virtual_bases() const
llvm::iterator_range< const_base_iter > bases() const
llvm::iterator_range< const_field_iter > fields() const
static const FunctionDecl * getCallee(const CXXConstructExpr &D)
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
PrimType
Enumeration of the primitive types of the VM.
std::optional< std::pair< bool, std::shared_ptr< InitMap > > > InitMapPtr
The JSON file list parser is used to communicate input to InstallAPI.
raw_ostream & Indent(raw_ostream &Out, const unsigned int Space, bool IsDot)
@ Result
The result type of a method or function.
const FunctionProtoType * T
Describes a memory block created by an allocation site.
unsigned getAllocSize() const
Returns the allocated size, including metadata.
unsigned getNumElems() const
Returns the number of elements stored in the block.
unsigned getSize() const
Returns the size of the object without metadata.
void dumpFull(unsigned Offset=0, unsigned Indent=0) const
Dump descriptor, including all valid offsets.
bool isPrimitive() const
Checks if the descriptor is of a primitive.
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
const Decl * asDecl() const
const Descriptor *const ElemDesc
Descriptor of the array element.
unsigned getMetadataSize() const
Returns the size of the metadata.
bool isUnknownSizeArray() const
Checks if the descriptor is of an array of unknown size.
unsigned getElemSize() const
returns the size of an element when the structure is viewed as an array.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
bool isZeroSizeArray() const
Checks if the descriptor is of an array of zero size.
PrimType getPrimType() const
bool isRecord() const
Checks if the descriptor is of a record.
const bool IsTemporary
Flag indicating if the block is a temporary.
const Record *const ElemRecord
Pointer to the record, if block contains records.
bool isUnion() const
Checks if the descriptor is of a union.
const Expr * asExpr() const
Inline descriptor embedded in structures and arrays.
unsigned IsActive
Flag indicating if the field is the active member of a union.
unsigned IsConstInMutable
Flag indicating if this field is a const field nested in a mutable parent field.
unsigned IsBase
Flag indicating if the field is an embedded base class.
unsigned InUnion
Flag indicating if this field is in a union (even if nested).
unsigned Offset
Offset inside the structure/array.
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
unsigned IsConst
Flag indicating if the storage is constant or not.
unsigned IsArrayElement
Flag indicating if the field is an element of a composite array.
unsigned IsFieldMutable
Flag indicating if the field is mutable (if in a record).