[clang] [clang][bytecode] Allocate Record fields, bases and virtual bases in Record tail storage (PR #185902)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 11 08:29:57 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
So we can do one heap allocation for the entire record (minus whatever the dense maps allocate). Also use the program allocator for the Function instances.
---
Full diff: https://github.com/llvm/llvm-project/pull/185902.diff
4 Files Affected:
- (modified) clang/lib/AST/ByteCode/Program.cpp (+52-18)
- (modified) clang/lib/AST/ByteCode/Program.h (+11-9)
- (modified) clang/lib/AST/ByteCode/Record.cpp (+5-21)
- (modified) clang/lib/AST/ByteCode/Record.h (+43-30)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp
index efef5db177e56..61df6618ce4e3 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -281,7 +281,7 @@ Function *Program::getFunction(const FunctionDecl *F) {
F = F->getCanonicalDecl();
assert(F);
auto It = Funcs.find(F);
- return It == Funcs.end() ? nullptr : It->second.get();
+ return It == Funcs.end() ? nullptr : It->second;
}
Record *Program::getOrCreateRecord(const RecordDecl *RD) {
@@ -300,11 +300,6 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
if (!Inserted)
return It->second;
- // Number of bytes required by fields and base classes.
- unsigned BaseSize = 0;
- // Number of bytes required by virtual base.
- unsigned VirtSize = 0;
-
// Helper to get a base descriptor.
auto GetBaseDesc = [this](const RecordDecl *BD,
const Record *BR) -> const Descriptor * {
@@ -316,10 +311,28 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
};
// Reserve space for base classes.
- Record::BaseList Bases;
- Record::VirtualBaseList VirtBases;
+ unsigned NumRecordBases = 0;
+ unsigned NumRecordVBases = 0;
+ unsigned NumFields = RD->getNumFields();
+ if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
+ NumRecordBases = CD->getNumBases();
+ NumRecordVBases = CD->getNumVBases();
+ }
+
+ char *Memory = new (*this) char[Record::allocSize(NumFields, NumRecordBases,
+ NumRecordVBases)];
+ Record *R =
+ new (Memory) Record(RD, NumRecordBases, NumFields, NumRecordVBases);
+ bool HasPtrField = false;
+
+ // Number of bytes required by fields and base classes.
+ unsigned BaseSize = 0;
+ // Number of bytes required by virtual base.
+ unsigned VirtSize = 0;
+
if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
- Bases.reserve(CD->getNumBases());
+ unsigned BaseIndex = 0;
+ Record::Base *Bases = R->getBases();
for (const CXXBaseSpecifier &Spec : CD->bases()) {
if (Spec.isVirtual())
continue;
@@ -335,28 +348,40 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
return nullptr;
BaseSize += align(sizeof(InlineDescriptor));
- Bases.emplace_back(BD, Desc, BR, BaseSize);
+ Record::Base *B =
+ new (&Bases[BaseIndex]) Record::Base(BD, Desc, BR, BaseSize);
BaseSize += align(BR->getSize());
+ ++BaseIndex;
+ R->BaseMap[B->Decl] = B;
+ if (!HasPtrField)
+ HasPtrField |= B->R->hasPtrField();
}
+ R->NumBases = BaseIndex;
+ unsigned VBaseIndex = 0;
+ Record::Base *VBases = R->getVBases();
for (const CXXBaseSpecifier &Spec : CD->vbases()) {
const auto *BD = Spec.getType()->castAsCXXRecordDecl();
const Record *BR = getOrCreateRecord(BD);
+ if (!BR)
+ return nullptr;
+
const Descriptor *Desc = GetBaseDesc(BD, BR);
if (!Desc)
return nullptr;
VirtSize += align(sizeof(InlineDescriptor));
- VirtBases.emplace_back(BD, Desc, BR, VirtSize);
+ new (&VBases[VBaseIndex]) Record::Base(BD, Desc, BR, VirtSize);
VirtSize += align(BR->getSize());
+ ++VBaseIndex;
}
+ R->NumVBases = VBaseIndex;
}
// Reserve space for fields.
- Record::FieldList Fields;
- Fields.reserve(RD->getNumFields());
- bool HasPtrField = false;
+ Record::Field *Fields = R->getFields();
+ unsigned FieldIndex = 0;
for (const FieldDecl *FD : RD->fields()) {
FD = FD->getFirstDecl();
// Note that we DO create fields and descriptors
@@ -386,13 +411,22 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
} else {
return nullptr;
}
- Fields.emplace_back(FD, Desc, BaseSize);
+ new (&Fields[FieldIndex]) Record::Field(FD, Desc, BaseSize);
BaseSize += align(Desc->getAllocSize());
+ ++FieldIndex;
+ }
+
+ for (unsigned I = 0; I != R->getNumVirtualBases(); ++I) {
+ Record::Base *V = &R->getVBases()[I];
+ V->Offset += BaseSize;
+ R->VirtualBaseMap[V->Decl] = V;
+ if (!HasPtrField)
+ HasPtrField |= V->R->hasPtrField();
}
- Record *R = new (Allocator)
- Record(RD, std::move(Bases), std::move(Fields), std::move(VirtBases),
- VirtSize, BaseSize, HasPtrField);
+ R->HasPtrField = HasPtrField;
+ R->VirtualSize = VirtSize;
+ R->BaseSize = BaseSize;
Records[RD] = R;
return R;
}
diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h
index c8795504391fa..2ad48799d1b20 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -52,6 +52,9 @@ class Program final {
if (Record *R = RecordPair.second)
R->~Record();
}
+
+ for (Function *F : Funcs.values())
+ F->~Function();
}
/// Marshals a native pointer to an ID for embedding in bytecode.
@@ -98,8 +101,9 @@ class Program final {
template <typename... Ts>
Function *createFunction(const FunctionDecl *Def, Ts &&...Args) {
Def = Def->getCanonicalDecl();
- auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
- Funcs.insert({Def, std::unique_ptr<Function>(Func)});
+ auto *Func =
+ new (Allocator) Function(*this, Def, std::forward<Ts>(Args)...);
+ Funcs.insert({Def, Func});
return Func;
}
/// Creates an anonymous function.
@@ -171,8 +175,12 @@ class Program final {
/// Reference to the VM context.
Context &Ctx;
+ /// Custom allocator for global storage.
+ using PoolAllocTy = llvm::BumpPtrAllocator;
+ /// Allocator for globals.
+ mutable PoolAllocTy Allocator;
/// Mapping from decls to cached bytecode functions.
- llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
+ llvm::DenseMap<const FunctionDecl *, Function *> Funcs;
/// List of anonymous functions.
std::vector<std::unique_ptr<Function>> AnonFuncs;
@@ -181,9 +189,6 @@ class Program final {
/// Cached native pointer indices.
llvm::DenseMap<const void *, unsigned> NativePointerIndices;
- /// Custom allocator for global storage.
- using PoolAllocTy = llvm::BumpPtrAllocator;
-
/// Descriptor + storage for a global object.
///
/// Global objects never go out of scope, thus they do not track pointers.
@@ -208,9 +213,6 @@ class Program final {
Block B;
};
- /// Allocator for globals.
- mutable PoolAllocTy Allocator;
-
/// Global objects.
std::vector<Global *> Globals;
/// Cached global indices.
diff --git a/clang/lib/AST/ByteCode/Record.cpp b/clang/lib/AST/ByteCode/Record.cpp
index 13a5ffb85787c..552ba78f76ae0 100644
--- a/clang/lib/AST/ByteCode/Record.cpp
+++ b/clang/lib/AST/ByteCode/Record.cpp
@@ -12,27 +12,11 @@
using namespace clang;
using namespace clang::interp;
-Record::Record(const RecordDecl *Decl, BaseList &&SrcBases,
- FieldList &&SrcFields, VirtualBaseList &&SrcVirtualBases,
- unsigned VirtualSize, unsigned BaseSize, bool HasPtrField)
- : Decl(Decl), Bases(std::move(SrcBases)), Fields(std::move(SrcFields)),
- BaseSize(BaseSize), VirtualSize(VirtualSize), IsUnion(Decl->isUnion()),
- IsAnonymousUnion(IsUnion && Decl->isAnonymousStructOrUnion()),
- HasPtrField(HasPtrField) {
- for (Base &V : SrcVirtualBases)
- VirtualBases.emplace_back(V.Decl, V.Desc, V.R, V.Offset + BaseSize);
-
- for (Base &B : Bases) {
- BaseMap[B.Decl] = &B;
- if (!this->HasPtrField)
- this->HasPtrField |= B.R->hasPtrField();
- }
- for (Base &V : VirtualBases) {
- VirtualBaseMap[V.Decl] = &V;
- if (!this->HasPtrField)
- this->HasPtrField |= V.R->hasPtrField();
- }
-}
+Record::Record(const RecordDecl *Decl, unsigned NumBases, unsigned NumFields,
+ unsigned NumVBases)
+ : Decl(Decl), NumBases(NumBases), NumFields(NumFields),
+ NumVBases(NumVBases), IsUnion(Decl->isUnion()),
+ IsAnonymousUnion(IsUnion && Decl->isAnonymousStructOrUnion()) {}
std::string Record::getName() const {
std::string Ret;
diff --git a/clang/lib/AST/ByteCode/Record.h b/clang/lib/AST/ByteCode/Record.h
index e43f683364e26..24be2cf02bbf9 100644
--- a/clang/lib/AST/ByteCode/Record.h
+++ b/clang/lib/AST/ByteCode/Record.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_AST_INTERP_RECORD_H
#define LLVM_CLANG_AST_INTERP_RECORD_H
+#include "PrimType.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -49,14 +50,13 @@ class Record final {
: Decl(D), Desc(Desc), R(R), Offset(Offset) {}
};
- /// Mapping from identifiers to field descriptors.
- using FieldList = llvm::SmallVector<Field, 8>;
- /// Mapping from identifiers to base classes.
- using BaseList = llvm::SmallVector<Base, 8>;
- /// List of virtual base classes.
- using VirtualBaseList = llvm::SmallVector<Base, 0>;
-
public:
+ static size_t allocSize(unsigned NumFields, unsigned NumBases,
+ unsigned NumVBases) {
+ return align(sizeof(Record)) + align((NumFields * sizeof(Field))) +
+ align((NumBases * sizeof(Base))) + align(NumVBases * sizeof(Base));
+ }
+
/// Returns the underlying declaration.
const RecordDecl *getDecl() const { return Decl; }
/// Returns the name of the underlying declaration.
@@ -82,40 +82,40 @@ class Record final {
/// with no destructor or for those with a trivial destructor.
bool hasTrivialDtor() const;
- using const_field_iter = FieldList::const_iterator;
+ using const_field_iter = ArrayRef<Field>::const_iterator;
llvm::iterator_range<const_field_iter> fields() const {
- return llvm::make_range(Fields.begin(), Fields.end());
+ return llvm::make_range(getFields(), getFields() + NumFields);
}
- unsigned getNumFields() const { return Fields.size(); }
- const Field *getField(unsigned I) const { return &Fields[I]; }
+ unsigned getNumFields() const { return NumFields; }
+ const Field *getField(unsigned I) const { return &getFields()[I]; }
/// Returns a field.
const Field *getField(const FieldDecl *FD) const {
- return &Fields[FD->getFieldIndex()];
+ return &getFields()[FD->getFieldIndex()];
}
- using const_base_iter = BaseList::const_iterator;
+ using const_base_iter = ArrayRef<Base>::const_iterator;
llvm::iterator_range<const_base_iter> bases() const {
- return llvm::make_range(Bases.begin(), Bases.end());
+ return llvm::make_range(getBases(), getBases() + NumBases);
}
- unsigned getNumBases() const { return Bases.size(); }
+ unsigned getNumBases() const { return NumBases; }
const Base *getBase(unsigned I) const {
assert(I < getNumBases());
- return &Bases[I];
+ return &getBases()[I];
}
/// Returns a base descriptor.
const Base *getBase(QualType T) const;
/// Returns a base descriptor.
const Base *getBase(const RecordDecl *FD) const;
- using const_virtual_iter = VirtualBaseList::const_iterator;
- llvm::iterator_range<const_virtual_iter> virtual_bases() const {
- return llvm::make_range(VirtualBases.begin(), VirtualBases.end());
+ using const_vbase_iter = ArrayRef<Base>::const_iterator;
+ llvm::iterator_range<const_vbase_iter> virtual_bases() const {
+ return llvm::make_range(getVBases(), getVBases() + NumVBases);
}
- unsigned getNumVirtualBases() const { return VirtualBases.size(); }
- const Base *getVirtualBase(unsigned I) const { return &VirtualBases[I]; }
+ unsigned getNumVirtualBases() const { return NumVBases; }
+ const Base *getVirtualBase(unsigned I) const { return &getVBases()[I]; }
/// Returns a virtual base descriptor.
const Base *getVirtualBase(const RecordDecl *RD) const;
@@ -125,21 +125,34 @@ class Record final {
private:
/// Constructor used by Program to create record descriptors.
- Record(const RecordDecl *, BaseList &&Bases, FieldList &&Fields,
- VirtualBaseList &&VirtualBases, unsigned VirtualSize,
- unsigned BaseSize, bool HasPtrField = true);
+ Record(const RecordDecl *, unsigned NumBases, unsigned NumFields,
+ unsigned NumVBases);
private:
friend class Program;
+ Field *getFields() const {
+ return reinterpret_cast<Field *>(
+ (reinterpret_cast<char *>(const_cast<Record *>(this))) +
+ align(sizeof(*this)));
+ }
+ Base *getBases() const {
+ return reinterpret_cast<Base *>(
+ (reinterpret_cast<char *>(const_cast<Record *>(this))) +
+ align(sizeof(*this)) + align((NumFields * sizeof(Field))));
+ }
+ Base *getVBases() const {
+ return reinterpret_cast<Base *>(
+ (reinterpret_cast<char *>(const_cast<Record *>(this))) +
+ align(sizeof(*this)) + align((NumFields * sizeof(Field))) +
+ align(NumBases * sizeof(Base)));
+ }
+
/// Original declaration.
const RecordDecl *Decl;
- /// List of all base classes.
- BaseList Bases;
- /// List of all the fields in the record.
- FieldList Fields;
- /// List o fall virtual bases.
- VirtualBaseList VirtualBases;
+ unsigned NumBases;
+ const unsigned NumFields;
+ unsigned NumVBases;
/// Mapping from declarations to bases.
llvm::DenseMap<const RecordDecl *, const Base *> BaseMap;
``````````
</details>
https://github.com/llvm/llvm-project/pull/185902
More information about the cfe-commits
mailing list