Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/InterpStack.h
213799 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 "FixedPoint.h"16#include "FunctionPointer.h"17#include "IntegralAP.h"18#include "MemberPointer.h"19#include "PrimType.h"20#include <memory>21#include <vector>2223namespace clang {24namespace interp {2526/// Stack frame storing temporaries and parameters.27class InterpStack final {28public:29InterpStack() {}3031/// Destroys the stack, freeing up storage.32~InterpStack();3334/// Constructs a value in place on the top of the stack.35template <typename T, typename... Tys> void push(Tys &&...Args) {36new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...);37#ifndef NDEBUG38ItemTypes.push_back(toPrimType<T>());39#endif40}4142/// Returns the value from the top of the stack and removes it.43template <typename T> T pop() {44#ifndef NDEBUG45assert(!ItemTypes.empty());46assert(ItemTypes.back() == toPrimType<T>());47ItemTypes.pop_back();48#endif49T *Ptr = &peekInternal<T>();50T Value = std::move(*Ptr);51shrink(aligned_size<T>());52return Value;53}5455/// Discards the top value from the stack.56template <typename T> void discard() {57#ifndef NDEBUG58assert(!ItemTypes.empty());59assert(ItemTypes.back() == toPrimType<T>());60ItemTypes.pop_back();61#endif62T *Ptr = &peekInternal<T>();63Ptr->~T();64shrink(aligned_size<T>());65}6667/// Returns a reference to the value on the top of the stack.68template <typename T> T &peek() const {69#ifndef NDEBUG70assert(!ItemTypes.empty());71assert(ItemTypes.back() == toPrimType<T>());72#endif73return peekInternal<T>();74}7576template <typename T> T &peek(size_t Offset) const {77assert(aligned(Offset));78return *reinterpret_cast<T *>(peekData(Offset));79}8081/// Returns a pointer to the top object.82void *top() const { return Chunk ? peekData(0) : nullptr; }8384/// Returns the size of the stack in bytes.85size_t size() const { return StackSize; }8687/// Clears the stack without calling any destructors.88void clear();89void clearTo(size_t NewSize);9091/// Returns whether the stack is empty.92bool empty() const { return StackSize == 0; }9394/// dump the stack contents to stderr.95void dump() const;9697private:98/// All stack slots are aligned to the native pointer alignment for storage.99/// The size of an object is rounded up to a pointer alignment multiple.100template <typename T> constexpr size_t aligned_size() const {101constexpr size_t PtrAlign = alignof(void *);102return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign;103}104105/// Like the public peek(), but without the debug type checks.106template <typename T> T &peekInternal() const {107return *reinterpret_cast<T *>(peekData(aligned_size<T>()));108}109110/// Grows the stack to accommodate a value and returns a pointer to it.111void *grow(size_t Size);112/// Returns a pointer from the top of the stack.113void *peekData(size_t Size) const;114/// Shrinks the stack.115void shrink(size_t Size);116117/// Allocate stack space in 1Mb chunks.118static constexpr size_t ChunkSize = 1024 * 1024;119120/// Metadata for each stack chunk.121///122/// The stack is composed of a linked list of chunks. Whenever an allocation123/// is out of bounds, a new chunk is linked. When a chunk becomes empty,124/// it is not immediately freed: a chunk is deallocated only when the125/// predecessor becomes empty.126struct StackChunk {127StackChunk *Next;128StackChunk *Prev;129char *End;130131StackChunk(StackChunk *Prev = nullptr)132: Next(nullptr), Prev(Prev), End(reinterpret_cast<char *>(this + 1)) {}133134/// Returns the size of the chunk, minus the header.135size_t size() const { return End - start(); }136137/// Returns a pointer to the start of the data region.138char *start() { return reinterpret_cast<char *>(this + 1); }139const char *start() const {140return reinterpret_cast<const char *>(this + 1);141}142};143static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size");144145/// First chunk on the stack.146StackChunk *Chunk = nullptr;147/// Total size of the stack.148size_t StackSize = 0;149150#ifndef NDEBUG151/// vector recording the type of data we pushed into the stack.152std::vector<PrimType> ItemTypes;153154template <typename T> static constexpr PrimType toPrimType() {155if constexpr (std::is_same_v<T, Pointer>)156return PT_Ptr;157else if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, Boolean>)158return PT_Bool;159else if constexpr (std::is_same_v<T, int8_t> ||160std::is_same_v<T, Integral<8, true>>)161return PT_Sint8;162else if constexpr (std::is_same_v<T, uint8_t> ||163std::is_same_v<T, Integral<8, false>>)164return PT_Uint8;165else if constexpr (std::is_same_v<T, int16_t> ||166std::is_same_v<T, Integral<16, true>>)167return PT_Sint16;168else if constexpr (std::is_same_v<T, uint16_t> ||169std::is_same_v<T, Integral<16, false>>)170return PT_Uint16;171else if constexpr (std::is_same_v<T, int32_t> ||172std::is_same_v<T, Integral<32, true>>)173return PT_Sint32;174else if constexpr (std::is_same_v<T, uint32_t> ||175std::is_same_v<T, Integral<32, false>>)176return PT_Uint32;177else if constexpr (std::is_same_v<T, int64_t> ||178std::is_same_v<T, Integral<64, true>>)179return PT_Sint64;180else if constexpr (std::is_same_v<T, uint64_t> ||181std::is_same_v<T, Integral<64, false>>)182return PT_Uint64;183else if constexpr (std::is_same_v<T, Floating>)184return PT_Float;185else if constexpr (std::is_same_v<T, IntegralAP<true>>)186return PT_IntAP;187else if constexpr (std::is_same_v<T, IntegralAP<false>>)188return PT_IntAP;189else if constexpr (std::is_same_v<T, MemberPointer>)190return PT_MemberPtr;191else if constexpr (std::is_same_v<T, FixedPoint>)192return PT_FixedPoint;193194llvm_unreachable("unknown type push()'ed into InterpStack");195}196#endif197};198199} // namespace interp200} // namespace clang201202#endif203204205