[clang] [clang][bytecode] Replace MoveFn With DtorFn + memcpy (PR #151717)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 1 08:47:48 PDT 2025


https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/151717

First, the old MoveFn was rather inefficient, since the dead data cannot ever be accessed anyway.

Second, there was a problem where the only reason a block still had a pointer to it (and thus was made into a DeadBlock instead of simply being deallocated) as that a nested field in the block pointed to the block itself.

Fix this by calling the dtor function unconditionally. If the block *still* has pointers after that, we really need to create a DeadBlock for it.

>From 50b1f9db9bf38b9618a39c0bfd1d181f9d146dea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 1 Aug 2025 16:33:02 +0200
Subject: [PATCH] [clang][bytecode] Replace MoveFn With DtorFn + memcpy

First, the old MoveFn was rather inefficient, since the dead data cannot
ever be accessed anyway.

Second, there was a problem where the only reason a block still had a
pointer to it (and thus was made into a DeadBlock instead of simply
being deallocated) as that a nested field in the block pointed to the
block itself.

Fix this by calling the dtor function unconditionally. If the block
*still* has pointers after that, we really need to create a DeadBlock
for it.
---
 clang/lib/AST/ByteCode/InterpState.cpp | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index 30108475d7db0..32ad07bb55d45 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -77,27 +77,27 @@ void InterpState::deallocate(Block *B) {
   const Descriptor *Desc = B->getDescriptor();
   assert(Desc);
 
+  // The block might have a pointer saved in a field in its data
+  // that points to the block itself. We call the dtor first,
+  // which will destroy all the data but leave InlineDescriptors
+  // intact. If the block THEN still has pointers, we create a
+  // DeadBlock for it.
+  if (B->IsInitialized)
+    B->invokeDtor();
+
   if (B->hasPointers()) {
     size_t Size = B->getSize();
-
     // Allocate a new block, transferring over pointers.
     char *Memory =
         reinterpret_cast<char *>(std::malloc(sizeof(DeadBlock) + Size));
     auto *D = new (Memory) DeadBlock(DeadBlocks, B);
-    std::memset(D->B.rawData(), 0, D->B.getSize());
-
-    // Move data and metadata from the old block to the new (dead)block.
-    if (B->IsInitialized && Desc->MoveFn) {
-      Desc->MoveFn(B, B->data(), D->data(), Desc);
-      if (Desc->getMetadataSize() > 0)
-        std::memcpy(D->rawData(), B->rawData(), Desc->getMetadataSize());
-    }
+    // Since the block doesn't hold any actual data anymore, we can just
+    // memcpy() everything over.
+    std::memcpy(D->rawData(), B->rawData(), Desc->getAllocSize());
     D->B.IsInitialized = B->IsInitialized;
 
     // We moved the contents over to the DeadBlock.
     B->IsInitialized = false;
-  } else if (B->IsInitialized) {
-    B->invokeDtor();
   }
 }
 



More information about the cfe-commits mailing list