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