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