Handle non-repeated submessages.

pull/13171/head
Joshua Haberman 4 years ago
parent e219a2d91d
commit f173642db4
  1. 20
      upb/decode.c
  2. 30
      upb/decode.h
  3. 72
      upb/decode_fast.c
  4. 21
      upbc/generator.cc

@ -199,31 +199,13 @@ static void decode_donatemem(upb_decstate *d) {
}
UPB_NOINLINE
static void *decode_mallocfallback(upb_decstate *d, size_t size) {
void *decode_mallocfallback(upb_decstate *d, size_t size) {
char *ptr = _upb_arena_slowmalloc(d->arena, size);
if (!ptr) decode_err(d);
decode_stealmem(d);
return ptr;
}
UPB_FORCEINLINE
static void *decode_malloc(upb_decstate *d, size_t size) {
UPB_ASSERT((size & 7) == 0);
char *ptr = d->arena_ptr;
if (UPB_UNLIKELY((size_t)(d->arena_end - d->arena_ptr) < size)) {
return decode_mallocfallback(d, size);
}
d->arena_ptr += size;
return ptr;
}
static upb_msg *decode_newmsg(upb_decstate *d, const upb_msglayout *l) {
size_t size = l->size + sizeof(upb_msg_internal);
char *msg_data = decode_malloc(d, size);
memset(msg_data, 0, size);
return msg_data + sizeof(upb_msg_internal);
}
UPB_NOINLINE
static void decode_realloc(upb_decstate *d, upb_array *arr, size_t need_elem) {
decode_donatemem(d);

@ -9,6 +9,8 @@
#include "upb/msg.h"
#include "upb/port_def.inc"
#ifdef __cplusplus
extern "C" {
#endif
@ -37,6 +39,28 @@ const char *fastdecode_generic(upb_decstate *d, const char *ptr, upb_msg *msg,
uint64_t data);
const char *fastdecode_err(upb_decstate *d);
void *decode_mallocfallback(upb_decstate *d, size_t size);
UPB_FORCEINLINE
static void *decode_malloc(upb_decstate *d, size_t size) {
UPB_ASSERT((size & 7) == 0);
char *ptr = d->arena_ptr;
if (UPB_UNLIKELY((size_t)(d->arena_end - d->arena_ptr) < size)) {
return decode_mallocfallback(d, size);
}
d->arena_ptr += size;
return ptr;
}
UPB_INLINE
upb_msg *decode_newmsg(upb_decstate *d, const upb_msglayout *l) {
size_t size = l->size + sizeof(upb_msg_internal);
char *msg_data = (char*)decode_malloc(d, size);
memset(msg_data, 0, size);
return msg_data + sizeof(upb_msg_internal);
}
#define UPB_PARSE_PARAMS \
upb_decstate *d, const char *ptr, upb_msg *msg, const upb_msglayout *table, \
uint64_t hasbits, uint64_t data
@ -63,6 +87,10 @@ const char *upb_pss_1bt(UPB_PARSE_PARAMS);
const char *upb_pss_2bt(UPB_PARSE_PARAMS);
const char *upb_pos_1bt(UPB_PARSE_PARAMS);
const char *upb_pos_2bt(UPB_PARSE_PARAMS);
const char *upb_psm_1bt(UPB_PARSE_PARAMS);
const char *upb_pom_1bt(UPB_PARSE_PARAMS);
const char *upb_psm_2bt(UPB_PARSE_PARAMS);
const char *upb_pom_2bt(UPB_PARSE_PARAMS);
#undef F
#undef TYPES
@ -73,4 +101,6 @@ const char *upb_pos_2bt(UPB_PARSE_PARAMS);
} /* extern "C" */
#endif
#include "upb/port_undef.inc"
#endif /* UPB_DECODE_H_ */

@ -56,9 +56,8 @@ UPB_FORCEINLINE uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigza
}
UPB_FORCEINLINE
static void *fastdecode_getfield(upb_msg *msg, uint64_t *data,
uint64_t *hasbits, upb_card card) {
size_t ofs = (*data >> 48);
static void *fastdecode_getfield_ofs(upb_msg *msg, size_t ofs, uint64_t *data,
uint64_t *hasbits, upb_card card) {
void *field = (char *)msg + ofs;
switch (card) {
@ -77,6 +76,12 @@ static void *fastdecode_getfield(upb_msg *msg, uint64_t *data,
}
}
UPB_FORCEINLINE
static void *fastdecode_getfield(upb_msg *msg, uint64_t *data,
uint64_t *hasbits, upb_card card) {
return fastdecode_getfield_ofs(msg, *data >> 48, data, hasbits, card);
}
/* varint fields **************************************************************/
UPB_FORCEINLINE
@ -183,3 +188,64 @@ const char *upb_pss_2bt(UPB_PARSE_PARAMS) {
const char *upb_pos_2bt(UPB_PARSE_PARAMS) {
return fastdecode_string(UPB_PARSE_ARGS, 2, CARD_o);
}
/* message fields *************************************************************/
UPB_FORCEINLINE
static const char *fastdecode_submsg(UPB_PARSE_PARAMS, int tagbytes,
upb_card card) {
const char *saved_limit;
const upb_msglayout_field *field = &table->fields[data >> 48];
size_t ofs = field->offset;
const upb_msglayout *subl = table->submsgs[field->submsg_index];
upb_msg **submsg;
int64_t len;
if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) {
return fastdecode_generic(UPB_PARSE_ARGS);
}
submsg = fastdecode_getfield_ofs(msg, ofs, &data, &hasbits, card);
len = ptr[tagbytes];
if (UPB_UNLIKELY(len < 0)) {
return fastdecode_generic(UPB_PARSE_ARGS);
}
ptr += tagbytes + 1;
if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, len, d->limit))) {
return fastdecode_err(d);
}
if (!*submsg) {
*submsg = decode_newmsg(d, subl);
}
saved_limit = d->limit;
if (--d->depth < 0) return fastdecode_err(d);
d->limit = ptr + len;
d->fastlimit = UPB_MIN(d->limit, d->fastend);
ptr = fastdecode_dispatch(d, ptr, *submsg, subl, 0);
if (ptr != d->limit) return fastdecode_err(d);
d->limit = saved_limit;
d->fastlimit = UPB_MIN(d->limit, d->fastend);
if (d->end_group != 0) return fastdecode_err(d);
d->depth++;
return fastdecode_dispatch(d, ptr, msg, table, hasbits);
}
const char *upb_psm_1bt(UPB_PARSE_PARAMS) {
return fastdecode_submsg(UPB_PARSE_ARGS, 1, CARD_s);
}
const char *upb_pom_1bt(UPB_PARSE_PARAMS) {
return fastdecode_submsg(UPB_PARSE_ARGS, 1, CARD_o);
}
const char *upb_psm_2bt(UPB_PARSE_PARAMS) {
return fastdecode_submsg(UPB_PARSE_ARGS, 2, CARD_s);
}
const char *upb_pom_2bt(UPB_PARSE_PARAMS) {
return fastdecode_submsg(UPB_PARSE_ARGS, 2, CARD_o);
}

@ -737,6 +737,10 @@ void TryFillTableEntry(const protobuf::Descriptor* message,
type = "s";
wire_type = 2;
break;
case protobuf::FieldDescriptor::TYPE_MESSAGE:
type = "m";
wire_type = 2;
break;
default:
return; // Not supported yet.
}
@ -755,12 +759,23 @@ void TryFillTableEntry(const protobuf::Descriptor* message,
}
uint16_t expected_tag = (num << 3) | wire_type;
if (num > 15) num |= 0x100;
if (num > 15) expected_tag |= 0x100;
MessageLayout::Size offset = layout.GetFieldOffset(field);
MessageLayout::Size data;
data.size32 = ((uint64_t)offset.size32 << 48) | expected_tag;
data.size64 = ((uint64_t)offset.size64 << 48) | expected_tag;
if (field->type() == protobuf::FieldDescriptor::TYPE_MESSAGE) {
// Message fields index into the field array instead of giving an offset.
std::vector<const protobuf::FieldDescriptor*> order =
FieldNumberOrder(message);
auto it = std::find(order.begin(), order.end(), field);
assert(it != order.end());
uint64_t idx = it - order.begin();
data.size32 = (idx << 48) | expected_tag;
data.size64 = (idx << 48) | expected_tag;
} else {
data.size32 = ((uint64_t)offset.size32 << 48) | expected_tag;
data.size64 = ((uint64_t)offset.size64 << 48) | expected_tag;
}
if (field->real_containing_oneof()) {
MessageLayout::Size case_ofs =

Loading…
Cancel
Save