| //===--- InterpStack.h - Stack implementation for the VM --------*- C++ -*-===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // Defines the upwards-growing stack used by the interpreter. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H | 
 | #define LLVM_CLANG_AST_INTERP_INTERPSTACK_H | 
 |  | 
 | #include <memory> | 
 |  | 
 | namespace clang { | 
 | namespace interp { | 
 |  | 
 | /// Stack frame storing temporaries and parameters. | 
 | class InterpStack final { | 
 | public: | 
 |   InterpStack() {} | 
 |  | 
 |   /// Destroys the stack, freeing up storage. | 
 |   ~InterpStack(); | 
 |  | 
 |   /// Constructs a value in place on the top of the stack. | 
 |   template <typename T, typename... Tys> void push(Tys &&... Args) { | 
 |     new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...); | 
 |   } | 
 |  | 
 |   /// Returns the value from the top of the stack and removes it. | 
 |   template <typename T> T pop() { | 
 |     auto *Ptr = &peek<T>(); | 
 |     auto Value = std::move(*Ptr); | 
 |     Ptr->~T(); | 
 |     shrink(aligned_size<T>()); | 
 |     return Value; | 
 |   } | 
 |  | 
 |   /// Discards the top value from the stack. | 
 |   template <typename T> void discard() { | 
 |     auto *Ptr = &peek<T>(); | 
 |     Ptr->~T(); | 
 |     shrink(aligned_size<T>()); | 
 |   } | 
 |  | 
 |   /// Returns a reference to the value on the top of the stack. | 
 |   template <typename T> T &peek() { | 
 |     return *reinterpret_cast<T *>(peek(aligned_size<T>())); | 
 |   } | 
 |  | 
 |   /// Returns a pointer to the top object. | 
 |   void *top() { return Chunk ? peek(0) : nullptr; } | 
 |  | 
 |   /// Returns the size of the stack in bytes. | 
 |   size_t size() const { return StackSize; } | 
 |  | 
 |   /// Clears the stack without calling any destructors. | 
 |   void clear(); | 
 |  | 
 | private: | 
 |   /// All stack slots are aligned to the native pointer alignment for storage. | 
 |   /// The size of an object is rounded up to a pointer alignment multiple. | 
 |   template <typename T> constexpr size_t aligned_size() const { | 
 |     constexpr size_t PtrAlign = alignof(void *); | 
 |     return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign; | 
 |   } | 
 |  | 
 |   /// Grows the stack to accommodate a value and returns a pointer to it. | 
 |   void *grow(size_t Size); | 
 |   /// Returns a pointer from the top of the stack. | 
 |   void *peek(size_t Size); | 
 |   /// Shrinks the stack. | 
 |   void shrink(size_t Size); | 
 |  | 
 |   /// Allocate stack space in 1Mb chunks. | 
 |   static constexpr size_t ChunkSize = 1024 * 1024; | 
 |  | 
 |   /// Metadata for each stack chunk. | 
 |   /// | 
 |   /// The stack is composed of a linked list of chunks. Whenever an allocation | 
 |   /// is out of bounds, a new chunk is linked. When a chunk becomes empty, | 
 |   /// it is not immediately freed: a chunk is deallocated only when the | 
 |   /// predecessor becomes empty. | 
 |   struct StackChunk { | 
 |     StackChunk *Next; | 
 |     StackChunk *Prev; | 
 |     char *End; | 
 |  | 
 |     StackChunk(StackChunk *Prev = nullptr) | 
 |         : Next(nullptr), Prev(Prev), End(reinterpret_cast<char *>(this + 1)) {} | 
 |  | 
 |     /// Returns the size of the chunk, minus the header. | 
 |     size_t size() { return End - start(); } | 
 |  | 
 |     /// Returns a pointer to the start of the data region. | 
 |     char *start() { return reinterpret_cast<char *>(this + 1); } | 
 |   }; | 
 |   static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size"); | 
 |  | 
 |   /// First chunk on the stack. | 
 |   StackChunk *Chunk = nullptr; | 
 |   /// Total size of the stack. | 
 |   size_t StackSize = 0; | 
 | }; | 
 |  | 
 | } // namespace interp | 
 | } // namespace clang | 
 |  | 
 | #endif |