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 <cassert>
14 #include <cstdlib>
15 
16 using namespace clang;
17 using namespace clang::interp;
18 
19 InterpStack::~InterpStack() {
20   clear();
21 }
22 
23 void InterpStack::clear() {
24   if (Chunk && Chunk->Next)
25     std::free(Chunk->Next);
26   if (Chunk)
27     std::free(Chunk);
28   Chunk = nullptr;
29   StackSize = 0;
30 #ifndef NDEBUG
31   ItemTypes.clear();
32 #endif
33 }
34 
35 void *InterpStack::grow(size_t Size) {
36   assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large");
37 
38   if (!Chunk || sizeof(StackChunk) + Chunk->size() + Size > ChunkSize) {
39     if (Chunk && Chunk->Next) {
40       Chunk = Chunk->Next;
41     } else {
42       StackChunk *Next = new (std::malloc(ChunkSize)) StackChunk(Chunk);
43       if (Chunk)
44         Chunk->Next = Next;
45       Chunk = Next;
46     }
47   }
48 
49   auto *Object = reinterpret_cast<void *>(Chunk->End);
50   Chunk->End += Size;
51   StackSize += Size;
52   return Object;
53 }
54 
55 void *InterpStack::peekData(size_t Size) const {
56   assert(Chunk && "Stack is empty!");
57 
58   StackChunk *Ptr = Chunk;
59   while (Size > Ptr->size()) {
60     Size -= Ptr->size();
61     Ptr = Ptr->Prev;
62     assert(Ptr && "Offset too large");
63   }
64 
65   return reinterpret_cast<void *>(Ptr->End - Size);
66 }
67 
68 void InterpStack::shrink(size_t Size) {
69   assert(Chunk && "Chunk is empty!");
70 
71   while (Size > Chunk->size()) {
72     Size -= Chunk->size();
73     if (Chunk->Next) {
74       std::free(Chunk->Next);
75       Chunk->Next = nullptr;
76     }
77     Chunk->End = Chunk->start();
78     Chunk = Chunk->Prev;
79     assert(Chunk && "Offset too large");
80   }
81 
82   Chunk->End -= Size;
83   StackSize -= Size;
84 }
85 
86 void InterpStack::dump() const {
87 #ifndef NDEBUG
88   llvm::errs() << "Items: " << ItemTypes.size() << ". Size: " << size() << "\n";
89   if (ItemTypes.empty())
90     return;
91 
92   size_t Index = 0;
93   size_t Offset = align(primSize(ItemTypes[0]));
94   for (PrimType Ty : ItemTypes) {
95     llvm::errs() << Index << "/" << Offset << ": ";
96     TYPE_SWITCH(Ty, {
97       const T &V = peek<T>(Offset);
98       llvm::errs() << V;
99     });
100     llvm::errs() << "\n";
101     Offset += align(primSize(Ty));
102     ++Index;
103   }
104 #endif
105 }
106