// Protocol Buffers - Google's data interchange format // Copyright 2025 Google LLC. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #include #include #include "upb/message/internal/message.h" #include "upb/message/message.h" #include "upb/mini_table/message.h" #include "upb/wire/decode.h" #include "upb/wire/decode_fast/cardinality.h" #include "upb/wire/decode_fast/combinations.h" #include "upb/wire/decode_fast/dispatch.h" #include "upb/wire/decode_fast/field_parsers.h" #include "upb/wire/eps_copy_input_stream.h" #include "upb/wire/internal/decoder.h" // Must be last. #include "upb/port/def.inc" typedef struct { intptr_t table; upb_Message* msg; } fastdecode_submsgdata; UPB_FORCEINLINE const char* fastdecode_tosubmsg(upb_EpsCopyInputStream* e, const char* ptr, int size, void* ctx) { upb_Decoder* d = (upb_Decoder*)e; fastdecode_submsgdata* submsg = ctx; ptr = upb_DecodeFast_Dispatch(d, ptr, submsg->msg, submsg->table, 0, 0); UPB_ASSUME(ptr != NULL); return ptr; } #define FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, type, card, \ tagsize) \ int tagbytes = upb_DecodeFast_TagSizeBytes(tagsize); \ \ if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { \ RETURN_GENERIC("submessage field tag mismatch\n"); \ } \ \ if (--d->depth == 0) { \ _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_MaxDepthExceeded); \ } \ \ upb_Message** dst; \ uint32_t submsg_idx = (data >> 16) & 0xff; \ const upb_MiniTable* tablep = decode_totablep(table); \ /* TODO: This is incorrect, but this code is currently dead. */ \ /* We will fix it when we actually enable fast decode for message fields. */ \ UPB_ASSERT(false); \ const upb_MiniTable* subtablep = \ *UPB_PTR_AT(tablep, submsg_idx, const upb_MiniTable*); \ fastdecode_submsgdata submsg = {decode_totable(subtablep)}; \ fastdecode_arr farr; \ \ if (subtablep->UPB_PRIVATE(table_mask) == (uint8_t)-1) { \ d->depth++; \ RETURN_GENERIC("submessage doesn't have fast tables."); \ } \ \ dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, \ sizeof(upb_Message*), card); \ \ if (card == kUpb_DecodeFast_Scalar) { \ upb_DecodeFast_SetHasbits(msg, hasbits); \ hasbits = 0; \ } \ \ again: \ if (card == kUpb_DecodeFast_Repeated) { \ dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*)); \ } \ \ submsg.msg = *dst; \ \ if (card == kUpb_DecodeFast_Repeated || UPB_LIKELY(!submsg.msg)) { \ *dst = submsg.msg = _upb_Message_New(subtablep, &d->arena); \ } \ \ ptr += tagbytes; \ ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); \ \ if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { \ _upb_FastDecoder_ErrorJmp(d, kUpb_DecodeStatus_Malformed); \ } \ \ if (card == kUpb_DecodeFast_Repeated) { \ fastdecode_nextret ret = fastdecode_nextrepeated( \ d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*)); \ switch (ret.next) { \ case FD_NEXT_SAMEFIELD: \ dst = ret.dst; \ goto again; \ case FD_NEXT_OTHERFIELD: \ d->depth++; \ data = ret.tag; \ UPB_MUSTTAIL return _upb_FastDecoder_TagDispatch(UPB_PARSE_ARGS); \ case FD_NEXT_ATLIMIT: \ d->depth++; \ return ptr; \ } \ } \ \ d->depth++; \ UPB_MUSTTAIL return upb_DecodeFast_Dispatch(UPB_PARSE_ARGS); #define F(type, card, tagsize) \ UPB_PRESERVE_NONE const char* UPB_DECODEFAST_FUNCNAME( \ type, card, tagsize)(UPB_PARSE_PARAMS) { \ FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, \ kUpb_DecodeFast_##type, kUpb_DecodeFast_##card, \ kUpb_DecodeFast_##tagsize); \ } UPB_DECODEFAST_CARDINALITIES(UPB_DECODEFAST_TAGSIZES, F, Message) #undef F #undef FASTDECODE_SUBMSG