Added fasttable support for oneofs.

pull/13171/head
Joshua Haberman 4 years ago
parent 7ffa9c181a
commit e3e797b680
  1. 1728
      cmake/google/protobuf/descriptor.upb.c
  2. 1
      tests/conformance_upb.c
  3. 2
      upb/decode.c
  4. 57
      upb/decode_fast.c
  5. 2
      upb/msg.h
  6. 70
      upbc/generator.cc

File diff suppressed because it is too large Load Diff

@ -286,6 +286,7 @@ int main(void) {
if (!DoTestIo(symtab)) { if (!DoTestIo(symtab)) {
fprintf(stderr, "conformance_upb: received EOF from test runner " fprintf(stderr, "conformance_upb: received EOF from test runner "
"after %d tests, exiting\n", test_count); "after %d tests, exiting\n", test_count);
upb_symtab_free(symtab);
return 0; return 0;
} }
} }

@ -640,7 +640,7 @@ const char *fastdecode_generic(upb_decstate *d, const char *ptr, upb_msg *msg,
const upb_msglayout *table, uint64_t hasbits, const upb_msglayout *table, uint64_t hasbits,
uint64_t data) { uint64_t data) {
decode_parseret ret; decode_parseret ret;
*(uint32_t*)msg |= hasbits >> 16; /* Sync hasbits. */ *(uint32_t*)msg |= hasbits; /* Sync hasbits. */
(void)data; (void)data;
if (decode_isdone(d, &ptr)) return ptr; if (decode_isdone(d, &ptr)) return ptr;
ret = decode_field(d, ptr, msg, table); ret = decode_field(d, ptr, msg, table);

@ -73,7 +73,7 @@ const char *fastdecode_dispatch(upb_decstate *d, const char *ptr, upb_msg *msg,
int overrun = ptr - d->end; int overrun = ptr - d->end;
if (UPB_LIKELY(overrun == d->limit)) { if (UPB_LIKELY(overrun == d->limit)) {
// Parse is finished. // Parse is finished.
*(uint32_t*)msg |= hasbits >> 16; // Sync hasbits. *(uint32_t*)msg |= hasbits; // Sync hasbits.
return ptr; return ptr;
} else { } else {
return fastdecode_isdonefallback(d, ptr, msg, table, hasbits, overrun); return fastdecode_isdonefallback(d, ptr, msg, table, hasbits, overrun);
@ -188,29 +188,32 @@ static fastdecode_nextret fastdecode_nextrepeated(upb_decstate *d, void *dst,
} }
UPB_FORCEINLINE UPB_FORCEINLINE
static void *fastdecode_getfield_ofs(upb_decstate *d, const char *ptr, static void *fastdecode_getfield(upb_decstate *d, const char *ptr, upb_msg *msg,
upb_msg *msg, uint64_t *data, uint64_t *data, uint64_t *hasbits,
uint64_t *hasbits, fastdecode_arr *farr, fastdecode_arr *farr, int valbytes,
int valbytes, upb_card card, upb_card card) {
bool hasbit_is_idx) {
size_t ofs = *data >> 48; size_t ofs = *data >> 48;
void *field = (char *)msg + ofs; void *field = (char *)msg + ofs;
switch (card) { switch (card) {
case CARD_s: case CARD_s: {
uint8_t hasbit_index = *data >> 24;
// Set hasbit and return pointer to scalar field. // Set hasbit and return pointer to scalar field.
if (hasbit_is_idx) { *hasbits |= 1ull << hasbit_index;
*hasbits |= 1ull << ((*data >> 32) & 63); return field;
} else { }
*hasbits |= *data; case CARD_o: {
} uint16_t case_ofs = *data >> 32;
uint32_t *oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t);
uint8_t field_number = *data >> 24;
*oneof_case = field_number;
return field; return field;
}
case CARD_r: { case CARD_r: {
// Get pointer to upb_array and allocate/expand if necessary. // Get pointer to upb_array and allocate/expand if necessary.
uint8_t elem_size_lg2 = __builtin_ctz(valbytes); uint8_t elem_size_lg2 = __builtin_ctz(valbytes);
upb_array **arr_p = field; upb_array **arr_p = field;
char *begin; char *begin;
*hasbits >>= 16;
*(uint32_t*)msg |= *hasbits; *(uint32_t*)msg |= *hasbits;
*hasbits = 0; *hasbits = 0;
if (UPB_LIKELY(!*arr_p)) { if (UPB_LIKELY(!*arr_p)) {
@ -259,8 +262,8 @@ static const char *fastdecode_varint(UPB_PARSE_PARAMS, int tagbytes,
RETURN_GENERIC("varint field tag mismatch\n"); RETURN_GENERIC("varint field tag mismatch\n");
} }
dst = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr, valbytes, dst =
card, false); fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card);
if (card == CARD_r) { if (card == CARD_r) {
if (UPB_UNLIKELY(!dst)) { if (UPB_UNLIKELY(!dst)) {
RETURN_GENERIC("need array resize\n"); RETURN_GENERIC("need array resize\n");
@ -362,8 +365,8 @@ static const char *fastdecode_fixed(UPB_PARSE_PARAMS, int tagbytes,
RETURN_GENERIC("fixed field tag mismatch\n"); RETURN_GENERIC("fixed field tag mismatch\n");
} }
dst = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr, valbytes, dst =
card, false); fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card);
if (card == CARD_r) { if (card == CARD_r) {
if (UPB_UNLIKELY(!dst)) { if (UPB_UNLIKELY(!dst)) {
RETURN_GENERIC("couldn't allocate array in arena\n"); RETURN_GENERIC("couldn't allocate array in arena\n");
@ -473,10 +476,10 @@ UPB_FORCEINLINE
static void fastdecode_docopy(upb_decstate *d, const char *ptr, uint32_t size, static void fastdecode_docopy(upb_decstate *d, const char *ptr, uint32_t size,
int copy, char *data, upb_strview *dst) { int copy, char *data, upb_strview *dst) {
d->arena.head.ptr += copy; d->arena.head.ptr += copy;
dst->data = data;
UPB_UNPOISON_MEMORY_REGION(data, copy); UPB_UNPOISON_MEMORY_REGION(data, copy);
memcpy(data, ptr, copy); memcpy(data, ptr, copy);
UPB_POISON_MEMORY_REGION(data + size, copy - size); UPB_POISON_MEMORY_REGION(data + size, copy - size);
dst->data = data;
} }
UPB_FORCEINLINE UPB_FORCEINLINE
@ -492,8 +495,8 @@ static const char *fastdecode_copystring(UPB_PARSE_PARAMS, int tagbytes,
UPB_ASSERT(!d->alias); UPB_ASSERT(!d->alias);
UPB_ASSERT(fastdecode_checktag(data, tagbytes)); UPB_ASSERT(fastdecode_checktag(data, tagbytes));
dst = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr, dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,
sizeof(upb_strview), card, false); sizeof(upb_strview), card);
again: again:
if (card == CARD_r) { if (card == CARD_r) {
@ -565,8 +568,8 @@ static const char *fastdecode_string(UPB_PARSE_PARAMS, int tagbytes,
return copyfunc(UPB_PARSE_ARGS); return copyfunc(UPB_PARSE_ARGS);
} }
dst = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr, dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,
sizeof(upb_strview), card, false); sizeof(upb_strview), card);
again: again:
if (card == CARD_r) { if (card == CARD_r) {
@ -579,6 +582,7 @@ again:
dst->size = size; dst->size = size;
if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) {
ptr--;
return fastdecode_longstring(d, ptr, msg, table, hasbits, dst); return fastdecode_longstring(d, ptr, msg, table, hasbits, dst);
} }
@ -667,16 +671,15 @@ static const char *fastdecode_submsg(UPB_PARSE_PARAMS, int tagbytes,
if (--d->depth == 0) return fastdecode_err(d); if (--d->depth == 0) return fastdecode_err(d);
upb_msg **submsg; upb_msg **submsg;
uint32_t submsg_idx = data; uint32_t submsg_idx = (data >> 16) & 0xff;
submsg_idx >>= 16;
const upb_msglayout *subl = table->submsgs[submsg_idx]; const upb_msglayout *subl = table->submsgs[submsg_idx];
fastdecode_arr farr; fastdecode_arr farr;
submsg = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr, submsg = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,
sizeof(upb_msg *), card, true); sizeof(upb_msg *), card);
if (card == CARD_s) { if (card == CARD_s) {
*(uint32_t*)msg |= hasbits >> 16; *(uint32_t*)msg |= hasbits;
hasbits = 0; hasbits = 0;
} }

@ -55,8 +55,8 @@ typedef const char *_upb_field_parser(struct upb_decstate *d, const char *ptr,
uint64_t hasbits, uint64_t data); uint64_t hasbits, uint64_t data);
typedef struct { typedef struct {
_upb_field_parser *field_parser;
uint64_t field_data; uint64_t field_data;
_upb_field_parser *field_parser;
} _upb_fasttable_entry; } _upb_fasttable_entry;
typedef struct upb_msglayout { typedef struct upb_msglayout {

@ -736,7 +736,7 @@ struct SubmsgArray {
absl::flat_hash_map<const protobuf::Descriptor*, int> indexes_; absl::flat_hash_map<const protobuf::Descriptor*, int> indexes_;
}; };
typedef std::pair<std::string, MessageLayout::Size> TableEntry; typedef std::pair<std::string, uint64_t> TableEntry;
void TryFillTableEntry(const protobuf::Descriptor* message, void TryFillTableEntry(const protobuf::Descriptor* message,
const MessageLayout& layout, int num, TableEntry& ent) { const MessageLayout& layout, int num, TableEntry& ent) {
@ -801,7 +801,7 @@ void TryFillTableEntry(const protobuf::Descriptor* message,
case protobuf::FieldDescriptor::LABEL_OPTIONAL: case protobuf::FieldDescriptor::LABEL_OPTIONAL:
case protobuf::FieldDescriptor::LABEL_REQUIRED: case protobuf::FieldDescriptor::LABEL_REQUIRED:
if (field->real_containing_oneof()) { if (field->real_containing_oneof()) {
return; // Not supported yet. cardinality = "o";
} else { } else {
cardinality = "s"; cardinality = "s";
} }
@ -811,37 +811,49 @@ void TryFillTableEntry(const protobuf::Descriptor* message,
uint16_t expected_tag = (num << 3) | wire_type; uint16_t expected_tag = (num << 3) | wire_type;
if (num > 15) expected_tag |= 0x100; if (num > 15) expected_tag |= 0x100;
MessageLayout::Size offset = layout.GetFieldOffset(field); MessageLayout::Size offset = layout.GetFieldOffset(field);
uint64_t hasbit_index = 0; // Zero means no hasbits.
if (layout.HasHasbit(field)) {
hasbit_index = layout.GetHasbitIndex(field);
if (hasbit_index > 31) return;
// thas hasbits mask in the parser occupies bits 16-48
// in the 64 bit register.
hasbit_index += 16; // account for the shifted hasbits
}
MessageLayout::Size data;
data.size32 = ((uint64_t)offset.size32 << 48) | expected_tag; // Data is:
data.size64 = ((uint64_t)offset.size64 << 48) | expected_tag; //
// 48 32 16 0
if (field->type() == protobuf::FieldDescriptor::TYPE_MESSAGE) { // |--------|--------|--------|--------|--------|--------|--------|--------|
SubmsgArray submsg_array(message); // | offset (16) |case offset (16) |presence| submsg | exp. tag (16) |
uint64_t idx = submsg_array.GetIndex(field); // |--------|--------|--------|--------|--------|--------|--------|--------|
data.size32 |= idx << 16 | hasbit_index << 32; //
data.size64 |= idx << 16 | hasbit_index << 32; // - |presence| is either hasbit index or field number for oneofs.
uint64_t data = offset.size64 << 48 | expected_tag;
if (field->is_repeated()) {
// No hasbit/oneof-related fields.
} if (field->real_containing_oneof()) {
MessageLayout::Size case_offset =
layout.GetOneofCaseOffset(field->real_containing_oneof());
if (case_offset.size64 > 0xffff) return;
assert(field->number() < 256);
data |= field->number() << 24;
data |= case_offset.size64 << 32;
} else { } else {
uint64_t hasbit_mask = (1ull << hasbit_index) & -0x10000; uint64_t hasbit_index = 63; // No hasbit (set a high, unused bit).
data.size32 |= (uint64_t)hasbit_mask; if (layout.HasHasbit(field)) {
data.size64 |= (uint64_t)hasbit_mask; hasbit_index = layout.GetHasbitIndex(field);
if (hasbit_index > 31) return;
}
data |= hasbit_index << 24;
} }
if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
SubmsgArray submsg_array(message);
uint64_t idx = submsg_array.GetIndex(field);
if (idx > 255) return;
data |= idx << 16;
if (field->type() == protobuf::FieldDescriptor::TYPE_MESSAGE) {
std::string size_ceil = "max"; std::string size_ceil = "max";
size_t size = SIZE_MAX; size_t size = SIZE_MAX;
if (field->message_type()->file() == field->file()) { if (field->message_type()->file() == field->file()) {
// We can only be guaranteed the size of the sub-message if it is in the
// same file as us. We could relax this to increase the speed of
// cross-file sub-message parsing if we are comfortable requiring that
// users compile all messages at the same time.
MessageLayout sub_layout(field->message_type()); MessageLayout sub_layout(field->message_type());
size = sub_layout.message_size().size64 + 8; size = sub_layout.message_size().size64 + 8;
} }
@ -865,11 +877,8 @@ void TryFillTableEntry(const protobuf::Descriptor* message,
std::vector<TableEntry> FastDecodeTable(const protobuf::Descriptor* message, std::vector<TableEntry> FastDecodeTable(const protobuf::Descriptor* message,
const MessageLayout& layout) { const MessageLayout& layout) {
std::vector<TableEntry> table; std::vector<TableEntry> table;
MessageLayout::Size empty_size;
empty_size.size32 = 0;
empty_size.size64 = 0;
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
table.emplace_back(TableEntry{"fastdecode_generic", empty_size}); table.emplace_back(TableEntry{"fastdecode_generic", 0});
TryFillTableEntry(message, layout, i, table.back()); TryFillTableEntry(message, layout, i, table.back());
} }
return table; return table;
@ -972,7 +981,8 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) {
output("const upb_msglayout $0 = {\n", MessageInit(message)); output("const upb_msglayout $0 = {\n", MessageInit(message));
output(" {\n"); output(" {\n");
for (const auto& ent : table) { for (const auto& ent : table) {
output(" {&$0, $1},\n", ent.first, GetSizeInit(ent.second)); output(" {0x$1, &$0},\n", ent.first,
absl::StrCat(absl::Hex(ent.second, absl::kZeroPad16)));
} }
output(" },\n"); output(" },\n");
output(" $0,\n", submsgs_array_ref); output(" $0,\n", submsgs_array_ref);

Loading…
Cancel
Save