30#include "llvm/Support/Compiler.h"
31#include "llvm/Support/FormatVariadic.h"
38 if constexpr (std::is_pointer_v<T>) {
39 uint32_t ID = OpPC.
read<uint32_t>();
41 llvm::raw_string_ostream SS(
Result);
46 llvm::raw_string_ostream SS(
Result);
47 auto Arg = OpPC.
read<T>();
49 if constexpr (std::is_integral_v<T>) {
50 if constexpr (
sizeof(T) == 1) {
51 if constexpr (std::is_signed_v<T>)
52 SS <<
static_cast<int32_t
>(Arg);
54 SS << static_cast<uint32_t>(Arg);
69 unsigned BitWidth = llvm::APFloatBase::semanticsSizeInBits(
70 llvm::APFloatBase::EnumToSemantics(Sem));
72 std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
79 llvm::raw_string_ostream SS(S);
87 uint32_t BitWidth = T::deserializeSize(*OpPC);
89 std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
91 T
Result(Memory.get(), BitWidth);
92 T::deserialize(*OpPC, &
Result);
97 llvm::raw_string_ostream SS(Str);
105 uint32_t BitWidth = T::deserializeSize(*OpPC);
107 std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
109 T
Result(Memory.get(), BitWidth);
110 T::deserialize(*OpPC, &
Result);
115 llvm::raw_string_ostream SS(Str);
122 OpPC +=
align(F.bytesToSerialize());
125 llvm::raw_string_ostream SS(
Result);
131 return Op == OP_Jmp || Op == OP_Jf || Op == OP_Jt;
135 unsigned L = 1u, M = 10u;
136 while (M <= N && ++L != std::numeric_limits<size_t>::digits10 + 1)
143 dump(llvm::errs(), PC);
149 assert(OpPC >= getCodeBegin());
150 assert(OpPC <= getCodeEnd());
153 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_GREEN,
true});
155 FD->getNameForDiagnostic(
156 OS, P.getContext().getASTContext().getPrintingPolicy(),
161 OS <<
" " << (
const void *)
this <<
"\n";
163 OS <<
"frame size: " << getFrameSize() <<
"\n";
164 OS <<
"arg size: " << getArgSize() <<
"\n";
165 OS <<
"rvo: " << hasRVO() <<
"\n";
166 OS <<
"this arg: " << hasThisPointer() <<
"\n";
172 bool CurrentOp =
false;
173 llvm::SmallVector<std::string> Args;
176 auto PrintName = [](
const char *Name) -> std::string {
177 return std::string(Name);
180 llvm::SmallVector<OpText> Code;
181 size_t LongestAddr = 0;
182 size_t LongestOp = 0;
184 for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
185 size_t Addr = PC - Start;
187 auto Op = PC.read<
Opcode>();
190 Text.CurrentOp = (PC == OpPC);
193#include "Opcodes.inc"
196 Code.push_back(
Text);
197 LongestOp = std::max(
Text.Op.size(), LongestOp);
206 llvm::SmallVector<JmpData> Jumps;
207 for (
auto &
Text : Code) {
209 Jumps.push_back({
Text.Addr,
Text.Addr + std::stoi(
Text.Args[0]) +
211 align(
sizeof(int32_t))});
214 llvm::SmallVector<std::string>
Text;
215 Text.reserve(Code.size());
216 size_t LongestLine = 0;
218 for (
const auto &
C : Code) {
220 llvm::raw_string_ostream LS(
Line);
230 LS.indent(LongestOp -
C.Op.size() + 4);
231 for (
auto &Arg :
C.Args) {
235 LongestLine = std::max(
Line.size(), LongestLine);
238 assert(Code.size() ==
Text.size());
240 auto spaces = [](
unsigned N) -> std::string {
242 for (
unsigned I = 0; I != N; ++I)
248 for (
auto &J : Jumps) {
250 bool FoundStart =
false;
251 for (
size_t LineIndex = 0; LineIndex !=
Text.size(); ++LineIndex) {
252 Text[LineIndex] += spaces(LongestLine -
Text[LineIndex].size());
254 if (Code[LineIndex].
Addr == J.From) {
255 Text[LineIndex] +=
" --+";
257 }
else if (Code[LineIndex].
Addr == J.To) {
258 Text[LineIndex] +=
" <-+";
260 }
else if (FoundStart) {
261 Text[LineIndex] +=
" |";
266 bool FoundStart =
false;
267 for (ssize_t LineIndex =
Text.size() - 1; LineIndex >= 0; --LineIndex) {
268 Text[LineIndex] += spaces(LongestLine -
Text[LineIndex].size());
269 if (Code[LineIndex].
Addr == J.From) {
270 Text[LineIndex] +=
" --+";
272 }
else if (Code[LineIndex].
Addr == J.To) {
273 Text[LineIndex] +=
" <-+";
275 }
else if (FoundStart) {
276 Text[LineIndex] +=
" |";
322 llvm_unreachable(
"Unhandled PrimType");
327 llvm::raw_string_ostream SS(
Result);
331 else if (B < (1u << 20u))
332 SS << llvm::formatv(
"{0:F2}", B / 1024.) <<
" KB";
334 SS << llvm::formatv(
"{0:F2}", B / 1024. / 1024.) <<
" MB";
341 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_RED,
true});
342 OS <<
"\n:: Program\n";
346 ColorScope SC(OS,
true, {llvm::raw_ostream::WHITE,
true});
348 Bytes += Allocator.getTotalMemory();
350 Bytes += GlobalIndices.getMemorySize();
351 Bytes += Records.getMemorySize();
352 Bytes += DummyVariables.getMemorySize();
355 for (
const Record *R : Records.values()) {
356 Bytes +=
sizeof(
Record) + R->BaseMap.getMemorySize() +
357 R->VirtualBaseMap.getMemorySize();
358 Bytes += R->Fields.capacity_in_bytes() + R->Bases.capacity_in_bytes() +
359 R->VirtualBases.capacity_in_bytes();
365 OS <<
"Global Variables: " << Globals.size() <<
'\n';
368 for (
const Global *G : Globals) {
369 const Descriptor *Desc = G->block()->getDescriptor();
372 OS << GI <<
": " << (
const void *)G->block() <<
" ";
378 OS << (GP.
isInitialized() ?
"initialized " :
"uninitialized ");
385 if (
const auto *MTE =
386 dyn_cast_if_present<MaterializeTemporaryExpr>(Desc->
asExpr());
387 MTE && MTE->getLifetimeExtendedTemporaryDecl()) {
389 MTE->getLifetimeExtendedTemporaryDecl()->getValue()) {
390 OS <<
" (global temporary value: ";
392 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_MAGENTA,
true});
394 llvm::raw_string_ostream SS(VStr);
395 V->dump(SS, Ctx.getASTContext());
397 for (
unsigned I = 0; I != VStr.size(); ++I) {
413 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_CYAN,
false});
423 ColorScope SC(OS,
true, {llvm::raw_ostream::WHITE,
true});
424 OS <<
"Functions: " << Funcs.size() <<
"\n";
426 for (
const auto &
Func : Funcs) {
429 for (
const auto &Anon : AnonFuncs) {
436 llvm::errs() <<
'\n';
442 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
443 if (
const auto *ND = dyn_cast_if_present<NamedDecl>(
asDecl()))
444 ND->printQualifiedName(OS);
446 OS <<
"Expr " << (
const void *)
asExpr();
456 OS <<
" union(" <<
ElemRecord->getName() <<
")";
458 OS <<
" record(" <<
ElemRecord->getName() <<
")";
463 OS <<
" zero-size-array";
465 OS <<
" unknown-size-array";
468 OS <<
" constexpr-unknown";
474 unsigned Spaces =
Indent * 2;
475 llvm::raw_ostream &OS = llvm::errs();
480 OS.indent(Spaces) <<
"Size: " <<
getSize() <<
" bytes\n";
481 OS.indent(Spaces) <<
"AllocSize: " <<
getAllocSize() <<
" bytes\n";
484 OS.indent(Spaces) <<
"Elements: " <<
getNumElems() <<
'\n';
485 unsigned FO = Offset;
488 assert(
ElemDesc->getMetadataSize() == 0);
489 OS.indent(Spaces) <<
"Element " << I <<
" offset: " << FO <<
'\n';
495 OS.indent(Spaces) <<
"Elements: " <<
getNumElems() <<
'\n';
500 OS.indent(Spaces) <<
"Element " << I <<
" offset: " << FO <<
'\n';
506 for (
const Record::Field &F :
ElemRecord->fields()) {
507 OS.indent(Spaces) <<
"- Field " << I <<
": ";
509 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_RED,
true});
510 OS << F.Decl->getName();
512 OS <<
". Offset " << (Offset + F.Offset) <<
"\n";
513 F.Desc->dumpFull(Offset + F.Offset,
Indent + 1);
525 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
526 OS <<
"InlineDescriptor " << (
const void *)
this <<
"\n";
528 OS <<
"Offset: " <<
Offset <<
"\n";
529 OS <<
"IsConst: " <<
IsConst <<
"\n";
531 OS <<
"IsBase: " <<
IsBase <<
"\n";
532 OS <<
"IsActive: " <<
IsActive <<
"\n";
533 OS <<
"InUnion: " <<
InUnion <<
"\n";
547 unsigned Spaces =
Indent * 2;
549 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
554 OS <<
"Frame (Depth: " <<
getDepth() <<
")";
557 OS.indent(Spaces) <<
"Function: " <<
getFunction();
559 OS <<
" (" << F->getName() <<
")";
563 OS.indent(Spaces) <<
"This: " <<
getThis() <<
"\n";
565 OS.indent(Spaces) <<
"This: -\n";
566 if (Func && Func->hasRVO())
567 OS.indent(Spaces) <<
"RVO: " <<
getRVOPtr() <<
"\n";
569 OS.indent(Spaces) <<
"RVO: -\n";
570 OS.indent(Spaces) <<
"Depth: " << Depth <<
"\n";
571 OS.indent(Spaces) <<
"ArgSize: " << ArgSize <<
"\n";
572 OS.indent(Spaces) <<
"Args: " << (
void *)Args <<
"\n";
573 OS.indent(Spaces) <<
"FrameOffset: " << FrameOffset <<
"\n";
574 OS.indent(Spaces) <<
"FrameSize: " << (Func ? Func->getFrameSize() : 0)
582LLVM_DUMP_METHOD
void Record::dump(llvm::raw_ostream &OS,
unsigned Indentation,
583 unsigned Offset)
const {
584 unsigned Indent = Indentation * 2;
587 ColorScope SC(OS,
true, {llvm::raw_ostream::BLUE,
true});
592 for (
const Record::Base &B :
bases()) {
593 OS.indent(
Indent) <<
"- Base " << I <<
". Offset " << (Offset + B.Offset)
595 B.R->dump(OS, Indentation + 1, Offset + B.Offset);
600 for (
const Record::Field &F :
fields()) {
601 OS.indent(
Indent) <<
"- Field " << I <<
": ";
603 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_RED,
true});
604 OS << F.Decl->getName();
606 OS <<
". Offset " << (Offset + F.Offset) <<
"\n";
612 OS.indent(
Indent) <<
"- Virtual Base " << I <<
". Offset "
613 << (Offset + B.Offset) <<
"\n";
614 B.R->dump(OS, Indentation + 1, Offset + B.Offset);
621 ColorScope SC(OS,
true, {llvm::raw_ostream::BRIGHT_BLUE,
true});
622 OS <<
"Block " << (
const void *)
this;
627 unsigned NPointers = 0;
628 for (
const Pointer *P = Pointers; P; P = P->asBlockPointer().
Next) {
631 OS <<
" EvalID: " << EvalID <<
'\n';
634 OS << *DeclID <<
'\n';
637 OS <<
" Pointers: " << NPointers <<
"\n";
638 OS <<
" Dead: " <<
isDead() <<
"\n";
639 OS <<
" Static: " << IsStatic <<
"\n";
640 OS <<
" Extern: " <<
isExtern() <<
"\n";
641 OS <<
" Initialized: " << IsInitialized <<
"\n";
642 OS <<
" Weak: " <<
isWeak() <<
"\n";
643 OS <<
" Dummy: " <<
isDummy() <<
'\n';
644 OS <<
" Dynamic: " <<
isDynamic() <<
"\n";
648 auto &OS = llvm::errs();
658 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.
Result
Implement __builtin_bit_cast and related operations.
#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).