From 484809c272df7b1f05e56d09f6a5e8e0f340cac4 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 21 Mar 2011 10:44:19 -0700 Subject: Key dispatch table by (num x type), for modest perf improvement. This allows us to remove one type check in the critical path. --- src/upb_decoder.c | 34 +++++++++++----------------------- src/upb_stream.c | 13 ++++++------- src/upb_stream.h | 1 - 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src/upb_decoder.c b/src/upb_decoder.c index a3d00bb..6c23c22 100644 --- a/src/upb_decoder.c +++ b/src/upb_decoder.c @@ -111,25 +111,22 @@ typedef struct { upb_field_number_t field_number; } upb_tag; -INLINE bool upb_decode_tag(upb_decoder *d, upb_tag *tag) { +INLINE bool upb_decode_tag(upb_decoder *d, uint32_t *tag) { const char *p = d->ptr; - uint32_t tag_int; upb_value val; // Nearly all tag varints will be either 1 byte (1-16) or 2 bytes (17-2048). if (upb_decoder_bufleft(d) < 2) goto slow; // unlikely. - tag_int = *p & 0x7f; + *tag = *p & 0x7f; if ((*(p++) & 0x80) == 0) goto done; // predictable if fields are in order - tag_int |= (*p & 0x7f) << 7; + *tag |= (*p & 0x7f) << 7; if ((*(p++) & 0x80) == 0) goto done; // likely slow: // Decode a full varint starting over from ptr. if (!upb_decode_varint_slow(d, &val)) return false; - tag_int = upb_value_getint64(val); + *tag = upb_value_getint64(val); p = d->ptr; // Trick the next line into not overwriting us. done: upb_decoder_advance(d, p - d->ptr); - tag->wire_type = (upb_wire_type_t)(tag_int & 0x07); - tag->field_number = tag_int >> 3; return true; } @@ -251,7 +248,7 @@ void upb_decoder_decode(upb_decoder *d, upb_status *status) { #endif // Parse/handle tag. - upb_tag tag; + uint32_t tag; if (!upb_decode_tag(d, &tag)) { if (status->code == UPB_EOF && upb_dispatcher_stackempty(&d->dispatcher)) { // Normal end-of-file. @@ -270,7 +267,8 @@ void upb_decoder_decode(upb_decoder *d, upb_status *status) { // Decode wire data. Hopefully this branch will predict pretty well // since most types will read a varint here. upb_value val; - switch (tag.wire_type) { + uint8_t wire_type = tag & 0x7; + switch (wire_type) { case UPB_WIRE_TYPE_START_GROUP: break; // Nothing to do now, below we will push appropriately. case UPB_WIRE_TYPE_END_GROUP: @@ -294,26 +292,16 @@ void upb_decoder_decode(upb_decoder *d, upb_status *status) { } // Look up field by tag number. - upb_dispatcher_field *f = - upb_dispatcher_lookup(&d->dispatcher, tag.field_number); + upb_dispatcher_field *f = upb_dispatcher_lookup(&d->dispatcher, tag); if (!f) { - if (tag.wire_type == UPB_WIRE_TYPE_DELIMITED) + if (wire_type == UPB_WIRE_TYPE_DELIMITED) CHECK(upb_decode_string(d, &val, &d->tmp)); - CHECK_FLOW(upb_dispatch_unknownval(&d->dispatcher, tag.field_number, val)); + // TODO. + CHECK_FLOW(upb_dispatch_unknownval(&d->dispatcher, 0, UPB_NO_VALUE)); continue; } - if (tag.wire_type != f->native_wire_type) { - // TODO: Support packed fields. - upb_seterr(status, UPB_ERROR, "Field had incorrect type, field number: %d" - ", field type: %d, expected wire type: %d, " - "actual wire type: %d, offset: %d", - tag.field_number, f->type, upb_types[f->type].native_wire_type, - tag.wire_type, upb_decoder_offset(d)); - goto err; - } - // Perform any further massaging of the data now that we have the field's // type. Now we can distinguish strings from submessages, and we know // about zig-zag-encoded types. diff --git a/src/upb_stream.c b/src/upb_stream.c index af266dc..3b0119c 100644 --- a/src/upb_stream.c +++ b/src/upb_stream.c @@ -77,17 +77,16 @@ void upb_handlers_uninit(upb_handlers *h) { static upb_handlers_fieldent *upb_handlers_getorcreate_without_fval( upb_handlers *h, upb_field_number_t fieldnum, upb_fieldtype_t type) { + uint32_t tag = fieldnum << 3 | upb_types[type].native_wire_type; upb_handlers_fieldent *f = - upb_inttable_lookup(&h->msgent->fieldtab, fieldnum); + upb_inttable_lookup(&h->msgent->fieldtab, tag); if (!f) { - upb_wire_type_t native_wire_type = upb_types[type].native_wire_type; - upb_handlers_fieldent new_f = { - false, type, native_wire_type, -1, UPB_NO_VALUE, + upb_handlers_fieldent new_f = {false, type, -1, UPB_NO_VALUE, {&upb_value_nop}, &upb_endsubmsg_nop}; if (upb_issubmsgtype(type)) new_f.cb.startsubmsg = &upb_startsubmsg_nop; - upb_inttable_insert(&h->msgent->fieldtab, fieldnum, &new_f); + upb_inttable_insert(&h->msgent->fieldtab, tag, &new_f); - f = upb_inttable_lookup(&h->msgent->fieldtab, fieldnum); + f = upb_inttable_lookup(&h->msgent->fieldtab, tag); assert(f); } assert(f->type == type); @@ -223,7 +222,7 @@ void upb_handlers_pop(upb_handlers *h, upb_fielddef *f) { /* upb_dispatcher *************************************************************/ static upb_handlers_fieldent toplevel_f = { - false, 0, 0, 0, // The one value that is actually read + false, 0, 0, // The one value that is actually read #ifdef NDEBUG {{0}}, #else diff --git a/src/upb_stream.h b/src/upb_stream.h index f2ae11c..783f6c8 100644 --- a/src/upb_stream.h +++ b/src/upb_stream.h @@ -84,7 +84,6 @@ typedef upb_flow_t (*upb_unknownval_handler_t)( typedef struct { bool junk; upb_fieldtype_t type; - upb_wire_type_t native_wire_type; // For upb_issubmsg(f) only, the index into the msgdef array of the submsg. // -1 if unset (indicates that submsg should be skipped). int32_t msgent_index; -- cgit v1.2.3