diff options
Diffstat (limited to 'upb')
34 files changed, 5038 insertions, 3088 deletions
diff --git a/upb/bytestream.upb.c b/upb/bytestream.upb.c index 4d84ec2..2da5405 100644 --- a/upb/bytestream.upb.c +++ b/upb/bytestream.upb.c @@ -9,14 +9,18 @@ const upb_fielddef upb_bytestream_fields[1]; const upb_enumdef upb_bytestream_enums[0]; const upb_tabent upb_bytestream_strentries[4]; const upb_tabent upb_bytestream_intentries[0]; -const _upb_value upb_bytestream_arrays[3]; +const _upb_value upb_bytestream_arrays[2]; + +#ifdef UPB_DEBUG_REFS +static upb_inttable reftables[4]; +#endif const upb_msgdef upb_bytestream_msgs[1] = { - UPB_MSGDEF_INIT("upb.ByteStream", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &upb_bytestream_arrays[0], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &upb_bytestream_strentries[0]), 5), + UPB_MSGDEF_INIT("upb.ByteStream", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &upb_bytestream_arrays[0], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &upb_bytestream_strentries[0]), 5, &reftables[0], &reftables[1]), }; const upb_fielddef upb_bytestream_fields[1] = { - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "bytes", 1, &upb_bytestream_msgs[0], NULL, 2, UPB_VALUE_INIT_NONE), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "bytes", 1, &upb_bytestream_msgs[0], NULL, 2, {0},&reftables[2], &reftables[3]), }; const upb_enumdef upb_bytestream_enums[0] = { @@ -32,9 +36,17 @@ const upb_tabent upb_bytestream_strentries[4] = { const upb_tabent upb_bytestream_intentries[0] = { }; -const _upb_value upb_bytestream_arrays[3] = { +const _upb_value upb_bytestream_arrays[2] = { UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&upb_bytestream_fields[0]), - UPB_ARRAY_EMPTYENT, }; +#ifdef UPB_DEBUG_REFS +static upb_inttable reftables[4] = { + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), +}; +#endif + diff --git a/upb/bytestream.upb.h b/upb/bytestream.upb.h index 0c6969b..9e18579 100644 --- a/upb/bytestream.upb.h +++ b/upb/bytestream.upb.h @@ -27,8 +27,8 @@ extern const upb_enumdef upb_bytestream_enums[0]; // Selector definitions. #define UPB_BYTESTREAM_BYTES_ENDSTR 4 -#define UPB_BYTESTREAM_BYTES_STRING 2 #define UPB_BYTESTREAM_BYTES_STARTSTR 3 +#define UPB_BYTESTREAM_BYTES_STRING 2 #ifdef __cplusplus }; // extern "C" @@ -88,39 +88,39 @@ bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) { upb_def *upb_def_dup(const upb_def *def, const void *o) { switch (def->type) { case UPB_DEF_MSG: - return upb_upcast(upb_msgdef_dup(upb_downcast_msgdef(def), o)); + return UPB_UPCAST(upb_msgdef_dup(upb_downcast_msgdef(def), o)); case UPB_DEF_FIELD: - return upb_upcast(upb_fielddef_dup(upb_downcast_fielddef(def), o)); + return UPB_UPCAST(upb_fielddef_dup(upb_downcast_fielddef(def), o)); case UPB_DEF_ENUM: - return upb_upcast(upb_enumdef_dup(upb_downcast_enumdef(def), o)); + return UPB_UPCAST(upb_enumdef_dup(upb_downcast_enumdef(def), o)); default: assert(false); return NULL; } } bool upb_def_isfrozen(const upb_def *def) { - return upb_refcounted_isfrozen(upb_upcast(def)); + return upb_refcounted_isfrozen(UPB_UPCAST(def)); } void upb_def_ref(const upb_def *def, const void *owner) { - upb_refcounted_ref(upb_upcast(def), owner); + upb_refcounted_ref(UPB_UPCAST(def), owner); } void upb_def_unref(const upb_def *def, const void *owner) { - upb_refcounted_unref(upb_upcast(def), owner); + upb_refcounted_unref(UPB_UPCAST(def), owner); } void upb_def_donateref(const upb_def *def, const void *from, const void *to) { - upb_refcounted_donateref(upb_upcast(def), from, to); + upb_refcounted_donateref(UPB_UPCAST(def), from, to); } void upb_def_checkref(const upb_def *def, const void *owner) { - upb_refcounted_checkref(upb_upcast(def), owner); + upb_refcounted_checkref(UPB_UPCAST(def), owner); } static bool upb_def_init(upb_def *def, upb_deftype_t type, const struct upb_refcounted_vtbl *vtbl, const void *owner) { - if (!upb_refcounted_init(upb_upcast(def), vtbl, owner)) return false; + if (!upb_refcounted_init(UPB_UPCAST(def), vtbl, owner)) return false; def->type = type; def->fullname = NULL; def->came_from_user = false; @@ -132,7 +132,7 @@ static void upb_def_uninit(upb_def *def) { } static const char *msgdef_name(const upb_msgdef *m) { - const char *name = upb_def_fullname(upb_upcast(m)); + const char *name = upb_def_fullname(UPB_UPCAST(m)); return name ? name : "(anonymous)"; } @@ -191,6 +191,7 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { } } + // Second pass of validation. Also assign selectors, compact tables. for (int i = 0; i < n; i++) { upb_msgdef *m = upb_dyncast_msgdef_mutable(defs[i]); upb_enumdef *e = upb_dyncast_enumdef_mutable(defs[i]); @@ -211,8 +212,11 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { } } + // Def graph contains FieldDefs between each MessageDef, so double the limit. + int maxdepth = UPB_MAX_MESSAGE_DEPTH * 2; + // Validation all passed; freeze the defs. - return upb_refcounted_freeze((upb_refcounted*const*)defs, n, s); + return upb_refcounted_freeze((upb_refcounted * const *)defs, n, s, maxdepth); err: for (int i = 0; i < n; i++) { @@ -235,7 +239,7 @@ static void upb_enumdef_free(upb_refcounted *r) { } upb_strtable_uninit(&e->ntoi); upb_inttable_uninit(&e->iton); - upb_def_uninit(upb_upcast(e)); + upb_def_uninit(UPB_UPCAST(e)); free(e); } @@ -243,7 +247,7 @@ upb_enumdef *upb_enumdef_new(const void *owner) { static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_enumdef_free}; upb_enumdef *e = malloc(sizeof(*e)); if (!e) return NULL; - if (!upb_def_init(upb_upcast(e), UPB_DEF_ENUM, &vtbl, owner)) goto err2; + if (!upb_def_init(UPB_UPCAST(e), UPB_DEF_ENUM, &vtbl, owner)) goto err2; if (!upb_strtable_init(&e->ntoi, UPB_CTYPE_INT32)) goto err2; if (!upb_inttable_init(&e->iton, UPB_CTYPE_CSTR)) goto err1; return e; @@ -271,33 +275,33 @@ upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner) { } bool upb_enumdef_isfrozen(const upb_enumdef *e) { - return upb_def_isfrozen(upb_upcast(e)); + return upb_def_isfrozen(UPB_UPCAST(e)); } void upb_enumdef_ref(const upb_enumdef *e, const void *owner) { - upb_def_ref(upb_upcast(e), owner); + upb_def_ref(UPB_UPCAST(e), owner); } void upb_enumdef_unref(const upb_enumdef *e, const void *owner) { - upb_def_unref(upb_upcast(e), owner); + upb_def_unref(UPB_UPCAST(e), owner); } void upb_enumdef_donateref( const upb_enumdef *e, const void *from, const void *to) { - upb_def_donateref(upb_upcast(e), from, to); + upb_def_donateref(UPB_UPCAST(e), from, to); } void upb_enumdef_checkref(const upb_enumdef *e, const void *owner) { - upb_def_checkref(upb_upcast(e), owner); + upb_def_checkref(UPB_UPCAST(e), owner); } const char *upb_enumdef_fullname(const upb_enumdef *e) { - return upb_def_fullname(upb_upcast(e)); + return upb_def_fullname(UPB_UPCAST(e)); } bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname, upb_status *s) { - return upb_def_setfullname(upb_upcast(e), fullname, s); + return upb_def_setfullname(UPB_UPCAST(e), fullname, s); } bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num, @@ -371,17 +375,17 @@ static void upb_fielddef_init_default(upb_fielddef *f); static void upb_fielddef_uninit_default(upb_fielddef *f) { if (f->type_is_set_ && f->default_is_string) - freestr(upb_value_getptr(f->defaultval)); + freestr(f->defaultval.bytes); } static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_fielddef *f = (const upb_fielddef*)r; if (f->msgdef) { - visit(r, upb_upcast2(f->msgdef), closure); + visit(r, UPB_UPCAST2(f->msgdef), closure); } if (!f->subdef_is_symbolic && f->sub.def) { - visit(r, upb_upcast(f->sub.def), closure); + visit(r, UPB_UPCAST(f->sub.def), closure); } } @@ -390,7 +394,7 @@ static void freefield(upb_refcounted *r) { upb_fielddef_uninit_default(f); if (f->subdef_is_symbolic) free(f->sub.name); - upb_def_uninit(upb_upcast(f)); + upb_def_uninit(UPB_UPCAST(f)); free(f); } @@ -398,7 +402,7 @@ upb_fielddef *upb_fielddef_new(const void *owner) { static const struct upb_refcounted_vtbl vtbl = {visitfield, freefield}; upb_fielddef *f = malloc(sizeof(*f)); if (!f) return NULL; - if (!upb_def_init(upb_upcast(f), UPB_DEF_FIELD, &vtbl, owner)) { + if (!upb_def_init(UPB_UPCAST(f), UPB_DEF_FIELD, &vtbl, owner)) { free(f); return NULL; } @@ -431,10 +435,10 @@ upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) { upb_fielddef_setnumber(newf, upb_fielddef_number(f), NULL); upb_fielddef_setname(newf, upb_fielddef_name(f), NULL); if (f->default_is_string) { - str_t *s = upb_value_getptr(upb_fielddef_default(f)); + str_t *s = f->defaultval.bytes; upb_fielddef_setdefaultstr(newf, s->str, s->len, NULL); } else { - upb_fielddef_setdefault(newf, upb_fielddef_default(f)); + newf->defaultval = f->defaultval; } const char *srcname; @@ -459,24 +463,24 @@ upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) { } bool upb_fielddef_isfrozen(const upb_fielddef *f) { - return upb_def_isfrozen(upb_upcast(f)); + return upb_def_isfrozen(UPB_UPCAST(f)); } void upb_fielddef_ref(const upb_fielddef *f, const void *owner) { - upb_def_ref(upb_upcast(f), owner); + upb_def_ref(UPB_UPCAST(f), owner); } void upb_fielddef_unref(const upb_fielddef *f, const void *owner) { - upb_def_unref(upb_upcast(f), owner); + upb_def_unref(UPB_UPCAST(f), owner); } void upb_fielddef_donateref( const upb_fielddef *f, const void *from, const void *to) { - upb_def_donateref(upb_upcast(f), from, to); + upb_def_donateref(UPB_UPCAST(f), from, to); } void upb_fielddef_checkref(const upb_fielddef *f, const void *owner) { - upb_def_checkref(upb_upcast(f), owner); + upb_def_checkref(UPB_UPCAST(f), owner); } bool upb_fielddef_typeisset(const upb_fielddef *f) { @@ -505,30 +509,69 @@ uint32_t upb_fielddef_number(const upb_fielddef *f) { } const char *upb_fielddef_name(const upb_fielddef *f) { - return upb_def_fullname(upb_upcast(f)); + return upb_def_fullname(UPB_UPCAST(f)); } -const upb_msgdef *upb_fielddef_msgdef(const upb_fielddef *f) { +const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) { return f->msgdef; } -upb_msgdef *upb_fielddef_msgdef_mutable(upb_fielddef *f) { +upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) { return (upb_msgdef*)f->msgdef; } bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) { - return upb_def_setfullname(upb_upcast(f), name, s); + return upb_def_setfullname(UPB_UPCAST(f), name, s); } -upb_value upb_fielddef_default(const upb_fielddef *f) { - assert(f->type_is_set_); - return f->defaultval; +static void chkdefaulttype(const upb_fielddef *f, upb_fieldtype_t type) { + UPB_UNUSED(f); + UPB_UNUSED(type); + assert(f->type_is_set_ && upb_fielddef_type(f) == type); +} + +int64_t upb_fielddef_defaultint64(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_INT64); + return f->defaultval.sint; +} + +int32_t upb_fielddef_defaultint32(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_INT32); + return f->defaultval.sint; +} + +uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_UINT64); + return f->defaultval.uint; +} + +uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_UINT32); + return f->defaultval.uint; +} + +bool upb_fielddef_defaultbool(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_BOOL); + return f->defaultval.uint; +} + +float upb_fielddef_defaultfloat(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_FLOAT); + return f->defaultval.flt; +} + +double upb_fielddef_defaultdouble(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_DOUBLE); + return f->defaultval.dbl; } const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) { assert(f->type_is_set_); + assert(upb_fielddef_type(f) == UPB_TYPE_STRING || + upb_fielddef_type(f) == UPB_TYPE_BYTES || + upb_fielddef_type(f) == UPB_TYPE_ENUM); if (f->default_is_string) { - str_t *str = upb_value_getptr(f->defaultval); + str_t *str = f->defaultval.bytes; if (len) *len = str->len; return str->str; } @@ -538,20 +581,20 @@ const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) { static void upb_fielddef_init_default(upb_fielddef *f) { f->default_is_string = false; switch (upb_fielddef_type(f)) { - case UPB_TYPE_DOUBLE: upb_value_setdouble(&f->defaultval, 0); break; - case UPB_TYPE_FLOAT: upb_value_setfloat(&f->defaultval, 0); break; - case UPB_TYPE_UINT64: upb_value_setuint64(&f->defaultval, 0); break; - case UPB_TYPE_INT64: upb_value_setint64(&f->defaultval, 0); break; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: upb_value_setint32(&f->defaultval, 0); break; - case UPB_TYPE_UINT32: upb_value_setuint32(&f->defaultval, 0); break; - case UPB_TYPE_BOOL: upb_value_setbool(&f->defaultval, false); break; + case UPB_TYPE_DOUBLE: f->defaultval.dbl = 0; break; + case UPB_TYPE_FLOAT: f->defaultval.flt = 0; break; + case UPB_TYPE_INT32: + case UPB_TYPE_INT64: + case UPB_TYPE_ENUM: f->defaultval.sint = 0; break; + case UPB_TYPE_UINT64: + case UPB_TYPE_UINT32: + case UPB_TYPE_BOOL: f->defaultval.uint = 0; break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: - upb_value_setptr(&f->defaultval, newstr("", 0)); + f->defaultval.bytes = newstr("", 0); f->default_is_string = true; break; - case UPB_TYPE_MESSAGE: upb_value_setptr(&f->defaultval, NULL); break; + case UPB_TYPE_MESSAGE: break; } } @@ -564,6 +607,16 @@ const upb_def *upb_fielddef_subdef(const upb_fielddef *f) { } } +const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) { + const upb_def *def = upb_fielddef_subdef(f); + return def ? upb_dyncast_msgdef(def) : NULL; +} + +const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) { + const upb_def *def = upb_fielddef_subdef(f); + return def ? upb_dyncast_enumdef(def) : NULL; +} + upb_def *upb_fielddef_subdef_mutable(upb_fielddef *f) { return (upb_def*)upb_fielddef_subdef(f); } @@ -715,17 +768,57 @@ bool upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim) { return true; } -void upb_fielddef_setdefault(upb_fielddef *f, upb_value value) { - assert(f->type_is_set_); - assert(!upb_fielddef_isfrozen(f)); - assert(!upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f)); +static bool checksetdefault(upb_fielddef *f, upb_fieldtype_t type) { + if (!f->type_is_set_ || upb_fielddef_isfrozen(f) || + upb_fielddef_type(f) != type) { + assert(false); + return false; + } if (f->default_is_string) { - str_t *s = upb_value_getptr(f->defaultval); + str_t *s = f->defaultval.bytes; assert(s); freestr(s); } - f->defaultval = value; f->default_is_string = false; + return true; +} + +void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t value) { + if (checksetdefault(f, UPB_TYPE_INT64)) + f->defaultval.sint = value; +} + +void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t value) { + if ((upb_fielddef_type(f) == UPB_TYPE_ENUM && + checksetdefault(f, UPB_TYPE_ENUM)) || + checksetdefault(f, UPB_TYPE_INT32)) { + f->defaultval.sint = value; + } +} + +void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t value) { + if (checksetdefault(f, UPB_TYPE_UINT64)) + f->defaultval.uint = value; +} + +void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t value) { + if (checksetdefault(f, UPB_TYPE_UINT32)) + f->defaultval.uint = value; +} + +void upb_fielddef_setdefaultbool(upb_fielddef *f, bool value) { + if (checksetdefault(f, UPB_TYPE_BOOL)) + f->defaultval.uint = value; +} + +void upb_fielddef_setdefaultfloat(upb_fielddef *f, float value) { + if (checksetdefault(f, UPB_TYPE_FLOAT)) + f->defaultval.flt = value; +} + +void upb_fielddef_setdefaultdouble(upb_fielddef *f, double value) { + if (checksetdefault(f, UPB_TYPE_DOUBLE)) + f->defaultval.dbl = value; } bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len, @@ -735,7 +828,7 @@ bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len, return false; if (f->default_is_string) { - str_t *s = upb_value_getptr(f->defaultval); + str_t *s = f->defaultval.bytes; assert(s); freestr(s); } else { @@ -743,7 +836,7 @@ bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len, } str_t *str2 = newstr(str, len); - upb_value_setptr(&f->defaultval, str2); + f->defaultval.bytes = str2; f->default_is_string = true; return true; } @@ -763,20 +856,20 @@ bool upb_fielddef_default_is_symbolic(const upb_fielddef *f) { bool upb_fielddef_resolveenumdefault(upb_fielddef *f, upb_status *s) { if (!upb_fielddef_default_is_symbolic(f)) return true; - str_t *str = upb_value_getptr(f->defaultval); + str_t *str = f->defaultval.bytes; const upb_enumdef *e = upb_downcast_enumdef(upb_fielddef_subdef(f)); assert(str); // Points to either a real default or the empty string. assert(e); if (str->len == 0) { // The "default default" for an enum is the first defined value. - upb_value_setint32(&f->defaultval, e->defaultval); + f->defaultval.sint = e->defaultval; } else { int32_t val = 0; if (!upb_enumdef_ntoi(e, str->str, &val)) { upb_status_seterrf(s, "enum default not found in enum (%s)", str->str); return false; } - upb_value_setint32(&f->defaultval, val); + f->defaultval.sint = val; } f->default_is_string = false; freestr(str); @@ -821,6 +914,16 @@ bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef, return true; } +bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef, + upb_status *s) { + return upb_fielddef_setsubdef(f, UPB_UPCAST(subdef), s); +} + +bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef, + upb_status *s) { + return upb_fielddef_setsubdef(f, UPB_UPCAST(subdef), s); +} + bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, upb_status *s) { assert(!upb_fielddef_isfrozen(f)); @@ -875,7 +978,7 @@ static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit, upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); - visit(r, upb_upcast2(f), closure); + visit(r, UPB_UPCAST2(f), closure); } } @@ -883,7 +986,7 @@ static void freemsg(upb_refcounted *r) { upb_msgdef *m = (upb_msgdef*)r; upb_strtable_uninit(&m->ntof); upb_inttable_uninit(&m->itof); - upb_def_uninit(upb_upcast(m)); + upb_def_uninit(UPB_UPCAST(m)); free(m); } @@ -891,7 +994,7 @@ upb_msgdef *upb_msgdef_new(const void *owner) { static const struct upb_refcounted_vtbl vtbl = {visitmsg, freemsg}; upb_msgdef *m = malloc(sizeof(*m)); if (!m) return NULL; - if (!upb_def_init(upb_upcast(m), UPB_DEF_MSG, &vtbl, owner)) goto err2; + if (!upb_def_init(UPB_UPCAST(m), UPB_DEF_MSG, &vtbl, owner)) goto err2; if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err2; if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err1; return m; @@ -906,8 +1009,8 @@ err2: upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) { upb_msgdef *newm = upb_msgdef_new(owner); if (!newm) return NULL; - bool ok = upb_def_setfullname(upb_upcast(newm), - upb_def_fullname(upb_upcast(m)), NULL); + bool ok = upb_def_setfullname(UPB_UPCAST(newm), + upb_def_fullname(UPB_UPCAST(m)), NULL); UPB_ASSERT_VAR(ok, ok); upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { @@ -921,33 +1024,33 @@ upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) { } bool upb_msgdef_isfrozen(const upb_msgdef *m) { - return upb_def_isfrozen(upb_upcast(m)); + return upb_def_isfrozen(UPB_UPCAST(m)); } void upb_msgdef_ref(const upb_msgdef *m, const void *owner) { - upb_def_ref(upb_upcast(m), owner); + upb_def_ref(UPB_UPCAST(m), owner); } void upb_msgdef_unref(const upb_msgdef *m, const void *owner) { - upb_def_unref(upb_upcast(m), owner); + upb_def_unref(UPB_UPCAST(m), owner); } void upb_msgdef_donateref( const upb_msgdef *m, const void *from, const void *to) { - upb_def_donateref(upb_upcast(m), from, to); + upb_def_donateref(UPB_UPCAST(m), from, to); } void upb_msgdef_checkref(const upb_msgdef *m, const void *owner) { - upb_def_checkref(upb_upcast(m), owner); + upb_def_checkref(UPB_UPCAST(m), owner); } const char *upb_msgdef_fullname(const upb_msgdef *m) { - return upb_def_fullname(upb_upcast(m)); + return upb_def_fullname(UPB_UPCAST(m)); } bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s) { - return upb_def_setfullname(upb_upcast(m), fullname, s); + return upb_def_setfullname(UPB_UPCAST(m), fullname, s); } bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef *const *fields, int n, @@ -1018,8 +1121,8 @@ void upb_msg_begin(upb_msg_iter *iter, const upb_msgdef *m) { void upb_msg_next(upb_msg_iter *iter) { upb_inttable_next(iter); } -bool upb_msg_done(upb_msg_iter *iter) { return upb_inttable_done(iter); } +bool upb_msg_done(const upb_msg_iter *iter) { return upb_inttable_done(iter); } -upb_fielddef *upb_msg_iter_field(upb_msg_iter *iter) { +upb_fielddef *upb_msg_iter_field(const upb_msg_iter *iter) { return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter)); } @@ -22,6 +22,8 @@ #ifndef UPB_DEF_H_ #define UPB_DEF_H_ +#include "upb/refcounted.h" + #ifdef __cplusplus #include <cstring> #include <string> @@ -50,7 +52,18 @@ typedef struct upb_fielddef upb_fielddef; typedef struct upb_msgdef upb_msgdef; #endif -#include "upb/refcounted.h" +// Maximum field number allowed for FieldDefs. This is an inherent limit of the +// protobuf wire format. +#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1) + +// The maximum message depth that the type graph can have. This is a resource +// limit for the C stack since we sometimes need to recursively traverse the +// graph. Cycles are ok; the traversal will stop when it detects a cycle, but +// we must hit the cycle before the maximum depth is reached. +// +// If having a single static limit is too inflexible, we can add another variant +// of Def::Freeze that allows specifying this as a parameter. +#define UPB_MAX_MESSAGE_DEPTH 64 /* upb::Def: base class for defs *********************************************/ @@ -61,9 +74,8 @@ typedef enum { UPB_DEF_MSG, UPB_DEF_FIELD, UPB_DEF_ENUM, - UPB_DEF_SERVICE, // Not yet implemented. - - UPB_DEF_ANY = -1, // Wildcard for upb_symtab_get*() + UPB_DEF_SERVICE, // Not yet implemented. + UPB_DEF_ANY = -1, // Wildcard for upb_symtab_get*() } upb_deftype_t; #ifdef __cplusplus @@ -83,8 +95,8 @@ class upb::Def { bool IsFrozen() const; void Ref(const void* owner) const; void Unref(const void* owner) const; - void DonateRef(const void *from, const void *to) const; - void CheckRef(const void *owner) const; + void DonateRef(const void* from, const void* to) const; + void CheckRef(const void* owner) const; Type def_type() const; @@ -95,8 +107,8 @@ class upb::Def { // not required to have a name; if a def has no name when it is frozen, it // will remain an anonymous def. On failure, returns false and details in "s" // if non-NULL. - bool set_full_name(const char *fullname, upb::Status* s); - bool set_full_name(const std::string& fullname, upb::Status* s); + bool set_full_name(const char* fullname, upb::Status* s); + bool set_full_name(const std::string &fullname, upb::Status* s); // Freezes the given defs; this validates all constraints and marks the defs // as frozen (read-only). "defs" may not contain any fielddefs, but fields @@ -109,8 +121,8 @@ class upb::Def { // // After this operation succeeds, the finalized defs must only be accessed // through a const pointer! - static bool Freeze(Def *const*defs, int n, Status *status); - static bool Freeze(const std::vector<Def*>& defs, Status *status); + static bool Freeze(Def* const* defs, int n, Status* status); + static bool Freeze(const std::vector<Def*>& defs, Status* status); private: UPB_DISALLOW_POD_OPS(Def); @@ -120,7 +132,7 @@ struct upb_def { #endif upb_refcounted base; const char *fullname; - upb_deftype_t type:8; + upb_deftype_t type : 8; // Used as a flag during the def's mutable stage. Must be false unless // it is currently being used by a function on the stack. This allows // us to easily determine which defs were passed into the function's @@ -128,7 +140,8 @@ struct upb_def { bool came_from_user; }; -#define UPB_DEF_INIT(name, type) {UPB_REFCOUNT_INIT, name, type, false} +#define UPB_DEF_INIT(name, type, refs, ref2s) \ + { UPB_REFCOUNT_INIT(refs, ref2s), name, type, false } // Native C API. #ifdef __cplusplus @@ -145,8 +158,8 @@ void upb_def_checkref(const upb_def *def, const void *owner); upb_deftype_t upb_def_type(const upb_def *d); const char *upb_def_fullname(const upb_def *d); -bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s); -bool upb_def_freeze(upb_def *const*defs, int n, upb_status *s); +bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s); +bool upb_def_freeze(upb_def *const *defs, int n, upb_status *s); #ifdef __cplusplus } // extern "C" #endif @@ -164,7 +177,7 @@ typedef enum { UPB_TYPE_STRING = 4, UPB_TYPE_BYTES = 5, UPB_TYPE_MESSAGE = 6, - UPB_TYPE_ENUM = 7, // Enum values are int32. + UPB_TYPE_ENUM = 7, // Enum values are int32. UPB_TYPE_INT32 = 8, UPB_TYPE_UINT32 = 9, UPB_TYPE_INT64 = 10, @@ -234,14 +247,14 @@ class upb::FieldDef { static IntegerFormat ConvertIntegerFormat(int32_t val); // Returns NULL if memory allocation failed. - static FieldDef* New(const void *owner); + static FieldDef* New(const void* owner); // Duplicates the given field, returning NULL if memory allocation failed. // When a fielddef is duplicated, the subdef (if any) is made symbolic if it // wasn't already. If the subdef is set but has no name (which is possible // since msgdefs are not required to have a name) the new fielddef's subdef // will be unset. - FieldDef* Dup(const void *owner) const; + FieldDef* Dup(const void* owner) const; // Though not declared as such in C++, upb::Def is the base of FieldDef and // we can upcast to it. @@ -252,20 +265,22 @@ class upb::FieldDef { bool IsFrozen() const; void Ref(const void* owner) const; void Unref(const void* owner) const; - void DonateRef(const void *from, const void *to) const; - void CheckRef(const void *owner) const; + void DonateRef(const void* from, const void* to) const; + void CheckRef(const void* owner) const; // Functionality from upb::Def. - const char *full_name() const; - bool set_full_name(const char *fullname, upb::Status* s); + const char* full_name() const; + bool set_full_name(const char* fullname, upb::Status* s); bool set_full_name(const std::string& fullname, upb::Status* s); bool type_is_set() const; // Whether set_[descriptor_]type() has been called. Type type() const; // Requires that type_is_set() == true. Label label() const; // Defaults to UPB_LABEL_OPTIONAL. - const char *name() const; // NULL if uninitialized. + const char* name() const; // NULL if uninitialized. uint32_t number() const; // Returns 0 if uninitialized. - const MessageDef* message_def() const; + + // The MessageDef to which this field belongs, or NULL if none. + const MessageDef* containing_type() const; // The field's type according to the enum in descriptor.proto. This is not // the same as UPB_TYPE_*, because it distinguishes between (for example) @@ -291,7 +306,7 @@ class upb::FieldDef { // also. Generally only extensions will want to think of this name as // fully-qualified. bool set_number(uint32_t number, upb::Status* s); - bool set_name(const char *name, upb::Status* s); + bool set_name(const char* name, upb::Status* s); bool set_name(const std::string& name, upb::Status* s); // Convenient field type tests. @@ -315,37 +330,41 @@ class upb::FieldDef { // numbers, empty for strings). The field's type indicates the type of the // returned value, except for enum fields that are still mutable. // - // For enums the default can be set either numerically or symbolically -- the - // upb_fielddef_default_is_symbolic() function below will indicate which it - // is. For string defaults, the value will be a upb_byteregion which is - // invalidated by any other non-const call on this object. Once the fielddef - // is frozen, symbolic enum defaults are resolved, so frozen enum fielddefs - // always have a default of type int32. - Value default_value() const; - - // Returns the NULL-terminated string default value for this field, or NULL - // if the default for this field is not a string. The user may optionally - // pass "len" to retrieve the length of the default also (this would be - // required to get default values with embedded NULLs). - const char *GetDefaultString(size_t* len) const; - - // Sets default value for the field. For numeric types, use - // upb_fielddef_setdefault(), and "value" must match the type of the field. - // For string/bytes types, use upb_fielddef_setdefaultstr(). Enum types may - // use either, since the default may be set either numerically or - // symbolically. + // Requires that the given function matches the field's current type. + int64_t default_int64() const; + int32_t default_int32() const; + uint64_t default_uint64() const; + uint32_t default_uint32() const; + bool default_bool() const; + float default_float() const; + double default_double() const; + + // Returns the default for UPB_TYPE_STRING, UPB_TYPE_BYTES, and UPB_TYPE_ENUM + // fields that haven't yet been resolved, The resulting string is always + // NULL-terminated. If non-NULL, the length will be stored in *len. + const char *default_string(size_t* len) const; + + // Sets default value for the field. The call must exactly match the type + // of the field. Enum fields may use either setint32 or setstring to set + // the default numerically or symbolically, respectively, but symbolic + // defaults must be resolved before finalizing (see ResolveEnumDefault()). // - // NOTE: May only be called for fields whose type has already been set. - // Also, will be reset to default if the field's type is set again. - void set_default_value(Value value); - bool set_default_string(const void *str, size_t len, Status* s); - bool set_default_string(const std::string& str, Status* s); - void set_default_cstr(const char *str, Status* s); + // Changing the type of a field will reset its default. + void set_default_int64(int64_t val); + void set_default_int32(int32_t val); + void set_default_uint64(uint64_t val); + void set_default_uint32(uint32_t val); + void set_default_bool(bool val); + void set_default_float(float val); + void set_default_double(double val); + bool set_default_string(const void *str, size_t len, Status *s); + bool set_default_string(const std::string &str, Status *s); + void set_default_cstr(const char *str, Status *s); // The results of this function are only meaningful for mutable enum fields, // which can have a default specified either as an integer or as a string. - // If this returns true, the default returned from upb_fielddef_default() is - // a string, otherwise it is an integer. + // If this returns true, the default should be retrieved as default_int32(), + // otherwise it should be retrieved with default_string(). bool IsDefaultSymbolic() const; // If this is an enum field with a symbolic default, resolves the default and @@ -370,6 +389,8 @@ class upb::FieldDef { // have a symbolic reference (they must be resolved before the msgdef can be // frozen). const Def* subdef() const; + const EnumDef* enum_subdef() const; + const MessageDef* message_subdef() const; const char* subdef_name() const; // Before a fielddef is frozen, its subdef may be set either directly (with a @@ -383,8 +404,10 @@ class upb::FieldDef { // the given subdef is not of the correct type. The subdef is reset if the // field's type is changed. The subdef can be set to NULL to clear it. bool set_subdef(const Def* subdef, Status* s); + bool set_enum_subdef(const EnumDef* subdef, Status* s); + bool set_message_subdef(const MessageDef* subdef, Status* s); bool set_subdef_name(const char* name, Status* s); - bool set_subdef_name(const std::string& name, Status* s); + bool set_subdef_name(const std::string &name, Status* s); private: UPB_DISALLOW_POD_OPS(FieldDef); @@ -393,11 +416,17 @@ class upb::FieldDef { struct upb_fielddef { #endif upb_def base; - upb_value defaultval; // Only for non-repeated scalars and strings. + union { + int64_t sint; + uint64_t uint; + double dbl; + float flt; + void *bytes; + } defaultval; const upb_msgdef *msgdef; union { const upb_def *def; // If !subdef_is_symbolic. - char *name; // If subdef_is_symbolic. + char *name; // If subdef_is_symbolic. } sub; // The msgdef or enumdef for this field, if upb_hassubdef(f). bool subdef_is_symbolic; bool default_is_string; @@ -410,11 +439,13 @@ struct upb_fielddef { uint32_t selector_base; // Used to index into a upb::Handlers table. }; -#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, \ - msgdef, subdef, selector_base, defaultval) \ - {UPB_DEF_INIT(name, UPB_DEF_FIELD), defaultval, msgdef, {subdef}, \ - false, type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, \ - intfmt, tagdelim, type, label, num, selector_base} +#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, msgdef, \ + subdef, selector_base, defaultval, refs, ref2s) \ + { \ + UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, msgdef, \ + {subdef}, false, type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, \ + true, intfmt, tagdelim, type, label, num, selector_base \ + } // Native C API. #ifdef __cplusplus @@ -427,8 +458,8 @@ upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner); bool upb_fielddef_isfrozen(const upb_fielddef *f); void upb_fielddef_ref(const upb_fielddef *f, const void *owner); void upb_fielddef_unref(const upb_fielddef *f, const void *owner); -void upb_fielddef_donateref( - const upb_fielddef *f, const void *from, const void *to); +void upb_fielddef_donateref(const upb_fielddef *f, const void *from, + const void *to); void upb_fielddef_checkref(const upb_fielddef *f, const void *owner); // From upb_def. @@ -442,19 +473,27 @@ upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f); upb_label_t upb_fielddef_label(const upb_fielddef *f); uint32_t upb_fielddef_number(const upb_fielddef *f); const char *upb_fielddef_name(const upb_fielddef *f); -const upb_msgdef *upb_fielddef_msgdef(const upb_fielddef *f); -upb_msgdef *upb_fielddef_msgdef_mutable(upb_fielddef *f); +const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f); +upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f); upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f); bool upb_fielddef_istagdelim(const upb_fielddef *f); bool upb_fielddef_issubmsg(const upb_fielddef *f); bool upb_fielddef_isstring(const upb_fielddef *f); bool upb_fielddef_isseq(const upb_fielddef *f); bool upb_fielddef_isprimitive(const upb_fielddef *f); -upb_value upb_fielddef_default(const upb_fielddef *f); +int64_t upb_fielddef_defaultint64(const upb_fielddef *f); +int32_t upb_fielddef_defaultint32(const upb_fielddef *f); +uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f); +uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f); +bool upb_fielddef_defaultbool(const upb_fielddef *f); +float upb_fielddef_defaultfloat(const upb_fielddef *f); +double upb_fielddef_defaultdouble(const upb_fielddef *f); const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len); bool upb_fielddef_default_is_symbolic(const upb_fielddef *f); bool upb_fielddef_hassubdef(const upb_fielddef *f); const upb_def *upb_fielddef_subdef(const upb_fielddef *f); +const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f); +const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f); const char *upb_fielddef_subdefname(const upb_fielddef *f); void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type); @@ -464,7 +503,13 @@ bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s); bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s); bool upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt); bool upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim); -void upb_fielddef_setdefault(upb_fielddef *f, upb_value value); +void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t val); +void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t val); +void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t val); +void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t val); +void upb_fielddef_setdefaultbool(upb_fielddef *f, bool val); +void upb_fielddef_setdefaultfloat(upb_fielddef *f, float val); +void upb_fielddef_setdefaultdouble(upb_fielddef *f, double val); bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len, upb_status *s); void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str, @@ -472,6 +517,10 @@ void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str, bool upb_fielddef_resolveenumdefault(upb_fielddef *f, upb_status *s); bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef, upb_status *s); +bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef, + upb_status *s); +bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef, + upb_status *s); bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, upb_status *s); @@ -495,7 +544,7 @@ typedef upb_inttable_iter upb_msg_iter; class upb::MessageDef { public: // Returns NULL if memory allocation failed. - static MessageDef* New(const void *owner); + static MessageDef* New(const void* owner); // Though not declared as such in C++, upb::Def is the base of MessageDef and // we can upcast to it. @@ -506,12 +555,12 @@ class upb::MessageDef { bool IsFrozen() const; void Ref(const void* owner) const; void Unref(const void* owner) const; - void DonateRef(const void *from, const void *to) const; - void CheckRef(const void *owner) const; + void DonateRef(const void* from, const void* to) const; + void CheckRef(const void* owner) const; // Functionality from upb::Def. - const char *full_name() const; - bool set_full_name(const char *fullname, Status* s); + const char* full_name() const; + bool set_full_name(const char* fullname, Status* s); bool set_full_name(const std::string& fullname, Status* s); // The number of fields that belong to the MessageDef. @@ -523,13 +572,13 @@ class upb::MessageDef { // number, and this fielddef may not be part of another message. In error // cases false is returned and the msgdef is unchanged. On success, the // caller donates a ref from ref_donor (if non-NULL). - bool AddField(upb_fielddef *f, const void *ref_donor, Status* s); + bool AddField(FieldDef* f, const void* ref_donor, Status* s); // These return NULL if the field is not found. FieldDef* FindFieldByNumber(uint32_t number); FieldDef* FindFieldByName(const char *name); const FieldDef* FindFieldByNumber(uint32_t number) const; - const FieldDef* FindFieldByName(const char *name) const; + const FieldDef* FindFieldByName(const char* name) const; // Returns a new msgdef that is a copy of the given msgdef (and a copy of all // the fields) but with any references to submessages broken and replaced @@ -539,34 +588,45 @@ class upb::MessageDef { // TODO(haberman): which is more useful, keeping fields resolved or // unresolving them? If there's no obvious answer, Should this functionality // just be moved into symtab.c? - MessageDef* Dup(const void *owner) const; + MessageDef* Dup(const void* owner) const; // Iteration over fields. The order is undefined. - class Iterator { + class iterator : public std::iterator<std::forward_iterator_tag, FieldDef*> { public: - explicit Iterator(MessageDef* md); + iterator(); + iterator(const iterator& other); + explicit iterator(MessageDef* md); - FieldDef* field(); - bool Done(); - void Next(); + void operator++(); + FieldDef* operator*() const; + bool operator!=(const iterator& other) const; + bool operator==(const iterator& other) const; private: upb_msg_iter iter_; }; - // For iterating over the fields of a const MessageDef. - class ConstIterator { + class const_iterator + : public std::iterator<std::forward_iterator_tag, const FieldDef*> { public: - explicit ConstIterator(const MessageDef* md); + const_iterator(); + const_iterator(const const_iterator& other); + explicit const_iterator(const MessageDef* md); - const FieldDef* field(); - bool Done(); - void Next(); + void operator++(); + const FieldDef* operator*() const; + bool operator!=(const const_iterator& other) const; + bool operator==(const const_iterator& other) const; private: upb_msg_iter iter_; }; + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + private: UPB_DISALLOW_POD_OPS(MessageDef); @@ -583,8 +643,8 @@ struct upb_msgdef { // TODO(haberman): proper extension ranges (there can be multiple). }; -#define UPB_MSGDEF_INIT(name, itof, ntof, selector_count) \ - {UPB_DEF_INIT(name, UPB_DEF_MSG), selector_count, itof, ntof} +#define UPB_MSGDEF_INIT(name, itof, ntof, selector_count, refs, ref2s) \ + { UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, itof, ntof } #ifdef __cplusplus extern "C" { @@ -596,8 +656,8 @@ upb_msgdef *upb_msgdef_new(const void *owner); bool upb_msgdef_isfrozen(const upb_msgdef *m); void upb_msgdef_ref(const upb_msgdef *m, const void *owner); void upb_msgdef_unref(const upb_msgdef *m, const void *owner); -void upb_msgdef_donateref( - const upb_msgdef *m, const void *from, const void *to); +void upb_msgdef_donateref(const upb_msgdef *m, const void *from, + const void *to); void upb_msgdef_checkref(const upb_msgdef *m, const void *owner); // From upb_def. @@ -620,10 +680,15 @@ int upb_msgdef_numfields(const upb_msgdef *m); // upb_fielddef *f = upb_msg_iter_field(&i); // // ... // } +// +// For C we don't have separate iterators for const and non-const. +// It is the caller's responsibility to cast the upb_fielddef* to +// const if the upb_msgdef* is const. void upb_msg_begin(upb_msg_iter *iter, const upb_msgdef *m); void upb_msg_next(upb_msg_iter *iter); -bool upb_msg_done(upb_msg_iter *iter); -upb_fielddef *upb_msg_iter_field(upb_msg_iter *iter); +bool upb_msg_done(const upb_msg_iter *iter); +upb_fielddef *upb_msg_iter_field(const upb_msg_iter *iter); +void upb_msg_iter_copy(upb_msg_iter *to, const upb_msg_iter *from); #ifdef __cplusplus } // extern "C #endif @@ -638,7 +703,7 @@ typedef upb_strtable_iter upb_enum_iter; class upb::EnumDef { public: // Returns NULL if memory allocation failed. - static EnumDef* New(const void *owner); + static EnumDef* New(const void* owner); // Though not declared as such in C++, upb::Def is the base of EnumDef and we // can upcast to it. @@ -649,12 +714,12 @@ class upb::EnumDef { bool IsFrozen() const; void Ref(const void* owner) const; void Unref(const void* owner) const; - void DonateRef(const void *from, const void *to) const; - void CheckRef(const void *owner) const; + void DonateRef(const void* from, const void* to) const; + void CheckRef(const void* owner) const; // Functionality from upb::Def. - const char *full_name() const; - bool set_full_name(const char *fullname, Status* s); + const char* full_name() const; + bool set_full_name(const char* fullname, Status* s); bool set_full_name(const std::string& fullname, Status* s); // The value that is used as the default when no field default is specified. @@ -681,7 +746,7 @@ class upb::EnumDef { // Returns a new EnumDef with all the same values. The new EnumDef will be // owned by the given owner. - EnumDef* Dup(const void *owner) const; + EnumDef* Dup(const void* owner) const; // Iteration over name/value pairs. The order is undefined. // Adding an enum val invalidates any iterators. @@ -690,7 +755,7 @@ class upb::EnumDef { explicit Iterator(const EnumDef*); int32_t number(); - const char* name(); + const char *name(); bool Done(); void Next(); @@ -710,8 +775,8 @@ struct upb_enumdef { int32_t defaultval; }; -#define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval) \ - {UPB_DEF_INIT(name, UPB_DEF_ENUM), ntoi, iton, defaultval} +#define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval, refs, ref2s) \ + { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntoi, iton, defaultval } // Native C API. #ifdef __cplusplus @@ -724,8 +789,8 @@ upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner); void upb_enumdef_unref(const upb_enumdef *e, const void *owner); bool upb_enumdef_isfrozen(const upb_enumdef *e); void upb_enumdef_ref(const upb_enumdef *e, const void *owner); -void upb_enumdef_donateref( - const upb_enumdef *m, const void *from, const void *to); +void upb_enumdef_donateref(const upb_enumdef *m, const void *from, + const void *to); void upb_enumdef_checkref(const upb_enumdef *e, const void *owner); // From upb_def. @@ -757,32 +822,68 @@ int32_t upb_enum_iter_number(upb_enum_iter *iter); /* upb_def casts **************************************************************/ +#ifdef __cplusplus + +#define UPB_CPP_CASTS(cname, cpptype) \ + namespace upb { \ + template <> \ + inline cpptype *down_cast<cpptype*, Def>(Def *def) { \ + return upb_downcast_##cname##_mutable(def); \ + } \ + template <> \ + inline cpptype *dyn_cast<cpptype*, Def>(Def *def) { \ + return upb_dyncast_##cname##_mutable(def); \ + } \ + template <> \ + inline const cpptype *down_cast<const cpptype*, const Def>(const Def *def) { \ + return upb_downcast_##cname(def); \ + } \ + template <> \ + inline const cpptype *dyn_cast<const cpptype*, const Def>(const Def *def) { \ + return upb_dyncast_##cname(def); \ + } \ + template <> \ + inline const cpptype *down_cast<const cpptype*, Def>(Def *def) { \ + return upb_downcast_##cname(def); \ + } \ + template <> \ + inline const cpptype *dyn_cast<const cpptype*, Def>(Def *def) { \ + return upb_dyncast_##cname(def); \ + } \ + } // namespace upb + +#else +#define UPB_CPP_CASTS(cname, cpptype) +#endif + // Dynamic casts, for determining if a def is of a particular type at runtime. // Downcasts, for when some wants to assert that a def is of a particular type. // These are only checked if we are building debug. -#define UPB_DEF_CASTS(lower, upper) \ - UPB_INLINE const upb_ ## lower *upb_dyncast_ ## lower(const upb_def *def) { \ - if (upb_def_type(def) != UPB_DEF_ ## upper) return NULL; \ - return (upb_ ## lower*)def; \ - } \ - UPB_INLINE const upb_ ## lower *upb_downcast_ ## lower(const upb_def *def) { \ - assert(upb_def_type(def) == UPB_DEF_ ## upper); \ - return (const upb_ ## lower*)def; \ - } \ - UPB_INLINE upb_ ## lower *upb_dyncast_ ## lower ## _mutable(upb_def *def) { \ - return (upb_ ## lower*)upb_dyncast_ ## lower(def); \ - } \ - UPB_INLINE upb_ ## lower *upb_downcast_ ## lower ## _mutable(upb_def *def) { \ - return (upb_ ## lower*)upb_downcast_ ## lower(def); \ - } -UPB_DEF_CASTS(msgdef, MSG); -UPB_DEF_CASTS(fielddef, FIELD); -UPB_DEF_CASTS(enumdef, ENUM); +#define UPB_DEF_CASTS(lower, upper, cpptype) \ + UPB_INLINE const upb_##lower *upb_dyncast_##lower(const upb_def *def) { \ + if (upb_def_type(def) != UPB_DEF_##upper) return NULL; \ + return (upb_##lower *)def; \ + } \ + UPB_INLINE const upb_##lower *upb_downcast_##lower(const upb_def *def) { \ + assert(upb_def_type(def) == UPB_DEF_##upper); \ + return (const upb_##lower *)def; \ + } \ + UPB_INLINE upb_##lower *upb_dyncast_##lower##_mutable(upb_def *def) { \ + return (upb_##lower *)upb_dyncast_##lower(def); \ + } \ + UPB_INLINE upb_##lower *upb_downcast_##lower##_mutable(upb_def *def) { \ + return (upb_##lower *)upb_downcast_##lower(def); \ + } \ + UPB_CPP_CASTS(lower, cpptype) + +UPB_DEF_CASTS(msgdef, MSG, MessageDef); +UPB_DEF_CASTS(fielddef, FIELD, FieldDef); +UPB_DEF_CASTS(enumdef, ENUM, EnumDef); #undef UPB_DEF_CASTS #ifdef __cplusplus -UPB_INLINE const char *upb_safecstr(const std::string& str) { +UPB_INLINE const char* upb_safecstr(const std::string& str) { assert(str.size() == std::strlen(str.c_str())); return str.c_str(); } @@ -790,50 +891,35 @@ UPB_INLINE const char *upb_safecstr(const std::string& str) { // Inline C++ wrappers. namespace upb { -inline Def* Def::Dup(const void *owner) const { +inline Def* Def::Dup(const void* owner) const { return upb_def_dup(this, owner); } -inline RefCounted* Def::Upcast() { - return upb_upcast(this); -} -inline const RefCounted* Def::Upcast() const { - return upb_upcast(this); -} -inline bool Def::IsFrozen() const { - return upb_def_isfrozen(this); -} -inline void Def::Ref(const void* owner) const { - upb_def_ref(this, owner); -} -inline void Def::Unref(const void* owner) const { - upb_def_unref(this, owner); -} -inline void Def::DonateRef(const void *from, const void *to) const { +inline RefCounted* Def::Upcast() { return UPB_UPCAST(this); } +inline const RefCounted* Def::Upcast() const { return UPB_UPCAST(this); } +inline bool Def::IsFrozen() const { return upb_def_isfrozen(this); } +inline void Def::Ref(const void* owner) const { upb_def_ref(this, owner); } +inline void Def::Unref(const void* owner) const { upb_def_unref(this, owner); } +inline void Def::DonateRef(const void* from, const void* to) const { upb_def_donateref(this, from, to); } -inline void Def::CheckRef(const void *owner) const { +inline void Def::CheckRef(const void* owner) const { upb_def_checkref(this, owner); } -inline Def::Type Def::def_type() const { - return upb_def_type(this); -} -inline const char *Def::full_name() const { - return upb_def_fullname(this); -} -inline bool Def::set_full_name(const char *fullname, Status* s) { +inline Def::Type Def::def_type() const { return upb_def_type(this); } +inline const char* Def::full_name() const { return upb_def_fullname(this); } +inline bool Def::set_full_name(const char* fullname, Status* s) { return upb_def_setfullname(this, fullname, s); } inline bool Def::set_full_name(const std::string& fullname, Status* s) { return upb_def_setfullname(this, upb_safecstr(fullname), s); } -inline bool Def::Freeze(Def *const*defs, int n, Status *status) { +inline bool Def::Freeze(Def* const* defs, int n, Status* status) { return upb_def_freeze(defs, n, status); } -inline bool Def::Freeze(const std::vector<Def*>& defs, Status *status) { - return upb_def_freeze((Def*const*)&defs[0], defs.size(), status); +inline bool Def::Freeze(const std::vector<Def*>& defs, Status* status) { + return upb_def_freeze((Def* const*)&defs[0], defs.size(), status); } - inline bool FieldDef::CheckType(int32_t val) { return upb_fielddef_checktype(val); } @@ -863,62 +949,50 @@ inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) { return static_cast<FieldDef::IntegerFormat>(val); } -inline FieldDef* FieldDef::New(const void *owner) { +inline FieldDef* FieldDef::New(const void* owner) { return upb_fielddef_new(owner); } -inline FieldDef* FieldDef::Dup(const void *owner) const { +inline FieldDef* FieldDef::Dup(const void* owner) const { return upb_fielddef_dup(this, owner); } -inline Def* FieldDef::Upcast() { - return upb_upcast(this); -} -inline const Def* FieldDef::Upcast() const { - return upb_upcast(this); -} -inline bool FieldDef::IsFrozen() const { - return upb_fielddef_isfrozen(this); -} +inline Def* FieldDef::Upcast() { return UPB_UPCAST(this); } +inline const Def* FieldDef::Upcast() const { return UPB_UPCAST(this); } +inline bool FieldDef::IsFrozen() const { return upb_fielddef_isfrozen(this); } inline void FieldDef::Ref(const void* owner) const { upb_fielddef_ref(this, owner); } inline void FieldDef::Unref(const void* owner) const { upb_fielddef_unref(this, owner); } -inline void FieldDef::DonateRef(const void *from, const void *to) const { +inline void FieldDef::DonateRef(const void* from, const void* to) const { upb_fielddef_donateref(this, from, to); } -inline void FieldDef::CheckRef(const void *owner) const { +inline void FieldDef::CheckRef(const void* owner) const { upb_fielddef_checkref(this, owner); } -inline const char *FieldDef::full_name() const { +inline const char* FieldDef::full_name() const { return upb_fielddef_fullname(this); } -inline bool FieldDef::set_full_name(const char *fullname, Status* s) { +inline bool FieldDef::set_full_name(const char* fullname, Status* s) { return upb_fielddef_setfullname(this, fullname, s); } -inline bool FieldDef::set_full_name(const std::string &fullname, Status *s) { +inline bool FieldDef::set_full_name(const std::string& fullname, Status* s) { return upb_fielddef_setfullname(this, upb_safecstr(fullname), s); } inline bool FieldDef::type_is_set() const { return upb_fielddef_typeisset(this); } -inline FieldDef::Type FieldDef::type() const { - return upb_fielddef_type(this); -} +inline FieldDef::Type FieldDef::type() const { return upb_fielddef_type(this); } inline FieldDef::DescriptorType FieldDef::descriptor_type() const { return upb_fielddef_descriptortype(this); } inline FieldDef::Label FieldDef::label() const { return upb_fielddef_label(this); } -inline uint32_t FieldDef::number() const { - return upb_fielddef_number(this); -} -inline const char *FieldDef::name() const { - return upb_fielddef_name(this); -} -inline const MessageDef* FieldDef::message_def() const { - return upb_fielddef_msgdef(this); +inline uint32_t FieldDef::number() const { return upb_fielddef_number(this); } +inline const char* FieldDef::name() const { return upb_fielddef_name(this); } +inline const MessageDef* FieldDef::containing_type() const { + return upb_fielddef_containingtype(this); } inline bool FieldDef::set_number(uint32_t number, Status* s) { return upb_fielddef_setnumber(this, number, s); @@ -941,20 +1015,52 @@ inline void FieldDef::set_label(upb_label_t label) { inline bool FieldDef::IsSubMessage() const { return upb_fielddef_issubmsg(this); } -inline bool FieldDef::IsString() const { - return upb_fielddef_isstring(this); +inline bool FieldDef::IsString() const { return upb_fielddef_isstring(this); } +inline bool FieldDef::IsSequence() const { return upb_fielddef_isseq(this); } +inline int64_t FieldDef::default_int64() const { + return upb_fielddef_defaultint64(this); +} +inline int32_t FieldDef::default_int32() const { + return upb_fielddef_defaultint32(this); +} +inline uint64_t FieldDef::default_uint64() const { + return upb_fielddef_defaultuint64(this); +} +inline uint32_t FieldDef::default_uint32() const { + return upb_fielddef_defaultuint32(this); +} +inline bool FieldDef::default_bool() const { + return upb_fielddef_defaultbool(this); } -inline bool FieldDef::IsSequence() const { - return upb_fielddef_isseq(this); +inline float FieldDef::default_float() const { + return upb_fielddef_defaultfloat(this); } -inline Value FieldDef::default_value() const { - return upb_fielddef_default(this); +inline double FieldDef::default_double() const { + return upb_fielddef_defaultdouble(this); } -inline const char *FieldDef::GetDefaultString(size_t* len) const { +inline const char* FieldDef::default_string(size_t* len) const { return upb_fielddef_defaultstr(this, len); } -inline void FieldDef::set_default_value(Value value) { - upb_fielddef_setdefault(this, value); +inline void FieldDef::set_default_int64(int64_t value) { + upb_fielddef_setdefaultint64(this, value); +} +inline void FieldDef::set_default_int32(int32_t value) { + upb_fielddef_setdefaultint32(this, value); +} +inline void FieldDef::set_default_uint64(uint64_t value) { + upb_fielddef_setdefaultuint64(this, value); +} +inline void FieldDef::set_default_uint32(uint32_t value) { + upb_fielddef_setdefaultuint32(this, value); +} +inline void FieldDef::set_default_bool(bool value) { + upb_fielddef_setdefaultbool(this, value); +} +inline void FieldDef::set_default_float(float value) { + upb_fielddef_setdefaultfloat(this, value); +} +inline void FieldDef::set_default_double(double value) { + upb_fielddef_setdefaultdouble(this, value); } inline bool FieldDef::set_default_string(const void *str, size_t len, Status *s) { @@ -963,7 +1069,7 @@ inline bool FieldDef::set_default_string(const void *str, size_t len, inline bool FieldDef::set_default_string(const std::string& str, Status* s) { return upb_fielddef_setdefaultstr(this, str.c_str(), str.size(), s); } -inline void FieldDef::set_default_cstr(const char *str, Status* s) { +inline void FieldDef::set_default_cstr(const char* str, Status* s) { return upb_fielddef_setdefaultcstr(this, str, s); } inline bool FieldDef::IsDefaultSymbolic() const { @@ -972,11 +1078,13 @@ inline bool FieldDef::IsDefaultSymbolic() const { inline bool FieldDef::ResolveEnumDefault(Status* s) { return upb_fielddef_resolveenumdefault(this, s); } -inline bool FieldDef::HasSubDef() const { - return upb_fielddef_hassubdef(this); +inline bool FieldDef::HasSubDef() const { return upb_fielddef_hassubdef(this); } +inline const Def* FieldDef::subdef() const { return upb_fielddef_subdef(this); } +inline const MessageDef *FieldDef::message_subdef() const { + return upb_fielddef_msgsubdef(this); } -inline const Def* FieldDef::subdef() const { - return upb_fielddef_subdef(this); +inline const EnumDef *FieldDef::enum_subdef() const { + return upb_fielddef_enumsubdef(this); } inline const char* FieldDef::subdef_name() const { return upb_fielddef_subdefname(this); @@ -984,6 +1092,12 @@ inline const char* FieldDef::subdef_name() const { inline bool FieldDef::set_subdef(const Def* subdef, Status* s) { return upb_fielddef_setsubdef(this, subdef, s); } +inline bool FieldDef::set_enum_subdef(const EnumDef* subdef, Status* s) { + return upb_fielddef_setenumsubdef(this, subdef, s); +} +inline bool FieldDef::set_message_subdef(const MessageDef* subdef, Status* s) { + return upb_fielddef_setmsgsubdef(this, subdef, s); +} inline bool FieldDef::set_subdef_name(const char* name, Status* s) { return upb_fielddef_setsubdefname(this, name, s); } @@ -991,34 +1105,28 @@ inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) { return upb_fielddef_setsubdefname(this, upb_safecstr(name), s); } -inline MessageDef* MessageDef::New(const void *owner) { +inline MessageDef* MessageDef::New(const void* owner) { return upb_msgdef_new(owner); } -inline Def* MessageDef::Upcast() { - return upb_upcast(this); -} -inline const Def* MessageDef::Upcast() const { - return upb_upcast(this); -} -inline bool MessageDef::IsFrozen() const { - return upb_msgdef_isfrozen(this); -} +inline Def* MessageDef::Upcast() { return UPB_UPCAST(this); } +inline const Def* MessageDef::Upcast() const { return UPB_UPCAST(this); } +inline bool MessageDef::IsFrozen() const { return upb_msgdef_isfrozen(this); } inline void MessageDef::Ref(const void* owner) const { return upb_msgdef_ref(this, owner); } inline void MessageDef::Unref(const void* owner) const { return upb_msgdef_unref(this, owner); } -inline void MessageDef::DonateRef(const void *from, const void *to) const { +inline void MessageDef::DonateRef(const void* from, const void* to) const { return upb_msgdef_donateref(this, from, to); } -inline void MessageDef::CheckRef(const void *owner) const { +inline void MessageDef::CheckRef(const void* owner) const { return upb_msgdef_checkref(this, owner); } inline const char *MessageDef::full_name() const { return upb_msgdef_fullname(this); } -inline bool MessageDef::set_full_name(const char *fullname, Status *s) { +inline bool MessageDef::set_full_name(const char* fullname, Status* s) { return upb_msgdef_setfullname(this, fullname, s); } inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) { @@ -1027,80 +1135,94 @@ inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) { inline int MessageDef::field_count() const { return upb_msgdef_numfields(this); } -inline bool MessageDef::AddField(upb_fielddef *f, const void *ref_donor, - Status *s) { +inline bool MessageDef::AddField(upb_fielddef* f, const void* ref_donor, + Status* s) { return upb_msgdef_addfield(this, f, ref_donor, s); } inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) { return upb_msgdef_itof_mutable(this, number); } -inline FieldDef* MessageDef::FindFieldByName(const char *name) { +inline FieldDef* MessageDef::FindFieldByName(const char* name) { return upb_msgdef_ntof_mutable(this, name); } inline const FieldDef* MessageDef::FindFieldByNumber(uint32_t number) const { return upb_msgdef_itof(this, number); } -inline const FieldDef* MessageDef::FindFieldByName(const char *name) const { +inline const FieldDef* MessageDef::FindFieldByName(const char* name) const { return upb_msgdef_ntof(this, name); } inline MessageDef* MessageDef::Dup(const void *owner) const { return upb_msgdef_dup(this, owner); } +inline MessageDef::iterator MessageDef::begin() { return iterator(this); } +inline MessageDef::iterator MessageDef::end() { return iterator(); } +inline MessageDef::const_iterator MessageDef::begin() const { + return const_iterator(this); +} +inline MessageDef::const_iterator MessageDef::end() const { + return const_iterator(); +} -inline MessageDef::Iterator::Iterator(MessageDef* md) { +inline MessageDef::iterator::iterator() { + upb_inttable_iter_setdone(&iter_); +} +inline MessageDef::iterator::iterator(MessageDef* md) { upb_msg_begin(&iter_, md); } -inline FieldDef* MessageDef::Iterator::field() { +inline FieldDef* MessageDef::iterator::operator*() const { return upb_msg_iter_field(&iter_); } -inline bool MessageDef::Iterator::Done() { - return upb_msg_done(&iter_); +inline void MessageDef::iterator::operator++() { return upb_msg_next(&iter_); } +inline bool MessageDef::iterator::operator==(const iterator &other) const { + return upb_inttable_iter_isequal(&iter_, &other.iter_); } -inline void MessageDef::Iterator::Next() { - return upb_msg_next(&iter_); +inline bool MessageDef::iterator::operator!=(const iterator &other) const { + return !(*this == other); } -inline MessageDef::ConstIterator::ConstIterator(const MessageDef* md) { +inline MessageDef::const_iterator::const_iterator() { + upb_inttable_iter_setdone(&iter_); +} +inline MessageDef::const_iterator::const_iterator(const MessageDef* md) { upb_msg_begin(&iter_, md); } -inline const FieldDef* MessageDef::ConstIterator::field() { +inline const FieldDef* MessageDef::const_iterator::operator*() const { return upb_msg_iter_field(&iter_); } -inline bool MessageDef::ConstIterator::Done() { - return upb_msg_done(&iter_); -} -inline void MessageDef::ConstIterator::Next() { +inline void MessageDef::const_iterator::operator++() { return upb_msg_next(&iter_); } +inline bool MessageDef::const_iterator::operator==( + const const_iterator &other) const { + return upb_inttable_iter_isequal(&iter_, &other.iter_); +} +inline bool MessageDef::const_iterator::operator!=( + const const_iterator &other) const { + return !(*this == other); +} inline EnumDef* EnumDef::New(const void *owner) { return upb_enumdef_new(owner); } -inline Def* EnumDef::Upcast() { - return upb_upcast(this); -} -inline const Def* EnumDef::Upcast() const { - return upb_upcast(this); -} -inline bool EnumDef::IsFrozen() const { - return upb_enumdef_isfrozen(this); -} +inline Def* EnumDef::Upcast() { return UPB_UPCAST(this); } +inline const Def* EnumDef::Upcast() const { return UPB_UPCAST(this); } +inline bool EnumDef::IsFrozen() const { return upb_enumdef_isfrozen(this); } inline void EnumDef::Ref(const void* owner) const { return upb_enumdef_ref(this, owner); } inline void EnumDef::Unref(const void* owner) const { return upb_enumdef_unref(this, owner); } -inline void EnumDef::DonateRef(const void *from, const void *to) const { +inline void EnumDef::DonateRef(const void* from, const void* to) const { return upb_enumdef_donateref(this, from, to); } -inline void EnumDef::CheckRef(const void *owner) const { +inline void EnumDef::CheckRef(const void* owner) const { return upb_enumdef_checkref(this, owner); } -inline const char *EnumDef::full_name() const { +inline const char* EnumDef::full_name() const { return upb_enumdef_fullname(this); } -inline bool EnumDef::set_full_name(const char *fullname, Status* s) { +inline bool EnumDef::set_full_name(const char* fullname, Status* s) { return upb_enumdef_setfullname(this, fullname, s); } inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) { @@ -1112,23 +1234,21 @@ inline int32_t EnumDef::default_value() const { inline void EnumDef::set_default_value(int32_t val) { upb_enumdef_setdefault(this, val); } -inline int EnumDef::value_count() const { - return upb_enumdef_numvals(this); -} +inline int EnumDef::value_count() const { return upb_enumdef_numvals(this); } inline bool EnumDef::AddValue(const char* name, int32_t num, Status* status) { return upb_enumdef_addval(this, name, num, status); } -inline bool EnumDef::AddValue( - const std::string& name, int32_t num, Status* status) { +inline bool EnumDef::AddValue(const std::string& name, int32_t num, + Status* status) { return upb_enumdef_addval(this, upb_safecstr(name), num, status); } -inline bool EnumDef::FindValueByName(const char* name, int32_t* num) const { +inline bool EnumDef::FindValueByName(const char* name, int32_t *num) const { return upb_enumdef_ntoi(this, name, num); } inline const char* EnumDef::FindValueByNumber(int32_t num) const { return upb_enumdef_iton(this, num); } -inline EnumDef* EnumDef::Dup(const void *owner) const { +inline EnumDef* EnumDef::Dup(const void* owner) const { return upb_enumdef_dup(this, owner); } @@ -1141,13 +1261,9 @@ inline int32_t EnumDef::Iterator::number() { inline const char* EnumDef::Iterator::name() { return upb_enum_iter_name(&iter_); } -inline bool EnumDef::Iterator::Done() { - return upb_enum_done(&iter_); -} -inline void EnumDef::Iterator::Next() { - return upb_enum_next(&iter_); -} +inline bool EnumDef::Iterator::Done() { return upb_enum_done(&iter_); } +inline void EnumDef::Iterator::Next() { return upb_enum_next(&iter_); } } // namespace upb #endif -#endif /* UPB_DEF_H_ */ +#endif /* UPB_DEF_H_ */ diff --git a/upb/descriptor/descriptor.upb.c b/upb/descriptor/descriptor.upb.c index e910d3a..32273ba 100755 --- a/upb/descriptor/descriptor.upb.c +++ b/upb/descriptor/descriptor.upb.c @@ -8,120 +8,124 @@ const upb_msgdef google_protobuf_msgs[20]; const upb_fielddef google_protobuf_fields[73]; const upb_enumdef google_protobuf_enums[4]; const upb_tabent google_protobuf_strentries[192]; -const upb_tabent google_protobuf_intentries[66]; -const _upb_value google_protobuf_arrays[97]; +const upb_tabent google_protobuf_intentries[14]; +const _upb_value google_protobuf_arrays[224]; + +#ifdef UPB_DEBUG_REFS +static upb_inttable reftables[194]; +#endif const upb_msgdef google_protobuf_msgs[20] = { - UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", UPB_INTTABLE_INIT(2, 3, 9, 2, &google_protobuf_intentries[0], &google_protobuf_arrays[0], 6, 5), UPB_STRTABLE_INIT(7, 15, 9, 4, &google_protobuf_strentries[0]), 33), - UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[6], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[16]), 4), - UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[10], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[20]), 13), - UPB_MSGDEF_INIT("google.protobuf.EnumOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[14], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[24]), 7), - UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[15], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[28]), 9), - UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[19], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[32]), 7), - UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", UPB_INTTABLE_INIT(3, 3, 9, 2, &google_protobuf_intentries[8], &google_protobuf_arrays[20], 6, 5), UPB_STRTABLE_INIT(8, 15, 9, 4, &google_protobuf_strentries[36]), 20), - UPB_MSGDEF_INIT("google.protobuf.FieldOptions", UPB_INTTABLE_INIT(2, 3, 9, 2, &google_protobuf_intentries[12], &google_protobuf_arrays[26], 5, 3), UPB_STRTABLE_INIT(5, 7, 9, 3, &google_protobuf_strentries[52]), 13), - UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", UPB_INTTABLE_INIT(4, 7, 9, 3, &google_protobuf_intentries[16], &google_protobuf_arrays[31], 6, 5), UPB_STRTABLE_INIT(9, 15, 9, 4, &google_protobuf_strentries[60]), 39), - UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[37], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[76]), 7), - UPB_MSGDEF_INIT("google.protobuf.FileOptions", UPB_INTTABLE_INIT(8, 15, 9, 4, &google_protobuf_intentries[24], &google_protobuf_arrays[40], 6, 1), UPB_STRTABLE_INIT(9, 15, 9, 4, &google_protobuf_strentries[80]), 19), - UPB_MSGDEF_INIT("google.protobuf.MessageOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[40], &google_protobuf_arrays[46], 4, 2), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[96]), 9), - UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[50], 5, 4), UPB_STRTABLE_INIT(4, 7, 9, 3, &google_protobuf_strentries[100]), 14), - UPB_MSGDEF_INIT("google.protobuf.MethodOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[42], &google_protobuf_arrays[55], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[108]), 7), - UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[56], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[112]), 13), - UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[44], &google_protobuf_arrays[60], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[116]), 7), - UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[61], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[120]), 7), - UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[64], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[124]), 8), - UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", UPB_INTTABLE_INIT(3, 3, 9, 2, &google_protobuf_intentries[46], &google_protobuf_arrays[68], 6, 4), UPB_STRTABLE_INIT(7, 15, 9, 4, &google_protobuf_strentries[128]), 19), - UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[74], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[144]), 6), + UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[0]), 33, &reftables[0], &reftables[1]), + UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[16]), 4, &reftables[2], &reftables[3]), + UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[20]), 13, &reftables[4], &reftables[5]), + UPB_MSGDEF_INIT("google.protobuf.EnumOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[0], &google_protobuf_arrays[15], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[24]), 7, &reftables[6], &reftables[7]), + UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[19], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[28]), 9, &reftables[8], &reftables[9]), + UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[2], &google_protobuf_arrays[23], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[32]), 7, &reftables[10], &reftables[11]), + UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[27], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[36]), 20, &reftables[12], &reftables[13]), + UPB_MSGDEF_INIT("google.protobuf.FieldOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[36], 32, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[52]), 13, &reftables[14], &reftables[15]), + UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[68], 10, 9), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[60]), 39, &reftables[16], &reftables[17]), + UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[78], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[76]), 7, &reftables[18], &reftables[19]), + UPB_MSGDEF_INIT("google.protobuf.FileOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[80], 64, 8), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[80]), 19, &reftables[20], &reftables[21]), + UPB_MSGDEF_INIT("google.protobuf.MessageOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[8], &google_protobuf_arrays[144], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[96]), 9, &reftables[22], &reftables[23]), + UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[160], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[100]), 14, &reftables[24], &reftables[25]), + UPB_MSGDEF_INIT("google.protobuf.MethodOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[10], &google_protobuf_arrays[165], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[108]), 7, &reftables[26], &reftables[27]), + UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[169], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[112]), 13, &reftables[28], &reftables[29]), + UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[12], &google_protobuf_arrays[173], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[116]), 7, &reftables[30], &reftables[31]), + UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[177], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[120]), 7, &reftables[32], &reftables[33]), + UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[179], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[124]), 8, &reftables[34], &reftables[35]), + UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[182], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[128]), 19, &reftables[36], &reftables[37]), + UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[191], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[144]), 6, &reftables[38], &reftables[39]), }; const upb_fielddef google_protobuf_fields[73] = { - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 12, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 5, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], upb_upcast(&google_protobuf_enums[2]), 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 17, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 10, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 4, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 15, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[2]), 17, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[2]), 20, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 5, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 5, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[6]), 36, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[6]), 27, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[1]), 22, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[6]), 7, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], upb_upcast(&google_protobuf_msgs[8]), 4, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 7, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 5, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 8, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 6, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 18, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 14, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_enums[0]), 9, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], upb_upcast(&google_protobuf_msgs[17]), 4, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[0]), 15, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], upb_upcast(&google_protobuf_msgs[12]), 7, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], upb_upcast(&google_protobuf_msgs[19]), 4, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 11, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[0]), 12, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 3, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 5, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 8, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], upb_upcast(&google_protobuf_enums[3]), 17, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], upb_upcast(&google_protobuf_msgs[13]), 11, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], upb_upcast(&google_protobuf_msgs[15]), 10, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[10]), 23, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], upb_upcast(&google_protobuf_msgs[3]), 10, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[11]), 30, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_msgs[7]), 11, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], upb_upcast(&google_protobuf_msgs[5]), 6, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 8, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 5, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 3, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 10, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 7, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[14]), 31, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[16]), 26, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 16, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_enums[1]), 10, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 14, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], upb_upcast(&google_protobuf_msgs[18]), 4, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], upb_upcast(&google_protobuf_msgs[18]), 6, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], upb_upcast(&google_protobuf_msgs[18]), 4, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], upb_upcast(&google_protobuf_msgs[18]), 11, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], upb_upcast(&google_protobuf_msgs[18]), 10, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], upb_upcast(&google_protobuf_msgs[18]), 4, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], upb_upcast(&google_protobuf_msgs[18]), 4, UPB_VALUE_INIT_NONE), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], upb_upcast(&google_protobuf_msgs[4]), 7, UPB_VALUE_INIT_NONE), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 16, {0},&reftables[40], &reftables[41]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 10, {0},&reftables[42], &reftables[43]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 2, {0},&reftables[44], &reftables[45]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 14, {0},&reftables[46], &reftables[47]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 10, {0},&reftables[48], &reftables[49]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 4, {0},&reftables[50], &reftables[51]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 12, {0},&reftables[52], &reftables[53]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, {0},&reftables[54], &reftables[55]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 17, {0},&reftables[56], &reftables[57]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 20, {0},&reftables[58], &reftables[59]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 5, {0},&reftables[60], &reftables[61]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 5, {0},&reftables[62], &reftables[63]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 30, {0},&reftables[64], &reftables[65]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 27, {0},&reftables[66], &reftables[67]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 22, {0},&reftables[68], &reftables[69]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 7, {0},&reftables[70], &reftables[71]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 4, {0},&reftables[72], &reftables[73]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 7, {0},&reftables[74], &reftables[75]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 5, {0},&reftables[76], &reftables[77]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, {0},&reftables[78], &reftables[79]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 13, {0},&reftables[80], &reftables[81]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 11, {0},&reftables[82], &reftables[83]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 9, {0},&reftables[84], &reftables[85]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 5, {0},&reftables[86], &reftables[87]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 2, {0},&reftables[88], &reftables[89]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 9, {0},&reftables[90], &reftables[91]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 4, {0},&reftables[92], &reftables[93]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 2, {0},&reftables[94], &reftables[95]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 15, {0},&reftables[96], &reftables[97]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 7, {0},&reftables[98], &reftables[99]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 4, {0},&reftables[100], &reftables[101]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 2, {0},&reftables[102], &reftables[103]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 2, {0},&reftables[104], &reftables[105]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 2, {0},&reftables[106], &reftables[107]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 2, {0},&reftables[108], &reftables[109]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 2, {0},&reftables[110], &reftables[111]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 2, {0},&reftables[112], &reftables[113]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 2, {0},&reftables[114], &reftables[115]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, {0},&reftables[116], &reftables[117]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 11, {0},&reftables[118], &reftables[119]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 12, {0},&reftables[120], &reftables[121]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 3, {0},&reftables[122], &reftables[123]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 5, {0},&reftables[124], &reftables[125]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 8, {0},&reftables[126], &reftables[127]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 8, {0},&reftables[128], &reftables[129]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 10, {0},&reftables[130], &reftables[131]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 33, {0},&reftables[132], &reftables[133]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 10, {0},&reftables[134], &reftables[135]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 30, {0},&reftables[136], &reftables[137]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 11, {0},&reftables[138], &reftables[139]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 6, {0},&reftables[140], &reftables[141]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 17, {0},&reftables[142], &reftables[143]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 8, {0},&reftables[144], &reftables[145]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 5, {0},&reftables[146], &reftables[147]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 3, {0},&reftables[148], &reftables[149]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, {0},&reftables[150], &reftables[151]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 10, {0},&reftables[152], &reftables[153]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 12, {0},&reftables[154], &reftables[155]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 25, {0},&reftables[156], &reftables[157]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 36, {0},&reftables[158], &reftables[159]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, {0},&reftables[160], &reftables[161]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, {0},&reftables[162], &reftables[163]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 13, {0},&reftables[164], &reftables[165]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 10, {0},&reftables[166], &reftables[167]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 11, {0},&reftables[168], &reftables[169]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[170], &reftables[171]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[172], &reftables[173]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 6, {0},&reftables[174], &reftables[175]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 16, {0},&reftables[176], &reftables[177]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 10, {0},&reftables[178], &reftables[179]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[180], &reftables[181]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[182], &reftables[183]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 7, {0},&reftables[184], &reftables[185]), }; const upb_enumdef google_protobuf_enums[4] = { - UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Label", UPB_STRTABLE_INIT(3, 3, 1, 2, &google_protobuf_strentries[148]), UPB_INTTABLE_INIT(0, 0, 8, 0, NULL, &google_protobuf_arrays[78], 4, 3), 0), - UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Type", UPB_STRTABLE_INIT(18, 31, 1, 5, &google_protobuf_strentries[152]), UPB_INTTABLE_INIT(12, 15, 8, 4, &google_protobuf_intentries[50], &google_protobuf_arrays[82], 7, 6), 0), - UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.CType", UPB_STRTABLE_INIT(3, 3, 1, 2, &google_protobuf_strentries[184]), UPB_INTTABLE_INIT(0, 0, 8, 0, NULL, &google_protobuf_arrays[89], 4, 3), 0), - UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, 1, 2, &google_protobuf_strentries[188]), UPB_INTTABLE_INIT(0, 0, 8, 0, NULL, &google_protobuf_arrays[93], 4, 3), 0), + UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Label", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &google_protobuf_strentries[148]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &google_protobuf_arrays[194], 4, 3), 0, &reftables[186], &reftables[187]), + UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Type", UPB_STRTABLE_INIT(18, 31, UPB_CTYPE_INT32, 5, &google_protobuf_strentries[152]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &google_protobuf_arrays[198], 19, 18), 0, &reftables[188], &reftables[189]), + UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.CType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &google_protobuf_strentries[184]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &google_protobuf_arrays[217], 3, 3), 0, &reftables[190], &reftables[191]), + UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &google_protobuf_strentries[188]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &google_protobuf_arrays[220], 4, 3), 0, &reftables[192], &reftables[193]), }; const upb_tabent google_protobuf_strentries[192] = { {UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[13]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]), NULL}, + {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[37]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, @@ -132,7 +136,7 @@ const upb_tabent google_protobuf_strentries[192] = { {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), NULL}, + {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[48]), NULL}, {UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[8]), &google_protobuf_strentries[14]}, {UPB_TABKEY_STR("start"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[61]), NULL}, {UPB_TABKEY_STR("end"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[7]), NULL}, @@ -140,16 +144,16 @@ const upb_tabent google_protobuf_strentries[192] = { {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_STR("value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[72]), NULL}, - {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[48]), NULL}, - {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[33]), &google_protobuf_strentries[22]}, - {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL}, + {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[45]), NULL}, + {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]), &google_protobuf_strentries[22]}, + {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[42]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[51]), NULL}, - {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[31]), &google_protobuf_strentries[30]}, + {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), NULL}, + {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[35]), &google_protobuf_strentries[30]}, {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[71]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, @@ -169,7 +173,7 @@ const upb_tabent google_protobuf_strentries[192] = { {UPB_TABKEY_STR("extendee"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[11]), NULL}, {UPB_TABKEY_STR("type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[63]), &google_protobuf_strentries[48]}, {UPB_TABKEY_STR("default_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[3]), NULL}, - {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), NULL}, + {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[51]), NULL}, {UPB_TABKEY_STR("experimental_map_key"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[10]), &google_protobuf_strentries[58]}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_STR("ctype"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[2]), NULL}, @@ -181,7 +185,7 @@ const upb_tabent google_protobuf_strentries[192] = { {UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[12]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[37]), NULL}, + {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[31]), NULL}, {UPB_TABKEY_STR("service"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[58]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_STR("source_code_info"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[59]), NULL}, @@ -192,7 +196,7 @@ const upb_tabent google_protobuf_strentries[192] = { {UPB_TABKEY_STR("message_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[28]), NULL}, {UPB_TABKEY_STR("package"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[53]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), NULL}, + {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[46]), NULL}, {UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[9]), &google_protobuf_strentries[74]}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_STR("file"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[16]), NULL}, @@ -216,25 +220,25 @@ const upb_tabent google_protobuf_strentries[192] = { {UPB_TABKEY_STR("java_outer_classname"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[23]), NULL}, {UPB_TABKEY_STR("message_set_wire_format"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[27]), &google_protobuf_strentries[98]}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL}, + {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[67]), NULL}, {UPB_TABKEY_STR("no_standard_descriptor_accessor"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[41]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[30]), NULL}, + {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[33]), NULL}, {UPB_TABKEY_STR("input_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[18]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_STR("output_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[52]), NULL}, - {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[45]), NULL}, - {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[67]), NULL}, + {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), NULL}, + {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[46]), &google_protobuf_strentries[114]}, + {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), &google_protobuf_strentries[114]}, {UPB_TABKEY_STR("method"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[29]), NULL}, {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[32]), &google_protobuf_strentries[113]}, - {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL}, + {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, @@ -249,7 +253,7 @@ const upb_tabent google_protobuf_strentries[192] = { {UPB_TABKEY_STR("double_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[6]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[35]), NULL}, + {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[30]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, @@ -312,95 +316,50 @@ const upb_tabent google_protobuf_strentries[192] = { {UPB_TABKEY_STR("LITE_RUNTIME"), UPB_VALUE_INIT_INT32(3), NULL}, }; -const upb_tabent google_protobuf_intentries[66] = { +const upb_tabent google_protobuf_intentries[14] = { {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[13]), NULL}, - {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL}, + {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[71]), NULL}, - {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[64]), NULL}, - {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[3]), NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[10]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[69]), NULL}, - {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), NULL}, - {UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[59]), NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[58]), NULL}, - {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[12]), NULL}, - {UPB_TABKEY_NUM(16), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[1]), NULL}, - {UPB_TABKEY_NUM(17), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[21]), NULL}, - {UPB_TABKEY_NUM(18), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[57]), NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(20), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[20]), NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[68]), NULL}, - {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[23]), NULL}, - {UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[44]), NULL}, - {UPB_TABKEY_NUM(10), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[22]), NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[67]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL}, - {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[0]), NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[6]), NULL}, - {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[62]), NULL}, - {UPB_TABKEY_NUM(16), UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED64"), NULL}, - {UPB_TABKEY_NUM(17), UPB_VALUE_INIT_CONSTPTR("TYPE_SINT32"), NULL}, - {UPB_TABKEY_NUM(18), UPB_VALUE_INIT_CONSTPTR("TYPE_SINT64"), NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, + {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL}, - {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED32"), NULL}, - {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR("TYPE_BOOL"), NULL}, - {UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR("TYPE_STRING"), NULL}, - {UPB_TABKEY_NUM(10), UPB_VALUE_INIT_CONSTPTR("TYPE_GROUP"), NULL}, - {UPB_TABKEY_NUM(11), UPB_VALUE_INIT_CONSTPTR("TYPE_MESSAGE"), NULL}, - {UPB_TABKEY_NUM(12), UPB_VALUE_INIT_CONSTPTR("TYPE_BYTES"), NULL}, - {UPB_TABKEY_NUM(13), UPB_VALUE_INIT_CONSTPTR("TYPE_UINT32"), NULL}, - {UPB_TABKEY_NUM(14), UPB_VALUE_INIT_CONSTPTR("TYPE_ENUM"), NULL}, - {UPB_TABKEY_NUM(15), UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED32"), NULL}, + {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL}, }; -const _upb_value google_protobuf_arrays[97] = { +const _upb_value google_protobuf_arrays[224] = { UPB_ARRAY_EMPTYENT, - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[37]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[15]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[40]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[8]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[14]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[13]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[48]), UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[61]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[7]), UPB_ARRAY_EMPTYENT, - UPB_ARRAY_EMPTYENT, - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[33]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[72]), - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[48]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[45]), UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[31]), + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[35]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[42]), - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[51]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[34]), @@ -408,59 +367,168 @@ const _upb_value google_protobuf_arrays[97] = { UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[43]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[25]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[63]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[64]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[3]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[51]), UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[2]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[54]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[5]), UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[37]), + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[10]), + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[31]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[53]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[4]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[28]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[9]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[58]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[12]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[46]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[59]), UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[16]), UPB_ARRAY_EMPTYENT, - UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[24]), UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[23]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[44]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[22]), + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[1]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[21]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[57]), + UPB_ARRAY_EMPTYENT, + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[20]), + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[27]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[41]), UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[30]), + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[33]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[18]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[52]), - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[45]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[32]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[29]), - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[46]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), + UPB_ARRAY_EMPTYENT, + UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[26]), UPB_ARRAY_EMPTYENT, + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[26]), UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[55]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[60]), UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT, - UPB_ARRAY_EMPTYENT, - UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[35]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[30]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[17]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[56]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[39]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[6]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[62]), + UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[0]), UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[38]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[19]), UPB_ARRAY_EMPTYENT, - UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR("LABEL_OPTIONAL"), UPB_VALUE_INIT_CONSTPTR("LABEL_REQUIRED"), UPB_VALUE_INIT_CONSTPTR("LABEL_REPEATED"), @@ -471,13 +539,223 @@ const _upb_value google_protobuf_arrays[97] = { UPB_VALUE_INIT_CONSTPTR("TYPE_UINT64"), UPB_VALUE_INIT_CONSTPTR("TYPE_INT32"), UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED64"), + UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED32"), + UPB_VALUE_INIT_CONSTPTR("TYPE_BOOL"), + UPB_VALUE_INIT_CONSTPTR("TYPE_STRING"), + UPB_VALUE_INIT_CONSTPTR("TYPE_GROUP"), + UPB_VALUE_INIT_CONSTPTR("TYPE_MESSAGE"), + UPB_VALUE_INIT_CONSTPTR("TYPE_BYTES"), + UPB_VALUE_INIT_CONSTPTR("TYPE_UINT32"), + UPB_VALUE_INIT_CONSTPTR("TYPE_ENUM"), + UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED32"), + UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED64"), + UPB_VALUE_INIT_CONSTPTR("TYPE_SINT32"), + UPB_VALUE_INIT_CONSTPTR("TYPE_SINT64"), UPB_VALUE_INIT_CONSTPTR("STRING"), UPB_VALUE_INIT_CONSTPTR("CORD"), UPB_VALUE_INIT_CONSTPTR("STRING_PIECE"), UPB_ARRAY_EMPTYENT, - UPB_ARRAY_EMPTYENT, UPB_VALUE_INIT_CONSTPTR("SPEED"), UPB_VALUE_INIT_CONSTPTR("CODE_SIZE"), UPB_VALUE_INIT_CONSTPTR("LITE_RUNTIME"), }; +#ifdef UPB_DEBUG_REFS +static upb_inttable reftables[194] = { + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), +}; +#endif + diff --git a/upb/descriptor/descriptor.upb.h b/upb/descriptor/descriptor.upb.h index e61178a..15fa383 100755 --- a/upb/descriptor/descriptor.upb.h +++ b/upb/descriptor/descriptor.upb.h @@ -84,198 +84,198 @@ extern const upb_enumdef google_protobuf_enums[4]; #define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART &google_protobuf_msgs[19] // Selector definitions. -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 14 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 12 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 13 -#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 5 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 2 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 19 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 17 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 18 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 12 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 9 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 10 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 11 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 8 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 4 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 15 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END_INT32 3 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 17 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 16 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 15 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 18 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 20 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 19 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 18 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 21 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 7 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 5 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 6 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 7 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 5 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 6 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 36 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 35 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 34 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 37 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 27 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 15 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 17 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END_INT32 3 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START_INT32 2 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 26 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 25 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 28 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 22 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 21 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 20 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 23 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 7 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 20 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 22 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 25 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 27 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 6 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 5 #define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 8 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 3 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 2 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 9 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 7 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 8 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 7 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 5 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 6 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION_BOOL 5 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 8 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 6 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 18 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 16 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 14 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 15 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 4 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 2 -#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 3 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 9 -#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 3 -#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 2 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 15 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 14 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 13 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 16 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 7 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 6 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 5 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 8 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 3 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 5 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 7 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 4 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 3 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 2 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 11 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSUBMSG 13 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 10 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 12 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 31 +#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 30 #define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 2 #define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 3 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 2 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 11 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 10 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 6 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 8 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 5 +#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 7 +#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 +#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 4 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 3 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 2 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 5 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7 +#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6 +#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 +#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 16 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 15 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 14 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 7 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 6 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 5 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 9 #define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 2 #define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 3 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 2 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 2 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 3 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 2 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 8 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 18 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 17 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 10 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 13 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 12 +#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 11 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 2 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 4 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 7 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 6 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 5 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 3 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 9 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 11 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 8 +#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 10 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 9 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 12 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 8 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 11 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 10 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 19 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 21 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 18 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 20 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 29 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 31 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 28 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 30 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 14 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 16 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 13 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 15 #define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 4 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 2 #define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 3 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_ENDSTR 4 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STRING 2 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STARTSTR 3 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 11 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 12 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 11 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 10 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSUBMSG 13 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 2 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 34 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 33 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 7 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 6 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 5 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 24 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 26 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 23 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 25 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 37 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 36 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 3 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSUBMSG 5 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 2 +#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 4 +#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 10 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 13 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 11 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 9 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 7 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 6 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 5 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 4 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 3 +#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 2 +#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 8 +#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 12 +#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 15 +#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 17 +#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 14 +#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 16 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 2 #define GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 3 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 5 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 8 -#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 17 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 11 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 5 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 7 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 4 +#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 6 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 7 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 6 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 5 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 4 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 3 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 2 #define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 12 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 10 -#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 11 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 23 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 24 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 10 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 11 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 30 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 31 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 11 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 12 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6 -#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 11 #define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 10 -#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 8 #define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 9 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 7 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 5 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 6 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 3 +#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 8 +#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 +#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 6 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 8 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 5 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 7 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 4 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 3 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 2 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 11 +#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 10 +#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 +#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 +#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 3 +#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSUBMSG 5 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_ENDSEQ 3 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_INT32 4 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_STARTSEQ 2 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 10 -#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 7 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 31 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 30 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 29 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 32 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 26 -#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 27 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_ENDSEQ 6 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_INT32 7 #define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_STARTSEQ 5 -#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START_INT32 2 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 18 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 16 -#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 17 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 10 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 16 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 14 -#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 15 -#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 -#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 6 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 5 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 4 -#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 7 -#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 -#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 11 -#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 10 -#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 9 -#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 12 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 10 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 9 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 8 -#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 11 -#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 -#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4 -#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3 -#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2 -#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 7 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 6 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 5 -#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 8 +#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 2 +#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 4 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 18 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 17 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 16 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 12 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 9 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 8 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 7 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION_BOOL 5 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_ENDSTR 4 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STARTSTR 3 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STRING 2 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 3 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSUBMSG 5 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 2 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 4 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 11 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 10 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 15 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 14 +#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 13 #ifdef __cplusplus }; // extern "C" diff --git a/upb/descriptor/reader.c b/upb/descriptor/reader.c index 43bbdea..8deaa35 100644 --- a/upb/descriptor/reader.c +++ b/upb/descriptor/reader.c @@ -100,7 +100,7 @@ static upb_def *upb_deflist_last(upb_deflist *l) { // Qualify the defname for all defs starting with offset "start" with "str". static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) { - for(uint32_t i = start; i < l->len; i++) { + for (uint32_t i = start; i < l->len; i++) { upb_def *def = l->defs[i]; char *name = upb_join(str, upb_def_fullname(def)); upb_def_setfullname(def, name, NULL); @@ -124,7 +124,7 @@ typedef struct { struct upb_descreader { upb_deflist defs; - upb_descreader_frame stack[UPB_MAX_TYPE_DEPTH]; + upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING]; int stack_len; uint32_t number; @@ -184,7 +184,7 @@ upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n) { } static upb_msgdef *upb_descreader_top(upb_descreader *r) { - if (r->stack_len <= 1) return NULL; + assert(r->stack_len > 1); int index = r->stack[r->stack_len-1].start - 1; assert(index >= 0); return upb_downcast_msgdef_mutable(r->defs.defs[index]); @@ -291,7 +291,7 @@ static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) { static bool enum_startmsg(void *closure, const void *hd) { UPB_UNUSED(hd); upb_descreader *r = closure; - upb_deflist_push(&r->defs, upb_upcast(upb_enumdef_new(&r->defs))); + upb_deflist_push(&r->defs, UPB_UPCAST(upb_enumdef_new(&r->defs))); return true; } @@ -333,64 +333,68 @@ static bool field_startmsg(void *closure, const void *hd) { // Converts the default value in string "str" into "d". Passes a ref on str. // Returns true on success. -static bool parse_default(char *str, upb_value *d, int type) { +static bool parse_default(char *str, upb_fielddef *f) { bool success = true; - if (str) { - switch(type) { - case UPB_TYPE_INT32: upb_value_setint32(d, 0); break; - case UPB_TYPE_INT64: upb_value_setint64(d, 0); break; - case UPB_TYPE_UINT32: upb_value_setuint32(d, 0); - case UPB_TYPE_UINT64: upb_value_setuint64(d, 0); break; - case UPB_TYPE_FLOAT: upb_value_setfloat(d, 0); break; - case UPB_TYPE_DOUBLE: upb_value_setdouble(d, 0); break; - case UPB_TYPE_BOOL: upb_value_setbool(d, false); break; - default: abort(); + char *end; + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultint32(f, val); + break; } - } else { - char *end; - switch (type) { - case UPB_TYPE_INT32: { - long val = strtol(str, &end, 0); - if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) - success = false; - else - upb_value_setint32(d, val); - break; - } - case UPB_TYPE_INT64: - upb_value_setint64(d, strtoll(str, &end, 0)); - if (errno == ERANGE || *end) success = false; - break; - case UPB_TYPE_UINT32: { - unsigned long val = strtoul(str, &end, 0); - if (val > UINT32_MAX || errno == ERANGE || *end) - success = false; - else - upb_value_setuint32(d, val); - break; - } - case UPB_TYPE_UINT64: - upb_value_setuint64(d, strtoull(str, &end, 0)); - if (errno == ERANGE || *end) success = false; - break; - case UPB_TYPE_DOUBLE: - upb_value_setdouble(d, strtod(str, &end)); - if (errno == ERANGE || *end) success = false; - break; - case UPB_TYPE_FLOAT: - upb_value_setfloat(d, strtof(str, &end)); - if (errno == ERANGE || *end) success = false; - break; - case UPB_TYPE_BOOL: { - if (strcmp(str, "false") == 0) - upb_value_setbool(d, false); - else if (strcmp(str, "true") == 0) - upb_value_setbool(d, true); - else - success = false; - } - default: abort(); + case UPB_TYPE_INT64: { + long long val = strtoll(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultint64(f, val); + break; + } + case UPB_TYPE_UINT32: { + long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultuint32(f, val); + break; + } + case UPB_TYPE_UINT64: { + unsigned long long val = strtoull(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultuint64(f, val); + break; + } + case UPB_TYPE_DOUBLE: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultdouble(f, val); + break; + } + case UPB_TYPE_FLOAT: { + float val = strtof(str, &end); + if (errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultfloat(f, val); + break; + } + case UPB_TYPE_BOOL: { + if (strcmp(str, "false") == 0) + upb_fielddef_setdefaultbool(f, false); + else if (strcmp(str, "true") == 0) + upb_fielddef_setdefaultbool(f, true); + else + success = false; + break; } + default: abort(); } return success; } @@ -411,15 +415,12 @@ static bool field_endmsg(void *closure, const void *hd, upb_status *status) { if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) { upb_fielddef_setdefaultcstr(f, r->default_string, NULL); } else { - upb_value val; - upb_value_setptr(&val, NULL); // Silence inaccurate compiler warnings. - if (!parse_default(r->default_string, &val, upb_fielddef_type(f))) { + if (r->default_string && !parse_default(r->default_string, f)) { // We don't worry too much about giving a great error message since the // compiler should have ensured this was correct. upb_status_seterrliteral(status, "Error converting default value."); return false; } - upb_fielddef_setdefault(f, val); } } return true; @@ -484,7 +485,7 @@ static size_t field_ondefaultval(void *closure, const void *hd, static bool msg_startmsg(void *closure, const void *hd) { UPB_UNUSED(hd); upb_descreader *r = closure; - upb_deflist_push(&r->defs, upb_upcast(upb_msgdef_new(&r->defs))); + upb_deflist_push(&r->defs, UPB_UPCAST(upb_msgdef_new(&r->defs))); upb_descreader_startcontainer(r); return true; } @@ -493,7 +494,7 @@ static bool msg_endmsg(void *closure, const void *hd, upb_status *status) { UPB_UNUSED(hd); upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); - if(!upb_def_fullname(upb_upcast(m))) { + if(!upb_def_fullname(UPB_UPCAST(m))) { upb_status_seterrliteral(status, "Encountered message with no name."); return false; } @@ -508,7 +509,7 @@ static size_t msg_onname(void *closure, const void *hd, const char *buf, upb_msgdef *m = upb_descreader_top(r); // XXX: see comment at the top of the file. char *name = upb_strndup(buf, n); - upb_def_setfullname(upb_upcast(m), name, NULL); + upb_def_setfullname(UPB_UPCAST(m), name, NULL); upb_descreader_setscopename(r, name); // Passes ownership of name. return n; } diff --git a/upb/descriptor/reader.h b/upb/descriptor/reader.h index b7c7d8b..d00830b 100644 --- a/upb/descriptor/reader.h +++ b/upb/descriptor/reader.h @@ -13,6 +13,18 @@ #include "upb/handlers.h" +// The maximum number of nested declarations that are allowed, ie. +// message Foo { +// message Bar { +// message Baz { +// } +// } +// } +// +// This is a resource limit that affects how big our runtime stack can grow. +// TODO: make this a runtime-settable property of the Reader instance. +#define UPB_MAX_MESSAGE_NESTING 64 + #ifdef __cplusplus namespace upb { namespace descriptor { diff --git a/upb/google/bridge.cc b/upb/google/bridge.cc index 9c2a69e..caf4935 100644 --- a/upb/google/bridge.cc +++ b/upb/google/bridge.cc @@ -19,6 +19,14 @@ #include "upb/google/proto2.h" #include "upb/handlers.h" +#define ASSERT_STATUS(status) do { \ + if (!upb_ok(status)) { \ + fprintf(stderr, "upb status failure: %s\n", upb_status_getstr(status)); \ + assert(upb_ok(status)); \ + } \ + } while (0) + + namespace upb { namespace proto2_bridge_google3 { class Defs; } namespace proto2_bridge_opensource { class Defs; } @@ -44,8 +52,8 @@ class me::Defs { const upb::MessageDef* md = h->message_def(); const goog::Message& m = *message_map_[md]; const goog::Descriptor* d = m.GetDescriptor(); - for (upb::MessageDef::ConstIterator i(md); !i.Done(); i.Next()) { - const upb::FieldDef* upb_f = i.field(); + for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) { + const upb::FieldDef* upb_f = *i; const goog::FieldDescriptor* proto2_f = d->FindFieldByNumber(upb_f->number()); if (!proto2_f) { @@ -137,27 +145,25 @@ FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f, } else { switch (upb_f->type()) { case UPB_TYPE_INT32: - upb_f->set_default_value(MakeValue(f->default_value_int32())); + upb_f->set_default_int32(f->default_value_int32()); break; case UPB_TYPE_INT64: - upb_f->set_default_value( - MakeValue(static_cast<int64_t>(f->default_value_int64()))); + upb_f->set_default_int64(f->default_value_int64()); break; case UPB_TYPE_UINT32: - upb_f->set_default_value(MakeValue(f->default_value_uint32())); + upb_f->set_default_uint32(f->default_value_uint32()); break; case UPB_TYPE_UINT64: - upb_f->set_default_value( - MakeValue(static_cast<uint64_t>(f->default_value_uint64()))); + upb_f->set_default_uint64(f->default_value_uint64()); break; case UPB_TYPE_DOUBLE: - upb_f->set_default_value(MakeValue(f->default_value_double())); + upb_f->set_default_double(f->default_value_double()); break; case UPB_TYPE_FLOAT: - upb_f->set_default_value(MakeValue(f->default_value_float())); + upb_f->set_default_float(f->default_value_float()); break; case UPB_TYPE_BOOL: - upb_f->set_default_value(MakeValue(f->default_value_bool())); + upb_f->set_default_bool(f->default_value_bool()); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: @@ -168,15 +174,14 @@ FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f, break; case UPB_TYPE_ENUM: // We set the enum default numerically. - upb_f->set_default_value( - MakeValue(static_cast<int32_t>(f->default_value_enum()->number()))); + upb_f->set_default_int32(f->default_value_enum()->number()); upb_f->set_subdef_name(f->enum_type()->full_name(), &status); break; } } md->AddField(upb_f, &upb_f, &status); - UPB_ASSERT_STATUS(&status); + ASSERT_STATUS(&status); if (weak_prototype) { *subm = weak_prototype; @@ -200,7 +205,7 @@ upb::EnumDef* NewEnumDef(const goog::EnumDescriptor* desc, const void* owner) { bool success = e->AddValue(val->name(), val->number(), &status); UPB_ASSERT_VAR(success, success); } - UPB_ASSERT_STATUS(&status); + ASSERT_STATUS(&status); return e; } @@ -245,7 +250,7 @@ static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner, } f->set_subdef(subdef, &status); } - UPB_ASSERT_STATUS(&status); + ASSERT_STATUS(&status); return md; } diff --git a/upb/handlers-inl.h b/upb/handlers-inl.h index 6b46b47..d5ed940 100644 --- a/upb/handlers-inl.h +++ b/upb/handlers-inl.h @@ -11,6 +11,86 @@ #ifndef UPB_HANDLERS_INL_H_ #define UPB_HANDLERS_INL_H_ +#include <limits.h> + +// Type detection and typedefs for integer types. +// For platforms where there are multiple 32-bit or 64-bit types, we need to be +// able to enumerate them so we can properly create overloads for all variants. +// +// If any platform existed where there were three integer types with the same +// size, this would have to become more complicated. For example, short, int, +// and long could all be 32-bits. Even more diabolically, short, int, long, +// and long long could all be 64 bits and still be standard-compliant. +// However, few platforms are this strange, and it's unlikely that upb will be +// used on the strangest ones. + +// Can't count on stdint.h limits like INT32_MAX, because in C++ these are +// only defined when __STDC_LIMIT_MACROS are defined before the *first* include +// of stdint.h. We can't guarantee that someone else didn't include these first +// without defining __STDC_LIMIT_MACROS. +#define UPB_INT32_MAX 0x7fffffffLL +#define UPB_INT32_MIN (-UPB_INT32_MAX - 1) +#define UPB_INT64_MAX 0x7fffffffffffffffLL +#define UPB_INT64_MIN (-UPB_INT64_MAX - 1) + +#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN +#define UPB_INT_IS_32BITS 1 +#endif + +#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN +#define UPB_LONG_IS_32BITS 1 +#endif + +#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN +#define UPB_LONG_IS_64BITS 1 +#endif + +#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN +#define UPB_LLONG_IS_64BITS 1 +#endif + +// We use macros instead of typedefs so we can undefine them later and avoid +// leaking them outside this header file. +#if UPB_INT_IS_32BITS +#define UPB_INT32_T int +#define UPB_UINT32_T unsigned int + +#if UPB_LONG_IS_32BITS +#define UPB_TWO_32BIT_TYPES 1 +#define UPB_INT32ALT_T long +#define UPB_UINT32ALT_T unsigned long +#endif // UPB_LONG_IS_32BITS + +#elif UPB_LONG_IS_32BITS // && !UPB_INT_IS_32BITS +#define UPB_INT32_T long +#define UPB_UINT32_T unsigned long +#endif // UPB_INT_IS_32BITS + + +#if UPB_LONG_IS_64BITS +#define UPB_INT64_T long +#define UPB_UINT64_T unsigned long + +#if UPB_LLONG_IS_64BITS +#define UPB_TWO_64BIT_TYPES 1 +#define UPB_INT64ALT_T long long +#define UPB_UINT64ALT_T unsigned long long +#endif // UPB_LLONG_IS_64BITS + +#elif UPB_LLONG_IS_64BITS // && !UPB_LONG_IS_64BITS +#define UPB_INT64_T long long +#define UPB_UINT64_T unsigned long long +#endif // UPB_LONG_IS_64BITS + +#undef UPB_INT32_MAX +#undef UPB_INT32_MIN +#undef UPB_INT64_MAX +#undef UPB_INT64_MIN +#undef UPB_INT_IS_32BITS +#undef UPB_LONG_IS_32BITS +#undef UPB_LONG_IS_64BITS +#undef UPB_LLONG_IS_64BITS + #ifdef __cplusplus namespace upb { @@ -312,20 +392,20 @@ inline Handlers::StringHandler BindHandler( TYPE_METHODS(Double, double, double, double); TYPE_METHODS(Float, float, float, float); -TYPE_METHODS(UInt64, uint64, uint64_t, upb_uint64_t); -TYPE_METHODS(UInt32, uint32, uint32_t, upb_uint32_t); -TYPE_METHODS(Int64, int64, int64_t, upb_int64_t); -TYPE_METHODS(Int32, int32, int32_t, upb_int32_t); +TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T); +TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T); +TYPE_METHODS(Int64, int64, int64_t, UPB_INT64_T); +TYPE_METHODS(Int32, int32, int32_t, UPB_INT32_T); TYPE_METHODS(Bool, bool, bool, bool); #ifdef UPB_TWO_32BIT_TYPES -TYPE_METHODS(Int32, int32, int32_t, upb_int32alt_t); -TYPE_METHODS(Uint32, uint32, uint32_t, upb_uint32alt_t); +TYPE_METHODS(Int32, int32, int32_t, UPB_INT32ALT_T); +TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T); #endif #ifdef UPB_TWO_64BIT_TYPES -TYPE_METHODS(Int64, int64, int64_t, upb_int64alt_t); -TYPE_METHODS(UInt64, uint64, uint64_t, upb_uint64alt_t); +TYPE_METHODS(Int64, int64, int64_t, UPB_INT64ALT_T); +TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T); #endif #undef TYPE_METHODS @@ -483,4 +563,15 @@ inline const void *Handlers::GetHandlerData(Handlers::Selector selector) { #endif // __cplusplus +#undef UPB_TWO_32BIT_TYPES +#undef UPB_TWO_64BIT_TYPES +#undef UPB_INT32_T +#undef UPB_UINT32_T +#undef UPB_INT32ALT_T +#undef UPB_UINT32ALT_T +#undef UPB_INT64_T +#undef UPB_UINT64_T +#undef UPB_INT64ALT_T +#undef UPB_UINT64ALT_T + #endif // UPB_HANDLERS_INL_H_ diff --git a/upb/handlers.c b/upb/handlers.c index 5adaee5..169dbe0 100644 --- a/upb/handlers.c +++ b/upb/handlers.c @@ -46,7 +46,7 @@ static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit, upb_fielddef *f = upb_msg_iter_field(&i); if (!upb_fielddef_issubmsg(f)) continue; const upb_handlers *sub = upb_handlers_getsubhandlers(h, f); - if (sub) visit(r, upb_upcast(sub), closure); + if (sub) visit(r, UPB_UPCAST(sub), closure); } } @@ -101,7 +101,7 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type) { upb_selector_t sel; assert(!upb_handlers_isfrozen(h)); - if (upb_handlers_msgdef(h) != upb_fielddef_msgdef(f)) { + if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) { upb_status_seterrf( h->status_, "type mismatch: field %s does not belong to message %s", upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h))); @@ -153,24 +153,24 @@ static bool doset(upb_handlers *h, upb_selector_t sel, upb_func *func, /* Public interface ***********************************************************/ bool upb_handlers_isfrozen(const upb_handlers *h) { - return upb_refcounted_isfrozen(upb_upcast(h)); + return upb_refcounted_isfrozen(UPB_UPCAST(h)); } void upb_handlers_ref(const upb_handlers *h, const void *owner) { - upb_refcounted_ref(upb_upcast(h), owner); + upb_refcounted_ref(UPB_UPCAST(h), owner); } void upb_handlers_unref(const upb_handlers *h, const void *owner) { - upb_refcounted_unref(upb_upcast(h), owner); + upb_refcounted_unref(UPB_UPCAST(h), owner); } void upb_handlers_donateref( const upb_handlers *h, const void *from, const void *to) { - upb_refcounted_donateref(upb_upcast(h), from, to); + upb_refcounted_donateref(UPB_UPCAST(h), from, to); } void upb_handlers_checkref(const upb_handlers *h, const void *owner) { - upb_refcounted_checkref(upb_upcast(h), owner); + upb_refcounted_checkref(UPB_UPCAST(h), owner); } @@ -192,13 +192,13 @@ upb_handlers *upb_handlers_new(const upb_msgdef *md, const upb_frametype *ft, h->cleanup_size = 0; h->cleanup_len = 0; upb_msgdef_ref(h->msg, h); - if (!upb_refcounted_init(upb_upcast(h), &vtbl, owner)) goto oom; + if (!upb_refcounted_init(UPB_UPCAST(h), &vtbl, owner)) goto oom; // calloc() above initialized all handlers to NULL. return h; oom: - freehandlers(upb_upcast(h)); + freehandlers(UPB_UPCAST(h)); return NULL; } @@ -217,8 +217,8 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, upb_inttable_uninit(&state.tab); if (!ret) return NULL; - upb_refcounted *r = upb_upcast(ret); - bool ok = upb_refcounted_freeze(&r, 1, NULL); + upb_refcounted *r = UPB_UPCAST(ret); + bool ok = upb_refcounted_freeze(&r, 1, NULL, UPB_MAX_HANDLER_DEPTH); UPB_ASSERT_VAR(ok, ok); return ret; @@ -276,7 +276,7 @@ bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, assert(!upb_handlers_isfrozen(h)); assert(upb_fielddef_issubmsg(f)); if (SUBH(h, f->selector_base)) return false; // Can't reset. - if (upb_upcast(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) { + if (UPB_UPCAST(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) { return false; } SUBH(h, f->selector_base) = sub; @@ -324,7 +324,8 @@ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { } } - if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s)) { + if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s, + UPB_MAX_HANDLER_DEPTH)) { return false; } @@ -395,7 +396,7 @@ bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, break; // Subhandler slot is selector_base + 2. } - assert(*s < upb_fielddef_msgdef(f)->selector_count); + assert(*s < upb_fielddef_containingtype(f)->selector_count); return true; } diff --git a/upb/handlers.h b/upb/handlers.h index 2108046..bb9c3b6 100644 --- a/upb/handlers.h +++ b/upb/handlers.h @@ -45,6 +45,15 @@ typedef struct upb_handlers upb_handlers; typedef struct upb_sinkframe upb_sinkframe; #endif +// The maximum depth that the handler graph can have. This is a resource limit +// for the C stack since we sometimes need to recursively traverse the graph. +// Cycles are ok; the traversal will stop when it detects a cycle, but we must +// hit the cycle before the maximum depth is reached. +// +// If having a single static limit is too inflexible, we can add another variant +// of Handlers::Freeze that allows specifying this as a parameter. +#define UPB_MAX_HANDLER_DEPTH 64 + typedef struct { void (*func)(); const void *data; diff --git a/upb/pb/compile_decoder.c b/upb/pb/compile_decoder.c new file mode 100644 index 0000000..c86a171 --- /dev/null +++ b/upb/pb/compile_decoder.c @@ -0,0 +1,855 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2013 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + * + * Code to compile a upb::MessageDef into bytecode for decoding that message. + * Bytecode definition is in decoder.int.h. + */ + +#include <stdarg.h> +#include "upb/pb/decoder.int.h" +#include "upb/pb/varint.int.h" +#include "upb/bytestream.h" + +#ifdef UPB_DUMP_BYTECODE +#include <stdio.h> +#endif + +#define MAXLABEL 5 +#define EMPTYLABEL -1 + +/* upb_pbdecodermethod ********************************************************/ + +static upb_pbdecodermethod *newmethod(const upb_msgdef *msg, + const upb_handlers *dest_handlers) { + upb_pbdecodermethod *ret = malloc(sizeof(upb_pbdecodermethod)); + ret->msg = msg; + ret->dest_handlers = dest_handlers; + ret->native_code = false; // If we JIT, it will update this later. + upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64); + + if (ret->dest_handlers) { + upb_handlers_ref(ret->dest_handlers, ret); + } + return ret; +} + +static void freemethod(upb_pbdecodermethod *method) { + if (method->dest_handlers) { + upb_handlers_unref(method->dest_handlers, method); + } + + upb_inttable_uninit(&method->dispatch); + free(method); +} + + +/* upb_pbdecoderplan **********************************************************/ + +upb_pbdecoderplan *newplan() { + upb_pbdecoderplan *p = malloc(sizeof(*p)); + upb_inttable_init(&p->methods, UPB_CTYPE_PTR); + p->code = NULL; + p->code_end = NULL; + return p; +} + +void freeplan(void *_p) { + upb_pbdecoderplan *p = _p; + + upb_inttable_iter i; + upb_inttable_begin(&i, &p->methods); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); + freemethod(method); + } + upb_inttable_uninit(&p->methods); + free(p->code); +#ifdef UPB_USE_JIT_X64 + upb_pbdecoder_freejit(p); +#endif + free(p); +} + +void set_bytecode_handlers(upb_pbdecoderplan *p, upb_handlers *h) { + upb_handlers_setstartstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_start, p, + NULL); + upb_handlers_setstring(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_decode, p, + freeplan); + upb_handlers_setendstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_end, p, NULL); +} + +static const upb_pbdecoderplan *getdecoderplan(const upb_handlers *h) { + if (upb_handlers_frametype(h) != &upb_pbdecoder_frametype) + return NULL; + upb_selector_t sel; + if (!upb_handlers_getselector(UPB_BYTESTREAM_BYTES, UPB_HANDLER_STARTSTR, + &sel)) { + return NULL; + } + return upb_handlers_gethandlerdata(h, sel); +} + + +/* compiler *******************************************************************/ + +// Data used only at compilation time. +typedef struct { + upb_pbdecoderplan *plan; + + uint32_t *pc; + int fwd_labels[MAXLABEL]; + int back_labels[MAXLABEL]; +} compiler; + +static compiler *newcompiler(upb_pbdecoderplan *plan) { + compiler *ret = malloc(sizeof(compiler)); + ret->plan = plan; + for (int i = 0; i < MAXLABEL; i++) { + ret->fwd_labels[i] = EMPTYLABEL; + ret->back_labels[i] = EMPTYLABEL; + } + return ret; +} + +static void freecompiler(compiler *c) { + free(c); +} + +const size_t ptr_words = sizeof(void*) / sizeof(uint32_t); + +// How many words an instruction is. +static int instruction_len(uint32_t instr) { + switch (getop(instr)) { + case OP_SETDISPATCH: return 1 + ptr_words; + case OP_TAGN: return 3; + case OP_SETBIGGROUPNUM: return 2; + default: return 1; + } +} + +bool op_has_longofs(int32_t instruction) { + switch (getop(instruction)) { + case OP_CALL: + case OP_BRANCH: + case OP_CHECKDELIM: + return true; + // The "tag" instructions only have 8 bytes available for the jump target, + // but that is ok because these opcodes only require short jumps. + case OP_TAG1: + case OP_TAG2: + case OP_TAGN: + return false; + default: + assert(false); + return false; + } +} + +static int32_t getofs(uint32_t instruction) { + if (op_has_longofs(instruction)) { + return (int32_t)instruction >> 8; + } else { + return (int8_t)(instruction >> 8); + } +} + +static void setofs(uint32_t *instruction, int32_t ofs) { + if (op_has_longofs(*instruction)) { + *instruction = getop(*instruction) | ofs << 8; + } else { + *instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8); + } + assert(getofs(*instruction) == ofs); // Would fail in cases of overflow. +} + +static uint32_t pcofs(compiler *c) { return c->pc - c->plan->code; } + +// Defines a local label at the current PC location. All previous forward +// references are updated to point to this location. The location is noted +// for any future backward references. +static void label(compiler *c, unsigned int label) { + assert(label < MAXLABEL); + int val = c->fwd_labels[label]; + uint32_t *codep = (val == EMPTYLABEL) ? NULL : c->plan->code + val; + while (codep) { + int ofs = getofs(*codep); + setofs(codep, c->pc - codep - instruction_len(*codep)); + codep = ofs ? codep + ofs : NULL; + } + c->fwd_labels[label] = EMPTYLABEL; + c->back_labels[label] = pcofs(c); +} + +// Creates a reference to a numbered label; either a forward reference +// (positive arg) or backward reference (negative arg). For forward references +// the value returned now is actually a "next" pointer into a linked list of all +// instructions that use this label and will be patched later when the label is +// defined with label(). +// +// The returned value is the offset that should be written into the instruction. +static int32_t labelref(compiler *c, int label) { + assert(label < MAXLABEL); + if (label == LABEL_DISPATCH) { + // No resolving required. + return 0; + } else if (label < 0) { + // Backward local label. Relative to the next instruction. + uint32_t from = (c->pc + 1) - c->plan->code; + return c->back_labels[-label] - from; + } else { + // Forward local label: prepend to (possibly-empty) linked list. + int *lptr = &c->fwd_labels[label]; + int32_t ret = (*lptr == EMPTYLABEL) ? 0 : *lptr - pcofs(c); + *lptr = pcofs(c); + return ret; + } +} + +static void put32(compiler *c, uint32_t v) { + if (c->pc == c->plan->code_end) { + int ofs = pcofs(c); + size_t oldsize = c->plan->code_end - c->plan->code; + size_t newsize = UPB_MAX(oldsize * 2, 64); + // TODO(haberman): handle OOM. + c->plan->code = realloc(c->plan->code, newsize * sizeof(uint32_t)); + c->plan->code_end = c->plan->code + newsize; + c->pc = c->plan->code + ofs; + } + *c->pc++ = v; +} + +static void putop(compiler *c, opcode op, ...) { + va_list ap; + va_start(ap, op); + + switch (op) { + case OP_SETDISPATCH: { + uintptr_t ptr = (uintptr_t)va_arg(ap, void*); + put32(c, OP_SETDISPATCH); + put32(c, ptr); + if (sizeof(uintptr_t) > sizeof(uint32_t)) + put32(c, (uint64_t)ptr >> 32); + break; + } + case OP_STARTMSG: + case OP_ENDMSG: + case OP_PUSHTAGDELIM: + case OP_PUSHLENDELIM: + case OP_POP: + case OP_SETDELIM: + case OP_HALT: + put32(c, op); + break; + case OP_PARSE_DOUBLE: + case OP_PARSE_FLOAT: + case OP_PARSE_INT64: + case OP_PARSE_UINT64: + case OP_PARSE_INT32: + case OP_PARSE_FIXED64: + case OP_PARSE_FIXED32: + case OP_PARSE_BOOL: + case OP_PARSE_UINT32: + case OP_PARSE_SFIXED32: + case OP_PARSE_SFIXED64: + case OP_PARSE_SINT32: + case OP_PARSE_SINT64: + case OP_STARTSEQ: + case OP_SETGROUPNUM: + case OP_ENDSEQ: + case OP_STARTSUBMSG: + case OP_ENDSUBMSG: + case OP_STARTSTR: + case OP_STRING: + case OP_ENDSTR: + put32(c, op | va_arg(ap, upb_selector_t) << 8); + break; + case OP_SETBIGGROUPNUM: + put32(c, op); + put32(c, va_arg(ap, int)); + break; + case OP_CALL: { + const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *); + put32(c, op | (method->base.ofs - (pcofs(c) + 1)) << 8); + break; + } + case OP_CHECKDELIM: + case OP_BRANCH: { + uint32_t instruction = op; + int label = va_arg(ap, int); + setofs(&instruction, labelref(c, label)); + put32(c, instruction); + break; + } + case OP_TAG1: + case OP_TAG2: { + int label = va_arg(ap, int); + uint64_t tag = va_arg(ap, uint64_t); + uint32_t instruction = op | (tag << 16); + assert(tag <= 0xffff); + setofs(&instruction, labelref(c, label)); + put32(c, instruction); + break; + } + case OP_TAGN: { + int label = va_arg(ap, int); + uint64_t tag = va_arg(ap, uint64_t); + uint32_t instruction = op | (upb_value_size(tag) << 16); + setofs(&instruction, labelref(c, label)); + put32(c, instruction); + put32(c, tag); + put32(c, tag >> 32); + break; + } + } + + va_end(ap); +} + +#if defined(UPB_USE_JIT_X64) || defined(UPB_DUMP_BYTECODE) + +const char *upb_pbdecoder_getopname(unsigned int op) { +#define OP(op) [OP_ ## op] = "OP_" #op +#define T(op) OP(PARSE_##op) + static const char *names[] = { + "<no opcode>", + T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32), + T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64), + OP(STARTMSG), OP(ENDMSG), OP(STARTSEQ), OP(ENDSEQ), OP(STARTSUBMSG), + OP(ENDSUBMSG), OP(STARTSTR), OP(STRING), OP(ENDSTR), OP(CALL), + OP(PUSHLENDELIM), OP(PUSHTAGDELIM), OP(SETDELIM), OP(CHECKDELIM), + OP(BRANCH), OP(TAG1), OP(TAG2), OP(TAGN), OP(SETDISPATCH), OP(POP), + OP(SETGROUPNUM), OP(SETBIGGROUPNUM), OP(HALT), + }; + return op > OP_HALT ? names[0] : names[op]; +#undef OP +#undef T +} + +#endif + +#ifdef UPB_DUMP_BYTECODE + +static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) { + + uint32_t *begin = p; + + while (p < end) { + fprintf(f, "%p %8tx", p, p - begin); + uint32_t instr = *p++; + uint8_t op = getop(instr); + fprintf(f, " %s", upb_pbdecoder_getopname(op)); + switch ((opcode)op) { + case OP_SETDISPATCH: { + const upb_inttable *dispatch; + memcpy(&dispatch, p, sizeof(void*)); + p += ptr_words; + const upb_pbdecodermethod *method = + (void *)((char *)dispatch - + offsetof(upb_pbdecodermethod, dispatch)); + fprintf(f, " %s", upb_msgdef_fullname(method->msg)); + break; + } + case OP_STARTMSG: + case OP_ENDMSG: + case OP_PUSHLENDELIM: + case OP_PUSHTAGDELIM: + case OP_POP: + case OP_SETDELIM: + case OP_HALT: + break; + case OP_PARSE_DOUBLE: + case OP_PARSE_FLOAT: + case OP_PARSE_INT64: + case OP_PARSE_UINT64: + case OP_PARSE_INT32: + case OP_PARSE_FIXED64: + case OP_PARSE_FIXED32: + case OP_PARSE_BOOL: + case OP_PARSE_UINT32: + case OP_PARSE_SFIXED32: + case OP_PARSE_SFIXED64: + case OP_PARSE_SINT32: + case OP_PARSE_SINT64: + case OP_STARTSEQ: + case OP_ENDSEQ: + case OP_STARTSUBMSG: + case OP_ENDSUBMSG: + case OP_STARTSTR: + case OP_STRING: + case OP_ENDSTR: + case OP_SETGROUPNUM: + fprintf(f, " %d", instr >> 8); + break; + case OP_SETBIGGROUPNUM: + fprintf(f, " %d", *p++); + break; + case OP_CHECKDELIM: + case OP_CALL: + case OP_BRANCH: + fprintf(f, " =>0x%tx", p + getofs(instr) - begin); + break; + case OP_TAG1: + case OP_TAG2: { + fprintf(f, " tag:0x%x", instr >> 16); + if (getofs(instr)) { + fprintf(f, " =>0x%tx", p + getofs(instr) - begin); + } + break; + } + case OP_TAGN: { + uint64_t tag = *p++; + tag |= (uint64_t)*p++ << 32; + fprintf(f, " tag:0x%llx", (long long)tag); + fprintf(f, " n:%d", instr >> 16); + if (getofs(instr)) { + fprintf(f, " =>0x%tx", p + getofs(instr) - begin); + } + break; + } + } + fputs("\n", f); + } +} + +#endif + +static uint64_t get_encoded_tag(const upb_fielddef *f, int wire_type) { + uint32_t tag = (upb_fielddef_number(f) << 3) | wire_type; + uint64_t encoded_tag = upb_vencode32(tag); + // No tag should be greater than 5 bytes. + assert(encoded_tag <= 0xffffffffff); + return encoded_tag; +} + +static void putchecktag(compiler *c, const upb_fielddef *f, + int wire_type, int dest) { + uint64_t tag = get_encoded_tag(f, wire_type); + switch (upb_value_size(tag)) { + case 1: + putop(c, OP_TAG1, dest, tag); + break; + case 2: + putop(c, OP_TAG2, dest, tag); + break; + default: + putop(c, OP_TAGN, dest, tag); + break; + } +} + +static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) { + upb_selector_t selector; + bool ok = upb_handlers_getselector(f, type, &selector); + UPB_ASSERT_VAR(ok, ok); + return selector; +} + +// Marks the current bytecode position as the dispatch target for this message, +// field, and wire type. +// +static void dispatchtarget(compiler *c, upb_pbdecodermethod *method, + const upb_fielddef *f, int wire_type) { + // Offset is relative to msg base. + uint64_t ofs = pcofs(c) - method->base.ofs; + uint32_t fn = upb_fielddef_number(f); + upb_inttable *d = &method->dispatch; + upb_value v; + if (upb_inttable_remove(d, fn, &v)) { + // TODO: prioritize based on packed setting in .proto file. + uint64_t oldval = upb_value_getuint64(v); + assert(((oldval >> 8) & 0xff) == 0); // wt2 should not be set yet. + upb_inttable_insert(d, fn, upb_value_uint64(oldval | (wire_type << 8))); + upb_inttable_insert(d, fn + UPB_MAX_FIELDNUMBER, upb_value_uint64(ofs)); + } else { + upb_inttable_insert(d, fn, upb_value_uint64((ofs << 16) | wire_type)); + } +} + +static void putpush(compiler *c, const upb_fielddef *f) { + if (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) { + putop(c, OP_PUSHLENDELIM); + } else { + uint32_t fn = upb_fielddef_number(f); + putop(c, OP_PUSHTAGDELIM); + if (fn >= 1 << 24) { + putop(c, OP_SETBIGGROUPNUM, fn); + } else { + putop(c, OP_SETGROUPNUM, fn); + } + } +} + +static upb_pbdecodermethod *find_submethod(const compiler *c, + const upb_pbdecodermethod *method, + const upb_fielddef *f) { + const void *key = method->dest_handlers ? + (const void*)upb_handlers_getsubhandlers(method->dest_handlers, f) : + (const void*)upb_downcast_msgdef(upb_fielddef_subdef(f)); + upb_value v; + bool ok = upb_inttable_lookupptr(&c->plan->methods, key, &v); + UPB_ASSERT_VAR(ok, ok); + return upb_value_getptr(v); +} + +// Adds bytecode for parsing the given message to the given decoderplan, +// while adding all dispatch targets to this message's dispatch table. +static void compile_method(compiler *c, upb_pbdecodermethod *method) { + assert(method); + + // Symbolic names for our local labels. + const int LABEL_LOOPSTART = 1; // Top of a repeated field loop. + const int LABEL_LOOPBREAK = 2; // To jump out of a repeated loop + const int LABEL_FIELD = 3; // Jump backward to find the most recent field. + const int LABEL_ENDMSG = 4; // To reach the OP_ENDMSG instr for this msg. + + // Index is descriptor type. + static const uint8_t native_wire_types[] = { + UPB_WIRE_TYPE_END_GROUP, // ENDGROUP + UPB_WIRE_TYPE_64BIT, // DOUBLE + UPB_WIRE_TYPE_32BIT, // FLOAT + UPB_WIRE_TYPE_VARINT, // INT64 + UPB_WIRE_TYPE_VARINT, // UINT64 + UPB_WIRE_TYPE_VARINT, // INT32 + UPB_WIRE_TYPE_64BIT, // FIXED64 + UPB_WIRE_TYPE_32BIT, // FIXED32 + UPB_WIRE_TYPE_VARINT, // BOOL + UPB_WIRE_TYPE_DELIMITED, // STRING + UPB_WIRE_TYPE_START_GROUP, // GROUP + UPB_WIRE_TYPE_DELIMITED, // MESSAGE + UPB_WIRE_TYPE_DELIMITED, // BYTES + UPB_WIRE_TYPE_VARINT, // UINT32 + UPB_WIRE_TYPE_VARINT, // ENUM + UPB_WIRE_TYPE_32BIT, // SFIXED32 + UPB_WIRE_TYPE_64BIT, // SFIXED64 + UPB_WIRE_TYPE_VARINT, // SINT32 + UPB_WIRE_TYPE_VARINT, // SINT64 + }; + + // Clear all entries in the dispatch table. + upb_inttable_uninit(&method->dispatch); + upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64); + + method->base.ofs = pcofs(c); + putop(c, OP_SETDISPATCH, &method->dispatch); + putop(c, OP_STARTMSG); + label(c, LABEL_FIELD); + upb_msg_iter i; + for(upb_msg_begin(&i, method->msg); !upb_msg_done(&i); upb_msg_next(&i)) { + const upb_fielddef *f = upb_msg_iter_field(&i); + upb_descriptortype_t type = upb_fielddef_descriptortype(f); + + // From a decoding perspective, ENUM is the same as INT32. + if (type == UPB_DESCRIPTOR_TYPE_ENUM) + type = UPB_DESCRIPTOR_TYPE_INT32; + + label(c, LABEL_FIELD); + + switch (upb_fielddef_type(f)) { + case UPB_TYPE_MESSAGE: { + const upb_pbdecodermethod *sub_m = find_submethod(c, method, f); + int wire_type = (type == UPB_DESCRIPTOR_TYPE_MESSAGE) ? + UPB_WIRE_TYPE_DELIMITED : UPB_WIRE_TYPE_START_GROUP; + if (upb_fielddef_isseq(f)) { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, wire_type, LABEL_DISPATCH); + dispatchtarget(c, method, f, wire_type); + putop(c, OP_PUSHTAGDELIM); + putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); + label(c, LABEL_LOOPSTART); + putpush(c, f); + putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG)); + putop(c, OP_CALL, sub_m); + putop(c, OP_POP); + putop(c, OP_ENDSUBMSG, getsel(f, UPB_HANDLER_ENDSUBMSG)); + if (wire_type == UPB_WIRE_TYPE_DELIMITED) { + putop(c, OP_SETDELIM); + } + putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); + putchecktag(c, f, wire_type, LABEL_LOOPBREAK); + putop(c, OP_BRANCH, -LABEL_LOOPSTART); + label(c, LABEL_LOOPBREAK); + putop(c, OP_POP); + putop(c, OP_ENDSEQ, getsel(f, UPB_HANDLER_ENDSEQ)); + } else { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, wire_type, LABEL_DISPATCH); + dispatchtarget(c, method, f, wire_type); + putpush(c, f); + putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG)); + putop(c, OP_CALL, sub_m); + putop(c, OP_POP); + putop(c, OP_ENDSUBMSG, getsel(f, UPB_HANDLER_ENDSUBMSG)); + if (wire_type == UPB_WIRE_TYPE_DELIMITED) { + putop(c, OP_SETDELIM); + } + } + break; + } + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + if (upb_fielddef_isseq(f)) { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); + dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); + putop(c, OP_PUSHTAGDELIM); + putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); + label(c, LABEL_LOOPSTART); + putop(c, OP_PUSHLENDELIM); + putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR)); + putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING)); + putop(c, OP_POP); + putop(c, OP_ENDSTR, getsel(f, UPB_HANDLER_ENDSTR)); + putop(c, OP_SETDELIM); + putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); + putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_LOOPBREAK); + putop(c, OP_BRANCH, -LABEL_LOOPSTART); + label(c, LABEL_LOOPBREAK); + putop(c, OP_POP); + putop(c, OP_ENDSEQ, getsel(f, UPB_HANDLER_ENDSEQ)); + } else { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); + dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); + putop(c, OP_PUSHLENDELIM); + putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR)); + putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING)); + putop(c, OP_POP); + putop(c, OP_ENDSTR, getsel(f, UPB_HANDLER_ENDSTR)); + putop(c, OP_SETDELIM); + } + break; + default: { + opcode parse_type = (opcode)type; + assert(parse_type >= 0 && parse_type <= OP_MAX); + upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); + int wire_type = native_wire_types[upb_fielddef_descriptortype(f)]; + if (upb_fielddef_isseq(f)) { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); + dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); + putop(c, OP_PUSHLENDELIM); + putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); // Packed + label(c, LABEL_LOOPSTART); + putop(c, parse_type, sel); + putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); + putop(c, OP_BRANCH, -LABEL_LOOPSTART); + dispatchtarget(c, method, f, wire_type); + putop(c, OP_PUSHTAGDELIM); + putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); // Non-packed + label(c, LABEL_LOOPSTART); + putop(c, parse_type, sel); + putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); + putchecktag(c, f, wire_type, LABEL_LOOPBREAK); + putop(c, OP_BRANCH, -LABEL_LOOPSTART); + label(c, LABEL_LOOPBREAK); + putop(c, OP_POP); // Packed and non-packed join. + putop(c, OP_ENDSEQ, getsel(f, UPB_HANDLER_ENDSEQ)); + putop(c, OP_SETDELIM); // Could remove for non-packed by dup ENDSEQ. + } else { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, wire_type, LABEL_DISPATCH); + dispatchtarget(c, method, f, wire_type); + putop(c, parse_type, sel); + } + } + } + } + // For now we just loop back to the last field of the message (or if none, + // the DISPATCH opcode for the message. + putop(c, OP_BRANCH, -LABEL_FIELD); + label(c, LABEL_ENDMSG); + putop(c, OP_ENDMSG); + + upb_inttable_compact(&method->dispatch); +} + +// Populate "methods" with new upb_pbdecodermethod objects reachable from "md". +// "h" can be NULL, in which case the methods will not be statically bound to +// destination handlers. +// +// Returns the method for this msgdef/handlers. +// +// Note that there is a deep difference between keying the method table on +// upb_msgdef and keying it on upb_handlers. Since upb_msgdef : upb_handlers +// can be 1:many, binding a handlers statically can result in *more* methods +// being generated than if the methods are dynamically-bound. +// +// On the other hand, if/when the optimization mentioned below is implemented, +// binding to a upb_handlers can result in *fewer* methods being generated if +// many of the submessages have no handlers bound to them. +static upb_pbdecodermethod *find_methods(compiler *c, + const upb_msgdef *md, + const upb_handlers *h) { + const void *key = h ? (const void*)h : (const void*)md; + upb_value v; + if (upb_inttable_lookupptr(&c->plan->methods, key, &v)) + return upb_value_getptr(v); + upb_pbdecodermethod *method = newmethod(md, h); + // Takes ownership of method. + upb_inttable_insertptr(&c->plan->methods, key, upb_value_ptr(method)); + + upb_msg_iter i; + for(upb_msg_begin(&i, md); !upb_msg_done(&i); upb_msg_next(&i)) { + const upb_fielddef *f = upb_msg_iter_field(&i); + if (upb_fielddef_type(f) != UPB_TYPE_MESSAGE) + continue; + const upb_handlers *sub_h = h ? upb_handlers_getsubhandlers(h, f) : NULL; + + if (h && !sub_h && + upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) { + // OPT: We could optimize away the sub-method, but would have to make sure + // this field is compiled as a string instead of a submessage. + } + + find_methods(c, upb_downcast_msgdef(upb_fielddef_subdef(f)), sub_h); + } + + return method; +} + +// (Re-)compile bytecode for all messages in "msgs", ensuring that the code +// for "md" is emitted first. Overwrites any existing bytecode in "c". +static void compile_methods(compiler *c) { + // Start over at the beginning of the bytecode. + c->pc = c->plan->code; + compile_method(c, c->plan->topmethod); + + upb_inttable_iter i; + upb_inttable_begin(&i, &c->plan->methods); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); + if (method != c->plan->topmethod) { + compile_method(c, method); + } + } +} + + +/* JIT setup. ******************************************************************/ + +#ifdef UPB_USE_JIT_X64 + +static void sethandlers(upb_pbdecoderplan *p, upb_handlers *h, bool allowjit) { + p->jit_code = NULL; + + if (allowjit) { + upb_pbdecoder_jit(p); // Compile byte-code into machine code. + upb_handlers_setstartstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_start, p, + freeplan); + upb_handlers_setstring(h, UPB_BYTESTREAM_BYTES, p->jit_code, NULL, NULL); + upb_handlers_setendstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_end, p, NULL); + } else { + set_bytecode_handlers(p, h); + } +} + +static bool bind_dynamic(bool allowjit) { + // For the moment, JIT handlers always bind statically, but bytecode handlers + // never do. + return !allowjit; +} + +#else // UPB_USE_JIT_X64 + +static void sethandlers(upb_pbdecoderplan *p, upb_handlers *h, bool allowjit) { + // No JIT compiled in; use bytecode handlers unconditionally. + UPB_UNUSED(allowjit); + set_bytecode_handlers(p, h); +} + +static bool bind_dynamic(bool allowjit) { + // Bytecode handlers never bind statically. + return true; +} + +#endif // UPB_USE_JIT_X64 + + +/* Public interface ***********************************************************/ + +bool upb_pbdecoder_isdecoder(const upb_handlers *h) { + return getdecoderplan(h) != NULL; +} + +bool upb_pbdecoderplan_hasjitcode(const upb_pbdecoderplan *p) { +#ifdef UPB_USE_JIT_X64 + return p->jit_code != NULL; +#else + UPB_UNUSED(p); + return false; +#endif +} + +bool upb_pbdecoder_hasjitcode(const upb_handlers *h) { + const upb_pbdecoderplan *p = getdecoderplan(h); + if (!p) return false; + return upb_pbdecoderplan_hasjitcode(p); +} + +uint32_t *upb_pbdecoderplan_codebase(const upb_pbdecoderplan *p) { + return p->code; +} + +upb_string_handler *upb_pbdecoderplan_jitcode(const upb_pbdecoderplan *p) { +#ifdef UPB_USE_JIT_X64 + return p->jit_code; +#else + assert(false); + return NULL; +#endif +} + +const upb_handlers *upb_pbdecoder_getdesthandlers(const upb_handlers *h) { + const upb_pbdecoderplan *p = getdecoderplan(h); + if (!p) return NULL; + return p->topmethod->dest_handlers; +} + +const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest, + bool allowjit, + const void *owner) { + UPB_UNUSED(allowjit); + assert(upb_handlers_isfrozen(dest)); + const upb_msgdef *md = upb_handlers_msgdef(dest); + + upb_pbdecoderplan *p = newplan(); + compiler *c = newcompiler(p); + + if (bind_dynamic(allowjit)) { + // If binding dynamically, remove the reference against destination + // handlers. + dest = NULL; + } + + p->topmethod = find_methods(c, md, dest); + + // We compile in two passes: + // 1. all messages are assigned relative offsets from the beginning of the + // bytecode (saved in method->base). + // 2. forwards OP_CALL instructions can be correctly linked since message + // offsets have been previously assigned. + // + // Could avoid the second pass by linking OP_CALL instructions somehow. + compile_methods(c); + compile_methods(c); + p->code_end = c->pc; + +#ifdef UPB_DUMP_BYTECODE + FILE *f = fopen("/tmp/upb-bytecode", "wb"); + assert(f); + dumpbc(p->code, p->code_end, stderr); + dumpbc(p->code, p->code_end, f); + fclose(f); +#endif + + upb_handlers *h = upb_handlers_new( + UPB_BYTESTREAM, &upb_pbdecoder_frametype, owner); + sethandlers(p, h, allowjit); + + freecompiler(c); + + return h; +} diff --git a/upb/pb/compile_decoder_x64.c b/upb/pb/compile_decoder_x64.c new file mode 100644 index 0000000..214ab35 --- /dev/null +++ b/upb/pb/compile_decoder_x64.c @@ -0,0 +1,368 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2013 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + * + * Driver code for the x64 JIT compiler. + */ + +#include <dlfcn.h> +#include <stdio.h> +#include <sys/mman.h> +#include "upb/pb/decoder.h" +#include "upb/pb/decoder.int.h" +#include "upb/pb/varint.int.h" +#include "upb/shim/shim.h" + +// These defines are necessary for DynASM codegen. +// See dynasm/dasm_proto.h for more info. +#define Dst_DECL jitcompiler *jc +#define Dst_REF (jc->dynasm) +#define Dst (jc) + +// In debug mode, make DynASM do internal checks (must be defined before any +// dasm header is included. +#ifndef NDEBUG +#define DASM_CHECKS +#endif + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +#define DECODE_EOF -3 + +typedef struct { + upb_pbdecoderplan *plan; + uint32_t *pc; + + // This pointer is allocated by dasm_init() and freed by dasm_free(). + struct dasm_State *dynasm; + + // Maps bytecode pc location -> pclabel. + upb_inttable pclabels; + upb_inttable pcdefined; + + // For marking labels that should go into the generated code. + // Maps pclabel -> char* label (string is owned by the table). + upb_inttable asmlabels; + + // For checking that two asmlabels aren't defined for the same byte. + int lastlabelofs; + + // The total number of pclabels currently defined. + uint32_t pclabel_count; + + // Used by DynASM to store globals. + void **globals; + + bool usefp; + bool chkret; +} jitcompiler; + +// Functions called by codegen. +static int pclabel(jitcompiler *jc, const void *here); +static int define_pclabel(jitcompiler *jc, const void *here); +static void asmlabel(jitcompiler *jc, const char *fmt, ...); + +#include "dynasm/dasm_proto.h" +#include "dynasm/dasm_x86.h" +#include "upb/pb/compile_decoder_x64.h" + +static jitcompiler *newjitcompiler(upb_pbdecoderplan *plan) { + jitcompiler *jc = malloc(sizeof(jitcompiler)); + jc->usefp = false; + jc->chkret = false; + jc->plan = plan; + jc->pclabel_count = 0; + jc->lastlabelofs = -1; + upb_inttable_init(&jc->pclabels, UPB_CTYPE_UINT32); + upb_inttable_init(&jc->pcdefined, UPB_CTYPE_BOOL); + upb_inttable_init(&jc->asmlabels, UPB_CTYPE_PTR); + jc->globals = malloc(UPB_JIT_GLOBAL__MAX * sizeof(*jc->globals)); + + dasm_init(jc, 1); + dasm_setupglobal(jc, jc->globals, UPB_JIT_GLOBAL__MAX); + dasm_setup(jc, upb_jit_actionlist); + + return jc; +} + +static void freejitcompiler(jitcompiler *jc) { + upb_inttable_iter i; + upb_inttable_begin(&i, &jc->asmlabels); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + free(upb_value_getptr(upb_inttable_iter_value(&i))); + } + upb_inttable_uninit(&jc->asmlabels); + upb_inttable_uninit(&jc->pclabels); + upb_inttable_uninit(&jc->pcdefined); + dasm_free(jc); + free(jc->globals); + free(jc); +} + +// Returns a pclabel associated with the given arbitrary pointer. +static int pclabel(jitcompiler *jc, const void *here) { + upb_value v; + bool found = upb_inttable_lookupptr(&jc->pclabels, here, &v); + if (!found) { + upb_value_setuint32(&v, jc->pclabel_count++); + dasm_growpc(jc, jc->pclabel_count); + upb_inttable_insertptr(&jc->pclabels, here, v); + } + return upb_value_getuint32(v); +} + +// Defines a pclabel associated with the given arbitrary pointer. +// May only be called once (to avoid redefining the pclabel). +static int define_pclabel(jitcompiler *jc, const void *here) { + // Will assert-fail if it already exists. + upb_inttable_insertptr(&jc->pcdefined, here, upb_value_bool(true)); + return pclabel(jc, here); +} + +static void upb_reg_jit_gdb(jitcompiler *jc); + +// Given a pcofs relative to method, returns the machine code offset for it +// (relative to the beginning of the machine code). +int nativeofs(jitcompiler *jc, const upb_pbdecodermethod *method, int pcofs) { + void *target = jc->plan->code + method->base.ofs + pcofs; + return dasm_getpclabel(jc, pclabel(jc, target)); +} + +// Given a pcofs relative to this method's base, returns a machine code offset +// relative to pclabel(dispatch->array) (which is used in jitdispatch as the +// machine code base for dispatch table lookups). +uint32_t dispatchofs(jitcompiler *jc, const upb_pbdecodermethod *method, + int pcofs) { + int ofs1 = dasm_getpclabel(jc, pclabel(jc, method->dispatch.array)); + int ofs2 = nativeofs(jc, method, pcofs); + assert(ofs1 > 0); + assert(ofs2 > 0); + int ret = ofs2 - ofs1; + assert(ret > 0); + return ret; +} + +// Rewrites the dispatch tables into machine code offsets. +static void patchdispatch(jitcompiler *jc) { + upb_inttable_iter i; + upb_inttable_begin(&i, &jc->plan->methods); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); + upb_inttable *dispatch = &method->dispatch; + upb_inttable_iter i2; + upb_inttable_begin(&i2, dispatch); + for (; !upb_inttable_done(&i2); upb_inttable_next(&i2)) { + uintptr_t key = upb_inttable_iter_key(&i2); + if (key == 0) continue; + uint64_t val = upb_value_getuint64(upb_inttable_iter_value(&i2)); + uint64_t newval; + if (key <= UPB_MAX_FIELDNUMBER) { + // Primary slot. + uint64_t oldofs = val >> 16; + uint64_t newofs = dispatchofs(jc, method, oldofs); + newval = (val & 0xffff) | (newofs << 16); + assert((int64_t)newval > 0); + } else { + // Secondary slot. Since we have 64 bits for the value, we use an + // absolute offset. + newval = (uint64_t)(jc->plan->jit_code + nativeofs(jc, method, val)); + } + bool ok = upb_inttable_replace(dispatch, key, upb_value_uint64(newval)); + UPB_ASSERT_VAR(ok, ok); + } + } +} + +// Define for JIT debugging. +#ifdef UPB_JIT_LOAD_SO +static void load_so(jitcompiler *jc) { + // Dump to a .so file in /tmp and load that, so all the tooling works right + // (for example, debuggers and profilers will see symbol names for the JIT-ted + // code). This is the same goal of the GDB JIT code below, but the GDB JIT + // interface is only used/understood by GDB. Hopefully a standard will + // develop for registering JIT-ted code that all tools will recognize, + // rendering this obsolete. + // + // Requires that gcc is available from the command-line. + + // Convert all asm labels from pclabel offsets to machine code offsets. + upb_inttable_iter i; + upb_inttable mclabels; + upb_inttable_init(&mclabels, UPB_CTYPE_PTR); + upb_inttable_begin(&i, &jc->asmlabels); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_inttable_insert(&mclabels, + dasm_getpclabel(jc, upb_inttable_iter_key(&i)), + upb_inttable_iter_value(&i)); + } + + FILE *f = fopen("/tmp/upb-jit-code.s", "w"); + if (f) { + fputs(" .text\n\n", f); + size_t linelen = 0; + for (size_t i = 0; i < jc->plan->jit_size; i++) { + upb_value v; + if (upb_inttable_lookup(&mclabels, i, &v)) { + const char *label = upb_value_getptr(v); + // "X." makes our JIT syms recognizable as such, which we build into + // other tooling. + fprintf(f, "\n\nX.%s:\n", label); + fprintf(f, " .globl X.%s", label); + linelen = 1000; + } + if (linelen >= 77) { + linelen = fprintf(f, "\n .byte %u", jit_code[i]); + } else { + linelen += fprintf(f, ",%u", jit_code[i]); + } + } + fputs("\n", f); + fclose(f); + } else { + fprintf(stderr, "Couldn't open /tmp/upb-jit-code.s for writing/\n"); + } + + // TODO: racy + if (system("gcc -shared -o /tmp/upb-jit-code.so /tmp/upb-jit-code.s") != 0) { + abort(); + } + + jc->dl = dlopen("/tmp/upb-jit-code.so", RTLD_LAZY); + if (!jc->dl) { + fprintf(stderr, "Couldn't dlopen(): %s\n", dlerror()); + abort(); + } + + munmap(jit_code, jc->plan->jit_size); + jit_code = dlsym(jc->dl, "X.enterjit"); + if (!jit_code) { + fprintf(stderr, "Couldn't find enterjit sym\n"); + abort(); + } + + upb_inttable_uninit(&mclabels); +} +#endif + +void upb_pbdecoder_jit(upb_pbdecoderplan *plan) { + plan->debug_info = NULL; + plan->dl = NULL; + + jitcompiler *jc = newjitcompiler(plan); + emit_static_asm(jc); + jitbytecode(jc); + + int dasm_status = dasm_link(jc, &jc->plan->jit_size); + if (dasm_status != DASM_S_OK) { + fprintf(stderr, "DynASM error; returned status: 0x%08x\n", dasm_status); + abort(); + } + + char *jit_code = mmap(NULL, jc->plan->jit_size, PROT_READ | PROT_WRITE, + MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + dasm_encode(jc, jit_code); + mprotect(jit_code, jc->plan->jit_size, PROT_EXEC | PROT_READ); + upb_reg_jit_gdb(jc); + +#ifdef UPB_JIT_LOAD_SO + load_so(jc); +#endif + + jc->plan->jit_code = (upb_string_handler *)jit_code; + patchdispatch(jc); + freejitcompiler(jc); +} + +void upb_pbdecoder_freejit(upb_pbdecoderplan *plan) { + if (!plan->jit_code) return; + if (plan->dl) { + dlclose(plan->dl); + } else { + munmap(plan->jit_code, plan->jit_size); + } + free(plan->debug_info); + // TODO: unregister GDB JIT interface. +} + +// To debug JIT-ted code with GDB we need to tell GDB about the JIT-ted code +// at runtime. GDB 7.x+ has defined an interface for doing this, and these +// structure/function defintions are copied out of gdb/jit.h +// +// We need to give GDB an ELF file at runtime describing the symbols we have +// generated. To avoid implementing the ELF format, we generate an ELF file +// at compile-time and compile it in as a character string. We can replace +// a few key constants (address of JIT-ted function and its size) by looking +// for a few magic numbers and doing a dumb string replacement. +// +// Unfortunately this approach is showing its limits; we can only define one +// symbol, and this approach only works with GDB. The .so approach above is +// more reliable. + +#ifndef __APPLE__ +const unsigned char upb_jit_debug_elf_file[] = { +#include "upb/pb/jit_debug_elf_file.h" +}; + +typedef enum { + GDB_JIT_NOACTION = 0, + GDB_JIT_REGISTER, + GDB_JIT_UNREGISTER +} jit_actions_t; + +typedef struct gdb_jit_entry { + struct gdb_jit_entry *next_entry; + struct gdb_jit_entry *prev_entry; + const char *symfile_addr; + uint64_t symfile_size; +} gdb_jit_entry; + +typedef struct { + uint32_t version; + uint32_t action_flag; + gdb_jit_entry *relevant_entry; + gdb_jit_entry *first_entry; +} gdb_jit_descriptor; + +gdb_jit_descriptor __jit_debug_descriptor = {1, GDB_JIT_NOACTION, NULL, NULL}; + +void __attribute__((noinline)) __jit_debug_register_code() { + __asm__ __volatile__(""); +} + +static void upb_reg_jit_gdb(jitcompiler *jc) { + // Create debug info. + size_t elf_len = sizeof(upb_jit_debug_elf_file); + jc->plan->debug_info = malloc(elf_len); + memcpy(jc->plan->debug_info, upb_jit_debug_elf_file, elf_len); + uint64_t *p = (void *)jc->plan->debug_info; + for (; (void *)(p + 1) <= (void *)jc->plan->debug_info + elf_len; ++p) { + if (*p == 0x12345678) { + *p = (uintptr_t)jc->plan->jit_code; + } + if (*p == 0x321) { + *p = jc->plan->jit_size; + } + } + + // Register the JIT-ted code with GDB. + gdb_jit_entry *e = malloc(sizeof(gdb_jit_entry)); + e->next_entry = __jit_debug_descriptor.first_entry; + e->prev_entry = NULL; + if (e->next_entry) e->next_entry->prev_entry = e; + e->symfile_addr = jc->plan->debug_info; + e->symfile_size = elf_len; + __jit_debug_descriptor.first_entry = e; + __jit_debug_descriptor.relevant_entry = e; + __jit_debug_descriptor.action_flag = GDB_JIT_REGISTER; + __jit_debug_register_code(); +} + +#else + +static void upb_reg_jit_gdb(jitcompiler *jc) { (void)jc; } + +#endif diff --git a/upb/pb/compile_decoder_x64.dasc b/upb/pb/compile_decoder_x64.dasc new file mode 100644 index 0000000..0bddade --- /dev/null +++ b/upb/pb/compile_decoder_x64.dasc @@ -0,0 +1,1087 @@ +|// +|// upb - a minimalist implementation of protocol buffers. +|// +|// Copyright (c) 2011-2013 Google Inc. See LICENSE for details. +|// Author: Josh Haberman <jhaberman@gmail.com> +|// +|// JIT compiler for upb_pbdecoder on x86-64. Generates machine code from the +|// bytecode generated in compile_decoder.c, but unlike the interpreter we bind +|// to a specific set of handlers for greater efficiency. +| +|.arch x64 +|.actionlist upb_jit_actionlist +|.globals UPB_JIT_GLOBAL_ +|.globalnames upb_jit_globalnames +| +|// Calling conventions. Note -- this will need to be changed for +|// Windows, which uses a different calling convention! +|.define ARG1_64, rdi +|.define ARG2_8, r6b // DynASM's equivalent to "sil" -- low byte of esi. +|.define ARG2_32, esi +|.define ARG2_64, rsi +|.define ARG3_8, dl +|.define ARG3_32, edx +|.define ARG3_64, rdx +|.define ARG4_64, rcx +|.define XMMARG1, xmm0 +| +|// Register allocation / type map. +|// ALL of the code in this file uses these register allocations. +|// When we "call" within this file, we do not use regular calling +|// conventions, but of course when calling to user callbacks we must. +|.define PTR, rbx // DECODER->ptr (unsynced) +|.define DATAEND, r12 // DECODER->data_end (unsynced) +|.define CLOSURE, r13 // FRAME->closure (unsynced) +|.type FRAME, upb_pbdecoder_frame, r14 // DECODER->top (unsynced) +|.type DECODER, upb_pbdecoder, r15 // DECODER (immutable) +|.define DELIMEND, rbp +| +| // Spills unsynced registers back to memory. +|.macro commit_regs +| mov DECODER->top, FRAME +| mov DECODER->ptr, PTR +| mov DECODER->data_end, DATAEND +| sub DELIMEND, DECODER->buf +| add DELIMEND, DECODER->bufstart_ofs +| mov FRAME->end_ofs, DELIMEND +| mov FRAME->u.closure, CLOSURE +|.endmacro +| +| // Loads unsynced registers from memory back into registers. +|.macro load_regs +| mov FRAME, DECODER->top +| mov PTR, DECODER->ptr +| mov DATAEND, DECODER->data_end +| mov CLOSURE, FRAME->u.closure +| mov DELIMEND, FRAME->end_ofs +| sub DELIMEND, DECODER->bufstart_ofs +| add DELIMEND, DECODER->buf +|.endmacro +| +| // OPT: use "call rel32" where possible. +|.macro callp, addr +|| { +|| //int64_t ofs = (int64_t)addr - (int64_t)upb_status_init; +|| //if (ofs > (1 << 30) || ofs < -(1 << 30)) { +| mov64 rax, (uintptr_t)addr +| call rax +|| //} else { +| // call &addr +|| //} +|| } +|.endmacro +| +|.macro ld64, val +|| { +|| uintptr_t v = (uintptr_t)val; +|| if (v > 0xffffffff) { +| mov64 ARG2_64, v +|| } else if (v) { +| mov ARG2_32, v +|| } else { +| xor ARG2_32, ARG2_32 +|| } +|| } +|.endmacro +| +|.macro load_handler_data, h, arg +| ld64 upb_handlers_gethandlerdata(h, arg) +|.endmacro +| +|.macro chkeob, bytes, target +|| if (bytes == 1) { +| cmp PTR, DATAEND +| je target +|| } else { +| mov rcx, DATAEND +| sub rcx, PTR +| cmp rcx, bytes +| jb target +|| } +|.endmacro +| +|.macro chkneob, bytes, target +|| if (bytes == 1) { +| cmp PTR, DATAEND +| jne target +|| } else { +| mov rcx, DATAEND +| sub rcx, PTR +| cmp rcx, bytes +| jae target +|| } +|.endmacro + +|.macro sethas, reg, hasbit +|| if (hasbit >= 0) { +| or byte [reg + ((uint32_t)hasbit / 8)], (1 << ((uint32_t)hasbit % 8)) +|| } +|.endmacro +| +| // Decodes 32-bit varint into rdx, inlining 1 byte. +|.macro dv32 +| chkeob 1, >7 +| movzx edx, byte [PTR] +| test dl, dl +| jns >8 +|7: +| call ->decodev32_fallback +|8: +| add PTR, 1 +|.endmacro + +static void asmlabel(jitcompiler *jc, const char *fmt, ...) { + int ofs = jc->dynasm->section->ofs; + assert(ofs != jc->lastlabelofs); + jc->lastlabelofs = ofs; + va_list args; + va_start(args, fmt); + + // Run once to get the length of the string. + va_list args_copy; + va_copy(args_copy, args); + int len = vsnprintf(NULL, 0, fmt, args_copy); + va_end(args_copy); + + char *str = malloc(len + 1); // + 1 for NULL terminator. + if (!str) exit(1); + int written = vsnprintf(str, len, fmt, args); + va_end(args); + UPB_ASSERT_VAR(written, written == len); + + uint32_t label = jc->pclabel_count++; + dasm_growpc(jc, jc->pclabel_count); + |=>label: + upb_inttable_insert(&jc->asmlabels, label, upb_value_ptr(str)); +} + +// Emit static assembly routines; code that does not vary based on the message +// schema. Since it's not input-dependent, we only need one single copy of it. +// For the moment we generate a single copy per generated handlers. Eventually +// we should generate this code at compile time and link it into the binary so +// we have one copy total. To do that we'll want to be sure that it is within +// 2GB of our JIT code, so that branches between the two are near (rel32). +// +// We'd put this assembly in a .s file directly, but DynASM's ability to +// calculate structure offsets automatically is too useful to pass up (it's way +// more convenient to write DECODER->sink than [rbx + 0x96], especially since +// the latter would have to be changed whenever the structure is updated). +static void emit_static_asm(jitcompiler *jc) { + | // Trampolines for entering/exiting the JIT. These are a bit tricky to + | // support full resuming; when we suspend we copy the JIT's portion of + | // the call stack into the upb_pbdecoder and restore it when we resume. + asmlabel(jc, "enterjit"); + |->enterjit: + |1: + | push rbp + if (jc->usefp) { + | mov rbp, rsp + } + | push r15 + | push r14 + | push r13 + | push r12 + | push rbx + | + | // Align stack. + | // Since the JIT can call other functions (the JIT'ted code is not a leaf + | // function) we must respect alignment rules. All x86-64 systems require + | // 16-byte stack alignment. + | sub rsp, 8 + | + | mov DECODER, rdi + | callp upb_pbdecoder_resume // Same args as us; reuse regs. + | mov DECODER->saved_rsp, rsp + | load_regs + | + | // Test whether we have a saved stack to resume. + | mov ARG3_64, DECODER->call_len + | test ARG3_64, ARG3_64 + | jnz >1 + | + | call =>pclabel(jc, jc->plan->topmethod) + | + | mov rax, DECODER->size_param + | mov qword DECODER->call_len, 0 + | add rsp, 8 // Counter previous alignment. + | pop rbx + | pop r12 + | pop r13 + | pop r14 + | pop r15 + | pop rbp + | ret + | + |1: + | // Resume decoder. + | lea ARG2_64, DECODER->callstack + | sub rsp, ARG3_64 + | mov ARG1_64, rsp + | callp memcpy // Restore stack. + | ret // Return to resumed function (not ->enterjit caller). + | + | // Other code can call this to suspend the JIT. + | // To the calling code, it will appear that the function returns when + | // the JIT resumes, and more buffer space will be available. + | // Args: eax=the value that decode() should return. + asmlabel(jc, "exitjit"); + |->exitjit: + | // Save the stack into DECODER->callstack. + | lea ARG1_64, DECODER->callstack + | mov ARG2_64, rsp + | mov ARG3_64, DECODER->saved_rsp + | sub ARG3_64, rsp + | mov DECODER->call_len, ARG3_64 // Preserve len for next resume. + | mov ebx, eax // Preserve return value across memcpy. + | callp memcpy // Copy stack into decoder. + | mov eax, ebx // This will be our return value. + | + | // Must NOT do this before the memcpy(), otherwise memcpy() will + | // clobber the stack we are trying to save! + | mov rsp, DECODER->saved_rsp + | add rsp, 8 // Counter previous alignment. + | pop rbx + | pop r12 + | pop r13 + | pop r14 + | pop r15 + | pop rbp + | ret + | + | // Like suspend() in the C decoder, except that the function appears + | // (from the caller's perspective) not to return until the decoder is + | // resumed. + asmlabel(jc, "suspend"); + |->suspend: + | cmp DECODER->ptr, PTR + | je >1 + | mov DECODER->checkpoint, PTR + |1: + | commit_regs + | mov rdi, DECODER + | callp upb_pbdecoder_suspend + | jmp ->exitjit + | + asmlabel(jc, "pushlendelim"); + |->pushlendelim: + |1: + | mov FRAME->u.closure, CLOSURE + | mov DECODER->checkpoint, PTR + | dv32 + | mov rcx, DELIMEND + | sub rcx, PTR + | sub rcx, rdx + | jb ->err // Len is greater than enclosing message. + | mov FRAME->end_ofs, rcx + | add FRAME, sizeof(upb_pbdecoder_frame) + | mov DELIMEND, PTR + | add DELIMEND, rdx + | cmp FRAME, DECODER->limit + | je >3 // Stack overflow + | test rcx, rcx + | jz >2 + | mov DATAEND, DECODER->end + | cmp PTR, DELIMEND + | ja >2 + | cmp DELIMEND, DATAEND + | ja >2 + | mov DATAEND, DELIMEND // If DELIMEND >= PTR && DELIMEND < DATAEND + |2: + | ret + |3: + | // Error -- call seterr. + | mov PTR, DECODER->checkpoint // Rollback to before the delim len. + | // Prepare seterr args. + | mov ARG1_64, DECODER + | ld64 kPbDecoderStackOverflow + | callp upb_pbdecoder_seterr + | call ->suspend + | jmp <1 + | + | // For getting a value that spans a buffer seam. Falls back to C. + | // Args: rdi=C decoding function (prototype: int f(upb_pbdecoder*, void*)) + asmlabel(jc, "getvalue_slow"); + |->getvalue_slow: + | sub rsp, 16 // Stack is [8-byte value, 8-byte func pointer] + | mov [rsp + 8], rdi // Need to preserve fptr across suspends. + |1: + | mov qword [rsp], 0 // For parsing routines that only parse 32 bits. + | mov ARG1_64, DECODER + | mov ARG2_64, rsp + | mov DECODER->checkpoint, PTR + | commit_regs + | call aword [rsp + 8] + | load_regs + | test eax, eax + | jns >2 + | // Success; return parsed data (in rdx AND xmm0). + | mov rdx, [rsp] + | movsd xmm0, qword [rsp] + | add rsp, 16 + | ret + |2: + | call ->exitjit // Return eax from decode function. + | jmp <1 + | + asmlabel(jc, "parse_unknown"); + | // Args: edx=fieldnum, cl=wire type + |->parse_unknown: + | // OPT: handle directly instead of kicking to C. + | // Check for ENDGROUP. + | mov ARG1_64, DECODER + | mov ARG2_32, edx + | movzx ARG3_32, cl + | commit_regs + | callp upb_pbdecoder_skipunknown + | load_regs + | cmp eax, DECODE_ENDGROUP + | jne >1 + | ret // Return eax=DECODE_ENDGROUP, not zero + |1: + | cmp eax, DECODE_OK + | je >1 + | call ->exitjit // Return eax from decode function. + |1: + | xor eax, eax + | ret + | + | // Fallback functions for parsing single values. These are used when the + | // buffer doesn't contain enough remaining data for the fast path. Each + | // primitive type (v32, v64, f32, f64) has two functions: decode & skip. + | // Decode functions return their value in rsi/esi. + | // + | // These functions leave PTR = value_end - fast_path_bytes, so that we can + | // re-join the fast path which will add fast_path_bytes after the callback + | // completes. We also set DECODER->ptr to this value which is a signal to + | // ->suspend that DECODER->checkpoint is up to date. + asmlabel(jc, "skip_decode_f32_fallback"); + |->skipf32_fallback: + |->decodef32_fallback: + | mov64 rdi, (uintptr_t)upb_pbdecoder_decode_f32 + | call ->getvalue_slow + | sub PTR, 4 + | mov DECODER->ptr, PTR + | ret + | + asmlabel(jc, "skip_decode_f64_fallback"); + |->skipf64_fallback: + |->decodef64_fallback: + | mov64 rdi, (uintptr_t)upb_pbdecoder_decode_f64 + | call ->getvalue_slow + | sub PTR, 8 + | mov DECODER->ptr, PTR + | ret + | + | // Called for varint >= 1 byte. + asmlabel(jc, "skip_decode_v32_fallback"); + |->skipv32_fallback: + |->skipv64_fallback: + | chkeob 16, >1 + | // With at least 16 bytes left, we can do a branch-less SSE version. + | movdqu xmm0, [PTR] + | pmovmskb eax, xmm0 // bits 0-15 are continuation bits, 16-31 are 0. + | not eax + | bsf eax, eax + | cmp al, 10 + | jae ->decode_varint_slow // Error (>10 byte varint). + | add PTR, rax // bsf result is 0-based, so PTR=end-1, as desired. + | ret + | + |1: + | // With fewer than 16 bytes, we have to read byte by byte. + | lea rcx, [PTR + 10] + | mov rax, PTR // Preserve PTR in case of fallback to slow path. + | cmp rcx, DATAEND + | cmova rcx, DATAEND // rax = MIN(DATAEND, PTR + 10) + |2: + | add rax, 1 + | cmp rax, rcx + | je ->decode_varint_slow + | test byte [rax], 0x80 + | jnz <2 + |3: + | mov PTR, rax // PTR = varint_end - 1, as desired + | ret + | + | // Returns tag in edx + asmlabel(jc, "decode_unknown_tag_fallback"); + |->decode_unknown_tag_fallback: + | sub rsp, 16 + |1: + | cmp PTR, DELIMEND + | jne >2 + | add rsp, 16 + | xor eax, eax + | ret + |2: + | // OPT: Have a medium-fast path before falling back to _slow. + | mov ARG1_64, DECODER + | mov ARG2_64, rsp + | commit_regs + | callp upb_pbdecoder_decode_varint_slow + | load_regs + | cmp eax, 0 + | jge >3 + | mov edx, [rsp] // Success; return parsed data. + | add rsp, 16 + | ret + |3: + | call ->exitjit // Return eax from decode function. + | jmp <1 + | + | // Called for varint >= 1 byte. + asmlabel(jc, "decode_v32_v64_fallback"); + |->decodev32_fallback: + |->decodev64_fallback: + | chkeob 10, ->decode_varint_slow + | // OPT: do something faster than just calling the C version. + | mov rdi, PTR + | callp upb_vdecode_fast + | test rax, rax + | je ->decode_varint_slow // Unterminated varint. + | mov PTR, rax + | sub PTR, 1 + | mov DECODER->ptr, PTR + | ret + | + asmlabel(jc, "decode_varint_slow"); + |->decode_varint_slow: + | // Slow path: end of buffer or error (varint length >= 10). + | mov64 rdi, (uintptr_t)upb_pbdecoder_decode_varint_slow + | call ->getvalue_slow + | sub PTR, 1 + | mov DECODER->ptr, PTR + | ret + | + | // Args: rsi=expected tag, return=rax (DECODE_{OK,MISMATCH}) + asmlabel(jc, "checktag_fallback"); + |->checktag_fallback: + | sub rsp, 8 + | mov [rsp], rsi // Preserve expected tag. + |1: + | mov ARG1_64, DECODER + | commit_regs + | mov DECODER->checkpoint, PTR + | callp upb_pbdecoder_checktag_slow + | load_regs + | cmp eax, 0 + | jge >2 + | add rsp, 8 + | ret + |2: + | call ->exitjit + | mov rsi, [rsp] + | cmp PTR, DELIMEND + | jne <1 + | mov eax, DECODE_EOF + | add rsp, 8 + | ret + | + | // Args: rsi=upb_inttable, rdx=key, return=rax (-1 if not found). + | // Preserves: rcx, rdx + | // OPT: Could write this in assembly if it's a hotspot. + asmlabel(jc, "hashlookup"); + |->hashlookup: + | push rcx + | push rdx + | sub rsp, 16 + | mov rdi, rsi + | mov rsi, rdx + | mov rdx, rsp + | callp upb_inttable_lookup + | add rsp, 16 + | pop rdx + | pop rcx + | test al, al + | jz >2 // Unknown field. + | mov rax, [rsp-32] // Value from table. + | ret + |2: + | xor rax, rax + | not rax + | ret +} + +static void jitprimitive(jitcompiler *jc, opcode op, + const upb_handlers *h, upb_selector_t sel) { + typedef enum { V32, V64, F32, F64, X } valtype_t; + static valtype_t types[] = { + X, F64, F32, V64, V64, V32, F64, F32, V64, X, X, X, X, V32, V32, F32, F64, + V32, V64 }; + static char fastpath_bytes[] = { 1, 1, 4, 8 }; + const valtype_t type = types[op]; + const int fastbytes = fastpath_bytes[type]; + upb_func *handler = upb_handlers_gethandler(h, sel); + + if (handler) { + |1: + | chkneob fastbytes, >3 + |2: + switch (type) { + case V32: + | call ->decodev32_fallback + break; + case V64: + | call ->decodev64_fallback + break; + case F32: + | call ->decodef32_fallback + break; + case F64: + | call ->decodef64_fallback + break; + case X: break; + } + | jmp >4 + + // Fast path decode; for when check_bytes bytes are available. + |3: + switch (op) { + case OP_PARSE_SFIXED32: + case OP_PARSE_FIXED32: + | mov edx, dword [PTR] + break; + case OP_PARSE_SFIXED64: + case OP_PARSE_FIXED64: + | mov rdx, qword [PTR] + break; + case OP_PARSE_FLOAT: + | movss xmm0, dword [PTR] + break; + case OP_PARSE_DOUBLE: + | movsd xmm0, qword [PTR] + break; + default: + // Inline one byte of varint decoding. + | movzx edx, byte [PTR] + | test dl, dl + | js <2 // Fallback to slow path for >1 byte varint. + break; + } + + // Second-stage decode; used for both fast and slow paths + // (only needed for a few types). + |4: + switch (op) { + case OP_PARSE_SINT32: + // 32-bit zig-zag decode. + | mov eax, edx + | shr edx, 1 + | and eax, 1 + | neg eax + | xor edx, eax + break; + case OP_PARSE_SINT64: + // 64-bit zig-zag decode. + | mov rax, rdx + | shr rdx, 1 + | and rax, 1 + | neg rax + | xor rdx, rax + break; + case OP_PARSE_BOOL: + | test rdx, rdx + | setne dl + break; + default: break; + } + + // Call callback (or specialize if we can). + upb_fieldtype_t type; + const upb_shim_data *data = upb_shim_getdata(h, sel, &type); + if (data) { + switch (type) { + case UPB_TYPE_INT64: + case UPB_TYPE_UINT64: + | mov [CLOSURE + data->offset], rdx + break; + case UPB_TYPE_INT32: + case UPB_TYPE_UINT32: + case UPB_TYPE_ENUM: + | mov [CLOSURE + data->offset], edx + break; + case UPB_TYPE_DOUBLE: + | movsd qword [CLOSURE + data->offset], XMMARG1 + break; + case UPB_TYPE_FLOAT: + | movss dword [CLOSURE + data->offset], XMMARG1 + break; + case UPB_TYPE_BOOL: + | mov [CLOSURE + data->offset], dl + break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + case UPB_TYPE_MESSAGE: + assert(false); break; + } + | sethas CLOSURE, data->hasbit + } else if (handler) { + | mov ARG1_64, CLOSURE + | load_handler_data h, sel + | callp handler + if (jc->chkret) { + | test al, al + | jz >5 + | call ->suspend + | jmp <1 + |5: + } + } + + // We do this last so that the checkpoint is not advanced past the user's + // data until the callback has returned success. + | add PTR, fastbytes + } else { + // No handler registered for this value, just skip it. + | chkneob fastbytes, >3 + |2: + switch (type) { + case V32: + | call ->skipv32_fallback + break; + case V64: + | call ->skipv64_fallback + break; + case F32: + | call ->skipf32_fallback + break; + case F64: + | call ->skipf64_fallback + break; + case X: break; + } + + // Fast-path skip. + |3: + if (type == V32 || type == V64) { + | test byte [PTR], 0x80 + | jnz <2 + } + | add PTR, fastbytes + } +} + +static void jitdispatch(jitcompiler *jc, + const upb_pbdecodermethod *method) { + // Lots of room for tweaking/optimization here. + + const upb_inttable *dispatch = &method->dispatch; + bool has_hash_entries = (dispatch->t.count > 0); + + // Whether any of the fields for this message can have two wire types which + // are both valid (packed & non-packed). + // + // OPT: populate this more precisely; not all messages with hash entries have + // this characteristic. + bool has_multi_wiretype = has_hash_entries; + + |=>define_pclabel(jc, &method->dispatch): + |1: + // Decode the field tag. + // OPT: inline two bytes of varint decoding for big messages. + | mov aword DECODER->checkpoint, PTR + | chkeob 1, >6 + | movzx edx, byte [PTR] + | test dl, dl + | jns >7 + |6: + | call ->decode_unknown_tag_fallback + | test eax, eax // Hit DELIMEND? + | jnz >8 + | ret + |7: + | add PTR, 1 + |8: + | mov ecx, edx + | shr edx, 3 + | and cl, 7 + + // See comment attached to upb_pbdecodermethod.dispatch for layout of the + // dispatch table. + |2: + | cmp edx, dispatch->array_size + if (has_hash_entries) { + | jae >7 + } else { + | jae >5 + } + | // OPT: Compact the lookup arr into 32-bit entries. + if ((uintptr_t)dispatch->array > 0x7fffffff) { + | mov64 rax, (uintptr_t)dispatch->array + | mov rax, qword [rax + rdx * 8] + } else { + | mov rax, qword [rdx * 8 + dispatch->array] + } + |3: + | // We take advantage of the fact that non-present entries are stored + | // as -1, which will result in wire types that will never match. + | cmp al, cl + if (has_multi_wiretype) { + | jne >6 + } else { + | jne >5 + } + | shr rax, 16 + | lea rdx, [>4] + |=>define_pclabel(jc, dispatch->array): + |4: + | add rax, rdx + | ret + | + |5: + | // Field isn't in our table. + | call ->parse_unknown + | test eax, eax // ENDGROUP? + | jz <1 + | lea rax, [>9] // ENDGROUP; Load address of OP_ENDMSG. + | ret + + if (has_multi_wiretype) { + |6: + | // Primary wire type didn't match, check secondary wire type. + | cmp ah, cl + | jne <5 + | // Secondary wire type is a match, look up fn + UPB_MAX_FIELDNUMBER. + | add rdx, UPB_MAX_FIELDNUMBER + | // This key will never be in the array part, so do a hash lookup. + assert(has_hash_entries); + | ld64 dispatch + | jmp ->hashlookup // Tail call. + } + + if (has_hash_entries) { + |7: + | // Hash table lookup. + | ld64 dispatch + | call ->hashlookup + | jmp <3 + } +} + +static void jittag(jitcompiler *jc, uint64_t tag, int n, int ofs, + const upb_pbdecodermethod *method) { + // Internally we parse unknown fields; if this runs us into DELIMEND we jump + // to the corresponding DELIMEND target (either msg end or repeated field + // end), which we find from the OP_CHECKDELIM which must have necessarily + // preceded us. + uint32_t last_instruction = *(jc->pc - 2); + int last_arg = (int32_t)last_instruction >> 8; + assert((last_instruction & 0xff) == OP_CHECKDELIM); + uint32_t *delimend = (jc->pc - 1) + last_arg; + const size_t ptr_words = sizeof(void*) / sizeof(uint32_t); + + if (getop(*(jc->pc - 1)) == OP_TAGN) { + jc->pc += ptr_words; + } + + | chkneob n, >1 + + | // OPT: this is way too much fallback code to put here. + | // Reduce and/or move to a separate section to make better icache usage. + | ld64 tag + | call ->checktag_fallback + | cmp eax, DECODE_MISMATCH + | je >3 + | cmp eax, DECODE_EOF + | je =>pclabel(jc, delimend) + | jmp >5 + + |1: + switch (n) { + case 1: + | cmp byte [PTR], tag + break; + case 2: + | cmp word [PTR], tag + break; + case 3: + | // OPT: Slightly more efficient code, but depends on an extra byte. + | // mov eax, dword [PTR] + | // shl eax, 8 + | // cmp eax, tag << 8 + | cmp word [PTR], (tag & 0xffff) + | jne >2 + | cmp byte [PTR + 2], (tag >> 16) + |2: + break; + case 4: + | cmp dword [PTR], tag + break; + case 5: + | cmp dword [PTR], (tag & 0xffffffff) + | jne >3 + | cmp byte [PTR + 4], (tag >> 32) + } + | je >4 + |3: + if (ofs == 0) { + | call =>pclabel(jc, &method->dispatch) + | test rax, rax + | jz =>pclabel(jc, delimend) + | jmp rax + } else { + | jmp =>pclabel(jc, jc->pc + ofs) + } + |4: + | add PTR, n + |5: +} + +// Emit message-specific assembly. Overall code layout is: +// +---------------------------------------------------------------------------+ +// | Message A | +// | 1. function prologue (startmsg), jmps to OP_CHECKDELIM_RET before first | +// | OP_TAG* in 4. | +// | 2. function epilogue (endmsg), returns from function. | +// | 3. dispatch function (returns fptr to 4) | +// | - loops internally to skip unknown fields | +// | - after each unknown field does OP_CHECKDELIM_RET (returns 2) | +// | - also returns 2 for END_GROUP. +// | 4. code for each op: | +// | - OP_TAG* on mismatch calls 3 to get addr, then jumps to 4 (or 2 on EOM).| +// | - OP_CHECKDELIM_RET jumps to 2 | +// +---------------------------------------------------------------------------+ +// | Message B | +// | 1. ... | +// | ... | +// +---------------------------------------------------------------------------+ +static void jitbytecode(jitcompiler *jc) { + upb_pbdecodermethod *method = NULL; + const upb_handlers *h = NULL; + for (jc->pc = jc->plan->code; jc->pc < jc->plan->code_end; ) { + int32_t instr = *jc->pc; + opcode op = instr & 0xff; + uint32_t arg = instr >> 8; + int32_t longofs = arg; + + if (op != OP_STARTMSG && op != OP_SETDISPATCH) { + asmlabel(jc, "0x%lx.%s", jc->pc - jc->plan->code, + upb_pbdecoder_getopname(op)); + } + // TODO: optimize this to only define pclabels that are actually used. + |=>define_pclabel(jc, jc->pc): + jc->pc++; + + switch (op) { + case OP_STARTMSG: { + // This opcode serves as a function prolouge also. + const char *msgname = upb_msgdef_fullname(method->msg); + asmlabel(jc, "parse.%s", msgname); + |=>define_pclabel(jc, method): + if (jc->usefp) { + | push rbp + | mov rbp, rsp + } else { + | sub rsp, 8 + } + upb_func *startmsg = upb_handlers_gethandler(h, UPB_STARTMSG_SELECTOR); + if (startmsg) { + // bool startmsg(void *closure, const void *hd) + |1: + | mov ARG1_64, CLOSURE + | load_handler_data h, UPB_STARTMSG_SELECTOR + | callp startmsg + if (jc->chkret) { + | test al, al + | jnz <2 + | call ->suspend + |2: + } + } + break; + } + case OP_ENDMSG: { + // This opcode serves as a function epiloue also. + upb_func *endmsg = upb_handlers_gethandler(h, UPB_ENDMSG_SELECTOR); + |9: + if (endmsg) { + // bool endmsg(void *closure, const void *hd, upb_status *status) + | mov ARG1_64, CLOSURE + | load_handler_data h, UPB_ENDMSG_SELECTOR + | mov ARG3_64, DECODER->status + | callp endmsg + } + if (jc->usefp) { + | pop rbp + } else { + | add rsp, 8 + } + | ret + break; + } + case OP_SETDISPATCH: { + upb_inttable *dispatch; + memcpy(&dispatch, jc->pc, sizeof(void*)); + jc->pc += sizeof(void*) / sizeof(uint32_t); + // The OP_SETDISPATCH bytecode contains a pointer that is + // &method->dispatch; we want to go backwards and recover method. + method = + (void*)((char*)dispatch - offsetof(upb_pbdecodermethod, dispatch)); + h = method->dest_handlers; + assert(h); // We only support statically-bound handlers for now. + const char *msgname = upb_msgdef_fullname(method->msg); + asmlabel(jc, "dispatch.%s", msgname); + jitdispatch(jc, method); + break; + } + case OP_PARSE_DOUBLE: + case OP_PARSE_FLOAT: + case OP_PARSE_INT64: + case OP_PARSE_UINT64: + case OP_PARSE_INT32: + case OP_PARSE_FIXED64: + case OP_PARSE_FIXED32: + case OP_PARSE_BOOL: + case OP_PARSE_UINT32: + case OP_PARSE_SFIXED32: + case OP_PARSE_SFIXED64: + case OP_PARSE_SINT32: + case OP_PARSE_SINT64: + jitprimitive(jc, op, h, arg); + break; + case OP_STARTSEQ: + case OP_STARTSUBMSG: + case OP_STARTSTR: { + upb_func *start = upb_handlers_gethandler(h, arg); + if (start) { + // void *startseq(void *closure, const void *hd) + // void *startsubmsg(void *closure, const void *hd) + // void *startstr(void *closure, const void *hd, size_t size_hint) + |1: + | mov ARG1_64, CLOSURE + | load_handler_data h, arg + if (op == OP_STARTSTR) { + | mov ARG3_64, DELIMEND + | sub ARG3_64, PTR + } + | callp start + if (jc->chkret) { + | test rax, rax + | jnz >2 + | call ->suspend + | jmp <1 + |2: + } + | mov CLOSURE, rax + } else { + // TODO: nop is only required because of asmlabel(). + | nop + } + break; + } + case OP_ENDSEQ: + case OP_ENDSUBMSG: + case OP_ENDSTR: { + upb_func *end = upb_handlers_gethandler(h, arg); + if (end) { + // bool endseq(void *closure, const void *hd) + // bool endsubmsg(void *closure, const void *hd) + // bool endstr(void *closure, const void *hd) + |1: + | mov ARG1_64, CLOSURE + | load_handler_data h, arg + | callp end + if (jc->chkret) { + | test al, al + | jnz >2 + | call ->suspend + | jmp <1 + |2: + } + } else { + // TODO: nop is only required because of asmlabel(). + | nop + } + break; + } + case OP_STRING: { + upb_func *str = upb_handlers_gethandler(h, arg); + | cmp PTR, DELIMEND + | je >4 + |1: + | cmp PTR, DATAEND + | jne >2 + | call ->suspend + | jmp <1 + |2: + if (str) { + // size_t str(void *closure, const void *hd, const char *str, size_t n) + | mov ARG1_64, CLOSURE + | load_handler_data h, arg + | mov ARG3_64, PTR + | mov ARG4_64, DATAEND + | sub ARG4_64, PTR + | callp str + | add PTR, rax + if (jc->chkret) { + | cmp PTR, DATAEND + | je >3 + | call ->strret_fallback + |3: + } + } else { + | mov PTR, DATAEND + } + | cmp PTR, DELIMEND + | jne <1 + |4: + break; + } + case OP_PUSHTAGDELIM: + | mov FRAME->u.closure, CLOSURE + | add FRAME, sizeof(upb_pbdecoder_frame) + | cmp FRAME, DECODER->limit + | je ->err + break; + case OP_PUSHLENDELIM: + | call ->pushlendelim + break; + case OP_POP: + | sub FRAME, sizeof(upb_pbdecoder_frame) + | mov CLOSURE, FRAME->u.closure + break; + case OP_SETDELIM: + // OPT: experiment with testing vs old offset to optimize away. + | mov DATAEND, DECODER->end + | add DELIMEND, FRAME->end_ofs + | jc >1 + | cmp DELIMEND, DATAEND + | ja >1 // OPT: try cmov. + | mov DATAEND, DELIMEND + |1: + break; + case OP_SETGROUPNUM: + | mov dword FRAME->groupnum, arg + break; + case OP_SETBIGGROUPNUM: + | mov dword FRAME->groupnum, *jc->pc++ + break; + case OP_CHECKDELIM: + | cmp DELIMEND, PTR + | je =>pclabel(jc, jc->pc + longofs) + break; + case OP_CALL: + | call =>pclabel(jc, jc->pc + longofs + 3) + break; + case OP_BRANCH: + | jmp =>pclabel(jc, jc->pc + longofs); + break; + case OP_TAG1: + jittag(jc, (arg >> 8) & 0xff, 1, (int8_t)arg, method); + break; + case OP_TAG2: + jittag(jc, (arg >> 8) & 0xffff, 2, (int8_t)arg, method); + break; + case OP_TAGN: { + uint64_t tag; + memcpy(&tag, jc->pc, 8); + jittag(jc, tag, arg >> 8, (int8_t)arg, method); + break; + } + case OP_HALT: + assert(false); + } + } + asmlabel(jc, "eof"); + | nop +} diff --git a/upb/pb/decoder.c b/upb/pb/decoder.c index 18bb430..0cfb12e 100644 --- a/upb/pb/decoder.c +++ b/upb/pb/decoder.c @@ -1,208 +1,63 @@ /* * upb - a minimalist implementation of protocol buffers. * - * Copyright (c) 2008-2011 Google Inc. See LICENSE for details. + * Copyright (c) 2008-2013 Google Inc. See LICENSE for details. * Author: Josh Haberman <jhaberman@gmail.com> */ #include <inttypes.h> #include <setjmp.h> +#include <stdarg.h> #include <stddef.h> #include <stdlib.h> #include "upb/bytestream.h" -#include "upb/pb/decoder.h" -#include "upb/pb/varint.h" +#include "upb/pb/decoder.int.h" +#include "upb/pb/varint.int.h" -#define UPB_NONDELIMITED (0xffffffffffffffffULL) - -/* upb_pbdecoder ****************************************************************/ - -struct dasm_State; - -typedef struct { - const upb_fielddef *f; - uint64_t end_ofs; - uint32_t group_fieldnum; // UINT32_MAX for non-groups. - bool is_sequence; // frame represents seq or submsg/str? (f might be both). - bool is_packed; // true for packed primitive sequences. -} frame; - -struct upb_pbdecoder { - // Where we push parsed data (not owned). - upb_sink *sink; - - // Current input buffer and its stream offset. - const char *buf, *ptr, *end, *checkpoint; - uint64_t bufstart_ofs; - - // Buffer for residual bytes not parsed from the previous buffer. - char residual[16]; - char *residual_end; - - // Stores the user buffer passed to our decode function. - const char *buf_param; - size_t size_param; - - // Equal to size_param while we are in the residual buf, 0 otherwise. - size_t userbuf_remaining; - - // Used to temporarily store the return value before calling longjmp(). - size_t ret; - - // End of the delimited region, relative to ptr, or NULL if not in this buf. - const char *delim_end; - -#ifdef UPB_USE_JIT_X64 - // For JIT, which doesn't do bounds checks in the middle of parsing a field. - const char *jit_end, *effective_end; // == MIN(jit_end, delim_end) - - // Used momentarily by the generated code to store a value while a user - // function is called. - uint32_t tmp_len; - - const void *saved_rbp; +#ifdef UPB_DUMP_BYTECODE +#include <stdio.h> #endif - // Our internal stack. - frame *top, *limit; - frame stack[UPB_MAX_NESTING]; - - // For exiting the decoder on error. - jmp_buf exitjmp; -}; - -typedef struct { - // The top-level handlers that this plan calls into. We own a ref. - const upb_handlers *dest_handlers; - -#ifdef UPB_USE_JIT_X64 - // JIT-generated machine code (else NULL). - char *jit_code; - size_t jit_size; - char *debug_info; - - // For storing upb_jitmsginfo, which contains per-msg runtime data needed - // by the JIT. - // Maps upb_handlers* -> upb_jitmsginfo. - upb_inttable msginfo; - - // The following members are used only while the JIT is being built. - - // This pointer is allocated by dasm_init() and freed by dasm_free(). - struct dasm_State *dynasm; - - // For storing pclabel bases while we are building the JIT. - // Maps (upb_handlers* or upb_fielddef*) -> int32 pclabel_base - upb_inttable pclabels; - - // For marking labels that should go into the generated code. - // Maps pclabel -> owned char* label. - upb_inttable asmlabels; - - // This is not the same as len(pclabels) because the table only contains base - // offsets for each def, but each def can have many pclabels. - uint32_t pclabel_count; -#endif -} decoderplan; - -typedef struct { - uint8_t native_wire_type; - bool is_numeric; -} upb_decoder_typeinfo; - -static const upb_decoder_typeinfo upb_decoder_types[] = { - {UPB_WIRE_TYPE_END_GROUP, false}, // ENDGROUP - {UPB_WIRE_TYPE_64BIT, true}, // DOUBLE - {UPB_WIRE_TYPE_32BIT, true}, // FLOAT - {UPB_WIRE_TYPE_VARINT, true}, // INT64 - {UPB_WIRE_TYPE_VARINT, true}, // UINT64 - {UPB_WIRE_TYPE_VARINT, true}, // INT32 - {UPB_WIRE_TYPE_64BIT, true}, // FIXED64 - {UPB_WIRE_TYPE_32BIT, true}, // FIXED32 - {UPB_WIRE_TYPE_VARINT, true}, // BOOL - {UPB_WIRE_TYPE_DELIMITED, false}, // STRING - {UPB_WIRE_TYPE_START_GROUP, false}, // GROUP - {UPB_WIRE_TYPE_DELIMITED, false}, // MESSAGE - {UPB_WIRE_TYPE_DELIMITED, false}, // BYTES - {UPB_WIRE_TYPE_VARINT, true}, // UINT32 - {UPB_WIRE_TYPE_VARINT, true}, // ENUM - {UPB_WIRE_TYPE_32BIT, true}, // SFIXED32 - {UPB_WIRE_TYPE_64BIT, true}, // SFIXED64 - {UPB_WIRE_TYPE_VARINT, true}, // SINT32 - {UPB_WIRE_TYPE_VARINT, true}, // SINT64 -}; - -static upb_selector_t getselector(const upb_fielddef *f, - upb_handlertype_t type) { - upb_selector_t selector; - bool ok = upb_handlers_getselector(f, type, &selector); - UPB_ASSERT_VAR(ok, ok); - return selector; -} - - -/* decoderplan ****************************************************************/ - -#ifdef UPB_USE_JIT_X64 -// These defines are necessary for DynASM codegen. -// See dynasm/dasm_proto.h for more info. -#define Dst_DECL 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 - -void freeplan(void *_p) { - decoderplan *p = _p; - upb_handlers_unref(p->dest_handlers, p); -#ifdef UPB_USE_JIT_X64 - if (p->jit_code) upb_decoderplan_freejit(p); -#endif - free(p); -} - -static const decoderplan *getdecoderplan(const upb_handlers *h) { - if (upb_handlers_frametype(h) != upb_pbdecoder_getframetype()) - return NULL; - upb_selector_t sel; - if (!upb_handlers_getselector(UPB_BYTESTREAM_BYTES, UPB_HANDLER_STRING, &sel)) - return NULL; - return upb_handlers_gethandlerdata(h, sel); -} - -bool upb_pbdecoder_isdecoder(const upb_handlers *h) { - return getdecoderplan(h) != NULL; -} - -bool upb_pbdecoder_hasjitcode(const upb_handlers *h) { -#ifdef UPB_USE_JIT_X64 - const decoderplan *p = getdecoderplan(h); - if (!p) return false; - return p->jit_code != NULL; -#else - UPB_UNUSED(h); - return false; -#endif -} - -const upb_handlers *upb_pbdecoder_getdesthandlers(const upb_handlers *h) { - const decoderplan *p = getdecoderplan(h); - if (!p) return NULL; - return p->dest_handlers; +#define CHECK_SUSPEND(x) if (!(x)) return upb_pbdecoder_suspend(d); +#define CHECK_RETURN(x) { int32_t ret = x; if (ret >= 0) return ret; } + +// Error messages that are shared between the bytecode and JIT decoders. +const char *kPbDecoderStackOverflow = "Nesting too deep."; + +// Error messages shared within this file. +static const char *kUnterminatedVarint = "Unterminated varint."; + +/* upb_pbdecoder **************************************************************/ + +static opcode halt = OP_HALT; + +// Whether an op consumes any of the input buffer. +static bool consumes_input(opcode op) { + switch (op) { + case OP_SETDISPATCH: + case OP_STARTMSG: + case OP_ENDMSG: + case OP_STARTSEQ: + case OP_ENDSEQ: + case OP_STARTSUBMSG: + case OP_ENDSUBMSG: + case OP_STARTSTR: + case OP_ENDSTR: + case OP_PUSHTAGDELIM: + case OP_POP: + case OP_SETDELIM: + case OP_SETGROUPNUM: + case OP_SETBIGGROUPNUM: + case OP_CHECKDELIM: + case OP_CALL: + case OP_BRANCH: + return false; + default: + return true; + } } - -/* upb_pbdecoder ****************************************************************/ - -static bool in_residual_buf(const upb_pbdecoder *d, const char *p); +static bool in_residual_buf(upb_pbdecoder *d, const char *p); // It's unfortunate that we have to micro-manage the compiler this way, // especially since this tuning is necessarily specific to one hardware @@ -210,68 +65,65 @@ static bool in_residual_buf(const upb_pbdecoder *d, const char *p); // with these annotations. Every instance where these appear, gcc 4.2.1 made // the wrong decision and degraded performance in benchmarks. #define FORCEINLINE static inline __attribute__((always_inline)) -#define NOINLINE static __attribute__((noinline)) +#define NOINLINE __attribute__((noinline)) -static upb_status *decoder_status(upb_pbdecoder *d) { +static void seterr(upb_pbdecoder *d, const char *msg) { // TODO(haberman): encapsulate this access to pipeline->status, but not sure // exactly what that interface should look like. - return &d->sink->pipeline_->status_; + upb_status_seterrliteral(&d->sink->pipeline_->status_, msg); } -UPB_NORETURN static void exitjmp(upb_pbdecoder *d) { - _longjmp(d->exitjmp, 1); +void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) { + seterr(d, msg); } -UPB_NORETURN static void abortjmp(upb_pbdecoder *d, const char *msg) { - d->ret = in_residual_buf(d, d->checkpoint) ? 0 : (d->checkpoint - d->buf); - upb_status_seterrliteral(decoder_status(d), msg); - exitjmp(d); -} /* Buffering ******************************************************************/ // We operate on one buffer at a time, which is either the user's buffer passed // to our "decode" callback or some residual bytes from the previous buffer. -// How many bytes can be safely read from d->ptr. -static size_t bufleft(upb_pbdecoder *d) { - assert(d->end >= d->ptr); - return d->end - d->ptr; +// How many bytes can be safely read from d->ptr without reading past end-of-buf +// or past the current delimited end. +static size_t curbufleft(upb_pbdecoder *d) { + assert(d->data_end >= d->ptr); + return d->data_end - d->ptr; +} + +static const char *ptr(upb_pbdecoder *d) { + return d->ptr; } // Overall offset of d->ptr. -uint64_t offset(const upb_pbdecoder *d) { - return d->bufstart_ofs + (d->ptr - d->buf); +uint64_t offset(upb_pbdecoder *d) { + return d->bufstart_ofs + (ptr(d) - d->buf); } // Advances d->ptr. static void advance(upb_pbdecoder *d, size_t len) { - assert(bufleft(d) >= len); + assert(curbufleft(d) >= len); d->ptr += len; } -// Commits d->ptr progress; should be called when an entire atomic value -// (ie tag+value) has been successfully consumed. -static void checkpoint(upb_pbdecoder *d) { - d->checkpoint = d->ptr; -} - static bool in_buf(const char *p, const char *buf, const char *end) { return p >= buf && p <= end; } -static bool in_residual_buf(const upb_pbdecoder *d, const char *p) { +static bool in_residual_buf(upb_pbdecoder *d, const char *p) { return in_buf(p, d->residual, d->residual_end); } // Calculates the delim_end value, which represents a combination of the // current buffer and the stack, so must be called whenever either is updated. static void set_delim_end(upb_pbdecoder *d) { - frame *f = d->top; - 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. + size_t delim_ofs = d->top->end_ofs - d->bufstart_ofs; + if (delim_ofs <= (d->end - d->buf)) { + d->delim_end = d->buf + delim_ofs; + d->data_end = d->delim_end; + } else { + d->data_end = d->end; + d->delim_end = NULL; + } } static void switchtobuf(upb_pbdecoder *d, const char *buf, const char *end) { @@ -279,498 +131,603 @@ static void switchtobuf(upb_pbdecoder *d, const char *buf, const char *end) { d->buf = buf; d->end = end; set_delim_end(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 - // JIT bounds-checks only *between* values (and for strings), the - // JIT bails if there are not 20 bytes available. - d->jit_end = d->end - 20; -#endif -} - -static void suspendjmp(upb_pbdecoder *d) { - switchtobuf(d, d->residual, d->residual_end); - exitjmp(d); } static void advancetobuf(upb_pbdecoder *d, const char *buf, size_t len) { - assert(d->ptr == d->end); - d->bufstart_ofs += (d->ptr - d->buf); + assert(curbufleft(d) == 0); + d->bufstart_ofs += (d->end - d->buf); switchtobuf(d, buf, buf + len); } -static void skip(upb_pbdecoder *d, size_t bytes) { - size_t avail = bufleft(d); - size_t total_avail = avail + d->userbuf_remaining; - if (avail >= bytes) { +static void checkpoint(upb_pbdecoder *d) { + // The assertion here is in the interests of efficiency, not correctness. + // We are trying to ensure that we don't checkpoint() more often than + // necessary. + assert(d->checkpoint != ptr(d)); + d->checkpoint = ptr(d); +} + +// Resumes the decoder from an initial state or from a previous suspend. +void *upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, + size_t size) { + UPB_UNUSED(p); // Useless; just for the benefit of the JIT. + d->buf_param = buf; + d->size_param = size; + d->skip = 0; + if (d->residual_end > d->residual) { + // We have residual bytes from the last buffer. + assert(ptr(d) == d->residual); + } else { + switchtobuf(d, buf, buf + size); + } + d->checkpoint = ptr(d); + return d; // For the JIT. +} + +// Suspends the decoder at the last checkpoint, without saving any residual +// bytes. If there are any unconsumed bytes, returns a short byte count. +size_t upb_pbdecoder_suspend(upb_pbdecoder *d) { + d->pc = d->last; + if (d->checkpoint == d->residual) { + // Checkpoint was in residual buf; no user bytes were consumed. + d->ptr = d->residual; + return 0; + } else { + assert(!in_residual_buf(d, d->checkpoint)); + assert(d->buf == d->buf_param); + size_t consumed = d->checkpoint - d->buf; + d->bufstart_ofs += consumed + d->skip; + d->residual_end = d->residual; + switchtobuf(d, d->residual, d->residual_end); + return consumed + d->skip; + } +} + +// Suspends the decoder at the last checkpoint, and saves any unconsumed +// bytes in our residual buffer. This is necessary if we need more user +// bytes to form a complete value, which might not be contiguous in the +// user's buffers. Always consumes all user bytes. +static size_t suspend_save(upb_pbdecoder *d) { + // We hit end-of-buffer before we could parse a full value. + // Save any unconsumed bytes (if any) to the residual buffer. + d->pc = d->last; + + if (d->checkpoint == d->residual) { + // Checkpoint was in residual buf; append user byte(s) to residual buf. + assert((d->residual_end - d->residual) + d->size_param <= + sizeof(d->residual)); + if (!in_residual_buf(d, ptr(d))) { + d->bufstart_ofs -= (d->residual_end - d->residual); + } + memcpy(d->residual_end, d->buf_param, d->size_param); + d->residual_end += d->size_param; + } else { + // Checkpoint was in user buf; old residual bytes not needed. + assert(!in_residual_buf(d, d->checkpoint)); + d->ptr = d->checkpoint; + size_t save = curbufleft(d); + assert(save <= sizeof(d->residual)); + memcpy(d->residual, ptr(d), save); + d->residual_end = d->residual + save; + d->bufstart_ofs = offset(d) + d->skip; + } + + switchtobuf(d, d->residual, d->residual_end); + return d->size_param + d->skip; +} + +static int32_t skip(upb_pbdecoder *d, size_t bytes) { + assert(!in_residual_buf(d, ptr(d)) || d->size_param == 0); + if (curbufleft(d) >= bytes) { // Skipped data is all in current buffer. advance(d, bytes); - } else if (total_avail >= bytes) { - // Skipped data is all in residual buf and param buffer. - assert(in_residual_buf(d, d->ptr)); - advance(d, avail); - advancetobuf(d, d->buf_param, d->size_param); - d->userbuf_remaining = 0; - advance(d, bytes - avail); } else { // Skipped data extends beyond currently available buffers. - // TODO: we need to do a checkdelim() equivalent that pops any frames that - // we just skipped past. - d->bufstart_ofs = offset(d) + bytes; - d->residual_end = d->residual; - d->ret += bytes - total_avail; - suspendjmp(d); + d->skip = bytes - curbufleft(d); + advance(d, curbufleft(d)); } + return DECODE_OK; } -static void consumebytes(upb_pbdecoder *d, void *buf, size_t bytes) { - assert(bytes <= bufleft(d)); - memcpy(buf, d->ptr, bytes); +FORCEINLINE void consumebytes(upb_pbdecoder *d, void *buf, size_t bytes) { + assert(bytes <= curbufleft(d)); + memcpy(buf, ptr(d), bytes); advance(d, bytes); } -NOINLINE void getbytes_slow(upb_pbdecoder *d, void *buf, size_t bytes) { - const size_t avail = bufleft(d); - if (avail + d->userbuf_remaining >= bytes) { - // Remaining residual buffer and param buffer together can satisfy. - // (We are only called from getbytes() which has already verified that - // the current buffer alone cannot satisfy). - assert(in_residual_buf(d, d->ptr)); - consumebytes(d, buf, avail); +static NOINLINE int32_t getbytes_slow(upb_pbdecoder *d, void *buf, + size_t bytes) { + const size_t avail = curbufleft(d); + consumebytes(d, buf, avail); + bytes -= avail; + assert(bytes > 0); + if (in_residual_buf(d, ptr(d))) { advancetobuf(d, d->buf_param, d->size_param); - consumebytes(d, buf + avail, bytes - avail); - d->userbuf_remaining = 0; + } + if (curbufleft(d) >= bytes) { + consumebytes(d, buf + avail, bytes); + return DECODE_OK; + } else if (d->data_end - d->buf == d->top->end_ofs - d->bufstart_ofs) { + seterr(d, "Submessage ended in the middle of a value"); + return upb_pbdecoder_suspend(d); } else { - // There is not enough remaining data, save residual bytes (if any) - // starting at the last committed checkpoint and exit. - if (in_buf(d->checkpoint, d->buf_param, d->buf_param + d->size_param)) { - // Checkpoint was in user buf; old residual bytes not needed. - d->ptr = d->checkpoint; - size_t save = bufleft(d); - assert(save <= sizeof(d->residual)); - memcpy(d->residual, d->ptr, save); - d->residual_end = d->residual + save; - d->bufstart_ofs = offset(d); - } else { - // Checkpoint was in residual buf; append user byte(s) to residual buf. - assert(d->checkpoint == d->residual); - assert((d->residual_end - d->residual) + d->size_param <= - sizeof(d->residual)); - if (!in_residual_buf(d, d->ptr)) { - d->bufstart_ofs -= (d->residual_end - d->residual); - } - memcpy(d->residual_end, d->buf_param, d->size_param); - d->residual_end += d->size_param; - } - suspendjmp(d); + return suspend_save(d); } } -FORCEINLINE void getbytes(upb_pbdecoder *d, void *buf, size_t bytes) { - if (bufleft(d) >= bytes) { +FORCEINLINE int32_t getbytes(upb_pbdecoder *d, void *buf, size_t bytes) { + if (curbufleft(d) >= bytes) { // Buffer has enough data to satisfy. consumebytes(d, buf, bytes); + return DECODE_OK; } else { - getbytes_slow(d, buf, bytes); + return getbytes_slow(d, buf, bytes); + } +} + +static NOINLINE size_t peekbytes_slow(upb_pbdecoder *d, void *buf, + size_t bytes) { + size_t ret = curbufleft(d); + memcpy(buf, ptr(d), ret); + if (in_residual_buf(d, ptr(d))) { + size_t copy = UPB_MIN(bytes - ret, d->size_param); + memcpy(buf + ret, d->buf_param, copy); + ret += copy; } + return ret; } -FORCEINLINE uint8_t getbyte(upb_pbdecoder *d) { - uint8_t byte; - getbytes(d, &byte, 1); - return byte; +FORCEINLINE size_t peekbytes(upb_pbdecoder *d, void *buf, size_t bytes) { + if (curbufleft(d) >= bytes) { + memcpy(buf, ptr(d), bytes); + return bytes; + } else { + return peekbytes_slow(d, buf, bytes); + } } /* Decoding of wire types *****************************************************/ -NOINLINE uint64_t decode_varint_slow(upb_pbdecoder *d) { +NOINLINE int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, + uint64_t *u64) { + *u64 = 0; uint8_t byte = 0x80; - uint64_t u64 = 0; int bitpos; for(bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) { - u64 |= ((uint64_t)((byte = getbyte(d)) & 0x7F)) << bitpos; + int32_t ret = getbytes(d, &byte, 1); + if (ret >= 0) return ret; + *u64 |= (uint64_t)(byte & 0x7F) << bitpos; } - if(bitpos == 70 && (byte & 0x80)) - abortjmp(d, "Unterminated varint"); - return u64; -} - -NOINLINE uint32_t decode_v32_slow(upb_pbdecoder *d) { - uint64_t u64 = decode_varint_slow(d); - if (u64 > UINT32_MAX) abortjmp(d, "Unterminated 32-bit varint"); - return (uint32_t)u64; -} - -// For tags and delimited lengths, which must be <=32bit and are usually small. -FORCEINLINE uint32_t decode_v32(upb_pbdecoder *d) { - // Nearly all will be either 1 byte (1-16) or 2 bytes (17-2048). - if (bufleft(d) >= 2) { - uint32_t ret = d->ptr[0] & 0x7f; - if ((d->ptr[0] & 0x80) == 0) { - advance(d, 1); - return ret; - } - ret |= (d->ptr[1] & 0x7f) << 7; - if ((d->ptr[1] & 0x80) == 0) { - advance(d, 2); - return ret; - } + if(bitpos == 70 && (byte & 0x80)) { + seterr(d, kUnterminatedVarint); + return upb_pbdecoder_suspend(d); } - return decode_v32_slow(d); + return DECODE_OK; } -FORCEINLINE uint64_t decode_varint(upb_pbdecoder *d) { - if (bufleft(d) >= 10) { +FORCEINLINE int32_t decode_varint(upb_pbdecoder *d, uint64_t *u64) { + if (curbufleft(d) > 0 && !(*ptr(d) & 0x80)) { + *u64 = *ptr(d); + advance(d, 1); + return DECODE_OK; + } else if (curbufleft(d) >= 10) { // Fast case. - upb_decoderet r = upb_vdecode_fast(d->ptr); - if (r.p == NULL) abortjmp(d, "Unterminated varint"); - advance(d, r.p - d->ptr); - return r.val; + upb_decoderet r = upb_vdecode_fast(ptr(d)); + if (r.p == NULL) { + seterr(d, kUnterminatedVarint); + return upb_pbdecoder_suspend(d); + } + advance(d, r.p - ptr(d)); + *u64 = r.val; + return DECODE_OK; } else { // Slow case -- varint spans buffer seam. - return decode_varint_slow(d); + return upb_pbdecoder_decode_varint_slow(d, u64); } } -FORCEINLINE uint32_t decode_fixed32(upb_pbdecoder *d) { - uint32_t u32; - getbytes(d, &u32, 4); - return u32; // TODO: proper byte swapping for big-endian machines. -} - -FORCEINLINE uint64_t decode_fixed64(upb_pbdecoder *d) { +FORCEINLINE int32_t decode_v32(upb_pbdecoder *d, uint32_t *u32) { uint64_t u64; - getbytes(d, &u64, 8); - return u64; // TODO: proper byte swapping for big-endian machines. + int32_t ret = decode_varint(d, &u64); + if (ret >= 0) return ret; + if (u64 > UINT32_MAX) { + seterr(d, "Unterminated 32-bit varint"); + return upb_pbdecoder_suspend(d); + } + *u32 = u64; + return DECODE_OK; } -static void push(upb_pbdecoder *d, const upb_fielddef *f, bool is_sequence, - bool is_packed, int32_t group_fieldnum, uint64_t end) { - frame *fr = d->top + 1; - if (fr >= d->limit) abortjmp(d, "Nesting too deep."); - fr->f = f; - fr->is_sequence = is_sequence; - fr->is_packed = is_packed; - fr->end_ofs = end; - fr->group_fieldnum = group_fieldnum; - d->top = fr; - set_delim_end(d); +// TODO: proper byte swapping for big-endian machines. +FORCEINLINE int32_t decode_fixed32(upb_pbdecoder *d, uint32_t *u32) { + return getbytes(d, u32, 4); } -static void push_msg(upb_pbdecoder *d, const upb_fielddef *f, uint64_t end) { - if (!upb_sink_startsubmsg(d->sink, getselector(f, UPB_HANDLER_STARTSUBMSG))) - abortjmp(d, "startsubmsg failed."); - int32_t group_fieldnum = (end == UPB_NONDELIMITED) ? - (int32_t)upb_fielddef_number(f) : -1; - push(d, f, false, false, group_fieldnum, end); +// TODO: proper byte swapping for big-endian machines. +FORCEINLINE int32_t decode_fixed64(upb_pbdecoder *d, uint64_t *u64) { + return getbytes(d, u64, 8); } -static void push_seq(upb_pbdecoder *d, const upb_fielddef *f, bool packed, - uint64_t end_ofs) { - if (!upb_sink_startseq(d->sink, getselector(f, UPB_HANDLER_STARTSEQ))) - abortjmp(d, "startseq failed."); - push(d, f, true, packed, -1, end_ofs); +int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32) { + return decode_fixed32(d, u32); } -static void push_str(upb_pbdecoder *d, const upb_fielddef *f, size_t len, - uint64_t end) { - if (!upb_sink_startstr(d->sink, getselector(f, UPB_HANDLER_STARTSTR), len)) - abortjmp(d, "startseq failed."); - push(d, f, false, false, -1, end); +int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64) { + return decode_fixed64(d, u64); } -static void pop_submsg(upb_pbdecoder *d) { - upb_sink_endsubmsg(d->sink, getselector(d->top->f, UPB_HANDLER_ENDSUBMSG)); - d->top--; - set_delim_end(d); -} +static double as_double(uint64_t n) { double d; memcpy(&d, &n, 8); return d; } +static float as_float(uint32_t n) { float f; memcpy(&f, &n, 4); return f; } -static void pop_seq(upb_pbdecoder *d) { - upb_sink_endseq(d->sink, getselector(d->top->f, UPB_HANDLER_ENDSEQ)); - d->top--; - set_delim_end(d); +static bool push(upb_pbdecoder *d, uint64_t end) { + upb_pbdecoder_frame *fr = d->top; + + if (end > fr->end_ofs) { + seterr(d, "Submessage end extends past enclosing submessage."); + return false; + } else if ((fr + 1) == d->limit) { + seterr(d, kPbDecoderStackOverflow); + return false; + } + + fr++; + fr->end_ofs = end; + fr->u.dispatch = NULL; + fr->groupnum = -1; + d->top = fr; + return true; } -static void pop_string(upb_pbdecoder *d) { - upb_sink_endstr(d->sink, getselector(d->top->f, UPB_HANDLER_ENDSTR)); - d->top--; - set_delim_end(d); +NOINLINE int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, + uint64_t expected) { + uint64_t data = 0; + size_t bytes = upb_value_size(expected); + size_t read = peekbytes(d, &data, bytes); + if (read == bytes && data == expected) { + // Advance past matched bytes. + int32_t ok = getbytes(d, &data, read); + UPB_ASSERT_VAR(ok, ok < 0); + return DECODE_OK; + } else if (read < bytes && memcmp(&data, &expected, read) == 0) { + return suspend_save(d); + } else { + return DECODE_MISMATCH; + } } -static void checkdelim(upb_pbdecoder *d) { - while (d->delim_end && d->ptr >= d->delim_end) { - // TODO(haberman): not sure what to do about this; if we detect this error - // we can possibly violate the promise that errors are always signaled by a - // short "parsed byte" count (because all bytes might have been successfully - // parsed prior to detecting this error). - // if (d->ptr > d->delim_end) abortjmp(d, "Bad submessage end"); - if (d->top->is_sequence) { - pop_seq(d); - } else { - pop_submsg(d); +int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, uint32_t fieldnum, + uint8_t wire_type) { + if (fieldnum == 0 || fieldnum > UPB_MAX_FIELDNUMBER) { + seterr(d, "Invalid field number"); + return upb_pbdecoder_suspend(d); + } + + if (wire_type == UPB_WIRE_TYPE_END_GROUP) { + if (fieldnum != d->top->groupnum) { + seterr(d, "Unmatched ENDGROUP tag."); + return upb_pbdecoder_suspend(d); + } + return DECODE_ENDGROUP; + } + + // TODO: deliver to unknown field callback. + switch (wire_type) { + case UPB_WIRE_TYPE_VARINT: { + uint64_t u64; + return decode_varint(d, &u64); + } + case UPB_WIRE_TYPE_32BIT: + return skip(d, 4); + case UPB_WIRE_TYPE_64BIT: + return skip(d, 8); + case UPB_WIRE_TYPE_DELIMITED: { + uint32_t len; + CHECK_RETURN(decode_v32(d, &len)); + return skip(d, len); } + case UPB_WIRE_TYPE_START_GROUP: + seterr(d, "Can't handle unknown groups yet"); + return upb_pbdecoder_suspend(d); + case UPB_WIRE_TYPE_END_GROUP: + default: + seterr(d, "Invalid wire type"); + return upb_pbdecoder_suspend(d); } } +static int32_t dispatch(upb_pbdecoder *d) { + upb_inttable *dispatch = d->top->u.dispatch; + + // Decode tag. + uint32_t tag; + CHECK_RETURN(decode_v32(d, &tag)); + uint8_t wire_type = tag & 0x7; + uint32_t fieldnum = tag >> 3; + + // Lookup tag. Because of packed/non-packed compatibility, we have to + // check the wire type against two possibilities. + upb_value val; + if (upb_inttable_lookup32(dispatch, fieldnum, &val)) { + uint64_t v = upb_value_getuint64(val); + if (wire_type == (v & 0xff)) { + d->pc = d->top->base + (v >> 16); + return DECODE_OK; + } else if (wire_type == ((v >> 8) & 0xff)) { + bool found = + upb_inttable_lookup(dispatch, fieldnum + UPB_MAX_FIELDNUMBER, &val); + UPB_ASSERT_VAR(found, found); + d->pc = d->top->base + upb_value_getuint64(val); + return DECODE_OK; + } + } + + // Unknown field or ENDGROUP. + int32_t ret = upb_pbdecoder_skipunknown(d, fieldnum, wire_type); -/* Decoding of .proto types ***************************************************/ - -// Technically, we are losing data if we see a 32-bit varint that is not -// properly sign-extended. We could detect this and error about the data loss, -// but proto2 does not do this, so we pass. - -#define T(type, sel, wt, name, convfunc) \ - static void decode_ ## type(upb_pbdecoder *d, const upb_fielddef *f) { \ - upb_sink_put ## name(d->sink, getselector(f, UPB_HANDLER_ ## sel), \ - (convfunc)(decode_ ## wt(d))); \ - } \ - -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; } - -T(INT32, INT32, varint, int32, int32_t) -T(INT64, INT64, varint, int64, int64_t) -T(UINT32, UINT32, varint, uint32, uint32_t) -T(UINT64, UINT64, varint, uint64, uint64_t) -T(FIXED32, UINT32, fixed32, uint32, uint32_t) -T(FIXED64, UINT64, fixed64, uint64, uint64_t) -T(SFIXED32, INT32, fixed32, int32, int32_t) -T(SFIXED64, INT64, fixed64, int64, int64_t) -T(BOOL, BOOL, varint, bool, bool) -T(ENUM, INT32, varint, int32, int32_t) -T(DOUBLE, DOUBLE, fixed64, double, upb_asdouble) -T(FLOAT, FLOAT, fixed32, float, upb_asfloat) -T(SINT32, INT32, varint, int32, upb_zzdec_32) -T(SINT64, INT64, varint, int64, upb_zzdec_64) -#undef T - -static void decode_GROUP(upb_pbdecoder *d, const upb_fielddef *f) { - push_msg(d, f, UPB_NONDELIMITED); -} - -static void decode_MESSAGE(upb_pbdecoder *d, const upb_fielddef *f) { - uint32_t len = decode_v32(d); - push_msg(d, f, offset(d) + len); -} - -static void decode_STRING(upb_pbdecoder *d, const upb_fielddef *f) { - uint32_t strlen = decode_v32(d); - if (strlen <= bufleft(d)) { - upb_sink_startstr(d->sink, getselector(f, UPB_HANDLER_STARTSTR), strlen); - if (strlen) - upb_sink_putstring(d->sink, getselector(f, UPB_HANDLER_STRING), - d->ptr, strlen); - upb_sink_endstr(d->sink, getselector(f, UPB_HANDLER_ENDSTR)); - advance(d, strlen); + if (ret == DECODE_ENDGROUP) { + d->pc = d->top->base - 1; // Back to OP_ENDMSG. + return DECODE_OK; } else { - // Buffer ends in the middle of the string; need to push a decoder frame - // for it. - push_str(d, f, strlen, offset(d) + strlen); - if (bufleft(d)) { - upb_sink_putstring(d->sink, getselector(f, UPB_HANDLER_STRING), - d->ptr, bufleft(d)); - advance(d, bufleft(d)); - } - d->bufstart_ofs = offset(d); - d->residual_end = d->residual; - suspendjmp(d); + d->pc = d->last - 1; // Rewind to CHECKDELIM. + return ret; } } /* The main decoding loop *****************************************************/ -static const upb_fielddef *decode_tag(upb_pbdecoder *d) { - while (1) { - uint32_t tag = decode_v32(d); - uint8_t wire_type = tag & 0x7; - uint32_t fieldnum = tag >> 3; const upb_fielddef *f = NULL; - const upb_handlers *h = d->sink->top->h; // TODO(haberman): rm - f = upb_msgdef_itof(upb_handlers_msgdef(h), fieldnum); - bool packed = false; - - if (f) { - // Wire type check. - upb_descriptortype_t type = upb_fielddef_descriptortype(f); - if (wire_type == upb_decoder_types[type].native_wire_type) { - // Wire type is ok. - } else if ((wire_type == UPB_WIRE_TYPE_DELIMITED && - upb_decoder_types[type].is_numeric)) { - // Wire type is ok (and packed). - packed = true; - } 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. - frame *fr = d->top; - if (fr->is_sequence && fr->f != f) { - pop_seq(d); - fr = d->top; - } +size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, + size_t size) { + upb_pbdecoder *d = closure; + const upb_pbdecoderplan *p = hd; + assert(buf); + upb_pbdecoder_resume(d, NULL, buf, size); + UPB_UNUSED(p); - if (f && upb_fielddef_isseq(f) && !fr->is_sequence) { - if (packed) { - uint32_t len = decode_v32(d); - push_seq(d, f, true, offset(d) + len); - checkpoint(d); - } else { - push_seq(d, f, false, fr->end_ofs); - } - } +#define VMCASE(op, code) \ + case op: { code; if (consumes_input(op)) checkpoint(d); break; } +#define PRIMITIVE_OP(type, wt, name, convfunc, ctype) \ + VMCASE(OP_PARSE_ ## type, { \ + ctype val; \ + CHECK_RETURN(decode_ ## wt(d, &val)); \ + upb_sink_put ## name(d->sink, arg, (convfunc)(val)); \ + }) - if (f) return f; - - // Unknown field or ENDGROUP. - if (fieldnum == 0 || fieldnum > UPB_MAX_FIELDNUMBER) - abortjmp(d, "Invalid field number"); - switch (wire_type) { - case UPB_WIRE_TYPE_VARINT: decode_varint(d); break; - case UPB_WIRE_TYPE_32BIT: skip(d, 4); break; - case UPB_WIRE_TYPE_64BIT: skip(d, 8); break; - case UPB_WIRE_TYPE_DELIMITED: skip(d, decode_v32(d)); break; - case UPB_WIRE_TYPE_START_GROUP: - abortjmp(d, "Can't handle unknown groups yet"); - case UPB_WIRE_TYPE_END_GROUP: - if (fieldnum != fr->group_fieldnum) - abortjmp(d, "Unmatched ENDGROUP tag"); - pop_submsg(d); - break; - default: - abortjmp(d, "Invalid wire type"); + while(1) { + d->last = d->pc; + int32_t instruction = *d->pc++; + opcode op = getop(instruction); + uint32_t arg = instruction >> 8; + int32_t longofs = arg; + assert(ptr(d) != d->residual_end); +#ifdef UPB_DUMP_BYTECODE + fprintf(stderr, "s_ofs=%d buf_ofs=%d data_rem=%d buf_rem=%d delim_rem=%d " + "%x %s (%d)\n", + (int)offset(d), + (int)(ptr(d) - d->buf), + (int)(d->data_end - ptr(d)), + (int)(d->end - ptr(d)), + (int)((d->top->end_ofs - d->bufstart_ofs) - (ptr(d) - d->buf)), + (int)(d->pc - 1 - upb_pbdecoderplan_codebase(p)), + upb_pbdecoder_getopname(op), + arg); +#endif + switch (op) { + // Technically, we are losing data if we see a 32-bit varint that is not + // properly sign-extended. We could detect this and error about the data + // loss, but proto2 does not do this, so we pass. + PRIMITIVE_OP(INT32, varint, int32, int32_t, uint64_t) + PRIMITIVE_OP(INT64, varint, int64, int64_t, uint64_t) + PRIMITIVE_OP(UINT32, varint, uint32, uint32_t, uint64_t) + PRIMITIVE_OP(UINT64, varint, uint64, uint64_t, uint64_t) + PRIMITIVE_OP(FIXED32, fixed32, uint32, uint32_t, uint32_t) + PRIMITIVE_OP(FIXED64, fixed64, uint64, uint64_t, uint64_t) + PRIMITIVE_OP(SFIXED32, fixed32, int32, int32_t, uint32_t) + PRIMITIVE_OP(SFIXED64, fixed64, int64, int64_t, uint64_t) + PRIMITIVE_OP(BOOL, varint, bool, bool, uint64_t) + PRIMITIVE_OP(DOUBLE, fixed64, double, as_double, uint64_t) + PRIMITIVE_OP(FLOAT, fixed32, float, as_float, uint32_t) + PRIMITIVE_OP(SINT32, varint, int32, upb_zzdec_32, uint64_t) + PRIMITIVE_OP(SINT64, varint, int64, upb_zzdec_64, uint64_t) + + VMCASE(OP_SETDISPATCH, + d->top->base = d->pc - 1; + memcpy(&d->top->u.dispatch, d->pc, sizeof(void*)); + d->pc += sizeof(void*) / sizeof(uint32_t); + ) + VMCASE(OP_STARTMSG, + CHECK_SUSPEND(upb_sink_startmsg(d->sink)); + ) + VMCASE(OP_ENDMSG, + CHECK_SUSPEND(upb_sink_endmsg(d->sink)); + assert(d->call_len > 0); + d->pc = d->callstack[--d->call_len]; + ) + VMCASE(OP_STARTSEQ, + CHECK_SUSPEND(upb_sink_startseq(d->sink, arg)); + ) + VMCASE(OP_ENDSEQ, + CHECK_SUSPEND(upb_sink_endseq(d->sink, arg)); + ) + VMCASE(OP_STARTSUBMSG, + CHECK_SUSPEND(upb_sink_startsubmsg(d->sink, arg)); + ) + VMCASE(OP_ENDSUBMSG, + CHECK_SUSPEND(upb_sink_endsubmsg(d->sink, arg)); + ) + VMCASE(OP_STARTSTR, + uint32_t len = d->top->end_ofs - offset(d); + CHECK_SUSPEND(upb_sink_startstr(d->sink, arg, len)); + if (len == 0) { + d->pc++; // Skip OP_STRING. + } + ) + VMCASE(OP_STRING, + uint32_t len = curbufleft(d); + CHECK_SUSPEND(upb_sink_putstring(d->sink, arg, ptr(d), len)); + advance(d, len); + if (d->delim_end == NULL) { // String extends beyond this buf? + d->pc--; + d->bufstart_ofs += size; + d->residual_end = d->residual; + return size; + } + ) + VMCASE(OP_ENDSTR, + CHECK_SUSPEND(upb_sink_endstr(d->sink, arg)); + ) + VMCASE(OP_PUSHTAGDELIM, + CHECK_SUSPEND(push(d, d->top->end_ofs)); + ) + VMCASE(OP_POP, + assert(d->top > d->stack); + d->top--; + ) + VMCASE(OP_PUSHLENDELIM, + uint32_t len; + CHECK_RETURN(decode_v32(d, &len)); + CHECK_SUSPEND(push(d, offset(d) + len)); + set_delim_end(d); + ) + VMCASE(OP_SETDELIM, + set_delim_end(d); + ) + VMCASE(OP_SETGROUPNUM, + d->top->groupnum = arg; + ) + VMCASE(OP_SETBIGGROUPNUM, + d->top->groupnum = *d->pc++; + ) + VMCASE(OP_CHECKDELIM, + assert(!(d->delim_end && ptr(d) > d->delim_end)); + if (ptr(d) == d->delim_end) + d->pc += longofs; + ) + VMCASE(OP_CALL, + d->callstack[d->call_len++] = d->pc; + d->pc += longofs; + ) + VMCASE(OP_BRANCH, + d->pc += longofs; + ) + VMCASE(OP_TAG1, + CHECK_SUSPEND(curbufleft(d) > 0); + uint8_t expected = (arg >> 8) & 0xff; + if (*ptr(d) == expected) { + advance(d, 1); + } else { + int8_t shortofs; + badtag: + shortofs = arg; + if (shortofs == LABEL_DISPATCH) { + CHECK_RETURN(dispatch(d)); + } else { + d->pc += shortofs; + break; // Avoid checkpoint(). + } + } + ) + VMCASE(OP_TAG2, + CHECK_SUSPEND(curbufleft(d) > 0); + uint16_t expected = (arg >> 8) & 0xffff; + if (curbufleft(d) >= 2) { + uint16_t actual; + memcpy(&actual, ptr(d), 2); + if (expected == actual) { + advance(d, 2); + } else { + goto badtag; + } + } else { + int32_t result = upb_pbdecoder_checktag_slow(d, expected); + if (result == DECODE_MISMATCH) goto badtag; + if (result >= 0) return result; + } + ) + VMCASE(OP_TAGN, { + uint64_t expected; + memcpy(&expected, d->pc, 8); + d->pc += 2; + int32_t result = upb_pbdecoder_checktag_slow(d, expected); + if (result == DECODE_MISMATCH) goto badtag; + if (result >= 0) return result; + }) + VMCASE(OP_HALT, { + return size; + }) } - // TODO: deliver to unknown field callback. - checkpoint(d); - checkdelim(d); } } -void *start(void *closure, const void *handler_data, size_t size_hint) { - UPB_UNUSED(handler_data); +void *upb_pbdecoder_start(void *closure, const void *handler_data, + size_t size_hint) { UPB_UNUSED(size_hint); upb_pbdecoder *d = closure; + const upb_pbdecoderplan *plan = handler_data; + UPB_UNUSED(plan); + if (upb_pbdecoderplan_hasjitcode(plan)) { + d->top->u.closure = d->sink->top->closure; + d->call_len = 0; + } else { + d->call_len = 1; + d->pc = upb_pbdecoderplan_codebase(plan); + } assert(d); assert(d->sink); - upb_sink_startmsg(d->sink); + if (plan->topmethod->dest_handlers) { + assert(d->sink->top->h == plan->topmethod->dest_handlers); + } + d->status = &d->sink->pipeline_->status_; return d; } -bool end(void *closure, const void *handler_data) { - UPB_UNUSED(handler_data); +bool upb_pbdecoder_end(void *closure, const void *handler_data) { upb_pbdecoder *d = closure; + const upb_pbdecoderplan *plan = handler_data; if (d->residual_end > d->residual) { - // We have preserved bytes. - upb_status_seterrliteral(decoder_status(d), "Unexpected EOF"); - return false; - } - - // We may need to dispatch a top-level implicit frame. - if (d->top == d->stack + 1 && - d->top->is_sequence && - !d->top->is_packed) { - pop_seq(d); - } - if (d->top != d->stack) { - upb_status_seterrliteral( - decoder_status(d), "Ended inside delimited field."); + seterr(d, "Unexpected EOF"); return false; } - upb_sink_endmsg(d->sink); - return true; -} - -size_t decode(void *closure, const void *hd, const char *buf, size_t size) { - upb_pbdecoder *d = closure; - const decoderplan *plan = hd; - UPB_UNUSED(plan); - assert(d->sink->top->h == plan->dest_handlers); - - if (size == 0) return 0; - // Assume we'll consume the whole buffer unless this is overwritten. - d->ret = size; - d->buf_param = buf; - d->size_param = size; - - if (_setjmp(d->exitjmp)) { - // Hit end-of-buffer or error. - return d->ret; - } - - if (d->residual_end > d->residual) { - // We have residual bytes from the last buffer. - d->userbuf_remaining = d->size_param; - } else { - d->userbuf_remaining = 0; - advancetobuf(d, buf, d->size_param); - - if (d->top != d->stack && - upb_fielddef_isstring(d->top->f) && - !d->top->is_sequence) { - // Last buffer ended in the middle of a string; deliver more of it. - size_t len = d->top->end_ofs - offset(d); - if (d->size_param >= len) { - upb_sink_putstring(d->sink, getselector(d->top->f, UPB_HANDLER_STRING), - d->ptr, len); - advance(d, len); - pop_string(d); - } else { - upb_sink_putstring(d->sink, getselector(d->top->f, UPB_HANDLER_STRING), - d->ptr, d->size_param); - advance(d, d->size_param); - d->residual_end = d->residual; - advancetobuf(d, d->residual, 0); - return d->size_param; - } - } - } - checkpoint(d); - const upb_fielddef *f = d->top->f; - while(1) { + // Message ends here. + uint64_t end = offset(d); + d->top->end_ofs = end; + char dummy; + if (upb_pbdecoderplan_hasjitcode(plan)) { #ifdef UPB_USE_JIT_X64 - upb_decoder_enterjit(d, plan); - checkpoint(d); - set_delim_end(d); // JIT doesn't keep this current. + if (d->top != d->stack) + d->stack->end_ofs = 0; + upb_pbdecoderplan_jitcode(plan)(closure, handler_data, &dummy, 0); #endif - checkdelim(d); - if (!d->top->is_packed) { - f = decode_tag(d); + } else { + d->stack->end_ofs = end; + uint32_t *p = d->pc - 1; + if (getop(*p) == OP_CHECKDELIM) { + // Rewind from OP_TAG* to OP_CHECKDELIM. + assert(getop(*d->pc) == OP_TAG1 || + getop(*d->pc) == OP_TAG2 || + getop(*d->pc) == OP_TAGN); + d->pc = p; } + upb_pbdecoder_decode(closure, handler_data, &dummy, 0); + } - switch (upb_fielddef_descriptortype(f)) { - case UPB_DESCRIPTOR_TYPE_DOUBLE: decode_DOUBLE(d, f); break; - case UPB_DESCRIPTOR_TYPE_FLOAT: decode_FLOAT(d, f); break; - case UPB_DESCRIPTOR_TYPE_INT64: decode_INT64(d, f); break; - case UPB_DESCRIPTOR_TYPE_UINT64: decode_UINT64(d, f); break; - case UPB_DESCRIPTOR_TYPE_INT32: decode_INT32(d, f); break; - case UPB_DESCRIPTOR_TYPE_FIXED64: decode_FIXED64(d, f); break; - case UPB_DESCRIPTOR_TYPE_FIXED32: decode_FIXED32(d, f); break; - case UPB_DESCRIPTOR_TYPE_BOOL: decode_BOOL(d, f); break; - case UPB_DESCRIPTOR_TYPE_STRING: UPB_FALLTHROUGH_INTENDED; - case UPB_DESCRIPTOR_TYPE_BYTES: decode_STRING(d, f); break; - case UPB_DESCRIPTOR_TYPE_GROUP: decode_GROUP(d, f); break; - case UPB_DESCRIPTOR_TYPE_MESSAGE: decode_MESSAGE(d, f); break; - case UPB_DESCRIPTOR_TYPE_UINT32: decode_UINT32(d, f); break; - case UPB_DESCRIPTOR_TYPE_ENUM: decode_ENUM(d, f); break; - case UPB_DESCRIPTOR_TYPE_SFIXED32: decode_SFIXED32(d, f); break; - case UPB_DESCRIPTOR_TYPE_SFIXED64: decode_SFIXED64(d, f); break; - case UPB_DESCRIPTOR_TYPE_SINT32: decode_SINT32(d, f); break; - case UPB_DESCRIPTOR_TYPE_SINT64: decode_SINT64(d, f); break; - } - checkpoint(d); + if (d->call_len != 0) { + seterr(d, "Unexpected EOF"); + return false; } + + return upb_ok(&d->sink->pipeline_->status_); } void init(void *_d, upb_pipeline *p) { UPB_UNUSED(p); upb_pbdecoder *d = _d; - d->limit = &d->stack[UPB_MAX_NESTING]; + d->limit = &d->stack[UPB_DECODER_MAX_NESTING]; d->sink = NULL; + d->callstack[0] = &halt; // reset() must be called before decoding; this is guaranteed by assert() in // start(). } @@ -778,15 +735,13 @@ void init(void *_d, upb_pipeline *p) { void reset(void *_d) { upb_pbdecoder *d = _d; d->top = d->stack; - d->top->is_sequence = false; - d->top->is_packed = false; - d->top->group_fieldnum = UINT32_MAX; - d->top->end_ofs = UPB_NONDELIMITED; + d->top->end_ofs = UINT64_MAX; d->bufstart_ofs = 0; d->ptr = d->residual; d->buf = d->residual; d->end = d->residual; d->residual_end = d->residual; + d->call_len = 1; } bool upb_pbdecoder_resetsink(upb_pbdecoder *d, upb_sink* sink) { @@ -807,24 +762,3 @@ const upb_frametype upb_pbdecoder_frametype = { const upb_frametype *upb_pbdecoder_getframetype() { return &upb_pbdecoder_frametype; } - -const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest, - bool allowjit, - const void *owner) { - UPB_UNUSED(allowjit); - decoderplan *p = malloc(sizeof(*p)); - assert(upb_handlers_isfrozen(dest)); - p->dest_handlers = dest; - upb_handlers_ref(dest, p); -#ifdef UPB_USE_JIT_X64 - p->jit_code = NULL; - if (allowjit) upb_decoderplan_makejit(p); -#endif - - upb_handlers *h = upb_handlers_new( - UPB_BYTESTREAM, &upb_pbdecoder_frametype, owner); - upb_handlers_setstartstr(h, UPB_BYTESTREAM_BYTES, start, NULL, NULL); - upb_handlers_setstring(h, UPB_BYTESTREAM_BYTES, decode, p, freeplan); - upb_handlers_setendstr(h, UPB_BYTESTREAM_BYTES, end, NULL, NULL); - return h; -} diff --git a/upb/pb/decoder.h b/upb/pb/decoder.h index c1b6cb3..c645688 100644 --- a/upb/pb/decoder.h +++ b/upb/pb/decoder.h @@ -14,6 +14,13 @@ #include "upb/sink.h" +// The maximum that any submessages can be nested. Matches proto2's limit. +// At the moment this specifies the size of several statically-sized arrays +// and therefore setting it high will cause more memory to be used. Will +// be replaced by a runtime-configurable limit and dynamically-resizing arrays. +// TODO: make this a runtime-settable property of Decoder. +#define UPB_DECODER_MAX_NESTING 64 + #ifdef __cplusplus namespace upb { namespace pb { diff --git a/upb/pb/decoder.int.h b/upb/pb/decoder.int.h new file mode 100644 index 0000000..8c8710c --- /dev/null +++ b/upb/pb/decoder.int.h @@ -0,0 +1,242 @@ + +#ifndef UPB_DECODER_INT_H_ +#define UPB_DECODER_INT_H_ + +#include <stdlib.h> +#include "upb/def.h" +#include "upb/handlers.h" +#include "upb/sink.h" +#include "upb/pb/decoder.h" + +// Opcode definitions. The canonical meaning of each opcode is its +// implementation in the interpreter (the JIT is written to match this). +// +// All instructions have the opcode in the low byte. +// Instruction format for most instructions is: +// +// +-------------------+--------+ +// | arg (24) | op (8) | +// +-------------------+--------+ +// +// Exceptions are indicated below. A few opcodes are multi-word. +typedef enum { + // Opcodes 1-8, 13, 15-18 parse their respective descriptor types. + // Arg for all of these is the upb selector for this field. +#define T(type) OP_PARSE_ ## type = UPB_DESCRIPTOR_TYPE_ ## type + T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32), + T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64), +#undef T + OP_STARTMSG = 9, // No arg. + OP_ENDMSG = 10, // No arg. + OP_STARTSEQ = 11, + OP_ENDSEQ = 12, + OP_STARTSUBMSG = 14, + OP_ENDSUBMSG = 19, + OP_STARTSTR = 20, + OP_STRING = 21, + OP_ENDSTR = 22, + + OP_PUSHTAGDELIM = 23, // No arg. + OP_PUSHLENDELIM = 24, // No arg. + OP_POP = 25, // No arg. + OP_SETDELIM = 26, // No arg. + OP_SETGROUPNUM = 27, + OP_SETBIGGROUPNUM = 28, // two words: | unused (24) | opc || groupnum (32) | + + // The arg for these opcodes is a local label reference. + OP_CHECKDELIM = 29, + OP_CALL = 30, + OP_BRANCH = 31, + + // Different opcodes depending on how many bytes expected. + OP_TAG1 = 32, // | expected tag (16) | jump target (8) | opc (8) | + OP_TAG2 = 33, // | expected tag (16) | jump target (8) | opc (8) | + OP_TAGN = 34, // three words: + // | unused (16) | jump target(8) | opc (8) | + // | expected tag 1 (32) | + // | expected tag 2 (32) | + + OP_SETDISPATCH = 35, // N words: + // | unused (24) | opc | + // | upb_inttable* (32 or 64) | + + OP_HALT = 36, // No arg. +} opcode; + +#define OP_MAX OP_HALT + +UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; } + +const upb_frametype upb_pbdecoder_frametype; + +// Decoder entry points; used as handlers. +void *upb_pbdecoder_start(void *closure, const void *handler_data, + size_t size_hint); +size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, + size_t size); +bool upb_pbdecoder_end(void *closure, const void *handler_data); + +// Decoder-internal functions that the JIT calls to handle fallback paths. +void *upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, + size_t size); +size_t upb_pbdecoder_suspend(upb_pbdecoder *d); +int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, uint32_t fieldnum, + uint8_t wire_type); +int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected); +int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64); +int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32); +int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64); +void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg); + +// Error messages that are shared between the bytecode and JIT decoders. +extern const char *kPbDecoderStackOverflow; + +typedef struct _upb_pbdecoderplan upb_pbdecoderplan; + +// Access to decoderplan members needed by the decoder. +bool upb_pbdecoderplan_hasjitcode(const upb_pbdecoderplan *p); +uint32_t *upb_pbdecoderplan_codebase(const upb_pbdecoderplan *p); +const char *upb_pbdecoder_getopname(unsigned int op); +upb_string_handler *upb_pbdecoderplan_jitcode(const upb_pbdecoderplan *p); + +// JIT entry point. +void upb_pbdecoder_jit(upb_pbdecoderplan *plan); +void upb_pbdecoder_freejit(upb_pbdecoderplan *plan); + + +// A special label that means "do field dispatch for this message and branch to +// wherever that takes you." +#define LABEL_DISPATCH 0 + +#define DECODE_OK -1 +#define DECODE_MISMATCH -2 // Used only from checktag_slow(). +#define DECODE_ENDGROUP -2 // Used only from checkunknown(). + +typedef struct { + // The absolute stream offset of the end-of-frame delimiter. + // Non-delimited frames (groups and non-packed repeated fields) reuse the + // delimiter of their parent, even though the frame may not end there. + // + // NOTE: the JIT stores a slightly different value here for non-top frames. + // It stores the value relative to the end of the enclosed message. But the + // innermost frame is still stored the same way, which is important for + // ensuring that calls from the JIT into C work correctly. + uint64_t end_ofs; + uint32_t *base; + uint32_t groupnum; + union { + upb_inttable *dispatch; // Not used by the JIT. + void *closure; // Only used by the JIT. + } u; +} upb_pbdecoder_frame; + +struct upb_pbdecoder { + // Where we push parsed data (not owned). + upb_sink *sink; + + size_t call_len; + uint32_t *pc, *last; + + // Current input buffer and its stream offset. + const char *buf, *ptr, *end, *checkpoint; + + // End of the delimited region, relative to ptr, or NULL if not in this buf. + const char *delim_end; + + // End of the delimited region, relative to ptr, or end if not in this buf. + const char *data_end; + + // Overall stream offset of "buf." + uint64_t bufstart_ofs; + + // How many bytes past the end of the user buffer we want to skip. + size_t skip; + + // Buffer for residual bytes not parsed from the previous buffer. + // The maximum number of residual bytes we require is 12; a five-byte + // unknown tag plus an eight-byte value, less one because the value + // is only a partial value. + char residual[12]; + char *residual_end; + + // Stores the user buffer passed to our decode function. + const char *buf_param; + size_t size_param; + +#ifdef UPB_USE_JIT_X64 + // Used momentarily by the generated code to store a value while a user + // function is called. + uint32_t tmp_len; + + const void *saved_rsp; +#endif + + upb_status *status; + + // Our internal stack. + upb_pbdecoder_frame *top, *limit; + upb_pbdecoder_frame stack[UPB_DECODER_MAX_NESTING]; + uint32_t *callstack[UPB_DECODER_MAX_NESTING * 2]; +}; + +// Data pertaining to a single decoding method/function. +// Each method contains code to parse a single message type. +// If may or may not be bound to a destination handlers object. +typedef struct { + // While compiling, the base is relative in "ofs", after compiling it is + // absolute in "ptr". + union { + uint32_t ofs; // PC offset of method. + const void *ptr; // Pointer to bytecode or machine code for this method. + } base; + + // Whether this method is native code or bytecode. + bool native_code; + + // The message type that this method is parsing. + const upb_msgdef *msg; + + // The destination handlers this method is bound to, or NULL if this method + // can be bound to a destination handlers instance at runtime. + // + // If non-NULL, we own a ref. + const upb_handlers *dest_handlers; + + // The dispatch table layout is: + // [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ] + // + // If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup + // (UPB_MAX_FIELDNUMBER + fieldnum) and jump there. + // + // We need two wire types because of packed/non-packed compatibility. A + // primitive repeated field can use either wire type and be valid. While we + // could key the table on fieldnum+wiretype, the table would be 8x sparser. + // + // Storing two wire types in the primary value allows us to quickly rule out + // the second wire type without needing to do a separate lookup (this case is + // less common than an unknown field). + upb_inttable dispatch; +} upb_pbdecodermethod; + +struct _upb_pbdecoderplan { + // Pointer to bytecode. + uint32_t *code, *code_end; + + // Maps upb_msgdef*/upb_handlers* -> upb_pbdecodermethod + upb_inttable methods; + + // The method that starts parsing when we first call into the plan. + // Ideally we will remove the idea that any of the methods in the plan + // are special like this, so that any method can be the top-level one. + upb_pbdecodermethod *topmethod; + +#ifdef UPB_USE_JIT_X64 + // JIT-generated machine code (else NULL). + upb_string_handler *jit_code; + size_t jit_size; + char *debug_info; + void *dl; +#endif +}; + +#endif // UPB_DECODER_INT_H_ diff --git a/upb/pb/decoder_x64.dasc b/upb/pb/decoder_x64.dasc deleted file mode 100644 index dee063a..0000000 --- a/upb/pb/decoder_x64.dasc +++ /dev/null @@ -1,1086 +0,0 @@ -|// -|// upb - a minimalist implementation of protocol buffers. -|// -|// Copyright (c) 2011 Google Inc. See LICENSE for details. -|// Author: Josh Haberman <jhaberman@gmail.com> -|// -|// JIT compiler for upb_pbdecoder on x86. Given a decoderplan object (which -|// contains an embedded set of upb_handlers), generates code specialized to -|// parsing the specific message and calling specific handlers. -|// -|// Since the JIT can call other functions (the JIT'ted code is not a leaf -|// function) we must respect alignment rules. All x86-64 systems require -|// 16-byte stack alignment. - -#define _GNU_SOURCE -#include <stdio.h> -#include <sys/mman.h> -#include "dynasm/dasm_x86.h" -#include "upb/shim/shim.h" - -#ifndef MAP_ANONYMOUS -# define MAP_ANONYMOUS MAP_ANON -#endif - -// We map into the low 32 bits when we can, but if this is not available -// (like on OS X) we take what we can get. It's not required for correctness, -// it's just a performance thing that makes it more likely that our jumps -// can be rel32 (i.e. within 32-bits of our pc) instead of the longer -// sequence required for other jumps (see callp). -#ifndef MAP_32BIT -#define MAP_32BIT 0 -#endif - -// These are used to track jump targets for messages and fields. -enum { - STARTMSG = 0, - AFTER_STARTMSG = 1, - ENDOFBUF = 2, - ENDOFMSG = 3, - DYNDISPATCH = 4, - TOTAL_MSG_PCLABELS = 5, -}; - -enum { - FIELD = 0, - FIELD_NO_TYPECHECK = 1, - TOTAL_FIELD_PCLABELS = 2, -}; - -typedef struct { - 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; - // Pointer to the JIT code for parsing this message. - void *jit_func; -} upb_jitmsginfo; - -static uint32_t upb_getpclabel(decoderplan *plan, const void *obj, int n) { - upb_value v; - bool found = upb_inttable_lookupptr(&plan->pclabels, obj, &v); - UPB_ASSERT_VAR(found, found); - return upb_value_getuint32(v) + n; -} - -static upb_jitmsginfo *upb_getmsginfo(const decoderplan *plan, - const upb_handlers *h) { - upb_value v; - bool found = upb_inttable_lookupptr(&plan->msginfo, h, &v); - UPB_ASSERT_VAR(found, found); - return upb_value_getptr(v); -} - -// To debug JIT-ted code with GDB we need to tell GDB about the JIT-ted code -// at runtime. GDB 7.x+ has defined an interface for doing this, and these -// structure/function defintions are copied out of gdb/jit.h -// -// We need to give GDB an ELF file at runtime describing the symbols we have -// generated. To avoid implementing the ELF format, we generate an ELF file -// at compile-time and compile it in as a character string. We can replace -// a few key constants (address of JIT-ted function and its size) by looking -// for a few magic numbers and doing a dumb string replacement. - -#ifndef __APPLE__ -const unsigned char upb_jit_debug_elf_file[] = { -#include "upb/pb/jit_debug_elf_file.h" -}; - -typedef enum -{ - GDB_JIT_NOACTION = 0, - GDB_JIT_REGISTER, - GDB_JIT_UNREGISTER -} jit_actions_t; - -typedef struct gdb_jit_entry { - struct gdb_jit_entry *next_entry; - struct gdb_jit_entry *prev_entry; - const char *symfile_addr; - uint64_t symfile_size; -} gdb_jit_entry; - -typedef struct { - uint32_t version; - uint32_t action_flag; - gdb_jit_entry *relevant_entry; - gdb_jit_entry *first_entry; -} gdb_jit_descriptor; - -gdb_jit_descriptor __jit_debug_descriptor = {1, GDB_JIT_NOACTION, NULL, NULL}; - -void __attribute__((noinline)) __jit_debug_register_code() { - __asm__ __volatile__(""); -} - -void upb_reg_jit_gdb(decoderplan *plan) { - // Create debug info. - size_t elf_len = sizeof(upb_jit_debug_elf_file); - plan->debug_info = malloc(elf_len); - memcpy(plan->debug_info, upb_jit_debug_elf_file, elf_len); - uint64_t *p = (void*)plan->debug_info; - for (; (void*)(p+1) <= (void*)plan->debug_info + elf_len; ++p) { - if (*p == 0x12345678) { *p = (uintptr_t)plan->jit_code; } - if (*p == 0x321) { *p = plan->jit_size; } - } - - // Register the JIT-ted code with GDB. - gdb_jit_entry *e = malloc(sizeof(gdb_jit_entry)); - e->next_entry = __jit_debug_descriptor.first_entry; - e->prev_entry = NULL; - if (e->next_entry) e->next_entry->prev_entry = e; - e->symfile_addr = plan->debug_info; - e->symfile_size = elf_len; - __jit_debug_descriptor.first_entry = e; - __jit_debug_descriptor.relevant_entry = e; - __jit_debug_descriptor.action_flag = GDB_JIT_REGISTER; - __jit_debug_register_code(); -} - -#else - -void upb_reg_jit_gdb(decoderplan *plan) { - (void)plan; -} - -#endif - -// Has to be a separate function, otherwise GCC will complain about -// expressions like (&foo != NULL) because they will never evaluate -// to false. -static void upb_assert_notnull(void *addr) { assert(addr != NULL); (void)addr; } - -|.arch x64 -|.actionlist upb_jit_actionlist -|.globals UPB_JIT_GLOBAL_ -|.globalnames upb_jit_globalnames -| -|// Calling conventions. Note -- this will need to be changed for -|// Windows, which uses a different calling convention! -|.define ARG1_64, rdi -|.define ARG2_8, r6b // DynASM's equivalent to "sil" -- low byte of esi. -|.define ARG2_32, esi -|.define ARG2_64, rsi -|.define ARG3_32, edx -|.define ARG3_64, rdx -|.define ARG4_32, ecx -|.define ARG4_64, rcx -|.define XMMARG1, xmm0 - -| -|// Register allocation / type map. -|// ALL of the code in this file uses these register allocations. -|// When we "call" within this file, we do not use regular calling -|// conventions, but of course when calling to user callbacks we must. -|.define PTR, rbx // Writing this to DECODER->ptr commits our progress. -|.define CLOSURE, r12 -|.type SINKFRAME, upb_sinkframe, r13 -|.type FRAME, frame, r14 -|.type DECODER, upb_pbdecoder, r15 -|.type SINK, upb_sink -| -|.macro callp, addr -|| upb_assert_notnull(addr); -|// TODO(haberman): fix this. I believe the predicate we should actually be -|// testing is whether the jump distance is greater than INT32_MAX, not the -|// absolute address of the target. -|| if ((uintptr_t)addr < 0xffffffff) { - | call &addr -|| } else { - | mov64 rax, (uintptr_t)addr - | call rax -|| } -|.endmacro -| -|.macro loadarg2, val -||{ -|| uintptr_t data = (uintptr_t)val; -|| if (data > 0xffffffff) { -| mov64 ARG2_64, data -|| } else if (data) { -| mov ARG2_32, data -|| } else { -| xor ARG2_32, ARG2_32 -|| } -|| } -|.endmacro -| -|.macro load_handler_data, h, f, type -| loadarg2 gethandlerdata(h, f, type) -|.endmacro -| -|// Checkpoints our progress by writing PTR to DECODER, and -|// checks for end-of-buffer. -|.macro checkpoint, h -| mov DECODER->ptr, PTR -| cmp PTR, DECODER->effective_end -| jae =>upb_getpclabel(plan, h, ENDOFBUF) -|.endmacro -| -|.macro check_bool_ret -| test al, al -| jz ->exit_jit -|.endmacro -| -|.macro check_ptr_ret -| test rax, rax -| jz ->exit_jit -|.endmacro -| -|// Decodes varint into ARG2. -|// Inputs: -|// - ecx: first 4 bytes of varint -|// - offset: offset from PTR where varint begins -|// Outputs: -|// - ARG2: contains decoded varint -|// - rax: new PTR -|.macro decode_loaded_varint, offset -| // Check for <=2 bytes inline, otherwise jump to 2-10 byte decoder. -| lea rax, [PTR + offset + 1] -| mov ARG2_32, ecx -| and ARG2_32, 0x7f -| test cl, cl -| jns >9 -| lea rax, [PTR + offset + 2] -| movzx edx, ch -| and edx, 0x7f -| shl edx, 7 -| or ARG2_32, edx -| test cx, cx -| jns >9 -| mov ARG1_64, rax -|// XXX: I don't think this handles 64-bit values correctly. -|// Test with UINT64_MAX -| callp upb_vdecode_max8_fast -|// rax return from function will contain new pointer -| mov ARG2_64, rdx -| check_ptr_ret // Check for unterminated, >10-byte varint. -|9: -|.endmacro -| -|.macro decode_varint, offset -| mov ecx, dword [PTR + offset] -| decode_loaded_varint offset -| mov PTR, rax -|.endmacro -| -|// Table-based field dispatch. -|// Inputs: -|// - ecx: first 4 bytes of tag -|// Outputs: -|// - edx: field number -|// - esi: wire type -|// Could specialize this by avoiding the value masking: could just key the -|// table on the raw (length-masked) varint to save 3-4 cycles of latency. -|// Currently only support tables where all entries are in the array part. -|.macro dyndispatch_, h -|| asmlabel(plan, "_UPB_MCODE_DISPATCH_%s.%d", -|| upb_msgdef_fullname(upb_handlers_msgdef(h)), rand()); -|=>upb_getpclabel(plan, h, DYNDISPATCH): -| decode_loaded_varint, 0 -| mov ecx, esi -| shr ecx, 3 -| and esi, 0x7 // Note: this value is used in the FIELD pclabel below. -| cmp esi, UPB_WIRE_TYPE_END_GROUP -| je >1 -|| upb_jitmsginfo *mi = upb_getmsginfo(plan, h); -| cmp ecx, mi->max_field_number // Bounds-check the field. -| ja ->exit_jit // In the future; could be unknown label -|| if ((uintptr_t)mi->tablearray < 0xffffffff) { -| // TODO: support hybrid array/hash tables. -| mov rax, qword [rcx*8 + mi->tablearray] -|| } else { -| mov64 rax, (uintptr_t)mi->tablearray -| mov rax, qword [rax + rcx*8] -|| } -| jmp rax // Dispatch: unpredictable jump. -|1: -|// End group. -| cmp ecx, FRAME->group_fieldnum -| jne ->exit_jit // Unexpected END_GROUP tag. -| mov PTR, rax // rax came from decode_loaded_varint -| mov DECODER->ptr, PTR -| jmp =>upb_getpclabel(plan, h, ENDOFMSG) -|.endmacro -| -|.if 1 -| // Replicated dispatch: larger code, but better branch prediction. -| .define dyndispatch, dyndispatch_ -|.else -| // Single dispatch: smaller code, could be faster because of reduced -| // icache usage. We keep this around to allow for easy comparison between -| // the two. -| .macro dyndispatch, h -| jmp =>upb_getpclabel(plan, h, DYNDISPATCH) -| .endmacro -|.endif -| -|.macro pushsinkframe, handlers, field, endtype -| mov rax, DECODER->sink -| mov dword SINKFRAME->selector, getselector(field, endtype) -| lea rcx, [SINKFRAME + sizeof(upb_sinkframe)] // rcx for short addressing -| cmp rcx, SINK:rax->limit -| jae ->exit_jit // Frame stack overflow. -| mov64 r9, (uintptr_t)handlers -| mov SINKFRAME:rcx->h, r9 -| mov SINKFRAME:rcx->closure, CLOSURE -| mov SINK:rax->top, rcx -| mov SINKFRAME, rcx -|.endmacro -| -|.macro popsinkframe -| sub SINKFRAME, sizeof(upb_sinkframe) -| mov rax, DECODER->sink -| mov SINK:rax->top, SINKFRAME -| mov CLOSURE, SINKFRAME->closure -|.endmacro -| -|// Push a stack frame (not the CPU stack, the upb_pbdecoder stack). -|.macro pushframe, handlers, field, end_offset_, endtype -|// Decoder Frame. -| lea rax, [FRAME + sizeof(frame)] // rax for short addressing -| cmp rax, DECODER->limit -| jae ->exit_jit // Frame stack overflow. -| mov64 r10, (uintptr_t)field -| mov FRAME:rax->f, r10 -| mov qword FRAME:rax->end_ofs, end_offset_ -| mov byte FRAME:rax->is_sequence, (endtype == UPB_HANDLER_ENDSEQ) -| mov byte FRAME:rax->is_packed, 0 -|| if (upb_fielddef_istagdelim(field) && endtype == UPB_HANDLER_ENDSUBMSG) { -| mov dword FRAME:rax->group_fieldnum, upb_fielddef_number(field) -|| } else { -| mov dword FRAME:rax->group_fieldnum, 0xffffffff -|| } -| mov DECODER->top, rax -| mov FRAME, rax -| pushsinkframe handlers, field, endtype -|.endmacro -| -|.macro popframe -| sub FRAME, sizeof(frame) -| mov DECODER->top, FRAME -| popsinkframe -| setmsgend -|.endmacro -| -|.macro setmsgend -| mov rsi, DECODER->jit_end -| mov rax, qword FRAME->end_ofs // Will be UINT64_MAX for groups. -| sub rax, qword DECODER->bufstart_ofs -| add rax, qword DECODER->buf // rax = d->buf + f->end_ofs - d->bufstart_ofs -| jc >8 // If the addition overflowed, use jit_end -| cmp rax, rsi -| ja >8 // If jit_end is less, use jit_end -| mov rsi, rax // Use frame end. -|8: -| mov DECODER->effective_end, rsi -|.endmacro -| -|// rcx contains the tag, compare it against "tag", but since it is a varint -|// we must only compare as many bytes as actually have data. -|.macro checktag, tag -|| switch (upb_value_size(tag)) { -|| case 1: -| cmp cl, tag -|| break; -|| case 2: -| cmp cx, tag -|| break; -|| case 3: -| and ecx, 0xffffff // 3 bytes -| cmp rcx, tag -|| case 4: -| cmp ecx, tag -|| break; -|| case 5: -| mov64 rdx, 0xffffffffff // 5 bytes -| and rcx, rdx -| cmp rcx, tag -|| break; -|| default: abort(); -|| } -|.endmacro -| -|.macro sethas, reg, hasbit -|| if (hasbit >= 0) { -| or byte [reg + ((uint32_t)hasbit / 8)], (1 << ((uint32_t)hasbit % 8)) -|| } -|.endmacro - - -#include <stdlib.h> -#include "upb/pb/varint.h" - -static upb_func *gethandler(const upb_handlers *h, const upb_fielddef *f, - upb_handlertype_t type) { - return upb_handlers_gethandler(h, getselector(f, type)); -} - -static uintptr_t gethandlerdata(const upb_handlers *h, const upb_fielddef *f, - upb_handlertype_t type) { - return (uintptr_t)upb_handlers_gethandlerdata(h, getselector(f, type)); -} - -static void asmlabel(decoderplan *plan, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - char *str = NULL; - size_t size = 0; - upb_vrprintf(&str, &size, 0, fmt, ap); - va_end(ap); - uint32_t label = plan->pclabel_count++; - dasm_growpc(plan, plan->pclabel_count); - |=>label: - upb_inttable_insert(&plan->asmlabels, label, upb_value_ptr(str)); -} - -// Decodes the next val into ARG2, advances PTR. -static void upb_decoderplan_jit_decodefield(decoderplan *plan, - size_t tag_size, - const upb_handlers *h, - const upb_fielddef *f) { - // Decode the value into arg 3 for the callback. - asmlabel(plan, "UPB_MCODE_DECODE_FIELD_%s.%s", - upb_msgdef_fullname(upb_handlers_msgdef(h)), - upb_fielddef_name(f)); - switch (upb_fielddef_descriptortype(f)) { - case UPB_DESCRIPTOR_TYPE_DOUBLE: - | movsd XMMARG1, qword [PTR + tag_size] - | add PTR, 8 + tag_size - break; - - case UPB_DESCRIPTOR_TYPE_FIXED64: - case UPB_DESCRIPTOR_TYPE_SFIXED64: - | mov ARG2_64, qword [PTR + tag_size] - | add PTR, 8 + tag_size - break; - - case UPB_DESCRIPTOR_TYPE_FLOAT: - | movss XMMARG1, dword [PTR + tag_size] - | add PTR, 4 + tag_size - break; - - case UPB_DESCRIPTOR_TYPE_FIXED32: - case UPB_DESCRIPTOR_TYPE_SFIXED32: - | mov ARG2_32, dword [PTR + tag_size] - | add PTR, 4 + tag_size - break; - - case UPB_DESCRIPTOR_TYPE_BOOL: - // Can't assume it's one byte long, because bool must be wire-compatible - // with all of the varint integer types. - | decode_varint tag_size - | test ARG2_64, ARG2_64 - | setne al - | movzx ARG2_32, al - break; - - case UPB_DESCRIPTOR_TYPE_INT64: - case UPB_DESCRIPTOR_TYPE_UINT64: - case UPB_DESCRIPTOR_TYPE_INT32: - case UPB_DESCRIPTOR_TYPE_UINT32: - case UPB_DESCRIPTOR_TYPE_ENUM: - | decode_varint tag_size - break; - - case UPB_DESCRIPTOR_TYPE_SINT64: - // 64-bit zig-zag decoding. - | decode_varint tag_size - | mov rax, ARG2_64 - | shr ARG2_64, 1 - | and rax, 1 - | neg rax - | xor ARG2_64, rax - break; - - case UPB_DESCRIPTOR_TYPE_SINT32: - // 32-bit zig-zag decoding. - | decode_varint tag_size - | mov eax, ARG2_32 - | shr ARG2_32, 1 - | and eax, 1 - | neg eax - | xor ARG2_32, eax - break; - - case UPB_DESCRIPTOR_TYPE_STRING: - case UPB_DESCRIPTOR_TYPE_BYTES: { - // We only handle the case where the entire string is in our current - // buf, which sidesteps any security problems. The C path has more - // robust checks. - | mov ecx, dword [PTR + tag_size] - | decode_loaded_varint tag_size - | mov rdi, DECODER->end - | sub rdi, rax - | cmp ARG2_64, rdi // if (len > d->end - str) - | ja ->exit_jit // Can't deliver, whole string not in buf. - | mov PTR, rax - - upb_func *handler = gethandler(h, f, UPB_HANDLER_STARTSTR); - if (handler) { - // void* startstr(void *c, const void *hd, size_t hint) - | mov DECODER->tmp_len, ARG2_32 - | mov ARG1_64, CLOSURE - | mov ARG3_64, ARG2_64 - | load_handler_data h, f, UPB_HANDLER_STARTSTR - | callp handler - | check_ptr_ret - | mov ARG1_64, rax // sub-closure - | mov ARG4_32, DECODER->tmp_len - } else { - | mov ARG1_64, CLOSURE - | mov ARG4_64, ARG2_64 - } - - handler = gethandler(h, f, UPB_HANDLER_STRING); - if (handler) { - // size_t str(void *c, const void *hd, const char *buf, size_t len) - | load_handler_data h, f, UPB_HANDLER_STRING - | mov ARG3_64, PTR - | callp handler - // TODO: properly handle returns other than "n" (the whole string). - | add PTR, rax - } else { - | add PTR, ARG4_64 - } - - handler = gethandler(h, f, UPB_HANDLER_ENDSTR); - if (handler) { - // bool endstr(const upb_sinkframe *frame); - | mov ARG1_64, CLOSURE - | load_handler_data h, f, UPB_HANDLER_ENDSTR - | callp handler - | check_bool_ret - } - break; - } - - // Will dispatch callbacks and call submessage in a second. - case UPB_DESCRIPTOR_TYPE_MESSAGE: - | decode_varint tag_size - break; - case UPB_DESCRIPTOR_TYPE_GROUP: - | add PTR, tag_size - break; - - default: abort(); - } -} - -static void upb_decoderplan_jit_callcb(decoderplan *plan, - const upb_handlers *h, - const upb_fielddef *f) { - // Call callbacks. Specializing the append accessors didn't yield a speed - // increase in benchmarks. - asmlabel(plan, "UPB_MCODE_CALLCB_%s.%s", - upb_msgdef_fullname(upb_handlers_msgdef(h)), - upb_fielddef_name(f)); - if (upb_fielddef_issubmsg(f)) { - // Call startsubmsg handler (if any). - upb_func *startsubmsg = gethandler(h, f, UPB_HANDLER_STARTSUBMSG); - if (startsubmsg) { - // upb_sflow_t startsubmsg(const upb_sinkframe *frame) - | mov DECODER->tmp_len, ARG2_32 - | mov ARG1_64, CLOSURE - | load_handler_data h, f, UPB_HANDLER_STARTSUBMSG - | callp startsubmsg - | check_ptr_ret - | mov CLOSURE, rax - } - - const upb_handlers *sub_h = upb_handlers_getsubhandlers(h, f); - if (sub_h) { - if (upb_fielddef_istagdelim(f)) { - | mov rdx, UPB_NONDELIMITED - } else { - | mov esi, DECODER->tmp_len - | mov rdx, PTR - | sub rdx, DECODER->buf - | add rdx, DECODER->bufstart_ofs - | add rdx, rsi // = d->bufstart_ofs + (d->ptr - d->buf) + delim_len - } - | pushframe sub_h, f, rdx, UPB_HANDLER_ENDSUBMSG - | call =>upb_getpclabel(plan, sub_h, STARTMSG) - | popframe - } else { - if (upb_fielddef_istagdelim(f)) { - // Groups with no handlers not supported yet. - assert(false); - } else { - | mov esi, DECODER->tmp_len - | add PTR, rsi - } - } - - // Call endsubmsg handler (if any). - upb_func *endsubmsg = gethandler(h, f, UPB_HANDLER_ENDSUBMSG); - if (endsubmsg) { - // upb_flow_t endsubmsg(void *closure, upb_value fval); - | mov ARG1_64, CLOSURE - | load_handler_data h, f, UPB_HANDLER_ENDSUBMSG - | callp endsubmsg - | check_bool_ret - } - } else if (!upb_fielddef_isstring(f)) { - upb_handlertype_t handlertype = upb_handlers_getprimitivehandlertype(f); - upb_selector_t sel = getselector(f, handlertype); - upb_func *handler = gethandler(h, f, handlertype); - const upb_shim_data *data = upb_shim_getdata(h, sel); - if (data) { - switch (upb_fielddef_type(f)) { - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: - | mov [CLOSURE + data->offset], ARG2_64 - break; - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_ENUM: - | mov [CLOSURE + data->offset], ARG2_32 - break; - case UPB_TYPE_DOUBLE: - | movsd qword [CLOSURE + data->offset], XMMARG1 - break; - case UPB_TYPE_FLOAT: - | movss dword [CLOSURE + data->offset], XMMARG1 - break; - case UPB_TYPE_BOOL: - | mov [CLOSURE + data->offset], ARG2_8 - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - assert(false); break; - } - | sethas CLOSURE, data->hasbit - } else if (handler) { - // bool value(const upb_sinkframe* frame, ctype val) - | mov ARG1_64, CLOSURE - | mov ARG3_64, ARG2_64 - | load_handler_data h, f, handlertype - | callp handler - | check_bool_ret - } - } -} - -static uint64_t upb_get_encoded_tag(const upb_fielddef *f) { - uint32_t tag = (upb_fielddef_number(f) << 3) | - upb_decoder_types[upb_fielddef_descriptortype(f)].native_wire_type; - uint64_t encoded_tag = upb_vencode32(tag); - // No tag should be greater than 5 bytes. - assert(encoded_tag <= 0xffffffffff); - return encoded_tag; -} - -static void upb_decoderplan_jit_endseq(decoderplan *plan, - const upb_handlers *h, - const upb_fielddef *f) { - | popframe - upb_func *endseq = gethandler(h, f, UPB_HANDLER_ENDSEQ); - if (endseq) { - | mov ARG1_64, CLOSURE - | load_handler_data h, f, UPB_HANDLER_ENDSEQ - | callp endseq - } -} - -// PTR should point to the beginning of the tag. -static void upb_decoderplan_jit_field(decoderplan *plan, - const upb_handlers *h, - const upb_fielddef *f, - const upb_fielddef *next_f) { - asmlabel(plan, "UPB_MCODE_FIELD_%s.%s", - upb_msgdef_fullname(upb_handlers_msgdef(h)), - upb_fielddef_name(f)); - uint64_t tag = upb_get_encoded_tag(f); - uint64_t next_tag = next_f ? upb_get_encoded_tag(next_f) : 0; - int tag_size = upb_value_size(tag); - - // PC-label for the dispatch table. - // We check the wire type (which must be loaded in edi) because the - // table is keyed on field number, not type. - |=>upb_getpclabel(plan, f, FIELD): - | cmp esi, (tag & 0x7) - | jne ->exit_jit // In the future: could be an unknown field or packed. - |=>upb_getpclabel(plan, f, FIELD_NO_TYPECHECK): - if (upb_fielddef_isseq(f)) { - upb_func *startseq = gethandler(h, f, UPB_HANDLER_STARTSEQ); - if (startseq) { - | mov ARG1_64, CLOSURE - | load_handler_data h, f, UPB_HANDLER_STARTSEQ - | callp startseq - | check_ptr_ret - | mov CLOSURE, rax - } - | mov rsi, FRAME->end_ofs - | pushframe h, f, rsi, UPB_HANDLER_ENDSEQ - } - - |1: // Label for repeating this field. - - upb_decoderplan_jit_decodefield(plan, tag_size, h, f); - upb_decoderplan_jit_callcb(plan, h, f); - - // This is kind of gross; future redesign should take into account how to - // make this work nicely. The difficult part is that the sequence can be - // broken either by end-of-message or by seeing a different field; in both - // cases we need to call the endseq handler, but what we do after that - // depends on which case triggered the end-of-sequence. - | mov DECODER->ptr, PTR - | cmp PTR, DECODER->jit_end - | jae ->exit_jit - | cmp PTR, DECODER->effective_end - | jb >2 - if (upb_fielddef_isseq(f)) { - upb_decoderplan_jit_endseq(plan, h, f); - } - | jmp =>upb_getpclabel(plan, h, ENDOFMSG) - |2: - | mov rcx, qword [PTR] - if (upb_fielddef_isseq(f)) { - | checktag tag - | je <1 - upb_decoderplan_jit_endseq(plan, h, f); - // Load next tag again (popframe/endseq clobbered it). - | mov rcx, qword [PTR] - } - - if (next_tag != 0) { - | checktag next_tag - | je =>upb_getpclabel(plan, next_f, FIELD_NO_TYPECHECK) - } - - // Fall back to dynamic dispatch. - | dyndispatch h -} - -static int upb_compare_uint32(const void *a, const void *b) { - return *(uint32_t*)a - *(uint32_t*)b; -} - -static void upb_decoderplan_jit_msg(decoderplan *plan, - const upb_handlers *h) { - asmlabel(plan, "UPB_MCODE_DECODEMSG_%s", - upb_msgdef_fullname(upb_handlers_msgdef(h))); - |=>upb_getpclabel(plan, h, AFTER_STARTMSG): - | push rbp - | mov rbp, rsp - | jmp >1 - - |=>upb_getpclabel(plan, h, STARTMSG): - | push rbp - | mov rbp, rsp - - // Call startmsg handler (if any): - upb_func *startmsg = upb_handlers_gethandler(h, UPB_STARTMSG_SELECTOR); - if (startmsg) { - // upb_flow_t startmsg(void *closure, const void *hd); - | mov ARG1_64, CLOSURE - | loadarg2 upb_handlers_gethandlerdata(h, UPB_STARTMSG_SELECTOR) - | callp startmsg - | check_bool_ret - } - - |1: - | setmsgend - | checkpoint h - | mov ecx, dword [PTR] - | dyndispatch_ h - - // --------- New code section (does not fall through) ------------------------ - - // Emit code for parsing each field (dynamic dispatch contains pointers to - // all of these). - - // Create an ordering over the fields in field number order. - // Parsing will theoretically be fastest if we emit code in the same - // order as field numbers are seen on-the-wire because of an optimization - // in the generated code that skips dynamic dispatch if the next field is - // as expected. - const upb_msgdef *md = upb_handlers_msgdef(h); - int num_keys = upb_msgdef_numfields(md); - uint32_t *keys = malloc(num_keys * sizeof(*keys)); - int idx = 0; - upb_msg_iter i; - for(upb_msg_begin(&i, md); !upb_msg_done(&i); upb_msg_next(&i)) { - keys[idx++] = upb_fielddef_number(upb_msg_iter_field(&i)); - } - qsort(keys, num_keys, sizeof(uint32_t), &upb_compare_uint32); - - for(int i = 0; i < num_keys; i++) { - const upb_fielddef *f = upb_msgdef_itof(md, keys[i]); - const upb_fielddef *next_f = - (i + 1 < num_keys) ? upb_msgdef_itof(md, keys[i + 1]) : NULL; - upb_decoderplan_jit_field(plan, h, f, next_f); - } - - free(keys); - - // --------- New code section (does not fall through) ------------------------ - - // End-of-buf / end-of-message. - // We hit a buffer limit; either we hit jit_end or end-of-submessage. - |=>upb_getpclabel(plan, h, ENDOFBUF): - | cmp PTR, DECODER->jit_end - | jae ->exit_jit - - |=>upb_getpclabel(plan, h, ENDOFMSG): - // We are at end-of-submsg: call endmsg handler (if any): - upb_func *endmsg = upb_handlers_gethandler(h, UPB_ENDMSG_SELECTOR); - if (endmsg) { - // void endmsg(void *closure, const void *hd, upb_status *status) { - | mov ARG1_64, CLOSURE - | loadarg2 upb_handlers_gethandlerdata(h, UPB_ENDMSG_SELECTOR) - | mov ARG3_64, DECODER->sink - | mov ARG3_64, SINK:ARG3_64->pipeline_ - | add ARG3_64, offsetof(upb_pipeline, status_) - | callp endmsg - } - - | leave - | ret -} - -static void upb_decoderplan_jit(decoderplan *plan) { - // The JIT prologue/epilogue trampoline that is generated in this function - // does not depend on the handlers, so it will never vary. Ideally we would - // put it in an object file and just link it into upb so we could have only a - // single copy of it instead of one copy for each decoderplan. But our - // options for doing that are undesirable: GCC inline assembly is - // complicated, not portable to other compilers, and comes with subtle - // caveats about incorrect things what the optimizer might do if you eg. - // execute non-local jumps. Putting this code in a .s file would force us to - // calculate the structure offsets ourself instead of symbolically - // (ie. [r15 + 0xcd] instead of DECODER->ptr). So we tolerate a bit of - // unnecessary duplication/redundancy. - asmlabel(plan, "upb_jit_trampoline"); - | push rbp - | mov rbp, rsp - | push r15 - | push r14 - | push r13 - | push r12 - | push rbx - // Align stack. - | sub rsp, 8 - | mov DECODER, ARG1_64 - | mov DECODER->saved_rbp, rbp - | mov FRAME, DECODER:ARG1_64->top - | mov rax, DECODER:ARG1_64->sink - | mov SINKFRAME, SINK:rax->top - | mov CLOSURE, SINKFRAME->closure - | mov PTR, DECODER->ptr - - // TODO: push return addresses for re-entry (will be necessary for multiple - // buffer support). - | call ARG2_64 - asmlabel(plan, "exitjit"); - |->exit_jit: - | mov rbp, DECODER->saved_rbp - | lea rsp, [rbp - 48] - // Counter previous alignment. - | add rsp, 8 - | pop rbx - | pop r12 - | pop r13 - | pop r14 - | pop r15 - | leave - | ret - - upb_inttable_iter i; - upb_inttable_begin(&i, &plan->msginfo); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - const upb_handlers *h = (const upb_handlers*)upb_inttable_iter_key(&i); - upb_decoderplan_jit_msg(plan, h); - } -} - -static void upb_decoderplan_jit_assignpclabels(decoderplan *plan, - const upb_handlers *h) { - // Limit the DFS. - if (upb_inttable_lookupptr(&plan->pclabels, h, NULL)) return; - - upb_inttable_insertptr(&plan->pclabels, h, - upb_value_uint32(plan->pclabel_count)); - plan->pclabel_count += TOTAL_MSG_PCLABELS; - - upb_jitmsginfo *info = malloc(sizeof(*info)); - info->max_field_number = 0; - upb_inttable_insertptr(&plan->msginfo, h, upb_value_ptr(info)); - - upb_msg_iter i; - upb_msg_begin(&i, upb_handlers_msgdef(h)); - for(; !upb_msg_done(&i); upb_msg_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - info->max_field_number = - UPB_MAX(info->max_field_number, upb_fielddef_number(f)); - upb_inttable_insertptr(&plan->pclabels, f, - upb_value_uint32(plan->pclabel_count)); - plan->pclabel_count += TOTAL_FIELD_PCLABELS; - - // Discover the whole graph of handlers depth-first. We will probably - // revise this later to be more explicit about the list of handlers that - // the plan should include. - if (upb_fielddef_issubmsg(f)) { - const upb_handlers *subh = upb_handlers_getsubhandlers(h, f); - if (subh) upb_decoderplan_jit_assignpclabels(plan, subh); - } - } - // TODO: support large field numbers by either using a hash table or - // generating code for a binary search. For now large field numbers - // will just fall back to the table decoder. - info->max_field_number = UPB_MIN(info->max_field_number, 16000); - info->tablearray = malloc((info->max_field_number + 1) * sizeof(void*)); -} - -static void upb_decoderplan_makejit(decoderplan *plan) { - upb_inttable_init(&plan->msginfo, UPB_CTYPE_PTR); - plan->debug_info = NULL; - - // Assign pclabels. - plan->pclabel_count = 0; - upb_inttable_init(&plan->pclabels, UPB_CTYPE_UINT32); - upb_decoderplan_jit_assignpclabels(plan, plan->dest_handlers); - - upb_inttable_init(&plan->asmlabels, UPB_CTYPE_PTR); - - void **globals = malloc(UPB_JIT_GLOBAL__MAX * sizeof(*globals)); - dasm_init(plan, 1); - dasm_setupglobal(plan, globals, UPB_JIT_GLOBAL__MAX); - dasm_growpc(plan, plan->pclabel_count); - dasm_setup(plan, upb_jit_actionlist); - - upb_decoderplan_jit(plan); - - int dasm_status = dasm_link(plan, &plan->jit_size); - (void)dasm_status; - assert(dasm_status == DASM_S_OK); - - plan->jit_code = mmap(NULL, plan->jit_size, PROT_READ | PROT_WRITE, - MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); - - upb_reg_jit_gdb(plan); - - dasm_encode(plan, plan->jit_code); - - // Create dispatch tables. - upb_inttable_iter i; - upb_inttable_begin(&i, &plan->msginfo); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - const upb_handlers *h = (const upb_handlers*)upb_inttable_iter_key(&i); - upb_jitmsginfo *mi = upb_getmsginfo(plan, h); - // We jump to after the startmsg handler since it is called before entering - // the JIT (either by upb_pbdecoder or by a previous call to the JIT). - mi->jit_func = plan->jit_code + - dasm_getpclabel(plan, upb_getpclabel(plan, h, AFTER_STARTMSG)); - for (uint32_t j = 0; j <= mi->max_field_number; j++) { - const upb_fielddef *f = upb_msgdef_itof(upb_handlers_msgdef(h), j); - if (f) { - mi->tablearray[j] = plan->jit_code + - dasm_getpclabel(plan, upb_getpclabel(plan, f, FIELD)); - } else { - // TODO: extend the JIT to handle unknown fields. - // For the moment we exit the JIT for any unknown field. - mi->tablearray[j] = globals[UPB_JIT_GLOBAL_exit_jit]; - } - } - } - - upb_inttable_uninit(&plan->pclabels); - - mprotect(plan->jit_code, plan->jit_size, PROT_EXEC | PROT_READ); - -#ifndef NDEBUG - // Dump to a .o file in /tmp, for easy inspection. - - // Convert all asm labels from pclabel offsets to machine code offsets. - upb_inttable mclabels; - upb_inttable_init(&mclabels, UPB_CTYPE_PTR); - upb_inttable_begin(&i, &plan->asmlabels); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - upb_inttable_insert( - &mclabels, - dasm_getpclabel(plan, upb_inttable_iter_key(&i)), - upb_inttable_iter_value(&i)); - } - - FILE *f = fopen("/tmp/upb-jit-code.s", "w"); - if (f) { - fputs(" .text", f); - size_t linelen = 0; - for (size_t i = 0; i < plan->jit_size; i++) { - upb_value v; - if (upb_inttable_lookup(&mclabels, i, &v)) { - const char *label = upb_value_getptr(v); - fprintf(f, "\n\n_%s:\n", label); - fprintf(f, " .globl _%s", label); - linelen = 1000; - } - if (linelen >= 77) { - linelen = fprintf(f, "\n .byte %u", plan->jit_code[i]); - } else { - linelen += fprintf(f, ",%u", plan->jit_code[i]); - } - } - fputs("\n", f); - fclose(f); - } else { - fprintf(stderr, "Couldn't open /tmp/upb-jit-code.s for writing/\n"); - } - - upb_inttable_uninit(&mclabels); -#endif - - upb_inttable_begin(&i, &plan->asmlabels); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - free(upb_value_getptr(upb_inttable_iter_value(&i))); - } - upb_inttable_uninit(&plan->asmlabels); - - dasm_free(plan); - free(globals); -} - -static void upb_decoderplan_freejit(decoderplan *plan) { - upb_inttable_iter i; - upb_inttable_begin(&i, &plan->msginfo); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - upb_jitmsginfo *mi = upb_value_getptr(upb_inttable_iter_value(&i)); - free(mi->tablearray); - free(mi); - } - upb_inttable_uninit(&plan->msginfo); - munmap(plan->jit_code, plan->jit_size); - free(plan->debug_info); - // TODO: unregister -} - -static void upb_decoder_enterjit(upb_pbdecoder *d, const decoderplan *plan) { - if (plan->jit_code && - d->top == d->stack && - d->sink->top == d->sink->stack && - d->ptr && d->ptr < d->jit_end) { -#ifndef NDEBUG - register uint64_t rbx asm ("rbx") = 11; - register uint64_t r12 asm ("r12") = 12; - register uint64_t r13 asm ("r13") = 13; - register uint64_t r14 asm ("r14") = 14; - register uint64_t r15 asm ("r15") = 15; -#endif - // Decodes as many fields as possible, updating d->ptr appropriately, - // before falling through to the slow(er) path. - void (*upb_jit_decode)(upb_pbdecoder *d, void*) = (void*)plan->jit_code; - upb_jitmsginfo *mi = upb_getmsginfo(plan, plan->dest_handlers); - assert(mi); - upb_jit_decode(d, mi->jit_func); - assert(d->ptr <= d->end); - - // Test that callee-save registers were properly restored. - assert(rbx == 11); - assert(r12 == 12); - assert(r13 == 13); - assert(r14 == 14); - assert(r15 == 15); - } -} diff --git a/upb/pb/glue.c b/upb/pb/glue.c index 2c621f4..9027e0f 100644 --- a/upb/pb/glue.c +++ b/upb/pb/glue.c @@ -19,7 +19,7 @@ upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, // Create handlers. const upb_handlers *reader_h = upb_descreader_gethandlers(&reader_h); const upb_handlers *decoder_h = - upb_pbdecoder_gethandlers(reader_h, false, &decoder_h); + upb_pbdecoder_gethandlers(reader_h, true, &decoder_h); // Create pipeline. upb_pipeline pipeline; @@ -68,8 +68,8 @@ char *upb_readfile(const char *filename, size_t *len) { long size = ftell(f); if(size < 0) goto error; if(fseek(f, 0, SEEK_SET) != 0) goto error; - char *buf = malloc(size); - if(fread(buf, size, 1, f) != 1) goto error; + char *buf = malloc(size + 1); + if(size && fread(buf, size, 1, f) != 1) goto error; fclose(f); if (len) *len = size; return buf; diff --git a/upb/pb/varint.c b/upb/pb/varint.c index d6d6161..ccd752d 100644 --- a/upb/pb/varint.c +++ b/upb/pb/varint.c @@ -5,7 +5,7 @@ * Author: Josh Haberman <jhaberman@gmail.com> */ -#include "upb/pb/varint.h" +#include "upb/pb/varint.int.h" // A basic branch-based decoder, uses 32-bit values to get good performance // on 32-bit architectures (but performs well on 64-bits also). diff --git a/upb/pb/varint.h b/upb/pb/varint.int.h index d33872d..d92fef9 100644 --- a/upb/pb/varint.h +++ b/upb/pb/varint.int.h @@ -11,6 +11,7 @@ #ifndef UPB_VARINT_DECODER_H_ #define UPB_VARINT_DECODER_H_ +#include <assert.h> #include <stdint.h> #include <string.h> #include "upb/upb.h" @@ -29,6 +30,8 @@ typedef enum { UPB_WIRE_TYPE_32BIT = 5, } upb_wiretype_t; +#define UPB_MAX_WIRE_TYPE 5 + // The maximum number of bytes that it takes to encode a 64-bit varint. // Note that with a better encoding this could be 9 (TODO: write up a // wiki document about this). @@ -87,7 +90,7 @@ UPB_VARINT_DECODER_CHECK2(massimino, upb_vdecode_max8_massimino); // favored best-performing implementations. UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) { if (sizeof(long) == 8) - return upb_vdecode_check2_massimino(p); + return upb_vdecode_check2_branch64(p); else return upb_vdecode_check2_branch32(p); } diff --git a/upb/refcounted.c b/upb/refcounted.c index 1e517b7..fbeca64 100644 --- a/upb/refcounted.c +++ b/upb/refcounted.c @@ -24,6 +24,7 @@ #include <stdlib.h> uint32_t static_refcount = 1; +static void freeobj(upb_refcounted *o); /* arch-specific atomic primitives *******************************************/ @@ -74,90 +75,26 @@ void upb_unlock(); // code-paths that can normally never fail, like upb_refcounted_ref(). Since // we have no way to propagage out-of-memory errors back to the user, and since // these errors can only occur in UPB_DEBUG_REFS mode, we immediately fail. -#define CHECK_OOM(predicate) assert(predicate) +#define CHECK_OOM(predicate) if (!(predicate)) { assert(predicate); exit(1); } typedef struct { - const upb_refcounted *obj; // Object we are taking a ref on. int count; // How many refs there are (duplicates only allowed for ref2). bool is_ref2; } trackedref; -trackedref *trackedref_new(const upb_refcounted *obj, bool is_ref2) { +trackedref *trackedref_new(bool is_ref2) { trackedref *ret = malloc(sizeof(*ret)); CHECK_OOM(ret); - ret->obj = obj; ret->count = 1; ret->is_ref2 = is_ref2; return ret; } -// A reversible function for obfuscating a uintptr_t. -// This depends on sizeof(uintptr_t) <= sizeof(uint64_t), so would fail -// on 128-bit machines. -static uintptr_t obfuscate(const void *x) { return ~(uintptr_t)x; } - -static upb_value obfuscate_v(const void *x) { - return upb_value_uint64(obfuscate(x)); -} - -static const void *unobfuscate_v(upb_value x) { - return (void*)~upb_value_getuint64(x); -} - -// -// Stores tracked references according to the following scheme: -// (upb_inttable)reftracks = { -// (void*)owner -> (upb_inttable*) = { -// obfuscate((upb_refcounted*)obj) -> obfuscate((trackedref*)is_ref2) -// } -// } -// -// obfuscate() is a function that hides the link from the heap checker, so -// that it is not followed for the purposes of deciding what has "indirectly -// leaked." Even though we have a pointer to the trackedref*, we want it to -// appear leaked if it is not freed. -// -// This scheme gives us the following desirable properties: -// -// 1. We can easily determine whether an (owner->obj) ref already exists -// and error out if a duplicate ref is taken. -// -// 2. Because the trackedref is allocated with malloc() at the point that -// the ref is taken, that memory will be leaked if the ref is not released. -// Because the malloc'd memory points to the refcounted object, the object -// itself will only be considered "indirectly leaked" by smart memory -// checkers like Valgrind. This will correctly blame the ref leaker -// instead of the innocent code that allocated the object to begin with. -// -// 3. We can easily enumerate all of the ref2 refs for a given owner, which -// allows us to double-check that the object's visit() function is -// correctly implemented. -// -static upb_inttable reftracks = UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR); - -static upb_inttable *trygettab(const void *p) { - upb_value v; - return upb_inttable_lookupptr(&reftracks, p, &v) ? upb_value_getptr(v) : NULL; -} - -// Gets or creates the tracking table for the given owner. -static upb_inttable *gettab(const void *p) { - upb_inttable *tab = trygettab(p); - if (tab == NULL) { - tab = malloc(sizeof(*tab)); - CHECK_OOM(tab); - upb_inttable_init(tab, UPB_CTYPE_UINT64); - upb_inttable_insertptr(&reftracks, p, upb_value_ptr(tab)); - } - return tab; -} - static void track(const upb_refcounted *r, const void *owner, bool ref2) { upb_lock(); - upb_inttable *refs = gettab(owner); upb_value v; - if (upb_inttable_lookup(refs, obfuscate(r), &v)) { - trackedref *ref = (trackedref*)unobfuscate_v(v); + if (upb_inttable_lookupptr(r->refs, owner, &v)) { + trackedref *ref = upb_value_getptr(v); // Since we allow multiple ref2's for the same to/from pair without // allocating separate memory for each one, we lose the fine-grained // tracking behavior we get with regular refs. Since ref2s only happen @@ -167,29 +104,38 @@ static void track(const upb_refcounted *r, const void *owner, bool ref2) { assert(ref->is_ref2); ref->count++; } else { - trackedref *ref = trackedref_new(r, ref2); - bool ok = upb_inttable_insert(refs, obfuscate(r), obfuscate_v(ref)); + trackedref *ref = trackedref_new(ref2); + bool ok = upb_inttable_insertptr(r->refs, owner, upb_value_ptr(ref)); CHECK_OOM(ok); + if (ref2) { + // We know this cast is safe when it is a ref2, because it's coming from + // another refcounted object. + const upb_refcounted *from = owner; + assert(!upb_inttable_lookupptr(from->ref2s, r, NULL)); + ok = upb_inttable_insertptr(from->ref2s, r, upb_value_ptr(NULL)); + CHECK_OOM(ok); + } } upb_unlock(); } static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { upb_lock(); - upb_inttable *refs = gettab(owner); upb_value v; - bool found = upb_inttable_lookup(refs, obfuscate(r), &v); + bool found = upb_inttable_lookupptr(r->refs, owner, &v); // This assert will fail if an owner attempts to release a ref it didn't have. UPB_ASSERT_VAR(found, found); - trackedref *ref = (trackedref*)unobfuscate_v(v); + trackedref *ref = upb_value_getptr(v); assert(ref->is_ref2 == ref2); if (--ref->count == 0) { free(ref); - upb_inttable_remove(refs, obfuscate(r), NULL); - if (upb_inttable_count(refs) == 0) { - upb_inttable_uninit(refs); - free(refs); - upb_inttable_removeptr(&reftracks, owner, NULL); + upb_inttable_removeptr(r->refs, owner, NULL); + if (ref2) { + // We know this cast is safe when it is a ref2, because it's coming from + // another refcounted object. + const upb_refcounted *from = owner; + bool removed = upb_inttable_removeptr(from->ref2s, r, NULL); + assert(removed); } } upb_unlock(); @@ -197,12 +143,10 @@ static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { upb_lock(); - upb_inttable *refs = gettab(owner); upb_value v; - bool found = upb_inttable_lookup(refs, obfuscate(r), &v); + bool found = upb_inttable_lookupptr(r->refs, owner, &v); UPB_ASSERT_VAR(found, found); - trackedref *ref = (trackedref*)unobfuscate_v(v); - assert(ref->obj == r); + trackedref *ref = upb_value_getptr(v); assert(ref->is_ref2 == ref2); upb_unlock(); } @@ -211,18 +155,20 @@ static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { // originate from the given owner. static void getref2s(const upb_refcounted *owner, upb_inttable *tab) { upb_lock(); - upb_inttable *refs = trygettab(owner); - if (refs) { - upb_inttable_iter i; - upb_inttable_begin(&i, refs); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - trackedref *ref = (trackedref*)unobfuscate_v(upb_inttable_iter_value(&i)); - if (ref->is_ref2) { - upb_value count = upb_value_int32(ref->count); - bool ok = upb_inttable_insertptr(tab, ref->obj, count); - CHECK_OOM(ok); - } - } + upb_inttable_iter i; + upb_inttable_begin(&i, owner->ref2s); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_refcounted *to = (upb_refcounted*)upb_inttable_iter_key(&i); + + // To get the count we need to look in the target's table. + upb_value v; + bool found = upb_inttable_lookupptr(to->refs, owner, &v); + assert(found); + trackedref *ref = upb_value_getptr(v); + upb_value count = upb_value_int32(ref->count); + + bool ok = upb_inttable_insertptr(tab, to, count); + CHECK_OOM(ok); } upb_unlock(); } @@ -269,6 +215,30 @@ static void visit(const upb_refcounted *r, upb_refcounted_visit *v, if (r->vtbl->visit) r->vtbl->visit(r, v, closure); } +static bool trackinit(upb_refcounted *r) { + r->refs = malloc(sizeof(*r->refs)); + r->ref2s = malloc(sizeof(*r->ref2s)); + if (!r->refs || !r->ref2s) goto err1; + + if (!upb_inttable_init(r->refs, UPB_CTYPE_PTR)) goto err1; + if (!upb_inttable_init(r->ref2s, UPB_CTYPE_PTR)) goto err2; + return true; + +err2: + upb_inttable_uninit(r->refs); +err1: + free(r->refs); + free(r->ref2s); + return false; +} + +static void trackfree(const upb_refcounted *r) { + upb_inttable_uninit(r->refs); + upb_inttable_uninit(r->ref2s); + free(r->refs); + free(r->ref2s); +} + #else static void track(const upb_refcounted *r, const void *owner, bool ref2) { @@ -289,6 +259,15 @@ static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { UPB_UNUSED(ref2); } +static bool trackinit(upb_refcounted *r) { + UPB_UNUSED(r); + return true; +} + +static void trackfree(const upb_refcounted *r) { + UPB_UNUSED(r); +} + static void visit(const upb_refcounted *r, upb_refcounted_visit *v, void *closure) { if (r->vtbl->visit) r->vtbl->visit(r, v, closure); @@ -505,7 +484,8 @@ static void crossref(const upb_refcounted *r, const upb_refcounted *subobj, } } -static bool freeze(upb_refcounted *const*roots, int n, upb_status *s) { +static bool freeze(upb_refcounted *const*roots, int n, upb_status *s, + int maxdepth) { volatile bool ret = false; // We run in two passes so that we can allocate all memory before performing @@ -514,7 +494,7 @@ static bool freeze(upb_refcounted *const*roots, int n, upb_status *s) { tarjan t; t.index = 0; t.depth = 0; - t.maxdepth = UPB_MAX_TYPE_DEPTH * 2; // May want to make this a parameter. + t.maxdepth = maxdepth; t.status = s; if (!upb_inttable_init(&t.objattr, UPB_CTYPE_UINT64)) goto err1; if (!upb_inttable_init(&t.stack, UPB_CTYPE_PTR)) goto err2; @@ -628,7 +608,7 @@ static bool freeze(upb_refcounted *const*roots, int n, upb_status *s) { o = obj; do { o->group = NULL; } while ((o = o->next) != obj); } - obj->vtbl->free(obj); + freeobj(obj); } } @@ -680,11 +660,11 @@ static void release_ref2(const upb_refcounted *obj, const upb_refcounted *subobj, void *closure) { UPB_UNUSED(closure); + untrack(subobj, obj, true); if (!merged(obj, subobj)) { assert(subobj->is_frozen); unref(subobj); } - untrack(subobj, obj, true); } static void unref(const upb_refcounted *r) { @@ -700,12 +680,17 @@ static void unref(const upb_refcounted *r) { do { const upb_refcounted *next = o->next; assert(o->is_frozen || o->individual_count == 0); - o->vtbl->free((upb_refcounted*)o); + freeobj((upb_refcounted*)o); o = next; } while(o != r); } } +static void freeobj(upb_refcounted *o) { + trackfree(o); + o->vtbl->free((upb_refcounted*)o); +} + /* Public interface ***********************************************************/ @@ -719,6 +704,10 @@ bool upb_refcounted_init(upb_refcounted *r, r->group = malloc(sizeof(*r->group)); if (!r->group) return false; *r->group = 0; + if (!trackinit(r)) { + free(r->group); + return false; + } upb_refcounted_ref(r, owner); return true; } @@ -728,37 +717,37 @@ bool upb_refcounted_isfrozen(const upb_refcounted *r) { } void upb_refcounted_ref(const upb_refcounted *r, const void *owner) { + track(r, owner, false); if (!r->is_frozen) ((upb_refcounted*)r)->individual_count++; atomic_inc(r->group); - track(r, owner, false); } void upb_refcounted_unref(const upb_refcounted *r, const void *owner) { + untrack(r, owner, false); if (!r->is_frozen) ((upb_refcounted*)r)->individual_count--; unref(r); - untrack(r, owner, false); } void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from) { assert(!from->is_frozen); // Non-const pointer implies this. + track(r, from, true); if (r->is_frozen) { atomic_inc(r->group); } else { merge((upb_refcounted*)r, from); } - track(r, from, true); } void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from) { assert(!from->is_frozen); // Non-const pointer implies this. + untrack(r, from, true); if (r->is_frozen) { unref(r); } else { assert(merged(r, from)); } - untrack(r, from, true); } void upb_refcounted_donateref( @@ -774,9 +763,10 @@ void upb_refcounted_checkref(const upb_refcounted *r, const void *owner) { checkref(r, owner, false); } -bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s) { +bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s, + int maxdepth) { for (int i = 0; i < n; i++) { assert(!roots[i]->is_frozen); } - return freeze(roots, n, s); + return freeze(roots, n, s, maxdepth); } diff --git a/upb/refcounted.h b/upb/refcounted.h index 19993ca..a0d535a 100644 --- a/upb/refcounted.h +++ b/upb/refcounted.h @@ -19,7 +19,7 @@ #ifndef UPB_REFCOUNTED_H_ #define UPB_REFCOUNTED_H_ -#include "upb/table.h" +#include "upb/table.int.h" // Reference tracking is designed to be used with a tool like Valgrind; when // enabled, it will cause reference leaks to show up as actual memory leaks @@ -86,6 +86,11 @@ struct upb_refcounted { uint32_t individual_count; bool is_frozen; + +#ifdef UPB_DEBUG_REFS + upb_inttable *refs; // Maps owner -> trackedref for incoming refs. + upb_inttable *ref2s; // Set of targets for outgoing ref2s. +#endif }; // Native C API. @@ -137,8 +142,9 @@ void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from); // Freezes all mutable object reachable by ref2() refs from the given roots. // This will split refcounting groups into precise SCC groups, so that // refcounting of frozen objects can be more aggressive. If memory allocation -// fails or if more than 2**31 mutable objects are reachable from "roots", -// false is returned and the objects are unchanged. +// fails, or if more than 2**31 mutable objects are reachable from "roots", or +// if the maximum depth of the graph exceeds "maxdepth", false is returned and +// the objects are unchanged. // // After this operation succeeds, the objects are frozen/const, and may not be // used through non-const pointers. In particular, they may not be passed as @@ -147,12 +153,18 @@ void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from); // at the precise moment that they become unreachable. // // Caller must own refs on each object in the "roots" list. -bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s); +bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s, + int maxdepth); // Shared by all compiled-in refcounted objects. extern uint32_t static_refcount; -#define UPB_REFCOUNT_INIT {&static_refcount, NULL, NULL, 0, true} +#ifdef UPB_DEBUG_REFS +#define UPB_REFCOUNT_INIT(refs, ref2s) \ + {&static_refcount, NULL, NULL, 0, true, refs, ref2s} +#else +#define UPB_REFCOUNT_INIT(refs, ref2s) {&static_refcount, NULL, NULL, 0, true} +#endif #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/shim/shim.c b/upb/shim/shim.c index 6a79ac0..a249e84 100644 --- a/upb/shim/shim.c +++ b/upb/shim/shim.c @@ -53,17 +53,27 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, #undef TYPE } -const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s) { +const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s, + upb_fieldtype_t *type) { upb_func *f = upb_handlers_gethandler(h, s); - if ((upb_int64_handler*)f == upb_shim_setint64 || - (upb_int32_handler*)f == upb_shim_setint32 || - (upb_uint64_handler*)f == upb_shim_setuint64 || - (upb_uint32_handler*)f == upb_shim_setuint32 || - (upb_double_handler*)f == upb_shim_setdouble || - (upb_float_handler*)f == upb_shim_setfloat || - (upb_bool_handler*)f == upb_shim_setbool) { - return (const upb_shim_data*)upb_handlers_gethandlerdata(h, s); + + if ((upb_int64_handler*)f == upb_shim_setint64) { + *type = UPB_TYPE_INT64; + } else if ((upb_int32_handler*)f == upb_shim_setint32) { + *type = UPB_TYPE_INT32; + } else if ((upb_uint64_handler*)f == upb_shim_setuint64) { + *type = UPB_TYPE_UINT64; + } else if ((upb_uint32_handler*)f == upb_shim_setuint32) { + *type = UPB_TYPE_UINT32; + } else if ((upb_double_handler*)f == upb_shim_setdouble) { + *type = UPB_TYPE_DOUBLE; + } else if ((upb_float_handler*)f == upb_shim_setfloat) { + *type = UPB_TYPE_FLOAT; + } else if ((upb_bool_handler*)f == upb_shim_setbool) { + *type = UPB_TYPE_BOOL; } else { return NULL; } + + return (const upb_shim_data*)upb_handlers_gethandlerdata(h, s); } diff --git a/upb/shim/shim.h b/upb/shim/shim.h index 98310d7..bc47bbb 100644 --- a/upb/shim/shim.h +++ b/upb/shim/shim.h @@ -37,9 +37,10 @@ struct Shim { // true if the handler was set successfully. static bool Set(Handlers *h, const FieldDef *f, size_t ofs, int32_t hasbit); - // If this handler is a shim, returns the corresponding upb::Shim::Data. - // Otherwise returns NULL. - static const Data* GetData(const Handlers* h, Handlers::Selector s); + // If this handler is a shim, returns the corresponding upb::Shim::Data and + // stores the type in "type". Otherwise returns NULL. + static const Data* GetData(const Handlers* h, Handlers::Selector s, + FieldDef::Type* type); }; } // namespace upb @@ -50,7 +51,8 @@ extern "C" { // C API. bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, int32_t hasbit); -const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s); +const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s, + upb_fieldtype_t *type); #ifdef __cplusplus } // extern "C" @@ -62,9 +64,9 @@ inline bool Shim::Set(Handlers* h, const FieldDef* f, size_t ofs, int32_t hasbit) { return upb_shim_set(h, f, ofs, hasbit); } -inline const Shim::Data* Shim::GetData(const Handlers* h, - Handlers::Selector s) { - return upb_shim_getdata(h, s); +inline const Shim::Data* Shim::GetData(const Handlers* h, Handlers::Selector s, + FieldDef::Type* type) { + return upb_shim_getdata(h, s, type); } } // namespace @@ -201,9 +201,9 @@ static void upb_sink_resetobj(void *obj) { static void upb_sink_init(upb_sink *s, const upb_handlers *h, upb_pipeline *p) { s->pipeline_ = p; - s->stack = upb_pipeline_alloc(p, sizeof(*s->stack) * UPB_MAX_NESTING); + s->stack = upb_pipeline_alloc(p, sizeof(*s->stack) * UPB_SINK_MAX_NESTING); s->top = s->stack; - s->limit = s->stack + UPB_MAX_NESTING; + s->limit = s->stack + UPB_SINK_MAX_NESTING; s->top->h = h; if (h->ft) { s->top->closure = upb_pipeline_allocobj(p, h->ft); @@ -231,7 +231,6 @@ bool upb_sink_startmsg(upb_sink *s) { } bool upb_sink_endmsg(upb_sink *s) { - assert(s->top == s->stack); const upb_handlers *h = s->top->h; upb_endmsg_handler *endmsg = (upb_endmsg_handler *)upb_handlers_gethandler(h, UPB_ENDMSG_SELECTOR); @@ -386,19 +385,10 @@ bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel) { // TODO: should add support for submessages without any handlers assert(s->top->h); s->top->closure = subc; - upb_sink_startmsg(s); return true; } bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) { - upb_endmsg_handler *endmsg = (upb_endmsg_handler *)upb_handlers_gethandler( - s->top->h, UPB_ENDMSG_SELECTOR); - if (endmsg) { - // TODO(haberman): check return value. - const void *hd = - upb_handlers_gethandlerdata(s->top->h, UPB_ENDMSG_SELECTOR); - endmsg(s->top->closure, hd, &s->pipeline_->status_); - } --s->top; assert(sel == s->top->selector); @@ -38,6 +38,10 @@ typedef struct upb_sink upb_sink; #endif struct upb_sinkframe; +// The maximum nesting depth that upb::Sink will allow. Matches proto2's limit. +// TODO: make this a runtime-settable property of Sink. +#define UPB_SINK_MAX_NESTING 64 + #ifdef __cplusplus // A upb::Pipeline is a set of sinks that can send data to each other. The @@ -168,7 +172,14 @@ class upb::Sink { // These may not be called from within one of the same sink's handlers (in // other words, handlers are not re-entrant). - // Should be called at the start and end of processing. + // Should be called at the start and end of every message; both the top-level + // message and submessages. This means that submessages should use the + // following sequence: + // sink->StartSubMessage(startsubmsg_selector); + // sink->StartMessage(); + // // ... + // sink->EndMessage(); + // sink->EndSubMessage(endsubmsg_selector); bool StartMessage(); bool EndMessage(); diff --git a/upb/symtab.c b/upb/symtab.c index 8b56f89..31ae132 100644 --- a/upb/symtab.c +++ b/upb/symtab.c @@ -11,24 +11,24 @@ #include <string.h> bool upb_symtab_isfrozen(const upb_symtab *s) { - return upb_refcounted_isfrozen(upb_upcast(s)); + return upb_refcounted_isfrozen(UPB_UPCAST(s)); } void upb_symtab_ref(const upb_symtab *s, const void *owner) { - upb_refcounted_ref(upb_upcast(s), owner); + upb_refcounted_ref(UPB_UPCAST(s), owner); } void upb_symtab_unref(const upb_symtab *s, const void *owner) { - upb_refcounted_unref(upb_upcast(s), owner); + upb_refcounted_unref(UPB_UPCAST(s), owner); } void upb_symtab_donateref( const upb_symtab *s, const void *from, const void *to) { - upb_refcounted_donateref(upb_upcast(s), from, to); + upb_refcounted_donateref(UPB_UPCAST(s), from, to); } void upb_symtab_checkref(const upb_symtab *s, const void *owner) { - upb_refcounted_checkref(upb_upcast(s), owner); + upb_refcounted_checkref(UPB_UPCAST(s), owner); } static void upb_symtab_free(upb_refcounted *r) { @@ -47,7 +47,7 @@ static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_symtab_free}; upb_symtab *upb_symtab_new(const void *owner) { upb_symtab *s = malloc(sizeof(*s)); - upb_refcounted_init(upb_upcast(s), &vtbl, owner); + upb_refcounted_init(UPB_UPCAST(s), &vtbl, owner); upb_strtable_init(&s->symtab, UPB_CTYPE_PTR); return s; } @@ -100,7 +100,7 @@ const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym, static upb_def *upb_resolvename(const upb_strtable *t, const char *base, const char *sym) { if(strlen(sym) == 0) return NULL; - if(sym[0] == UPB_SYMBOL_SEPARATOR) { + if(sym[0] == '.') { // Symbols starting with '.' are absolute, so we do a single lookup. // Slice to omit the leading '.' upb_value v; @@ -243,7 +243,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, upb_msgdef *m = upb_dyncast_msgdef_mutable(def); if (!m) continue; // Type names are resolved relative to the message in which they appear. - const char *base = upb_def_fullname(upb_upcast(m)); + const char *base = upb_msgdef_fullname(m); upb_msg_iter j; for(upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j)) { diff --git a/upb/symtab.h b/upb/symtab.h index 883324a..01d5cd0 100644 --- a/upb/symtab.h +++ b/upb/symtab.h @@ -154,9 +154,9 @@ inline SymbolTable* SymbolTable::New(const void* owner) { return upb_symtab_new(owner); } -inline RefCounted* SymbolTable::Upcast() { return upb_upcast(this); } +inline RefCounted* SymbolTable::Upcast() { return UPB_UPCAST(this); } inline const RefCounted* SymbolTable::Upcast() const { - return upb_upcast(this); + return UPB_UPCAST(this); } inline bool SymbolTable::IsFrozen() const { return upb_symtab_isfrozen(this); diff --git a/upb/table.c b/upb/table.c index 40f841d..0b43fd9 100644 --- a/upb/table.c +++ b/upb/table.c @@ -7,23 +7,31 @@ * Implementation is heavily inspired by Lua's ltable.c. */ -#include "upb/table.h" +#include "upb/table.int.h" #include <stdlib.h> #include <string.h> #define UPB_MAXARRSIZE 16 // 64k. +// From Chromium. +#define ARRAY_SIZE(x) \ + ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) + static const double MAX_LOAD = 0.85; -// The minimum percentage of an array part that we will allow. This is a -// speed/memory-usage tradeoff (though it's not straightforward because of +// The minimum utilization of the array part of a mixed hash/array table. This +// is a speed/memory-usage tradeoff (though it's not straightforward because of // cache effects). The lower this is, the more memory we'll use. static const double MIN_DENSITY = 0.1; -int upb_log2(uint64_t v) { +bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } + +int log2ceil(uint64_t v) { int ret = 0; + bool pow2 = is_pow2(v); while (v >>= 1) ret++; + ret = pow2 ? ret : ret + 1; // Ceiling. return UPB_MIN(UPB_MAXARRSIZE, ret); } @@ -49,9 +57,9 @@ static bool isfull(upb_table *t) { return (double)(t->count + 1) / upb_table_size(t) > MAX_LOAD; } -static bool init(upb_table *t, upb_ctype_t type, uint8_t size_lg2) { +static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2) { t->count = 0; - t->type = type; + t->ctype = ctype; t->size_lg2 = size_lg2; t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; size_t bytes = upb_table_size(t) * sizeof(upb_tabent); @@ -88,7 +96,7 @@ static bool lookup(const upb_table *t, upb_tabkey key, upb_value *v, const upb_tabent *e = findentry(t, key, hash, eql); if (e) { if (v) { - _upb_value_setval(v, e->val, t->type); + _upb_value_setval(v, e->val, t->ctype); } return true; } else { @@ -100,7 +108,7 @@ static bool lookup(const upb_table *t, upb_tabkey key, upb_value *v, static void insert(upb_table *t, upb_tabkey key, upb_value val, hashfunc_t *hash, eqlfunc_t *eql) { assert(findentry(t, key, hash, eql) == NULL); - assert(val.type == t->type); + assert(val.ctype == t->ctype); t->count++; upb_tabent *mainpos_e = (upb_tabent*)hash(t, key); upb_tabent *our_e = mainpos_e; @@ -145,7 +153,7 @@ static bool rm(upb_table *t, upb_tabkey key, upb_value *val, // Element to remove is at the head of its chain. t->count--; if (val) { - _upb_value_setval(val, chain->val, t->type); + _upb_value_setval(val, chain->val, t->ctype); } if (chain->next) { upb_tabent *move = (upb_tabent*)chain->next; @@ -164,7 +172,7 @@ static bool rm(upb_table *t, upb_tabkey key, upb_value *val, if (chain->next) { // Found element to remove. if (val) { - _upb_value_setval(val, chain->next->val, t->type); + _upb_value_setval(val, chain->next->val, t->ctype); } upb_tabent *rm = (upb_tabent*)chain->next; if (removed) *removed = rm->key; @@ -204,8 +212,8 @@ static bool streql(upb_tabkey k1, upb_tabkey k2) { return strcmp(k1.str, k2.str) == 0; } -bool upb_strtable_init(upb_strtable *t, upb_ctype_t type) { - return init(&t->t, type, 2); +bool upb_strtable_init(upb_strtable *t, upb_ctype_t ctype) { + return init(&t->t, ctype, 2); } void upb_strtable_uninit(upb_strtable *t) { @@ -218,7 +226,7 @@ bool upb_strtable_insert(upb_strtable *t, const char *k, upb_value v) { if (isfull(&t->t)) { // Need to resize. New table of double the size, add old elements to it. upb_strtable new_table; - if (!init(&new_table.t, t->t.type, t->t.size_lg2 + 1)) + if (!init(&new_table.t, t->t.ctype, t->t.size_lg2 + 1)) return false; upb_strtable_iter i; upb_strtable_begin(&i, t); @@ -267,6 +275,21 @@ static bool inteql(upb_tabkey k1, upb_tabkey k2) { return k1.num == k2.num; } +static _upb_value *inttable_val(upb_inttable *t, uintptr_t key) { + if (key < t->array_size) { + return upb_arrhas(t->array[key]) ? (_upb_value*)&t->array[key] : NULL; + } else { + upb_tabent *e = + (upb_tabent*)findentry(&t->t, upb_intkey(key), &upb_inthash, &inteql); + return e ? &e->val : NULL; + } +} + +static const _upb_value *inttable_val_const(const upb_inttable *t, + uintptr_t key) { + return inttable_val((upb_inttable*)t, key); +} + size_t upb_inttable_count(const upb_inttable *t) { return t->t.count + t->array_count; } @@ -285,9 +308,9 @@ static void check(upb_inttable *t) { #endif } -bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t type, +bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype, size_t asize, int hsize_lg2) { - if (!init(&t->t, type, hsize_lg2)) return false; + if (!init(&t->t, ctype, hsize_lg2)) return false; // Always make the array part at least 1 long, so that we know key 0 // won't be in the hash part, which simplifies things. t->array_size = UPB_MAX(1, asize); @@ -303,8 +326,8 @@ bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t type, return true; } -bool upb_inttable_init(upb_inttable *t, upb_ctype_t type) { - return upb_inttable_sizedinit(t, type, 0, 4); +bool upb_inttable_init(upb_inttable *t, upb_ctype_t ctype) { + return upb_inttable_sizedinit(t, ctype, 0, 4); } void upb_inttable_uninit(upb_inttable *t) { @@ -322,12 +345,12 @@ bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) { if (isfull(&t->t)) { // Need to resize the hash part, but we re-use the array part. upb_table new_table; - if (!init(&new_table, t->t.type, t->t.size_lg2 + 1)) + if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1)) return false; const upb_tabent *e; for (e = begin(&t->t); e; e = next(&t->t, e)) { upb_value v; - _upb_value_setval(&v, e->val, t->t.type); + _upb_value_setval(&v, e->val, t->t.ctype); insert(&new_table, e->key, v, &upb_inthash, &inteql); } @@ -343,15 +366,17 @@ bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) { } bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) { - if (key < t->array_size) { - bool ret = upb_arrhas(t->array[key]); - if (ret && v) { - _upb_value_setval(v, t->array[key], t->t.type); - } - return ret; - } else { - return lookup(&t->t, upb_intkey(key), v, &upb_inthash, &inteql); - } + const _upb_value *table_v = inttable_val_const(t, key); + if (!table_v) return false; + if (v) _upb_value_setval(v, *table_v, t->t.ctype); + return true; +} + +bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) { + _upb_value *table_v = inttable_val(t, key); + if (!table_v) return false; + *table_v = val.val; + return true; } bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { @@ -360,7 +385,7 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { if (upb_arrhas(t->array[key])) { t->array_count--; if (val) { - _upb_value_setval(val, t->array[key], t->t.type); + _upb_value_setval(val, t->array[key], t->t.ctype); } ((upb_value*)t->array)[key] = upb_value_uint64(-1); success = true; @@ -400,31 +425,58 @@ bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) { } void upb_inttable_compact(upb_inttable *t) { - // Find the largest power of two that satisfies the MIN_DENSITY definition. + // Create a power-of-two histogram of the table keys. int counts[UPB_MAXARRSIZE + 1] = {0}; + uintptr_t max_key = 0; upb_inttable_iter i; - for (upb_inttable_begin(&i, t); !upb_inttable_done(&i); upb_inttable_next(&i)) - counts[upb_log2(upb_inttable_iter_key(&i))]++; - // Int part must always be at least 1 entry large to catch lookups of key 0. - // Key 0 must always be in the array part because "0" in the hash part - // denotes an empty entry. - int count = UPB_MAX(upb_inttable_count(t), 1); - int size; - for (size = UPB_MAXARRSIZE; size > 1; size--) { - count -= counts[size]; - if (count >= (1 << size) * MIN_DENSITY) break; + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t key = upb_inttable_iter_key(&i); + if (key > max_key) { + max_key = key; + } + counts[log2ceil(key)]++; } + int arr_size; + int arr_count = upb_inttable_count(t); + + if (upb_inttable_count(t) >= max_key * MIN_DENSITY) { + // We can put 100% of the entries in the array part. + arr_size = max_key + 1; + } else { + // Find the largest power of two that satisfies the MIN_DENSITY definition. + for (int size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 1; size_lg2--) { + arr_size = 1 << size_lg2; + arr_count -= counts[size_lg2]; + if (arr_count >= arr_size * MIN_DENSITY) { + break; + } + } + } + + // Array part must always be at least 1 entry large to catch lookups of key + // 0. Key 0 must always be in the array part because "0" in the hash part + // denotes an empty entry. + arr_size = UPB_MAX(arr_size, 1); + // Insert all elements into new, perfectly-sized table. - upb_inttable new_table; - int hashsize = (upb_inttable_count(t) - count + 1) / MAX_LOAD; + int hash_count = upb_inttable_count(t) - arr_count; + int hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; + int hashsize_lg2 = log2ceil(hash_size); + assert(hash_count >= 0); - upb_inttable_sizedinit(&new_table, t->t.type, size, upb_log2(hashsize)); - for (upb_inttable_begin(&i, t); !upb_inttable_done(&i); upb_inttable_next(&i)) - upb_inttable_insert( - &new_table, upb_inttable_iter_key(&i), upb_inttable_iter_value(&i)); + upb_inttable new_t; + upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2); + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t k = upb_inttable_iter_key(&i); + upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i)); + } + assert(new_t.array_size == arr_size); + assert(new_t.t.size_lg2 == hashsize_lg2); upb_inttable_uninit(t); - *t = new_table; + *t = new_t; } void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) { diff --git a/upb/table.h b/upb/table.int.h index f96dee9..0ed37ba 100644 --- a/upb/table.h +++ b/upb/table.int.h @@ -4,6 +4,7 @@ * Copyright (c) 2009 Google Inc. See LICENSE for details. * Author: Josh Haberman <jhaberman@gmail.com> * + * This header is INTERNAL-ONLY! Its interfaces are not public or stable! * This file defines very fast int->upb_value (inttable) and string->upb_value * (strtable) hash tables. * @@ -15,24 +16,132 @@ * store pointers or integers of at least 32 bits (upb isn't really useful on * systems where sizeof(void*) < 4). * - * This header is internal to upb; its interface should not be considered - * public or stable. - * - * The table must be homogenous (all values of the same type). We currently - * enforce this on insert but store the full upb_value (with type) anyway. - * This is required with the current interface because lookups vend a pointer - * to the table's internal storage. + * The table must be homogenous (all values of the same type). In debug + * mode, we check this on insert and lookup. */ #ifndef UPB_TABLE_H_ #define UPB_TABLE_H_ +#include <assert.h> +#include <stdint.h> #include "upb.h" #ifdef __cplusplus extern "C" { #endif + +/* upb_value ******************************************************************/ + +// A tagged union (stored untagged inside the table) so that we can check that +// clients calling table accessors are correctly typed without having to have +// an explosion of accessors. +typedef enum { + UPB_CTYPE_INT32 = 1, + UPB_CTYPE_INT64 = 2, + UPB_CTYPE_UINT32 = 3, + UPB_CTYPE_UINT64 = 4, + UPB_CTYPE_BOOL = 5, + UPB_CTYPE_CSTR = 6, + UPB_CTYPE_PTR = 7, +} upb_ctype_t; + +typedef union { + int32_t int32; + int64_t int64; + uint64_t uint64; + uint32_t uint32; + bool _bool; + char *cstr; + void *ptr; + const void *constptr; +} _upb_value; + +typedef struct { + _upb_value val; +#ifndef NDEBUG + // In debug mode we carry the value type around also so we can check accesses + // to be sure the right member is being read. + upb_ctype_t ctype; +#endif +} upb_value; + +#ifdef UPB_C99 +#define UPB_VALUE_INIT(v, member) {.member = v} +#endif +#define UPB__VALUE_INIT_NONE UPB_VALUE_INIT(NULL, ptr) + +#ifdef NDEBUG +#define SET_TYPE(dest, val) UPB_UNUSED(val) +#define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE} +#else +#define SET_TYPE(dest, val) dest = val +// Non-existent type, all reads will fail. +#define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE, -1} +#endif + +#define UPB_VALUE_INIT_INT32(v) UPB_VALUE_INIT(v, int32) +#define UPB_VALUE_INIT_INT64(v) UPB_VALUE_INIT(v, int64) +#define UPB_VALUE_INIT_UINT32(v) UPB_VALUE_INIT(v, uint32) +#define UPB_VALUE_INIT_UINT64(v) UPB_VALUE_INIT(v, uint64) +#define UPB_VALUE_INIT_BOOL(v) UPB_VALUE_INIT(v, _bool) +#define UPB_VALUE_INIT_CSTR(v) UPB_VALUE_INIT(v, cstr) +#define UPB_VALUE_INIT_PTR(v) UPB_VALUE_INIT(v, ptr) +#define UPB_VALUE_INIT_CONSTPTR(v) UPB_VALUE_INIT(v, constptr) + +// Like strdup(), which isn't always available since it's not ANSI C. +char *upb_strdup(const char *s); + +UPB_INLINE void _upb_value_setval(upb_value *v, _upb_value val, + upb_ctype_t ctype) { + v->val = val; + SET_TYPE(v->ctype, ctype); +} + +UPB_INLINE upb_value _upb_value_val(_upb_value val, upb_ctype_t ctype) { + upb_value ret; + _upb_value_setval(&ret, val, ctype); + return ret; +} + +// For each value ctype, define the following set of functions: +// +// // Get/set an int32 from a upb_value. +// int32_t upb_value_getint32(upb_value val); +// void upb_value_setint32(upb_value *val, int32_t cval); +// +// // Construct a new upb_value from an int32. +// upb_value upb_value_int32(int32_t val); +#define FUNCS(name, membername, type_t, proto_type) \ + UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \ + val->val.uint64 = 0; \ + SET_TYPE(val->ctype, proto_type); \ + val->val.membername = cval; \ + } \ + UPB_INLINE upb_value upb_value_ ## name(type_t val) { \ + upb_value ret; \ + upb_value_set ## name(&ret, val); \ + return ret; \ + } \ + UPB_INLINE type_t upb_value_get ## name(upb_value val) { \ + assert(val.ctype == proto_type); \ + return val.val.membername; \ + } + +FUNCS(int32, int32, int32_t, UPB_CTYPE_INT32); +FUNCS(int64, int64, int64_t, UPB_CTYPE_INT64); +FUNCS(uint32, uint32, uint32_t, UPB_CTYPE_UINT32); +FUNCS(uint64, uint64, uint64_t, UPB_CTYPE_UINT64); +FUNCS(bool, _bool, bool, UPB_CTYPE_BOOL); +FUNCS(cstr, cstr, char*, UPB_CTYPE_CSTR); +FUNCS(ptr, ptr, void*, UPB_CTYPE_PTR); + +#undef FUNCS + + +/* upb_table ******************************************************************/ + typedef union { uintptr_t num; const char *str; // We own, nullz. @@ -58,7 +167,7 @@ typedef struct _upb_tabent { typedef struct { size_t count; // Number of entries in the hash part. size_t mask; // Mask to turn hash value -> bucket. - upb_ctype_t type; // Type of all values. + upb_ctype_t ctype; // Type of all values. uint8_t size_lg2; // Size of the hash table part is 2^size_lg2 entries. const upb_tabent *entries; // Hash table. } upb_table; @@ -67,8 +176,8 @@ typedef struct { upb_table t; } upb_strtable; -#define UPB_STRTABLE_INIT(count, mask, type, size_lg2, entries) \ - {{count, mask, type, size_lg2, entries}} +#define UPB_STRTABLE_INIT(count, mask, ctype, size_lg2, entries) \ + {{count, mask, ctype, size_lg2, entries}} typedef struct { upb_table t; // For entries that don't fit in the array part. @@ -77,11 +186,11 @@ typedef struct { size_t array_count; // Array part number of elements. } upb_inttable; -#define UPB_INTTABLE_INIT(count, mask, type, size_lg2, ent, a, asize, acount) \ - {{count, mask, type, size_lg2, ent}, a, asize, acount} +#define UPB_INTTABLE_INIT(count, mask, ctype, size_lg2, ent, a, asize, acount) \ + {{count, mask, ctype, size_lg2, ent}, a, asize, acount} -#define UPB_EMPTY_INTTABLE_INIT(type) \ - UPB_INTTABLE_INIT(0, 0, type, 0, NULL, NULL, 0, 0) +#define UPB_EMPTY_INTTABLE_INIT(ctype) \ + UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0) #define UPB_ARRAY_EMPTYENT UPB_VALUE_INIT_INT64(-1) @@ -113,8 +222,8 @@ uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed); // Initialize and uninitialize a table, respectively. If memory allocation // failed, false is returned that the table is uninitialized. -bool upb_inttable_init(upb_inttable *table, upb_ctype_t type); -bool upb_strtable_init(upb_strtable *table, upb_ctype_t type); +bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype); +bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype); void upb_inttable_uninit(upb_inttable *table); void upb_strtable_uninit(upb_strtable *table); @@ -145,6 +254,11 @@ bool upb_strtable_lookup(const upb_strtable *t, const char *key, upb_value *v); bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val); bool upb_strtable_remove(upb_strtable *t, const char *key, upb_value *val); +// Updates an existing entry in an inttable. If the entry does not exist, +// returns false and does nothing. Unlike insert/remove, this does not +// invalidate iterators. +bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val); + // Handy routines for treating an inttable like a stack. May not be mixed with // other insert/remove calls. bool upb_inttable_push(upb_inttable *t, upb_value val); @@ -168,7 +282,7 @@ UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, if (key < t->array_size) { _upb_value arrval = t->array[key]; if (upb_arrhas(arrval)) { - _upb_value_setval(v, arrval, t->t.type); + _upb_value_setval(v, arrval, t->t.ctype); return true; } else { return false; @@ -178,7 +292,7 @@ UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, if (t->t.entries == NULL) return NULL; for (e = upb_inthash(&t->t, upb_intkey(key)); true; e = e->next) { if ((uint32_t)e->key.num == key) { - _upb_value_setval(v, e->val, t->t.type); + _upb_value_setval(v, e->val, t->t.ctype); return true; } if (e->next == NULL) return false; @@ -209,7 +323,18 @@ UPB_INLINE const char *upb_strtable_iter_key(upb_strtable_iter *i) { return i->e->key.str; } UPB_INLINE upb_value upb_strtable_iter_value(upb_strtable_iter *i) { - return _upb_value_val(i->e->val, i->t->t.type); + return _upb_value_val(i->e->val, i->t->t.ctype); +} +UPB_INLINE void upb_strtable_iter_copy(upb_strtable_iter *to, + const upb_strtable_iter *from) { + *to = *from; +} +UPB_INLINE void upb_strtable_iter_setdone(upb_strtable_iter *i) { + i->e = NULL; +} +UPB_INLINE bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, + const upb_strtable_iter *i2) { + return i1->e == i2->e; } @@ -235,15 +360,26 @@ typedef struct { void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t); void upb_inttable_next(upb_inttable_iter *i); -UPB_INLINE bool upb_inttable_done(upb_inttable_iter *i) { +UPB_INLINE bool upb_inttable_done(const upb_inttable_iter *i) { return i->ptr.ent == NULL; } -UPB_INLINE uintptr_t upb_inttable_iter_key(upb_inttable_iter *i) { +UPB_INLINE uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) { return i->array_part ? i->arrkey : i->ptr.ent->key.num; } -UPB_INLINE upb_value upb_inttable_iter_value(upb_inttable_iter *i) { +UPB_INLINE upb_value upb_inttable_iter_value(const upb_inttable_iter *i) { return _upb_value_val( - i->array_part ? *i->ptr.val : i->ptr.ent->val, i->t->t.type); + i->array_part ? *i->ptr.val : i->ptr.ent->val, i->t->t.ctype); +} +UPB_INLINE void upb_inttable_iter_copy(upb_inttable_iter *to, + const upb_inttable_iter *from) { + *to = *from; +} +UPB_INLINE void upb_inttable_iter_setdone(upb_inttable_iter *i) { + i->ptr.ent = NULL; +} +UPB_INLINE bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, + const upb_inttable_iter *i2) { + return i1->ptr.ent == i2->ptr.ent; } #ifdef __cplusplus @@ -8,16 +8,41 @@ #include <errno.h> #include <stdarg.h> #include <stddef.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "upb/upb.h" -#ifdef NDEBUG -upb_value UPB_NO_VALUE = {{0}}; -#else -upb_value UPB_NO_VALUE = {{0}, -1}; -#endif +// Like vasprintf (which allocates a string large enough for the result), but +// uses *buf (which can be NULL) as a starting point and reallocates it only if +// the new value will not fit. "size" is updated to reflect the allocated size +// of the buffer. Starts writing at the given offset into the string; bytes +// preceding this offset are unaffected. Returns the new length of the string, +// or -1 on memory allocation failure. +static int upb_vrprintf(char **buf, size_t *size, size_t ofs, + const char *fmt, va_list args) { + // Try once without reallocating. We have to va_copy because we might have + // to call vsnprintf again. + uint32_t len = *size - ofs; + va_list args_copy; + va_copy(args_copy, args); + uint32_t true_len = vsnprintf(*buf + ofs, len, fmt, args_copy); + va_end(args_copy); + + // Resize to be the correct size. + if (true_len >= len) { + // Need to print again, because some characters were truncated. vsnprintf + // will not write the entire string unless you give it space to store the + // NULL terminator also. + *size = (ofs + true_len + 1); + char *newbuf = realloc(*buf, *size); + if (!newbuf) return -1; + vsnprintf(newbuf + ofs, true_len + 1, fmt, args); + *buf = newbuf; + } + return true_len; +} void upb_status_init(upb_status *status) { status->buf = NULL; @@ -104,27 +129,3 @@ void upb_status_seteof(upb_status *status) { if (!status) return; status->eof_ = true; } - -int upb_vrprintf(char **buf, size_t *size, size_t ofs, - const char *fmt, va_list args) { - // Try once without reallocating. We have to va_copy because we might have - // to call vsnprintf again. - uint32_t len = *size - ofs; - va_list args_copy; - va_copy(args_copy, args); - uint32_t true_len = vsnprintf(*buf + ofs, len, fmt, args_copy); - va_end(args_copy); - - // Resize to be the correct size. - if (true_len >= len) { - // Need to print again, because some characters were truncated. vsnprintf - // will not write the entire string unless you give it space to store the - // NULL terminator also. - *size = (ofs + true_len + 1); - char *newbuf = realloc(*buf, *size); - if (!newbuf) return -1; - vsnprintf(newbuf + ofs, true_len + 1, fmt, args); - *buf = newbuf; - } - return true_len; -} @@ -13,16 +13,8 @@ #ifndef UPB_H_ #define UPB_H_ -#include <assert.h> -#include <limits.h> -#include <stdarg.h> #include <stdbool.h> #include <stddef.h> -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif // inline if possible, emit standalone code if required. #ifdef __cplusplus @@ -54,108 +46,15 @@ extern "C" { void operator=(const class_name&); #endif -#if defined(__clang__) && defined(LANG_CXX11) && defined(__has_warning) -#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") -#define UPB_FALLTHROUGH_INTENDED [[clang::fallthrough]] -#endif -#endif - -#ifndef UPB_FALLTHROUGH_INTENDED -#define UPB_FALLTHROUGH_INTENDED do { } while (0) -#endif - #ifdef __GNUC__ #define UPB_NORETURN __attribute__((__noreturn__)) #else #define UPB_NORETURN #endif -// Type detection and typedefs for integer types. -// For platforms where there are multiple 32-bit or 64-bit types, we need to be -// able to enumerate them so we can properly create overloads for all variants. -// -// If any platform existed where there were three integer types with the same -// size, this would have to become more complicated. For example, short, int, -// and long could all be 32-bits. Even more diabolically, short, int, long, -// and long long could all be 64 bits and still be standard-compliant. -// However, few platforms are this strange, and it's unlikely that upb will be -// used on the strangest ones. - -// Can't count on stdint.h limits like INT32_MAX, because in C++ these are -// only defined when __STDC_LIMIT_MACROS are defined before the *first* include -// of stdint.h. We can't guarantee that someone else didn't include these first -// without defining __STDC_LIMIT_MACROS. -#define UPB_INT32_MAX 0x7fffffffLL -#define UPB_INT32_MIN (-UPB_INT32_MAX - 1) -#define UPB_INT64_MAX 0x7fffffffffffffffLL -#define UPB_INT64_MIN (-UPB_INT64_MAX - 1) - -#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN -#define UPB_INT_IS_32BITS 1 -#endif - -#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN -#define UPB_LONG_IS_32BITS 1 -#endif - -#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN -#define UPB_LONG_IS_64BITS 1 -#endif - -#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN -#define UPB_LLONG_IS_64BITS 1 -#endif - -#if UPB_INT_IS_32BITS -typedef int upb_int32_t; -typedef unsigned int upb_uint32_t; -#define UPB_INT32_CTYPE i - -#if UPB_LONG_IS_32BITS -#define UPB_TWO_32BIT_TYPES 1 -typedef long upb_int32alt_t; -typedef unsigned long upb_uint32alt_t; -#define UPB_INT32_CTYPE2 l -#endif // UPB_LONG_IS_32BITS - -#elif UPB_LONG_IS_32BITS // && !UPB_INT_IS_32BITS -typedef long upb_int32_t; -typedef unsigned long upb_uint32_t; -#define UPB_INT32_CTYPE l -#endif // UPB_INT_IS_32BITS - - -#if UPB_LONG_IS_64BITS -typedef long upb_int64_t; -typedef unsigned long upb_uint64_t; -#define UPB_INT64_CTYPE l - -#if UPB_LLONG_IS_64BITS -#define UPB_TWO_64BIT_TYPES 1 -typedef long long upb_int64alt_t; -typedef unsigned long long upb_uint64alt_t; -#define UPB_INT64_CTYPE2 ll -#endif // UPB_LLONG_IS_64BITS - -#elif UPB_LLONG_IS_64BITS // && !UPB_LONG_IS_64BITS -typedef long long upb_int64_t; -typedef unsigned long long upb_uint64_t; -#define UPB_INT64_CTYPE ll -#endif // UPB_LONG_IS_64BITS - #define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) #define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) -// For our C-based inheritance, sometimes it's necessary to upcast an object to -// its base class. We try to minimize the need for this by replicating base -// class functions in the derived class -- the derived class functions simply -// forward to the base class implementations. This strategy simplifies the C++ -// API since we can't use real C++ inheritance. -#define upb_upcast(obj) (&(obj)->base) -#define upb_upcast2(obj) upb_upcast(upb_upcast(obj)) - -char *upb_strdup(const char *s); - #define UPB_UNUSED(var) (void)var // For asserting something about a variable when the variable is not used for @@ -163,42 +62,39 @@ char *upb_strdup(const char *s); // debug mode. #define UPB_ASSERT_VAR(var, predicate) UPB_UNUSED(var); assert(predicate) -#define UPB_ASSERT_STATUS(status) do { \ - if (!upb_ok(status)) { \ - fprintf(stderr, "upb status failure: %s\n", upb_status_getstr(status)); \ - assert(upb_ok(status)); \ - } \ - } while (0) - -// The maximum that any submessages can be nested. Matches proto2's limit. -// At the moment this specifies the size of several statically-sized arrays -// and therefore setting it high will cause more memory to be used. Will -// be replaced by a runtime-configurable limit and dynamically-resizing arrays. -// TODO: make this a runtime-settable property of upb_handlers. -#define UPB_MAX_NESTING 64 - -// Inherent limit of protobuf wire format and schema definition. -#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1) - -// Nested type names are separated by periods. -#define UPB_SYMBOL_SEPARATOR '.' - -// The longest chain that mutually-recursive types are allowed to form. For -// example, this is a type cycle of length 2: -// message A { -// B b = 1; -// } -// message B { -// A a = 1; -// } -#define UPB_MAX_TYPE_CYCLE_LEN 16 - -// The maximum depth that the type graph can have. Note that this setting does -// not automatically constrain UPB_MAX_NESTING, because type cycles allow for -// unlimited nesting if we do not limit it. Many algorithms in upb call -// recursive functions that traverse the type graph, so we must limit this to -// avoid blowing the C stack. -#define UPB_MAX_TYPE_DEPTH 64 + +/* Casts **********************************************************************/ + +// Upcasts for C. For downcasts see the definitions of the subtypes. +#define UPB_UPCAST(obj) (&(obj)->base) +#define UPB_UPCAST2(obj) UPB_UPCAST(UPB_UPCAST(obj)) + +#ifdef __cplusplus + +// Downcasts for C++. We can't use C++ inheritance directly and maintain +// compatibility with C. So our inheritance is undeclared in C++. +// Specializations of these casting functions are defined for appropriate type +// pairs, and perform the necessary checks. +// +// Example: +// upb::Def* def = <...>; +// upb::MessageDef* = upb::dyn_cast<upb::MessageDef*>(def); +// +// For upcasts, see the Upcast() method in the types themselves. + +namespace upb { + +// Casts to a direct subclass. The caller must know that cast is correct; an +// incorrect cast will throw an assertion failure. +template<class To, class From> To down_cast(From* f); + +// Casts to a direct subclass. If the class does not actually match the given +// subtype, returns NULL. +template<class To, class From> To dyn_cast(From* f); + +} + +#endif /* upb::Status ****************************************************************/ @@ -260,6 +156,10 @@ struct upb_status { #define UPB_STATUS_INIT {UPB_OK, false, 0, NULL, NULL, NULL, 0} +#ifdef __cplusplus +extern "C" { +#endif + void upb_status_init(upb_status *status); void upb_status_uninit(upb_status *status); @@ -278,203 +178,11 @@ void upb_status_seteof(upb_status *status); const char *upb_status_getstr(const upb_status *status); void upb_status_copy(upb_status *to, const upb_status *from); -// Like vasprintf (which allocates a string large enough for the result), but -// uses *buf (which can be NULL) as a starting point and reallocates it only if -// the new value will not fit. "size" is updated to reflect the allocated size -// of the buffer. Starts writing at the given offset into the string; bytes -// preceding this offset are unaffected. Returns the new length of the string, -// or -1 on memory allocation failure. -int upb_vrprintf(char **buf, size_t *size, size_t ofs, - const char *fmt, va_list args); - - -/* upb::Value *****************************************************************/ - -// TODO(haberman): upb::Value is gross and should be retired from the public -// interface (we *may* still want to keep it for internal use). upb::Handlers -// and upb::Def should replace their use of Value with one function for each C -// type. - -// Clients should not need to access these enum values; they are used internally -// to do typechecks of upb_value accesses. -typedef enum { - UPB_CTYPE_INT32 = 1, - UPB_CTYPE_INT64 = 2, - UPB_CTYPE_UINT32 = 3, - UPB_CTYPE_UINT64 = 4, - UPB_CTYPE_DOUBLE = 5, - UPB_CTYPE_FLOAT = 6, - UPB_CTYPE_BOOL = 7, - UPB_CTYPE_CSTR = 8, - UPB_CTYPE_PTR = 9, - UPB_CTYPE_BYTEREGION = 10, - UPB_CTYPE_FIELDDEF = 11, -} upb_ctype_t; - -typedef union { - uint64_t uint64; - int32_t int32; - int64_t int64; - uint32_t uint32; - double _double; - float _float; - bool _bool; - char *cstr; - void *ptr; - const void *constptr; -} _upb_value; - -// A single .proto value. The owner must have an out-of-band way of knowing -// the type, so that it knows which union member to use. -typedef struct { - _upb_value val; -#ifndef NDEBUG - // In debug mode we carry the value type around also so we can check accesses - // to be sure the right member is being read. - upb_ctype_t type; -#endif -} upb_value; - -#ifdef UPB_C99 -#define UPB_VALUE_INIT(v, member) {.member = v} -#endif -// TODO(haberman): C++ -// -// -#define UPB__VALUE_INIT_NONE UPB_VALUE_INIT(NULL, ptr) - -#ifdef NDEBUG -#define SET_TYPE(dest, val) UPB_UNUSED(val) -#define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE} -#else -#define SET_TYPE(dest, val) dest = val -// Non-existent type, all reads will fail. -#define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE, -1} -#endif - -#define UPB_VALUE_INIT_INT32(v) UPB_VALUE_INIT(v, int32) -#define UPB_VALUE_INIT_INT64(v) UPB_VALUE_INIT(v, int64) -#define UPB_VALUE_INIT_UINT32(v) UPB_VALUE_INIT(v, uint32) -#define UPB_VALUE_INIT_UINT64(v) UPB_VALUE_INIT(v, uint64) -#define UPB_VALUE_INIT_DOUBLE(v) UPB_VALUE_INIT(v, _double) -#define UPB_VALUE_INIT_FLOAT(v) UPB_VALUE_INIT(v, _float) -#define UPB_VALUE_INIT_BOOL(v) UPB_VALUE_INIT(v, _bool) -#define UPB_VALUE_INIT_CSTR(v) UPB_VALUE_INIT(v, cstr) -#define UPB_VALUE_INIT_PTR(v) UPB_VALUE_INIT(v, ptr) -#define UPB_VALUE_INIT_CONSTPTR(v) UPB_VALUE_INIT(v, constptr) - -UPB_INLINE void _upb_value_setval(upb_value *v, _upb_value val, - upb_ctype_t type) { - v->val = val; - SET_TYPE(v->type, type); -} - -UPB_INLINE upb_value _upb_value_val(_upb_value val, upb_ctype_t type) { - upb_value ret; - _upb_value_setval(&ret, val, type); - return ret; -} - -// For each value type, define the following set of functions: -// -// // Get/set an int32 from a upb_value. -// int32_t upb_value_getint32(upb_value val); -// void upb_value_setint32(upb_value *val, int32_t cval); -// -// // Construct a new upb_value from an int32. -// upb_value upb_value_int32(int32_t val); - -#define WRITERS(name, membername, ctype, proto_type) \ - UPB_INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \ - val->val.uint64 = 0; \ - SET_TYPE(val->type, proto_type); \ - val->val.membername = cval; \ - } \ - UPB_INLINE upb_value upb_value_ ## name(ctype val) { \ - upb_value ret; \ - upb_value_set ## name(&ret, val); \ - return ret; \ - } - -#define ALL(name, membername, ctype, proto_type) \ - /* Can't reuse WRITERS() here unfortunately because "bool" is a macro \ - * that expands to _Bool, so it ends up defining eg. upb_value_set_Bool */ \ - UPB_INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \ - val->val.uint64 = 0; \ - SET_TYPE(val->type, proto_type); \ - val->val.membername = cval; \ - } \ - UPB_INLINE upb_value upb_value_ ## name(ctype val) { \ - upb_value ret; \ - upb_value_set ## name(&ret, val); \ - return ret; \ - } \ - UPB_INLINE ctype upb_value_get ## name(upb_value val) { \ - assert(val.type == proto_type); \ - return val.val.membername; \ - } - -ALL(int32, int32, int32_t, UPB_CTYPE_INT32); -ALL(int64, int64, int64_t, UPB_CTYPE_INT64); -ALL(uint32, uint32, uint32_t, UPB_CTYPE_UINT32); -ALL(uint64, uint64, uint64_t, UPB_CTYPE_UINT64); -ALL(bool, _bool, bool, UPB_CTYPE_BOOL); -ALL(cstr, cstr, char*, UPB_CTYPE_CSTR); -ALL(ptr, ptr, void*, UPB_CTYPE_PTR); - -#ifdef __KERNEL__ -// Linux kernel modules are compiled without SSE and therefore are incapable -// of compiling functions that return floating-point values, so we define as -// macros instead and lose the type check. -WRITERS(double, _double, double, UPB_CTYPE_DOUBLE); -WRITERS(float, _float, float, UPB_CTYPE_FLOAT); -#define upb_value_getdouble(v) (v.val._double) -#define upb_value_getfloat(v) (v.val._float) -#else -ALL(double, _double, double, UPB_CTYPE_DOUBLE); -ALL(float, _float, float, UPB_CTYPE_FLOAT); -#endif /* __KERNEL__ */ - -#undef WRITERS -#undef ALL - -extern upb_value UPB_NO_VALUE; - #ifdef __cplusplus } // extern "C" namespace upb { -typedef upb_value Value; - -template <typename T> T GetValue(Value v); -template <typename T> Value MakeValue(T v); - -#define UPB_VALUE_ACCESSORS(type, ctype) \ - template <> inline ctype GetValue<ctype>(Value v) { \ - return upb_value_get ## type(v); \ - } \ - template <> inline Value MakeValue<ctype>(ctype v) { \ - return upb_value_ ## type(v); \ - } - -UPB_VALUE_ACCESSORS(double, double); -UPB_VALUE_ACCESSORS(float, float); -UPB_VALUE_ACCESSORS(int32, int32_t); -UPB_VALUE_ACCESSORS(int64, int64_t); -UPB_VALUE_ACCESSORS(uint32, uint32_t); -UPB_VALUE_ACCESSORS(uint64, uint64_t); -UPB_VALUE_ACCESSORS(bool, bool); - -#undef UPB_VALUE_ACCESSORS - -template <typename T> inline T* GetPtrValue(Value v) { - return static_cast<T*>(upb_value_getptr(v)); -} -template <typename T> inline Value MakePtrValue(T* v) { - return upb_value_ptr(static_cast<void*>(v)); -} - // C++ Wrappers inline Status::Status() { upb_status_init(this); } inline Status::~Status() { upb_status_uninit(this); } |