Esempio n. 1
0
File: handlers.c Progetto: YauzZ/upb
// 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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
File: def.c Progetto: Phuehvk/upb
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);
  }
}
Esempio n. 5
0
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.");
    }
  }
}
Esempio n. 6
0
File: handlers.c Progetto: YauzZ/upb
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);
  }
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
/*
 * 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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
File: def.c Progetto: Phuehvk/upb
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;
}
Esempio n. 11
0
File: def.c Progetto: YauzZ/upb
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;
}
Esempio n. 12
0
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);
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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);
}
Esempio n. 15
0
File: def.c Progetto: YauzZ/upb
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;
}
Esempio n. 16
0
File: handlers.c Progetto: YauzZ/upb
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;
}
Esempio n. 17
0
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;
}