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