Move iteration APIs to headers, so they're inlined in loop calls

PiperOrigin-RevId: 698497070
diff --git a/upb/message/compare.c b/upb/message/compare.c
index 49ee33e..6963ea5 100644
--- a/upb/message/compare.c
+++ b/upb/message/compare.c
@@ -142,8 +142,8 @@
   upb_MessageValue val1;
 
   // Iterate over all extensions for msg1, and search msg2 for each extension.
-  size_t iter1 = kUpb_Extension_Begin;
-  while (UPB_PRIVATE(_upb_Message_NextExtension)(msg1, m, &e, &val1, &iter1)) {
+  size_t iter1 = kUpb_Message_ExtensionBegin;
+  while (upb_Message_NextExtension(msg1, &e, &val1, &iter1)) {
     const upb_Extension* ext2 = UPB_PRIVATE(_upb_Message_Getext)(msg2, e);
     if (!ext2) return false;
 
diff --git a/upb/message/compat.c b/upb/message/compat.c
index 1bb2adc..0d79887 100644
--- a/upb/message/compat.c
+++ b/upb/message/compat.c
@@ -10,36 +10,27 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "upb/message/internal/extension.h"
 #include "upb/message/message.h"
+#include "upb/message/value.h"
 #include "upb/mini_table/extension.h"
 
 // Must be last.
 #include "upb/port/def.inc"
 
-bool upb_Message_NextExtension(const upb_Message* msg,
-                               const upb_MiniTableExtension** result,
-                               uintptr_t* iter) {
-  size_t count;
-  const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
-  size_t i = *iter;
-  if (i >= count) {
-    return false;
-    *result = NULL;
-  }
-  *result = ext[i].ext;
-  *iter = i + 1;
-  return true;
+bool upb_Message_NextExtensionReverse(const upb_Message* msg,
+                                      const upb_MiniTableExtension** result,
+                                      uintptr_t* iter) {
+  upb_MessageValue val;
+  return UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, result, &val,
+                                                        iter);
 }
 
 const upb_MiniTableExtension* upb_Message_FindExtensionByNumber(
     const upb_Message* msg, uint32_t field_number) {
-  size_t count;
-  const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
-
-  for (; count--; ext++) {
-    const upb_MiniTableExtension* e = ext->ext;
-    if (upb_MiniTableExtension_Number(e) == field_number) return e;
+  uintptr_t iter = kUpb_Message_ExtensionBegin;
+  const upb_MiniTableExtension* result;
+  while (upb_Message_NextExtensionReverse(msg, &result, &iter)) {
+    if (upb_MiniTableExtension_Number(result) == field_number) return result;
   }
   return NULL;
 }
diff --git a/upb/message/compat.h b/upb/message/compat.h
index 14ed2fe..7600ffa 100644
--- a/upb/message/compat.h
+++ b/upb/message/compat.h
@@ -25,11 +25,10 @@
 extern "C" {
 #endif
 
-#define kUpb_Message_ExtensionBegin 0;
-
-bool upb_Message_NextExtension(const upb_Message* msg,
-                               const upb_MiniTableExtension** result,
-                               uintptr_t* iter);
+// Same as upb_Message_NextExtension but iterates in reverse wire order
+bool upb_Message_NextExtensionReverse(const upb_Message* msg,
+                                      const upb_MiniTableExtension** result,
+                                      uintptr_t* iter);
 // Returns the minitable with the given field number, or NULL on failure.
 const upb_MiniTableExtension* upb_Message_FindExtensionByNumber(
     const upb_Message* msg, uint32_t field_number);
diff --git a/upb/message/internal/extension.c b/upb/message/internal/extension.c
index f55253d..5eb41c4 100644
--- a/upb/message/internal/extension.c
+++ b/upb/message/internal/extension.c
@@ -40,7 +40,7 @@
   upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
   if (in) {
     *count = (in->size - in->ext_begin) / sizeof(upb_Extension);
-    return UPB_PTR_AT(in, in->ext_begin, void);
+    return UPB_PTR_AT(in, in->ext_begin, const upb_Extension);
   } else {
     *count = 0;
     return NULL;
diff --git a/upb/message/internal/iterator.c b/upb/message/internal/iterator.c
index 82f2b37..b3ad76c 100644
--- a/upb/message/internal/iterator.c
+++ b/upb/message/internal/iterator.c
@@ -12,10 +12,8 @@
 #include "upb/message/accessors.h"
 #include "upb/message/array.h"
 #include "upb/message/internal/accessors.h"
-#include "upb/message/internal/extension.h"
 #include "upb/message/map.h"
 #include "upb/message/message.h"
-#include "upb/mini_table/extension.h"
 #include "upb/mini_table/field.h"
 #include "upb/mini_table/message.h"
 
@@ -58,21 +56,3 @@
 
   return false;
 }
-
-bool UPB_PRIVATE(_upb_Message_NextExtension)(
-    const upb_Message* msg, const upb_MiniTable* m,
-    const upb_MiniTableExtension** out_e, upb_MessageValue* out_v,
-    size_t* iter) {
-  size_t count;
-  const upb_Extension* exts = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
-  size_t i = *iter;
-
-  if (++i < count) {
-    *out_e = exts[i].ext;
-    *out_v = exts[i].data;
-    *iter = i;
-    return true;
-  }
-
-  return false;
-}
\ No newline at end of file
diff --git a/upb/message/internal/iterator.h b/upb/message/internal/iterator.h
index ad080db..484762d 100644
--- a/upb/message/internal/iterator.h
+++ b/upb/message/internal/iterator.h
@@ -9,10 +9,10 @@
 #define THIRD_PARTY_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H_
 
 #include <stddef.h>
+#include <stdint.h>
 
 #include "upb/message/message.h"
 #include "upb/message/value.h"
-#include "upb/mini_table/extension.h"
 #include "upb/mini_table/field.h"
 #include "upb/mini_table/message.h"
 
@@ -20,16 +20,10 @@
 #include "upb/port/def.inc"
 
 #define kUpb_BaseField_Begin ((size_t)-1)
-#define kUpb_Extension_Begin ((size_t)-1)
-
 bool UPB_PRIVATE(_upb_Message_NextBaseField)(const upb_Message* msg,
                                              const upb_MiniTable* m,
                                              const upb_MiniTableField** out_f,
                                              upb_MessageValue* out_v,
-                                             size_t* iter);
+                                             uintptr_t* iter);
 
-bool UPB_PRIVATE(_upb_Message_NextExtension)(
-    const upb_Message* msg, const upb_MiniTable* m,
-    const upb_MiniTableExtension** out_e, upb_MessageValue* out_v,
-    size_t* iter);
 #endif  // THIRD_PARTY_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H_
diff --git a/upb/message/internal/map_sorter.h b/upb/message/internal/map_sorter.h
index 33474d1..bd997bc 100644
--- a/upb/message/internal/map_sorter.h
+++ b/upb/message/internal/map_sorter.h
@@ -18,6 +18,7 @@
 #include "upb/message/internal/extension.h"
 #include "upb/message/internal/map.h"
 #include "upb/message/internal/map_entry.h"
+#include "upb/message/internal/message.h"
 
 // Must be last.
 #include "upb/port/def.inc"
@@ -80,7 +81,7 @@
 bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
                             const struct upb_Map* map, _upb_sortedmap* sorted);
 
-bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Extension* exts,
+bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in,
                              size_t count, _upb_sortedmap* sorted);
 
 #ifdef __cplusplus
diff --git a/upb/message/internal/message.h b/upb/message/internal/message.h
index 2f7f0fa..c00b911 100644
--- a/upb/message/internal/message.h
+++ b/upb/message/internal/message.h
@@ -15,11 +15,15 @@
 #ifndef UPB_MESSAGE_INTERNAL_MESSAGE_H_
 #define UPB_MESSAGE_INTERNAL_MESSAGE_H_
 
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include "upb/base/string_view.h"
 #include "upb/mem/arena.h"
 #include "upb/message/internal/extension.h"
+#include "upb/message/internal/types.h"
+#include "upb/mini_table/extension.h"
 #include "upb/mini_table/message.h"
 
 // Must be last.
@@ -101,6 +105,68 @@
 bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need,
                                        upb_Arena* arena);
 
+#define kUpb_Message_UnknownBegin 0
+#define kUpb_Message_ExtensionBegin 0
+
+UPB_INLINE bool upb_Message_NextUnknown(const struct upb_Message* msg,
+                                        upb_StringView* data, uintptr_t* iter) {
+  const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
+  if (in && *iter == kUpb_Message_UnknownBegin) {
+    size_t len = in->unknown_end - sizeof(upb_Message_Internal);
+    if (len != 0) {
+      data->size = len;
+      data->data = (const char*)(in + 1);
+      (*iter)++;
+      return true;
+    }
+  }
+  data->size = 0;
+  data->data = NULL;
+  return false;
+}
+
+UPB_INLINE bool upb_Message_HasUnknown(const struct upb_Message* msg) {
+  upb_StringView data;
+  uintptr_t iter = kUpb_Message_UnknownBegin;
+  return upb_Message_NextUnknown(msg, &data, &iter);
+}
+
+UPB_INLINE bool upb_Message_NextExtension(const struct upb_Message* msg,
+                                          const upb_MiniTableExtension** out_e,
+                                          upb_MessageValue* out_v,
+                                          uintptr_t* iter) {
+  size_t count;
+  const upb_Extension* exts = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
+  size_t i = *iter;
+  if (i < count) {
+    // Extensions are stored in reverse wire order, so to iterate in wire order,
+    // we need to iterate backwards.
+    *out_e = exts[count - 1 - i].ext;
+    *out_v = exts[count - 1 - i].data;
+    *iter = i + 1;
+    return true;
+  }
+
+  return false;
+}
+
+UPB_INLINE bool UPB_PRIVATE(_upb_Message_NextExtensionReverse)(
+    const struct upb_Message* msg, const upb_MiniTableExtension** out_e,
+    upb_MessageValue* out_v, uintptr_t* iter) {
+  size_t count;
+  const upb_Extension* exts = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
+  size_t i = *iter;
+  if (i < count) {
+    // Extensions are stored in reverse wire order
+    *out_e = exts[i].ext;
+    *out_v = exts[i].data;
+    *iter = i + 1;
+    return true;
+  }
+
+  return false;
+}
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/upb/message/map_sorter.c b/upb/message/map_sorter.c
index f0a4865..f0836ca 100644
--- a/upb/message/map_sorter.c
+++ b/upb/message/map_sorter.c
@@ -14,8 +14,9 @@
 #include "upb/base/internal/log2.h"
 #include "upb/base/string_view.h"
 #include "upb/mem/alloc.h"
+#include "upb/message/internal/extension.h"
+#include "upb/message/internal/message.h"
 #include "upb/message/map.h"
-#include "upb/message/message.h"
 #include "upb/mini_table/extension.h"
 
 // Must be last.
@@ -144,14 +145,15 @@
   return a_num < b_num ? -1 : 1;
 }
 
-bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Extension* exts,
+bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in,
                              size_t count, _upb_sortedmap* sorted) {
   if (!_upb_mapsorter_resize(s, sorted, count)) return false;
+  const upb_Extension* exts =
+      UPB_PTR_AT(in, in->ext_begin, const upb_Extension);
 
   for (size_t i = 0; i < count; i++) {
     s->entries[sorted->start + i] = &exts[i];
   }
-
   qsort(&s->entries[sorted->start], count, sizeof(*s->entries),
         _upb_mapsorter_cmpext);
   return true;
diff --git a/upb/message/message.c b/upb/message/message.c
index 6ac5788..3a2d8e5 100644
--- a/upb/message/message.c
+++ b/upb/message/message.c
@@ -30,8 +30,6 @@
 // Must be last.
 #include "upb/port/def.inc"
 
-static const size_t message_overhead = sizeof(upb_Message_Internal);
-
 upb_Message* upb_Message_New(const upb_MiniTable* m, upb_Arena* a) {
   return _upb_Message_New(m, a);
 }
@@ -75,39 +73,14 @@
   UPB_ASSERT(!upb_Message_IsFrozen(msg));
   upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
   if (in) {
-    in->unknown_end = message_overhead;
+    in->unknown_end = sizeof(upb_Message_Internal);
   }
 }
 
-bool upb_Message_NextUnknown(const upb_Message* msg, upb_StringView* data,
-                             uintptr_t* iter) {
-  const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
-  if (in && *iter == kUpb_Message_UnknownBegin) {
-    size_t len = in->unknown_end - message_overhead;
-    if (len != 0) {
-      data->size = len;
-      data->data = (const char*)(in + 1);
-      (*iter)++;
-      return true;
-    }
-  }
-  data->size = 0;
-  data->data = NULL;
-  return false;
-}
-
-bool upb_Message_HasUnknown(const upb_Message* msg) {
-  const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
-  if (in) {
-    return in->unknown_end > message_overhead;
-  }
-  return false;
-}
-
 const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) {
   upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
   if (in) {
-    *len = in->unknown_end - message_overhead;
+    *len = in->unknown_end - sizeof(upb_Message_Internal);
     return (char*)(in + 1);
   } else {
     *len = 0;
@@ -185,17 +158,13 @@
   }
 
   // Extensions.
-  size_t ext_count;
-  const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count);
-
-  for (size_t i = 0; i < ext_count; i++) {
-    const upb_MiniTableExtension* e = ext[i].ext;
+  uintptr_t iter = kUpb_Message_ExtensionBegin;
+  const upb_MiniTableExtension* e;
+  upb_MessageValue val;
+  while (upb_Message_NextExtension(msg, &e, &val, &iter)) {
     const upb_MiniTableField* f = &e->UPB_PRIVATE(field);
     const upb_MiniTable* m2 = upb_MiniTableExtension_GetSubMessage(e);
 
-    upb_MessageValue val;
-    memcpy(&val, &ext[i].data, sizeof(upb_MessageValue));
-
     switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) {
       case kUpb_FieldMode_Array: {
         upb_Array* arr = (upb_Array*)val.array_val;
diff --git a/upb/message/message.h b/upb/message/message.h
index a33cf32..f50cadb 100644
--- a/upb/message/message.h
+++ b/upb/message/message.h
@@ -17,8 +17,11 @@
 
 #include "upb/base/string_view.h"
 #include "upb/mem/arena.h"
+#include "upb/message/array.h"
+#include "upb/message/internal/extension.h"
 #include "upb/message/internal/message.h"
 #include "upb/message/internal/types.h"
+#include "upb/mini_table/extension.h"
 #include "upb/mini_table/message.h"
 
 // Must be last.
@@ -42,13 +45,15 @@
 //   while (upb_Message_NextUnknown(msg, &data, &iter)) {
 //     // Use data
 //   }
+// Iterates in the order unknown fields were parsed.
 
 #define kUpb_Message_UnknownBegin 0
+#define kUpb_Message_ExtensionBegin 0
 
-bool upb_Message_NextUnknown(const upb_Message* msg, upb_StringView* data,
-                             uintptr_t* iter);
+UPB_INLINE bool upb_Message_NextUnknown(const upb_Message* msg,
+                                        upb_StringView* data, uintptr_t* iter);
 
-bool upb_Message_HasUnknown(const upb_Message* msg);
+UPB_INLINE bool upb_Message_HasUnknown(const upb_Message* msg);
 
 // Returns a reference to the message's unknown data.
 const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len);
@@ -80,6 +85,17 @@
 // Returns the number of extensions present in this message.
 size_t upb_Message_ExtensionCount(const upb_Message* msg);
 
+// Iterates extensions in wire order
+UPB_INLINE bool upb_Message_NextExtension(const upb_Message* msg,
+                                          const upb_MiniTableExtension** out_e,
+                                          upb_MessageValue* out_v,
+                                          uintptr_t* iter);
+
+// Iterates extensions in reverse wire order
+UPB_INLINE bool UPB_PRIVATE(_upb_Message_NextExtensionReverse)(
+    const struct upb_Message* msg, const upb_MiniTableExtension** out_e,
+    upb_MessageValue* out_v, uintptr_t* iter);
+
 // Mark a message and all of its descendents as frozen/immutable.
 UPB_API void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m);
 
diff --git a/upb/text/debug_string.c b/upb/text/debug_string.c
index eebf79e..c4b6609 100644
--- a/upb/text/debug_string.c
+++ b/upb/text/debug_string.c
@@ -184,9 +184,9 @@
 
   const upb_MiniTableExtension* ext;
   upb_MessageValue val_ext;
-  iter = kUpb_Extension_Begin;
-  while (
-      UPB_PRIVATE(_upb_Message_NextExtension)(msg, mt, &ext, &val_ext, &iter)) {
+  iter = kUpb_Message_ExtensionBegin;
+  while (UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, &ext, &val_ext,
+                                                        &iter)) {
     const upb_MiniTableField* f = &ext->UPB_PRIVATE(field);
     // It is not sufficient to only pass |f| as we lose valuable information
     // about sub-messages. It is required that we pass |ext|.
diff --git a/upb/wire/encode.c b/upb/wire/encode.c
index d3e68f1..b68ddc6 100644
--- a/upb/wire/encode.c
+++ b/upb/wire/encode.c
@@ -12,6 +12,7 @@
 #include <setjmp.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "upb/base/descriptor_constants.h"
@@ -27,6 +28,7 @@
 #include "upb/message/internal/map.h"
 #include "upb/message/internal/map_entry.h"
 #include "upb/message/internal/map_sorter.h"
+#include "upb/message/internal/message.h"
 #include "upb/message/internal/tagged_ptr.h"
 #include "upb/message/map.h"
 #include "upb/message/message.h"
@@ -523,32 +525,33 @@
   }
 }
 
-static void encode_msgset_item(upb_encstate* e, const upb_Extension* ext) {
+static void encode_msgset_item(upb_encstate* e,
+                               const upb_MiniTableExtension* ext,
+                               const upb_MessageValue ext_val) {
   size_t size;
   encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_EndGroup);
-  encode_message(e, ext->data.msg_val,
-                 upb_MiniTableExtension_GetSubMessage(ext->ext), &size);
+  encode_message(e, ext_val.msg_val, upb_MiniTableExtension_GetSubMessage(ext),
+                 &size);
   encode_varint(e, size);
   encode_tag(e, kUpb_MsgSet_Message, kUpb_WireType_Delimited);
-  encode_varint(e, upb_MiniTableExtension_Number(ext->ext));
+  encode_varint(e, upb_MiniTableExtension_Number(ext));
   encode_tag(e, kUpb_MsgSet_TypeId, kUpb_WireType_Varint);
   encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup);
 }
 
-static void encode_ext(upb_encstate* e, const upb_Extension* ext,
-                       bool is_message_set) {
+static void encode_ext(upb_encstate* e, const upb_MiniTableExtension* ext,
+                       upb_MessageValue ext_val, bool is_message_set) {
   if (UPB_UNLIKELY(is_message_set)) {
-    encode_msgset_item(e, ext);
+    encode_msgset_item(e, ext, ext_val);
   } else {
     upb_MiniTableSubInternal sub;
-    if (upb_MiniTableField_IsSubMessage(&ext->ext->UPB_PRIVATE(field))) {
-      sub.UPB_PRIVATE(submsg) = &ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(submsg);
+    if (upb_MiniTableField_IsSubMessage(&ext->UPB_PRIVATE(field))) {
+      sub.UPB_PRIVATE(submsg) = &ext->UPB_PRIVATE(sub).UPB_PRIVATE(submsg);
     } else {
-      sub.UPB_PRIVATE(subenum) =
-          ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(subenum);
+      sub.UPB_PRIVATE(subenum) = ext->UPB_PRIVATE(sub).UPB_PRIVATE(subenum);
     }
-    encode_field(e, &ext->data.UPB_PRIVATE(ext_msg_val), &sub,
-                 &ext->ext->UPB_PRIVATE(field));
+    encode_field(e, &ext_val.UPB_PRIVATE(ext_msg_val), &sub,
+                 &ext->UPB_PRIVATE(field));
   }
 }
 
@@ -568,7 +571,7 @@
     size_t unknown_size = 0;
     uintptr_t iter = kUpb_Message_UnknownBegin;
     upb_StringView unknown;
-    // Need to write in reverse order, but list is single-linked; scan to
+    // Need to write in reverse order, but iteration is in-order; scan to
     // reserve capacity up front, then write in-order
     while (upb_Message_NextUnknown(msg, &unknown, &iter)) {
       unknown_size += unknown.size;
@@ -585,24 +588,33 @@
   }
 
   if (m->UPB_PRIVATE(ext) != kUpb_ExtMode_NonExtendable) {
-    /* Encode all extensions together. Unlike C++, we do not attempt to keep
-     * these in field number order relative to normal fields or even to each
-     * other. */
-    size_t ext_count;
-    const upb_Extension* ext =
-        UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count);
-    if (ext_count) {
-      if (e->options & kUpb_EncodeOption_Deterministic) {
-        _upb_sortedmap sorted;
-        _upb_mapsorter_pushexts(&e->sorter, ext, ext_count, &sorted);
-        while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
-          encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
-        }
-        _upb_mapsorter_popmap(&e->sorter, &sorted);
-      } else {
-        const upb_Extension* end = ext + ext_count;
-        for (; ext != end; ext++) {
-          encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
+    upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
+    if (in) {
+      /* Encode all extensions together. Unlike C++, we do not attempt to keep
+       * these in field number order relative to normal fields or even to each
+       * other. */
+      size_t ext_count = upb_Message_ExtensionCount(msg);
+      if (ext_count) {
+        if (e->options & kUpb_EncodeOption_Deterministic) {
+          _upb_sortedmap sorted;
+          if (!_upb_mapsorter_pushexts(&e->sorter, in, ext_count, &sorted)) {
+            // TODO: b/378744096 - handle alloc failure
+          }
+          const upb_Extension* ext;
+          while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
+            encode_ext(e, ext->ext, ext->data,
+                       m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
+          }
+          _upb_mapsorter_popmap(&e->sorter, &sorted);
+        } else {
+          const upb_MiniTableExtension* ext;
+          upb_MessageValue ext_val;
+          uintptr_t iter = kUpb_Message_ExtensionBegin;
+          while (UPB_PRIVATE(_upb_Message_NextExtensionReverse)(
+              msg, &ext, &ext_val, &iter)) {
+            encode_ext(e, ext, ext_val,
+                       m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
+          }
         }
       }
     }