Removed the cleanup list

It no longer has any users. If we need it later, we can add it back.

This saves one pointer of memory from `sizeof(upb_Arena)`.

Also, we now allow fuses if if the block allocators differ.  This is made possible by cl/520144430, but was not take advantage of in that CL.

PiperOrigin-RevId: 520174588
diff --git a/upb/mem/arena.c b/upb/mem/arena.c
index 4b0bd45..43b254d 100644
--- a/upb/mem/arena.c
+++ b/upb/mem/arena.c
@@ -31,14 +31,6 @@
 // Must be last.
 #include "upb/port/def.inc"
 
-static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) {
-  return (uint32_t*)(cleanup_metadata & ~0x1);
-}
-
-static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) {
-  return cleanup_metadata & 0x1;
-}
-
 static uintptr_t upb_cleanup_metadata(uint32_t* cleanup,
                                       bool has_initial_block) {
   return (uintptr_t)cleanup | has_initial_block;
@@ -48,15 +40,9 @@
   // Atomic only for the benefit of SpaceAllocated().
   UPB_ATOMIC(_upb_MemBlock*) next;
   uint32_t size;
-  uint32_t cleanups;
   // Data follows.
 };
 
-typedef struct cleanup_ent {
-  upb_CleanupFunc* cleanup;
-  void* ud;
-} cleanup_ent;
-
 static const size_t memblock_reserve =
     UPB_ALIGN_UP(sizeof(_upb_MemBlock), UPB_MALLOC_ALIGN);
 
@@ -128,13 +114,10 @@
   // Insert into linked list.
   upb_Atomic_Init(&block->next, a->blocks);
   block->size = (uint32_t)size;
-  block->cleanups = 0;
   upb_Atomic_Store(&a->blocks, block, memory_order_relaxed);
 
   a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char);
   a->head.end = UPB_PTR_AT(block, size, char);
-  a->cleanup_metadata = upb_cleanup_metadata(
-      &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata));
 
   UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr);
 }
@@ -144,7 +127,7 @@
   _upb_MemBlock* last_block = upb_Atomic_Load(&a->blocks, memory_order_relaxed);
   size_t last_size = last_block != NULL ? last_block->size : 128;
   size_t block_size = UPB_MAX(size, last_size * 2) + memblock_reserve;
-  _upb_MemBlock* block = upb_malloc(a->block_alloc, block_size);
+  _upb_MemBlock* block = upb_malloc(upb_Arena_BlockAlloc(a), block_size);
 
   if (!block) return false;
   upb_Arena_AddBlock(a, block, block_size);
@@ -159,12 +142,13 @@
 
 /* Public Arena API ***********************************************************/
 
-static upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) {
+static upb_Arena* upb_Arena_InitSlow(upb_alloc* alloc) {
   const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve;
   upb_Arena* a;
 
   /* We need to malloc the initial block. */
-  n = first_block_overhead + 256;
+  char* mem;
+  size_t n = first_block_overhead + 256;
   if (!alloc || !(mem = upb_malloc(alloc, n))) {
     return NULL;
   }
@@ -172,12 +156,11 @@
   a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena);
   n -= sizeof(*a);
 
-  a->block_alloc = alloc;
+  a->block_alloc = upb_Arena_MakeBlockAlloc(alloc, 0);
   upb_Atomic_Init(&a->parent_or_count, _upb_Arena_TaggedFromRefcount(1));
   upb_Atomic_Init(&a->next, NULL);
   upb_Atomic_Init(&a->tail, a);
   upb_Atomic_Init(&a->blocks, NULL);
-  a->cleanup_metadata = upb_cleanup_metadata(NULL, false);
 
   upb_Arena_AddBlock(a, mem, n);
 
@@ -200,7 +183,7 @@
   n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena));
 
   if (UPB_UNLIKELY(n < sizeof(upb_Arena))) {
-    return arena_initslow(mem, n, alloc);
+    return upb_Arena_InitSlow(alloc);
   }
 
   a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena);
@@ -209,10 +192,9 @@
   upb_Atomic_Init(&a->next, NULL);
   upb_Atomic_Init(&a->tail, a);
   upb_Atomic_Init(&a->blocks, NULL);
-  a->block_alloc = alloc;
+  a->block_alloc = upb_Arena_MakeBlockAlloc(alloc, 1);
   a->head.ptr = mem;
   a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char);
-  a->cleanup_metadata = upb_cleanup_metadata(NULL, true);
 
   return a;
 }
@@ -224,22 +206,13 @@
     // Load first since arena itself is likely from one of its blocks.
     upb_Arena* next_arena =
         (upb_Arena*)upb_Atomic_Load(&a->next, memory_order_acquire);
+    upb_alloc* block_alloc = upb_Arena_BlockAlloc(a);
     _upb_MemBlock* block = upb_Atomic_Load(&a->blocks, memory_order_relaxed);
     while (block != NULL) {
-      /* Load first since we are deleting block. */
+      // Load first since we are deleting block.
       _upb_MemBlock* next_block =
           upb_Atomic_Load(&block->next, memory_order_relaxed);
-
-      if (block->cleanups > 0) {
-        cleanup_ent* end = UPB_PTR_AT(block, block->size, void);
-        cleanup_ent* ptr = end - block->cleanups;
-
-        for (; ptr < end; ptr++) {
-          ptr->cleanup(ptr->ud);
-        }
-      }
-
-      upb_free(a->block_alloc, block);
+      upb_free(block_alloc, block);
       block = next_block;
     }
     a = next_arena;
@@ -275,27 +248,6 @@
   goto retry;
 }
 
-bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) {
-  cleanup_ent* ent;
-  uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata);
-
-  if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) {
-    if (!upb_Arena_AllocBlock(a, 128)) return false; /* Out of memory. */
-    UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent));
-    cleanups = upb_cleanup_pointer(a->cleanup_metadata);
-  }
-
-  a->head.end -= sizeof(cleanup_ent);
-  ent = (cleanup_ent*)a->head.end;
-  (*cleanups)++;
-  UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent));
-
-  ent->cleanup = func;
-  ent->ud = ud;
-
-  return true;
-}
-
 bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) {
   // SAFE IN THE PRESENCE OF FUSE/FREE RACES BUT NOT IN THE
   // PRESENCE OF FUSE/FUSE RACES!!!
@@ -318,17 +270,16 @@
   // that only refcounts can change once we have found the root.  Because the
   // threads doing the fuse must hold references, we can guarantee that no
   // refcounts will reach zero concurrently.
+
   upb_Arena* r1 = _upb_Arena_FindRoot(a1);
   upb_Arena* r2 = _upb_Arena_FindRoot(a2);
 
   if (r1 == r2) return true;  // Already fused.
 
   // Do not fuse initial blocks since we cannot lifetime extend them.
-  if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false;
-  if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false;
-
-  // Only allow fuse with a common allocator
-  if (r1->block_alloc != r2->block_alloc) return false;
+  // Any other fuse scenario is allowed.
+  if (upb_Arena_HasInitialBlock(r1)) return false;
+  if (upb_Arena_HasInitialBlock(r2)) return false;
 
   uintptr_t r1_poc =
       upb_Atomic_Load(&r1->parent_or_count, memory_order_acquire);
diff --git a/upb/mem/arena.h b/upb/mem/arena.h
index 3e1ddf1..4586b07 100644
--- a/upb/mem/arena.h
+++ b/upb/mem/arena.h
@@ -49,8 +49,6 @@
 
 typedef struct upb_Arena upb_Arena;
 
-typedef void upb_CleanupFunc(void* context);
-
 typedef struct {
   char *ptr, *end;
 } _upb_ArenaHead;
@@ -65,8 +63,6 @@
 UPB_API upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc);
 
 UPB_API void upb_Arena_Free(upb_Arena* a);
-UPB_API bool upb_Arena_AddCleanup(upb_Arena* a, void* ud,
-                                  upb_CleanupFunc* func);
 UPB_API bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b);
 
 void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size);
diff --git a/upb/mem/arena_internal.h b/upb/mem/arena_internal.h
index 9b940dc..e5a81f0 100644
--- a/upb/mem/arena_internal.h
+++ b/upb/mem/arena_internal.h
@@ -37,23 +37,18 @@
 
 struct upb_Arena {
   _upb_ArenaHead head;
-  /* Stores cleanup metadata for this arena.
-   * - a pointer to the current cleanup counter.
-   * - a boolean indicating if there is an unowned initial block.  */
-  uintptr_t cleanup_metadata;
 
-  /* Allocator to allocate arena blocks.  We are responsible for freeing these
-   * when we are destroyed. */
-  upb_alloc* block_alloc;
+  // upb_alloc* together with a low bit which signals if there is an initial
+  // block.
+  uintptr_t block_alloc;
 
-  /* When multiple arenas are fused together, each arena points to a parent
-   * arena (root points to itself). The root tracks how many live arenas
-   * reference it.
-   *
-   * The low bit is tagged:
-   *   0: pointer to parent
-   *   1: count, left shifted by one
-   */
+  // When multiple arenas are fused together, each arena points to a parent
+  // arena (root points to itself). The root tracks how many live arenas
+  // reference it.
+
+  // The low bit is tagged:
+  //   0: pointer to parent
+  //   1: count, left shifted by one
   UPB_ATOMIC(uintptr_t) parent_or_count;
 
   // All nodes that are fused together are in a singly-linked list.
@@ -99,6 +94,21 @@
   return parent_or_count;
 }
 
+UPB_INLINE upb_alloc* upb_Arena_BlockAlloc(upb_Arena* arena) {
+  return (upb_alloc*)(arena->block_alloc & ~0x1);
+}
+
+UPB_INLINE uintptr_t upb_Arena_MakeBlockAlloc(upb_alloc* alloc,
+                                              bool has_initial) {
+  uintptr_t alloc_uint = (uintptr_t)alloc;
+  UPB_ASSERT((alloc_uint & 1) == 0);
+  return alloc_uint | (has_initial ? 1 : 0);
+}
+
+UPB_INLINE bool upb_Arena_HasInitialBlock(upb_Arena* arena) {
+  return arena->block_alloc & 0x1;
+}
+
 #include "upb/port/undef.inc"
 
 #endif /* UPB_MEM_ARENA_INTERNAL_H_ */
diff --git a/upb/mem/arena_test.cc b/upb/mem/arena_test.cc
index b091997..87fadfd 100644
--- a/upb/mem/arena_test.cc
+++ b/upb/mem/arena_test.cc
@@ -17,38 +17,14 @@
 
 namespace {
 
-static void decrement_int(void* ptr) {
-  int* iptr = static_cast<int*>(ptr);
-  (*iptr)--;
-}
-
 TEST(ArenaTest, ArenaFuse) {
-  int i1 = 5;
-  int i2 = 5;
-  int i3 = 5;
-  int i4 = 5;
-
   upb_Arena* arena1 = upb_Arena_New();
   upb_Arena* arena2 = upb_Arena_New();
 
-  upb_Arena_AddCleanup(arena1, &i1, decrement_int);
-  upb_Arena_AddCleanup(arena2, &i2, decrement_int);
-
   EXPECT_TRUE(upb_Arena_Fuse(arena1, arena2));
 
-  upb_Arena_AddCleanup(arena1, &i3, decrement_int);
-  upb_Arena_AddCleanup(arena2, &i4, decrement_int);
-
   upb_Arena_Free(arena1);
-  EXPECT_EQ(5, i1);
-  EXPECT_EQ(5, i2);
-  EXPECT_EQ(5, i3);
-  EXPECT_EQ(5, i4);
   upb_Arena_Free(arena2);
-  EXPECT_EQ(4, i1);
-  EXPECT_EQ(4, i2);
-  EXPECT_EQ(4, i3);
-  EXPECT_EQ(4, i4);
 }
 
 /* Do nothing allocator for testing */
@@ -56,19 +32,18 @@
                                size_t size) {
   return upb_alloc_global.func(alloc, ptr, oldsize, size);
 }
-ABSL_CONST_INIT upb_alloc test_alloc = {&TestAllocFunc};
 
 TEST(ArenaTest, FuseWithInitialBlock) {
   char buf1[1024];
   char buf2[1024];
   upb_Arena* arenas[] = {upb_Arena_Init(buf1, 1024, &upb_alloc_global),
                          upb_Arena_Init(buf2, 1024, &upb_alloc_global),
-                         upb_Arena_Init(NULL, 0, &test_alloc),
                          upb_Arena_Init(NULL, 0, &upb_alloc_global)};
   int size = sizeof(arenas) / sizeof(arenas[0]);
   for (int i = 0; i < size; ++i) {
     for (int j = 0; j < size; ++j) {
       if (i == j) {
+        // Fuse to self is always allowed.
         EXPECT_TRUE(upb_Arena_Fuse(arenas[i], arenas[j]));
       } else {
         EXPECT_FALSE(upb_Arena_Fuse(arenas[i], arenas[j]));
diff --git a/upb/test/test_cpp.cc b/upb/test/test_cpp.cc
index eb77872..6e8bb1d 100644
--- a/upb/test/test_cpp.cc
+++ b/upb/test/test_cpp.cc
@@ -65,67 +65,6 @@
   EXPECT_EQ(oneof_count, md.oneof_count());
 }
 
-TEST(Cpp, Arena) {
-  int n = 100000;
-
-  struct Decrementer {
-    Decrementer(int* _p) : p(_p) {}
-    ~Decrementer() { (*p)--; }
-    int* p;
-  };
-
-  {
-    upb::Arena arena;
-    for (int i = 0; i < n; i++) {
-      arena.Own(new Decrementer(&n));
-
-      // Intersperse allocation and ensure we can write to it.
-      int* val = static_cast<int*>(upb_Arena_Malloc(arena.ptr(), sizeof(int)));
-      *val = i;
-    }
-
-    // Test a large allocation.
-    upb_Arena_Malloc(arena.ptr(), 1000000);
-  }
-  EXPECT_EQ(0, n);
-
-  {
-    // Test fuse.
-    upb::Arena arena1;
-    upb::Arena arena2;
-
-    arena1.Fuse(arena2);
-
-    upb_Arena_Malloc(arena1.ptr(), 10000);
-    upb_Arena_Malloc(arena2.ptr(), 10000);
-  }
-}
-
-TEST(Cpp, InlinedArena) {
-  int n = 100000;
-
-  struct Decrementer {
-    Decrementer(int* _p) : p(_p) {}
-    ~Decrementer() { (*p)--; }
-    int* p;
-  };
-
-  {
-    upb::InlinedArena<1024> arena;
-    for (int i = 0; i < n; i++) {
-      arena.Own(new Decrementer(&n));
-
-      // Intersperse allocation and ensure we can write to it.
-      int* val = static_cast<int*>(upb_Arena_Malloc(arena.ptr(), sizeof(int)));
-      *val = i;
-    }
-
-    // Test a large allocation.
-    upb_Arena_Malloc(arena.ptr(), 1000000);
-  }
-  EXPECT_EQ(0, n);
-}
-
 TEST(Cpp, InlinedArena2) {
   upb::InlinedArena<64> arena;
   upb_Arena_Malloc(arena.ptr(), sizeof(int));
diff --git a/upb/test/test_generated_code.cc b/upb/test/test_generated_code.cc
index e2db7d9..99d5b46 100644
--- a/upb/test/test_generated_code.cc
+++ b/upb/test/test_generated_code.cc
@@ -854,95 +854,11 @@
   (*iptr)--;
 }
 
-TEST(GeneratedCode, ArenaFuse) {
-  int i1 = 5;
-  int i2 = 5;
-  int i3 = 5;
-  int i4 = 5;
-
-  upb_Arena* arena1 = upb_Arena_New();
-  upb_Arena* arena2 = upb_Arena_New();
-
-  upb_Arena_AddCleanup(arena1, &i1, decrement_int);
-  upb_Arena_AddCleanup(arena2, &i2, decrement_int);
-
-  EXPECT_TRUE(upb_Arena_Fuse(arena1, arena2));
-
-  upb_Arena_AddCleanup(arena1, &i3, decrement_int);
-  upb_Arena_AddCleanup(arena2, &i4, decrement_int);
-
-  upb_Arena_Free(arena1);
-  EXPECT_EQ(5, i1);
-  EXPECT_EQ(5, i2);
-  EXPECT_EQ(5, i3);
-  EXPECT_EQ(5, i4);
-  upb_Arena_Free(arena2);
-  EXPECT_EQ(4, i1);
-  EXPECT_EQ(4, i2);
-  EXPECT_EQ(4, i3);
-  EXPECT_EQ(4, i4);
-}
-
 /* Do nothing allocator for testing */
 static void* test_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize,
                             size_t size) {
   return upb_alloc_global.func(alloc, ptr, oldsize, size);
 }
-upb_alloc test_alloc = {&test_allocfunc};
-
-TEST(GeneratedCode, FuseWithInitialBlock) {
-  char buf1[1024];
-  char buf2[1024];
-  upb_Arena* arenas[] = {upb_Arena_Init(buf1, 1024, &upb_alloc_global),
-                         upb_Arena_Init(buf2, 1024, &upb_alloc_global),
-                         upb_Arena_Init(NULL, 0, &test_alloc),
-                         upb_Arena_Init(NULL, 0, &upb_alloc_global)};
-  int size = sizeof(arenas) / sizeof(arenas[0]);
-  for (int i = 0; i < size; ++i) {
-    for (int j = 0; j < size; ++j) {
-      if (i == j) {
-        EXPECT_TRUE(upb_Arena_Fuse(arenas[i], arenas[j]));
-      } else {
-        EXPECT_FALSE(upb_Arena_Fuse(arenas[i], arenas[j]));
-      }
-    }
-  }
-
-  for (int i = 0; i < size; ++i) upb_Arena_Free(arenas[i]);
-}
-
-TEST(GeneratedCode, ArenaDecode) {
-  // Tests against a bug that previously existed when passing an arena to
-  // upb_decode().
-  char large_string[1024] = {0};
-  upb_StringView large_string_view = {large_string, sizeof(large_string)};
-  upb_Arena* tmp = upb_Arena_New();
-
-  protobuf_test_messages_proto3_TestAllTypesProto3* msg =
-      protobuf_test_messages_proto3_TestAllTypesProto3_new(tmp);
-
-  protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_bytes(
-      msg, large_string_view);
-
-  upb_StringView serialized;
-  serialized.data = protobuf_test_messages_proto3_TestAllTypesProto3_serialize(
-      msg, tmp, &serialized.size);
-
-  upb_Arena* arena = upb_Arena_New();
-  // Parse the large payload, forcing an arena block to be allocated. This used
-  // to corrupt the cleanup list, preventing subsequent upb_Arena_AddCleanup()
-  // calls from working properly.
-  protobuf_test_messages_proto3_TestAllTypesProto3_parse(
-      serialized.data, serialized.size, arena);
-
-  int i1 = 5;
-  upb_Arena_AddCleanup(arena, &i1, decrement_int);
-  EXPECT_EQ(5, i1);
-  upb_Arena_Free(arena);
-  EXPECT_EQ(4, i1);
-
-  upb_Arena_Free(tmp);
-}
 
 TEST(GeneratedCode, ArenaUnaligned) {
   char buf1[1024];
diff --git a/upb/upb.hpp b/upb/upb.hpp
index c99ac33..78f1c77 100644
--- a/upb/upb.hpp
+++ b/upb/upb.hpp
@@ -77,14 +77,6 @@
 
   upb_Arena* ptr() const { return ptr_.get(); }
 
-  // Add a cleanup function to run when the arena is destroyed.
-  // Returns false on out-of-memory.
-  template <class T>
-  bool Own(T* obj) {
-    return upb_Arena_AddCleanup(ptr_.get(), obj,
-                                [](void* obj) { delete static_cast<T*>(obj); });
-  }
-
   void Fuse(Arena& other) { upb_Arena_Fuse(ptr(), other.ptr()); }
 
  protected:
diff --git a/upb/wire/decode.c b/upb/wire/decode.c
index e1697fa..ed2ee98 100644
--- a/upb/wire/decode.c
+++ b/upb/wire/decode.c
@@ -1285,7 +1285,6 @@
   _upb_MemBlock* blocks =
       upb_Atomic_Load(&decoder->arena.blocks, memory_order_relaxed);
   arena->head = decoder->arena.head;
-  arena->cleanup_metadata = decoder->arena.cleanup_metadata;
   upb_Atomic_Store(&arena->blocks, blocks, memory_order_relaxed);
   return decoder->status;
 }
@@ -1316,7 +1315,6 @@
   _upb_MemBlock* blocks = upb_Atomic_Load(&arena->blocks, memory_order_relaxed);
   decoder.arena.head = arena->head;
   decoder.arena.block_alloc = arena->block_alloc;
-  decoder.arena.cleanup_metadata = arena->cleanup_metadata;
   upb_Atomic_Init(&decoder.arena.blocks, blocks);
 
   return upb_Decoder_Decode(&decoder, buf, msg, l, arena);