Make all handlers objects refcounted.

I'm realizing that basically all upb objects
will need to be refcounted to be sharable
across languages, but *not* messages which
are on their way out so we can get out of
the business of data representations.

Things which must be refcounted:
- encoders, decoders
- handlers objects
- defs
pull/13171/head
Joshua Haberman 14 years ago
parent 2ccebb74c3
commit a503b8859c
  1. 8
      benchmarks/parsestream.upb_table.c
  2. 8
      benchmarks/parsetostruct.upb_table.c
  3. 4
      src/upb.h
  4. 52
      src/upb_atomic.h
  5. 2
      src/upb_decoder.c
  6. 12
      src/upb_decoder_x86.dasc
  7. 10
      src/upb_def.c
  8. 8
      src/upb_def.h
  9. 24
      src/upb_glue.c
  10. 76
      src/upb_handlers.c
  11. 155
      src/upb_handlers.h
  12. 12
      src/upb_msg.c
  13. 4
      src/upb_msg.h
  14. 2
      src/upb_string.c
  15. 2
      src/upb_string.h
  16. 8
      tests/tests.c

@ -10,7 +10,6 @@ static upb_string *input_str;
static upb_msgdef *def;
static upb_decoder decoder;
static upb_stringsrc stringsrc;
upb_handlers handlers;
static upb_sflow_t startsubmsg(void *_m, upb_value fval) {
(void)_m;
@ -61,11 +60,12 @@ static bool initialize()
return false;
}
upb_handlers_init(&handlers);
upb_handlers *handlers = upb_handlers_new();
// Cause all messages to be read, but do nothing when they are.
upb_handlerset hset = {NULL, NULL, value, startsubmsg, NULL, NULL, NULL};
upb_handlers_reghandlerset(&handlers, def, &hset);
upb_decoder_init(&decoder, &handlers);
upb_handlers_reghandlerset(handlers, def, &hset);
upb_decoder_init(&decoder, handlers);
upb_handlers_unref(handlers);
upb_stringsrc_init(&stringsrc);
return true;
}

@ -12,7 +12,6 @@ static upb_msgdef *def;
static upb_msg *msg;
static upb_stringsrc strsrc;
static upb_decoder d;
static upb_handlers h;
static bool initialize()
{
@ -53,9 +52,10 @@ static bool initialize()
msg = upb_msg_new(def);
upb_stringsrc_init(&strsrc);
upb_handlers_init(&h);
upb_msg_reghandlers(&h, def);
upb_decoder_init(&d, &h);
upb_handlers *handlers = upb_handlers_new();
upb_msg_reghandlers(handlers, def);
upb_decoder_init(&d, handlers);
upb_handlers_unref(handlers);
if (!BYREF) {
// Pretend the input string is stack-allocated, which will force its data

@ -162,7 +162,7 @@ typedef struct {
upb_bytesrc *bytesrc;
upb_msg *msg;
upb_array *arr;
upb_atomic_refcount_t *refcount;
upb_atomic_t *refcount;
upb_fielddef *fielddef;
void *_void;
} val;
@ -204,7 +204,7 @@ UPB_VALUE_ACCESSORS(fielddef, fielddef, upb_fielddef*, UPB_VALUETYPE_FIELDDEF);
extern upb_value UPB_NO_VALUE;
INLINE upb_atomic_refcount_t *upb_value_getrefcount(upb_value val) {
INLINE upb_atomic_t *upb_value_getrefcount(upb_value val) {
assert(val.type == UPB_TYPE(MESSAGE) ||
val.type == UPB_TYPE(STRING) ||
val.type == UPB_VALUETYPE_ARRAY);

@ -39,35 +39,19 @@ extern "C" {
typedef struct {
int v;
} upb_atomic_refcount_t;
} upb_atomic_t;
INLINE void upb_atomic_refcount_init(upb_atomic_refcount_t *a, int val) {
a->v = val;
}
INLINE bool upb_atomic_ref(upb_atomic_refcount_t *a) {
return a->v++ == 0;
}
INLINE bool upb_atomic_unref(upb_atomic_refcount_t *a) {
return --a->v == 0;
}
#define UPB_ATOMIC_INIT(x) {x}
INLINE int upb_atomic_read(upb_atomic_refcount_t *a) {
return a->v;
}
INLINE bool upb_atomic_add(upb_atomic_refcount_t *a, int val) {
INLINE void upb_atomic_init(upb_atomic_t *a, int val) { a->v = val; }
INLINE bool upb_atomic_ref(upb_atomic_t *a) { return a->v++ == 0; }
INLINE bool upb_atomic_unref(upb_atomic_t *a) { return --a->v == 0; }
INLINE int upb_atomic_read(upb_atomic_t *a) { return a->v; }
INLINE bool upb_atomic_add(upb_atomic_t *a, int val) {
a->v += val;
return a->v == 0;
}
INLINE int upb_atomic_fetch_and_add(upb_atomic_refcount_t *a, int val) {
int ret = a->v;
a->v += val;
return ret;
}
#endif
/* Atomic refcount ************************************************************/
@ -82,26 +66,26 @@ INLINE int upb_atomic_fetch_and_add(upb_atomic_refcount_t *a, int val) {
typedef struct {
volatile int v;
} upb_atomic_refcount_t;
} upb_atomic_t;
INLINE void upb_atomic_refcount_init(upb_atomic_refcount_t *a, int val) {
INLINE void upb_atomic_init(upb_atomic_t *a, int val) {
a->v = val;
__sync_synchronize(); /* Ensure the initialized value is visible. */
}
INLINE bool upb_atomic_ref(upb_atomic_refcount_t *a) {
INLINE bool upb_atomic_ref(upb_atomic_t *a) {
return __sync_fetch_and_add(&a->v, 1) == 0;
}
INLINE bool upb_atomic_add(upb_atomic_refcount_t *a, int n) {
INLINE bool upb_atomic_add(upb_atomic_t *a, int n) {
return __sync_add_and_fetch(&a->v, n) == 0;
}
INLINE bool upb_atomic_unref(upb_atomic_refcount_t *a) {
INLINE bool upb_atomic_unref(upb_atomic_t *a) {
return __sync_sub_and_fetch(&a->v, 1) == 0;
}
INLINE bool upb_atomic_read(upb_atomic_refcount_t *a) {
INLINE bool upb_atomic_read(upb_atomic_t *a) {
return __sync_fetch_and_add(&a->v, 0);
}
@ -112,17 +96,17 @@ INLINE bool upb_atomic_read(upb_atomic_refcount_t *a) {
typedef struct {
volatile LONG val;
} upb_atomic_refcount_t;
} upb_atomic_t;
INLINE void upb_atomic_refcount_init(upb_atomic_refcount_t *a, int val) {
INLINE void upb_atomic_init(upb_atomic_t *a, int val) {
InterlockedExchange(&a->val, val);
}
INLINE bool upb_atomic_ref(upb_atomic_refcount_t *a) {
INLINE bool upb_atomic_ref(upb_atomic_t *a) {
return InterlockedIncrement(&a->val) == 1;
}
INLINE bool upb_atomic_unref(upb_atomic_refcount_t *a) {
INLINE bool upb_atomic_unref(upb_atomic_t *a) {
return InterlockedDecrement(&a->val) == 0;
}
@ -131,7 +115,7 @@ INLINE bool upb_atomic_unref(upb_atomic_refcount_t *a) {
Implement them or compile with UPB_THREAD_UNSAFE.
#endif
INLINE bool upb_atomic_only(upb_atomic_refcount_t *a) {
INLINE bool upb_atomic_only(upb_atomic_t *a) {
return upb_atomic_read(a) == 1;
}

@ -399,10 +399,10 @@ void upb_decoder_reset(upb_decoder *d, upb_bytesrc *bytesrc, void *closure) {
}
void upb_decoder_uninit(upb_decoder *d) {
upb_dispatcher_uninit(&d->dispatcher);
upb_string_unref(d->bufstr);
upb_string_unref(d->tmp);
#ifdef UPB_USE_JIT_X64
if (d->dispatcher.handlers->should_jit) upb_decoder_freejit(d);
#endif
upb_dispatcher_uninit(&d->dispatcher);
}

@ -286,7 +286,7 @@ static void upb_decoder_jit_field(upb_decoder *d, uint32_t tag, uint32_t next_ta
| jne ->exit_jit // In the future: could be an unknown field or packed.
|=>f->jit_pclabel_notypecheck:
if (f->repeated) {
if (f->startseq != upb_startfield_nop) {
if (f->startseq) {
| mov ARG1_64, CLOSURE
| loadfval f
| callp f->startseq
@ -394,7 +394,7 @@ static void upb_decoder_jit_field(upb_decoder *d, uint32_t tag, uint32_t next_ta
// Call callbacks.
if (upb_issubmsgtype(f->type)) {
// Call startsubmsg handler (if any).
if (f->startsubmsg != upb_startfield_nop) {
if (f->startsubmsg) {
// upb_sflow_t startsubmsg(void *closure, upb_value fval)
| mov r12d, ARG3_32
| callp f->startsubmsg
@ -423,7 +423,7 @@ static void upb_decoder_jit_field(upb_decoder *d, uint32_t tag, uint32_t next_ta
| popframe
// Call endsubmsg handler (if any).
if (f->endsubmsg != upb_endfield_nop) {
if (f->endsubmsg) {
// upb_flow_t endsubmsg(void *closure, upb_value fval);
| mov ARG1_64, CLOSURE
| loadfval f
@ -441,7 +441,7 @@ static void upb_decoder_jit_field(upb_decoder *d, uint32_t tag, uint32_t next_ta
| checktag tag
| je <1
| popframe
if (f->endseq != upb_endfield_nop) {
if (f->endseq) {
| mov ARG1_64, CLOSURE
| loadfval f
| callp f->endseq
@ -466,7 +466,7 @@ static int upb_compare_uint32(const void *a, const void *b) {
static void upb_decoder_jit_msg(upb_decoder *d, upb_mhandlers *m) {
|=>m->jit_startmsg_pclabel:
// Call startmsg handler (if any):
if (m->startmsg != upb_startmsg_nop) {
if (m->startmsg) {
// upb_flow_t startmsg(void *closure);
| mov ARG1_64, FRAME->closure
| callp m->startmsg
@ -520,7 +520,7 @@ static void upb_decoder_jit_msg(upb_decoder *d, upb_mhandlers *m) {
|=>m->jit_endofmsg_pclabel:
// We are at end-of-submsg: call endmsg handler (if any):
if (m->endmsg != upb_endmsg_nop) {
if (m->endmsg) {
// void endmsg(void *closure, upb_status *status) {
| mov ARG1_64, FRAME->closure
| lea ARG2_64, DECODER->dispatcher.status

@ -172,7 +172,7 @@ static void upb_def_init(upb_def *def, upb_deftype type) {
def->is_cyclic = 0; // We detect this later, after resolving refs.
def->search_depth = 0;
def->fqname = NULL;
upb_atomic_refcount_init(&def->refcount, 1);
upb_atomic_init(&def->refcount, 1);
}
static void upb_def_uninit(upb_def *def) {
@ -868,7 +868,7 @@ static upb_flow_t upb_msgdef_startmsg(void *_b) {
upb_defbuilder *b = _b;
upb_msgdef *m = malloc(sizeof(*m));
upb_def_init(&m->base, UPB_DEF_MSG);
upb_atomic_refcount_init(&m->cycle_refcount, 0);
upb_atomic_init(&m->cycle_refcount, 0);
upb_inttable_init(&m->itof, 4, sizeof(upb_itof_ent));
upb_strtable_init(&m->ntof, 4, sizeof(upb_ntof_ent));
m->default_message = NULL;
@ -898,7 +898,7 @@ static void upb_msgdef_endmsg(void *_b, upb_status *status) {
// Assign offsets in the msg.
m->set_flags_bytes = upb_div_round_up(n, 8);
m->size = sizeof(upb_atomic_refcount_t) + m->set_flags_bytes;
m->size = sizeof(upb_atomic_t) + m->set_flags_bytes;
size_t max_align = 0;
for (int i = 0; i < n; i++) {
@ -926,7 +926,7 @@ static void upb_msgdef_endmsg(void *_b, upb_status *status) {
// whole must be a multiple of the greatest alignment of any member.
size_t offset = upb_align_up(m->size, align);
// Offsets are relative to the end of the refcount.
f->byte_offset = offset - sizeof(upb_atomic_refcount_t);
f->byte_offset = offset - sizeof(upb_atomic_t);
m->size = offset + size;
max_align = UPB_MAX(max_align, align);
}
@ -1242,7 +1242,7 @@ err:
upb_symtab *upb_symtab_new()
{
upb_symtab *s = malloc(sizeof(*s));
upb_atomic_refcount_init(&s->refcount, 1);
upb_atomic_init(&s->refcount, 1);
upb_rwlock_init(&s->lock);
upb_strtable_init(&s->symtab, 16, sizeof(upb_symtab_ent));
s->fds_msgdef = NULL;

@ -56,7 +56,7 @@ typedef int8_t upb_deftype_t;
typedef struct {
upb_string *fqname; // Fully qualified.
upb_atomic_refcount_t refcount;
upb_atomic_t refcount;
upb_deftype_t type;
// The is_cyclic flag could go in upb_msgdef instead of here, because only
@ -110,7 +110,7 @@ struct _upb_fielddef {
// For the case of an enum or a submessage, points to the def for that type.
upb_def *def;
upb_atomic_refcount_t refcount;
upb_atomic_t refcount;
};
// A variety of tests about the type of a field.
@ -159,7 +159,7 @@ INLINE bool upb_elem_ismm(upb_fielddef *f) {
// Structure that describes a single .proto message type.
typedef struct _upb_msgdef {
upb_def base;
upb_atomic_refcount_t cycle_refcount;
upb_atomic_t cycle_refcount;
uint32_t size;
uint32_t set_flags_bytes;
@ -283,7 +283,7 @@ INLINE int32_t upb_enum_iter_number(upb_enum_iter iter) {
// Clients add definitions to the symtab by supplying descriptors (as defined
// in descriptor.proto) via the upb_stream interface.
struct _upb_symtab {
upb_atomic_refcount_t refcount;
upb_atomic_t refcount;
upb_rwlock_t lock; // Protects all members except the refcount.
upb_strtable symtab; // The symbol table.
upb_msgdef *fds_msgdef; // Msgdef for google.protobuf.FileDescriptorSet.

@ -17,13 +17,13 @@ void upb_strtomsg(upb_string *str, upb_msg *msg, upb_msgdef *md,
upb_stringsrc_init(&strsrc);
upb_stringsrc_reset(&strsrc, str);
upb_handlers h;
upb_handlers_init(&h);
upb_msg_reghandlers(&h, md);
upb_handlers *h = upb_handlers_new();
upb_msg_reghandlers(h, md);
upb_decoder d;
upb_decoder_init(&d, &h);
upb_decoder_init(&d, h);
upb_decoder_reset(&d, upb_stringsrc_bytesrc(&strsrc), msg);
upb_handlers_unref(h);
upb_decoder_decode(&d, status);
@ -38,13 +38,12 @@ void upb_msgtotext(upb_string *str, upb_msg *msg, upb_msgdef *md,
upb_stringsink_reset(&strsink, str);
upb_textprinter *p = upb_textprinter_new();
upb_handlers h;
upb_handlers_init(&h);
upb_textprinter_reghandlers(&h, md);
upb_handlers *h = upb_handlers_new();
upb_textprinter_reghandlers(h, md);
upb_textprinter_reset(p, upb_stringsink_bytesink(&strsink), single_line);
upb_status status = UPB_STATUS_INIT;
upb_msg_runhandlers(msg, md, &h, p, &status);
upb_msg_runhandlers(msg, md, h, p, &status);
// None of {upb_msg_runhandlers, upb_textprinter, upb_stringsink} should be
// capable of returning an error.
assert(upb_ok(&status));
@ -52,6 +51,7 @@ void upb_msgtotext(upb_string *str, upb_msg *msg, upb_msgdef *md,
upb_stringsink_uninit(&strsink);
upb_textprinter_free(p);
upb_handlers_unref(h);
}
void upb_parsedesc(upb_symtab *symtab, upb_string *str, upb_status *status) {
@ -59,12 +59,12 @@ void upb_parsedesc(upb_symtab *symtab, upb_string *str, upb_status *status) {
upb_stringsrc_init(&strsrc);
upb_stringsrc_reset(&strsrc, str);
upb_handlers h;
upb_handlers_init(&h);
upb_defbuilder_reghandlers(&h);
upb_handlers *h = upb_handlers_new();
upb_defbuilder_reghandlers(h);
upb_decoder d;
upb_decoder_init(&d, &h);
upb_decoder_init(&d, h);
upb_handlers_unref(h);
upb_defbuilder *b = upb_defbuilder_new(symtab);
upb_decoder_reset(&d, upb_stringsrc_bytesrc(&strsrc), b);

@ -9,42 +9,13 @@
#include "upb_handlers.h"
upb_flow_t upb_startmsg_nop(void *closure) {
(void)closure;
return UPB_CONTINUE;
}
void upb_endmsg_nop(void *closure, upb_status *status) {
(void)closure;
(void)status;
}
upb_flow_t upb_value_nop(void *closure, upb_value fval, upb_value val) {
(void)closure;
(void)fval;
(void)val;
return UPB_CONTINUE;
}
upb_sflow_t upb_startfield_nop(void *closure, upb_value fval) {
(void)fval;
return UPB_CONTINUE_WITH(closure);
}
upb_flow_t upb_endfield_nop(void *closure, upb_value fval) {
(void)closure;
(void)fval;
return UPB_CONTINUE;
}
/* upb_mhandlers **************************************************************/
static upb_mhandlers *upb_mhandlers_new() {
upb_mhandlers *m = malloc(sizeof(*m));
upb_inttable_init(&m->fieldtab, 8, sizeof(upb_fhandlers));
m->startmsg = &upb_startmsg_nop;
m->endmsg = &upb_endmsg_nop;
m->startmsg = NULL;
m->endmsg = NULL;
m->tablearray = NULL;
m->is_group = false;
return m;
@ -57,11 +28,8 @@ static upb_fhandlers *_upb_mhandlers_newfhandlers(upb_mhandlers *m, uint32_t n,
upb_fhandlers *f = upb_inttable_lookup(&m->fieldtab, tag);
if (f) abort();
upb_fhandlers new_f = {false, type, repeated,
repeated && upb_isprimitivetype(type), n, m, NULL, UPB_NO_VALUE,
&upb_value_nop,
&upb_startfield_nop, &upb_endfield_nop,
&upb_startfield_nop, &upb_endfield_nop,
0, 0, 0, NULL};
repeated && upb_isprimitivetype(type), UPB_ATOMIC_INIT(0),
n, m, NULL, UPB_NO_VALUE, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL};
upb_inttable_insert(&m->fieldtab, tag, &new_f);
f = upb_inttable_lookup(&m->fieldtab, tag);
assert(f);
@ -92,14 +60,20 @@ upb_fhandlers *upb_mhandlers_newfhandlers_subm(upb_mhandlers *m, uint32_t n,
/* upb_handlers ***************************************************************/
void upb_handlers_init(upb_handlers *h) {
upb_handlers *upb_handlers_new() {
upb_handlers *h = malloc(sizeof(*h));
upb_atomic_init(&h->refcount, 1);
h->msgs_len = 0;
h->msgs_size = 4;
h->msgs = malloc(h->msgs_size * sizeof(*h->msgs));
h->should_jit = true;
return h;
}
void upb_handlers_uninit(upb_handlers *h) {
void upb_handlers_ref(upb_handlers *h) { upb_atomic_ref(&h->refcount); }
void upb_handlers_unref(upb_handlers *h) {
if (upb_atomic_unref(&h->refcount)) {
for (int i = 0; i < h->msgs_len; i++) {
upb_mhandlers *mh = h->msgs[i];
upb_inttable_free(&mh->fieldtab);
@ -107,6 +81,8 @@ void upb_handlers_uninit(upb_handlers *h) {
free(mh);
}
free(h->msgs);
free(h);
}
}
upb_mhandlers *upb_handlers_newmhandlers(upb_handlers *h) {
@ -172,7 +148,7 @@ upb_mhandlers *upb_handlers_regmsgdef(upb_handlers *h, upb_msgdef *m,
/* upb_dispatcher *************************************************************/
static upb_fhandlers toplevel_f = {
false, UPB_TYPE(GROUP), false, false, 0,
false, UPB_TYPE(GROUP), false, false, UPB_ATOMIC_INIT(0), 0,
NULL, NULL, // submsg
#ifdef NDEBUG
{{0}},
@ -185,6 +161,7 @@ void upb_dispatcher_init(upb_dispatcher *d, upb_handlers *h,
upb_skip_handler *skip, upb_exit_handler *exit,
void *srcclosure) {
d->handlers = h;
upb_handlers_ref(h);
for (int i = 0; i < h->msgs_len; i++) {
upb_mhandlers *m = h->msgs[i];
upb_inttable_compact(&m->fieldtab);
@ -207,18 +184,19 @@ upb_dispatcher_frame *upb_dispatcher_reset(upb_dispatcher *d, void *closure) {
}
void upb_dispatcher_uninit(upb_dispatcher *d) {
upb_handlers_uninit(d->handlers);
upb_handlers_unref(d->handlers);
upb_status_uninit(&d->status);
}
void upb_dispatch_startmsg(upb_dispatcher *d) {
upb_flow_t flow = d->msgent->startmsg(d->top->closure);
upb_flow_t flow = UPB_CONTINUE;
if (d->msgent->startmsg) d->msgent->startmsg(d->top->closure);
if (flow != UPB_CONTINUE) _upb_dispatcher_unwind(d, flow);
}
void upb_dispatch_endmsg(upb_dispatcher *d, upb_status *status) {
assert(d->top == d->stack);
d->msgent->endmsg(d->top->closure, &d->status);
if (d->msgent->endmsg) d->msgent->endmsg(d->top->closure, &d->status);
// TODO: should we avoid this copy by passing client's status obj to cbs?
upb_copyerr(status, &d->status);
}
@ -241,7 +219,8 @@ upb_dispatcher_frame *upb_dispatch_startseq(upb_dispatcher *d,
return d->top; // Dummy.
}
upb_sflow_t sflow = f->startseq(d->top->closure, f->fval);
upb_sflow_t sflow = UPB_CONTINUE_WITH(d->top->closure);
if (f->startseq) sflow = f->startseq(d->top->closure, f->fval);
if (sflow.flow != UPB_CONTINUE) {
_upb_dispatcher_unwind(d, sflow.flow);
return d->top; // Dummy.
@ -261,7 +240,8 @@ upb_dispatcher_frame *upb_dispatch_endseq(upb_dispatcher *d) {
assert(d->top->is_sequence);
upb_fhandlers *f = d->top->f;
--d->top;
upb_flow_t flow = f->endseq(d->top->closure, f->fval);
upb_flow_t flow = UPB_CONTINUE;
if (f->endseq) flow = f->endseq(d->top->closure, f->fval);
if (flow != UPB_CONTINUE) {
printf("YO, UNWINDING!\n");
_upb_dispatcher_unwind(d, flow);
@ -282,7 +262,8 @@ upb_dispatcher_frame *upb_dispatch_startsubmsg(upb_dispatcher *d,
return d->top; // Dummy.
}
upb_sflow_t sflow = f->startsubmsg(d->top->closure, f->fval);
upb_sflow_t sflow = UPB_CONTINUE_WITH(d->top->closure);
if (f->startsubmsg) sflow = f->startsubmsg(d->top->closure, f->fval);
if (sflow.flow != UPB_CONTINUE) {
_upb_dispatcher_unwind(d, sflow.flow);
return d->top; // Dummy.
@ -304,11 +285,12 @@ upb_dispatcher_frame *upb_dispatch_endsubmsg(upb_dispatcher *d) {
assert(d->top > d->stack);
assert(!d->top->is_sequence);
upb_fhandlers *f = d->top->f;
d->msgent->endmsg(d->top->closure, &d->status);
if (d->msgent->endmsg) d->msgent->endmsg(d->top->closure, &d->status);
d->msgent = d->top->f->msg;
d->dispatch_table = &d->msgent->fieldtab;
--d->top;
upb_flow_t flow = f->endsubmsg(d->top->closure, f->fval);
upb_flow_t flow = UPB_CONTINUE;
if (f->endsubmsg) f->endsubmsg(d->top->closure, f->fval);
if (flow != UPB_CONTINUE) _upb_dispatcher_unwind(d, flow);
return d->top;
}

@ -22,7 +22,7 @@
extern "C" {
#endif
/* upb_handlers ***************************************************************/
/* Handlers protocol definition ***********************************************/
// A upb_handlers object represents a graph of handlers. Each message can have
// a set of handlers as well as a set of fields which themselves have handlers.
@ -106,49 +106,42 @@ typedef enum {
// TODO: Add UPB_SUSPEND, for resumable producers/consumers.
} upb_flow_t;
// The startsubmsg handler needs to also pass a closure to the submsg.
typedef struct {
upb_flow_t flow;
void *closure;
} upb_sflow_t;
INLINE upb_sflow_t UPB_SFLOW(upb_flow_t flow, void *closure) {
upb_sflow_t ret = {flow, closure};
return ret;
}
#define UPB_CONTINUE_WITH(c) UPB_SFLOW(UPB_CONTINUE, c)
#define UPB_SBREAK UPB_SFLOW(UPB_BREAK, NULL)
// Typedefs for all of the handler functions defined above.
typedef struct _upb_sflow upb_sflow_t;
typedef upb_flow_t (upb_startmsg_handler)(void *c);
typedef void (upb_endmsg_handler)(void *c, upb_status *status);
typedef upb_flow_t (upb_value_handler)(void *c, upb_value fval, upb_value val);
typedef upb_sflow_t (upb_startfield_handler)(void *closure, upb_value fval);
typedef upb_flow_t (upb_endfield_handler)(void *closure, upb_value fval);
// No-op implementations of all of the above handlers. Use these instead of
// rolling your own -- the JIT can recognize these and optimize away the call.
upb_flow_t upb_startmsg_nop(void *closure);
void upb_endmsg_nop(void *closure, upb_status *status);
upb_flow_t upb_value_nop(void *closure, upb_value fval, upb_value val);
upb_sflow_t upb_startfield_nop(void *closure, upb_value fval);
upb_flow_t upb_endfield_nop(void *closure, upb_value fval);
// Structure definitions. Do not access any fields directly! Accessors are
// provided for the fields that may be get/set.
typedef struct _upb_mhandlers {
upb_startmsg_handler *startmsg;
upb_endmsg_handler *endmsg;
upb_inttable fieldtab; // Maps field number -> upb_fhandlers.
uint32_t jit_startmsg_pclabel;
uint32_t jit_endofbuf_pclabel;
uint32_t jit_endofmsg_pclabel;
uint32_t jit_unknownfield_pclabel;
bool is_group;
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;
} upb_mhandlers;
/* upb_fhandlers **************************************************************/
// A upb_fhandlers object represents the set of handlers associated with one
// specific message field.
struct _upb_decoder;
struct _upb_mhandlers;
typedef struct _upb_fieldent {
bool junk;
upb_fieldtype_t type;
bool repeated;
bool is_repeated_primitive;
upb_atomic_t refcount;
uint32_t number;
upb_mhandlers *msg;
upb_mhandlers *submsg; // Must be set iff upb_issubmsgtype(type) == true.
struct _upb_mhandlers *msg;
struct _upb_mhandlers *submsg; // Set iff upb_issubmsgtype(type) == true.
upb_value fval;
upb_value_handler *value;
upb_startfield_handler *startsubmsg;
@ -161,34 +154,50 @@ typedef struct _upb_fieldent {
void (*decode)(struct _upb_decoder *d, struct _upb_fieldent *f);
} upb_fhandlers;
struct _upb_handlers {
// Array of msgdefs, [0]=toplevel.
upb_mhandlers **msgs;
int msgs_len, msgs_size;
bool should_jit;
};
typedef struct _upb_handlers upb_handlers;
// fhandlers are created as part of a upb_handlers instance, but can be ref'd
// and unref'd to prolong the life of the handlers.
void upb_fhandlers_ref(upb_fhandlers *m);
void upb_fhandlers_unref(upb_fhandlers *m);
void upb_handlers_init(upb_handlers *h);
void upb_handlers_uninit(upb_handlers *h);
// upb_fhandlers accessors
#define UPB_FHANDLERS_ACCESSORS(name, type) \
INLINE void upb_fhandlers_set ## name(upb_fhandlers *f, type v){f->name = v;} \
INLINE type upb_fhandlers_get ## name(upb_fhandlers *f) { return f->name; }
UPB_FHANDLERS_ACCESSORS(fval, upb_value)
UPB_FHANDLERS_ACCESSORS(value, upb_value_handler*)
UPB_FHANDLERS_ACCESSORS(startsubmsg, upb_startfield_handler*)
UPB_FHANDLERS_ACCESSORS(endsubmsg, upb_endfield_handler*)
UPB_FHANDLERS_ACCESSORS(startseq, upb_startfield_handler*)
UPB_FHANDLERS_ACCESSORS(endseq, upb_endfield_handler*)
UPB_FHANDLERS_ACCESSORS(submsg, struct _upb_mhandlers*)
// The startsubmsg handler needs to also pass a closure to the submsg.
struct _upb_sflow {
upb_flow_t flow;
void *closure;
};
INLINE upb_sflow_t UPB_SFLOW(upb_flow_t flow, void *closure) {
upb_sflow_t ret = {flow, closure};
return ret;
}
#define UPB_CONTINUE_WITH(c) UPB_SFLOW(UPB_CONTINUE, c)
#define UPB_SBREAK UPB_SFLOW(UPB_BREAK, NULL)
// Appends a new message to the graph of handlers and returns it. This message
// can be obtained later at index upb_handlers_msgcount()-1. All handlers will
// be initialized to no-op handlers.
upb_mhandlers *upb_handlers_newmhandlers(upb_handlers *h);
upb_mhandlers *upb_handlers_getmhandlers(upb_handlers *h, int index);
/* upb_mhandlers **************************************************************/
// A upb_mhandlers object represents the set of handlers associated with a
// message in the graph of messages.
typedef struct _upb_mhandlers {
upb_atomic_t refcount;
upb_startmsg_handler *startmsg;
upb_endmsg_handler *endmsg;
upb_inttable fieldtab; // Maps field number -> upb_fhandlers.
uint32_t jit_startmsg_pclabel;
uint32_t jit_endofbuf_pclabel;
uint32_t jit_endofmsg_pclabel;
uint32_t jit_unknownfield_pclabel;
bool is_group;
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;
} upb_mhandlers;
// mhandlers are created as part of a upb_handlers instance, but can be ref'd
// and unref'd to prolong the life of the handlers.
void upb_mhandlers_ref(upb_mhandlers *m);
void upb_mhandlers_unref(upb_mhandlers *m);
// Creates a new field with the given name and number. There must not be an
// existing field with either this name or number or abort() will be called.
@ -209,17 +218,26 @@ upb_fhandlers *upb_mhandlers_newfhandlers_subm(upb_mhandlers *m, uint32_t n,
UPB_MHANDLERS_ACCESSORS(startmsg, upb_startmsg_handler*);
UPB_MHANDLERS_ACCESSORS(endmsg, upb_endmsg_handler*);
// upb_fhandlers accessors
#define UPB_FHANDLERS_ACCESSORS(name, type) \
INLINE void upb_fhandlers_set ## name(upb_fhandlers *f, type v){f->name = v;} \
INLINE type upb_fhandlers_get ## name(upb_fhandlers *f) { return f->name; }
UPB_FHANDLERS_ACCESSORS(fval, upb_value)
UPB_FHANDLERS_ACCESSORS(value, upb_value_handler*)
UPB_FHANDLERS_ACCESSORS(startsubmsg, upb_startfield_handler*)
UPB_FHANDLERS_ACCESSORS(endsubmsg, upb_endfield_handler*)
UPB_FHANDLERS_ACCESSORS(startseq, upb_startfield_handler*)
UPB_FHANDLERS_ACCESSORS(endseq, upb_endfield_handler*)
UPB_FHANDLERS_ACCESSORS(submsg, upb_mhandlers*)
/* upb_handlers ***************************************************************/
struct _upb_handlers {
upb_atomic_t refcount;
upb_mhandlers **msgs; // Array of msgdefs, [0]=toplevel.
int msgs_len, msgs_size;
bool should_jit;
};
typedef struct _upb_handlers upb_handlers;
upb_handlers *upb_handlers_new();
void upb_handlers_ref(upb_handlers *h);
void upb_handlers_unref(upb_handlers *h);
// Appends a new message to the graph of handlers and returns it. This message
// can be obtained later at index upb_handlers_msgcount()-1. All handlers will
// be initialized to no-op handlers.
upb_mhandlers *upb_handlers_newmhandlers(upb_handlers *h);
upb_mhandlers *upb_handlers_getmhandlers(upb_handlers *h, int index);
// Convenience function for registering handlers for all messages and
// fields in a msgdef and all its children. For every registered message
@ -338,16 +356,15 @@ void _upb_dispatcher_unwind(upb_dispatcher *d, upb_flow_t flow);
// Dispatch functions -- call the user handler and handle errors.
INLINE void upb_dispatch_value(upb_dispatcher *d, upb_fhandlers *f,
upb_value val) {
upb_flow_t flow = f->value(d->top->closure, f->fval, val);
upb_flow_t flow = UPB_CONTINUE;
if (f->value) flow = f->value(d->top->closure, f->fval, val);
if (flow != UPB_CONTINUE) _upb_dispatcher_unwind(d, flow);
}
void upb_dispatch_startmsg(upb_dispatcher *d);
void upb_dispatch_endmsg(upb_dispatcher *d, upb_status *status);
upb_dispatcher_frame *upb_dispatch_startsubmsg(upb_dispatcher *d,
upb_fhandlers *f);
upb_dispatcher_frame *upb_dispatch_startsubmsg(upb_dispatcher *d, upb_fhandlers *f);
upb_dispatcher_frame *upb_dispatch_endsubmsg(upb_dispatcher *d);
upb_dispatcher_frame *upb_dispatch_startseq(upb_dispatcher *d,
upb_fhandlers *f);
upb_dispatcher_frame *upb_dispatch_startseq(upb_dispatcher *d, upb_fhandlers *f);
upb_dispatcher_frame *upb_dispatch_endseq(upb_dispatcher *d);
#ifdef __cplusplus

@ -38,7 +38,7 @@ static void upb_elem_free(upb_value v, upb_fielddef *f) {
static void upb_elem_unref(upb_value v, upb_fielddef *f) {
assert(upb_elem_ismm(f));
upb_atomic_refcount_t *refcount = upb_value_getrefcount(v);
upb_atomic_t *refcount = upb_value_getrefcount(v);
if (refcount && upb_atomic_unref(refcount))
upb_elem_free(v, f);
}
@ -53,7 +53,7 @@ static void upb_field_free(upb_value v, upb_fielddef *f) {
static void upb_field_unref(upb_value v, upb_fielddef *f) {
assert(upb_field_ismm(f));
upb_atomic_refcount_t *refcount = upb_value_getrefcount(v);
upb_atomic_t *refcount = upb_value_getrefcount(v);
if (refcount && upb_atomic_unref(refcount))
upb_field_free(v, f);
}
@ -63,7 +63,7 @@ static void upb_field_unref(upb_value v, upb_fielddef *f) {
upb_array *upb_array_new(void) {
upb_array *arr = malloc(sizeof(*arr));
upb_atomic_refcount_init(&arr->refcount, 1);
upb_atomic_init(&arr->refcount, 1);
arr->size = 0;
arr->len = 0;
arr->ptr = NULL;
@ -134,7 +134,7 @@ upb_msg *upb_msg_new(upb_msgdef *md) {
upb_msg *msg = malloc(md->size);
// Clear all set bits and cached pointers.
memset(msg, 0, md->size);
upb_atomic_refcount_init(&msg->refcount, 1);
upb_atomic_init(&msg->refcount, 1);
return msg;
}
@ -178,7 +178,7 @@ void upb_msg_set(upb_msg *msg, upb_fielddef *f, upb_value val) {
upb_field_unref(oldval, f);
// Ref the new value.
upb_atomic_refcount_t *refcount = upb_value_getrefcount(val);
upb_atomic_t *refcount = upb_value_getrefcount(val);
if (refcount) upb_atomic_ref(refcount);
}
upb_msg_sethas(msg, f);
@ -194,7 +194,7 @@ upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) {
upb_msg *m = upb_msg_new(md);
// Copy all set bits and values, except the refcount.
memcpy(m , upb_value_getmsg(val), md->size);
upb_atomic_refcount_init(&m->refcount, 0); // The msg will take a ref.
upb_atomic_init(&m->refcount, 0); // The msg will take a ref.
upb_value_setmsg(&val, m);
}
upb_msg_set(msg, f, val);

@ -142,7 +142,7 @@ INLINE void upb_value_write(upb_valueptr ptr, upb_value val,
typedef uint32_t upb_arraylen_t;
struct _upb_array {
upb_atomic_refcount_t refcount;
upb_atomic_t refcount;
// "len" and "size" are measured in elements, not bytes.
int32_t len;
int32_t size;
@ -192,7 +192,7 @@ INLINE upb_value upb_array_get(upb_array *arr, upb_fielddef *f,
// 2. you would want the msg to own a ref on its msgdef, but this would require
// an atomic operation for every message create or destroy!
struct _upb_msg {
upb_atomic_refcount_t refcount;
upb_atomic_t refcount;
uint8_t data[4]; // We allocate the appropriate amount per message.
};

@ -35,7 +35,7 @@ upb_string *upb_string_new() {
str->size = 0;
#endif
str->src = NULL;
upb_atomic_refcount_init(&str->refcount, 1);
upb_atomic_init(&str->refcount, 1);
return str;
}

@ -59,7 +59,7 @@ extern "C" {
// the associated functions.
struct _upb_string {
// The string's refcount.
upb_atomic_refcount_t refcount;
upb_atomic_t refcount;
// The pointer to our currently active data. This may be memory we own
// or a pointer into memory we don't own.

@ -38,15 +38,15 @@ static void test_upb_jit() {
upb_string_unref(symname);
ASSERT(def);
upb_handlers h;
upb_handlers_init(&h);
upb_handlers *h = upb_handlers_new();
upb_handlerset hset = {NULL, NULL, &upb_test_onvalue, NULL, NULL, NULL, NULL};
upb_handlers_reghandlerset(&h, upb_downcast_msgdef(def), &hset);
upb_handlers_reghandlerset(h, upb_downcast_msgdef(def), &hset);
upb_decoder d;
upb_decoder_init(&d, &h);
upb_decoder_init(&d, h);
upb_decoder_uninit(&d);
upb_symtab_unref(s);
upb_def_unref(def);
upb_handlers_unref(h);
}
static void test_upb_symtab() {

Loading…
Cancel
Save