Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/InterpStack.h
35292 views
//===--- InterpStack.h - Stack implementation for the VM --------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines the upwards-growing stack used by the interpreter.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H13#define LLVM_CLANG_AST_INTERP_INTERPSTACK_H1415#include "FunctionPointer.h"16#include "IntegralAP.h"17#include "MemberPointer.h"18#include "PrimType.h"19#include <memory>20#include <vector>2122namespace clang {23namespace interp {2425/// Stack frame storing temporaries and parameters.26class InterpStack final {27public:28InterpStack() {}2930/// Destroys the stack, freeing up storage.31~InterpStack();3233/// Constructs a value in place on the top of the stack.34template <typename T, typename... Tys> void push(Tys &&... Args) {35new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...);36#ifndef NDEBUG37ItemTypes.push_back(toPrimType<T>());38#endif39}4041/// Returns the value from the top of the stack and removes it.42template <typename T> T pop() {43#ifndef NDEBUG44assert(!ItemTypes.empty());45assert(ItemTypes.back() == toPrimType<T>());46ItemTypes.pop_back();47#endif48T *Ptr = &peekInternal<T>();49T Value = std::move(*Ptr);50shrink(aligned_size<T>());51return Value;52}5354/// Discards the top value from the stack.55template <typename T> void discard() {56#ifndef NDEBUG57assert(!ItemTypes.empty());58assert(ItemTypes.back() == toPrimType<T>());59ItemTypes.pop_back();60#endif61T *Ptr = &peekInternal<T>();62Ptr->~T();63shrink(aligned_size<T>());64}6566/// Returns a reference to the value on the top of the stack.67template <typename T> T &peek() const {68#ifndef NDEBUG69assert(!ItemTypes.empty());70assert(ItemTypes.back() == toPrimType<T>());71#endif72return peekInternal<T>();73}7475template <typename T> T &peek(size_t Offset) const {76assert(aligned(Offset));77return *reinterpret_cast<T *>(peekData(Offset));78}7980/// Returns a pointer to the top object.81void *top() const { return Chunk ? peekData(0) : nullptr; }8283/// Returns the size of the stack in bytes.84size_t size() const { return StackSize; }8586/// Clears the stack without calling any destructors.87void clear();8889/// Returns whether the stack is empty.90bool empty() const { return StackSize == 0; }9192/// dump the stack contents to stderr.93void dump() const;9495private:96/// All stack slots are aligned to the native pointer alignment for storage.97/// The size of an object is rounded up to a pointer alignment multiple.98template <typename T> constexpr size_t aligned_size() const {99constexpr size_t PtrAlign = alignof(void *);100return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign;101}102103/// Like the public peek(), but without the debug type checks.104template <typename T> T &peekInternal() const {105return *reinterpret_cast<T *>(peekData(aligned_size<T>()));106}107108/// Grows the stack to accommodate a value and returns a pointer to it.109void *grow(size_t Size);110/// Returns a pointer from the top of the stack.111void *peekData(size_t Size) const;112/// Shrinks the stack.113void shrink(size_t Size);114115/// Allocate stack space in 1Mb chunks.116static constexpr size_t ChunkSize = 1024 * 1024;117118/// Metadata for each stack chunk.119///120/// The stack is composed of a linked list of chunks. Whenever an allocation121/// is out of bounds, a new chunk is linked. When a chunk becomes empty,122/// it is not immediately freed: a chunk is deallocated only when the123/// predecessor becomes empty.124struct StackChunk {125StackChunk *Next;126StackChunk *Prev;127char *End;128129StackChunk(StackChunk *Prev = nullptr)130: Next(nullptr), Prev(Prev), End(reinterpret_cast<char *>(this + 1)) {}131132/// Returns the size of the chunk, minus the header.133size_t size() const { return End - start(); }134135/// Returns a pointer to the start of the data region.136char *start() { return reinterpret_cast<char *>(this + 1); }137const char *start() const {138return reinterpret_cast<const char *>(this + 1);139}140};141static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size");142143/// First chunk on the stack.144StackChunk *Chunk = nullptr;145/// Total size of the stack.146size_t StackSize = 0;147148#ifndef NDEBUG149/// vector recording the type of data we pushed into the stack.150std::vector<PrimType> ItemTypes;151152template <typename T> static constexpr PrimType toPrimType() {153if constexpr (std::is_same_v<T, Pointer>)154return PT_Ptr;155else if constexpr (std::is_same_v<T, bool> ||156std::is_same_v<T, Boolean>)157return PT_Bool;158else if constexpr (std::is_same_v<T, int8_t> ||159std::is_same_v<T, Integral<8, true>>)160return PT_Sint8;161else if constexpr (std::is_same_v<T, uint8_t> ||162std::is_same_v<T, Integral<8, false>>)163return PT_Uint8;164else if constexpr (std::is_same_v<T, int16_t> ||165std::is_same_v<T, Integral<16, true>>)166return PT_Sint16;167else if constexpr (std::is_same_v<T, uint16_t> ||168std::is_same_v<T, Integral<16, false>>)169return PT_Uint16;170else if constexpr (std::is_same_v<T, int32_t> ||171std::is_same_v<T, Integral<32, true>>)172return PT_Sint32;173else if constexpr (std::is_same_v<T, uint32_t> ||174std::is_same_v<T, Integral<32, false>>)175return PT_Uint32;176else if constexpr (std::is_same_v<T, int64_t> ||177std::is_same_v<T, Integral<64, true>>)178return PT_Sint64;179else if constexpr (std::is_same_v<T, uint64_t> ||180std::is_same_v<T, Integral<64, false>>)181return PT_Uint64;182else if constexpr (std::is_same_v<T, Floating>)183return PT_Float;184else if constexpr (std::is_same_v<T, FunctionPointer>)185return PT_FnPtr;186else if constexpr (std::is_same_v<T, IntegralAP<true>>)187return PT_IntAP;188else if constexpr (std::is_same_v<T, IntegralAP<false>>)189return PT_IntAP;190else if constexpr (std::is_same_v<T, MemberPointer>)191return PT_MemberPtr;192193llvm_unreachable("unknown type push()'ed into InterpStack");194}195#endif196};197198} // namespace interp199} // namespace clang200201#endif202203204