xref: /llvm-project/clang/lib/AST/ByteCode/InterpStack.cpp (revision 048bc6727644c103044ea22a6f06b80cb2443ec5)
1 //===--- InterpStack.cpp - Stack implementation 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 "InterpStack.h"
10 #include "Boolean.h"
11 #include "FixedPoint.h"
12 #include "Floating.h"
13 #include "Integral.h"
14 #include "MemberPointer.h"
15 #include "Pointer.h"
16 #include <cassert>
17 #include <cstdlib>
18 
19 using namespace clang;
20 using namespace clang::interp;
21 
22 InterpStack::~InterpStack() { clear(); }
23 
24 void InterpStack::clear() {
25   if (Chunk && Chunk->Next)
26     std::free(Chunk->Next);
27   if (Chunk)
28     std::free(Chunk);
29   Chunk = nullptr;
30   StackSize = 0;
31 #ifndef NDEBUG
32   ItemTypes.clear();
33 #endif
34 }
35 
36 void InterpStack::clearTo(size_t NewSize) {
37   assert(NewSize <= size());
38   size_t ToShrink = size() - NewSize;
39   if (ToShrink == 0)
40     return;
41 
42   shrink(ToShrink);
43   assert(size() == NewSize);
44 }
45 
46 void *InterpStack::grow(size_t Size) {
47   assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large");
48 
49   if (!Chunk || sizeof(StackChunk) + Chunk->size() + Size > ChunkSize) {
50     if (Chunk && Chunk->Next) {
51       Chunk = Chunk->Next;
52     } else {
53       StackChunk *Next = new (std::malloc(ChunkSize)) StackChunk(Chunk);
54       if (Chunk)
55         Chunk->Next = Next;
56       Chunk = Next;
57     }
58   }
59 
60   auto *Object = reinterpret_cast<void *>(Chunk->End);
61   Chunk->End += Size;
62   StackSize += Size;
63   return Object;
64 }
65 
66 void *InterpStack::peekData(size_t Size) const {
67   assert(Chunk && "Stack is empty!");
68 
69   StackChunk *Ptr = Chunk;
70   while (Size > Ptr->size()) {
71     Size -= Ptr->size();
72     Ptr = Ptr->Prev;
73     assert(Ptr && "Offset too large");
74   }
75 
76   return reinterpret_cast<void *>(Ptr->End - Size);
77 }
78 
79 void InterpStack::shrink(size_t Size) {
80   assert(Chunk && "Chunk is empty!");
81 
82   while (Size > Chunk->size()) {
83     Size -= Chunk->size();
84     if (Chunk->Next) {
85       std::free(Chunk->Next);
86       Chunk->Next = nullptr;
87     }
88     Chunk->End = Chunk->start();
89     Chunk = Chunk->Prev;
90     assert(Chunk && "Offset too large");
91   }
92 
93   Chunk->End -= Size;
94   StackSize -= Size;
95 
96 #ifndef NDEBUG
97   size_t TypesSize = 0;
98   for (PrimType T : ItemTypes)
99     TYPE_SWITCH(T, { TypesSize += aligned_size<T>(); });
100 
101   size_t StackSize = size();
102   while (TypesSize > StackSize) {
103     TYPE_SWITCH(ItemTypes.back(), {
104       TypesSize -= aligned_size<T>();
105       ItemTypes.pop_back();
106     });
107   }
108   assert(TypesSize == StackSize);
109 #endif
110 }
111 
112 void InterpStack::dump() const {
113 #ifndef NDEBUG
114   llvm::errs() << "Items: " << ItemTypes.size() << ". Size: " << size() << '\n';
115   if (ItemTypes.empty())
116     return;
117 
118   size_t Index = 0;
119   size_t Offset = 0;
120 
121   // The type of the item on the top of the stack is inserted to the back
122   // of the vector, so the iteration has to happen backwards.
123   for (auto TyIt = ItemTypes.rbegin(); TyIt != ItemTypes.rend(); ++TyIt) {
124     Offset += align(primSize(*TyIt));
125 
126     llvm::errs() << Index << '/' << Offset << ": ";
127     TYPE_SWITCH(*TyIt, {
128       const T &V = peek<T>(Offset);
129       llvm::errs() << V;
130     });
131     llvm::errs() << '\n';
132 
133     ++Index;
134   }
135 #endif
136 }
137