Skip to content

Commit 25c137e

Browse files
authored
[clang][bytecode] Save a per-block dynamic allocation ID (#154094)
This fixes an old todo item about wrong allocation counting and some diagnostic differences.
1 parent f84ce1e commit 25c137e

File tree

7 files changed

+23
-20
lines changed

7 files changed

+23
-20
lines changed

clang/lib/AST/ByteCode/Disasm.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
545545
OS << " Initialized: " << IsInitialized << "\n";
546546
OS << " Weak: " << isWeak() << "\n";
547547
OS << " Dummy: " << isDummy() << '\n';
548-
OS << " Dynamic: " << IsDynamic << "\n";
548+
OS << " Dynamic: " << isDynamic() << "\n";
549549
}
550550

551551
LLVM_DUMP_METHOD void EvaluationResult::dump() const {

clang/lib/AST/ByteCode/DynamicAllocator.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,17 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
101101
ID->LifeState =
102102
AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started;
103103

104-
B->IsDynamic = true;
105-
106-
if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
104+
if (auto It = AllocationSites.find(D->asExpr());
105+
It != AllocationSites.end()) {
107106
It->second.Allocations.emplace_back(std::move(Memory));
108-
else
107+
B->setDynAllocId(It->second.NumAllocs);
108+
++It->second.NumAllocs;
109+
} else {
109110
AllocationSites.insert(
110111
{D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});
112+
B->setDynAllocId(0);
113+
}
114+
assert(B->isDynamic());
111115
return B;
112116
}
113117

clang/lib/AST/ByteCode/DynamicAllocator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ class DynamicAllocator final {
4848

4949
struct AllocationSite {
5050
llvm::SmallVector<Allocation> Allocations;
51+
unsigned NumAllocs = 0;
5152
Form AllocForm;
5253

5354
AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm)
5455
: AllocForm(AllocForm) {
5556
Allocations.push_back({std::move(Memory)});
57+
++NumAllocs;
5658
}
5759

5860
size_t size() const { return Allocations.size(); }

clang/lib/AST/ByteCode/InterpBlock.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ void Block::removePointer(Pointer *P) {
5656
}
5757

5858
void Block::cleanup() {
59-
if (Pointers == nullptr && !IsDynamic && isDead())
59+
if (Pointers == nullptr && !isDynamic() && isDead())
6060
(reinterpret_cast<DeadBlock *>(this + 1) - 1)->free();
6161
}
6262

@@ -111,7 +111,7 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
111111
Prev = nullptr;
112112
Root = this;
113113

114-
B.IsDynamic = Blk->IsDynamic;
114+
B.DynAllocId = Blk->DynAllocId;
115115

116116
// Transfer pointers.
117117
B.Pointers = Blk->Pointers;

clang/lib/AST/ByteCode/InterpBlock.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class Block final {
6262

6363
Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,
6464
bool IsExtern = false, bool IsWeak = false, bool IsDummy = false)
65-
: Desc(Desc), EvalID(EvalID), IsStatic(IsStatic), IsDynamic(false) {
65+
: Desc(Desc), EvalID(EvalID), IsStatic(IsStatic) {
6666
assert(Desc);
6767
AccessFlags |= (ExternFlag * IsExtern);
6868
AccessFlags |= (WeakFlag * IsWeak);
@@ -80,7 +80,7 @@ class Block final {
8080
/// Checks if the block is temporary.
8181
bool isTemporary() const { return Desc->IsTemporary; }
8282
bool isWeak() const { return AccessFlags & WeakFlag; }
83-
bool isDynamic() const { return IsDynamic; }
83+
bool isDynamic() const { return (DynAllocId != std::nullopt); }
8484
bool isDummy() const { return AccessFlags & DummyFlag; }
8585
bool isDead() const { return AccessFlags & DeadFlag; }
8686
/// Returns the size of the block.
@@ -160,6 +160,9 @@ class Block final {
160160
AccessFlags |= (DummyFlag * IsDummy);
161161
}
162162

163+
/// To be called by DynamicAllocator.
164+
void setDynAllocId(unsigned ID) { DynAllocId = ID; }
165+
163166
/// Deletes a dead block at the end of its lifetime.
164167
void cleanup();
165168

@@ -183,9 +186,8 @@ class Block final {
183186
/// Flag indicating if the block contents have been initialized
184187
/// via invokeCtor.
185188
bool IsInitialized = false;
186-
/// Flag indicating if this block has been allocated via dynamic
187-
/// memory allocation (e.g. malloc).
188-
bool IsDynamic = false;
189+
/// Allocation ID for this dynamic allocation, if it is one.
190+
UnsignedOrNone DynAllocId = std::nullopt;
189191
/// AccessFlags containing IsExtern, IsDead, IsWeak, and IsDummy bits.
190192
uint8_t AccessFlags = 0;
191193
};

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,7 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
179179
else if (const auto *E = Desc->asExpr()) {
180180
if (block()->isDynamic()) {
181181
QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
182-
// FIXME: Suboptimal counting of dynamic allocations. Move this to Context
183-
// or InterpState?
184-
static int ReportedDynamicAllocs = 0;
185-
DynamicAllocLValue DA(ReportedDynamicAllocs++);
182+
DynamicAllocLValue DA(*block()->DynAllocId);
186183
Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
187184
} else {
188185
Base = E;

clang/test/AST/ByteCode/new-delete.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ static_assert(noInit() == 0, "");
8282
/// Try to delete a pointer that hasn't been heap allocated.
8383
constexpr int notHeapAllocated() { // both-error {{never produces a constant expression}}
8484
int A = 0; // both-note 2{{declared here}}
85-
delete &A; // ref-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}} \
86-
// expected-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}}
85+
delete &A; // both-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}}
8786

8887
return 1;
8988
}
@@ -374,8 +373,7 @@ namespace delete_random_things {
374373
static_assert((delete &(new A)->n, true)); // both-error {{}} \
375374
// both-note {{delete of pointer to subobject }}
376375
static_assert((delete (new int + 1), true)); // both-error {{}} \
377-
// ref-note {{delete of pointer '&{*new int#0} + 1' that does not point to complete object}} \
378-
// expected-note {{delete of pointer '&{*new int#1} + 1' that does not point to complete object}}
376+
// both-note {{delete of pointer '&{*new int#0} + 1' that does not point to complete object}}
379377
static_assert((delete[] (new int[3] + 1), true)); // both-error {{}} \
380378
// both-note {{delete of pointer to subobject}}
381379
static_assert((delete &(int&)(int&&)0, true)); // both-error {{}} \

0 commit comments

Comments
 (0)