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 "FixedPoint.h" 12 #include "Floating.h" 13 #include "Integral.h" 14 #include "MemberPointer.h" 15 #include "Pointer.h" 16 #include <cassert> 17 #include <cstdlib> 18 19 using namespace clang; 20 using namespace clang::interp; 21 22 InterpStack::~InterpStack() { 23 if (Chunk && Chunk->Next) 24 std::free(Chunk->Next); 25 if (Chunk) 26 std::free(Chunk); 27 Chunk = nullptr; 28 StackSize = 0; 29 #ifndef NDEBUG 30 ItemTypes.clear(); 31 #endif 32 } 33 34 // We keep the last chunk around to reuse. 35 void InterpStack::clear() { 36 if (!Chunk) 37 return; 38 39 if (Chunk->Next) 40 std::free(Chunk->Next); 41 42 assert(Chunk); 43 StackSize = 0; 44 #ifndef NDEBUG 45 ItemTypes.clear(); 46 #endif 47 } 48 49 void InterpStack::clearTo(size_t NewSize) { 50 assert(NewSize <= size()); 51 size_t ToShrink = size() - NewSize; 52 if (ToShrink == 0) 53 return; 54 55 shrink(ToShrink); 56 assert(size() == NewSize); 57 } 58 59 void *InterpStack::grow(size_t Size) { 60 assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large"); 61 62 if (!Chunk || sizeof(StackChunk) + Chunk->size() + Size > ChunkSize) { 63 if (Chunk && Chunk->Next) { 64 Chunk = Chunk->Next; 65 } else { 66 StackChunk *Next = new (std::malloc(ChunkSize)) StackChunk(Chunk); 67 if (Chunk) 68 Chunk->Next = Next; 69 Chunk = Next; 70 } 71 } 72 73 auto *Object = reinterpret_cast<void *>(Chunk->End); 74 Chunk->End += Size; 75 StackSize += Size; 76 return Object; 77 } 78 79 void *InterpStack::peekData(size_t Size) const { 80 assert(Chunk && "Stack is empty!"); 81 82 StackChunk *Ptr = Chunk; 83 while (Size > Ptr->size()) { 84 Size -= Ptr->size(); 85 Ptr = Ptr->Prev; 86 assert(Ptr && "Offset too large"); 87 } 88 89 return reinterpret_cast<void *>(Ptr->End - Size); 90 } 91 92 void InterpStack::shrink(size_t Size) { 93 assert(Chunk && "Chunk is empty!"); 94 95 while (Size > Chunk->size()) { 96 Size -= Chunk->size(); 97 if (Chunk->Next) { 98 std::free(Chunk->Next); 99 Chunk->Next = nullptr; 100 } 101 Chunk->End = Chunk->start(); 102 Chunk = Chunk->Prev; 103 assert(Chunk && "Offset too large"); 104 } 105 106 Chunk->End -= Size; 107 StackSize -= Size; 108 109 #ifndef NDEBUG 110 size_t TypesSize = 0; 111 for (PrimType T : ItemTypes) 112 TYPE_SWITCH(T, { TypesSize += aligned_size<T>(); }); 113 114 size_t StackSize = size(); 115 while (TypesSize > StackSize) { 116 TYPE_SWITCH(ItemTypes.back(), { 117 TypesSize -= aligned_size<T>(); 118 ItemTypes.pop_back(); 119 }); 120 } 121 assert(TypesSize == StackSize); 122 #endif 123 } 124 125 void InterpStack::dump() const { 126 #ifndef NDEBUG 127 llvm::errs() << "Items: " << ItemTypes.size() << ". Size: " << size() << '\n'; 128 if (ItemTypes.empty()) 129 return; 130 131 size_t Index = 0; 132 size_t Offset = 0; 133 134 // The type of the item on the top of the stack is inserted to the back 135 // of the vector, so the iteration has to happen backwards. 136 for (auto TyIt = ItemTypes.rbegin(); TyIt != ItemTypes.rend(); ++TyIt) { 137 Offset += align(primSize(*TyIt)); 138 139 llvm::errs() << Index << '/' << Offset << ": "; 140 TYPE_SWITCH(*TyIt, { 141 const T &V = peek<T>(Offset); 142 llvm::errs() << V; 143 }); 144 llvm::errs() << '\n'; 145 146 ++Index; 147 } 148 #endif 149 } 150