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