Use _upb_Message_AlignedMemsetZero in upb_Message_Clear `upb_Message_Clear` zeroed the message with a `memset` library call. Use the same inline aligned zeroing as `_upb_Message_New` instead (message sizes are multiples of kUpb_Message_Align, and messages are always kUpb_Message_Align-aligned). Also stop resetting the size of the message's internal data (unknown fields and extensions) after clearing: the internal data pointer is in the message header, which the clear zeroes, so nothing refers to that internal data afterwards and the store was dead. (Copies never share internal data: upb_Message_ShallowCopy gives the copy its own.) This saves loading the header before the clear. android_arm64 (-c opt, fasttable), upb_Message_DeepCopy (which inlines upb_Message_Clear), before: stp x30, x23, [sp, #-0x30]! stp x22, x21, [sp, #0x10] stp x20, x19, [sp, #0x20] mov x20, x2 ldr x8, [x0] ldrh w2, [x2, #0x8] mov x21, x1 mov w1, wzr mov x19, x3 mov x22, x0 and x23, x8, #0xfffffffffffffffe bl memset cbz x23, 1f str wzr, [x23] 1:mov x0, x22 mov x1, x21 mov x2, x20 mov x3, x19 bl _upb_Message_Copy ldp x20, x19, [sp, #0x20] cmp x0, #0x0 ldp x22, x21, [sp, #0x10] cset w0, ne ldp x30, x23, [sp], #0x30 ret after (no call, so no callee-saved registers to spill around it, and no load and store of the internal data): str x30, [sp, #-0x10]! ldrh w8, [x2, #0x8] mov x9, x0 add x10, x0, x8 str xzr, [x9] cmp x8, #0x8 b.eq 2f 1:stp xzr, xzr, [x9], #0x10 stp xzr, xzr, [x10, #-0x10]! cmp x9, x10 b.lo 1b 2:bl _upb_Message_Copy cmp x0, #0x0 cset w0, ne ldr x30, [sp], #0x10 ret The error path of `_upb_Message_Copy`, which clears `dst`, likewise replaces its `memset` call with the inline loop. No other function in the upb message, wire and decode_fast objects changes. PiperOrigin-RevId: 998754226
diff --git a/upb/message/internal/accessors.h b/upb/message/internal/accessors.h index 5d83a16..e1af487 100644 --- a/upb/message/internal/accessors.h +++ b/upb/message/internal/accessors.h
@@ -874,12 +874,9 @@ UPB_API_INLINE void upb_Message_Clear(struct upb_Message* msg, const upb_MiniTable* m) { UPB_ASSERT(!upb_Message_IsFrozen(msg)); - upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); - memset(msg, 0, m->UPB_PRIVATE(size)); - if (in) { - // Reset the internal buffer to empty. - in->size = 0; - } + // This also clears the pointer to the internal data (unknown fields and + // extensions), which stays in the arena unreferenced. + _upb_Message_AlignedMemsetZero(msg, m->UPB_PRIVATE(size)); } UPB_API_INLINE void upb_Message_ClearBaseField(struct upb_Message* msg,