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