| // 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 <stddef.h> |
| #include <stdint.h> |
| |
| #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, |
| 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); \ |
| const upb_MiniTable* subtablep = \ |
| UPB_PRIVATE(_upb_MiniTable_GetSubTableByIndex)(tablep, submsg_idx); \ |
| 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 |