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