summaryrefslogtreecommitdiff
path: root/upb/pb/decoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'upb/pb/decoder.c')
-rw-r--r--upb/pb/decoder.c361
1 files changed, 240 insertions, 121 deletions
diff --git a/upb/pb/decoder.c b/upb/pb/decoder.c
index ae54e47..1b5fc17 100644
--- a/upb/pb/decoder.c
+++ b/upb/pb/decoder.c
@@ -13,14 +13,95 @@
#include "upb/pb/decoder.h"
#include "upb/pb/varint.h"
+/* upb_decoderplan ************************************************************/
+
#ifdef UPB_USE_JIT_X64
-#define Dst_DECL upb_decoder *d
-#define Dst_REF (d->dynasm)
-#define Dst (d)
+// These defines are necessary for DynASM codegen.
+// See dynasm/dasm_proto.h for more info.
+#define Dst_DECL upb_decoderplan *plan
+#define Dst_REF (plan->dynasm)
+#define Dst (plan)
+
+// In debug mode, make DynASM do internal checks (must be defined before any
+// dasm header is included.
+#ifndef NDEBUG
+#define DASM_CHECKS
+#endif
+
#include "dynasm/dasm_proto.h"
#include "upb/pb/decoder_x64.h"
#endif
+typedef struct {
+ upb_fhandlers base;
+ void (*decode)(struct _upb_decoder *d, struct _upb_fieldent *f);
+#ifdef UPB_USE_JIT_X64
+ uint32_t jit_pclabel;
+ uint32_t jit_pclabel_notypecheck;
+#endif
+} upb_dplanfield;
+
+typedef struct {
+ upb_mhandlers base;
+#ifdef UPB_USE_JIT_X64
+ uint32_t jit_startmsg_pclabel;
+ uint32_t jit_endofbuf_pclabel;
+ uint32_t jit_endofmsg_pclabel;
+ uint32_t jit_dyndispatch_pclabel;
+ uint32_t jit_unknownfield_pclabel;
+ int32_t jit_parent_field_done_pclabel;
+ uint32_t max_field_number;
+ // Currently keyed on field number. Could also try keying it
+ // on encoded or decoded tag, or on encoded field number.
+ void **tablearray;
+#endif
+} upb_dplanmsg;
+
+static void *upb_decoderplan_fptrs[];
+
+void upb_decoderplan_initfhandlers(upb_fhandlers *f) {
+ f->decode = upb_decoderplan_fptrs[f->type];
+}
+
+upb_decoderplan *upb_decoderplan_new(upb_handlers *h, bool allowjit) {
+ upb_decoderplan *p = malloc(sizeof(*p));
+ p->handlers = h;
+ upb_handlers_ref(h);
+ h->should_jit = allowjit;
+#ifdef UPB_USE_JIT_X64
+ p->jit_code = NULL;
+ if (allowjit) upb_decoderplan_makejit(p);
+#endif
+ // Set function pointers for each field's decode function.
+ for (int i = 0; i < h->msgs_len; i++) {
+ upb_mhandlers *m = h->msgs[i];
+ for(upb_inttable_iter i = upb_inttable_begin(&m->fieldtab);
+ !upb_inttable_done(i);
+ i = upb_inttable_next(&m->fieldtab, i)) {
+ upb_itofhandlers_ent *e = upb_inttable_iter_value(i);
+ upb_fhandlers *f = e->f;
+ upb_decoderplan_initfhandlers(f);
+ }
+ }
+ return p;
+}
+
+void upb_decoderplan_unref(upb_decoderplan *p) {
+ // TODO: make truly refcounted.
+ upb_handlers_unref(p->handlers);
+#ifdef UPB_USE_JIT_X64
+ if (p->jit_code) upb_decoderplan_freejit(p);
+#endif
+ free(p);
+}
+
+bool upb_decoderplan_hasjitcode(upb_decoderplan *p) {
+ return p->jit_code != NULL;
+}
+
+
+/* upb_decoder ****************************************************************/
+
// It's unfortunate that we have to micro-manage the compiler this way,
// especially since this tuning is necessarily specific to one hardware
// configuration. But emperically on a Core i7, performance increases 30-50%
@@ -29,18 +110,17 @@
#define FORCEINLINE static __attribute__((always_inline))
#define NOINLINE static __attribute__((noinline))
-static void upb_decoder_exit(upb_decoder *d) {
+UPB_NORETURN static void upb_decoder_exitjmp(upb_decoder *d) {
// Resumable decoder would back out to completed_ptr (and possibly get a
// previous buffer).
siglongjmp(d->exitjmp, 1);
}
-static void upb_decoder_exit2(void *_d) {
- upb_decoder *d = _d;
- upb_decoder_exit(d);
+UPB_NORETURN static void upb_decoder_exitjmp2(void *d) {
+ upb_decoder_exitjmp(d);
}
-static void upb_decoder_abort(upb_decoder *d, const char *msg) {
- upb_status_seterrliteral(d->status, msg);
- upb_decoder_exit(d);
+UPB_NORETURN static void upb_decoder_abortjmp(upb_decoder *d, const char *msg) {
+ upb_status_seterrliteral(&d->status, msg);
+ upb_decoder_exitjmp(d);
}
/* Buffering ******************************************************************/
@@ -50,8 +130,12 @@ static void upb_decoder_abort(upb_decoder *d, const char *msg) {
// the next one. When we've committed our progress we discard any previous
// buffers' regions.
-static uint32_t upb_decoder_bufleft(upb_decoder *d) { return d->end - d->ptr; }
-static void upb_decoder_advance(upb_decoder *d, uint32_t len) {
+static size_t upb_decoder_bufleft(upb_decoder *d) {
+ assert(d->end >= d->ptr);
+ return d->end - d->ptr;
+}
+
+static void upb_decoder_advance(upb_decoder *d, size_t len) {
assert(upb_decoder_bufleft(d) >= len);
d->ptr += len;
}
@@ -66,29 +150,49 @@ uint64_t upb_decoder_bufendofs(upb_decoder *d) {
static void upb_decoder_setmsgend(upb_decoder *d) {
upb_dispatcher_frame *f = d->dispatcher.top;
- uint32_t delimlen = f->end_ofs - d->bufstart_ofs;
- uint32_t buflen = d->end - d->buf;
+ size_t delimlen = f->end_ofs - d->bufstart_ofs;
+ size_t buflen = d->end - d->buf;
d->delim_end = (f->end_ofs != UPB_NONDELIMITED && delimlen <= buflen) ?
d->buf + delimlen : NULL; // NULL if not in this buf.
d->top_is_packed = f->is_packed;
+ d->dispatch_table = &d->dispatcher.msgent->fieldtab;
}
-static bool upb_trypullbuf(upb_decoder *d) {
- assert(upb_decoder_bufleft(d) == 0);
- d->bufstart_ofs = upb_decoder_offset(d);
+static void upb_decoder_skiptonewbuf(upb_decoder *d, uint64_t ofs) {
+ assert(ofs >= upb_decoder_offset(d));
+ if (ofs > upb_byteregion_endofs(d->input))
+ upb_decoder_abortjmp(d, "Unexpected EOF");
d->buf = NULL;
d->ptr = NULL;
d->end = NULL;
- if (upb_byteregion_available(d->input, upb_decoder_offset(d)) == 0 &&
- !upb_byteregion_fetch(d->input, d->status)) {
- if (upb_eof(d->status)) return false;
- upb_decoder_exit(d); // Non-EOF error.
+ d->delim_end = NULL;
+#ifdef UPB_USE_JIT_X64
+ d->jit_end = NULL;
+#endif
+ d->bufstart_ofs = ofs;
+}
+
+static bool upb_trypullbuf(upb_decoder *d) {
+ assert(upb_decoder_bufleft(d) == 0);
+ upb_decoder_skiptonewbuf(d, upb_decoder_offset(d));
+ if (upb_byteregion_available(d->input, d->bufstart_ofs) == 0) {
+ switch (upb_byteregion_fetch(d->input)) {
+ case UPB_BYTE_OK:
+ assert(upb_byteregion_available(d->input, d->bufstart_ofs) > 0);
+ break;
+ case UPB_BYTE_EOF: return false;
+ case UPB_BYTE_ERROR: upb_decoder_abortjmp(d, "I/O error in input");
+ // Decoder resuming is not yet supported.
+ case UPB_BYTE_WOULDBLOCK:
+ upb_decoder_abortjmp(d, "Input returned WOULDBLOCK");
+ }
}
- uint32_t len;
+ size_t len;
d->buf = upb_byteregion_getptr(d->input, d->bufstart_ofs, &len);
assert(len > 0);
d->ptr = d->buf;
d->end = d->buf + len;
+ upb_decoder_setmsgend(d);
#ifdef UPB_USE_JIT_X64
// If we start parsing a value, we can parse up to 20 bytes without
// having to bounds-check anything (2 10-byte varints). Since the
@@ -96,27 +200,29 @@ static bool upb_trypullbuf(upb_decoder *d) {
// JIT bails if there are not 20 bytes available.
d->jit_end = d->end - 20;
#endif
- upb_decoder_setmsgend(d);
+ assert(upb_decoder_bufleft(d) > 0);
return true;
}
static void upb_pullbuf(upb_decoder *d) {
- if (!upb_trypullbuf(d)) upb_decoder_abort(d, "Unexpected EOF");
+ if (!upb_trypullbuf(d)) upb_decoder_abortjmp(d, "Unexpected EOF");
}
-void upb_decoder_skipto(upb_decoder *d, uint64_t ofs) {
- if (ofs < upb_decoder_bufendofs(d)) {
+void upb_decoder_checkpoint(upb_decoder *d) {
+ upb_byteregion_discard(d->input, upb_decoder_offset(d));
+}
+
+void upb_decoder_discardto(upb_decoder *d, uint64_t ofs) {
+ if (ofs <= upb_decoder_bufendofs(d)) {
upb_decoder_advance(d, ofs - upb_decoder_offset(d));
} else {
- d->buf = NULL;
- d->ptr = NULL;
- d->end = NULL;
- d->bufstart_ofs = ofs;
+ upb_decoder_skiptonewbuf(d, ofs);
}
+ upb_decoder_checkpoint(d);
}
-void upb_decoder_checkpoint(upb_decoder *d) {
- upb_byteregion_discard(d->input, upb_decoder_offset(d));
+void upb_decoder_discard(upb_decoder *d, size_t bytes) {
+ upb_decoder_discardto(d, upb_decoder_offset(d) + bytes);
}
@@ -126,15 +232,13 @@ NOINLINE uint64_t upb_decode_varint_slow(upb_decoder *d) {
uint8_t byte = 0x80;
uint64_t u64 = 0;
int bitpos;
- const char *ptr = d->ptr;
for(bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) {
- if (upb_decoder_bufleft(d) == 0) {
- upb_pullbuf(d);
- ptr = d->ptr;
- }
- u64 |= ((uint64_t)(byte = *ptr++) & 0x7F) << bitpos;
+ if (upb_decoder_bufleft(d) == 0) upb_pullbuf(d);
+ u64 |= ((uint64_t)(byte = *d->ptr) & 0x7F) << bitpos;
+ upb_decoder_advance(d, 1);
}
- if(bitpos == 70 && (byte & 0x80)) upb_decoder_abort(d, "Unterminated varint");
+ if(bitpos == 70 && (byte & 0x80))
+ upb_decoder_abortjmp(d, "Unterminated varint");
return u64;
}
@@ -151,7 +255,7 @@ FORCEINLINE uint32_t upb_decode_varint32(upb_decoder *d) {
if ((*(p++) & 0x80) == 0) goto done; // likely
slow:
u64 = upb_decode_varint_slow(d);
- if (u64 > 0xffffffff) upb_decoder_abort(d, "Unterminated 32-bit varint");
+ if (u64 > UINT32_MAX) upb_decoder_abortjmp(d, "Unterminated 32-bit varint");
ret = (uint32_t)u64;
p = d->ptr; // Turn the next line into a nop.
done:
@@ -174,7 +278,7 @@ FORCEINLINE uint64_t upb_decode_varint(upb_decoder *d) {
if (upb_decoder_bufleft(d) >= 10) {
// Fast case.
upb_decoderet r = upb_vdecode_fast(d->ptr);
- if (r.p == NULL) upb_decoder_abort(d, "Unterminated varint");
+ if (r.p == NULL) upb_decoder_abortjmp(d, "Unterminated varint");
upb_decoder_advance(d, r.p - d->ptr);
return r.val;
} else if (upb_decoder_bufleft(d) > 0) {
@@ -200,11 +304,12 @@ FORCEINLINE void upb_decode_fixed(upb_decoder *d, char *buf, size_t bytes) {
} else {
// Slow case.
size_t read = 0;
- while (read < bytes) {
- size_t avail = upb_decoder_bufleft(d);
+ while (1) {
+ size_t avail = UPB_MIN(upb_decoder_bufleft(d), bytes - read);
memcpy(buf + read, d->ptr, avail);
upb_decoder_advance(d, avail);
read += avail;
+ if (read == bytes) break;
upb_pullbuf(d);
}
}
@@ -213,26 +318,28 @@ FORCEINLINE void upb_decode_fixed(upb_decoder *d, char *buf, size_t bytes) {
FORCEINLINE uint32_t upb_decode_fixed32(upb_decoder *d) {
uint32_t u32;
upb_decode_fixed(d, (char*)&u32, sizeof(uint32_t));
- return u32; // TODO: proper byte swapping
+ return u32; // TODO: proper byte swapping for big-endian machines.
}
FORCEINLINE uint64_t upb_decode_fixed64(upb_decoder *d) {
uint64_t u64;
upb_decode_fixed(d, (char*)&u64, sizeof(uint64_t));
- return u64; // TODO: proper byte swapping
+ return u64; // TODO: proper byte swapping for big-endian machines.
}
INLINE upb_byteregion *upb_decode_string(upb_decoder *d) {
uint32_t strlen = upb_decode_varint32(d);
uint64_t offset = upb_decoder_offset(d);
+ if (offset + strlen > upb_byteregion_endofs(d->input))
+ upb_decoder_abortjmp(d, "Unexpected EOF");
upb_byteregion_reset(&d->str_byteregion, d->input, offset, strlen);
// Could make it an option on the callback whether we fetchall() first or not.
- upb_byteregion_fetchall(&d->str_byteregion, d->status);
- if (!upb_ok(d->status)) upb_decoder_exit(d);
- upb_decoder_skipto(d, offset + strlen);
+ if (upb_byteregion_fetchall(&d->str_byteregion) != UPB_BYTE_OK)
+ upb_decoder_abortjmp(d, "Couldn't fetchall() on string.");
+ upb_decoder_discardto(d, offset + strlen);
return &d->str_byteregion;
}
-INLINE void upb_push(upb_decoder *d, upb_fhandlers *f, uint64_t end) {
+INLINE void upb_push_msg(upb_decoder *d, upb_fhandlers *f, uint64_t end) {
upb_dispatch_startsubmsg(&d->dispatcher, f)->end_ofs = end;
upb_decoder_setmsgend(d);
}
@@ -253,8 +360,6 @@ INLINE void upb_push(upb_decoder *d, upb_fhandlers *f, uint64_t end) {
static double upb_asdouble(uint64_t n) { double d; memcpy(&d, &n, 8); return d; }
static float upb_asfloat(uint32_t n) { float f; memcpy(&f, &n, 4); return f; }
-static int32_t upb_zzdec_32(uint32_t n) { return (n >> 1) ^ -(int32_t)(n & 1); }
-static int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); }
T(INT32, varint, int32, int32_t)
T(INT64, varint, int64, int64_t)
@@ -271,9 +376,10 @@ T(FLOAT, fixed32, float, upb_asfloat)
T(SINT32, varint, int32, upb_zzdec_32)
T(SINT64, varint, int64, upb_zzdec_64)
T(STRING, string, byteregion, upb_byteregion*)
+#undef T
static void upb_decode_GROUP(upb_decoder *d, upb_fhandlers *f) {
- upb_push(d, f, UPB_NONDELIMITED);
+ upb_push_msg(d, f, UPB_NONDELIMITED);
}
static void upb_endgroup(upb_decoder *d, upb_fhandlers *f) {
(void)f;
@@ -281,15 +387,30 @@ static void upb_endgroup(upb_decoder *d, upb_fhandlers *f) {
upb_decoder_setmsgend(d);
}
static void upb_decode_MESSAGE(upb_decoder *d, upb_fhandlers *f) {
- upb_push(d, f, upb_decode_varint32(d) + upb_decoder_offset(d));
+ uint32_t len = upb_decode_varint32(d);
+ upb_push_msg(d, f, upb_decoder_offset(d) + len);
}
+#define F(type) &upb_decode_ ## type
+static void *upb_decoderplan_fptrs[] = {
+ &upb_endgroup, F(DOUBLE), F(FLOAT), F(INT64),
+ F(UINT64), F(INT32), F(FIXED64), F(FIXED32), F(BOOL), F(STRING),
+ F(GROUP), F(MESSAGE), F(STRING), F(UINT32), F(ENUM), F(SFIXED32),
+ F(SFIXED64), F(SINT32), F(SINT64)};
+#undef F
+
/* The main decoding loop *****************************************************/
static void upb_decoder_checkdelim(upb_decoder *d) {
+ // TODO: This doesn't work for the case that no buffer is currently loaded
+ // (ie. d->buf == NULL) because delim_end is NULL even if we are at
+ // end-of-delim. Need to add a test that exercises this by putting a buffer
+ // seam in the middle of the final delimited value in a proto that we skip
+ // for some reason (like because it's unknown and we have no unknown field
+ // handler).
while (d->delim_end != NULL && d->ptr >= d->delim_end) {
- if (d->ptr > d->delim_end) upb_decoder_abort(d, "Bad submessage end");
+ if (d->ptr > d->delim_end) upb_decoder_abortjmp(d, "Bad submessage end");
if (d->dispatcher.top->is_sequence) {
upb_dispatch_endseq(&d->dispatcher);
} else {
@@ -299,33 +420,36 @@ static void upb_decoder_checkdelim(upb_decoder *d) {
}
}
-static void upb_decoder_enterjit(upb_decoder *d) {
- (void)d;
-#ifdef UPB_USE_JIT_X64
- if (d->jit_code && d->dispatcher.top == d->dispatcher.stack && d->ptr < d->jit_end) {
- // Decodes as many fields as possible, updating d->ptr appropriately,
- // before falling through to the slow(er) path.
- void (*upb_jit_decode)(upb_decoder *d) = (void*)d->jit_code;
- upb_jit_decode(d);
- }
-#endif
-}
-
INLINE upb_fhandlers *upb_decode_tag(upb_decoder *d) {
while (1) {
uint32_t tag;
if (!upb_trydecode_varint32(d, &tag)) return NULL;
uint8_t wire_type = tag & 0x7;
- upb_fhandlers *f = upb_dispatcher_lookup(&d->dispatcher, tag);
+ uint32_t fieldnum = tag >> 3;
+ upb_itofhandlers_ent *e = upb_inttable_fastlookup(
+ d->dispatch_table, fieldnum, sizeof(upb_itofhandlers_ent));
+ upb_fhandlers *f = e ? e->f : NULL;
+
+ if (f) {
+ // Wire type check.
+ if (wire_type == upb_types[f->type].native_wire_type ||
+ (wire_type == UPB_WIRE_TYPE_DELIMITED &&
+ upb_types[f->type].is_numeric)) {
+ // Wire type is ok.
+ } else {
+ f = NULL;
+ }
+ }
// There are no explicit "startseq" or "endseq" markers in protobuf
// streams, so we have to infer them by noticing when a repeated field
// starts or ends.
- if (d->dispatcher.top->is_sequence && d->dispatcher.top->f != f) {
+ upb_dispatcher_frame *fr = d->dispatcher.top;
+ if (fr->is_sequence && fr->f != f) {
upb_dispatch_endseq(&d->dispatcher);
upb_decoder_setmsgend(d);
}
- if (f && f->repeated && d->dispatcher.top->f != f) {
+ if (f && f->repeated && (!fr->is_sequence || fr->f != f)) {
uint64_t old_end = d->dispatcher.top->end_ofs;
upb_dispatcher_frame *fr = upb_dispatch_startseq(&d->dispatcher, f);
if (wire_type != UPB_WIRE_TYPE_DELIMITED ||
@@ -334,7 +458,8 @@ INLINE upb_fhandlers *upb_decode_tag(upb_decoder *d) {
fr->end_ofs = old_end;
} else {
// Packed primitive field.
- fr->end_ofs = upb_decoder_offset(d) + upb_decode_varint(d);
+ uint32_t len = upb_decode_varint32(d);
+ fr->end_ofs = upb_decoder_offset(d) + len;
fr->is_packed = true;
}
upb_decoder_setmsgend(d);
@@ -343,14 +468,20 @@ INLINE upb_fhandlers *upb_decode_tag(upb_decoder *d) {
if (f) return f;
// Unknown field.
+ if (fieldnum == 0 || fieldnum > UPB_MAX_FIELDNUMBER)
+ upb_decoder_abortjmp(d, "Invalid field number");
switch (wire_type) {
case UPB_WIRE_TYPE_VARINT: upb_decode_varint(d); break;
- case UPB_WIRE_TYPE_32BIT: upb_decoder_advance(d, 4); break;
- case UPB_WIRE_TYPE_64BIT: upb_decoder_advance(d, 8); break;
+ case UPB_WIRE_TYPE_32BIT: upb_decoder_discard(d, 4); break;
+ case UPB_WIRE_TYPE_64BIT: upb_decoder_discard(d, 8); break;
case UPB_WIRE_TYPE_DELIMITED:
- upb_decoder_advance(d, upb_decode_varint32(d)); break;
+ upb_decoder_discard(d, upb_decode_varint32(d)); break;
+ case UPB_WIRE_TYPE_START_GROUP:
+ upb_decoder_abortjmp(d, "Can't handle unknown groups yet");
+ case UPB_WIRE_TYPE_END_GROUP:
+ upb_decoder_abortjmp(d, "Unmatched ENDGROUP tag");
default:
- upb_decoder_abort(d, "Invalid wire type");
+ upb_decoder_abortjmp(d, "Invalid wire type");
}
// TODO: deliver to unknown field callback.
upb_decoder_checkpoint(d);
@@ -358,16 +489,22 @@ INLINE upb_fhandlers *upb_decode_tag(upb_decoder *d) {
}
}
-void upb_decoder_decode(upb_decoder *d, upb_status *status) {
- if (sigsetjmp(d->exitjmp, 0)) { assert(!upb_ok(status)); return; }
- d->status = status;
+upb_success_t upb_decoder_decode(upb_decoder *d) {
+ assert(d->input);
+ if (sigsetjmp(d->exitjmp, 0)) {
+ assert(!upb_ok(&d->status));
+ return UPB_ERROR;
+ }
upb_dispatch_startmsg(&d->dispatcher);
// Prime the buf so we can hit the JIT immediately.
upb_trypullbuf(d);
upb_fhandlers *f = d->dispatcher.top->f;
- while(1) { // Main loop: executed once per tag/field pair.
+ while(1) {
upb_decoder_checkdelim(d);
+#ifdef UPB_USE_JIT_X64
upb_decoder_enterjit(d);
+ upb_decoder_checkpoint(d);
+#endif
if (!d->top_is_packed) f = upb_decode_tag(d);
if (!f) {
// Sucessful EOF. We may need to dispatch a top-level implicit frame.
@@ -375,64 +512,46 @@ void upb_decoder_decode(upb_decoder *d, upb_status *status) {
assert(d->dispatcher.top->is_sequence);
upb_dispatch_endseq(&d->dispatcher);
}
- return;
+ return UPB_OK;
}
f->decode(d, f);
upb_decoder_checkpoint(d);
}
}
-static void upb_decoder_skip(void *_d, upb_dispatcher_frame *f) {
- upb_decoder *d = _d;
- if (f->end_ofs != UPB_NONDELIMITED) {
- upb_decoder_skipto(d, d->dispatcher.top->end_ofs);
- } else {
- // TODO: how to support skipping groups? Dispatcher could drop callbacks,
- // or it could be special-cased inside the decoder.
- }
+void upb_decoder_init(upb_decoder *d) {
+ upb_status_init(&d->status);
+ upb_dispatcher_init(&d->dispatcher, &d->status, &upb_decoder_exitjmp2, d);
+ d->plan = NULL;
+ d->input = NULL;
}
-void upb_decoder_init(upb_decoder *d, upb_handlers *handlers) {
- upb_dispatcher_init(
- &d->dispatcher, handlers, upb_decoder_skip, upb_decoder_exit2, d);
-#ifdef UPB_USE_JIT_X64
- d->jit_code = NULL;
- if (d->dispatcher.handlers->should_jit) upb_decoder_makejit(d);
-#endif
- // Set function pointers for each field's decode function.
- for (int i = 0; i < handlers->msgs_len; i++) {
- upb_mhandlers *m = handlers->msgs[i];
- for(upb_inttable_iter i = upb_inttable_begin(&m->fieldtab); !upb_inttable_done(i);
- i = upb_inttable_next(&m->fieldtab, i)) {
- upb_fhandlers *f = upb_inttable_iter_value(i);
-#define F(type) &upb_decode_ ## type
- static void *fptrs[] = {&upb_endgroup, F(DOUBLE), F(FLOAT), F(INT64),
- F(UINT64), F(INT32), F(FIXED64), F(FIXED32), F(BOOL), F(STRING),
- F(GROUP), F(MESSAGE), F(STRING), F(UINT32), F(ENUM), F(SFIXED32),
- F(SFIXED64), F(SINT32), F(SINT64)};
- f->decode = fptrs[f->type];
- }
- }
+void upb_decoder_resetplan(upb_decoder *d, upb_decoderplan *p, int msg_offset) {
+ assert(msg_offset >= 0);
+ assert(msg_offset < p->handlers->msgs_len);
+ d->plan = p;
+ d->msg_offset = msg_offset;
+ d->input = NULL;
}
-void upb_decoder_reset(upb_decoder *d, upb_byteregion *input, void *closure) {
- upb_dispatcher_frame *f = upb_dispatcher_reset(&d->dispatcher, closure);
+void upb_decoder_resetinput(upb_decoder *d, upb_byteregion *input,
+ void *closure) {
+ assert(d->plan);
+ upb_dispatcher_frame *f =
+ upb_dispatcher_reset(&d->dispatcher, closure, d->plan->handlers->msgs[0]);
+ upb_status_clear(&d->status);
f->end_ofs = UPB_NONDELIMITED;
d->input = input;
- d->bufstart_ofs = upb_byteregion_startofs(input);
- d->buf = NULL;
- d->ptr = NULL;
- d->end = NULL; // Force a buffer pull.
- d->delim_end = NULL; // But don't let end-of-message get triggered.
d->str_byteregion.bytesrc = input->bytesrc;
-#ifdef UPB_USE_JIT_X64
- d->jit_end = NULL;
-#endif
+
+ // Protect against assert in skiptonewbuf().
+ d->bufstart_ofs = 0;
+ d->ptr = NULL;
+ d->buf = NULL;
+ upb_decoder_skiptonewbuf(d, upb_byteregion_startofs(input));
}
void upb_decoder_uninit(upb_decoder *d) {
-#ifdef UPB_USE_JIT_X64
- if (d->dispatcher.handlers->should_jit) upb_decoder_freejit(d);
-#endif
upb_dispatcher_uninit(&d->dispatcher);
+ upb_status_uninit(&d->status);
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback