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)) {
fprintf(stderr, "conformance_upb: received EOF from test runner "
"after %d tests, exiting\n", test_count);
upb_symtab_free(symtab);
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,
uint64_t data) {
decode_parseret ret;
*(uint32_t*)msg |= hasbits >> 16; /* Sync hasbits. */
*(uint32_t*)msg |= hasbits; /* Sync hasbits. */
(void)data;
if (decode_isdone(d, &ptr)) return ptr;
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;
if (UPB_LIKELY(overrun == d->limit)) {
// Parse is finished.
*(uint32_t*)msg |= hasbits >> 16; // Sync hasbits.
*(uint32_t*)msg |= hasbits; // Sync hasbits.
return ptr;
} else {
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
static void *fastdecode_getfield_ofs(upb_decstate *d, const char *ptr,
upb_msg *msg, uint64_t *data,
uint64_t *hasbits, fastdecode_arr *farr,
int valbytes, upb_card card,
bool hasbit_is_idx) {
static void *fastdecode_getfield(upb_decstate *d, const char *ptr, upb_msg *msg,
uint64_t *data, uint64_t *hasbits,
fastdecode_arr *farr, int valbytes,
upb_card card) {
size_t ofs = *data >> 48;
void *field = (char *)msg + ofs;
switch (card) {
case CARD_s:
case CARD_s: {
uint8_t hasbit_index = *data >> 24;
// Set hasbit and return pointer to scalar field.
if (hasbit_is_idx) {
*hasbits |= 1ull << ((*data >> 32) & 63);
} else {
*hasbits |= *data;
}
*hasbits |= 1ull << hasbit_index;
return field;
}
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;
}
case CARD_r: {
// Get pointer to upb_array and allocate/expand if necessary.
uint8_t elem_size_lg2 = __builtin_ctz(valbytes);
upb_array **arr_p = field;
char *begin;
*hasbits >>= 16;
*(uint32_t*)msg |= *hasbits;
*hasbits = 0;
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");
}
dst = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr, valbytes,
card, false);
dst =
fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card);
if (card == CARD_r) {
if (UPB_UNLIKELY(!dst)) {
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");
}
dst = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr, valbytes,
card, false);
dst =
fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card);
if (card == CARD_r) {
if (UPB_UNLIKELY(!dst)) {
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,
int copy, char *data, upb_strview *dst) {
d->arena.head.ptr += copy;
dst->data = data;
UPB_UNPOISON_MEMORY_REGION(data, copy);
memcpy(data, ptr, copy);
UPB_POISON_MEMORY_REGION(data + size, copy - size);
dst->data = data;
}
UPB_FORCEINLINE
@ -492,8 +495,8 @@ static const char *fastdecode_copystring(UPB_PARSE_PARAMS, int tagbytes,
UPB_ASSERT(!d->alias);
UPB_ASSERT(fastdecode_checktag(data, tagbytes));
dst = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr,
sizeof(upb_strview), card, false);
dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,
sizeof(upb_strview), card);
again:
if (card == CARD_r) {
@ -565,8 +568,8 @@ static const char *fastdecode_string(UPB_PARSE_PARAMS, int tagbytes,
return copyfunc(UPB_PARSE_ARGS);
}
dst = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr,
sizeof(upb_strview), card, false);
dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,
sizeof(upb_strview), card);
again:
if (card == CARD_r) {
@ -579,6 +582,7 @@ again:
dst->size = size;
if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) {
ptr--;
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);
upb_msg **submsg;
uint32_t submsg_idx = data;
submsg_idx >>= 16;
uint32_t submsg_idx = (data >> 16) & 0xff;
const upb_msglayout *subl = table->submsgs[submsg_idx];
fastdecode_arr farr;
submsg = fastdecode_getfield_ofs(d, ptr, msg, &data, &hasbits, &farr,
sizeof(upb_msg *), card, true);
submsg = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,
sizeof(upb_msg *), card);
if (card == CARD_s) {
*(uint32_t*)msg |= hasbits >> 16;
*(uint32_t*)msg |= hasbits;
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);
typedef struct {
_upb_field_parser *field_parser;
uint64_t field_data;
_upb_field_parser *field_parser;
} _upb_fasttable_entry;
typedef struct upb_msglayout {

@ -736,7 +736,7 @@ struct SubmsgArray {
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,
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_REQUIRED:
if (field->real_containing_oneof()) {
return; // Not supported yet.
cardinality = "o";
} else {
cardinality = "s";
}
@ -811,37 +811,49 @@ void TryFillTableEntry(const protobuf::Descriptor* message,
uint16_t expected_tag = (num << 3) | wire_type;
if (num > 15) expected_tag |= 0x100;
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.size64 = ((uint64_t)offset.size64 << 48) | expected_tag;
if (field->type() == protobuf::FieldDescriptor::TYPE_MESSAGE) {
SubmsgArray submsg_array(message);
uint64_t idx = submsg_array.GetIndex(field);
data.size32 |= idx << 16 | hasbit_index << 32;
data.size64 |= idx << 16 | hasbit_index << 32;
// Data is:
//
// 48 32 16 0
// |--------|--------|--------|--------|--------|--------|--------|--------|
// | offset (16) |case offset (16) |presence| submsg | exp. tag (16) |
// |--------|--------|--------|--------|--------|--------|--------|--------|
//
// - |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 {
uint64_t hasbit_mask = (1ull << hasbit_index) & -0x10000;
data.size32 |= (uint64_t)hasbit_mask;
data.size64 |= (uint64_t)hasbit_mask;
uint64_t hasbit_index = 63; // No hasbit (set a high, unused bit).
if (layout.HasHasbit(field)) {
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";
size_t size = SIZE_MAX;
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());
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,
const MessageLayout& layout) {
std::vector<TableEntry> table;
MessageLayout::Size empty_size;
empty_size.size32 = 0;
empty_size.size64 = 0;
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());
}
return table;
@ -972,7 +981,8 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) {
output("const upb_msglayout $0 = {\n", MessageInit(message));
output(" {\n");
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(" $0,\n", submsgs_array_ref);

Loading…
Cancel
Save