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