|
|
|
@ -56,11 +56,11 @@ static int div_round_up(int numerator, int denominator) { |
|
|
|
|
// This algorithm is relatively cheap, since it only requires extra work when
|
|
|
|
|
// the external refcount on a cyclic type transitions from 0->1 or 1->0.
|
|
|
|
|
|
|
|
|
|
static void msgdef_free(struct upb_msgdef *m); |
|
|
|
|
static void enumdef_free(struct upb_enumdef *e); |
|
|
|
|
static void unresolveddef_free(struct upb_unresolveddef *u); |
|
|
|
|
static void msgdef_free(upb_msgdef *m); |
|
|
|
|
static void enumdef_free(upb_enumdef *e); |
|
|
|
|
static void unresolveddef_free(struct _upb_unresolveddef *u); |
|
|
|
|
|
|
|
|
|
static void def_free(struct upb_def *def) |
|
|
|
|
static void def_free(upb_def *def) |
|
|
|
|
{ |
|
|
|
|
switch(def->type) { |
|
|
|
|
case UPB_DEF_MSG: |
|
|
|
@ -91,9 +91,8 @@ static void def_free(struct upb_def *def) |
|
|
|
|
// search so we can stop the search if we detect a cycles that do not involve
|
|
|
|
|
// cycle_base. We can't color the nodes as we go by writing to a member of the
|
|
|
|
|
// def, because another thread could be performing the search concurrently.
|
|
|
|
|
static int cycle_ref_or_unref(struct upb_msgdef *m, |
|
|
|
|
struct upb_msgdef *cycle_base, |
|
|
|
|
struct upb_msgdef **open_defs, int num_open_defs, |
|
|
|
|
static int cycle_ref_or_unref(upb_msgdef *m, upb_msgdef *cycle_base, |
|
|
|
|
upb_msgdef **open_defs, int num_open_defs, |
|
|
|
|
bool ref) { |
|
|
|
|
bool found = false; |
|
|
|
|
for(int i = 0; i < num_open_defs; i++) { |
|
|
|
@ -116,10 +115,10 @@ static int cycle_ref_or_unref(struct upb_msgdef *m, |
|
|
|
|
open_defs[num_open_defs++] = m; |
|
|
|
|
} |
|
|
|
|
for(int i = 0; i < m->num_fields; i++) { |
|
|
|
|
struct upb_fielddef *f = &m->fields[i]; |
|
|
|
|
struct upb_def *def = f->def; |
|
|
|
|
upb_fielddef *f = &m->fields[i]; |
|
|
|
|
upb_def *def = f->def; |
|
|
|
|
if(upb_issubmsg(f) && def->is_cyclic) { |
|
|
|
|
struct upb_msgdef *sub_m = upb_downcast_msgdef(def); |
|
|
|
|
upb_msgdef *sub_m = upb_downcast_msgdef(def); |
|
|
|
|
path_count += cycle_ref_or_unref(sub_m, cycle_base, open_defs, |
|
|
|
|
num_open_defs, ref); |
|
|
|
|
} |
|
|
|
@ -134,22 +133,22 @@ static int cycle_ref_or_unref(struct upb_msgdef *m, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void _upb_def_reftozero(struct upb_def *def) { |
|
|
|
|
void _upb_def_reftozero(upb_def *def) { |
|
|
|
|
if(def->is_cyclic) { |
|
|
|
|
struct upb_msgdef *m = upb_downcast_msgdef(def); |
|
|
|
|
struct upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; |
|
|
|
|
upb_msgdef *m = upb_downcast_msgdef(def); |
|
|
|
|
upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; |
|
|
|
|
cycle_ref_or_unref(m, NULL, open_defs, 0, false); |
|
|
|
|
} else { |
|
|
|
|
def_free(def); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void _upb_def_cyclic_ref(struct upb_def *def) { |
|
|
|
|
struct upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; |
|
|
|
|
void _upb_def_cyclic_ref(upb_def *def) { |
|
|
|
|
upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; |
|
|
|
|
cycle_ref_or_unref(upb_downcast_msgdef(def), NULL, open_defs, 0, true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void upb_def_init(struct upb_def *def, enum upb_def_type type, |
|
|
|
|
static void upb_def_init(upb_def *def, enum upb_def_type type, |
|
|
|
|
upb_strptr fqname) { |
|
|
|
|
def->type = type; |
|
|
|
|
def->is_cyclic = 0; // We detect this later, after resolving refs.
|
|
|
|
@ -158,26 +157,26 @@ static void upb_def_init(struct upb_def *def, enum upb_def_type type, |
|
|
|
|
upb_atomic_refcount_init(&def->refcount, 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void upb_def_uninit(struct upb_def *def) { |
|
|
|
|
static void upb_def_uninit(upb_def *def) { |
|
|
|
|
upb_string_unref(def->fqname); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* upb_unresolveddef **********************************************************/ |
|
|
|
|
|
|
|
|
|
struct upb_unresolveddef { |
|
|
|
|
struct upb_def base; |
|
|
|
|
typedef struct _upb_unresolveddef { |
|
|
|
|
upb_def base; |
|
|
|
|
upb_strptr name; |
|
|
|
|
}; |
|
|
|
|
} upb_unresolveddef; |
|
|
|
|
|
|
|
|
|
static struct upb_unresolveddef *upb_unresolveddef_new(upb_strptr str) { |
|
|
|
|
struct upb_unresolveddef *def = malloc(sizeof(*def)); |
|
|
|
|
static upb_unresolveddef *upb_unresolveddef_new(upb_strptr str) { |
|
|
|
|
upb_unresolveddef *def = malloc(sizeof(*def)); |
|
|
|
|
upb_strptr name = upb_string_getref(str, UPB_REF_THREADUNSAFE_READONLY); |
|
|
|
|
upb_def_init(&def->base, UPB_DEF_UNRESOLVED, name); |
|
|
|
|
def->name = name; |
|
|
|
|
return def; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void unresolveddef_free(struct upb_unresolveddef *def) { |
|
|
|
|
static void unresolveddef_free(struct _upb_unresolveddef *def) { |
|
|
|
|
upb_string_unref(def->name); |
|
|
|
|
upb_def_uninit(&def->base); |
|
|
|
|
free(def); |
|
|
|
@ -185,7 +184,7 @@ static void unresolveddef_free(struct upb_unresolveddef *def) { |
|
|
|
|
|
|
|
|
|
/* upb_fielddef ***************************************************************/ |
|
|
|
|
|
|
|
|
|
static void fielddef_init(struct upb_fielddef *f, |
|
|
|
|
static void fielddef_init(upb_fielddef *f, |
|
|
|
|
google_protobuf_FieldDescriptorProto *fd) |
|
|
|
|
{ |
|
|
|
|
f->type = fd->type; |
|
|
|
@ -201,14 +200,14 @@ static void fielddef_init(struct upb_fielddef *f, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct upb_fielddef *fielddef_new( |
|
|
|
|
google_protobuf_FieldDescriptorProto *fd) { |
|
|
|
|
struct upb_fielddef *f = malloc(sizeof(*f)); |
|
|
|
|
static upb_fielddef *fielddef_new(google_protobuf_FieldDescriptorProto *fd) |
|
|
|
|
{ |
|
|
|
|
upb_fielddef *f = malloc(sizeof(*f)); |
|
|
|
|
fielddef_init(f, fd); |
|
|
|
|
return f; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void fielddef_uninit(struct upb_fielddef *f) |
|
|
|
|
static void fielddef_uninit(upb_fielddef *f) |
|
|
|
|
{ |
|
|
|
|
upb_string_unref(f->name); |
|
|
|
|
if(upb_hasdef(f) && f->owned) { |
|
|
|
@ -216,12 +215,12 @@ static void fielddef_uninit(struct upb_fielddef *f) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void fielddef_free(struct upb_fielddef *f) { |
|
|
|
|
static void fielddef_free(upb_fielddef *f) { |
|
|
|
|
fielddef_uninit(f); |
|
|
|
|
free(f); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void fielddef_copy(struct upb_fielddef *dst, struct upb_fielddef *src) |
|
|
|
|
static void fielddef_copy(upb_fielddef *dst, upb_fielddef *src) |
|
|
|
|
{ |
|
|
|
|
*dst = *src; |
|
|
|
|
dst->name = upb_string_getref(src->name, UPB_REF_FROZEN); |
|
|
|
@ -232,7 +231,7 @@ static void fielddef_copy(struct upb_fielddef *dst, struct upb_fielddef *src) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Callback for sorting fields.
|
|
|
|
|
static int compare_fields(struct upb_fielddef *f1, struct upb_fielddef *f2) { |
|
|
|
|
static int compare_fields(upb_fielddef *f1, upb_fielddef *f2) { |
|
|
|
|
// Required fields go before non-required.
|
|
|
|
|
bool req1 = f1->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED; |
|
|
|
|
bool req2 = f2->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED; |
|
|
|
@ -250,7 +249,7 @@ static int compare_fielddefs(const void *e1, const void *e2) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int compare_fds(const void *e1, const void *e2) { |
|
|
|
|
struct upb_fielddef f1, f2; |
|
|
|
|
upb_fielddef f1, f2; |
|
|
|
|
fielddef_init(&f1, *(void**)e1); |
|
|
|
|
fielddef_init(&f2, *(void**)e2); |
|
|
|
|
int ret = compare_fields(&f1, &f2); |
|
|
|
@ -264,17 +263,15 @@ void upb_fielddef_sortfds(google_protobuf_FieldDescriptorProto **fds, size_t num |
|
|
|
|
qsort(fds, num, sizeof(*fds), compare_fds); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void fielddef_sort(struct upb_fielddef **defs, size_t num) |
|
|
|
|
static void fielddef_sort(upb_fielddef **defs, size_t num) |
|
|
|
|
{ |
|
|
|
|
qsort(defs, num, sizeof(*defs), compare_fielddefs); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* upb_msgdef *****************************************************************/ |
|
|
|
|
|
|
|
|
|
static struct upb_msgdef *msgdef_new(struct upb_fielddef **fields, |
|
|
|
|
int num_fields, |
|
|
|
|
upb_strptr fqname, |
|
|
|
|
struct upb_status *status) |
|
|
|
|
static upb_msgdef *msgdef_new(upb_fielddef **fields, int num_fields, |
|
|
|
|
upb_strptr fqname, upb_status *status) |
|
|
|
|
{ |
|
|
|
|
if(num_fields > UPB_MAX_FIELDS) { |
|
|
|
|
upb_seterr(status, UPB_STATUS_ERROR, |
|
|
|
@ -282,23 +279,23 @@ static struct upb_msgdef *msgdef_new(struct upb_fielddef **fields, |
|
|
|
|
free(fields); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
struct upb_msgdef *m = malloc(sizeof(*m)); |
|
|
|
|
upb_msgdef *m = malloc(sizeof(*m)); |
|
|
|
|
upb_def_init(&m->base, UPB_DEF_MSG, fqname); |
|
|
|
|
upb_atomic_refcount_init(&m->cycle_refcount, 0); |
|
|
|
|
upb_inttable_init(&m->itof, num_fields, sizeof(struct upb_itof_ent)); |
|
|
|
|
upb_strtable_init(&m->ntof, num_fields, sizeof(struct upb_ntof_ent)); |
|
|
|
|
upb_inttable_init(&m->itof, num_fields, sizeof(upb_itof_ent)); |
|
|
|
|
upb_strtable_init(&m->ntof, num_fields, sizeof(upb_ntof_ent)); |
|
|
|
|
|
|
|
|
|
m->num_fields = num_fields; |
|
|
|
|
m->set_flags_bytes = div_round_up(m->num_fields, 8); |
|
|
|
|
// These are incremented in the loop.
|
|
|
|
|
m->num_required_fields = 0; |
|
|
|
|
m->size = m->set_flags_bytes + 4; // 4 for the refcount.
|
|
|
|
|
m->fields = malloc(sizeof(struct upb_fielddef) * num_fields); |
|
|
|
|
m->fields = malloc(sizeof(upb_fielddef) * num_fields); |
|
|
|
|
|
|
|
|
|
size_t max_align = 0; |
|
|
|
|
for(int i = 0; i < num_fields; i++) { |
|
|
|
|
struct upb_fielddef *f = &m->fields[i]; |
|
|
|
|
struct upb_type_info *type_info = &upb_type_info[fields[i]->type]; |
|
|
|
|
upb_fielddef *f = &m->fields[i]; |
|
|
|
|
upb_type_info *type_info = &upb_types[fields[i]->type]; |
|
|
|
|
fielddef_copy(f, fields[i]); |
|
|
|
|
|
|
|
|
|
// General alignment rules are: each member must be at an address that is a
|
|
|
|
@ -316,8 +313,8 @@ static struct upb_msgdef *msgdef_new(struct upb_fielddef **fields, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Insert into the tables.
|
|
|
|
|
struct upb_itof_ent itof_ent = {{f->number, 0}, f}; |
|
|
|
|
struct upb_ntof_ent ntof_ent = {{f->name, 0}, f}; |
|
|
|
|
upb_itof_ent itof_ent = {{f->number, 0}, f}; |
|
|
|
|
upb_ntof_ent ntof_ent = {{f->name, 0}, f}; |
|
|
|
|
upb_inttable_insert(&m->itof, &itof_ent.e); |
|
|
|
|
upb_strtable_insert(&m->ntof, &ntof_ent.e); |
|
|
|
|
} |
|
|
|
@ -326,7 +323,7 @@ static struct upb_msgdef *msgdef_new(struct upb_fielddef **fields, |
|
|
|
|
return m; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void msgdef_free(struct upb_msgdef *m) |
|
|
|
|
static void msgdef_free(upb_msgdef *m) |
|
|
|
|
{ |
|
|
|
|
for (upb_field_count_t i = 0; i < m->num_fields; i++) |
|
|
|
|
fielddef_uninit(&m->fields[i]); |
|
|
|
@ -337,8 +334,7 @@ static void msgdef_free(struct upb_msgdef *m) |
|
|
|
|
free(m); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void upb_msgdef_resolve(struct upb_msgdef *m, struct upb_fielddef *f, |
|
|
|
|
struct upb_def *def) { |
|
|
|
|
static void upb_msgdef_resolve(upb_msgdef *m, upb_fielddef *f, upb_def *def) { |
|
|
|
|
(void)m; |
|
|
|
|
if(f->owned) upb_def_unref(f->def); |
|
|
|
|
f->def = def; |
|
|
|
@ -349,75 +345,75 @@ static void upb_msgdef_resolve(struct upb_msgdef *m, struct upb_fielddef *f, |
|
|
|
|
|
|
|
|
|
/* upb_enumdef ****************************************************************/ |
|
|
|
|
|
|
|
|
|
struct ntoi_ent { |
|
|
|
|
struct upb_strtable_entry e; |
|
|
|
|
typedef struct { |
|
|
|
|
upb_strtable_entry e; |
|
|
|
|
uint32_t value; |
|
|
|
|
}; |
|
|
|
|
} ntoi_ent; |
|
|
|
|
|
|
|
|
|
struct iton_ent { |
|
|
|
|
struct upb_inttable_entry e; |
|
|
|
|
typedef struct { |
|
|
|
|
upb_inttable_entry e; |
|
|
|
|
upb_strptr string; |
|
|
|
|
}; |
|
|
|
|
} iton_ent; |
|
|
|
|
|
|
|
|
|
static struct upb_enumdef *enumdef_new(google_protobuf_EnumDescriptorProto *ed, |
|
|
|
|
upb_strptr fqname) |
|
|
|
|
static upb_enumdef *enumdef_new(google_protobuf_EnumDescriptorProto *ed, |
|
|
|
|
upb_strptr fqname) |
|
|
|
|
{ |
|
|
|
|
struct upb_enumdef *e = malloc(sizeof(*e)); |
|
|
|
|
upb_enumdef *e = malloc(sizeof(*e)); |
|
|
|
|
upb_def_init(&e->base, UPB_DEF_ENUM, fqname); |
|
|
|
|
int num_values = ed->set_flags.has.value ? |
|
|
|
|
google_protobuf_EnumValueDescriptorProto_array_len(ed->value) : 0; |
|
|
|
|
upb_strtable_init(&e->ntoi, num_values, sizeof(struct ntoi_ent)); |
|
|
|
|
upb_inttable_init(&e->iton, num_values, sizeof(struct iton_ent)); |
|
|
|
|
upb_strtable_init(&e->ntoi, num_values, sizeof(ntoi_ent)); |
|
|
|
|
upb_inttable_init(&e->iton, num_values, sizeof(iton_ent)); |
|
|
|
|
|
|
|
|
|
for(int i = 0; i < num_values; i++) { |
|
|
|
|
google_protobuf_EnumValueDescriptorProto *value = |
|
|
|
|
google_protobuf_EnumValueDescriptorProto_array_get(ed->value, i); |
|
|
|
|
struct ntoi_ent ntoi_ent = {{value->name, 0}, value->number}; |
|
|
|
|
struct iton_ent iton_ent = {{value->number, 0}, value->name}; |
|
|
|
|
ntoi_ent ntoi_ent = {{value->name, 0}, value->number}; |
|
|
|
|
iton_ent iton_ent = {{value->number, 0}, value->name}; |
|
|
|
|
upb_strtable_insert(&e->ntoi, &ntoi_ent.e); |
|
|
|
|
upb_inttable_insert(&e->iton, &iton_ent.e); |
|
|
|
|
} |
|
|
|
|
return e; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void enumdef_free(struct upb_enumdef *e) { |
|
|
|
|
static void enumdef_free(upb_enumdef *e) { |
|
|
|
|
upb_strtable_free(&e->ntoi); |
|
|
|
|
upb_inttable_free(&e->iton); |
|
|
|
|
upb_def_uninit(&e->base); |
|
|
|
|
free(e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void fill_iter(struct upb_enum_iter *iter, struct ntoi_ent *ent) { |
|
|
|
|
static void fill_iter(upb_enum_iter *iter, ntoi_ent *ent) { |
|
|
|
|
iter->state = ent; |
|
|
|
|
iter->name = ent->e.key; |
|
|
|
|
iter->val = ent->value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void upb_enum_begin(struct upb_enum_iter *iter, struct upb_enumdef *e) { |
|
|
|
|
void upb_enum_begin(upb_enum_iter *iter, upb_enumdef *e) { |
|
|
|
|
// We could iterate over either table here; the choice is arbitrary.
|
|
|
|
|
struct ntoi_ent *ent = upb_strtable_begin(&e->ntoi); |
|
|
|
|
ntoi_ent *ent = upb_strtable_begin(&e->ntoi); |
|
|
|
|
iter->e = e; |
|
|
|
|
fill_iter(iter, ent); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void upb_enum_next(struct upb_enum_iter *iter) { |
|
|
|
|
struct ntoi_ent *ent = iter->state; |
|
|
|
|
void upb_enum_next(upb_enum_iter *iter) { |
|
|
|
|
ntoi_ent *ent = iter->state; |
|
|
|
|
assert(ent); |
|
|
|
|
ent = upb_strtable_next(&iter->e->ntoi, &ent->e); |
|
|
|
|
iter->state = ent; |
|
|
|
|
if(ent) fill_iter(iter, ent); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool upb_enum_done(struct upb_enum_iter *iter) { |
|
|
|
|
bool upb_enum_done(upb_enum_iter *iter) { |
|
|
|
|
return iter->state == NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* symtab internal ***********************************************************/ |
|
|
|
|
|
|
|
|
|
struct symtab_ent { |
|
|
|
|
struct upb_strtable_entry e; |
|
|
|
|
struct upb_def *def; |
|
|
|
|
}; |
|
|
|
|
typedef struct { |
|
|
|
|
upb_strtable_entry e; |
|
|
|
|
upb_def *def; |
|
|
|
|
} symtab_ent; |
|
|
|
|
|
|
|
|
|
/* Search for a character in a string, in reverse. */ |
|
|
|
|
static int my_memrchr(char *data, char c, size_t len) |
|
|
|
@ -429,9 +425,7 @@ static int my_memrchr(char *data, char c, size_t len) |
|
|
|
|
|
|
|
|
|
/* Given a symbol and the base symbol inside which it is defined, find the
|
|
|
|
|
* symbol's definition in t. */ |
|
|
|
|
static struct symtab_ent *resolve(struct upb_strtable *t, |
|
|
|
|
upb_strptr base, |
|
|
|
|
upb_strptr symbol) |
|
|
|
|
static symtab_ent *resolve(upb_strtable *t, upb_strptr base, upb_strptr symbol) |
|
|
|
|
{ |
|
|
|
|
if(upb_strlen(base) + upb_strlen(symbol) + 1 >= UPB_SYMBOL_MAXLEN || |
|
|
|
|
upb_strlen(symbol) == 0) return NULL; |
|
|
|
@ -440,7 +434,7 @@ static struct symtab_ent *resolve(struct upb_strtable *t, |
|
|
|
|
// Symbols starting with '.' are absolute, so we do a single lookup.
|
|
|
|
|
// Slice to omit the leading '.'
|
|
|
|
|
upb_strptr sym_str = upb_strslice(symbol, 1, INT_MAX); |
|
|
|
|
struct symtab_ent *e = upb_strtable_lookup(t, sym_str); |
|
|
|
|
symtab_ent *e = upb_strtable_lookup(t, sym_str); |
|
|
|
|
upb_string_unref(sym_str); |
|
|
|
|
return e; |
|
|
|
|
} else { |
|
|
|
@ -455,7 +449,7 @@ static struct symtab_ent *resolve(struct upb_strtable *t, |
|
|
|
|
buf[baselen] = UPB_SYMBOL_SEPARATOR; |
|
|
|
|
memcpy(buf + baselen + 1, upb_string_getrobuf(symbol), upb_strlen(symbol)); |
|
|
|
|
|
|
|
|
|
struct symtab_ent *e = upb_strtable_lookup(t, sym_str); |
|
|
|
|
symtab_ent *e = upb_strtable_lookup(t, sym_str); |
|
|
|
|
if (e) return e; |
|
|
|
|
else if(baselen == 0) return NULL; /* No more scopes to try. */ |
|
|
|
|
|
|
|
|
@ -478,8 +472,8 @@ static upb_strptr join(upb_strptr base, upb_strptr name) { |
|
|
|
|
return joined; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static upb_strptr try_define(struct upb_strtable *t, upb_strptr base, |
|
|
|
|
upb_strptr name, struct upb_status *status) |
|
|
|
|
static upb_strptr try_define(upb_strtable *t, upb_strptr base, |
|
|
|
|
upb_strptr name, upb_status *status) |
|
|
|
|
{ |
|
|
|
|
if(upb_string_isnull(name)) { |
|
|
|
|
upb_seterr(status, UPB_STATUS_ERROR, |
|
|
|
@ -498,26 +492,23 @@ static upb_strptr try_define(struct upb_strtable *t, upb_strptr base, |
|
|
|
|
return fqname; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void insert_enum(struct upb_strtable *t, |
|
|
|
|
static void insert_enum(upb_strtable *t, |
|
|
|
|
google_protobuf_EnumDescriptorProto *ed, |
|
|
|
|
upb_strptr base, |
|
|
|
|
struct upb_status *status) |
|
|
|
|
upb_strptr base, upb_status *status) |
|
|
|
|
{ |
|
|
|
|
upb_strptr name = ed->set_flags.has.name ? ed->name : UPB_STRING_NULL; |
|
|
|
|
upb_strptr fqname = try_define(t, base, name, status); |
|
|
|
|
if(upb_string_isnull(fqname)) return; |
|
|
|
|
|
|
|
|
|
struct symtab_ent e; |
|
|
|
|
symtab_ent e; |
|
|
|
|
e.e.key = fqname; |
|
|
|
|
e.def = UPB_UPCAST(enumdef_new(ed, fqname)); |
|
|
|
|
upb_strtable_insert(t, &e.e); |
|
|
|
|
upb_string_unref(fqname); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void insert_message(struct upb_strtable *t, |
|
|
|
|
google_protobuf_DescriptorProto *d, |
|
|
|
|
upb_strptr base, bool sort, |
|
|
|
|
struct upb_status *status) |
|
|
|
|
static void insert_message(upb_strtable *t, google_protobuf_DescriptorProto *d, |
|
|
|
|
upb_strptr base, bool sort, upb_status *status) |
|
|
|
|
{ |
|
|
|
|
upb_strptr name = d->set_flags.has.name ? d->name : UPB_STRING_NULL; |
|
|
|
|
upb_strptr fqname = try_define(t, base, name, status); |
|
|
|
@ -525,11 +516,11 @@ static void insert_message(struct upb_strtable *t, |
|
|
|
|
|
|
|
|
|
int num_fields = d->set_flags.has.field ? |
|
|
|
|
google_protobuf_FieldDescriptorProto_array_len(d->field) : 0; |
|
|
|
|
struct symtab_ent e; |
|
|
|
|
symtab_ent e; |
|
|
|
|
e.e.key = fqname; |
|
|
|
|
|
|
|
|
|
// Gather our list of fields, sorting if necessary.
|
|
|
|
|
struct upb_fielddef **fielddefs = malloc(sizeof(*fielddefs) * num_fields); |
|
|
|
|
upb_fielddef **fielddefs = malloc(sizeof(*fielddefs) * num_fields); |
|
|
|
|
for (int i = 0; i < num_fields; i++) { |
|
|
|
|
google_protobuf_FieldDescriptorProto *fd = |
|
|
|
|
google_protobuf_FieldDescriptorProto_array_get(d->field, i); |
|
|
|
@ -562,8 +553,7 @@ error: |
|
|
|
|
upb_string_unref(fqname); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool find_cycles(struct upb_msgdef *m, int search_depth, |
|
|
|
|
struct upb_status *status) |
|
|
|
|
static bool find_cycles(upb_msgdef *m, int search_depth, upb_status *status) |
|
|
|
|
{ |
|
|
|
|
if(search_depth > UPB_MAX_TYPE_DEPTH) { |
|
|
|
|
// There are many situations in upb where we recurse over the type tree
|
|
|
|
@ -592,10 +582,10 @@ static bool find_cycles(struct upb_msgdef *m, int search_depth, |
|
|
|
|
UPB_UPCAST(m)->search_depth = ++search_depth; |
|
|
|
|
bool cycle_found = false; |
|
|
|
|
for(upb_field_count_t i = 0; i < m->num_fields; i++) { |
|
|
|
|
struct upb_fielddef *f = &m->fields[i]; |
|
|
|
|
upb_fielddef *f = &m->fields[i]; |
|
|
|
|
if(!upb_issubmsg(f)) continue; |
|
|
|
|
struct upb_def *sub_def = f->def; |
|
|
|
|
struct upb_msgdef *sub_m = upb_downcast_msgdef(sub_def); |
|
|
|
|
upb_def *sub_def = f->def; |
|
|
|
|
upb_msgdef *sub_m = upb_downcast_msgdef(sub_def); |
|
|
|
|
if(find_cycles(sub_m, search_depth, status)) { |
|
|
|
|
cycle_found = true; |
|
|
|
|
UPB_UPCAST(m)->is_cyclic = true; |
|
|
|
@ -610,9 +600,9 @@ static bool find_cycles(struct upb_msgdef *m, int search_depth, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void addfd(struct upb_strtable *addto, struct upb_strtable *existingdefs, |
|
|
|
|
static void addfd(upb_strtable *addto, upb_strtable *existingdefs, |
|
|
|
|
google_protobuf_FileDescriptorProto *fd, bool sort, |
|
|
|
|
struct upb_status *status) |
|
|
|
|
upb_status *status) |
|
|
|
|
{ |
|
|
|
|
upb_strptr pkg; |
|
|
|
|
if(fd->set_flags.has.package) { |
|
|
|
@ -639,16 +629,16 @@ static void addfd(struct upb_strtable *addto, struct upb_strtable *existingdefs, |
|
|
|
|
/* TODO: handle extensions and services. */ |
|
|
|
|
|
|
|
|
|
// Attempt to resolve all references.
|
|
|
|
|
struct symtab_ent *e; |
|
|
|
|
symtab_ent *e; |
|
|
|
|
for(e = upb_strtable_begin(addto); e; e = upb_strtable_next(addto, &e->e)) { |
|
|
|
|
struct upb_msgdef *m = upb_dyncast_msgdef(e->def); |
|
|
|
|
upb_msgdef *m = upb_dyncast_msgdef(e->def); |
|
|
|
|
if(!m) continue; |
|
|
|
|
upb_strptr base = e->e.key; |
|
|
|
|
for(upb_field_count_t i = 0; i < m->num_fields; i++) { |
|
|
|
|
struct upb_fielddef *f = &m->fields[i]; |
|
|
|
|
upb_fielddef *f = &m->fields[i]; |
|
|
|
|
if(!upb_hasdef(f)) continue; // No resolving necessary.
|
|
|
|
|
upb_strptr name = upb_downcast_unresolveddef(f->def)->name; |
|
|
|
|
struct symtab_ent *found = resolve(existingdefs, base, name); |
|
|
|
|
symtab_ent *found = resolve(existingdefs, base, name); |
|
|
|
|
if(!found) found = resolve(addto, base, name); |
|
|
|
|
upb_field_type_t expected = upb_issubmsg(f) ? UPB_DEF_MSG : UPB_DEF_ENUM; |
|
|
|
|
if(!found) { |
|
|
|
@ -667,33 +657,33 @@ static void addfd(struct upb_strtable *addto, struct upb_strtable *existingdefs, |
|
|
|
|
|
|
|
|
|
// Deal with type cycles.
|
|
|
|
|
for(e = upb_strtable_begin(addto); e; e = upb_strtable_next(addto, &e->e)) { |
|
|
|
|
struct upb_msgdef *m = upb_dyncast_msgdef(e->def); |
|
|
|
|
upb_msgdef *m = upb_dyncast_msgdef(e->def); |
|
|
|
|
if(!m) continue; |
|
|
|
|
|
|
|
|
|
// Do an initial pass over the graph to check that there are no cycles
|
|
|
|
|
// longer than the maximum length. We also mark all cyclic defs as such,
|
|
|
|
|
// and decrement refs on cyclic defs.
|
|
|
|
|
find_cycles(m, 0, status); |
|
|
|
|
struct upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; |
|
|
|
|
upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; |
|
|
|
|
cycle_ref_or_unref(m, NULL, open_defs, 0, true); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* upb_symtab *****************************************************************/ |
|
|
|
|
|
|
|
|
|
struct upb_symtab *upb_symtab_new() |
|
|
|
|
upb_symtab *upb_symtab_new() |
|
|
|
|
{ |
|
|
|
|
struct upb_symtab *s = malloc(sizeof(*s)); |
|
|
|
|
upb_symtab *s = malloc(sizeof(*s)); |
|
|
|
|
upb_atomic_refcount_init(&s->refcount, 1); |
|
|
|
|
upb_rwlock_init(&s->lock); |
|
|
|
|
upb_strtable_init(&s->symtab, 16, sizeof(struct symtab_ent)); |
|
|
|
|
upb_strtable_init(&s->psymtab, 16, sizeof(struct symtab_ent)); |
|
|
|
|
upb_strtable_init(&s->symtab, 16, sizeof(symtab_ent)); |
|
|
|
|
upb_strtable_init(&s->psymtab, 16, sizeof(symtab_ent)); |
|
|
|
|
|
|
|
|
|
// Add descriptor.proto types to private symtable so we can parse descriptors.
|
|
|
|
|
// We know there is only 1.
|
|
|
|
|
google_protobuf_FileDescriptorProto *fd = |
|
|
|
|
google_protobuf_FileDescriptorProto_array_get(upb_file_descriptor_set->file, 0); |
|
|
|
|
struct upb_status status = UPB_STATUS_INIT; |
|
|
|
|
upb_status status = UPB_STATUS_INIT; |
|
|
|
|
addfd(&s->psymtab, &s->symtab, fd, false, &status); |
|
|
|
|
if(!upb_ok(&status)) { |
|
|
|
|
fprintf(stderr, "Failed to initialize upb: %s.\n", status.msg); |
|
|
|
@ -703,21 +693,21 @@ struct upb_symtab *upb_symtab_new() |
|
|
|
|
upb_static_string name = |
|
|
|
|
UPB_STATIC_STRING_INIT("google.protobuf.FileDescriptorSet"); |
|
|
|
|
upb_strptr nameptr = UPB_STATIC_STRING_PTR_INIT(name); |
|
|
|
|
struct symtab_ent *e = upb_strtable_lookup(&s->psymtab, nameptr); |
|
|
|
|
symtab_ent *e = upb_strtable_lookup(&s->psymtab, nameptr); |
|
|
|
|
assert(e); |
|
|
|
|
s->fds_msgdef = upb_downcast_msgdef(e->def); |
|
|
|
|
return s; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void free_symtab(struct upb_strtable *t) |
|
|
|
|
static void free_symtab(upb_strtable *t) |
|
|
|
|
{ |
|
|
|
|
struct symtab_ent *e = upb_strtable_begin(t); |
|
|
|
|
for(; e; e = upb_strtable_next(t, &e->e)) |
|
|
|
|
symtab_ent *e; |
|
|
|
|
for(e = upb_strtable_begin(t); e; e = upb_strtable_next(t, &e->e)) |
|
|
|
|
upb_def_unref(e->def); |
|
|
|
|
upb_strtable_free(t); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void _upb_symtab_free(struct upb_symtab *s) |
|
|
|
|
void _upb_symtab_free(upb_symtab *s) |
|
|
|
|
{ |
|
|
|
|
free_symtab(&s->symtab); |
|
|
|
|
free_symtab(&s->psymtab); |
|
|
|
@ -725,18 +715,17 @@ void _upb_symtab_free(struct upb_symtab *s) |
|
|
|
|
free(s); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct upb_def **upb_symtab_getdefs(struct upb_symtab *s, int *count, |
|
|
|
|
upb_def_type_t type) |
|
|
|
|
upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_def_type_t type) |
|
|
|
|
{ |
|
|
|
|
upb_rwlock_rdlock(&s->lock); |
|
|
|
|
int total = upb_strtable_count(&s->symtab); |
|
|
|
|
// We may only use part of this, depending on how many symbols are of the
|
|
|
|
|
// correct type.
|
|
|
|
|
struct upb_def **defs = malloc(sizeof(*defs) * total); |
|
|
|
|
struct symtab_ent *e = upb_strtable_begin(&s->symtab); |
|
|
|
|
upb_def **defs = malloc(sizeof(*defs) * total); |
|
|
|
|
symtab_ent *e = upb_strtable_begin(&s->symtab); |
|
|
|
|
int i = 0; |
|
|
|
|
for(; e; e = upb_strtable_next(&s->symtab, &e->e)) { |
|
|
|
|
struct upb_def *def = e->def; |
|
|
|
|
upb_def *def = e->def; |
|
|
|
|
assert(def); |
|
|
|
|
if(type == UPB_DEF_ANY || def->type == type) |
|
|
|
|
defs[i++] = def; |
|
|
|
@ -748,11 +737,11 @@ struct upb_def **upb_symtab_getdefs(struct upb_symtab *s, int *count, |
|
|
|
|
return defs; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct upb_def *upb_symtab_lookup(struct upb_symtab *s, upb_strptr sym) |
|
|
|
|
upb_def *upb_symtab_lookup(upb_symtab *s, upb_strptr sym) |
|
|
|
|
{ |
|
|
|
|
upb_rwlock_rdlock(&s->lock); |
|
|
|
|
struct symtab_ent *e = upb_strtable_lookup(&s->symtab, sym); |
|
|
|
|
struct upb_def *ret = NULL; |
|
|
|
|
symtab_ent *e = upb_strtable_lookup(&s->symtab, sym); |
|
|
|
|
upb_def *ret = NULL; |
|
|
|
|
if(e) { |
|
|
|
|
ret = e->def; |
|
|
|
|
upb_def_ref(ret); |
|
|
|
@ -762,11 +751,10 @@ struct upb_def *upb_symtab_lookup(struct upb_symtab *s, upb_strptr sym) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct upb_def *upb_symtab_resolve(struct upb_symtab *s, upb_strptr base, |
|
|
|
|
upb_strptr symbol) { |
|
|
|
|
upb_def *upb_symtab_resolve(upb_symtab *s, upb_strptr base, upb_strptr symbol) { |
|
|
|
|
upb_rwlock_rdlock(&s->lock); |
|
|
|
|
struct symtab_ent *e = resolve(&s->symtab, base, symbol); |
|
|
|
|
struct upb_def *ret = NULL; |
|
|
|
|
symtab_ent *e = resolve(&s->symtab, base, symbol); |
|
|
|
|
upb_def *ret = NULL; |
|
|
|
|
if(e) { |
|
|
|
|
ret = e->def; |
|
|
|
|
upb_def_ref(ret); |
|
|
|
@ -775,15 +763,14 @@ struct upb_def *upb_symtab_resolve(struct upb_symtab *s, upb_strptr base, |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void upb_symtab_addfds(struct upb_symtab *s, |
|
|
|
|
google_protobuf_FileDescriptorSet *fds, |
|
|
|
|
struct upb_status *status) |
|
|
|
|
void upb_symtab_addfds(upb_symtab *s, google_protobuf_FileDescriptorSet *fds, |
|
|
|
|
upb_status *status) |
|
|
|
|
{ |
|
|
|
|
if(fds->set_flags.has.file) { |
|
|
|
|
// Insert new symbols into a temporary table until we have verified that
|
|
|
|
|
// the descriptor is valid.
|
|
|
|
|
struct upb_strtable tmp; |
|
|
|
|
upb_strtable_init(&tmp, 0, sizeof(struct symtab_ent)); |
|
|
|
|
upb_strtable tmp; |
|
|
|
|
upb_strtable_init(&tmp, 0, sizeof(symtab_ent)); |
|
|
|
|
|
|
|
|
|
{ // Read lock scope
|
|
|
|
|
upb_rwlock_rdlock(&s->lock); |
|
|
|
@ -801,7 +788,7 @@ void upb_symtab_addfds(struct upb_symtab *s, |
|
|
|
|
// Everything was successfully added, copy from the tmp symtable.
|
|
|
|
|
{ // Write lock scope
|
|
|
|
|
upb_rwlock_wrlock(&s->lock); |
|
|
|
|
struct symtab_ent *e; |
|
|
|
|
symtab_ent *e; |
|
|
|
|
for(e = upb_strtable_begin(&tmp); e; e = upb_strtable_next(&tmp, &e->e)) { |
|
|
|
|
// We checked for duplicates when we had only the read lock, but it is
|
|
|
|
|
// theoretically possible that a duplicate symbol when we dropped the
|
|
|
|
@ -825,8 +812,7 @@ void upb_symtab_addfds(struct upb_symtab *s, |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void upb_symtab_add_desc(struct upb_symtab *s, upb_strptr desc, |
|
|
|
|
struct upb_status *status) |
|
|
|
|
void upb_symtab_add_desc(upb_symtab *s, upb_strptr desc, upb_status *status) |
|
|
|
|
{ |
|
|
|
|
upb_msg *fds = upb_msg_new(s->fds_msgdef); |
|
|
|
|
upb_msg_decodestr(fds, s->fds_msgdef, desc, status); |
|
|
|
|