Auto-generate files after cl/593821827
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index bcfca4d..27aa17e 100644 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c
@@ -12487,7 +12487,7 @@ } static void _upb_Decoder_MungeInt32(wireval* val) { - if (!_upb_IsLittleEndian()) { + if (!UPB_PRIVATE(_upb_IsLittleEndian)()) { /* The next stage will memcpy(dst, &val, 4) */ val->uint32_val = val->uint64_val; } @@ -12707,7 +12707,7 @@ arr->UPB_PRIVATE(size) += count; // Note: if/when the decoder supports multi-buffer input, we will need to // handle buffer seams here. - if (_upb_IsLittleEndian()) { + if (UPB_PRIVATE(_upb_IsLittleEndian)()) { ptr = upb_EpsCopyInputStream_Copy(&d->input, ptr, mem, val->size); } else { int delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size); @@ -13031,7 +13031,7 @@ } uint64_t msg_head; memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); + msg_head = UPB_PRIVATE(_upb_BigEndian64)(msg_head); if (UPB_PRIVATE(_upb_MiniTable_RequiredMask)(m) & ~msg_head) { d->missing_required = true; } @@ -13660,6 +13660,626 @@ #undef OP_FIXPCK_LG2 #undef OP_VARPCK_LG2 +// We encode backwards, to avoid pre-computing lengths (one-pass encode). + + +#include <setjmp.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> + + +// Must be last. + +#define UPB_PB_VARINT_MAX_LEN 10 + +UPB_NOINLINE +static size_t encode_varint64(uint64_t val, char* buf) { + size_t i = 0; + do { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + buf[i++] = byte; + } while (val); + return i; +} + +static uint32_t encode_zz32(int32_t n) { + return ((uint32_t)n << 1) ^ (n >> 31); +} +static uint64_t encode_zz64(int64_t n) { + return ((uint64_t)n << 1) ^ (n >> 63); +} + +typedef struct { + upb_EncodeStatus status; + jmp_buf err; + upb_Arena* arena; + char *buf, *ptr, *limit; + int options; + int depth; + _upb_mapsorter sorter; +} upb_encstate; + +static size_t upb_roundup_pow2(size_t bytes) { + size_t ret = 128; + while (ret < bytes) { + ret *= 2; + } + return ret; +} + +UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) { + UPB_ASSERT(s != kUpb_EncodeStatus_Ok); + e->status = s; + UPB_LONGJMP(e->err, 1); +} + +UPB_NOINLINE +static void encode_growbuffer(upb_encstate* e, size_t bytes) { + size_t old_size = e->limit - e->buf; + size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); + char* new_buf = upb_Arena_Realloc(e->arena, e->buf, old_size, new_size); + + if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory); + + // We want previous data at the end, realloc() put it at the beginning. + // TODO: This is somewhat inefficient since we are copying twice. + // Maybe create a realloc() that copies to the end of the new buffer? + if (old_size > 0) { + memmove(new_buf + new_size - old_size, e->buf, old_size); + } + + e->ptr = new_buf + new_size - (e->limit - e->ptr); + e->limit = new_buf + new_size; + e->buf = new_buf; + + e->ptr -= bytes; +} + +/* Call to ensure that at least "bytes" bytes are available for writing at + * e->ptr. Returns false if the bytes could not be allocated. */ +UPB_FORCEINLINE +static void encode_reserve(upb_encstate* e, size_t bytes) { + if ((size_t)(e->ptr - e->buf) < bytes) { + encode_growbuffer(e, bytes); + return; + } + + e->ptr -= bytes; +} + +/* Writes the given bytes to the buffer, handling reserve/advance. */ +static void encode_bytes(upb_encstate* e, const void* data, size_t len) { + if (len == 0) return; /* memcpy() with zero size is UB */ + encode_reserve(e, len); + memcpy(e->ptr, data, len); +} + +static void encode_fixed64(upb_encstate* e, uint64_t val) { + val = UPB_PRIVATE(_upb_BigEndian64)(val); + encode_bytes(e, &val, sizeof(uint64_t)); +} + +static void encode_fixed32(upb_encstate* e, uint32_t val) { + val = UPB_PRIVATE(_upb_BigEndian32)(val); + encode_bytes(e, &val, sizeof(uint32_t)); +} + +UPB_NOINLINE +static void encode_longvarint(upb_encstate* e, uint64_t val) { + size_t len; + char* start; + + encode_reserve(e, UPB_PB_VARINT_MAX_LEN); + len = encode_varint64(val, e->ptr); + start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; + memmove(start, e->ptr, len); + e->ptr = start; +} + +UPB_FORCEINLINE +static void encode_varint(upb_encstate* e, uint64_t val) { + if (val < 128 && e->ptr != e->buf) { + --e->ptr; + *e->ptr = val; + } else { + encode_longvarint(e, val); + } +} + +static void encode_double(upb_encstate* e, double d) { + uint64_t u64; + UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); + memcpy(&u64, &d, sizeof(uint64_t)); + encode_fixed64(e, u64); +} + +static void encode_float(upb_encstate* e, float d) { + uint32_t u32; + UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); + memcpy(&u32, &d, sizeof(uint32_t)); + encode_fixed32(e, u32); +} + +static void encode_tag(upb_encstate* e, uint32_t field_number, + uint8_t wire_type) { + encode_varint(e, (field_number << 3) | wire_type); +} + +static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, + size_t elem_size, uint32_t tag) { + size_t bytes = arr->UPB_PRIVATE(size) * elem_size; + const char* data = _upb_array_constptr(arr); + const char* ptr = data + bytes - elem_size; + + if (tag || !UPB_PRIVATE(_upb_IsLittleEndian)()) { + while (true) { + if (elem_size == 4) { + uint32_t val; + memcpy(&val, ptr, sizeof(val)); + val = UPB_PRIVATE(_upb_BigEndian32)(val); + encode_bytes(e, &val, elem_size); + } else { + UPB_ASSERT(elem_size == 8); + uint64_t val; + memcpy(&val, ptr, sizeof(val)); + val = UPB_PRIVATE(_upb_BigEndian64)(val); + encode_bytes(e, &val, elem_size); + } + + if (tag) encode_varint(e, tag); + if (ptr == data) break; + ptr -= elem_size; + } + } else { + encode_bytes(e, data, bytes); + } +} + +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size); + +static void encode_TaggedMessagePtr(upb_encstate* e, + upb_TaggedMessagePtr tagged, + const upb_MiniTable* m, size_t* size) { + if (upb_TaggedMessagePtr_IsEmpty(tagged)) { + m = UPB_PRIVATE(_upb_MiniTable_Empty)(); + } + encode_message(e, _upb_TaggedMessagePtr_GetMessage(tagged), m, size); +} + +static void encode_scalar(upb_encstate* e, const void* _field_mem, + const upb_MiniTableSub* subs, + const upb_MiniTableField* f) { + const char* field_mem = _field_mem; + int wire_type; + +#define CASE(ctype, type, wtype, encodeval) \ + { \ + ctype val = *(ctype*)field_mem; \ + encode_##type(e, encodeval); \ + wire_type = wtype; \ + break; \ + } + + switch (f->UPB_PRIVATE(descriptortype)) { + case kUpb_FieldType_Double: + CASE(double, double, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Float: + CASE(float, float, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + CASE(uint64_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_UInt32: + CASE(uint32_t, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); + case kUpb_FieldType_Bool: + CASE(bool, varint, kUpb_WireType_Varint, val); + case kUpb_FieldType_SInt32: + CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); + case kUpb_FieldType_SInt64: + CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + upb_StringView view = *(upb_StringView*)field_mem; + encode_bytes(e, view.data, view.size); + encode_varint(e, view.size); + wire_type = kUpb_WireType_Delimited; + break; + } + case kUpb_FieldType_Group: { + size_t size; + upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem; + const upb_MiniTable* subm = + upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); + if (submsg == 0) { + return; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_EndGroup); + encode_TaggedMessagePtr(e, submsg, subm, &size); + wire_type = kUpb_WireType_StartGroup; + e->depth++; + break; + } + case kUpb_FieldType_Message: { + size_t size; + upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem; + const upb_MiniTable* subm = + upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); + if (submsg == 0) { + return; + } + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + encode_TaggedMessagePtr(e, submsg, subm, &size); + encode_varint(e, size); + wire_type = kUpb_WireType_Delimited; + e->depth++; + break; + } + default: + UPB_UNREACHABLE(); + } +#undef CASE + + encode_tag(e, f->UPB_PRIVATE(number), wire_type); +} + +static void encode_array(upb_encstate* e, const upb_Message* msg, + const upb_MiniTableSub* subs, + const upb_MiniTableField* f) { + const upb_Array* arr = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), upb_Array*); + bool packed = upb_MiniTableField_IsPacked(f); + size_t pre_len = e->limit - e->ptr; + + if (arr == NULL || arr->UPB_PRIVATE(size) == 0) { + return; + } + +#define VARINT_CASE(ctype, encode) \ + { \ + const ctype* start = _upb_array_constptr(arr); \ + const ctype* ptr = start + arr->UPB_PRIVATE(size); \ + uint32_t tag = \ + packed ? 0 : (f->UPB_PRIVATE(number) << 3) | kUpb_WireType_Varint; \ + do { \ + ptr--; \ + encode_varint(e, encode); \ + if (tag) encode_varint(e, tag); \ + } while (ptr != start); \ + } \ + break; + +#define TAG(wire_type) (packed ? 0 : (f->UPB_PRIVATE(number) << 3 | wire_type)) + + switch (f->UPB_PRIVATE(descriptortype)) { + case kUpb_FieldType_Double: + encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Float: + encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_SFixed64: + case kUpb_FieldType_Fixed64: + encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); + break; + case kUpb_FieldType_Fixed32: + case kUpb_FieldType_SFixed32: + encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); + break; + case kUpb_FieldType_Int64: + case kUpb_FieldType_UInt64: + VARINT_CASE(uint64_t, *ptr); + case kUpb_FieldType_UInt32: + VARINT_CASE(uint32_t, *ptr); + case kUpb_FieldType_Int32: + case kUpb_FieldType_Enum: + VARINT_CASE(int32_t, (int64_t)*ptr); + case kUpb_FieldType_Bool: + VARINT_CASE(bool, *ptr); + case kUpb_FieldType_SInt32: + VARINT_CASE(int32_t, encode_zz32(*ptr)); + case kUpb_FieldType_SInt64: + VARINT_CASE(int64_t, encode_zz64(*ptr)); + case kUpb_FieldType_String: + case kUpb_FieldType_Bytes: { + const upb_StringView* start = _upb_array_constptr(arr); + const upb_StringView* ptr = start + arr->UPB_PRIVATE(size); + do { + ptr--; + encode_bytes(e, ptr->data, ptr->size); + encode_varint(e, ptr->size); + encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited); + } while (ptr != start); + return; + } + case kUpb_FieldType_Group: { + const upb_TaggedMessagePtr* start = _upb_array_constptr(arr); + const upb_TaggedMessagePtr* ptr = start + arr->UPB_PRIVATE(size); + const upb_MiniTable* subm = + upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + ptr--; + encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_EndGroup); + encode_TaggedMessagePtr(e, *ptr, subm, &size); + encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_StartGroup); + } while (ptr != start); + e->depth++; + return; + } + case kUpb_FieldType_Message: { + const upb_TaggedMessagePtr* start = _upb_array_constptr(arr); + const upb_TaggedMessagePtr* ptr = start + arr->UPB_PRIVATE(size); + const upb_MiniTable* subm = + upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); + do { + size_t size; + ptr--; + encode_TaggedMessagePtr(e, *ptr, subm, &size); + encode_varint(e, size); + encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited); + } while (ptr != start); + e->depth++; + return; + } + } +#undef VARINT_CASE + + if (packed) { + encode_varint(e, e->limit - e->ptr - pre_len); + encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited); + } +} + +static void encode_mapentry(upb_encstate* e, uint32_t number, + const upb_MiniTable* layout, + const upb_MapEntry* ent) { + const upb_MiniTableField* key_field = &layout->UPB_PRIVATE(fields)[0]; + const upb_MiniTableField* val_field = &layout->UPB_PRIVATE(fields)[1]; + size_t pre_len = e->limit - e->ptr; + size_t size; + encode_scalar(e, &ent->data.v, layout->UPB_PRIVATE(subs), val_field); + encode_scalar(e, &ent->data.k, layout->UPB_PRIVATE(subs), key_field); + size = (e->limit - e->ptr) - pre_len; + encode_varint(e, size); + encode_tag(e, number, kUpb_WireType_Delimited); +} + +static void encode_map(upb_encstate* e, const upb_Message* msg, + const upb_MiniTableSub* subs, + const upb_MiniTableField* f) { + const upb_Map* map = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), const upb_Map*); + const upb_MiniTable* layout = + upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); + UPB_ASSERT(layout->UPB_PRIVATE(field_count) == 2); + + if (map == NULL) return; + + if (e->options & kUpb_EncodeOption_Deterministic) { + _upb_sortedmap sorted; + _upb_mapsorter_pushmap( + &e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype), + map, &sorted); + upb_MapEntry ent; + while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { + encode_mapentry(e, f->UPB_PRIVATE(number), layout, &ent); + } + _upb_mapsorter_popmap(&e->sorter, &sorted); + } else { + intptr_t iter = UPB_STRTABLE_BEGIN; + upb_StringView key; + upb_value val; + while (upb_strtable_next2(&map->table, &key, &val, &iter)) { + upb_MapEntry ent; + _upb_map_fromkey(key, &ent.data.k, map->key_size); + _upb_map_fromvalue(val, &ent.data.v, map->val_size); + encode_mapentry(e, f->UPB_PRIVATE(number), layout, &ent); + } + } +} + +static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, + const upb_MiniTableSub* subs, + const upb_MiniTableField* f) { + if (f->presence == 0) { + // Proto3 presence or map/array. + const void* mem = UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), void); + switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) { + case kUpb_FieldRep_1Byte: { + char ch; + memcpy(&ch, mem, 1); + return ch != 0; + } + case kUpb_FieldRep_4Byte: { + uint32_t u32; + memcpy(&u32, mem, 4); + return u32 != 0; + } + case kUpb_FieldRep_8Byte: { + uint64_t u64; + memcpy(&u64, mem, 8); + return u64 != 0; + } + case kUpb_FieldRep_StringView: { + const upb_StringView* str = (const upb_StringView*)mem; + return str->size != 0; + } + default: + UPB_UNREACHABLE(); + } + } else if (f->presence > 0) { + // Proto2 presence: hasbit. + return UPB_PRIVATE(_upb_Message_GetHasbit)(msg, f); + } else { + // Field is in a oneof. + return UPB_PRIVATE(_upb_Message_GetOneofCase)(msg, f) == + f->UPB_PRIVATE(number); + } +} + +static void encode_field(upb_encstate* e, const upb_Message* msg, + const upb_MiniTableSub* subs, + const upb_MiniTableField* field) { + switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) { + case kUpb_FieldMode_Array: + encode_array(e, msg, subs, field); + break; + case kUpb_FieldMode_Map: + encode_map(e, msg, subs, field); + break; + case kUpb_FieldMode_Scalar: + encode_scalar(e, UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void), subs, + field); + break; + default: + UPB_UNREACHABLE(); + } +} + +static void encode_msgset_item(upb_encstate* e, const upb_Extension* ext) { + size_t size; + encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_EndGroup); + encode_message(e, ext->data.ptr, + upb_MiniTableExtension_GetSubMessage(ext->ext), &size); + encode_varint(e, size); + encode_tag(e, kUpb_MsgSet_Message, kUpb_WireType_Delimited); + encode_varint(e, upb_MiniTableExtension_Number(ext->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) { + if (UPB_UNLIKELY(is_message_set)) { + encode_msgset_item(e, ext); + } else { + encode_field(e, (upb_Message*)&ext->data, &ext->ext->UPB_PRIVATE(sub), + &ext->ext->UPB_PRIVATE(field)); + } +} + +static void encode_message(upb_encstate* e, const upb_Message* msg, + const upb_MiniTable* m, size_t* size) { + size_t pre_len = e->limit - e->ptr; + + if ((e->options & kUpb_EncodeOption_CheckRequired) && + m->UPB_PRIVATE(required_count)) { + uint64_t msg_head; + memcpy(&msg_head, msg, 8); + msg_head = UPB_PRIVATE(_upb_BigEndian64)(msg_head); + if (UPB_PRIVATE(_upb_MiniTable_RequiredMask)(m) & ~msg_head) { + encode_err(e, kUpb_EncodeStatus_MissingRequired); + } + } + + if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) { + size_t unknown_size; + const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); + + if (unknown) { + encode_bytes(e, unknown, unknown_size); + } + } + + 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); + } + } + } + } + + if (m->UPB_PRIVATE(field_count)) { + const upb_MiniTableField* f = + &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; + const upb_MiniTableField* first = &m->UPB_PRIVATE(fields)[0]; + while (f != first) { + f--; + if (encode_shouldencode(e, msg, m->UPB_PRIVATE(subs), f)) { + encode_field(e, msg, m->UPB_PRIVATE(subs), f); + } + } + } + + *size = (e->limit - e->ptr) - pre_len; +} + +static upb_EncodeStatus upb_Encoder_Encode(upb_encstate* const encoder, + const upb_Message* const msg, + const upb_MiniTable* const l, + char** const buf, + size_t* const size) { + // Unfortunately we must continue to perform hackery here because there are + // code paths which blindly copy the returned pointer without bothering to + // check for errors until much later (b/235839510). So we still set *buf to + // NULL on error and we still set it to non-NULL on a successful empty result. + if (UPB_SETJMP(encoder->err) == 0) { + encode_message(encoder, msg, l, size); + *size = encoder->limit - encoder->ptr; + if (*size == 0) { + static char ch; + *buf = &ch; + } else { + UPB_ASSERT(encoder->ptr); + *buf = encoder->ptr; + } + } else { + UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok); + *buf = NULL; + *size = 0; + } + + _upb_mapsorter_destroy(&encoder->sorter); + return encoder->status; +} + +upb_EncodeStatus upb_Encode(const upb_Message* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size) { + upb_encstate e; + unsigned depth = (unsigned)options >> 16; + + e.status = kUpb_EncodeStatus_Ok; + e.arena = arena; + e.buf = NULL; + e.limit = NULL; + e.ptr = NULL; + e.depth = depth ? depth : kUpb_WireFormat_DefaultDepthLimit; + e.options = options; + _upb_mapsorter_init(&e.sorter); + + return upb_Encoder_Encode(&e, msg, l, buf, size); +} + // Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64. // Also the table size grows by 2x. // @@ -14648,633 +15268,16 @@ #endif /* UPB_FASTTABLE */ -// We encode backwards, to avoid pre-computing lengths (one-pass encode). - -#include <setjmp.h> -#include <stdbool.h> +#include <stddef.h> #include <stdint.h> -#include <string.h> // Must be last. -#define UPB_PB_VARINT_MAX_LEN 10 - -UPB_NOINLINE -static size_t encode_varint64(uint64_t val, char* buf) { - size_t i = 0; - do { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - buf[i++] = byte; - } while (val); - return i; -} - -static uint32_t encode_zz32(int32_t n) { - return ((uint32_t)n << 1) ^ (n >> 31); -} -static uint64_t encode_zz64(int64_t n) { - return ((uint64_t)n << 1) ^ (n >> 63); -} - -typedef struct { - upb_EncodeStatus status; - jmp_buf err; - upb_Arena* arena; - char *buf, *ptr, *limit; - int options; - int depth; - _upb_mapsorter sorter; -} upb_encstate; - -static size_t upb_roundup_pow2(size_t bytes) { - size_t ret = 128; - while (ret < bytes) { - ret *= 2; - } - return ret; -} - -UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) { - UPB_ASSERT(s != kUpb_EncodeStatus_Ok); - e->status = s; - UPB_LONGJMP(e->err, 1); -} - -UPB_NOINLINE -static void encode_growbuffer(upb_encstate* e, size_t bytes) { - size_t old_size = e->limit - e->buf; - size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); - char* new_buf = upb_Arena_Realloc(e->arena, e->buf, old_size, new_size); - - if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory); - - // We want previous data at the end, realloc() put it at the beginning. - // TODO: This is somewhat inefficient since we are copying twice. - // Maybe create a realloc() that copies to the end of the new buffer? - if (old_size > 0) { - memmove(new_buf + new_size - old_size, e->buf, old_size); - } - - e->ptr = new_buf + new_size - (e->limit - e->ptr); - e->limit = new_buf + new_size; - e->buf = new_buf; - - e->ptr -= bytes; -} - -/* Call to ensure that at least "bytes" bytes are available for writing at - * e->ptr. Returns false if the bytes could not be allocated. */ -UPB_FORCEINLINE -static void encode_reserve(upb_encstate* e, size_t bytes) { - if ((size_t)(e->ptr - e->buf) < bytes) { - encode_growbuffer(e, bytes); - return; - } - - e->ptr -= bytes; -} - -/* Writes the given bytes to the buffer, handling reserve/advance. */ -static void encode_bytes(upb_encstate* e, const void* data, size_t len) { - if (len == 0) return; /* memcpy() with zero size is UB */ - encode_reserve(e, len); - memcpy(e->ptr, data, len); -} - -static void encode_fixed64(upb_encstate* e, uint64_t val) { - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, sizeof(uint64_t)); -} - -static void encode_fixed32(upb_encstate* e, uint32_t val) { - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, sizeof(uint32_t)); -} - -UPB_NOINLINE -static void encode_longvarint(upb_encstate* e, uint64_t val) { - size_t len; - char* start; - - encode_reserve(e, UPB_PB_VARINT_MAX_LEN); - len = encode_varint64(val, e->ptr); - start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; - memmove(start, e->ptr, len); - e->ptr = start; -} - -UPB_FORCEINLINE -static void encode_varint(upb_encstate* e, uint64_t val) { - if (val < 128 && e->ptr != e->buf) { - --e->ptr; - *e->ptr = val; - } else { - encode_longvarint(e, val); - } -} - -static void encode_double(upb_encstate* e, double d) { - uint64_t u64; - UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); - memcpy(&u64, &d, sizeof(uint64_t)); - encode_fixed64(e, u64); -} - -static void encode_float(upb_encstate* e, float d) { - uint32_t u32; - UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); - memcpy(&u32, &d, sizeof(uint32_t)); - encode_fixed32(e, u32); -} - -static void encode_tag(upb_encstate* e, uint32_t field_number, - uint8_t wire_type) { - encode_varint(e, (field_number << 3) | wire_type); -} - -static void encode_fixedarray(upb_encstate* e, const upb_Array* arr, - size_t elem_size, uint32_t tag) { - size_t bytes = arr->UPB_PRIVATE(size) * elem_size; - const char* data = _upb_array_constptr(arr); - const char* ptr = data + bytes - elem_size; - - if (tag || !_upb_IsLittleEndian()) { - while (true) { - if (elem_size == 4) { - uint32_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap32(val); - encode_bytes(e, &val, elem_size); - } else { - UPB_ASSERT(elem_size == 8); - uint64_t val; - memcpy(&val, ptr, sizeof(val)); - val = _upb_BigEndian_Swap64(val); - encode_bytes(e, &val, elem_size); - } - - if (tag) encode_varint(e, tag); - if (ptr == data) break; - ptr -= elem_size; - } - } else { - encode_bytes(e, data, bytes); - } -} - -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size); - -static void encode_TaggedMessagePtr(upb_encstate* e, - upb_TaggedMessagePtr tagged, - const upb_MiniTable* m, size_t* size) { - if (upb_TaggedMessagePtr_IsEmpty(tagged)) { - m = UPB_PRIVATE(_upb_MiniTable_Empty)(); - } - encode_message(e, _upb_TaggedMessagePtr_GetMessage(tagged), m, size); -} - -static void encode_scalar(upb_encstate* e, const void* _field_mem, - const upb_MiniTableSub* subs, - const upb_MiniTableField* f) { - const char* field_mem = _field_mem; - int wire_type; - -#define CASE(ctype, type, wtype, encodeval) \ - { \ - ctype val = *(ctype*)field_mem; \ - encode_##type(e, encodeval); \ - wire_type = wtype; \ - break; \ - } - - switch (f->UPB_PRIVATE(descriptortype)) { - case kUpb_FieldType_Double: - CASE(double, double, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Float: - CASE(float, float, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - CASE(uint64_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_UInt32: - CASE(uint32_t, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); - case kUpb_FieldType_Bool: - CASE(bool, varint, kUpb_WireType_Varint, val); - case kUpb_FieldType_SInt32: - CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); - case kUpb_FieldType_SInt64: - CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - upb_StringView view = *(upb_StringView*)field_mem; - encode_bytes(e, view.data, view.size); - encode_varint(e, view.size); - wire_type = kUpb_WireType_Delimited; - break; - } - case kUpb_FieldType_Group: { - size_t size; - upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem; - const upb_MiniTable* subm = - upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); - if (submsg == 0) { - return; - } - if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); - encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_EndGroup); - encode_TaggedMessagePtr(e, submsg, subm, &size); - wire_type = kUpb_WireType_StartGroup; - e->depth++; - break; - } - case kUpb_FieldType_Message: { - size_t size; - upb_TaggedMessagePtr submsg = *(upb_TaggedMessagePtr*)field_mem; - const upb_MiniTable* subm = - upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); - if (submsg == 0) { - return; - } - if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); - encode_TaggedMessagePtr(e, submsg, subm, &size); - encode_varint(e, size); - wire_type = kUpb_WireType_Delimited; - e->depth++; - break; - } - default: - UPB_UNREACHABLE(); - } -#undef CASE - - encode_tag(e, f->UPB_PRIVATE(number), wire_type); -} - -static void encode_array(upb_encstate* e, const upb_Message* msg, - const upb_MiniTableSub* subs, - const upb_MiniTableField* f) { - const upb_Array* arr = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), upb_Array*); - bool packed = upb_MiniTableField_IsPacked(f); - size_t pre_len = e->limit - e->ptr; - - if (arr == NULL || arr->UPB_PRIVATE(size) == 0) { - return; - } - -#define VARINT_CASE(ctype, encode) \ - { \ - const ctype* start = _upb_array_constptr(arr); \ - const ctype* ptr = start + arr->UPB_PRIVATE(size); \ - uint32_t tag = \ - packed ? 0 : (f->UPB_PRIVATE(number) << 3) | kUpb_WireType_Varint; \ - do { \ - ptr--; \ - encode_varint(e, encode); \ - if (tag) encode_varint(e, tag); \ - } while (ptr != start); \ - } \ - break; - -#define TAG(wire_type) (packed ? 0 : (f->UPB_PRIVATE(number) << 3 | wire_type)) - - switch (f->UPB_PRIVATE(descriptortype)) { - case kUpb_FieldType_Double: - encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Float: - encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_SFixed64: - case kUpb_FieldType_Fixed64: - encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit)); - break; - case kUpb_FieldType_Fixed32: - case kUpb_FieldType_SFixed32: - encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit)); - break; - case kUpb_FieldType_Int64: - case kUpb_FieldType_UInt64: - VARINT_CASE(uint64_t, *ptr); - case kUpb_FieldType_UInt32: - VARINT_CASE(uint32_t, *ptr); - case kUpb_FieldType_Int32: - case kUpb_FieldType_Enum: - VARINT_CASE(int32_t, (int64_t)*ptr); - case kUpb_FieldType_Bool: - VARINT_CASE(bool, *ptr); - case kUpb_FieldType_SInt32: - VARINT_CASE(int32_t, encode_zz32(*ptr)); - case kUpb_FieldType_SInt64: - VARINT_CASE(int64_t, encode_zz64(*ptr)); - case kUpb_FieldType_String: - case kUpb_FieldType_Bytes: { - const upb_StringView* start = _upb_array_constptr(arr); - const upb_StringView* ptr = start + arr->UPB_PRIVATE(size); - do { - ptr--; - encode_bytes(e, ptr->data, ptr->size); - encode_varint(e, ptr->size); - encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited); - } while (ptr != start); - return; - } - case kUpb_FieldType_Group: { - const upb_TaggedMessagePtr* start = _upb_array_constptr(arr); - const upb_TaggedMessagePtr* ptr = start + arr->UPB_PRIVATE(size); - const upb_MiniTable* subm = - upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); - if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); - do { - size_t size; - ptr--; - encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_EndGroup); - encode_TaggedMessagePtr(e, *ptr, subm, &size); - encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_StartGroup); - } while (ptr != start); - e->depth++; - return; - } - case kUpb_FieldType_Message: { - const upb_TaggedMessagePtr* start = _upb_array_constptr(arr); - const upb_TaggedMessagePtr* ptr = start + arr->UPB_PRIVATE(size); - const upb_MiniTable* subm = - upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); - if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); - do { - size_t size; - ptr--; - encode_TaggedMessagePtr(e, *ptr, subm, &size); - encode_varint(e, size); - encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited); - } while (ptr != start); - e->depth++; - return; - } - } -#undef VARINT_CASE - - if (packed) { - encode_varint(e, e->limit - e->ptr - pre_len); - encode_tag(e, f->UPB_PRIVATE(number), kUpb_WireType_Delimited); - } -} - -static void encode_mapentry(upb_encstate* e, uint32_t number, - const upb_MiniTable* layout, - const upb_MapEntry* ent) { - const upb_MiniTableField* key_field = &layout->UPB_PRIVATE(fields)[0]; - const upb_MiniTableField* val_field = &layout->UPB_PRIVATE(fields)[1]; - size_t pre_len = e->limit - e->ptr; - size_t size; - encode_scalar(e, &ent->data.v, layout->UPB_PRIVATE(subs), val_field); - encode_scalar(e, &ent->data.k, layout->UPB_PRIVATE(subs), key_field); - size = (e->limit - e->ptr) - pre_len; - encode_varint(e, size); - encode_tag(e, number, kUpb_WireType_Delimited); -} - -static void encode_map(upb_encstate* e, const upb_Message* msg, - const upb_MiniTableSub* subs, - const upb_MiniTableField* f) { - const upb_Map* map = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), const upb_Map*); - const upb_MiniTable* layout = - upb_MiniTableSub_Message(subs[f->UPB_PRIVATE(submsg_index)]); - UPB_ASSERT(layout->UPB_PRIVATE(field_count) == 2); - - if (map == NULL) return; - - if (e->options & kUpb_EncodeOption_Deterministic) { - _upb_sortedmap sorted; - _upb_mapsorter_pushmap( - &e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype), - map, &sorted); - upb_MapEntry ent; - while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { - encode_mapentry(e, f->UPB_PRIVATE(number), layout, &ent); - } - _upb_mapsorter_popmap(&e->sorter, &sorted); - } else { - intptr_t iter = UPB_STRTABLE_BEGIN; - upb_StringView key; - upb_value val; - while (upb_strtable_next2(&map->table, &key, &val, &iter)) { - upb_MapEntry ent; - _upb_map_fromkey(key, &ent.data.k, map->key_size); - _upb_map_fromvalue(val, &ent.data.v, map->val_size); - encode_mapentry(e, f->UPB_PRIVATE(number), layout, &ent); - } - } -} - -static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, - const upb_MiniTableSub* subs, - const upb_MiniTableField* f) { - if (f->presence == 0) { - // Proto3 presence or map/array. - const void* mem = UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), void); - switch (UPB_PRIVATE(_upb_MiniTableField_GetRep)(f)) { - case kUpb_FieldRep_1Byte: { - char ch; - memcpy(&ch, mem, 1); - return ch != 0; - } - case kUpb_FieldRep_4Byte: { - uint32_t u32; - memcpy(&u32, mem, 4); - return u32 != 0; - } - case kUpb_FieldRep_8Byte: { - uint64_t u64; - memcpy(&u64, mem, 8); - return u64 != 0; - } - case kUpb_FieldRep_StringView: { - const upb_StringView* str = (const upb_StringView*)mem; - return str->size != 0; - } - default: - UPB_UNREACHABLE(); - } - } else if (f->presence > 0) { - // Proto2 presence: hasbit. - return UPB_PRIVATE(_upb_Message_GetHasbit)(msg, f); - } else { - // Field is in a oneof. - return UPB_PRIVATE(_upb_Message_GetOneofCase)(msg, f) == - f->UPB_PRIVATE(number); - } -} - -static void encode_field(upb_encstate* e, const upb_Message* msg, - const upb_MiniTableSub* subs, - const upb_MiniTableField* field) { - switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) { - case kUpb_FieldMode_Array: - encode_array(e, msg, subs, field); - break; - case kUpb_FieldMode_Map: - encode_map(e, msg, subs, field); - break; - case kUpb_FieldMode_Scalar: - encode_scalar(e, UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void), subs, - field); - break; - default: - UPB_UNREACHABLE(); - } -} - -static void encode_msgset_item(upb_encstate* e, const upb_Extension* ext) { - size_t size; - encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_EndGroup); - encode_message(e, ext->data.ptr, - upb_MiniTableExtension_GetSubMessage(ext->ext), &size); - encode_varint(e, size); - encode_tag(e, kUpb_MsgSet_Message, kUpb_WireType_Delimited); - encode_varint(e, upb_MiniTableExtension_Number(ext->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) { - if (UPB_UNLIKELY(is_message_set)) { - encode_msgset_item(e, ext); - } else { - encode_field(e, (upb_Message*)&ext->data, &ext->ext->UPB_PRIVATE(sub), - &ext->ext->UPB_PRIVATE(field)); - } -} - -static void encode_message(upb_encstate* e, const upb_Message* msg, - const upb_MiniTable* m, size_t* size) { - size_t pre_len = e->limit - e->ptr; - - if ((e->options & kUpb_EncodeOption_CheckRequired) && - m->UPB_PRIVATE(required_count)) { - uint64_t msg_head; - memcpy(&msg_head, msg, 8); - msg_head = _upb_BigEndian_Swap64(msg_head); - if (UPB_PRIVATE(_upb_MiniTable_RequiredMask)(m) & ~msg_head) { - encode_err(e, kUpb_EncodeStatus_MissingRequired); - } - } - - if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) { - size_t unknown_size; - const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); - - if (unknown) { - encode_bytes(e, unknown, unknown_size); - } - } - - 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); - } - } - } - } - - if (m->UPB_PRIVATE(field_count)) { - const upb_MiniTableField* f = - &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; - const upb_MiniTableField* first = &m->UPB_PRIVATE(fields)[0]; - while (f != first) { - f--; - if (encode_shouldencode(e, msg, m->UPB_PRIVATE(subs), f)) { - encode_field(e, msg, m->UPB_PRIVATE(subs), f); - } - } - } - - *size = (e->limit - e->ptr) - pre_len; -} - -static upb_EncodeStatus upb_Encoder_Encode(upb_encstate* const encoder, - const upb_Message* const msg, - const upb_MiniTable* const l, - char** const buf, - size_t* const size) { - // Unfortunately we must continue to perform hackery here because there are - // code paths which blindly copy the returned pointer without bothering to - // check for errors until much later (b/235839510). So we still set *buf to - // NULL on error and we still set it to non-NULL on a successful empty result. - if (UPB_SETJMP(encoder->err) == 0) { - encode_message(encoder, msg, l, size); - *size = encoder->limit - encoder->ptr; - if (*size == 0) { - static char ch; - *buf = &ch; - } else { - UPB_ASSERT(encoder->ptr); - *buf = encoder->ptr; - } - } else { - UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok); - *buf = NULL; - *size = 0; - } - - _upb_mapsorter_destroy(&encoder->sorter); - return encoder->status; -} - -upb_EncodeStatus upb_Encode(const upb_Message* msg, const upb_MiniTable* l, - int options, upb_Arena* arena, char** buf, - size_t* size) { - upb_encstate e; - unsigned depth = (unsigned)options >> 16; - - e.status = kUpb_EncodeStatus_Ok; - e.arena = arena; - e.buf = NULL; - e.limit = NULL; - e.ptr = NULL; - e.depth = depth ? depth : kUpb_WireFormat_DefaultDepthLimit; - e.options = options; - _upb_mapsorter_init(&e.sorter); - - return upb_Encoder_Encode(&e, msg, l, buf, size); -} - - - -// Must be last. - -UPB_NOINLINE _upb_WireReader_ReadLongVarintRet -_upb_WireReader_ReadLongVarint(const char* ptr, uint64_t val) { - _upb_WireReader_ReadLongVarintRet ret = {NULL, 0}; +UPB_NOINLINE UPB_PRIVATE(_upb_WireReader_LongVarint) + UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val) { + UPB_PRIVATE(_upb_WireReader_LongVarint) ret = {NULL, 0}; uint64_t byte; int i; for (i = 1; i < 10; i++) { @@ -15289,9 +15292,9 @@ return ret; } -const char* _upb_WireReader_SkipGroup(const char* ptr, uint32_t tag, - int depth_limit, - upb_EpsCopyInputStream* stream) { +const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream) { if (--depth_limit == 0) return NULL; uint32_t end_group_tag = (tag & ~7ULL) | kUpb_WireType_EndGroup; while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) {
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index 005e234..d644416 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h
@@ -1356,8 +1356,9 @@ // Must be last. struct upb_Decoder; +struct upb_Message; typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr, - upb_Message* msg, intptr_t table, + struct upb_Message* msg, intptr_t table, uint64_t hasbits, uint64_t data); typedef struct { uint64_t field_data; @@ -4006,6 +4007,72 @@ #endif /* UPB_WIRE_DECODE_H_ */ +// upb_Encode: parsing from a upb_Message using a upb_MiniTable. + +#ifndef UPB_WIRE_ENCODE_H_ +#define UPB_WIRE_ENCODE_H_ + +#include <stddef.h> +#include <stdint.h> + + +// Must be last. + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* If set, the results of serializing will be deterministic across all + * instances of this binary. There are no guarantees across different + * binary builds. + * + * If your proto contains maps, the encoder will need to malloc()/free() + * memory during encode. */ + kUpb_EncodeOption_Deterministic = 1, + + // When set, unknown fields are not printed. + kUpb_EncodeOption_SkipUnknown = 2, + + // When set, the encode will fail if any required fields are missing. + kUpb_EncodeOption_CheckRequired = 4, +}; + +typedef enum { + kUpb_EncodeStatus_Ok = 0, + 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_API upb_EncodeStatus upb_Encode(const upb_Message* msg, + const upb_MiniTable* l, int options, + upb_Arena* arena, char** buf, size_t* size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /* UPB_WIRE_ENCODE_H_ */ + // These are the specialized field parser functions for the fast parser. // Generated tables will refer to these by name. // @@ -4040,8 +4107,8 @@ // - '1' for one-byte tags (field numbers 1-15) // - '2' for two-byte tags (field numbers 16-2048) -#ifndef UPB_WIRE_DECODE_FAST_H_ -#define UPB_WIRE_DECODE_FAST_H_ +#ifndef UPB_WIRE_DECODE_INTERNAL_FAST_H_ +#define UPB_WIRE_DECODE_INTERNAL_FAST_H_ // Must be last. @@ -4142,73 +4209,7 @@ #endif -#endif /* UPB_WIRE_DECODE_FAST_H_ */ - -// upb_Encode: parsing from a upb_Message using a upb_MiniTable. - -#ifndef UPB_WIRE_ENCODE_H_ -#define UPB_WIRE_ENCODE_H_ - -#include <stddef.h> -#include <stdint.h> - - -// Must be last. - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* If set, the results of serializing will be deterministic across all - * instances of this binary. There are no guarantees across different - * binary builds. - * - * If your proto contains maps, the encoder will need to malloc()/free() - * memory during encode. */ - kUpb_EncodeOption_Deterministic = 1, - - // When set, unknown fields are not printed. - kUpb_EncodeOption_SkipUnknown = 2, - - // When set, the encode will fail if any required fields are missing. - kUpb_EncodeOption_CheckRequired = 4, -}; - -typedef enum { - kUpb_EncodeStatus_Ok = 0, - 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_API upb_EncodeStatus upb_Encode(const upb_Message* msg, - const upb_MiniTable* l, int options, - upb_Arena* arena, char** buf, size_t* size); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_WIRE_ENCODE_H_ */ +#endif /* UPB_WIRE_DECODE_INTERNAL_FAST_H_ */ // IWYU pragma: end_exports #endif // UPB_GENERATED_CODE_SUPPORT_H_ @@ -13533,8 +13534,8 @@ #endif /* UPB_WIRE_INTERNAL_DECODE_H_ */ -#ifndef UPB_WIRE_INTERNAL_SWAP_H_ -#define UPB_WIRE_INTERNAL_SWAP_H_ +#ifndef UPB_WIRE_INTERNAL_ENDIAN_H_ +#define UPB_WIRE_INTERNAL_ENDIAN_H_ #include <stdint.h> @@ -13544,23 +13545,23 @@ extern "C" { #endif -UPB_INLINE bool _upb_IsLittleEndian(void) { - int x = 1; +UPB_INLINE bool UPB_PRIVATE(_upb_IsLittleEndian)(void) { + const int x = 1; return *(char*)&x == 1; } -UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) { - if (_upb_IsLittleEndian()) return val; +UPB_INLINE uint32_t UPB_PRIVATE(_upb_BigEndian32)(uint32_t val) { + if (UPB_PRIVATE(_upb_IsLittleEndian)()) return val; return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); } -UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { - if (_upb_IsLittleEndian()) return val; +UPB_INLINE uint64_t UPB_PRIVATE(_upb_BigEndian64)(uint64_t val) { + if (UPB_PRIVATE(_upb_IsLittleEndian)()) return val; - return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | - _upb_BigEndian_Swap32((uint32_t)(val >> 32)); + return ((uint64_t)UPB_PRIVATE(_upb_BigEndian32)((uint32_t)val) << 32) | + UPB_PRIVATE(_upb_BigEndian32)((uint32_t)(val >> 32)); } #ifdef __cplusplus @@ -13568,12 +13569,65 @@ #endif -#endif /* UPB_WIRE_INTERNAL_SWAP_H_ */ +#endif /* UPB_WIRE_INTERNAL_ENDIAN_H_ */ #ifndef UPB_WIRE_READER_H_ #define UPB_WIRE_READER_H_ +#ifndef UPB_WIRE_INTERNAL_READER_H_ +#define UPB_WIRE_INTERNAL_READER_H_ + +// Must be last. + +#define kUpb_WireReader_WireTypeBits 3 +#define kUpb_WireReader_WireTypeMask 7 + +typedef struct { + const char* ptr; + uint64_t val; +} UPB_PRIVATE(_upb_WireReader_LongVarint); + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_PRIVATE(_upb_WireReader_LongVarint) +UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val); + +static UPB_FORCEINLINE const char* UPB_PRIVATE(_upb_WireReader_ReadVarint)( + const char* ptr, uint64_t* val, int maxlen, uint64_t maxval) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = (uint32_t)byte; + return ptr + 1; + } + const char* start = ptr; + UPB_PRIVATE(_upb_WireReader_LongVarint) + res = UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(ptr, byte); + if (!res.ptr || (maxlen < 10 && res.ptr - start > maxlen) || + res.val > maxval) { + return NULL; // Malformed. + } + *val = res.val; + return res.ptr; +} + +UPB_INLINE uint32_t UPB_PRIVATE(_upb_WireReader_GetFieldNumber)(uint32_t tag) { + return tag >> kUpb_WireReader_WireTypeBits; +} + +UPB_INLINE uint8_t UPB_PRIVATE(_upb_WireReader_GetWireType)(uint32_t tag) { + return tag & kUpb_WireReader_WireTypeMask; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_INTERNAL_READER_H_ + #ifndef UPB_WIRE_TYPES_H_ #define UPB_WIRE_TYPES_H_ @@ -13591,46 +13645,15 @@ // Must be last. -#ifdef __cplusplus -extern "C" { -#endif - // The upb_WireReader interface is suitable for general-purpose parsing of -// protobuf binary wire format. It is designed to be used along with +// protobuf binary wire format. It is designed to be used along with // upb_EpsCopyInputStream for buffering, and all parsing routines in this file // assume that at least kUpb_EpsCopyInputStream_SlopBytes worth of data is // available to read without any bounds checks. -#define kUpb_WireReader_WireTypeMask 7 -#define kUpb_WireReader_WireTypeBits 3 - -typedef struct { - const char* ptr; - uint64_t val; -} _upb_WireReader_ReadLongVarintRet; - -_upb_WireReader_ReadLongVarintRet _upb_WireReader_ReadLongVarint( - const char* ptr, uint64_t val); - -static UPB_FORCEINLINE const char* _upb_WireReader_ReadVarint(const char* ptr, - uint64_t* val, - int maxlen, - uint64_t maxval) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = (uint32_t)byte; - return ptr + 1; - } - const char* start = ptr; - _upb_WireReader_ReadLongVarintRet res = - _upb_WireReader_ReadLongVarint(ptr, byte); - if (!res.ptr || (maxlen < 10 && res.ptr - start > maxlen) || - res.val > maxval) { - return NULL; // Malformed. - } - *val = res.val; - return res.ptr; -} +#ifdef __cplusplus +extern "C" { +#endif // Parses a tag into `tag`, and returns a pointer past the end of the tag, or // NULL if there was an error in the tag data. @@ -13641,7 +13664,7 @@ static UPB_FORCEINLINE const char* upb_WireReader_ReadTag(const char* ptr, uint32_t* tag) { uint64_t val; - ptr = _upb_WireReader_ReadVarint(ptr, &val, 5, UINT32_MAX); + ptr = UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, &val, 5, UINT32_MAX); if (!ptr) return NULL; *tag = val; return ptr; @@ -13649,17 +13672,17 @@ // Given a tag, returns the field number. UPB_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag) { - return tag >> kUpb_WireReader_WireTypeBits; + return UPB_PRIVATE(_upb_WireReader_GetFieldNumber)(tag); } // Given a tag, returns the wire type. UPB_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag) { - return tag & kUpb_WireReader_WireTypeMask; + return UPB_PRIVATE(_upb_WireReader_GetWireType)(tag); } UPB_INLINE const char* upb_WireReader_ReadVarint(const char* ptr, uint64_t* val) { - return _upb_WireReader_ReadVarint(ptr, val, 10, UINT64_MAX); + return UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, val, 10, UINT64_MAX); } // Skips data for a varint, returning a pointer past the end of the varint, or @@ -13695,7 +13718,7 @@ UPB_INLINE const char* upb_WireReader_ReadFixed32(const char* ptr, void* val) { uint32_t uval; memcpy(&uval, ptr, 4); - uval = _upb_BigEndian_Swap32(uval); + uval = UPB_PRIVATE(_upb_BigEndian32)(uval); memcpy(val, &uval, 4); return ptr + 4; } @@ -13708,14 +13731,14 @@ UPB_INLINE const char* upb_WireReader_ReadFixed64(const char* ptr, void* val) { uint64_t uval; memcpy(&uval, ptr, 8); - uval = _upb_BigEndian_Swap64(uval); + uval = UPB_PRIVATE(_upb_BigEndian64)(uval); memcpy(val, &uval, 8); return ptr + 8; } -const char* _upb_WireReader_SkipGroup(const char* ptr, uint32_t tag, - int depth_limit, - upb_EpsCopyInputStream* stream); +const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream); // Skips data for a group, returning a pointer past the end of the group, or // NULL if there was an error parsing the group. The `tag` argument should be @@ -13728,7 +13751,7 @@ // control over this? UPB_INLINE const char* upb_WireReader_SkipGroup( const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { - return _upb_WireReader_SkipGroup(ptr, tag, 100, stream); + return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, 100, stream); } UPB_INLINE const char* _upb_WireReader_SkipValue( @@ -13749,7 +13772,8 @@ return ptr; } case kUpb_WireType_StartGroup: - return _upb_WireReader_SkipGroup(ptr, tag, depth_limit, stream); + return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, depth_limit, + stream); case kUpb_WireType_EndGroup: return NULL; // Should be handled before now. default: