#ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H
#define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
#include "FunctionPointer.h"
#include "IntegralAP.h"
#include "MemberPointer.h"
#include "PrimType.h"
#include <memory>
#include <vector>
namespace clang {
namespace interp {
class InterpStack final {
public:
InterpStack() {}
~InterpStack();
template <typename T, typename... Tys> void push(Tys &&... Args) {
new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...);
#ifndef NDEBUG
ItemTypes.push_back(toPrimType<T>());
#endif
}
template <typename T> T pop() {
#ifndef NDEBUG
assert(!ItemTypes.empty());
assert(ItemTypes.back() == toPrimType<T>());
ItemTypes.pop_back();
#endif
T *Ptr = &peekInternal<T>();
T Value = std::move(*Ptr);
shrink(aligned_size<T>());
return Value;
}
template <typename T> void discard() {
#ifndef NDEBUG
assert(!ItemTypes.empty());
assert(ItemTypes.back() == toPrimType<T>());
ItemTypes.pop_back();
#endif
T *Ptr = &peekInternal<T>();
Ptr->~T();
shrink(aligned_size<T>());
}
template <typename T> T &peek() const {
#ifndef NDEBUG
assert(!ItemTypes.empty());
assert(ItemTypes.back() == toPrimType<T>());
#endif
return peekInternal<T>();
}
template <typename T> T &peek(size_t Offset) const {
assert(aligned(Offset));
return *reinterpret_cast<T *>(peekData(Offset));
}
void *top() const { return Chunk ? peekData(0) : nullptr; }
size_t size() const { return StackSize; }
void clear();
bool empty() const { return StackSize == 0; }
void dump() const;
private:
template <typename T> constexpr size_t aligned_size() const {
constexpr size_t PtrAlign = alignof(void *);
return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign;
}
template <typename T> T &peekInternal() const {
return *reinterpret_cast<T *>(peekData(aligned_size<T>()));
}
void *grow(size_t Size);
void *peekData(size_t Size) const;
void shrink(size_t Size);
static constexpr size_t ChunkSize = 1024 * 1024;
struct StackChunk {
StackChunk *Next;
StackChunk *Prev;
char *End;
StackChunk(StackChunk *Prev = nullptr)
: Next(nullptr), Prev(Prev), End(reinterpret_cast<char *>(this + 1)) {}
size_t size() const { return End - start(); }
char *start() { return reinterpret_cast<char *>(this + 1); }
const char *start() const {
return reinterpret_cast<const char *>(this + 1);
}
};
static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size");
StackChunk *Chunk = nullptr;
size_t StackSize = 0;
#ifndef NDEBUG
std::vector<PrimType> ItemTypes;
template <typename T> static constexpr PrimType toPrimType() {
if constexpr (std::is_same_v<T, Pointer>)
return PT_Ptr;
else if constexpr (std::is_same_v<T, bool> ||
std::is_same_v<T, Boolean>)
return PT_Bool;
else if constexpr (std::is_same_v<T, int8_t> ||
std::is_same_v<T, Integral<8, true>>)
return PT_Sint8;
else if constexpr (std::is_same_v<T, uint8_t> ||
std::is_same_v<T, Integral<8, false>>)
return PT_Uint8;
else if constexpr (std::is_same_v<T, int16_t> ||
std::is_same_v<T, Integral<16, true>>)
return PT_Sint16;
else if constexpr (std::is_same_v<T, uint16_t> ||
std::is_same_v<T, Integral<16, false>>)
return PT_Uint16;
else if constexpr (std::is_same_v<T, int32_t> ||
std::is_same_v<T, Integral<32, true>>)
return PT_Sint32;
else if constexpr (std::is_same_v<T, uint32_t> ||
std::is_same_v<T, Integral<32, false>>)
return PT_Uint32;
else if constexpr (std::is_same_v<T, int64_t> ||
std::is_same_v<T, Integral<64, true>>)
return PT_Sint64;
else if constexpr (std::is_same_v<T, uint64_t> ||
std::is_same_v<T, Integral<64, false>>)
return PT_Uint64;
else if constexpr (std::is_same_v<T, Floating>)
return PT_Float;
else if constexpr (std::is_same_v<T, FunctionPointer>)
return PT_FnPtr;
else if constexpr (std::is_same_v<T, IntegralAP<true>>)
return PT_IntAP;
else if constexpr (std::is_same_v<T, IntegralAP<false>>)
return PT_IntAP;
else if constexpr (std::is_same_v<T, MemberPointer>)
return PT_MemberPtr;
llvm_unreachable("unknown type push()'ed into InterpStack");
}
#endif
};
}
}
#endif