summaryrefslogtreecommitdiff
path: root/upb
diff options
context:
space:
mode:
Diffstat (limited to 'upb')
-rw-r--r--upb/bytestream.upb.c22
-rw-r--r--upb/bytestream.upb.h2
-rw-r--r--upb/def.c253
-rw-r--r--upb/def.h608
-rwxr-xr-xupb/descriptor/descriptor.upb.c656
-rwxr-xr-xupb/descriptor/descriptor.upb.h336
-rw-r--r--upb/descriptor/reader.c133
-rw-r--r--upb/descriptor/reader.h12
-rw-r--r--upb/google/bridge.cc37
-rw-r--r--upb/handlers-inl.h107
-rw-r--r--upb/handlers.c29
-rw-r--r--upb/handlers.h9
-rw-r--r--upb/pb/compile_decoder.c855
-rw-r--r--upb/pb/compile_decoder_x64.c368
-rw-r--r--upb/pb/compile_decoder_x64.dasc1087
-rw-r--r--upb/pb/decoder.c1198
-rw-r--r--upb/pb/decoder.h7
-rw-r--r--upb/pb/decoder.int.h242
-rw-r--r--upb/pb/decoder_x64.dasc1086
-rw-r--r--upb/pb/glue.c6
-rw-r--r--upb/pb/varint.c2
-rw-r--r--upb/pb/varint.int.h (renamed from upb/pb/varint.h)5
-rw-r--r--upb/refcounted.c200
-rw-r--r--upb/refcounted.h22
-rw-r--r--upb/shim/shim.c28
-rw-r--r--upb/shim/shim.h16
-rw-r--r--upb/sink.c14
-rw-r--r--upb/sink.h13
-rw-r--r--upb/symtab.c16
-rw-r--r--upb/symtab.h4
-rw-r--r--upb/table.c146
-rw-r--r--upb/table.int.h (renamed from upb/table.h)182
-rw-r--r--upb/upb.c59
-rw-r--r--upb/upb.h366
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"
diff --git a/upb/def.c b/upb/def.c
index 1e19f8a..2b3ab5f 100644
--- a/upb/def.c
+++ b/upb/def.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));
}
diff --git a/upb/def.h b/upb/def.h
index 717bde3..5ebff9e 100644
--- a/upb/def.h
+++ b/upb/def.h
@@ -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
diff --git a/upb/sink.c b/upb/sink.c
index 59134d3..8f810ee 100644
--- a/upb/sink.c
+++ b/upb/sink.c
@@ -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);
diff --git a/upb/sink.h b/upb/sink.h
index bf88222..27e9fd2 100644
--- a/upb/sink.h
+++ b/upb/sink.h
@@ -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
diff --git a/upb/upb.c b/upb/upb.c
index 226fc78..881615e 100644
--- a/upb/upb.c
+++ b/upb/upb.c
@@ -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;
-}
diff --git a/upb/upb.h b/upb/upb.h
index fcf1b65..743f173 100644
--- a/upb/upb.h
+++ b/upb/upb.h
@@ -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); }
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback