You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
4.1 KiB
141 lines
4.1 KiB
//===-- InterpBlock.h - Allocated blocks for the interpreter -*- 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 classes describing allocated blocks.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_AST_INTERP_BLOCK_H
|
|
#define LLVM_CLANG_AST_INTERP_BLOCK_H
|
|
|
|
#include "Descriptor.h"
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/AST/DeclCXX.h"
|
|
#include "clang/AST/Expr.h"
|
|
#include "clang/AST/ComparisonCategories.h"
|
|
#include "llvm/ADT/PointerUnion.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
namespace clang {
|
|
namespace interp {
|
|
class Block;
|
|
class DeadBlock;
|
|
class Context;
|
|
class InterpState;
|
|
class Pointer;
|
|
class Function;
|
|
enum PrimType : unsigned;
|
|
|
|
/// A memory block, either on the stack or in the heap.
|
|
///
|
|
/// The storage described by the block immediately follows it in memory.
|
|
class Block {
|
|
public:
|
|
// Creates a new block.
|
|
Block(const llvm::Optional<unsigned> &DeclID, Descriptor *Desc,
|
|
bool IsStatic = false, bool IsExtern = false)
|
|
: DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
|
|
|
|
Block(Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
|
|
: DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern),
|
|
Desc(Desc) {}
|
|
|
|
/// Returns the block's descriptor.
|
|
Descriptor *getDescriptor() const { return Desc; }
|
|
/// Checks if the block has any live pointers.
|
|
bool hasPointers() const { return Pointers; }
|
|
/// Checks if the block is extern.
|
|
bool isExtern() const { return IsExtern; }
|
|
/// Checks if the block has static storage duration.
|
|
bool isStatic() const { return IsStatic; }
|
|
/// Checks if the block is temporary.
|
|
bool isTemporary() const { return Desc->IsTemporary; }
|
|
/// Returns the size of the block.
|
|
InterpSize getSize() const { return Desc->getAllocSize(); }
|
|
/// Returns the declaration ID.
|
|
llvm::Optional<unsigned> getDeclID() const { return DeclID; }
|
|
|
|
/// Returns a pointer to the stored data.
|
|
char *data() { return reinterpret_cast<char *>(this + 1); }
|
|
|
|
/// Returns a view over the data.
|
|
template <typename T>
|
|
T &deref() { return *reinterpret_cast<T *>(data()); }
|
|
|
|
/// Invokes the constructor.
|
|
void invokeCtor() {
|
|
std::memset(data(), 0, getSize());
|
|
if (Desc->CtorFn)
|
|
Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
|
|
/*isActive=*/true, Desc);
|
|
}
|
|
|
|
protected:
|
|
friend class Pointer;
|
|
friend class DeadBlock;
|
|
friend class InterpState;
|
|
|
|
Block(Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead)
|
|
: IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {}
|
|
|
|
// Deletes a dead block at the end of its lifetime.
|
|
void cleanup();
|
|
|
|
// Pointer chain management.
|
|
void addPointer(Pointer *P);
|
|
void removePointer(Pointer *P);
|
|
void movePointer(Pointer *From, Pointer *To);
|
|
|
|
/// Start of the chain of pointers.
|
|
Pointer *Pointers = nullptr;
|
|
/// Unique identifier of the declaration.
|
|
llvm::Optional<unsigned> DeclID;
|
|
/// Flag indicating if the block has static storage duration.
|
|
bool IsStatic = false;
|
|
/// Flag indicating if the block is an extern.
|
|
bool IsExtern = false;
|
|
/// Flag indicating if the pointer is dead.
|
|
bool IsDead = false;
|
|
/// Pointer to the stack slot descriptor.
|
|
Descriptor *Desc;
|
|
};
|
|
|
|
/// Descriptor for a dead block.
|
|
///
|
|
/// Dead blocks are chained in a double-linked list to deallocate them
|
|
/// whenever pointers become dead.
|
|
class DeadBlock {
|
|
public:
|
|
/// Copies the block.
|
|
DeadBlock(DeadBlock *&Root, Block *Blk);
|
|
|
|
/// Returns a pointer to the stored data.
|
|
char *data() { return B.data(); }
|
|
|
|
private:
|
|
friend class Block;
|
|
friend class InterpState;
|
|
|
|
void free();
|
|
|
|
/// Root pointer of the list.
|
|
DeadBlock *&Root;
|
|
/// Previous block in the list.
|
|
DeadBlock *Prev;
|
|
/// Next block in the list.
|
|
DeadBlock *Next;
|
|
|
|
/// Actual block storing data and tracking pointers.
|
|
Block B;
|
|
};
|
|
|
|
} // namespace interp
|
|
} // namespace clang
|
|
|
|
#endif
|