xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/InterpStack.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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*0fca6ea1SDimitry Andric #include "MemberPointer.h"
145f757f3fSDimitry Andric #include "Pointer.h"
15a7dea167SDimitry Andric #include <cassert>
16a7dea167SDimitry Andric #include <cstdlib>
17a7dea167SDimitry Andric 
18a7dea167SDimitry Andric using namespace clang;
19a7dea167SDimitry Andric using namespace clang::interp;
20a7dea167SDimitry Andric 
~InterpStack()21a7dea167SDimitry Andric InterpStack::~InterpStack() {
22a7dea167SDimitry Andric   clear();
23a7dea167SDimitry Andric }
24a7dea167SDimitry Andric 
clear()25a7dea167SDimitry Andric void InterpStack::clear() {
26a7dea167SDimitry Andric   if (Chunk && Chunk->Next)
2706c3fb27SDimitry Andric     std::free(Chunk->Next);
28a7dea167SDimitry Andric   if (Chunk)
2906c3fb27SDimitry Andric     std::free(Chunk);
30a7dea167SDimitry Andric   Chunk = nullptr;
31a7dea167SDimitry Andric   StackSize = 0;
3206c3fb27SDimitry Andric #ifndef NDEBUG
3306c3fb27SDimitry Andric   ItemTypes.clear();
3406c3fb27SDimitry Andric #endif
35a7dea167SDimitry Andric }
36a7dea167SDimitry Andric 
grow(size_t Size)37a7dea167SDimitry Andric void *InterpStack::grow(size_t Size) {
38a7dea167SDimitry Andric   assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large");
39a7dea167SDimitry Andric 
40a7dea167SDimitry Andric   if (!Chunk || sizeof(StackChunk) + Chunk->size() + Size > ChunkSize) {
41a7dea167SDimitry Andric     if (Chunk && Chunk->Next) {
42a7dea167SDimitry Andric       Chunk = Chunk->Next;
43a7dea167SDimitry Andric     } else {
4406c3fb27SDimitry Andric       StackChunk *Next = new (std::malloc(ChunkSize)) StackChunk(Chunk);
45a7dea167SDimitry Andric       if (Chunk)
46a7dea167SDimitry Andric         Chunk->Next = Next;
47a7dea167SDimitry Andric       Chunk = Next;
48a7dea167SDimitry Andric     }
49a7dea167SDimitry Andric   }
50a7dea167SDimitry Andric 
51a7dea167SDimitry Andric   auto *Object = reinterpret_cast<void *>(Chunk->End);
52a7dea167SDimitry Andric   Chunk->End += Size;
53a7dea167SDimitry Andric   StackSize += Size;
54a7dea167SDimitry Andric   return Object;
55a7dea167SDimitry Andric }
56a7dea167SDimitry Andric 
peekData(size_t Size) const5706c3fb27SDimitry Andric void *InterpStack::peekData(size_t Size) const {
58a7dea167SDimitry Andric   assert(Chunk && "Stack is empty!");
59a7dea167SDimitry Andric 
60a7dea167SDimitry Andric   StackChunk *Ptr = Chunk;
61a7dea167SDimitry Andric   while (Size > Ptr->size()) {
62a7dea167SDimitry Andric     Size -= Ptr->size();
63a7dea167SDimitry Andric     Ptr = Ptr->Prev;
64a7dea167SDimitry Andric     assert(Ptr && "Offset too large");
65a7dea167SDimitry Andric   }
66a7dea167SDimitry Andric 
67a7dea167SDimitry Andric   return reinterpret_cast<void *>(Ptr->End - Size);
68a7dea167SDimitry Andric }
69a7dea167SDimitry Andric 
shrink(size_t Size)70a7dea167SDimitry Andric void InterpStack::shrink(size_t Size) {
71a7dea167SDimitry Andric   assert(Chunk && "Chunk is empty!");
72a7dea167SDimitry Andric 
73a7dea167SDimitry Andric   while (Size > Chunk->size()) {
74a7dea167SDimitry Andric     Size -= Chunk->size();
75a7dea167SDimitry Andric     if (Chunk->Next) {
7606c3fb27SDimitry Andric       std::free(Chunk->Next);
77a7dea167SDimitry Andric       Chunk->Next = nullptr;
78a7dea167SDimitry Andric     }
79a7dea167SDimitry Andric     Chunk->End = Chunk->start();
80a7dea167SDimitry Andric     Chunk = Chunk->Prev;
81a7dea167SDimitry Andric     assert(Chunk && "Offset too large");
82a7dea167SDimitry Andric   }
83a7dea167SDimitry Andric 
84a7dea167SDimitry Andric   Chunk->End -= Size;
85a7dea167SDimitry Andric   StackSize -= Size;
86a7dea167SDimitry Andric }
8706c3fb27SDimitry Andric 
dump() const8806c3fb27SDimitry Andric void InterpStack::dump() const {
8906c3fb27SDimitry Andric #ifndef NDEBUG
905f757f3fSDimitry Andric   llvm::errs() << "Items: " << ItemTypes.size() << ". Size: " << size() << '\n';
9106c3fb27SDimitry Andric   if (ItemTypes.empty())
9206c3fb27SDimitry Andric     return;
9306c3fb27SDimitry Andric 
9406c3fb27SDimitry Andric   size_t Index = 0;
955f757f3fSDimitry Andric   size_t Offset = 0;
965f757f3fSDimitry Andric 
975f757f3fSDimitry Andric   // The type of the item on the top of the stack is inserted to the back
985f757f3fSDimitry Andric   // of the vector, so the iteration has to happen backwards.
995f757f3fSDimitry Andric   for (auto TyIt = ItemTypes.rbegin(); TyIt != ItemTypes.rend(); ++TyIt) {
1005f757f3fSDimitry Andric     Offset += align(primSize(*TyIt));
1015f757f3fSDimitry Andric 
1025f757f3fSDimitry Andric     llvm::errs() << Index << '/' << Offset << ": ";
1035f757f3fSDimitry Andric     TYPE_SWITCH(*TyIt, {
10406c3fb27SDimitry Andric       const T &V = peek<T>(Offset);
10506c3fb27SDimitry Andric       llvm::errs() << V;
10606c3fb27SDimitry Andric     });
1075f757f3fSDimitry Andric     llvm::errs() << '\n';
1085f757f3fSDimitry Andric 
10906c3fb27SDimitry Andric     ++Index;
11006c3fb27SDimitry Andric   }
11106c3fb27SDimitry Andric #endif
11206c3fb27SDimitry Andric }
113