diff options
Diffstat (limited to 'upb/def.c')
-rw-r--r-- | upb/def.c | 348 |
1 files changed, 19 insertions, 329 deletions
@@ -122,22 +122,6 @@ bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) { const upb_filedef *upb_def_file(const upb_def *d) { return d->file; } -upb_def *upb_def_dup(const upb_def *def, const void *o) { - switch (def->type) { - case UPB_DEF_MSG: - return upb_msgdef_upcast_mutable( - upb_msgdef_dup(upb_downcast_msgdef(def), o)); - case UPB_DEF_FIELD: - return upb_fielddef_upcast_mutable( - upb_fielddef_dup(upb_downcast_fielddef(def), o)); - case UPB_DEF_ENUM: - return upb_enumdef_upcast_mutable( - upb_enumdef_dup(upb_downcast_enumdef(def), o)); - default: - UPB_UNREACHABLE(); - } -} - static bool upb_def_init(upb_def *def, upb_deftype_t type, const struct upb_refcounted_vtbl *vtbl, const void *owner) { @@ -394,13 +378,14 @@ bool _upb_def_validate(upb_def *const*defs, size_t n, upb_status *s) { } else if (def->type == UPB_DEF_FIELD) { upb_status_seterrmsg(s, "standalone fielddefs can not be frozen"); goto err; - } else if (def->type == UPB_DEF_ENUM) { - if (!upb_validate_enumdef(upb_dyncast_enumdef(def), s)) { - goto err; - } } else { /* Set now to detect transitive closure in the second pass. */ def->came_from_user = true; + + if (def->type == UPB_DEF_ENUM && + !upb_validate_enumdef(upb_dyncast_enumdef(def), s)) { + goto err; + } } } @@ -493,21 +478,6 @@ err2: return NULL; } -upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner) { - upb_enum_iter i; - upb_enumdef *new_e = upb_enumdef_new(owner); - if (!new_e) return NULL; - for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) { - bool success = upb_enumdef_addval( - new_e, upb_enum_iter_name(&i),upb_enum_iter_number(&i), NULL); - if (!success) { - upb_enumdef_unref(new_e, owner); - return NULL; - } - } - return new_e; -} - bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status) { upb_def *d = upb_enumdef_upcast_mutable(e); return upb_def_freeze(&d, 1, status); @@ -742,42 +712,6 @@ upb_fielddef *upb_fielddef_new(const void *o) { return f; } -upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) { - const char *srcname; - upb_fielddef *newf = upb_fielddef_new(owner); - if (!newf) return NULL; - upb_fielddef_settype(newf, upb_fielddef_type(f)); - upb_fielddef_setlabel(newf, upb_fielddef_label(f)); - upb_fielddef_setnumber(newf, upb_fielddef_number(f), NULL); - upb_fielddef_setname(newf, upb_fielddef_name(f), NULL); - if (f->default_is_string && f->defaultval.bytes) { - str_t *s = f->defaultval.bytes; - upb_fielddef_setdefaultstr(newf, s->str, s->len, NULL); - } else { - newf->default_is_string = f->default_is_string; - newf->defaultval = f->defaultval; - } - - if (f->subdef_is_symbolic) { - srcname = f->sub.name; /* Might be NULL. */ - } else { - srcname = f->sub.def ? upb_def_fullname(f->sub.def) : NULL; - } - if (srcname) { - char *newname = upb_gmalloc(strlen(f->sub.def->fullname) + 2); - if (!newname) { - upb_fielddef_unref(newf, owner); - return NULL; - } - strcpy(newname, "."); - strcat(newname, f->sub.def->fullname); - upb_fielddef_setsubdefname(newf, newname, NULL); - upb_gfree(newname); - } - - return newf; -} - bool upb_fielddef_typeisset(const upb_fielddef *f) { return f->type_is_set_; } @@ -1457,42 +1391,6 @@ err2: return NULL; } -upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) { - bool ok; - upb_msg_field_iter i; - upb_msg_oneof_iter o; - - upb_msgdef *newm = upb_msgdef_new(owner); - if (!newm) return NULL; - ok = upb_def_setfullname(upb_msgdef_upcast_mutable(newm), - upb_def_fullname(upb_msgdef_upcast(m)), - NULL); - newm->map_entry = m->map_entry; - newm->syntax = m->syntax; - UPB_ASSERT(ok); - for(upb_msg_field_begin(&i, m); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f); - /* Fields in oneofs are dup'd below. */ - if (upb_fielddef_containingoneof(f)) continue; - if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) { - upb_msgdef_unref(newm, owner); - return NULL; - } - } - for(upb_msg_oneof_begin(&o, m); - !upb_msg_oneof_done(&o); - upb_msg_oneof_next(&o)) { - upb_oneofdef *f = upb_oneofdef_dup(upb_msg_iter_oneof(&o), &f); - if (!f || !upb_msgdef_addoneof(newm, f, &f, NULL)) { - upb_msgdef_unref(newm, owner); - return NULL; - } - } - return newm; -} - bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status) { upb_def *d = upb_msgdef_upcast_mutable(m); return upb_def_freeze(&d, 1, status); @@ -1793,23 +1691,6 @@ err2: return NULL; } -upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner) { - bool ok; - upb_oneof_iter i; - upb_oneofdef *newo = upb_oneofdef_new(owner); - if (!newo) return NULL; - ok = upb_oneofdef_setname(newo, upb_oneofdef_name(o), NULL); - UPB_ASSERT(ok); - for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) { - upb_fielddef *f = upb_fielddef_dup(upb_oneof_iter_field(&i), &f); - if (!f || !upb_oneofdef_addfield(newo, f, &f, NULL)) { - upb_oneofdef_unref(newo, owner); - return NULL; - } - } - return newo; -} - const char *upb_oneofdef_name(const upb_oneofdef *o) { return o->name; } bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s) { @@ -2142,8 +2023,7 @@ bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep) { } } -static void upb_symtab_free(upb_refcounted *r) { - upb_symtab *s = (upb_symtab*)r; +void upb_symtab_free(upb_symtab *s) { upb_strtable_iter i; upb_strtable_begin(&i, &s->symtab); for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { @@ -2154,32 +2034,16 @@ static void upb_symtab_free(upb_refcounted *r) { upb_gfree(s); } -upb_symtab *upb_symtab_new(const void *owner) { - static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_symtab_free}; - +upb_symtab *upb_symtab_new() { upb_symtab *s = upb_gmalloc(sizeof(*s)); if (!s) { return NULL; } - upb_refcounted_init(upb_symtab_upcast_mutable(s), &vtbl, owner); upb_strtable_init(&s->symtab, UPB_CTYPE_PTR); return s; } -void upb_symtab_freeze(upb_symtab *s) { - upb_refcounted *r; - bool ok; - - UPB_ASSERT(!upb_symtab_isfrozen(s)); - r = upb_symtab_upcast_mutable(s); - /* The symtab does not take ref2's (see refcounted.h) on the defs, because - * defs cannot refer back to the table and therefore cannot create cycles. So - * 0 will suffice for maxdepth here. */ - ok = upb_refcounted_freeze(&r, 1, NULL, 0); - UPB_ASSERT(ok); -} - const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym) { upb_value v; upb_def *ret = upb_strtable_lookup(&s->symtab, sym, &v) ? @@ -2226,115 +2090,7 @@ const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, return ret; } -/* Starts a depth-first traversal at "def", recursing into any subdefs - * (ie. submessage types). Adds duplicates of existing defs to addtab - * wherever necessary, so that the resulting symtab will be consistent once - * addtab is added. - * - * More specifically, if any def D is found in the DFS that: - * - * 1. can reach a def that is being replaced by something in addtab, AND - * - * 2. is not itself being replaced already (ie. this name doesn't already - * exist in addtab) - * - * ...then a duplicate (new copy) of D will be added to addtab. - * - * Returns true if this happened for any def reachable from "def." - * - * It is slightly tricky to do this correctly in the presence of cycles. If we - * detect that our DFS has hit a cycle, we might not yet know if any SCCs on - * our stack can reach a def in addtab or not. Once we figure this out, that - * answer needs to apply to *all* defs in these SCCs, even if we visited them - * already. So a straight up one-pass cycle-detecting DFS won't work. - * - * To work around this problem, we traverse each SCC (which we already - * computed, since these defs are frozen) as a single node. We first compute - * whether the SCC as a whole can reach any def in addtab, then we dup (or not) - * the entire SCC. This requires breaking the encapsulation of upb_refcounted, - * since that is where we get the data about what SCC we are in. */ -static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab, - const void *new_owner, upb_inttable *seen, - upb_status *s) { - upb_value v; - bool need_dup; - const upb_def *base; - const void* memoize_key; - - /* Memoize results of this function for efficiency (since we're traversing a - * DAG this is not needed to limit the depth of the search). - * - * We memoize by SCC instead of by individual def. */ - memoize_key = def->base.group; - - if (upb_inttable_lookupptr(seen, memoize_key, &v)) - return upb_value_getbool(v); - - /* Visit submessages for all messages in the SCC. */ - need_dup = false; - base = def; - do { - upb_value v; - const upb_msgdef *m; - - UPB_ASSERT(upb_def_isfrozen(def)); - if (def->type == UPB_DEF_FIELD) continue; - if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) { - need_dup = true; - } - - /* For messages, continue the recursion by visiting all subdefs, but only - * ones in different SCCs. */ - m = upb_dyncast_msgdef(def); - if (m) { - upb_msg_field_iter i; - for(upb_msg_field_begin(&i, m); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - upb_fielddef *f = upb_msg_iter_field(&i); - const upb_def *subdef; - - if (!upb_fielddef_hassubdef(f)) continue; - subdef = upb_fielddef_subdef(f); - - /* Skip subdefs in this SCC. */ - if (def->base.group == subdef->base.group) continue; - - /* |= to avoid short-circuit; we need its side-effects. */ - need_dup |= upb_resolve_dfs(subdef, addtab, new_owner, seen, s); - if (!upb_ok(s)) return false; - } - } - } while ((def = (upb_def*)def->base.next) != base); - - if (need_dup) { - /* Dup all defs in this SCC that don't already have entries in addtab. */ - def = base; - do { - const char *name; - - if (def->type == UPB_DEF_FIELD) continue; - name = upb_def_fullname(def); - if (!upb_strtable_lookup(addtab, name, NULL)) { - upb_def *newdef = upb_def_dup(def, new_owner); - if (!newdef) goto oom; - newdef->came_from_user = false; - if (!upb_strtable_insert(addtab, name, upb_value_ptr(newdef))) - goto oom; - } - } while ((def = (upb_def*)def->base.next) != base); - } - - upb_inttable_insertptr(seen, memoize_key, upb_value_bool(need_dup)); - return need_dup; - -oom: - upb_status_seterrmsg(s, "out of memory"); - return false; -} - -/* TODO(haberman): we need a lot more testing of error conditions. - * The came_from_user stuff in particular is not tested. */ +/* TODO(haberman): we need a lot more testing of error conditions. */ static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, void *ref_donor, upb_refcounted *freeze_also, upb_status *status) { @@ -2346,13 +2102,11 @@ static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, upb_def **add_defs = NULL; size_t add_objs_size; upb_strtable addtab; - upb_inttable seen; if (n == 0 && !freeze_also) { return true; } - UPB_ASSERT(!upb_symtab_isfrozen(s)); if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) { upb_status_seterrmsg(status, "out of memory"); return false; @@ -2390,74 +2144,23 @@ static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, upb_status_seterrf(status, "Conflicting defs named '%s'", fullname); goto err; } - /* We need this to back out properly, because if there is a failure we - * need to donate the ref back to the caller. */ - def->came_from_user = true; - upb_def_donateref(def, ref_donor, s); - if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def))) - goto oom_err; - } - } - - /* Add standalone fielddefs (ie. extensions) to the appropriate messages. - * If the appropriate message only exists in the existing symtab, duplicate - * it so we have a mutable copy we can add the fields to. */ - for (i = 0; i < n; i++) { - upb_def *def = defs[i]; - upb_fielddef *f = upb_dyncast_fielddef_mutable(def); - const char *msgname; - upb_value v; - upb_msgdef *m; - - if (!f) continue; - msgname = upb_fielddef_containingtypename(f); - /* We validated this earlier in this function. */ - UPB_ASSERT(msgname); - - /* If the extendee name is absolutely qualified, move past the initial ".". - * TODO(haberman): it is not obvious what it would mean if this was not - * absolutely qualified. */ - if (msgname[0] == '.') { - msgname++; - } - - if (upb_strtable_lookup(&addtab, msgname, &v)) { - /* Extendee is in the set of defs the user asked us to add. */ - m = upb_value_getptr(v); - } else { - /* Need to find and dup the extendee from the existing symtab. */ - const upb_msgdef *frozen_m = upb_symtab_lookupmsg(s, msgname); - if (!frozen_m) { - upb_status_seterrf(status, - "Tried to extend message %s that does not exist " - "in this SymbolTable.", - msgname); + if (upb_strtable_lookup(&s->symtab, fullname, NULL)) { + upb_status_seterrf(status, "Symtab already has a def named '%s'", + fullname); goto err; } - m = upb_msgdef_dup(frozen_m, s); - if (!m) goto oom_err; - if (!upb_strtable_insert(&addtab, msgname, upb_value_ptr(m))) { - upb_msgdef_unref(m, s); + if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def))) goto oom_err; - } + upb_def_donateref(def, ref_donor, s); } - if (!upb_msgdef_addfield(m, f, ref_donor, status)) { + if (upb_dyncast_fielddef_mutable(def)) { + /* TODO(haberman): allow adding extensions attached to files. */ + upb_status_seterrf(status, "Can't add extensions to symtab.\n"); goto err; } } - /* Add dups of any existing def that can reach a def with the same name as - * anything in our "add" set. */ - if (!upb_inttable_init(&seen, UPB_CTYPE_BOOL)) goto oom_err; - upb_strtable_begin(&iter, &s->symtab); - for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { - upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter)); - upb_resolve_dfs(def, &addtab, s, &seen, status); - if (!upb_ok(status)) goto err; - } - upb_inttable_uninit(&seen); - /* Now using the table, resolve symbolic references for subdefs. */ upb_strtable_begin(&iter, &addtab); for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { @@ -2535,15 +2238,9 @@ static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, for (i = 0; i < add_n; i++) { upb_def *def = (upb_def*)add_objs[i]; const char *name = upb_def_fullname(def); - upb_value v; bool success; - - if (upb_strtable_remove(&s->symtab, name, &v)) { - const upb_def *def = upb_value_getptr(v); - upb_def_unref(def, s); - } success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def)); - UPB_ASSERT(success == true); + UPB_ASSERT(success); } upb_gfree(add_defs); return true; @@ -2551,18 +2248,11 @@ static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, oom_err: upb_status_seterrmsg(status, "out of memory"); err: { - /* For defs the user passed in, we need to donate the refs back. For defs - * we dup'd, we need to just unref them. */ + /* We need to donate the refs back. */ upb_strtable_begin(&iter, &addtab); for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter)); - bool came_from_user = def->came_from_user; - def->came_from_user = false; - if (came_from_user) { - upb_def_donateref(def, s, ref_donor); - } else { - upb_def_unref(def, s); - } + upb_def_donateref(def, s, ref_donor); } } upb_strtable_uninit(&addtab); |