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