1*a7dea167SDimitry Andric //===--- InterpStack.h - Stack implementation for the VM --------*- C++ -*-===// 2*a7dea167SDimitry Andric // 3*a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*a7dea167SDimitry Andric // 7*a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8*a7dea167SDimitry Andric // 9*a7dea167SDimitry Andric // Defines the upwards-growing stack used by the interpreter. 10*a7dea167SDimitry Andric // 11*a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 12*a7dea167SDimitry Andric 13*a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H 14*a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_INTERPSTACK_H 15*a7dea167SDimitry Andric 16*a7dea167SDimitry Andric #include <memory> 17*a7dea167SDimitry Andric 18*a7dea167SDimitry Andric namespace clang { 19*a7dea167SDimitry Andric namespace interp { 20*a7dea167SDimitry Andric 21*a7dea167SDimitry Andric /// Stack frame storing temporaries and parameters. 22*a7dea167SDimitry Andric class InterpStack final { 23*a7dea167SDimitry Andric public: 24*a7dea167SDimitry Andric InterpStack() {} 25*a7dea167SDimitry Andric 26*a7dea167SDimitry Andric /// Destroys the stack, freeing up storage. 27*a7dea167SDimitry Andric ~InterpStack(); 28*a7dea167SDimitry Andric 29*a7dea167SDimitry Andric /// Constructs a value in place on the top of the stack. 30*a7dea167SDimitry Andric template <typename T, typename... Tys> void push(Tys &&... Args) { 31*a7dea167SDimitry Andric new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...); 32*a7dea167SDimitry Andric } 33*a7dea167SDimitry Andric 34*a7dea167SDimitry Andric /// Returns the value from the top of the stack and removes it. 35*a7dea167SDimitry Andric template <typename T> T pop() { 36*a7dea167SDimitry Andric auto *Ptr = &peek<T>(); 37*a7dea167SDimitry Andric auto Value = std::move(*Ptr); 38*a7dea167SDimitry Andric Ptr->~T(); 39*a7dea167SDimitry Andric shrink(aligned_size<T>()); 40*a7dea167SDimitry Andric return Value; 41*a7dea167SDimitry Andric } 42*a7dea167SDimitry Andric 43*a7dea167SDimitry Andric /// Discards the top value from the stack. 44*a7dea167SDimitry Andric template <typename T> void discard() { 45*a7dea167SDimitry Andric auto *Ptr = &peek<T>(); 46*a7dea167SDimitry Andric Ptr->~T(); 47*a7dea167SDimitry Andric shrink(aligned_size<T>()); 48*a7dea167SDimitry Andric } 49*a7dea167SDimitry Andric 50*a7dea167SDimitry Andric /// Returns a reference to the value on the top of the stack. 51*a7dea167SDimitry Andric template <typename T> T &peek() { 52*a7dea167SDimitry Andric return *reinterpret_cast<T *>(peek(aligned_size<T>())); 53*a7dea167SDimitry Andric } 54*a7dea167SDimitry Andric 55*a7dea167SDimitry Andric /// Returns a pointer to the top object. 56*a7dea167SDimitry Andric void *top() { return Chunk ? peek(0) : nullptr; } 57*a7dea167SDimitry Andric 58*a7dea167SDimitry Andric /// Returns the size of the stack in bytes. 59*a7dea167SDimitry Andric size_t size() const { return StackSize; } 60*a7dea167SDimitry Andric 61*a7dea167SDimitry Andric /// Clears the stack without calling any destructors. 62*a7dea167SDimitry Andric void clear(); 63*a7dea167SDimitry Andric 64*a7dea167SDimitry Andric private: 65*a7dea167SDimitry Andric /// All stack slots are aligned to the native pointer alignment for storage. 66*a7dea167SDimitry Andric /// The size of an object is rounded up to a pointer alignment multiple. 67*a7dea167SDimitry Andric template <typename T> constexpr size_t aligned_size() const { 68*a7dea167SDimitry Andric constexpr size_t PtrAlign = alignof(void *); 69*a7dea167SDimitry Andric return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign; 70*a7dea167SDimitry Andric } 71*a7dea167SDimitry Andric 72*a7dea167SDimitry Andric /// Grows the stack to accomodate a value and returns a pointer to it. 73*a7dea167SDimitry Andric void *grow(size_t Size); 74*a7dea167SDimitry Andric /// Returns a pointer from the top of the stack. 75*a7dea167SDimitry Andric void *peek(size_t Size); 76*a7dea167SDimitry Andric /// Shrinks the stack. 77*a7dea167SDimitry Andric void shrink(size_t Size); 78*a7dea167SDimitry Andric 79*a7dea167SDimitry Andric /// Allocate stack space in 1Mb chunks. 80*a7dea167SDimitry Andric static constexpr size_t ChunkSize = 1024 * 1024; 81*a7dea167SDimitry Andric 82*a7dea167SDimitry Andric /// Metadata for each stack chunk. 83*a7dea167SDimitry Andric /// 84*a7dea167SDimitry Andric /// The stack is composed of a linked list of chunks. Whenever an allocation 85*a7dea167SDimitry Andric /// is out of bounds, a new chunk is linked. When a chunk becomes empty, 86*a7dea167SDimitry Andric /// it is not immediately freed: a chunk is deallocated only when the 87*a7dea167SDimitry Andric /// predecessor becomes empty. 88*a7dea167SDimitry Andric struct StackChunk { 89*a7dea167SDimitry Andric StackChunk *Next; 90*a7dea167SDimitry Andric StackChunk *Prev; 91*a7dea167SDimitry Andric char *End; 92*a7dea167SDimitry Andric 93*a7dea167SDimitry Andric StackChunk(StackChunk *Prev = nullptr) 94*a7dea167SDimitry Andric : Next(nullptr), Prev(Prev), End(reinterpret_cast<char *>(this + 1)) {} 95*a7dea167SDimitry Andric 96*a7dea167SDimitry Andric /// Returns the size of the chunk, minus the header. 97*a7dea167SDimitry Andric size_t size() { return End - start(); } 98*a7dea167SDimitry Andric 99*a7dea167SDimitry Andric /// Returns a pointer to the start of the data region. 100*a7dea167SDimitry Andric char *start() { return reinterpret_cast<char *>(this + 1); } 101*a7dea167SDimitry Andric }; 102*a7dea167SDimitry Andric static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size"); 103*a7dea167SDimitry Andric 104*a7dea167SDimitry Andric /// First chunk on the stack. 105*a7dea167SDimitry Andric StackChunk *Chunk = nullptr; 106*a7dea167SDimitry Andric /// Total size of the stack. 107*a7dea167SDimitry Andric size_t StackSize = 0; 108*a7dea167SDimitry Andric }; 109*a7dea167SDimitry Andric 110*a7dea167SDimitry Andric } // namespace interp 111*a7dea167SDimitry Andric } // namespace clang 112*a7dea167SDimitry Andric 113*a7dea167SDimitry Andric #endif 114