Delete old numpy_test.py file and replace references with the new one.

This is the final step to make numpy/pip_deps a test-only dependency.

PiperOrigin-RevId: 525785717
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c
index 1209b1c..f7b0eef 100644
--- a/ruby/ext/google/protobuf_c/ruby-upb.c
+++ b/ruby/ext/google/protobuf_c/ruby-upb.c
@@ -399,6 +399,7 @@
 }
 
 bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) {
+  UPB_ASSERT(arena);
   if (!upb_Array_Resize(arr, arr->size + 1, arena)) {
     return false;
   }
@@ -415,6 +416,7 @@
 
 bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count,
                       upb_Arena* arena) {
+  UPB_ASSERT(arena);
   UPB_ASSERT(i <= arr->size);
   UPB_ASSERT(count + arr->size >= count);
   const size_t oldsize = arr->size;
@@ -509,6 +511,7 @@
 
 upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key,
                                    upb_MessageValue val, upb_Arena* arena) {
+  UPB_ASSERT(arena);
   return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val,
                                               map->val_size, arena);
 }
@@ -773,9 +776,9 @@
   UPB_SIZE(72, 144), 13, kUpb_ExtMode_NonExtendable, 13, UPB_FASTTABLE_MASK(120), 0,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x000800000100000a, &upb_psb_1bt},
-    {0x0018000002000012, &upb_psb_1bt},
-    {0x002800003f00001a, &upb_prb_1bt},
+    {0x000800000100000a, &upb_pss_1bt},
+    {0x0018000002000012, &upb_pss_1bt},
+    {0x002800003f00001a, &upb_prs_1bt},
     {0x003000003f000022, &upb_prm_1bt_max128b},
     {0x003800003f01002a, &upb_prm_1bt_max64b},
     {0x004000003f020032, &upb_prm_1bt_max64b},
@@ -784,8 +787,8 @@
     {0x005800000405004a, &upb_psm_1bt_max64b},
     {0x006000003f000050, &upb_prv4_1bt},
     {0x006800003f000058, &upb_prv4_1bt},
-    {0x0070000005000062, &upb_psb_1bt},
-    {0x008000000600006a, &upb_psb_1bt},
+    {0x0070000005000062, &upb_pss_1bt},
+    {0x008000000600006a, &upb_pss_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
   })
@@ -821,7 +824,7 @@
   UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, UPB_FASTTABLE_MASK(120), 0,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x000800000100000a, &upb_psb_1bt},
+    {0x000800000100000a, &upb_pss_1bt},
     {0x001800003f000012, &upb_prm_1bt_max128b},
     {0x002000003f01001a, &upb_prm_1bt_max128b},
     {0x002800003f020022, &upb_prm_1bt_max64b},
@@ -830,7 +833,7 @@
     {0x004000000205003a, &upb_psm_1bt_max64b},
     {0x004800003f060042, &upb_prm_1bt_max64b},
     {0x005000003f07004a, &upb_prm_1bt_max64b},
-    {0x005800003f000052, &upb_prb_1bt},
+    {0x005800003f000052, &upb_prs_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
@@ -943,8 +946,8 @@
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0004000001000008, &upb_psv4_1bt},
-    {0x0010000002000012, &upb_psb_1bt},
-    {0x002000000300001a, &upb_psb_1bt},
+    {0x0010000002000012, &upb_pss_1bt},
+    {0x002000000300001a, &upb_pss_1bt},
     {0x0008000004000020, &upb_psb1_1bt},
     {0x0009000005000028, &upb_psb1_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
@@ -978,16 +981,16 @@
   UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, UPB_FASTTABLE_MASK(248), 0,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x001800000100000a, &upb_psb_1bt},
-    {0x0028000002000012, &upb_psb_1bt},
+    {0x001800000100000a, &upb_pss_1bt},
+    {0x0028000002000012, &upb_pss_1bt},
     {0x0004000003000018, &upb_psv4_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x0038000006000032, &upb_psb_1bt},
-    {0x004800000700003a, &upb_psb_1bt},
+    {0x0038000006000032, &upb_pss_1bt},
+    {0x004800000700003a, &upb_pss_1bt},
     {0x0058000008020042, &upb_psm_1bt_max64b},
     {0x0010000009000048, &upb_psv4_1bt},
-    {0x006000000a000052, &upb_psb_1bt},
+    {0x006000000a000052, &upb_pss_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
@@ -1027,7 +1030,7 @@
   UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 0,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x000800000100000a, &upb_psb_1bt},
+    {0x000800000100000a, &upb_pss_1bt},
     {0x0018000002000012, &upb_psm_1bt_max64b},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
   })
@@ -1053,11 +1056,11 @@
   UPB_SIZE(32, 56), 5, kUpb_ExtMode_NonExtendable, 5, UPB_FASTTABLE_MASK(56), 0,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x000800000100000a, &upb_psb_1bt},
+    {0x000800000100000a, &upb_pss_1bt},
     {0x001800003f000012, &upb_prm_1bt_max64b},
     {0x002000000201001a, &upb_psm_1bt_max64b},
     {0x002800003f020022, &upb_prm_1bt_max64b},
-    {0x003000003f00002a, &upb_prb_1bt},
+    {0x003000003f00002a, &upb_prs_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
   })
@@ -1096,7 +1099,7 @@
   UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(24), 0,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x000800000100000a, &upb_psb_1bt},
+    {0x000800000100000a, &upb_pss_1bt},
     {0x0004000002000010, &upb_psv4_1bt},
     {0x001800000300001a, &upb_psm_1bt_max64b},
   })
@@ -1119,7 +1122,7 @@
   UPB_SIZE(24, 40), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(24), 0,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x000800000100000a, &upb_psb_1bt},
+    {0x000800000100000a, &upb_pss_1bt},
     {0x001800003f000012, &upb_prm_1bt_max128b},
     {0x002000000201001a, &upb_psm_1bt_max64b},
   })
@@ -1144,9 +1147,9 @@
   UPB_SIZE(40, 64), 6, kUpb_ExtMode_NonExtendable, 6, UPB_FASTTABLE_MASK(56), 0,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x000800000100000a, &upb_psb_1bt},
-    {0x0018000002000012, &upb_psb_1bt},
-    {0x002800000300001a, &upb_psb_1bt},
+    {0x000800000100000a, &upb_pss_1bt},
+    {0x0018000002000012, &upb_pss_1bt},
+    {0x002800000300001a, &upb_pss_1bt},
     {0x0038000004000022, &upb_psm_1bt_max64b},
     {0x0001000005000028, &upb_psb1_1bt},
     {0x0002000006000030, &upb_psb1_1bt},
@@ -1189,17 +1192,17 @@
   UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(248), 0,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x001800000100000a, &upb_psb_1bt},
+    {0x001800000100000a, &upb_pss_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x0028000002000042, &upb_psb_1bt},
+    {0x0028000002000042, &upb_pss_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0008000004000050, &upb_psb1_1bt},
-    {0x003800000500005a, &upb_psb_1bt},
+    {0x003800000500005a, &upb_pss_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
@@ -1209,15 +1212,15 @@
     {0x000b000008000190, &upb_psb1_2bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x000c0000090001a0, &upb_psb1_2bt},
-    {0x005800000e0002aa, &upb_psb_2bt},
+    {0x005800000e0002aa, &upb_pss_2bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x000d00000a0001b8, &upb_psb1_2bt},
-    {0x00780000100002c2, &upb_psb_2bt},
-    {0x00880000110002ca, &upb_psb_2bt},
+    {0x00780000100002c2, &upb_pss_2bt},
+    {0x00880000110002ca, &upb_pss_2bt},
     {0x00100000120002d0, &upb_psb1_2bt},
     {0x000e00000b0001d8, &upb_psb1_2bt},
-    {0x00980000130002e2, &upb_psb_2bt},
-    {0x00a80000140002ea, &upb_psb_2bt},
+    {0x00980000130002e2, &upb_pss_2bt},
+    {0x00a80000140002ea, &upb_pss_2bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x000f00000c0001f8, &upb_psb1_2bt},
   })
@@ -1610,12 +1613,12 @@
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x000800003f000012, &upb_prm_1bt_max64b},
-    {0x001000000100001a, &upb_psb_1bt},
+    {0x001000000100001a, &upb_pss_1bt},
     {0x0020000002000020, &upb_psv8_1bt},
     {0x0028000003000028, &upb_psv8_1bt},
     {0x0030000004000031, &upb_psf8_1bt},
     {0x003800000500003a, &upb_psb_1bt},
-    {0x0048000006000042, &upb_psb_1bt},
+    {0x0048000006000042, &upb_pss_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
@@ -1637,7 +1640,7 @@
   UPB_SIZE(16, 24), 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 2,
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x000800000100000a, &upb_psb_1bt},
+    {0x000800000100000a, &upb_pss_1bt},
     {0x0001000002000010, &upb_psb1_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
   })
@@ -1677,10 +1680,10 @@
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x000800003f00000a, &upb_ppv4_1bt},
     {0x001000003f000012, &upb_ppv4_1bt},
-    {0x001800000100001a, &upb_psb_1bt},
-    {0x0028000002000022, &upb_psb_1bt},
+    {0x001800000100001a, &upb_pss_1bt},
+    {0x0028000002000022, &upb_pss_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
-    {0x003800003f000032, &upb_prb_1bt},
+    {0x003800003f000032, &upb_prs_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
   })
 };
@@ -1722,7 +1725,7 @@
   UPB_FASTTABLE_INIT({
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
     {0x001000003f00000a, &upb_ppv4_1bt},
-    {0x0018000001000012, &upb_psb_1bt},
+    {0x0018000001000012, &upb_pss_1bt},
     {0x0004000002000018, &upb_psv4_1bt},
     {0x0008000003000020, &upb_psv4_1bt},
     {0x0000000000000000, &_upb_FastDecoder_DecodeGeneric},
@@ -5350,26 +5353,29 @@
   goto retry;
 }
 
-static void _upb_Arena_DoFuseArenaLists(upb_Arena* r1, upb_Arena* r2) {
-  // Find the region for `r2`'s linked list.
-  upb_Arena* r1_tail = upb_Atomic_Load(&r1->tail, memory_order_relaxed);
-  while (true) {
-    upb_Arena* r1_next = upb_Atomic_Load(&r1_tail->next, memory_order_relaxed);
-    while (r1_next != NULL) {
-      // r1->tail was stale.  This can happen, but tail should always converge
-      // on the true tail.
-      r1_tail = r1_next;
-      r1_next = upb_Atomic_Load(&r1_tail->next, memory_order_relaxed);
+static void _upb_Arena_DoFuseArenaLists(upb_Arena* const parent,
+                                        upb_Arena* child) {
+  upb_Arena* parent_tail = upb_Atomic_Load(&parent->tail, memory_order_relaxed);
+  do {
+    // Our tail might be stale, but it will always converge to the true tail.
+    upb_Arena* parent_tail_next =
+        upb_Atomic_Load(&parent_tail->next, memory_order_relaxed);
+    while (parent_tail_next != NULL) {
+      parent_tail = parent_tail_next;
+      parent_tail_next =
+          upb_Atomic_Load(&parent_tail->next, memory_order_relaxed);
     }
-    if (upb_Atomic_CompareExchangeStrong(&r1_tail->next, &r1_next, r2,
-                                         memory_order_relaxed,
-                                         memory_order_relaxed)) {
-      break;
-    }
-  }
 
-  upb_Arena* r2_tail = upb_Atomic_Load(&r2->tail, memory_order_relaxed);
-  upb_Atomic_Store(&r1->tail, r2_tail, memory_order_relaxed);
+    upb_Arena* displaced =
+        upb_Atomic_Exchange(&parent_tail->next, child, memory_order_relaxed);
+    parent_tail = upb_Atomic_Load(&child->tail, memory_order_relaxed);
+
+    // If we displaced something that got installed racily, we can simply
+    // reinstall it on our new tail.
+    child = displaced;
+  } while (child != NULL);
+
+  upb_Atomic_Store(&parent->tail, parent_tail, memory_order_relaxed);
 }
 
 static upb_Arena* _upb_Arena_DoFuse(upb_Arena* a1, upb_Arena* a2,
@@ -5466,246 +5472,6 @@
 
 // Must be last.
 
-// Parses unknown data by merging into existing base_message or creating a
-// new message usingg mini_table.
-static upb_UnknownToMessageRet upb_MiniTable_ParseUnknownMessage(
-    const char* unknown_data, size_t unknown_size,
-    const upb_MiniTable* mini_table, upb_Message* base_message,
-    int decode_options, upb_Arena* arena) {
-  upb_UnknownToMessageRet ret;
-  ret.message =
-      base_message ? base_message : _upb_Message_New(mini_table, arena);
-  if (!ret.message) {
-    ret.status = kUpb_UnknownToMessage_OutOfMemory;
-    return ret;
-  }
-  // Decode sub message using unknown field contents.
-  const char* data = unknown_data;
-  uint32_t tag;
-  uint64_t message_len = 0;
-  data = upb_WireReader_ReadTag(data, &tag);
-  data = upb_WireReader_ReadVarint(data, &message_len);
-  upb_DecodeStatus status = upb_Decode(data, message_len, ret.message,
-                                       mini_table, NULL, decode_options, arena);
-  if (status == kUpb_DecodeStatus_OutOfMemory) {
-    ret.status = kUpb_UnknownToMessage_OutOfMemory;
-  } else if (status == kUpb_DecodeStatus_Ok) {
-    ret.status = kUpb_UnknownToMessage_Ok;
-  } else {
-    ret.status = kUpb_UnknownToMessage_ParseError;
-  }
-  return ret;
-}
-
-upb_GetExtension_Status upb_MiniTable_GetOrPromoteExtension(
-    upb_Message* msg, const upb_MiniTableExtension* ext_table,
-    int decode_options, upb_Arena* arena,
-    const upb_Message_Extension** extension) {
-  UPB_ASSERT(ext_table->field.descriptortype == kUpb_FieldType_Message);
-  *extension = _upb_Message_Getext(msg, ext_table);
-  if (*extension) {
-    return kUpb_GetExtension_Ok;
-  }
-
-  // Check unknown fields, if available promote.
-  int field_number = ext_table->field.number;
-  upb_FindUnknownRet result = upb_MiniTable_FindUnknown(
-      msg, field_number, kUpb_WireFormat_DefaultDepthLimit);
-  if (result.status != kUpb_FindUnknown_Ok) {
-    return kUpb_GetExtension_NotPresent;
-  }
-  size_t len;
-  size_t ofs = result.ptr - upb_Message_GetUnknown(msg, &len);
-  // Decode and promote from unknown.
-  const upb_MiniTable* extension_table = ext_table->sub.submsg;
-  upb_UnknownToMessageRet parse_result = upb_MiniTable_ParseUnknownMessage(
-      result.ptr, result.len, extension_table,
-      /* base_message= */ NULL, decode_options, arena);
-  switch (parse_result.status) {
-    case kUpb_UnknownToMessage_OutOfMemory:
-      return kUpb_GetExtension_OutOfMemory;
-    case kUpb_UnknownToMessage_ParseError:
-      return kUpb_GetExtension_ParseError;
-    case kUpb_UnknownToMessage_NotFound:
-      return kUpb_GetExtension_NotPresent;
-    case kUpb_UnknownToMessage_Ok:
-      break;
-  }
-  upb_Message* extension_msg = parse_result.message;
-  // Add to extensions.
-  upb_Message_Extension* ext =
-      _upb_Message_GetOrCreateExtension(msg, ext_table, arena);
-  if (!ext) {
-    return kUpb_GetExtension_OutOfMemory;
-  }
-  memcpy(&ext->data, &extension_msg, sizeof(extension_msg));
-  *extension = ext;
-  const char* delete_ptr = upb_Message_GetUnknown(msg, &len) + ofs;
-  upb_Message_DeleteUnknown(msg, delete_ptr, result.len);
-  return kUpb_GetExtension_Ok;
-}
-
-upb_GetExtensionAsBytes_Status upb_MiniTable_GetExtensionAsBytes(
-    const upb_Message* msg, const upb_MiniTableExtension* ext_table,
-    int encode_options, upb_Arena* arena, const char** extension_data,
-    size_t* len) {
-  const upb_Message_Extension* msg_ext = _upb_Message_Getext(msg, ext_table);
-  UPB_ASSERT(ext_table->field.descriptortype == kUpb_FieldType_Message);
-  if (msg_ext) {
-    upb_EncodeStatus status =
-        upb_Encode(msg_ext->data.ptr, msg_ext->ext->sub.submsg, encode_options,
-                   arena, (char**)extension_data, len);
-    if (status != kUpb_EncodeStatus_Ok) {
-      return kUpb_GetExtensionAsBytes_EncodeError;
-    }
-    return kUpb_GetExtensionAsBytes_Ok;
-  }
-  int field_number = ext_table->field.number;
-  upb_FindUnknownRet result = upb_MiniTable_FindUnknown(
-      msg, field_number, upb_DecodeOptions_GetMaxDepth(encode_options));
-  if (result.status != kUpb_FindUnknown_Ok) {
-    return kUpb_GetExtensionAsBytes_NotPresent;
-  }
-  const char* data = result.ptr;
-  uint32_t tag;
-  uint64_t message_len = 0;
-  data = upb_WireReader_ReadTag(data, &tag);
-  data = upb_WireReader_ReadVarint(data, &message_len);
-  *extension_data = data;
-  *len = message_len;
-  return kUpb_GetExtensionAsBytes_Ok;
-}
-
-static upb_FindUnknownRet upb_FindUnknownRet_ParseError(void) {
-  return (upb_FindUnknownRet){.status = kUpb_FindUnknown_ParseError};
-}
-
-upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg,
-                                             uint32_t field_number,
-                                             int depth_limit) {
-  size_t size;
-  upb_FindUnknownRet ret;
-
-  const char* ptr = upb_Message_GetUnknown(msg, &size);
-  upb_EpsCopyInputStream stream;
-  upb_EpsCopyInputStream_Init(&stream, &ptr, size, true);
-
-  while (!upb_EpsCopyInputStream_IsDone(&stream, &ptr)) {
-    uint32_t tag;
-    const char* unknown_begin = ptr;
-    ptr = upb_WireReader_ReadTag(ptr, &tag);
-    if (!ptr) return upb_FindUnknownRet_ParseError();
-    if (field_number == upb_WireReader_GetFieldNumber(tag)) {
-      ret.status = kUpb_FindUnknown_Ok;
-      ret.ptr = upb_EpsCopyInputStream_GetAliasedPtr(&stream, unknown_begin);
-      ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream);
-      // Because we know that the input is a flat buffer, it is safe to perform
-      // pointer arithmetic on aliased pointers.
-      ret.len = upb_EpsCopyInputStream_GetAliasedPtr(&stream, ptr) - ret.ptr;
-      return ret;
-    }
-
-    ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream);
-    if (!ptr) return upb_FindUnknownRet_ParseError();
-  }
-  ret.status = kUpb_FindUnknown_NotPresent;
-  ret.ptr = NULL;
-  ret.len = 0;
-  return ret;
-}
-
-// Warning: See TODO(b/267655898)
-upb_UnknownToMessageRet upb_MiniTable_PromoteUnknownToMessage(
-    upb_Message* msg, const upb_MiniTable* mini_table,
-    const upb_MiniTableField* field, const upb_MiniTable* sub_mini_table,
-    int decode_options, upb_Arena* arena) {
-  upb_FindUnknownRet unknown;
-  // We need to loop and merge unknowns that have matching tag field->number.
-  upb_Message* message = NULL;
-  // Callers should check that message is not set first before calling
-  // PromotoUnknownToMessage.
-  UPB_ASSERT(upb_MiniTable_GetSubMessageTable(mini_table, field) ==
-             sub_mini_table);
-  bool is_oneof = _upb_MiniTableField_InOneOf(field);
-  if (!is_oneof || _upb_getoneofcase_field(msg, field) == field->number) {
-    UPB_ASSERT(upb_Message_GetMessage(msg, field, NULL) == NULL);
-  }
-  upb_UnknownToMessageRet ret;
-  ret.status = kUpb_UnknownToMessage_Ok;
-  do {
-    unknown = upb_MiniTable_FindUnknown(
-        msg, field->number, upb_DecodeOptions_GetMaxDepth(decode_options));
-    switch (unknown.status) {
-      case kUpb_FindUnknown_Ok: {
-        const char* unknown_data = unknown.ptr;
-        size_t unknown_size = unknown.len;
-        ret = upb_MiniTable_ParseUnknownMessage(unknown_data, unknown_size,
-                                                sub_mini_table, message,
-                                                decode_options, arena);
-        if (ret.status == kUpb_UnknownToMessage_Ok) {
-          message = ret.message;
-          upb_Message_DeleteUnknown(msg, unknown_data, unknown_size);
-        }
-      } break;
-      case kUpb_FindUnknown_ParseError:
-        ret.status = kUpb_UnknownToMessage_ParseError;
-        break;
-      case kUpb_FindUnknown_NotPresent:
-        // If we parsed at least one unknown, we are done.
-        ret.status =
-            message ? kUpb_UnknownToMessage_Ok : kUpb_UnknownToMessage_NotFound;
-        break;
-    }
-  } while (unknown.status == kUpb_FindUnknown_Ok);
-  if (message) {
-    if (is_oneof) {
-      *_upb_oneofcase_field(msg, field) = field->number;
-    }
-    upb_Message_SetMessage(msg, mini_table, field, message);
-    ret.message = message;
-  }
-  return ret;
-}
-
-// Moves repeated messages in unknowns to a upb_Array.
-//
-// Since the repeated field is not a scalar type we don't check for
-// kUpb_LabelFlags_IsPacked.
-// TODO(b/251007554): Optimize. Instead of converting messages one at a time,
-// scan all unknown data once and compact.
-upb_UnknownToMessage_Status upb_MiniTable_PromoteUnknownToMessageArray(
-    upb_Message* msg, const upb_MiniTableField* field,
-    const upb_MiniTable* mini_table, int decode_options, upb_Arena* arena) {
-  upb_Array* repeated_messages = upb_Message_GetMutableArray(msg, field);
-  // Find all unknowns with given field number and parse.
-  upb_FindUnknownRet unknown;
-  do {
-    unknown = upb_MiniTable_FindUnknown(
-        msg, field->number, upb_DecodeOptions_GetMaxDepth(decode_options));
-    if (unknown.status == kUpb_FindUnknown_Ok) {
-      upb_UnknownToMessageRet ret = upb_MiniTable_ParseUnknownMessage(
-          unknown.ptr, unknown.len, mini_table,
-          /* base_message= */ NULL, decode_options, arena);
-      if (ret.status == kUpb_UnknownToMessage_Ok) {
-        upb_MessageValue value;
-        value.msg_val = ret.message;
-        // Allocate array on demand before append.
-        if (!repeated_messages) {
-          upb_Message_ResizeArray(msg, field, 0, arena);
-          repeated_messages = upb_Message_GetMutableArray(msg, field);
-        }
-        if (!upb_Array_Append(repeated_messages, value, arena)) {
-          return kUpb_UnknownToMessage_OutOfMemory;
-        }
-        upb_Message_DeleteUnknown(msg, unknown.ptr, unknown.len);
-      } else {
-        return ret.status;
-      }
-    }
-  } while (unknown.status == kUpb_FindUnknown_Ok);
-  return kUpb_UnknownToMessage_Ok;
-}
-
 upb_MapInsertStatus upb_Message_InsertMapEntry(upb_Map* map,
                                                const upb_MiniTable* mini_table,
                                                const upb_MiniTableField* field,
@@ -5732,42 +5498,6 @@
   return upb_Map_Insert(map, map_entry_key, map_entry_value, arena);
 }
 
-// Moves repeated messages in unknowns to a upb_Map.
-upb_UnknownToMessage_Status upb_MiniTable_PromoteUnknownToMap(
-    upb_Message* msg, const upb_MiniTable* mini_table,
-    const upb_MiniTableField* field, int decode_options, upb_Arena* arena) {
-  const upb_MiniTable* map_entry_mini_table =
-      mini_table->subs[field->UPB_PRIVATE(submsg_index)].submsg;
-  UPB_ASSERT(map_entry_mini_table);
-  UPB_ASSERT(map_entry_mini_table);
-  UPB_ASSERT(map_entry_mini_table->field_count == 2);
-  UPB_ASSERT(upb_FieldMode_Get(field) == kUpb_FieldMode_Map);
-  // Find all unknowns with given field number and parse.
-  upb_FindUnknownRet unknown;
-  while (1) {
-    unknown = upb_MiniTable_FindUnknown(
-        msg, field->number, upb_DecodeOptions_GetMaxDepth(decode_options));
-    if (unknown.status != kUpb_FindUnknown_Ok) break;
-    upb_UnknownToMessageRet ret = upb_MiniTable_ParseUnknownMessage(
-        unknown.ptr, unknown.len, map_entry_mini_table,
-        /* base_message= */ NULL, decode_options, arena);
-    if (ret.status != kUpb_UnknownToMessage_Ok) return ret.status;
-    // Allocate map on demand before append.
-    upb_Map* map = upb_Message_GetOrCreateMutableMap(msg, map_entry_mini_table,
-                                                     field, arena);
-    upb_Message* map_entry_message = ret.message;
-    upb_MapInsertStatus insert_status = upb_Message_InsertMapEntry(
-        map, mini_table, field, map_entry_message, arena);
-    if (insert_status == kUpb_MapInsertStatus_OutOfMemory) {
-      return kUpb_UnknownToMessage_OutOfMemory;
-    }
-    UPB_ASSUME(insert_status == kUpb_MapInsertStatus_Inserted ||
-               insert_status == kUpb_MapInsertStatus_Replaced);
-    upb_Message_DeleteUnknown(msg, unknown.ptr, unknown.len);
-  }
-  return kUpb_UnknownToMessage_Ok;
-}
-
 
 #include <math.h>
 
@@ -5973,15 +5703,15 @@
 
 upb_FieldType upb_MiniTableField_Type(const upb_MiniTableField* field) {
   if (field->mode & kUpb_LabelFlags_IsAlternate) {
-    if (field->descriptortype == kUpb_FieldType_Int32) {
+    if (field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Int32) {
       return kUpb_FieldType_Enum;
-    } else if (field->descriptortype == kUpb_FieldType_Bytes) {
+    } else if (field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bytes) {
       return kUpb_FieldType_String;
     } else {
       UPB_ASSERT(false);
     }
   }
-  return field->descriptortype;
+  return field->UPB_PRIVATE(descriptortype);
 }
 
 static bool upb_MiniTable_Is_Oneof(const upb_MiniTableField* f) {
@@ -6120,14 +5850,14 @@
 
 static bool upb_MiniTable_HasSub(upb_MiniTableField* field,
                                  uint64_t msg_modifiers) {
-  switch (field->descriptortype) {
+  switch (field->UPB_PRIVATE(descriptortype)) {
     case kUpb_FieldType_Message:
     case kUpb_FieldType_Group:
     case kUpb_FieldType_Enum:
       return true;
     case kUpb_FieldType_String:
       if (!(msg_modifiers & kUpb_MessageModifier_ValidateUtf8)) {
-        field->descriptortype = kUpb_FieldType_Bytes;
+        field->UPB_PRIVATE(descriptortype) = kUpb_FieldType_Bytes;
         field->mode |= kUpb_LabelFlags_IsAlternate;
       }
       return false;
@@ -6138,18 +5868,18 @@
 
 static bool upb_MtDecoder_FieldIsPackable(upb_MiniTableField* field) {
   return (field->mode & kUpb_FieldMode_Array) &&
-         upb_FieldType_IsPackable(field->descriptortype);
+         upb_FieldType_IsPackable(field->UPB_PRIVATE(descriptortype));
 }
 
 static void upb_MiniTable_SetTypeAndSub(upb_MiniTableField* field,
                                         upb_FieldType type, uint32_t* sub_count,
                                         uint64_t msg_modifiers,
                                         bool is_proto3_enum) {
-  field->descriptortype = type;
+  field->UPB_PRIVATE(descriptortype) = type;
 
   if (is_proto3_enum) {
-    UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum);
-    field->descriptortype = kUpb_FieldType_Int32;
+    UPB_ASSERT(field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Enum);
+    field->UPB_PRIVATE(descriptortype) = kUpb_FieldType_Int32;
     field->mode |= kUpb_LabelFlags_IsAlternate;
   }
 
@@ -6673,7 +6403,7 @@
 
   if ((1 << upb_MiniTableField_Type(f)) & not_ok_types) {
     upb_MtDecoder_ErrorFormat(d, "map %s cannot have type %d", name,
-                              (int)f->descriptortype);
+                              (int)f->UPB_PRIVATE(descriptortype));
   }
 }
 
@@ -7010,7 +6740,7 @@
 
   const bool sub_is_map = sub->ext & kUpb_ExtMode_IsMapEntry;
 
-  switch (field->descriptortype) {
+  switch (field->UPB_PRIVATE(descriptortype)) {
     case kUpb_FieldType_Message:
       if (sub_is_map) {
         const bool table_is_map = table->ext & kUpb_ExtMode_IsMapEntry;
@@ -11633,7 +11363,7 @@
   while (!_upb_Decoder_IsDone(d, &ptr)) {
     wireval elem;
     ptr = _upb_Decoder_DecodeVarint(d, ptr, &elem.uint64_val);
-    _upb_Decoder_Munge(field->descriptortype, &elem);
+    _upb_Decoder_Munge(field->UPB_PRIVATE(descriptortype), &elem);
     if (_upb_Decoder_Reserve(d, arr, 1)) {
       out = UPB_PTR_AT(_upb_array_ptr(arr), arr->size << lg2, void);
     }
@@ -11696,7 +11426,7 @@
       [kUpb_FieldType_SInt64] = 3,
   };
 
-  size_t lg2 = kElemSizeLg2[field->descriptortype];
+  size_t lg2 = kElemSizeLg2[field->UPB_PRIVATE(descriptortype)];
   upb_Array* ret = _upb_Array_New(&d->arena, 4, lg2);
   if (!ret) _upb_Decoder_ErrorJmp(d, kUpb_DecodeStatus_OutOfMemory);
   return ret;
@@ -11742,7 +11472,8 @@
       *UPB_PTR_AT(_upb_array_ptr(arr), arr->size * sizeof(void*),
                   upb_Message*) = submsg;
       arr->size++;
-      if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) {
+      if (UPB_UNLIKELY(field->UPB_PRIVATE(descriptortype) ==
+                       kUpb_FieldType_Group)) {
         return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, subs, field);
       } else {
         return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, subs, field,
@@ -11793,8 +11524,8 @@
 
   const upb_MiniTableField* key_field = &entry->fields[0];
   const upb_MiniTableField* val_field = &entry->fields[1];
-  char key_size = kSizeInMap[key_field->descriptortype];
-  char val_size = kSizeInMap[val_field->descriptortype];
+  char key_size = kSizeInMap[key_field->UPB_PRIVATE(descriptortype)];
+  char val_size = kSizeInMap[val_field->UPB_PRIVATE(descriptortype)];
   UPB_ASSERT(key_field->offset == offsetof(upb_MapEntryData, k));
   UPB_ASSERT(val_field->offset == offsetof(upb_MapEntryData, v));
   upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size);
@@ -11825,8 +11556,8 @@
   // Parse map entry.
   memset(&ent, 0, sizeof(ent));
 
-  if (entry->fields[1].descriptortype == kUpb_FieldType_Message ||
-      entry->fields[1].descriptortype == kUpb_FieldType_Group) {
+  if (entry->fields[1].UPB_PRIVATE(descriptortype) == kUpb_FieldType_Message ||
+      entry->fields[1].UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group) {
     const upb_MiniTable* submsg_table = entry->subs[0].submsg;
     // Any sub-message entry must be linked.  We do not allow dynamic tree
     // shaking in this case.
@@ -11869,7 +11600,7 @@
     const upb_MiniTableSub* subs, const upb_MiniTableField* field, wireval* val,
     int op) {
   void* mem = UPB_PTR_AT(msg, field->offset, void);
-  int type = field->descriptortype;
+  int type = field->UPB_PRIVATE(descriptortype);
 
   if (UPB_UNLIKELY(op == kUpb_DecodeOp_Enum) &&
       !_upb_Decoder_CheckEnum(d, ptr, msg,
@@ -12180,7 +11911,7 @@
       [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField,
   };
 
-  return kVarintOps[field->descriptortype];
+  return kVarintOps[field->UPB_PRIVATE(descriptortype)];
 }
 
 UPB_FORCEINLINE
@@ -12190,7 +11921,21 @@
   // If sub-message is not linked, treat as unknown.
   if (field->mode & kUpb_LabelFlags_IsExtension) return;
   const upb_MiniTableSub* sub = &mt->subs[field->UPB_PRIVATE(submsg_index)];
-  if (!sub->submsg) *op = kUpb_DecodeOp_UnknownField;
+  if (sub->submsg) return;
+#ifndef NDEBUG
+  const upb_MiniTableField* oneof = upb_MiniTable_GetOneof(mt, field);
+  if (oneof) {
+    // All other members of the oneof must be message fields that are also
+    // unlinked.
+    do {
+      assert(upb_MiniTableField_CType(oneof) == kUpb_CType_Message);
+      const upb_MiniTableSub* oneof_sub =
+          &mt->subs[oneof->UPB_PRIVATE(submsg_index)];
+      assert(!oneof_sub);
+    } while (upb_MiniTable_NextOneofField(mt, &oneof));
+  }
+#endif  // NDEBUG
+  *op = kUpb_DecodeOp_UnknownField;
 }
 
 int _upb_Decoder_GetDelimitedOp(const upb_MiniTable* mt,
@@ -12243,7 +11988,7 @@
       // repeated msgset type
   };
 
-  int ndx = field->descriptortype;
+  int ndx = field->UPB_PRIVATE(descriptortype);
   if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += kRepeatedBase;
   int op = kDelimitedOps[ndx];
 
@@ -12272,17 +12017,17 @@
     case kUpb_WireType_Varint:
       ptr = _upb_Decoder_DecodeVarint(d, ptr, &val->uint64_val);
       *op = _upb_Decoder_GetVarintOp(field);
-      _upb_Decoder_Munge(field->descriptortype, val);
+      _upb_Decoder_Munge(field->UPB_PRIVATE(descriptortype), val);
       return ptr;
     case kUpb_WireType_32Bit:
       *op = kUpb_DecodeOp_Scalar4Byte;
-      if (((1 << field->descriptortype) & kFixed32OkMask) == 0) {
+      if (((1 << field->UPB_PRIVATE(descriptortype)) & kFixed32OkMask) == 0) {
         *op = kUpb_DecodeOp_UnknownField;
       }
       return upb_WireReader_ReadFixed32(ptr, &val->uint32_val);
     case kUpb_WireType_64Bit:
       *op = kUpb_DecodeOp_Scalar8Byte;
-      if (((1 << field->descriptortype) & kFixed64OkMask) == 0) {
+      if (((1 << field->UPB_PRIVATE(descriptortype)) & kFixed64OkMask) == 0) {
         *op = kUpb_DecodeOp_UnknownField;
       }
       return upb_WireReader_ReadFixed64(ptr, &val->uint64_val);
@@ -12292,10 +12037,11 @@
       return ptr;
     case kUpb_WireType_StartGroup:
       val->uint32_val = field->number;
-      if (field->descriptortype == kUpb_FieldType_Group) {
+      if (field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group) {
         *op = kUpb_DecodeOp_SubMessage;
         _upb_Decoder_CheckUnlinked(mt, field, op);
-      } else if (field->descriptortype == kUpb_FakeFieldType_MessageSetItem) {
+      } else if (field->UPB_PRIVATE(descriptortype) ==
+                 kUpb_FakeFieldType_MessageSetItem) {
         *op = kUpb_DecodeOp_MessageSetItem;
       } else {
         *op = kUpb_DecodeOp_UnknownField;
@@ -13726,7 +13472,7 @@
     break;                                  \
   }
 
-  switch (f->descriptortype) {
+  switch (f->UPB_PRIVATE(descriptortype)) {
     case kUpb_FieldType_Double:
       CASE(double, double, kUpb_WireType_64Bit, val);
     case kUpb_FieldType_Float:
@@ -13821,7 +13567,7 @@
 
 #define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type))
 
-  switch (f->descriptortype) {
+  switch (f->UPB_PRIVATE(descriptortype)) {
     case kUpb_FieldType_Double:
       encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit));
       break;
@@ -13926,7 +13672,8 @@
 
   if (e->options & kUpb_EncodeOption_Deterministic) {
     _upb_sortedmap sorted;
-    _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map,
+    _upb_mapsorter_pushmap(&e->sorter,
+                           layout->fields[0].UPB_PRIVATE(descriptortype), map,
                            &sorted);
     upb_MapEntry ent;
     while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h
index 48dff8d..8a111a6 100755
--- a/ruby/ext/google/protobuf_c/ruby-upb.h
+++ b/ruby/ext/google/protobuf_c/ruby-upb.h
@@ -848,6 +848,7 @@
 // Resize without initializing new elements.
 UPB_INLINE bool _upb_Array_ResizeUninitialized(upb_Array* arr, size_t size,
                                                upb_Arena* arena) {
+  UPB_ASSERT(size <= arr->size || arena);  // Allow NULL arena when shrinking.
   if (!_upb_array_reserve(arr, size, arena)) return false;
   arr->size = size;
   return true;
@@ -1459,11 +1460,9 @@
 #define UPB_MESSAGE_EXTENSION_INTERNAL_H_
 
 
-// Public APIs for message operations that do not require descriptors.
-// These functions can be used even in build that does not want to depend on
-// reflection or descriptors.
+// Public APIs for message operations that do not depend on the schema.
 //
-// Descriptor-based reflection functionality lives in reflection.h.
+// MiniTable-based accessors live in accessors.h.
 
 #ifndef UPB_MESSAGE_MESSAGE_H_
 #define UPB_MESSAGE_MESSAGE_H_
@@ -1521,7 +1520,7 @@
   // Will be set to `kUpb_NoSub` if `descriptortype` != MESSAGE/GROUP/ENUM
   uint16_t UPB_PRIVATE(submsg_index);
 
-  uint8_t descriptortype;
+  uint8_t UPB_PRIVATE(descriptortype);
 
   // upb_FieldMode | upb_LabelFlags | (upb_FieldRep << kUpb_FieldRep_Shift)
   uint8_t mode;
@@ -1599,8 +1598,8 @@
 }
 
 UPB_INLINE bool upb_IsSubMessage(const upb_MiniTableField* field) {
-  return field->descriptortype == kUpb_FieldType_Message ||
-         field->descriptortype == kUpb_FieldType_Group;
+  return field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Message ||
+         field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group;
 }
 
 // LINT.IfChange(presence_logic)
@@ -2226,6 +2225,10 @@
 #define UPB_MESSAGE_ACCESSORS_H_
 
 
+#ifndef UPB_MESSAGE_ACCESSORS_INTERNAL_H_
+#define UPB_MESSAGE_ACCESSORS_INTERNAL_H_
+
+
 #ifndef UPB_MINI_TABLE_COMMON_H_
 #define UPB_MINI_TABLE_COMMON_H_
 
@@ -2261,7 +2264,7 @@
 UPB_API upb_FieldType upb_MiniTableField_Type(const upb_MiniTableField* field);
 
 UPB_API_INLINE upb_CType upb_MiniTableField_CType(const upb_MiniTableField* f) {
-  switch (f->descriptortype) {
+  switch (f->UPB_PRIVATE(descriptortype)) {
     case kUpb_FieldType_Double:
       return kUpb_CType_Double;
     case kUpb_FieldType_Float:
@@ -2300,6 +2303,11 @@
   return field->mode & kUpb_LabelFlags_IsExtension;
 }
 
+UPB_API_INLINE bool upb_MiniTableField_IsClosedEnum(
+    const upb_MiniTableField* field) {
+  return field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Enum;
+}
+
 UPB_API_INLINE bool upb_MiniTableField_HasPresence(
     const upb_MiniTableField* field) {
   if (upb_MiniTableField_IsExtension(field)) {
@@ -2472,7 +2480,7 @@
       2,               // kUpb_FieldType_SInt32 = 17,
       3,               // kUpb_FieldType_SInt64 = 18,
   };
-  return table[field->descriptortype];
+  return table[field->UPB_PRIVATE(descriptortype)];
 }
 
 // Here we define universal getter/setter functions for message fields.
@@ -2492,7 +2500,7 @@
 //   UPB_INLINE bool upb_Message_SetBool(upb_Message* msg,
 //                                       const upb_MiniTableField* field,
 //                                       bool value, upb_Arena* a) {
-//     UPB_ASSUME(field->descriptortype == kUpb_FieldType_Bool);
+//     UPB_ASSUME(field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bool);
 //     UPB_ASSUME(!upb_IsRepeatedOrMap(field));
 //     UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte);
 //     _upb_Message_SetField(msg, field, &value, a);
@@ -2636,7 +2644,22 @@
   return map;
 }
 
-// EVERYTHING ABOVE THIS LINE IS INTERNAL - DO NOT USE /////////////////////////
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+
+#endif  // UPB_MESSAGE_ACCESSORS_INTERNAL_H_
+
+// Must be last.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 UPB_API_INLINE void upb_Message_ClearField(upb_Message* msg,
                                            const upb_MiniTableField* field) {
@@ -2667,9 +2690,9 @@
 UPB_API_INLINE bool upb_Message_GetBool(const upb_Message* msg,
                                         const upb_MiniTableField* field,
                                         bool default_val) {
-  UPB_ASSUME(field->descriptortype == kUpb_FieldType_Bool);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Bool);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   bool ret;
   _upb_Message_GetField(msg, field, &default_val, &ret);
   return ret;
@@ -2678,21 +2701,19 @@
 UPB_API_INLINE bool upb_Message_SetBool(upb_Message* msg,
                                         const upb_MiniTableField* field,
                                         bool value, upb_Arena* a) {
-  UPB_ASSUME(field->descriptortype == kUpb_FieldType_Bool);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Bool);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   return _upb_Message_SetField(msg, field, &value, a);
 }
 
 UPB_API_INLINE int32_t upb_Message_GetInt32(const upb_Message* msg,
                                             const upb_MiniTableField* field,
                                             int32_t default_val) {
-  UPB_ASSUME(field->descriptortype == kUpb_FieldType_Int32 ||
-             field->descriptortype == kUpb_FieldType_SInt32 ||
-             field->descriptortype == kUpb_FieldType_SFixed32 ||
-             field->descriptortype == kUpb_FieldType_Enum);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Int32 ||
+             upb_MiniTableField_CType(field) == kUpb_CType_Enum);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   int32_t ret;
   _upb_Message_GetField(msg, field, &default_val, &ret);
   return ret;
@@ -2701,21 +2722,18 @@
 UPB_API_INLINE bool upb_Message_SetInt32(upb_Message* msg,
                                          const upb_MiniTableField* field,
                                          int32_t value, upb_Arena* a) {
-  UPB_ASSUME(field->descriptortype == kUpb_FieldType_Int32 ||
-             field->descriptortype == kUpb_FieldType_SInt32 ||
-             field->descriptortype == kUpb_FieldType_SFixed32);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Int32);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   return _upb_Message_SetField(msg, field, &value, a);
 }
 
 UPB_API_INLINE uint32_t upb_Message_GetUInt32(const upb_Message* msg,
                                               const upb_MiniTableField* field,
                                               uint32_t default_val) {
-  UPB_ASSUME(field->descriptortype == kUpb_FieldType_UInt32 ||
-             field->descriptortype == kUpb_FieldType_Fixed32);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_UInt32);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   uint32_t ret;
   _upb_Message_GetField(msg, field, &default_val, &ret);
   return ret;
@@ -2724,19 +2742,18 @@
 UPB_API_INLINE bool upb_Message_SetUInt32(upb_Message* msg,
                                           const upb_MiniTableField* field,
                                           uint32_t value, upb_Arena* a) {
-  UPB_ASSUME(field->descriptortype == kUpb_FieldType_UInt32 ||
-             field->descriptortype == kUpb_FieldType_Fixed32);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_UInt32);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   return _upb_Message_SetField(msg, field, &value, a);
 }
 
 UPB_API_INLINE void upb_Message_SetEnumProto2(
     upb_Message* msg, const upb_MiniTable* msg_mini_table,
     const upb_MiniTableField* field, int32_t value) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSERT(upb_MiniTableField_IsClosedEnum(field));
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   UPB_ASSERT(upb_MiniTableEnum_CheckValue(
       upb_MiniTable_GetSubEnumTable(msg_mini_table, field), value));
   _upb_Message_SetNonExtensionField(msg, field, &value);
@@ -2745,11 +2762,9 @@
 UPB_API_INLINE int64_t upb_Message_GetInt64(const upb_Message* msg,
                                             const upb_MiniTableField* field,
                                             uint64_t default_val) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int64 ||
-             field->descriptortype == kUpb_FieldType_SInt64 ||
-             field->descriptortype == kUpb_FieldType_SFixed64);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Int64);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   int64_t ret;
   _upb_Message_GetField(msg, field, &default_val, &ret);
   return ret;
@@ -2758,21 +2773,18 @@
 UPB_API_INLINE bool upb_Message_SetInt64(upb_Message* msg,
                                          const upb_MiniTableField* field,
                                          int64_t value, upb_Arena* a) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int64 ||
-             field->descriptortype == kUpb_FieldType_SInt64 ||
-             field->descriptortype == kUpb_FieldType_SFixed64);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Int64);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   return _upb_Message_SetField(msg, field, &value, a);
 }
 
 UPB_API_INLINE uint64_t upb_Message_GetUInt64(const upb_Message* msg,
                                               const upb_MiniTableField* field,
                                               uint64_t default_val) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt64 ||
-             field->descriptortype == kUpb_FieldType_Fixed64);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_UInt64);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   uint64_t ret;
   _upb_Message_GetField(msg, field, &default_val, &ret);
   return ret;
@@ -2781,19 +2793,18 @@
 UPB_API_INLINE bool upb_Message_SetUInt64(upb_Message* msg,
                                           const upb_MiniTableField* field,
                                           uint64_t value, upb_Arena* a) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt64 ||
-             field->descriptortype == kUpb_FieldType_Fixed64);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_UInt64);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   return _upb_Message_SetField(msg, field, &value, a);
 }
 
 UPB_API_INLINE float upb_Message_GetFloat(const upb_Message* msg,
                                           const upb_MiniTableField* field,
                                           float default_val) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Float);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Float);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   float ret;
   _upb_Message_GetField(msg, field, &default_val, &ret);
   return ret;
@@ -2802,18 +2813,18 @@
 UPB_API_INLINE bool upb_Message_SetFloat(upb_Message* msg,
                                          const upb_MiniTableField* field,
                                          float value, upb_Arena* a) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Float);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Float);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_4Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   return _upb_Message_SetField(msg, field, &value, a);
 }
 
 UPB_API_INLINE double upb_Message_GetDouble(const upb_Message* msg,
                                             const upb_MiniTableField* field,
                                             double default_val) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Double);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Double);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   double ret;
   _upb_Message_GetField(msg, field, &default_val, &ret);
   return ret;
@@ -2822,19 +2833,19 @@
 UPB_API_INLINE bool upb_Message_SetDouble(upb_Message* msg,
                                           const upb_MiniTableField* field,
                                           double value, upb_Arena* a) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Double);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Double);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_8Byte);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   return _upb_Message_SetField(msg, field, &value, a);
 }
 
 UPB_API_INLINE upb_StringView
 upb_Message_GetString(const upb_Message* msg, const upb_MiniTableField* field,
                       upb_StringView def_val) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bytes ||
-             field->descriptortype == kUpb_FieldType_String);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_String ||
+             upb_MiniTableField_CType(field) == kUpb_CType_Bytes);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_StringView);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   upb_StringView ret;
   _upb_Message_GetField(msg, field, &def_val, &ret);
   return ret;
@@ -2843,21 +2854,20 @@
 UPB_API_INLINE bool upb_Message_SetString(upb_Message* msg,
                                           const upb_MiniTableField* field,
                                           upb_StringView value, upb_Arena* a) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bytes ||
-             field->descriptortype == kUpb_FieldType_String);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_String ||
+             upb_MiniTableField_CType(field) == kUpb_CType_Bytes);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_StringView);
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   return _upb_Message_SetField(msg, field, &value, a);
 }
 
 UPB_API_INLINE const upb_Message* upb_Message_GetMessage(
     const upb_Message* msg, const upb_MiniTableField* field,
     upb_Message* default_val) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message ||
-             field->descriptortype == kUpb_FieldType_Group);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Message);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) ==
              UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte));
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   upb_Message* ret;
   _upb_Message_GetNonExtensionField(msg, field, &default_val, &ret);
   return ret;
@@ -2867,11 +2877,10 @@
                                            const upb_MiniTable* mini_table,
                                            const upb_MiniTableField* field,
                                            upb_Message* sub_message) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message ||
-             field->descriptortype == kUpb_FieldType_Group);
-  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Message);
   UPB_ASSUME(_upb_MiniTableField_GetRep(field) ==
              UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte));
+  UPB_ASSUME(!upb_IsRepeatedOrMap(field));
   UPB_ASSERT(mini_table->subs[field->UPB_PRIVATE(submsg_index)].submsg);
   _upb_Message_SetNonExtensionField(msg, field, &sub_message);
 }
@@ -2879,8 +2888,8 @@
 UPB_API_INLINE upb_Message* upb_Message_GetOrCreateMutableMessage(
     upb_Message* msg, const upb_MiniTable* mini_table,
     const upb_MiniTableField* field, upb_Arena* arena) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message ||
-             field->descriptortype == kUpb_FieldType_Group);
+  UPB_ASSERT(arena);
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Message);
   upb_Message* sub_message = *UPB_PTR_AT(msg, field->offset, upb_Message*);
   if (!sub_message) {
     const upb_MiniTable* sub_mini_table =
@@ -2910,6 +2919,7 @@
 
 UPB_API_INLINE upb_Array* upb_Message_GetOrCreateMutableArray(
     upb_Message* msg, const upb_MiniTableField* field, upb_Arena* arena) {
+  UPB_ASSERT(arena);
   _upb_MiniTableField_CheckIsArray(field);
   upb_Array* array = upb_Message_GetMutableArray(msg, field);
   if (!array) {
@@ -2942,11 +2952,6 @@
   return _upb_array_ptr(arr);
 }
 
-UPB_API_INLINE bool upb_MiniTableField_IsClosedEnum(
-    const upb_MiniTableField* field) {
-  return field->descriptortype == kUpb_FieldType_Enum;
-}
-
 UPB_API_INLINE const upb_Map* upb_Message_GetMap(
     const upb_Message* msg, const upb_MiniTableField* field) {
   _upb_MiniTableField_CheckIsMap(field);
@@ -2959,8 +2964,7 @@
 UPB_API_INLINE upb_Map* upb_Message_GetOrCreateMutableMap(
     upb_Message* msg, const upb_MiniTable* map_entry_mini_table,
     const upb_MiniTableField* field, upb_Arena* arena) {
-  UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message ||
-             field->descriptortype == kUpb_FieldType_Group);
+  UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Message);
   const upb_MiniTableField* map_entry_key_field =
       &map_entry_mini_table->fields[0];
   const upb_MiniTableField* map_entry_value_field =
@@ -2979,108 +2983,10 @@
                                                upb_Message* map_entry_message,
                                                upb_Arena* arena);
 
-typedef enum {
-  kUpb_GetExtension_Ok,
-  kUpb_GetExtension_NotPresent,
-  kUpb_GetExtension_ParseError,
-  kUpb_GetExtension_OutOfMemory,
-} upb_GetExtension_Status;
-
-typedef enum {
-  kUpb_GetExtensionAsBytes_Ok,
-  kUpb_GetExtensionAsBytes_NotPresent,
-  kUpb_GetExtensionAsBytes_EncodeError,
-} upb_GetExtensionAsBytes_Status;
-
-// Returns a message extension or promotes an unknown field to
-// an extension.
-//
-// TODO(ferhat): Only supports extension fields that are messages,
-// expand support to include non-message types.
-upb_GetExtension_Status upb_MiniTable_GetOrPromoteExtension(
-    upb_Message* msg, const upb_MiniTableExtension* ext_table,
-    int decode_options, upb_Arena* arena,
-    const upb_Message_Extension** extension);
-
-// Returns a message extension or unknown field matching the extension
-// data as bytes.
-//
-// If an extension has already been decoded it will be re-encoded
-// to bytes.
-upb_GetExtensionAsBytes_Status upb_MiniTable_GetExtensionAsBytes(
-    const upb_Message* msg, const upb_MiniTableExtension* ext_table,
-    int encode_options, upb_Arena* arena, const char** extension_data,
-    size_t* len);
-
-typedef enum {
-  kUpb_FindUnknown_Ok,
-  kUpb_FindUnknown_NotPresent,
-  kUpb_FindUnknown_ParseError,
-} upb_FindUnknown_Status;
-
-typedef struct {
-  upb_FindUnknown_Status status;
-  // Start of unknown field data in message arena.
-  const char* ptr;
-  // Size of unknown field data.
-  size_t len;
-} upb_FindUnknownRet;
-
-// Finds first occurrence of unknown data by tag id in message.
-upb_FindUnknownRet upb_MiniTable_FindUnknown(const upb_Message* msg,
-                                             uint32_t field_number,
-                                             int depth_limit);
-
-typedef enum {
-  kUpb_UnknownToMessage_Ok,
-  kUpb_UnknownToMessage_ParseError,
-  kUpb_UnknownToMessage_OutOfMemory,
-  kUpb_UnknownToMessage_NotFound,
-} upb_UnknownToMessage_Status;
-
-typedef struct {
-  upb_UnknownToMessage_Status status;
-  upb_Message* message;
-} upb_UnknownToMessageRet;
-
-// Promotes unknown data inside message to a upb_Message parsing the unknown.
-//
-// The unknown data is removed from message after field value is set
-// using upb_Message_SetMessage.
-//
-// WARNING!: See b/267655898
-upb_UnknownToMessageRet upb_MiniTable_PromoteUnknownToMessage(
-    upb_Message* msg, const upb_MiniTable* mini_table,
-    const upb_MiniTableField* field, const upb_MiniTable* sub_mini_table,
-    int decode_options, upb_Arena* arena);
-
-// Promotes all unknown data that matches field tag id to repeated messages
-// in upb_Array.
-//
-// The unknown data is removed from message after upb_Array is populated.
-// Since repeated messages can't be packed we remove each unknown that
-// contains the target tag id.
-upb_UnknownToMessage_Status upb_MiniTable_PromoteUnknownToMessageArray(
-    upb_Message* msg, const upb_MiniTableField* field,
-    const upb_MiniTable* mini_table, int decode_options, upb_Arena* arena);
-
-// Promotes all unknown data that matches field tag id to upb_Map.
-//
-// The unknown data is removed from message after upb_Map is populated.
-// Since repeated messages can't be packed we remove each unknown that
-// contains the target tag id.
-upb_UnknownToMessage_Status upb_MiniTable_PromoteUnknownToMap(
-    upb_Message* msg, const upb_MiniTable* mini_table,
-    const upb_MiniTableField* field, int decode_options, upb_Arena* arena);
-
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
 
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
 
 #endif  // UPB_MESSAGE_ACCESSORS_H_
 
@@ -3138,10 +3044,11 @@
 
 typedef enum {
   kUpb_DecodeStatus_Ok = 0,
-  kUpb_DecodeStatus_Malformed = 1,         // Wire format was corrupt
-  kUpb_DecodeStatus_OutOfMemory = 2,       // Arena alloc failed
-  kUpb_DecodeStatus_BadUtf8 = 3,           // String field had bad UTF-8
-  kUpb_DecodeStatus_MaxDepthExceeded = 4,  // Exceeded UPB_DECODE_MAXDEPTH
+  kUpb_DecodeStatus_Malformed = 1,    // Wire format was corrupt
+  kUpb_DecodeStatus_OutOfMemory = 2,  // Arena alloc failed
+  kUpb_DecodeStatus_BadUtf8 = 3,      // String field had bad UTF-8
+  kUpb_DecodeStatus_MaxDepthExceeded =
+      4,  // Exceeded upb_DecodeOptions_MaxDepth
 
   // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise
   // succeeded.
@@ -3319,24 +3226,37 @@
    * memory during encode. */
   kUpb_EncodeOption_Deterministic = 1,
 
-  /* When set, unknown fields are not printed. */
+  // When set, unknown fields are not printed.
   kUpb_EncodeOption_SkipUnknown = 2,
 
-  /* When set, the encode will fail if any required fields are missing. */
+  // When set, the encode will fail if any required fields are missing.
   kUpb_EncodeOption_CheckRequired = 4,
 };
 
-#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16)
-
 typedef enum {
   kUpb_EncodeStatus_Ok = 0,
-  kUpb_EncodeStatus_OutOfMemory = 1,       // Arena alloc failed
-  kUpb_EncodeStatus_MaxDepthExceeded = 2,  // Exceeded UPB_ENCODE_MAXDEPTH
+  kUpb_EncodeStatus_OutOfMemory = 1,  // Arena alloc failed
+  kUpb_EncodeStatus_MaxDepthExceeded = 2,
 
   // kUpb_EncodeOption_CheckRequired failed but the parse otherwise succeeded.
   kUpb_EncodeStatus_MissingRequired = 3,
 } upb_EncodeStatus;
 
+UPB_INLINE uint32_t upb_EncodeOptions_MaxDepth(uint16_t depth) {
+  return (uint32_t)depth << 16;
+}
+
+UPB_INLINE uint16_t upb_EncodeOptions_GetMaxDepth(uint32_t options) {
+  return options >> 16;
+}
+
+// Enforce an upper bound on recursion depth.
+UPB_INLINE int upb_Encode_LimitDepth(uint32_t encode_options, uint32_t limit) {
+  uint32_t max_depth = upb_EncodeOptions_GetMaxDepth(encode_options);
+  if (max_depth > limit) max_depth = limit;
+  return upb_EncodeOptions_MaxDepth(max_depth) | (encode_options & 0xffff);
+}
+
 upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l,
                             int options, upb_Arena* arena, char** buf,
                             size_t* size);
@@ -9769,7 +9689,9 @@
 #define upb_Atomic_Add(addr, val, order) \
   atomic_fetch_add_explicit(addr, val, order)
 #define upb_Atomic_Sub(addr, val, order) \
-  atomic_fetch_sub_explicit(addr, val, memory_order_release);
+  atomic_fetch_sub_explicit(addr, val, order)
+#define upb_Atomic_Exchange(addr, val, order) \
+  atomic_exchange_explicit(addr, val, order)
 #define upb_Atomic_CompareExchangeStrong(addr, expected, desired,      \
                                          success_order, failure_order) \
   atomic_compare_exchange_strong_explicit(addr, expected, desired,     \
@@ -9789,6 +9711,15 @@
 #define upb_Atomic_Add(addr, val, order) (*(addr) += val)
 #define upb_Atomic_Sub(addr, val, order) (*(addr) -= val)
 
+UPB_INLINE void* _upb_NonAtomic_Exchange(void* addr, void* value) {
+  void* old;
+  memcpy(&old, addr, sizeof(value));
+  memcpy(addr, &value, sizeof(value));
+  return old;
+}
+
+#define upb_Atomic_Exchange(addr, val, order) _upb_NonAtomic_Exchange(addr, val)
+
 // `addr` and `expected` are logically double pointers.
 UPB_INLINE bool _upb_NonAtomic_CompareExchangeStrongP(void* addr,
                                                       void* expected,