// TODO(haberman): discard upb_handlers* objects that do not actually have any // handlers set and cannot reach any upb_handlers* object that does. This is // slightly tricky to do correctly. static upb_handlers *newformsg(const upb_msgdef *m, const void *owner, dfs_state *s) { upb_handlers *h = upb_handlers_new(m, owner); if (!h) return NULL; if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom; s->callback(s->closure, h); // For each submessage field, get or create a handlers object and set it as // the subhandlers. 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); if (!upb_fielddef_issubmsg(f)) continue; const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f)); upb_value subm_ent; if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) { upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent)); } else { upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s); if (!sub_mh) goto oom; upb_handlers_setsubhandlers(h, f, sub_mh); upb_handlers_unref(sub_mh, &sub_mh); } } return h; oom: upb_handlers_unref(h, owner); return NULL; }
bool upb_symtab_dfs(upb_def *def, upb_def **open_defs, int n, upb_strtable *addtab) { // This linear search makes the DFS O(n^2) in the length of the paths. // Could make this O(n) with a hash table, but n is small. for (int i = 0; i < n; i++) { if (def == open_defs[i]) return false; } bool needcopy = false; upb_msgdef *m = upb_dyncast_msgdef(def); if (m) { upb_msg_iter i; open_defs[n++] = def; for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { upb_fielddef *f = upb_msg_iter_field(i); if (!upb_hassubdef(f)) continue; needcopy |= upb_symtab_dfs(f->def, open_defs, n, addtab); } } bool replacing = (upb_strtable_lookup(addtab, m->base.fqname) != NULL); if (needcopy && !replacing) { upb_symtab_ent e = {upb_def_dup(def)}; upb_strtable_insert(addtab, def->fqname, &e); replacing = true; } return replacing; }
static void upb_msgdef_free(upb_msgdef *m) { upb_msg_iter i; for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) upb_fielddef_free(upb_msg_iter_field(i)); upb_strtable_free(&m->ntof); upb_inttable_free(&m->itof); upb_def_uninit(&m->base); free(m); }
static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_msgdef *m = (const upb_msgdef*)r; 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); } }
static void validate_msgdef(const upb_msgdef* msgdef) { // Verify that no required fields exist. proto3 does not support these. upb_msg_iter it; for (upb_msg_begin(&it, msgdef); !upb_msg_done(&it); upb_msg_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) { rb_raise(rb_eTypeError, "Required fields are unsupported in proto3."); } } }
static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_handlers *h = (const upb_handlers*)r; upb_msg_iter i; for(upb_msg_begin(&i, h->msg); !upb_msg_done(&i); upb_msg_next(&i)) { 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); } }
upb_msgdef *upb_msgdef_dup(const upb_msgdef *m) { upb_msgdef *newm = upb_msgdef_new(); newm->size = m->size; newm->hasbit_bytes = m->hasbit_bytes; newm->extstart = m->extstart; newm->extend = m->extend; upb_msg_iter i; for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { upb_msgdef_addfield(newm, upb_fielddef_dup(upb_msg_iter_field(i))); } return newm; }
/* * call-seq: * Descriptor.each(&block) * * Iterates over fields in this message type, yielding to the block on each one. */ VALUE Descriptor_each(VALUE _self) { DEFINE_SELF(Descriptor, self, _self); upb_msg_iter it; for (upb_msg_begin(&it, self->msgdef); !upb_msg_done(&it); upb_msg_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); VALUE obj = get_def_obj(field); rb_yield(obj); } return Qnil; }
upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) { upb_msgdef *newm = upb_msgdef_new(owner); if (!newm) return NULL; upb_def_setfullname(upb_upcast(newm), upb_def_fullname(upb_upcast(m))); upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f); if (!f || !upb_msgdef_addfield(newm, f, &f)) { upb_msgdef_unref(newm, owner); return NULL; } } return newm; }
bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { // First perform validation, in two passes so we can check that we have a // transitive closure without needing to search. for (int i = 0; i < n; i++) { upb_def *def = defs[i]; if (upb_def_isfrozen(def)) { // Could relax this requirement if it's annoying. upb_status_seterrliteral(s, "def is already frozen"); goto err; } else if (def->type == UPB_DEF_FIELD) { upb_status_seterrliteral(s, "standalone fielddefs can not be frozen"); goto err; } else { // Set now to detect transitive closure in the second pass. def->came_from_user = true; } } 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]); if (m) { upb_inttable_compact(&m->itof); upb_msg_iter j; uint32_t selector = UPB_STATIC_SELECTOR_COUNT; for(upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j)) { upb_fielddef *f = upb_msg_iter_field(&j); assert(f->msgdef == m); if (!upb_validate_field(f, s)) goto err; f->selector_base = selector + upb_handlers_selectorbaseoffset(f); selector += upb_handlers_selectorcount(f); } m->selector_count = selector; } else if (e) { upb_inttable_compact(&e->iton); } } // Validation all passed; freeze the defs. return upb_refcounted_freeze((upb_refcounted*const*)defs, n, s); err: for (int i = 0; i < n; i++) { defs[i]->came_from_user = false; } assert(!upb_ok(s)); return false; }
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); UPB_ASSERT_VAR(ok, ok); upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f); if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) { upb_msgdef_unref(newm, owner); return NULL; } } return newm; }
void upb_msgdef_layout(upb_msgdef *m) { // Create an ordering over the fields, but only include fields with accessors. upb_fielddef **sorted_fields = malloc(sizeof(upb_fielddef*) * upb_msgdef_numfields(m)); int n = 0; upb_msg_iter i; for (i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { upb_fielddef *f = upb_msg_iter_field(i); if (f->accessor) sorted_fields[n++] = f; } m->hasbit_bytes = upb_div_round_up(n, 8); m->size = m->hasbit_bytes; // + header_size? // Assign hasbits. qsort(sorted_fields, n, sizeof(*sorted_fields), upb_fielddef_cmphasbit); for (int i = 0; i < n; i++) { upb_fielddef *f = sorted_fields[i]; f->hasbit = i; } // Assign value offsets. qsort(sorted_fields, n, sizeof(*sorted_fields), upb_fielddef_cmpval); size_t max_align = 0; for (int i = 0; i < n; i++) { upb_fielddef *f = sorted_fields[i]; const upb_type_info *type_info = &upb_types[f->type]; size_t size = type_info->size; size_t align = type_info->align; if (upb_isseq(f)) { size = sizeof(void*); align = alignof(void*); } // General alignment rules are: each member must be at an address that is a // multiple of that type's alignment. Also, the size of the structure as a // whole must be a multiple of the greatest alignment of any member. f->offset = upb_align_up(m->size, align); m->size = f->offset + size; max_align = UPB_MAX(max_align, align); } if (max_align > 0) m->size = upb_align_up(m->size, max_align); free(sorted_fields); }
static upb_flow_t upb_msg_dispatch(upb_msg *msg, upb_msgdef *md, upb_dispatcher *d) { upb_msg_iter i; for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { upb_fielddef *f = upb_msg_iter_field(i); if (!upb_msg_has(msg, f)) continue; upb_fhandlers *hf = upb_dispatcher_lookup(d, f->number); if (!hf) continue; upb_value val = upb_msg_get(msg, f); if (upb_isarray(f)) { upb_array *arr = upb_value_getarr(val); for (uint32_t j = 0; j < upb_array_len(arr); ++j) { upb_msg_pushval(upb_array_get(arr, f, j), f, d, hf); } } else { upb_msg_pushval(val, f, d, hf); } } return UPB_CONTINUE; }
void upb_stdmsg_free(void *m, const upb_msgdef *md) { if (m == NULL) return; upb_msg_iter i; for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { upb_fielddef *f = upb_msg_iter_field(i); if (!upb_isseq(f) && !upb_issubmsg(f) && !upb_isstring(f)) continue; void *subp = upb_value_getptr(upb_stdmsg_getptr(m, f->fval)); if (subp == NULL) continue; if (upb_isseq(f)) { upb_stdseq_free(subp, f); } else if (upb_issubmsg(f)) { upb_stdmsg_free(subp, upb_downcast_msgdef(f->def)); } else { upb_stdarray *str = subp; free(str->ptr); free(str); } } free(m); }
static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { // Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the // lowest indexes, but we do not publicly guarantee this. int n = upb_msgdef_numfields(m); upb_fielddef **fields = malloc(n * sizeof(*fields)); if (!fields) return false; upb_msg_iter j; int i; m->submsg_field_count = 0; for(i = 0, upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j), i++) { upb_fielddef *f = upb_msg_iter_field(&j); assert(f->msg.def == m); if (!upb_validate_field(f, s)) { free(fields); return false; } if (upb_fielddef_issubmsg(f)) { m->submsg_field_count++; } fields[i] = f; } qsort(fields, n, sizeof(*fields), cmp_fields); uint32_t selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count; for (i = 0; i < n; i++) { upb_fielddef *f = fields[i]; f->index_ = i; f->selector_base = selector + upb_handlers_selectorbaseoffset(f); selector += upb_handlers_selectorcount(f); } m->selector_count = selector; free(fields); return false; }
bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { // TODO: verify we have a transitive closure. for (int i = 0; i < n; i++) { upb_handlers *h = handlers[i]; if (!upb_ok(&h->status_)) { upb_status_seterrf(s, "handlers for message %s had error status: %s", upb_msgdef_fullname(upb_handlers_msgdef(h)), upb_status_errmsg(&h->status_)); return false; } // Check that there are no closure mismatches due to missing Start* handlers // or subhandlers with different type-level types. upb_msg_iter j; for(upb_msg_begin(&j, h->msg); !upb_msg_done(&j); upb_msg_next(&j)) { const upb_fielddef *f = upb_msg_iter_field(&j); if (upb_fielddef_isseq(f)) { if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s)) return false; } if (upb_fielddef_isstring(f)) { if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s)) return false; } if (upb_fielddef_issubmsg(f)) { bool hashandler = false; if (upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_STARTSUBMSG)) || upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_ENDSUBMSG))) { hashandler = true; } if (upb_fielddef_isseq(f) && (upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_STARTSEQ)) || upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_ENDSEQ)))) { hashandler = true; } if (hashandler && !upb_handlers_getsubhandlers(h, f)) { // For now we add an empty subhandlers in this case. It makes the // decoder code generator simpler, because it only has to handle two // cases (submessage has handlers or not) as opposed to three // (submessage has handlers in enclosing message but no subhandlers). // // This makes parsing less efficient in the case that we want to // notice a submessage but skip its contents (like if we're testing // for submessage presence or counting the number of repeated // submessages). In this case we will end up parsing the submessage // field by field and throwing away the results for each, instead of // skipping the whole delimited thing at once. If this is an issue we // can revisit it, but do remember that this only arises when you have // handlers (startseq/startsubmsg/endsubmsg/endseq) set for the // submessage but no subhandlers. The uses cases for this are // limited. upb_handlers *sub = upb_handlers_new(upb_fielddef_msgsubdef(f), &sub); upb_handlers_setsubhandlers(h, f, sub); upb_handlers_unref(sub, &sub); } // TODO(haberman): check type of submessage. // This is slightly tricky; also consider whether we should check that // they match at setsubhandlers time. } } } if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s, UPB_MAX_HANDLER_DEPTH)) { return false; } return true; }
bool upb_symtab_add(upb_symtab *s, upb_def **defs, int n, upb_status *status) { upb_rwlock_wrlock(&s->lock); // Add all defs to a table for resolution. upb_strtable addtab; upb_strtable_init(&addtab, n, sizeof(upb_symtab_ent)); for (int i = 0; i < n; i++) { upb_def *def = defs[i]; if (upb_strtable_lookup(&addtab, def->fqname)) { upb_status_seterrf(status, "Conflicting defs named '%s'", def->fqname); upb_strtable_free(&addtab); return false; } upb_strtable_insert(&addtab, def->fqname, &def); } // All existing defs that can reach defs that are being replaced must // themselves be replaced with versions that will point to the new defs. // Do a DFS -- any path that finds a new def must replace all ancestors. upb_strtable *symtab = &s->symtab; upb_strtable_iter i; upb_strtable_begin(&i, symtab); for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { upb_def *open_defs[UPB_MAX_TYPE_DEPTH]; const upb_symtab_ent *e = upb_strtable_iter_value(&i); upb_symtab_dfs(e->def, open_defs, 0, &addtab); } // Resolve all refs. upb_strtable_begin(&i, &addtab); for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { const upb_symtab_ent *e = upb_strtable_iter_value(&i); upb_msgdef *m = upb_dyncast_msgdef(e->def); if(!m) continue; // Type names are resolved relative to the message in which they appear. const char *base = m->base.fqname; upb_msg_iter j; for(j = upb_msg_begin(m); !upb_msg_done(j); j = upb_msg_next(m, j)) { upb_fielddef *f = upb_msg_iter_field(j); if (f->type == 0) { upb_status_seterrf(status, "Field type was not set."); return false; } if (!upb_hassubdef(f)) continue; // No resolving necessary. upb_downcast_unresolveddef(f->def); // Type check. const char *name = f->def->fqname; // Resolve from either the addtab (pending adds) or symtab (existing // defs). If both exist, prefer the pending add, because it will be // overwriting the existing def. upb_symtab_ent *found; if(!(found = upb_resolve(&addtab, base, name)) && !(found = upb_resolve(symtab, base, name))) { upb_status_seterrf(status, "could not resolve symbol '%s' " "in context '%s'", name, base); return false; } // Check the type of the found def. upb_fieldtype_t expected = upb_issubmsg(f) ? UPB_DEF_MSG : UPB_DEF_ENUM; if(found->def->type != expected) { upb_status_seterrliteral(status, "Unexpected type"); return false; } if (!upb_fielddef_resolve(f, found->def, status)) return false; } } // The defs in the transaction have been vetted, and can be moved to the // symtab without causing errors. upb_strtable_begin(&i, &addtab); for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { const upb_symtab_ent *tmptab_e = upb_strtable_iter_value(&i); upb_def_movetosymtab(tmptab_e->def, s); upb_symtab_ent *symtab_e = upb_strtable_lookup(&s->symtab, tmptab_e->def->fqname); if(symtab_e) { upb_deflist_push(&s->olddefs, symtab_e->def); symtab_e->def = tmptab_e->def; } else { upb_strtable_insert(&s->symtab, tmptab_e->def->fqname, tmptab_e); } } upb_strtable_free(&addtab); upb_rwlock_unlock(&s->lock); upb_symtab_gc(s); return true; }