xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/InterpStack.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1a7dea167SDimitry Andric //===--- InterpStack.cpp - Stack implementation for the VM ------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric 
906c3fb27SDimitry Andric #include "InterpStack.h"
1006c3fb27SDimitry Andric #include "Boolean.h"
1106c3fb27SDimitry Andric #include "Floating.h"
1206c3fb27SDimitry Andric #include "Integral.h"
13*5f757f3fSDimitry Andric #include "Pointer.h"
14a7dea167SDimitry Andric #include <cassert>
15a7dea167SDimitry Andric #include <cstdlib>
16a7dea167SDimitry Andric 
17a7dea167SDimitry Andric using namespace clang;
18a7dea167SDimitry Andric using namespace clang::interp;
19a7dea167SDimitry Andric 
20a7dea167SDimitry Andric InterpStack::~InterpStack() {
21a7dea167SDimitry Andric   clear();
22a7dea167SDimitry Andric }
23a7dea167SDimitry Andric 
24a7dea167SDimitry Andric void InterpStack::clear() {
25a7dea167SDimitry Andric   if (Chunk && Chunk->Next)
2606c3fb27SDimitry Andric     std::free(Chunk->Next);
27a7dea167SDimitry Andric   if (Chunk)
2806c3fb27SDimitry Andric     std::free(Chunk);
29a7dea167SDimitry Andric   Chunk = nullptr;
30a7dea167SDimitry Andric   StackSize = 0;
3106c3fb27SDimitry Andric #ifndef NDEBUG
3206c3fb27SDimitry Andric   ItemTypes.clear();
3306c3fb27SDimitry Andric #endif
34a7dea167SDimitry Andric }
35a7dea167SDimitry Andric 
36a7dea167SDimitry Andric void *InterpStack::grow(size_t Size) {
37a7dea167SDimitry Andric   assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large");
38a7dea167SDimitry Andric 
39a7dea167SDimitry Andric   if (!Chunk || sizeof(StackChunk) + Chunk->size() + Size > ChunkSize) {
40a7dea167SDimitry Andric     if (Chunk && Chunk->Next) {
41a7dea167SDimitry Andric       Chunk = Chunk->Next;
42a7dea167SDimitry Andric     } else {
4306c3fb27SDimitry Andric       StackChunk *Next = new (std::malloc(ChunkSize)) StackChunk(Chunk);
44a7dea167SDimitry Andric       if (Chunk)
45a7dea167SDimitry Andric         Chunk->Next = Next;
46a7dea167SDimitry Andric       Chunk = Next;
47a7dea167SDimitry Andric     }
48a7dea167SDimitry Andric   }
49a7dea167SDimitry Andric 
50a7dea167SDimitry Andric   auto *Object = reinterpret_cast<void *>(Chunk->End);
51a7dea167SDimitry Andric   Chunk->End += Size;
52a7dea167SDimitry Andric   StackSize += Size;
53a7dea167SDimitry Andric   return Object;
54a7dea167SDimitry Andric }
55a7dea167SDimitry Andric 
5606c3fb27SDimitry Andric void *InterpStack::peekData(size_t Size) const {
57a7dea167SDimitry Andric   assert(Chunk && "Stack is empty!");
58a7dea167SDimitry Andric 
59a7dea167SDimitry Andric   StackChunk *Ptr = Chunk;
60a7dea167SDimitry Andric   while (Size > Ptr->size()) {
61a7dea167SDimitry Andric     Size -= Ptr->size();
62a7dea167SDimitry Andric     Ptr = Ptr->Prev;
63a7dea167SDimitry Andric     assert(Ptr && "Offset too large");
64a7dea167SDimitry Andric   }
65a7dea167SDimitry Andric 
66a7dea167SDimitry Andric   return reinterpret_cast<void *>(Ptr->End - Size);
67a7dea167SDimitry Andric }
68a7dea167SDimitry Andric 
69a7dea167SDimitry Andric void InterpStack::shrink(size_t Size) {
70a7dea167SDimitry Andric   assert(Chunk && "Chunk is empty!");
71a7dea167SDimitry Andric 
72a7dea167SDimitry Andric   while (Size > Chunk->size()) {
73a7dea167SDimitry Andric     Size -= Chunk->size();
74a7dea167SDimitry Andric     if (Chunk->Next) {
7506c3fb27SDimitry Andric       std::free(Chunk->Next);
76a7dea167SDimitry Andric       Chunk->Next = nullptr;
77a7dea167SDimitry Andric     }
78a7dea167SDimitry Andric     Chunk->End = Chunk->start();
79a7dea167SDimitry Andric     Chunk = Chunk->Prev;
80a7dea167SDimitry Andric     assert(Chunk && "Offset too large");
81a7dea167SDimitry Andric   }
82a7dea167SDimitry Andric 
83a7dea167SDimitry Andric   Chunk->End -= Size;
84a7dea167SDimitry Andric   StackSize -= Size;
85a7dea167SDimitry Andric }
8606c3fb27SDimitry Andric 
8706c3fb27SDimitry Andric void InterpStack::dump() const {
8806c3fb27SDimitry Andric #ifndef NDEBUG
89*5f757f3fSDimitry Andric   llvm::errs() << "Items: " << ItemTypes.size() << ". Size: " << size() << '\n';
9006c3fb27SDimitry Andric   if (ItemTypes.empty())
9106c3fb27SDimitry Andric     return;
9206c3fb27SDimitry Andric 
9306c3fb27SDimitry Andric   size_t Index = 0;
94*5f757f3fSDimitry Andric   size_t Offset = 0;
95*5f757f3fSDimitry Andric 
96*5f757f3fSDimitry Andric   // The type of the item on the top of the stack is inserted to the back
97*5f757f3fSDimitry Andric   // of the vector, so the iteration has to happen backwards.
98*5f757f3fSDimitry Andric   for (auto TyIt = ItemTypes.rbegin(); TyIt != ItemTypes.rend(); ++TyIt) {
99*5f757f3fSDimitry Andric     Offset += align(primSize(*TyIt));
100*5f757f3fSDimitry Andric 
101*5f757f3fSDimitry Andric     llvm::errs() << Index << '/' << Offset << ": ";
102*5f757f3fSDimitry Andric     TYPE_SWITCH(*TyIt, {
10306c3fb27SDimitry Andric       const T &V = peek<T>(Offset);
10406c3fb27SDimitry Andric       llvm::errs() << V;
10506c3fb27SDimitry Andric     });
106*5f757f3fSDimitry Andric     llvm::errs() << '\n';
107*5f757f3fSDimitry Andric 
10806c3fb27SDimitry Andric     ++Index;
10906c3fb27SDimitry Andric   }
11006c3fb27SDimitry Andric #endif
11106c3fb27SDimitry Andric }
112