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});
154 FD->getNameForDiagnostic(
155 OS, P.getContext().getASTContext().getPrintingPolicy(),
160 OS <<
" " << (
const void *)
this <<
"\n";
162 OS <<
"frame size: " << getFrameSize() <<
"\n";
163 OS <<
"arg size: " << getArgSize() <<
"\n";
164 OS <<
"rvo: " << hasRVO() <<
"\n";
165 OS <<
"this arg: " << hasThisPointer() <<
"\n";
171 bool CurrentOp =
false;
172 llvm::SmallVector<std::string> Args;
175 auto PrintName = [](
const char *Name) -> std::string {
176 return std::string(Name);
179 llvm::SmallVector<OpText> Code;
180 size_t LongestAddr = 0;
181 size_t LongestOp = 0;
183 for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
184 size_t Addr = PC - Start;
186 auto Op = PC.read<
Opcode>();
189 Text.CurrentOp = (PC == OpPC);
192#include "Opcodes.inc"
195 Code.push_back(
Text);
196 LongestOp = std::max(
Text.Op.size(), LongestOp);
205 llvm::SmallVector<JmpData> Jumps;
206 for (
auto &
Text : Code) {
208 Jumps.push_back({
Text.Addr,
Text.Addr + std::stoi(
Text.Args[0]) +
210 align(
sizeof(int32_t))});
213 llvm::SmallVector<std::string>
Text;
214 Text.reserve(Code.size());
215 size_t LongestLine = 0;
217 for (
const auto &
C : Code) {
219 llvm::raw_string_ostream LS(
Line);
229 LS.indent(LongestOp -
C.Op.size() + 4);
230 for (
auto &Arg :
C.Args) {
234 LongestLine = std::max(
Line.size(), LongestLine);
237 assert(Code.size() ==
Text.size());
239 auto spaces = [](
unsigned N) -> std::string {
241 for (
unsigned I = 0; I != N; ++I)
247 for (
auto &J : Jumps) {
249 bool FoundStart =
false;
250 for (
size_t LineIndex = 0; LineIndex !=
Text.size(); ++LineIndex) {
251 Text[LineIndex] += spaces(LongestLine -
Text[LineIndex].size());
253 if (Code[LineIndex].
Addr == J.From) {
254 Text[LineIndex] +=
" --+";
256 }
else if (Code[LineIndex].
Addr == J.To) {
257 Text[LineIndex] +=
" <-+";
259 }
else if (FoundStart) {
260 Text[LineIndex] +=
" |";
265 bool FoundStart =
false;
266 for (ssize_t LineIndex =
Text.size() - 1; LineIndex >= 0; --LineIndex) {
267 Text[LineIndex] += spaces(LongestLine -
Text[LineIndex].size());
268 if (Code[LineIndex].
Addr == J.From) {
269 Text[LineIndex] +=
" --+";
271 }
else if (Code[LineIndex].
Addr == J.To) {
272 Text[LineIndex] +=
" <-+";
274 }
else if (FoundStart) {
275 Text[LineIndex] +=
" |";
321 llvm_unreachable(
"Unhandled PrimType");
326 llvm::raw_string_ostream SS(Result);
330 else if (B < (1u << 20u))
331 SS << llvm::format(
"{0:F2}", B / 1024.) <<
" KB";
333 SS << llvm::format(
"{0:F2}", B / 1024. / 1024.) <<
" MB";
340 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_RED,
true});
341 OS <<
"\n:: Program\n";
345 ColorScope SC(OS,
true, {llvm::raw_ostream::WHITE,
true});
347 Bytes += Allocator.getTotalMemory();
349 Bytes += GlobalIndices.getMemorySize();
350 Bytes += Records.getMemorySize();
351 Bytes += DummyVariables.getMemorySize();
354 for (
const Record *R : Records.values()) {
355 Bytes +=
sizeof(
Record) + R->BaseMap.getMemorySize() +
356 R->VirtualBaseMap.getMemorySize();
357 Bytes += R->Fields.capacity_in_bytes() + R->Bases.capacity_in_bytes() +
358 R->VirtualBases.capacity_in_bytes();
364 OS <<
"Global Variables: " << Globals.size() <<
'\n';
367 for (
const Global *G : Globals) {
368 const Descriptor *Desc = G->block()->getDescriptor();
371 OS << GI <<
": " << (
const void *)G->block() <<
" ";
377 OS << (GP.
isInitialized() ?
"initialized " :
"uninitialized ");
384 if (
const auto *MTE =
385 dyn_cast_if_present<MaterializeTemporaryExpr>(Desc->
asExpr());
386 MTE && MTE->getLifetimeExtendedTemporaryDecl()) {
388 MTE->getLifetimeExtendedTemporaryDecl()->getValue()) {
389 OS <<
" (global temporary value: ";
391 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_MAGENTA,
true});
393 llvm::raw_string_ostream SS(VStr);
394 V->dump(SS, Ctx.getASTContext());
396 for (
unsigned I = 0; I != VStr.size(); ++I) {
412 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_CYAN,
false});
422 ColorScope SC(OS,
true, {llvm::raw_ostream::WHITE,
true});
423 OS <<
"Functions: " << Funcs.size() <<
"\n";
425 for (
const auto &
Func : Funcs) {
428 for (
const auto &Anon : AnonFuncs) {
435 llvm::errs() <<
'\n';
441 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
442 if (
const auto *ND = dyn_cast_if_present<NamedDecl>(
asDecl()))
443 ND->printQualifiedName(OS);
445 OS <<
"Expr " << (
const void *)
asExpr();
450 OS <<
" primitive-array";
452 OS <<
" composite-array";
461 OS <<
" zero-size-array";
463 OS <<
" unknown-size-array";
466 OS <<
" constexpr-unknown";
472 unsigned Spaces =
Indent * 2;
473 llvm::raw_ostream &OS = llvm::errs();
478 OS.indent(Spaces) <<
"Size: " <<
getSize() <<
" bytes\n";
479 OS.indent(Spaces) <<
"AllocSize: " <<
getAllocSize() <<
" bytes\n";
482 OS.indent(Spaces) <<
"Elements: " <<
getNumElems() <<
'\n';
483 unsigned FO = Offset;
486 assert(
ElemDesc->getMetadataSize() == 0);
487 OS.indent(Spaces) <<
"Element " << I <<
" offset: " << FO <<
'\n';
493 OS.indent(Spaces) <<
"Elements: " <<
getNumElems() <<
'\n';
498 OS.indent(Spaces) <<
"Element " << I <<
" offset: " << FO <<
'\n';
504 for (
const Record::Field &F :
ElemRecord->fields()) {
505 OS.indent(Spaces) <<
"- Field " << I <<
": ";
507 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_RED,
true});
508 OS << F.Decl->getName();
510 OS <<
". Offset " << (Offset + F.Offset) <<
"\n";
511 F.Desc->dumpFull(Offset + F.Offset,
Indent + 1);
523 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
524 OS <<
"InlineDescriptor " << (
const void *)
this <<
"\n";
526 OS <<
"Offset: " <<
Offset <<
"\n";
527 OS <<
"IsConst: " <<
IsConst <<
"\n";
529 OS <<
"IsBase: " <<
IsBase <<
"\n";
530 OS <<
"IsActive: " <<
IsActive <<
"\n";
531 OS <<
"InUnion: " <<
InUnion <<
"\n";
545 unsigned Spaces =
Indent * 2;
547 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
552 OS <<
"Frame (Depth: " <<
getDepth() <<
")";
555 OS.indent(Spaces) <<
"Function: " <<
getFunction();
557 OS <<
" (" << F->getName() <<
")";
561 OS.indent(Spaces) <<
"This: " <<
getThis() <<
"\n";
563 OS.indent(Spaces) <<
"This: -\n";
564 if (Func && Func->hasRVO())
565 OS.indent(Spaces) <<
"RVO: " <<
getRVOPtr() <<
"\n";
567 OS.indent(Spaces) <<
"RVO: -\n";
568 OS.indent(Spaces) <<
"Depth: " << Depth <<
"\n";
569 OS.indent(Spaces) <<
"ArgSize: " << ArgSize <<
"\n";
570 OS.indent(Spaces) <<
"Args: " << (
void *)Args <<
"\n";
571 OS.indent(Spaces) <<
"FrameOffset: " << FrameOffset <<
"\n";
572 OS.indent(Spaces) <<
"FrameSize: " << (Func ? Func->getFrameSize() : 0)
580LLVM_DUMP_METHOD
void Record::dump(llvm::raw_ostream &OS,
unsigned Indentation,
581 unsigned Offset)
const {
582 unsigned Indent = Indentation * 2;
585 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
590 for (
const Record::Base &B :
bases()) {
591 OS.indent(
Indent) <<
"- Base " << I <<
". Offset " << (Offset + B.Offset)
593 B.R->dump(OS, Indentation + 1, Offset + B.Offset);
598 for (
const Record::Field &F :
fields()) {
599 OS.indent(
Indent) <<
"- Field " << I <<
": ";
601 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_RED,
true});
602 OS << F.Decl->getName();
604 OS <<
". Offset " << (Offset + F.Offset) <<
"\n";
610 OS.indent(
Indent) <<
"- Virtual Base " << I <<
". Offset "
611 << (Offset + B.Offset) <<
"\n";
612 B.R->dump(OS, Indentation + 1, Offset + B.Offset);
619 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_BLUE,
true});
620 OS <<
"Block " << (
const void *)
this;
625 unsigned NPointers = 0;
626 for (
const Pointer *P = Pointers; P; P = P->asBlockPointer().
Next) {
629 OS <<
" EvalID: " << EvalID <<
'\n';
632 OS << *DeclID <<
'\n';
635 OS <<
" Pointers: " << NPointers <<
"\n";
636 OS <<
" Dead: " <<
isDead() <<
"\n";
637 OS <<
" Static: " << IsStatic <<
"\n";
638 OS <<
" Extern: " <<
isExtern() <<
"\n";
639 OS <<
" Initialized: " << IsInitialized <<
"\n";
640 OS <<
" Weak: " <<
isWeak() <<
"\n";
641 OS <<
" Dummy: " <<
isDummy() <<
'\n';
642 OS <<
" Dynamic: " <<
isDynamic() <<
"\n";
646 auto &OS = llvm::errs();
656 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 std::string formatBytes(size_t B)
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],...
Represents a function declaration or definition.
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() 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.
Structure/Class descriptor.
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,...
StringRef getName(const HeaderType T)
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
PrimType
Enumeration of the primitive types of the VM.
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.
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
A pointer-sized struct we use to allocate into data storage.
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).