use mini descriptors to build message defs and extension defs

PiperOrigin-RevId: 477332937
pull/13171/head
Eric Salo 2 years ago committed by Copybara-Service
parent e779b9d90a
commit efd06e46a4
  1. 2
      upb/mini_table.c
  2. 10
      upb/reflection/def_builder.c
  3. 13
      upb/reflection/def_builder.h
  4. 79
      upb/reflection/def_pool.c
  5. 41
      upb/reflection/def_pool.h
  6. 24
      upb/reflection/enum_def.c
  7. 5
      upb/reflection/enum_def.h
  8. 21
      upb/reflection/enum_value_def.c
  9. 3
      upb/reflection/enum_value_def.h
  10. 584
      upb/reflection/field_def.c
  11. 18
      upb/reflection/field_def.h
  12. 29
      upb/reflection/file_def.c
  13. 147
      upb/reflection/message_def.c
  14. 4
      upb/reflection/message_def.h
  15. 69
      upb/reflection/mini_descriptor_encode.c
  16. 13
      upb/reflection/mini_descriptor_encode.h

@ -990,7 +990,7 @@ upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len,
done:
*buf = decoder.vec.data;
*buf_size = decoder.vec.capacity / sizeof(*decoder.vec.data);
*buf_size = decoder.vec.capacity * sizeof(*decoder.vec.data);
return decoder.table;
}

@ -59,17 +59,19 @@ const char* _upb_DefBuilder_FullToShort(const char* fullname) {
}
}
void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); }
void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) {
va_list argp;
va_start(argp, fmt);
upb_Status_VSetErrorFormat(ctx->status, fmt, argp);
va_end(argp);
UPB_LONGJMP(ctx->err, 1);
_upb_DefBuilder_FailJmp(ctx);
}
void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) {
upb_Status_SetErrorMessage(ctx->status, "out of memory");
UPB_LONGJMP(ctx->err, 1);
_upb_DefBuilder_FailJmp(ctx);
}
const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx,
@ -114,7 +116,7 @@ const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx,
if (sym.data[0] == '.') {
/* Symbols starting with '.' are absolute, so we do a single lookup.
* Slice to omit the leading '.' */
if (!_upb_DefPool_LookupAny2(ctx->symtab, sym.data + 1, sym.size - 1, &v)) {
if (!_upb_DefPool_LookupSym(ctx->symtab, sym.data + 1, sym.size - 1, &v)) {
goto notfound;
}
} else {
@ -130,7 +132,7 @@ const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx,
}
memcpy(p, sym.data, sym.size);
p += sym.size;
if (_upb_DefPool_LookupAny2(ctx->symtab, tmp, p - tmp, &v)) {
if (_upb_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) {
break;
}
if (!remove_component(tmp, &baselen)) {

@ -69,6 +69,9 @@ struct upb_DefBuilder {
extern const char* kUpbDefOptDefault;
// ctx->status has already been set elsewhere so just fail/longjmp()
UPB_NORETURN void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx);
UPB_NORETURN void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt,
...) UPB_PRINTF(2, 3);
UPB_NORETURN void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx);
@ -105,13 +108,9 @@ UPB_INLINE void* _upb_DefBuilder_Alloc(upb_DefBuilder* ctx, size_t bytes) {
// adding, so we know which entries to remove if building this file fails.
UPB_INLINE void _upb_DefBuilder_Add(upb_DefBuilder* ctx, const char* name,
upb_value v) {
// TODO: table should support an operation "tryinsert" to avoid the double
// lookup.
if (_upb_DefPool_Contains(ctx->symtab, name)) {
_upb_DefBuilder_Errf(ctx, "duplicate symbol '%s'", name);
}
bool ok = _upb_DefPool_Insert(ctx->symtab, name, v);
if (!ok) _upb_DefBuilder_OomErr(ctx);
upb_StringView sym = {.data = name, .size = strlen(name)};
bool ok = _upb_DefPool_InsertSym(ctx->symtab, sym, v, ctx->status);
if (!ok) _upb_DefBuilder_FailJmp(ctx);
}
UPB_INLINE upb_Arena* _upb_DefBuilder_Arena(const upb_DefBuilder* ctx) {

@ -27,8 +27,6 @@
#include "upb/reflection/def_pool.h"
#include <stdio.h>
#include "upb/reflection/def_builder.h"
#include "upb/reflection/def_type.h"
#include "upb/reflection/enum_def.h"
@ -47,11 +45,14 @@ struct upb_DefPool {
upb_strtable files; // file_name -> (upb_FileDef*)
upb_inttable exts; // (upb_MiniTable_Extension*) -> (upb_FieldDef*)
upb_ExtensionRegistry* extreg;
void* scratch_data;
size_t scratch_size;
size_t bytes_loaded;
};
void upb_DefPool_Free(upb_DefPool* s) {
upb_Arena_Free(s->arena);
upb_gfree(s->scratch_data);
upb_gfree(s);
}
@ -62,6 +63,10 @@ upb_DefPool* upb_DefPool_New(void) {
s->arena = upb_Arena_New();
s->bytes_loaded = 0;
s->scratch_size = 240;
s->scratch_data = upb_gmalloc(s->scratch_size);
if (!s->scratch_data) goto err;
if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err;
if (!upb_strtable_init(&s->files, 4, s->arena)) goto err;
if (!upb_inttable_init(&s->exts, s->arena)) goto err;
@ -72,45 +77,41 @@ upb_DefPool* upb_DefPool_New(void) {
return s;
err:
upb_Arena_Free(s->arena);
upb_gfree(s);
upb_DefPool_Free(s);
return NULL;
}
bool _upb_DefPool_Contains(const upb_DefPool* s, const char* sym) {
return upb_strtable_lookup(&s->syms, sym, NULL);
}
bool _upb_DefPool_Insert(upb_DefPool* s, const char* sym, upb_value v) {
return _upb_DefPool_Insert2(s, sym, strlen(sym), v);
}
bool _upb_DefPool_Insert2(upb_DefPool* s, const char* sym, size_t size,
upb_value v) {
return upb_strtable_insert(&s->syms, sym, size, v, s->arena);
}
bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext,
upb_FieldDef* f, upb_Arena* a) {
upb_FieldDef* f) {
return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f),
a);
s->arena);
}
static const void* _upb_DefPool_Lookup(const upb_DefPool* s, const char* sym,
upb_deftype_t type) {
return _upb_DefPool_Lookup2(s, sym, strlen(sym), type);
bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v,
upb_Status* status) {
// TODO: table should support an operation "tryinsert" to avoid the double
// lookup.
if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) {
upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data);
return false;
}
if (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) {
upb_Status_SetErrorMessage(status, "out of memory");
return false;
}
return true;
}
const void* _upb_DefPool_Lookup2(const upb_DefPool* s, const char* sym,
size_t size, upb_deftype_t type) {
static const void* _upb_DefPool_Unpack(const upb_DefPool* s, const char* sym,
size_t size, upb_deftype_t type) {
upb_value v;
return upb_strtable_lookup2(&s->syms, sym, size, &v)
? _upb_DefType_Unpack(v, type)
: NULL;
}
bool _upb_DefPool_LookupAny2(const upb_DefPool* s, const char* sym, size_t size,
upb_value* v) {
bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size,
upb_value* v) {
return upb_strtable_lookup2(&s->syms, sym, size, v);
}
@ -118,24 +119,32 @@ upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) {
return s->extreg;
}
void** _upb_DefPool_ScratchData(const upb_DefPool* s) {
return (void**)&s->scratch_data;
}
size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) {
return (size_t*)&s->scratch_size;
}
const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s,
const char* sym) {
return _upb_DefPool_Lookup(s, sym, UPB_DEFTYPE_MSG);
return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_MSG);
}
const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize(
const upb_DefPool* s, const char* sym, size_t len) {
return _upb_DefPool_Lookup2(s, sym, len, UPB_DEFTYPE_MSG);
return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG);
}
const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s,
const char* sym) {
return _upb_DefPool_Lookup(s, sym, UPB_DEFTYPE_ENUM);
return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUM);
}
const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s,
const char* sym) {
return _upb_DefPool_Lookup(s, sym, UPB_DEFTYPE_ENUMVAL);
return _upb_DefPool_Unpack(s, sym, strlen(sym), UPB_DEFTYPE_ENUMVAL);
}
const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s,
@ -182,12 +191,12 @@ const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s,
const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s,
const char* name) {
return _upb_DefPool_Lookup(s, name, UPB_DEFTYPE_SERVICE);
return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE);
}
const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize(
const upb_DefPool* s, const char* name, size_t size) {
return _upb_DefPool_Lookup2(s, name, size, UPB_DEFTYPE_SERVICE);
return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE);
}
const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s,
@ -275,6 +284,12 @@ static const upb_FileDef* _upb_DefPool_AddFile(
const upb_MiniTable_File* layout, upb_Status* status) {
const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto);
if (name.size == 0) {
upb_Status_SetErrorFormat(status,
"missing name in google_protobuf_FileDescriptorProto");
return NULL;
}
// Determine whether we already know about this file.
{
upb_value v;

@ -96,44 +96,37 @@ const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s,
// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE /////////////////////////
// For generated code only: loads a generated descriptor.
typedef struct _upb_DefPool_Init {
struct _upb_DefPool_Init** deps; // Dependencies of this file.
const upb_MiniTable_File* layout;
const char* filename;
upb_StringView descriptor; // Serialized descriptor.
} _upb_DefPool_Init;
upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s);
size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s);
bool _upb_DefPool_Contains(const upb_DefPool* s, const char* sym);
upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s);
bool _upb_DefPool_Insert(upb_DefPool* s, const char* sym, upb_value v);
bool _upb_DefPool_Insert2(upb_DefPool* s, const char* sym, size_t size,
upb_value v);
const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable(
const upb_DefPool* s, const upb_MiniTable_Extension* ext);
bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTable_Extension* ext,
upb_FieldDef* f, upb_Arena* a);
upb_FieldDef* f);
bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v,
upb_Status* status);
bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size,
upb_value* v);
const void* _upb_DefPool_Lookup2(const upb_DefPool* s, const char* sym,
size_t size, upb_deftype_t type);
void** _upb_DefPool_ScratchData(const upb_DefPool* s);
size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s);
bool _upb_DefPool_LookupAny2(const upb_DefPool* s, const char* sym, size_t size,
upb_value* v);
// For generated code only: loads a generated descriptor.
typedef struct _upb_DefPool_Init {
struct _upb_DefPool_Init** deps; // Dependencies of this file.
const upb_MiniTable_File* layout;
const char* filename;
upb_StringView descriptor; // Serialized descriptor.
} _upb_DefPool_Init;
const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable(
const upb_DefPool* s, const upb_MiniTable_Extension* ext);
bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init);
// Should only be directly called by tests. This variant lets us suppress
// the use of compiled-in tables, forcing a rebuild of the tables at runtime.
bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init,
bool rebuild_minitable);
bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init);
#ifdef __cplusplus
} /* extern "C" */
#endif

@ -85,27 +85,7 @@ bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a) {
return true;
}
static int cmp_values(const void* a, const void* b) {
const uint32_t A = upb_EnumValueDef_Number(*(const upb_EnumValueDef**)a);
const uint32_t B = upb_EnumValueDef_Number(*(const upb_EnumValueDef**)b);
return (A < B) ? -1 : (A > B);
}
bool _upb_EnumDef_MiniDescriptor(const upb_EnumDef* e, upb_Arena* a,
upb_StringView* out) {
if (e->is_sorted) return _upb_MiniDescriptor_EncodeEnum(e, NULL, a, out);
const upb_EnumValueDef** sorted = (const upb_EnumValueDef**)upb_Arena_Malloc(
a, e->value_count * sizeof(void*));
if (!sorted) return false;
for (size_t i = 0; i < e->value_count; i++) {
sorted[i] = upb_EnumDef_Value(e, i);
}
qsort(sorted, e->value_count, sizeof(void*), cmp_values);
return _upb_MiniDescriptor_EncodeEnum(e, sorted, a, out);
}
bool _upb_EnumDef_IsSorted(const upb_EnumDef* e) { return e->is_sorted; }
const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) {
return e->opts;
@ -168,7 +148,7 @@ const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) {
static upb_MiniTable_Enum* create_enumlayout(upb_DefBuilder* ctx,
const upb_EnumDef* e) {
upb_StringView sv;
bool ok = _upb_EnumDef_MiniDescriptor(e, ctx->tmp_arena, &sv);
bool ok = upb_MiniDescriptor_EncodeEnum(e, ctx->tmp_arena, &sv);
if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor");
upb_Status status;

@ -60,12 +60,9 @@ int upb_EnumDef_ValueCount(const upb_EnumDef* e);
upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i);
bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a);
bool _upb_EnumDef_IsSorted(const upb_EnumDef* e);
const upb_MiniTable_Enum* _upb_EnumDef_MiniTable(const upb_EnumDef* e);
// Builds a mini descriptor, returns false if OOM.
bool _upb_EnumDef_MiniDescriptor(const upb_EnumDef* e, upb_Arena* a,
upb_StringView* out);
// Allocate and initialize an array of |n| enum defs.
upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n,
const google_protobuf_EnumDescriptorProto* const* protos,

@ -46,6 +46,27 @@ upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) {
return (upb_EnumValueDef*)&v[i];
}
static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) {
const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number;
const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number;
return (v1 < v2) ? -1 : (v1 > v2);
}
const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v,
int n, upb_Arena* a) {
// TODO: Try to replace this arena alloc with a persistent scratch buffer.
upb_EnumValueDef** out =
(upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*));
if (!out) return NULL;
for (int i = 0; i < n; i++) {
out[i] = (upb_EnumValueDef*)&v[i];
}
qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare);
return (const upb_EnumValueDef**)out;
}
const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options(
const upb_EnumValueDef* v) {
return v->opts;

@ -58,6 +58,9 @@ upb_EnumValueDef* _upb_EnumValueDefs_New(
const google_protobuf_EnumValueDescriptorProto* const* protos, upb_EnumDef* e,
bool* is_sorted);
const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v,
int n, upb_Arena* a);
#ifdef __cplusplus
} /* extern "C" */
#endif

@ -39,6 +39,7 @@
#include "upb/reflection/extension_range.h"
#include "upb/reflection/file_def.h"
#include "upb/reflection/message_def.h"
#include "upb/reflection/mini_descriptor_encode.h"
#include "upb/reflection/oneof_def.h"
// Must be last.
@ -76,10 +77,10 @@ struct upb_FieldDef {
} sub;
uint32_t number_;
uint16_t index_;
uint16_t layout_index; /* Index into msgdef->layout->fields or file->exts */
uint16_t layout_index; // Index into msgdef->layout->fields or file->exts
bool has_default;
bool is_extension_;
bool packed_;
bool is_packed_;
bool proto3_optional_;
bool has_json_name_;
upb_FieldType type_;
@ -152,7 +153,7 @@ bool upb_FieldDef_IsExtension(const upb_FieldDef* f) {
return f->is_extension_;
}
bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->packed_; }
bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->is_packed_; }
const char* upb_FieldDef_Name(const upb_FieldDef* f) {
return _upb_DefBuilder_FullToShort(f->full_name);
@ -245,47 +246,30 @@ const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable(
return _upb_FileDef_ExtensionMiniTable(file, f->layout_index);
}
bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) {
return f->proto3_optional_;
}
bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) {
return upb_FieldDef_CType(f) == kUpb_CType_Message;
}
bool upb_FieldDef_IsString(const upb_FieldDef* f) {
return upb_FieldDef_CType(f) == kUpb_CType_String ||
upb_FieldDef_CType(f) == kUpb_CType_Bytes;
}
bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) {
if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false;
if (f->type_ != kUpb_FieldType_Enum) return false;
bool upb_FieldDef_IsOptional(const upb_FieldDef* f) {
return upb_FieldDef_Label(f) == kUpb_Label_Optional;
}
bool upb_FieldDef_IsRequired(const upb_FieldDef* f) {
return upb_FieldDef_Label(f) == kUpb_Label_Required;
}
// TODO(https://github.com/protocolbuffers/upb/issues/541):
// fix map enum values to check for unknown enum values and put
// them in the unknown field set.
if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) {
return false;
}
bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) {
return upb_FieldDef_Label(f) == kUpb_Label_Repeated;
// TODO: Maybe make is_proto2 a bool at creation?
const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef);
return upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2;
}
bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) {
return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f);
bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) {
return f->proto3_optional_;
}
bool upb_FieldDef_IsMap(const upb_FieldDef* f) {
return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) &&
upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f));
}
int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; }
bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; }
bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) {
return upb_FieldDef_IsSubMessage(f) ||
upb_FieldDef_CType(f) == kUpb_CType_Enum;
}
bool upb_FieldDef_HasPresence(const upb_FieldDef* f) {
if (upb_FieldDef_IsRepeated(f)) return false;
const upb_FileDef* file = upb_FieldDef_File(f);
@ -293,372 +277,51 @@ bool upb_FieldDef_HasPresence(const upb_FieldDef* f) {
upb_FileDef_Syntax(file) == kUpb_Syntax_Proto2;
}
static bool between(int32_t x, int32_t low, int32_t high) {
return x >= low && x <= high;
bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) {
return upb_FieldDef_IsSubMessage(f) ||
upb_FieldDef_CType(f) == kUpb_CType_Enum;
}
bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); }
bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); }
bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); }
bool upb_FieldDef_checkdescriptortype(int32_t type) {
return between(type, 1, 18);
bool upb_FieldDef_IsMap(const upb_FieldDef* f) {
return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) &&
upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f));
}
/* Code to build defs from descriptor protos. *********************************/
/* There is a question of how much validation to do here. It will be difficult
* to perfectly match the amount of validation performed by proto2. But since
* this code is used to directly build defs from Ruby (for example) we do need
* to validate important constraints like uniqueness of names and numbers. */
static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; }
static size_t upb_MessageValue_sizeof(upb_CType type) {
switch (type) {
case kUpb_CType_Double:
case kUpb_CType_Int64:
case kUpb_CType_UInt64:
return 8;
case kUpb_CType_Enum:
case kUpb_CType_Int32:
case kUpb_CType_UInt32:
case kUpb_CType_Float:
return 4;
case kUpb_CType_Bool:
return 1;
case kUpb_CType_Message:
return sizeof(void*);
case kUpb_CType_Bytes:
case kUpb_CType_String:
return sizeof(upb_StringView);
}
UPB_UNREACHABLE();
bool upb_FieldDef_IsOptional(const upb_FieldDef* f) {
return upb_FieldDef_Label(f) == kUpb_Label_Optional;
}
static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) {
if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) {
upb_MapEntry ent;
UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v));
return sizeof(ent.k);
} else if (upb_FieldDef_IsRepeated(f)) {
return sizeof(void*);
} else {
return upb_MessageValue_sizeof(upb_FieldDef_CType(f));
}
bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) {
return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f);
}
static uint32_t upb_MiniTable_place(upb_DefBuilder* ctx, upb_MiniTable* l,
size_t size, const upb_MessageDef* m) {
size_t ofs = UPB_ALIGN_UP(l->size, size);
size_t next = ofs + size;
if (next > UINT16_MAX) {
_upb_DefBuilder_Errf(ctx,
"size of message %s exceeded max size of %zu bytes",
upb_MessageDef_FullName(m), (size_t)UINT16_MAX);
}
l->size = next;
return ofs;
bool upb_FieldDef_IsRequired(const upb_FieldDef* f) {
return upb_FieldDef_Label(f) == kUpb_Label_Required;
}
static int field_number_cmp(const void* p1, const void* p2) {
const upb_MiniTable_Field* f1 = p1;
const upb_MiniTable_Field* f2 = p2;
return f1->number - f2->number;
bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) {
return upb_FieldDef_Label(f) == kUpb_Label_Repeated;
}
static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l,
upb_MiniTable_Field* fields) {
int i;
int n = upb_MessageDef_FieldCount(m);
int dense_below = 0;
for (i = 0; i < n; i++) {
upb_FieldDef* f =
(upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number);
UPB_ASSERT(f);
f->layout_index = i;
if (i < UINT8_MAX && fields[i].number == i + 1 &&
(i == 0 || fields[i - 1].number == i)) {
dense_below = i + 1;
}
}
l->dense_below = dense_below;
bool upb_FieldDef_IsString(const upb_FieldDef* f) {
return upb_FieldDef_CType(f) == kUpb_CType_String ||
upb_FieldDef_CType(f) == kUpb_CType_Bytes;
}
static uint8_t map_descriptortype(const upb_FieldDef* f) {
uint8_t type = upb_FieldDef_Type(f);
/* See TableDescriptorType() in upbc/generator.cc for details and
* rationale of these exceptions. */
if (type == kUpb_FieldType_String) {
const upb_FileDef* file = upb_FieldDef_File(f);
const upb_Syntax syntax = upb_FileDef_Syntax(file);
if (syntax == kUpb_Syntax_Proto2) return kUpb_FieldType_Bytes;
} else if (type == kUpb_FieldType_Enum) {
const upb_FileDef* file = upb_EnumDef_File(f->sub.enumdef);
const upb_Syntax syntax = upb_FileDef_Syntax(file);
if (syntax == kUpb_Syntax_Proto3 || UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 ||
// TODO(https://github.com/protocolbuffers/upb/issues/541):
// fix map enum values to check for unknown enum values and put
// them in the unknown field set.
upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) {
return kUpb_FieldType_Int32;
}
}
return type;
bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) {
return upb_FieldDef_CType(f) == kUpb_CType_Message;
}
static void fill_fieldlayout(upb_MiniTable_Field* field,
const upb_FieldDef* f) {
field->number = upb_FieldDef_Number(f);
field->descriptortype = map_descriptortype(f);
if (upb_FieldDef_IsMap(f)) {
field->mode =
kUpb_FieldMode_Map | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift);
} else if (upb_FieldDef_IsRepeated(f)) {
field->mode =
kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift);
} else {
/* Maps descriptor type -> elem_size_lg2. */
static const uint8_t sizes[] = {
-1, /* invalid descriptor type */
kUpb_FieldRep_8Byte, /* DOUBLE */
kUpb_FieldRep_4Byte, /* FLOAT */
kUpb_FieldRep_8Byte, /* INT64 */
kUpb_FieldRep_8Byte, /* UINT64 */
kUpb_FieldRep_4Byte, /* INT32 */
kUpb_FieldRep_8Byte, /* FIXED64 */
kUpb_FieldRep_4Byte, /* FIXED32 */
kUpb_FieldRep_1Byte, /* BOOL */
kUpb_FieldRep_StringView, /* STRING */
kUpb_FieldRep_Pointer, /* GROUP */
kUpb_FieldRep_Pointer, /* MESSAGE */
kUpb_FieldRep_StringView, /* BYTES */
kUpb_FieldRep_4Byte, /* UINT32 */
kUpb_FieldRep_4Byte, /* ENUM */
kUpb_FieldRep_4Byte, /* SFIXED32 */
kUpb_FieldRep_8Byte, /* SFIXED64 */
kUpb_FieldRep_4Byte, /* SINT32 */
kUpb_FieldRep_8Byte, /* SINT64 */
};
field->mode = kUpb_FieldMode_Scalar |
(sizes[field->descriptortype] << kUpb_FieldRep_Shift);
}
if (upb_FieldDef_IsPacked(f)) {
field->mode |= kUpb_LabelFlags_IsPacked;
}
if (upb_FieldDef_IsExtension(f)) {
field->mode |= kUpb_LabelFlags_IsExtension;
}
static bool between(int32_t x, int32_t low, int32_t high) {
return x >= low && x <= high;
}
/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc.
* It computes a dynamic layout for all of the fields in |m|. */
void _upb_FieldDef_MakeLayout(upb_DefBuilder* ctx, const upb_MessageDef* m) {
upb_MiniTable* l = (upb_MiniTable*)upb_MessageDef_MiniTable(m);
size_t field_count = upb_MessageDef_FieldCount(m);
size_t sublayout_count = 0;
upb_MiniTable_Sub* subs;
upb_MiniTable_Field* fields;
memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry));
// Count sub-messages.
for (size_t i = 0; i < field_count; i++) {
const upb_FieldDef* f = upb_MessageDef_Field(m, i);
if (upb_FieldDef_IsSubMessage(f)) {
sublayout_count++;
}
if (upb_FieldDef_CType(f) == kUpb_CType_Enum &&
upb_FileDef_Syntax(upb_EnumDef_File(f->sub.enumdef)) ==
kUpb_Syntax_Proto2) {
sublayout_count++;
}
}
fields = _upb_DefBuilder_Alloc(ctx, field_count * sizeof(*fields));
subs = _upb_DefBuilder_Alloc(ctx, sublayout_count * sizeof(*subs));
l->field_count = upb_MessageDef_FieldCount(m);
l->fields = fields;
l->subs = subs;
l->table_mask = 0;
l->required_count = 0;
if (upb_MessageDef_ExtensionRangeCount(m) > 0) {
if (google_protobuf_MessageOptions_message_set_wire_format(
upb_MessageDef_Options(m))) {
l->ext = kUpb_ExtMode_IsMessageSet;
} else {
l->ext = kUpb_ExtMode_Extendable;
}
} else {
l->ext = kUpb_ExtMode_NonExtendable;
}
/* TODO(haberman): initialize fast tables so that reflection-based parsing
* can get the same speeds as linked-in types. */
l->fasttable[0].field_parser = &_upb_FastDecoder_DecodeGeneric;
l->fasttable[0].field_data = 0;
if (upb_MessageDef_IsMapEntry(m)) {
/* TODO(haberman): refactor this method so this special case is more
* elegant. */
const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1);
const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2);
fields[0].number = 1;
fields[1].number = 2;
fields[0].mode = kUpb_FieldMode_Scalar;
fields[1].mode = kUpb_FieldMode_Scalar;
fields[0].presence = 0;
fields[1].presence = 0;
fields[0].descriptortype = map_descriptortype(key);
fields[1].descriptortype = map_descriptortype(val);
fields[0].offset = 0;
fields[1].offset = sizeof(upb_StringView);
fields[1].submsg_index = 0;
if (upb_FieldDef_CType(val) == kUpb_CType_Message) {
subs[0].submsg =
upb_MessageDef_MiniTable(upb_FieldDef_MessageSubDef(val));
}
upb_FieldDef* fielddefs = (upb_FieldDef*)upb_MessageDef_Field(m, 0);
UPB_ASSERT(fielddefs[0].number_ == 1);
UPB_ASSERT(fielddefs[1].number_ == 2);
fielddefs[0].layout_index = 0;
fielddefs[1].layout_index = 1;
l->field_count = 2;
l->size = 2 * sizeof(upb_StringView);
l->size = UPB_ALIGN_UP(l->size, 8);
l->dense_below = 2;
return;
}
/* Allocate data offsets in three stages:
*
* 1. hasbits.
* 2. regular fields.
* 3. oneof fields.
*
* OPT: There is a lot of room for optimization here to minimize the size.
*/
/* Assign hasbits for required fields first. */
size_t hasbit = 0;
for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) {
const upb_FieldDef* f = upb_MessageDef_Field(m, i);
upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)];
if (upb_FieldDef_Label(f) == kUpb_Label_Required) {
field->presence = ++hasbit;
if (hasbit >= 63) {
_upb_DefBuilder_Errf(ctx, "Message with >=63 required fields: %s",
upb_MessageDef_FullName(m));
}
l->required_count++;
}
}
/* Allocate hasbits and set basic field attributes. */
sublayout_count = 0;
for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) {
const upb_FieldDef* f = upb_MessageDef_Field(m, i);
upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)];
fill_fieldlayout(field, f);
if (field->descriptortype == kUpb_FieldType_Message ||
field->descriptortype == kUpb_FieldType_Group) {
field->submsg_index = sublayout_count++;
subs[field->submsg_index].submsg =
upb_MessageDef_MiniTable(upb_FieldDef_MessageSubDef(f));
} else if (field->descriptortype == kUpb_FieldType_Enum) {
field->submsg_index = sublayout_count++;
subs[field->submsg_index].subenum =
_upb_EnumDef_MiniTable(upb_FieldDef_EnumSubDef(f));
UPB_ASSERT(subs[field->submsg_index].subenum);
}
if (upb_FieldDef_Label(f) == kUpb_Label_Required) {
/* Hasbit was already assigned. */
} else if (upb_FieldDef_HasPresence(f) &&
!upb_FieldDef_RealContainingOneof(f)) {
/* We don't use hasbit 0, so that 0 can indicate "no presence" in the
* table. This wastes one hasbit, but we don't worry about it for now. */
field->presence = ++hasbit;
} else {
field->presence = 0;
}
}
/* Account for space used by hasbits. */
l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0;
/* Allocate non-oneof fields. */
for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) {
const upb_FieldDef* f = upb_MessageDef_Field(m, i);
size_t field_size = upb_msg_fielddefsize(f);
size_t index = upb_FieldDef_Index(f);
if (upb_FieldDef_RealContainingOneof(f)) {
/* Oneofs are handled separately below. */
continue;
}
fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m);
}
/* Allocate oneof fields. Each oneof field consists of a uint32 for the case
* and space for the actual data. */
for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) {
const upb_OneofDef* o = upb_MessageDef_Oneof(m, i);
size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */
size_t field_size = 0;
uint32_t case_offset;
uint32_t data_offset;
if (upb_OneofDef_IsSynthetic(o)) continue;
if (upb_OneofDef_FieldCount(o) == 0) {
_upb_DefBuilder_Errf(ctx, "Oneof must have at least one field (%s)",
upb_OneofDef_FullName(o));
}
/* Calculate field size: the max of all field sizes. */
for (int j = 0; j < upb_OneofDef_FieldCount(o); j++) {
const upb_FieldDef* f = upb_OneofDef_Field(o, j);
field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f));
}
/* Align and allocate case offset. */
case_offset = upb_MiniTable_place(ctx, l, case_size, m);
data_offset = upb_MiniTable_place(ctx, l, field_size, m);
for (int i = 0; i < upb_OneofDef_FieldCount(o); i++) {
const upb_FieldDef* f = upb_OneofDef_Field(o, i);
fields[upb_FieldDef_Index(f)].offset = data_offset;
fields[upb_FieldDef_Index(f)].presence = ~case_offset;
}
}
/* Size of the entire structure should be a multiple of its greatest
* alignment. TODO: track overall alignment for real? */
l->size = UPB_ALIGN_UP(l->size, 8);
bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); }
bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); }
bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); }
/* Sort fields by number. */
if (fields) {
qsort(fields, upb_MessageDef_FieldCount(m), sizeof(*fields),
field_number_cmp);
}
assign_layout_indices(m, l, fields);
bool upb_FieldDef_checkdescriptortype(int32_t type) {
return between(type, 1, 18);
}
static bool streql2(const char* a, size_t n, const char* b) {
@ -861,9 +524,8 @@ static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f) {
}
static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix,
upb_MessageDef* m,
const google_protobuf_FieldDescriptorProto* field_proto,
upb_FieldDef* f) {
upb_MessageDef* m, upb_FieldDef* f) {
// Must happen before _upb_DefBuilder_Add()
f->file = _upb_DefBuilder_File(ctx);
@ -950,7 +612,7 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix,
}
if (!m) {
_upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)",
_upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg",
f->full_name);
}
@ -963,23 +625,21 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix,
bool ok = _upb_OneofDef_Insert(oneof, f, name.data, name.size, ctx->arena);
if (!ok) _upb_DefBuilder_OomErr(ctx);
} else {
if (f->proto3_optional_) {
_upb_DefBuilder_Errf(ctx,
"field with proto3_optional was not in a oneof (%s)",
f->full_name);
}
} else if (f->proto3_optional_) {
_upb_DefBuilder_Errf(ctx,
"field with proto3_optional was not in a oneof (%s)",
f->full_name);
}
UBP_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto);
if (google_protobuf_FieldOptions_has_packed(f->opts)) {
f->packed_ = google_protobuf_FieldOptions_packed(f->opts);
f->is_packed_ = google_protobuf_FieldOptions_packed(f->opts);
} else {
// Repeated fields default to packed for proto3 only.
f->packed_ = upb_FieldDef_IsPrimitive(f) &&
f->label_ == kUpb_Label_Repeated &&
upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3;
f->is_packed_ = upb_FieldDef_IsPrimitive(f) &&
f->label_ == kUpb_Label_Repeated &&
upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3;
}
}
@ -987,9 +647,14 @@ static void _upb_FieldDef_CreateExt(
upb_DefBuilder* ctx, const char* prefix,
const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m,
upb_FieldDef* f) {
_upb_FieldDef_Create(ctx, prefix, m, field_proto, f);
_upb_FieldDef_Create(ctx, prefix, field_proto, m, f);
f->is_extension_ = true;
if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) {
_upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)",
f->full_name);
}
f->scope.extension_scope = m;
_upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT));
f->layout_index = ctx->ext_count++;
@ -1003,47 +668,58 @@ static void _upb_FieldDef_CreateNotExt(
upb_DefBuilder* ctx, const char* prefix,
const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m,
upb_FieldDef* f) {
_upb_FieldDef_Create(ctx, prefix, m, field_proto, f);
_upb_FieldDef_Create(ctx, prefix, field_proto, m, f);
f->is_extension_ = false;
_upb_MessageDef_InsertField(ctx, m, f);
if (ctx->layout) {
const upb_MiniTable* mt = upb_MessageDef_MiniTable(m);
const upb_MiniTable_Field* fields = mt->fields;
const int count = mt->field_count;
bool found = false;
for (int i = 0; i < count; i++) {
if (fields[i].number == f->number_) {
f->layout_index = i;
found = true;
break;
}
if (!ctx->layout) return;
const upb_MiniTable* mt = upb_MessageDef_MiniTable(m);
const upb_MiniTable_Field* fields = mt->fields;
for (int i = 0; i < mt->field_count; i++) {
if (fields[i].number == f->number_) {
f->layout_index = i;
return;
}
UPB_ASSERT(found);
}
UPB_ASSERT(false); // It should be impossible to reach this point.
}
upb_FieldDef* _upb_FieldDefs_New(
upb_DefBuilder* ctx, int n,
const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix,
upb_MessageDef* m, bool is_ext) {
upb_MessageDef* m, bool* is_sorted) {
_upb_DefType_CheckPadding(sizeof(upb_FieldDef));
upb_FieldDef* f =
upb_FieldDef* defs =
(upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n);
if (is_ext) {
for (size_t i = 0; i < n; i++) {
_upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, &f[i]);
f[i].index_ = i;
// If we are creating extensions then is_sorted will be NULL.
// If we are not creating extensions then is_sorted will be non-NULL.
if (is_sorted) {
uint32_t previous = 0;
for (int i = 0; i < n; i++) {
upb_FieldDef* f = &defs[i];
_upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f);
f->index_ = i;
if (!ctx->layout) f->layout_index = i;
const uint32_t current = f->number_;
if (previous > current) *is_sorted = false;
previous = current;
}
} else {
for (size_t i = 0; i < n; i++) {
_upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, &f[i]);
f[i].index_ = i;
for (int i = 0; i < n; i++) {
upb_FieldDef* f = &defs[i];
_upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f);
f->index_ = i;
}
}
return f;
return defs;
}
static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix,
@ -1092,6 +768,29 @@ static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix,
}
}
static int _upb_FieldDef_Compare(const void* p1, const void* p2) {
const uint32_t v1 = (*(upb_FieldDef**)p1)->number_;
const uint32_t v2 = (*(upb_FieldDef**)p2)->number_;
return (v1 < v2) ? -1 : (v1 > v2);
}
const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n,
upb_Arena* a) {
// TODO: Try to replace this arena alloc with a persistent scratch buffer.
upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*));
if (!out) return NULL;
for (int i = 0; i < n; i++) {
out[i] = (upb_FieldDef*)&f[i];
}
qsort(out, n, sizeof(void*), _upb_FieldDef_Compare);
for (int i = 0; i < n; i++) {
out[i]->layout_index = i;
}
return (const upb_FieldDef**)out;
}
static void resolve_extension(upb_DefBuilder* ctx, const char* prefix,
upb_FieldDef* f,
const google_protobuf_FieldDescriptorProto* field_proto) {
@ -1105,39 +804,42 @@ static void resolve_extension(upb_DefBuilder* ctx, const char* prefix,
_upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG);
f->msgdef = m;
bool found = false;
for (int i = 0, n = upb_MessageDef_ExtensionRangeCount(m); i < n; i++) {
const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i);
if (upb_ExtensionRange_Start(r) <= f->number_ &&
f->number_ < upb_ExtensionRange_End(r)) {
found = true;
break;
}
}
if (!found) {
if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) {
_upb_DefBuilder_Errf(
ctx,
"field number %u in extension %s has no extension range in "
"message %s",
(unsigned)f->number_, f->full_name, upb_MessageDef_FullName(f->msgdef));
"field number %u in extension %s has no extension range in message %s",
(unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m));
}
const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f);
if (ctx->layout) {
UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number);
} else {
upb_StringView desc;
if (!upb_MiniDescriptor_EncodeField(f, ctx->tmp_arena, &desc)) {
_upb_DefBuilder_OomErr(ctx);
}
upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext;
fill_fieldlayout(&mut_ext->field, f);
mut_ext->field.presence = 0;
mut_ext->field.offset = 0;
mut_ext->field.submsg_index = 0;
mut_ext->extendee = upb_MessageDef_MiniTable(f->msgdef);
mut_ext->sub.submsg = upb_MessageDef_MiniTable(f->sub.msgdef);
upb_MiniTable_Sub sub;
sub.submsg = NULL;
sub.subenum = NULL;
bool ok2 = upb_MiniTable_BuildExtension(desc.data, desc.size, mut_ext,
upb_MessageDef_MiniTable(m), sub,
ctx->status);
if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table");
assert(mut_ext->field.number == f->number_);
mut_ext->extendee = upb_MessageDef_MiniTable(m);
if (upb_FieldDef_IsSubMessage(f)) {
mut_ext->sub.submsg = upb_MessageDef_MiniTable(f->sub.msgdef);
} else if (mut_ext->field.descriptortype == kUpb_FieldType_Enum) {
mut_ext->sub.subenum = _upb_EnumDef_MiniTable(f->sub.enumdef);
}
}
bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f, ctx->arena);
bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f);
if (!ok) _upb_DefBuilder_OomErr(ctx);
}

@ -78,20 +78,28 @@ upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f);
// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE /////////////////////////
upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i);
const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable(
const upb_FieldDef* f);
bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f);
bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f);
int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f);
void _upb_FieldDef_MakeLayout(upb_DefBuilder* ctx, const upb_MessageDef* m);
void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix,
upb_FieldDef* f);
// Allocate and initialize an array of |n| field defs.
upb_FieldDef* _upb_FieldDefs_New(
upb_DefBuilder* ctx, int n,
const google_protobuf_FieldDescriptorProto* const* protos, const char* prefix,
upb_MessageDef* m, bool is_ext);
upb_MessageDef* m, bool* is_sorted);
void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix,
upb_FieldDef* f);
void _upb_FieldDef_MakeLayout(upb_DefBuilder* ctx, const upb_MessageDef* m);
// Allocate and return a list of pointers to the |n| field defs in |ff|,
// sorted by field number.
const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n,
upb_Arena* a);
#ifdef __cplusplus
} /* extern "C" */

@ -192,7 +192,7 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx,
const upb_StringView* strs;
const int32_t* public_deps;
const int32_t* weak_deps;
size_t i, n;
size_t n;
file->symtab = ctx->symtab;
@ -261,7 +261,7 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx,
file->dep_count = n;
file->deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->deps) * n);
for (i = 0; i < n; i++) {
for (size_t i = 0; i < n; i++) {
upb_StringView str = strs[i];
file->deps[i] =
upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size);
@ -278,7 +278,7 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx,
file->public_deps =
_upb_DefBuilder_Alloc(ctx, sizeof(*file->public_deps) * n);
int32_t* mutable_public_deps = (int32_t*)file->public_deps;
for (i = 0; i < n; i++) {
for (size_t i = 0; i < n; i++) {
if (public_deps[i] >= file->dep_count) {
_upb_DefBuilder_Errf(ctx, "public_dep %d is out of range",
(int)public_deps[i]);
@ -290,7 +290,7 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx,
file->weak_dep_count = n;
file->weak_deps = _upb_DefBuilder_Alloc(ctx, sizeof(*file->weak_deps) * n);
int32_t* mutable_weak_deps = (int32_t*)file->weak_deps;
for (i = 0; i < n; i++) {
for (size_t i = 0; i < n; i++) {
if (weak_deps[i] >= file->dep_count) {
_upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range",
(int)weak_deps[i]);
@ -307,7 +307,7 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx,
exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n);
file->top_lvl_ext_count = n;
file->top_lvl_exts =
_upb_FieldDefs_New(ctx, n, exts, file->package, NULL, true);
_upb_FieldDefs_New(ctx, n, exts, file->package, NULL, NULL);
// Create messages.
msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n);
@ -320,17 +320,24 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx,
file->services = _upb_ServiceDefs_New(ctx, n, services);
// Now that all names are in the table, build layouts and resolve refs.
for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) {
_upb_FieldDef_Resolve(
ctx, file->package,
(upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i));
}
for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) {
for (int i = 0; i < file->top_lvl_msg_count; i++) {
upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i);
_upb_MessageDef_Resolve(ctx, m);
}
for (int i = 0; i < file->top_lvl_ext_count; i++) {
upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i);
_upb_FieldDef_Resolve(ctx, file->package, f);
}
if (!ctx->layout) {
for (int i = 0; i < file->top_lvl_msg_count; i++) {
upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i);
_upb_MessageDef_LinkMiniTable(ctx, m);
}
}
if (file->ext_count) {
bool ok = _upb_extreg_add(_upb_DefPool_ExtReg(ctx->symtab),
file->ext_layouts, file->ext_count);

@ -34,6 +34,7 @@
#include "upb/reflection/extension_range.h"
#include "upb/reflection/field_def.h"
#include "upb/reflection/file_def.h"
#include "upb/reflection/mini_descriptor_encode.h"
#include "upb/reflection/oneof_def.h"
// Must be last.
@ -67,6 +68,7 @@ struct upb_MessageDef {
int nested_enum_count;
int nested_ext_count;
bool in_message_set;
bool is_sorted;
upb_WellKnown well_known_type;
#if UINTPTR_MAX == 0xffffffff
uint32_t padding; // Increase size to a multiple of 8.
@ -120,6 +122,18 @@ upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) {
return (upb_MessageDef*)&m[i];
}
bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) {
for (int i = 0; i < m->ext_range_count; i++) {
const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i);
if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) {
return true;
}
}
return false;
}
bool _upb_MessageDef_IsSorted(const upb_MessageDef* m) { return m->is_sorted; }
const google_protobuf_MessageOptions* upb_MessageDef_Options(
const upb_MessageDef* m) {
return m->opts;
@ -215,14 +229,6 @@ const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize(
return f;
}
int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; }
int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; }
int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) {
return m->real_oneof_count;
}
int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) {
return m->ext_range_count;
}
@ -247,10 +253,6 @@ int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) {
return m->nested_ext_count;
}
int upb_MessageDef_realoneofcount(const upb_MessageDef* m) {
return m->real_oneof_count;
}
const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) {
return m->layout;
}
@ -315,12 +317,56 @@ bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) {
upb_MessageDef_Options(m));
}
static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx,
const upb_MessageDef* m) {
if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) {
return upb_MiniTable_BuildMessageSet(kUpb_MiniTablePlatform_Native,
ctx->arena);
}
if (upb_MessageDef_IsMapEntry(m)) {
if (m->field_count != 2) {
_upb_DefBuilder_Errf(ctx, "invalid map (%s)", m->full_name);
}
const upb_FieldDef* f0 = upb_MessageDef_Field(m, 0);
const upb_FieldDef* f1 = upb_MessageDef_Field(m, 1);
const upb_FieldType t0 = upb_FieldDef_Type(f0);
const upb_FieldType t1 = upb_FieldDef_Type(f1);
const bool is_proto3_enum =
(t1 == kUpb_FieldType_Enum) && !_upb_FieldDef_IsClosedEnum(f1);
UPB_ASSERT(_upb_FieldDef_LayoutIndex(f0) == 0);
UPB_ASSERT(_upb_FieldDef_LayoutIndex(f1) == 1);
return upb_MiniTable_BuildMapEntry(
t0, t1, is_proto3_enum, kUpb_MiniTablePlatform_Native, ctx->arena);
}
upb_StringView desc;
bool ok = upb_MiniDescriptor_EncodeMessage(m, ctx->tmp_arena, &desc);
if (!ok) _upb_DefBuilder_OomErr(ctx);
void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab);
size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab);
upb_MiniTable* ret = upb_MiniTable_BuildWithBuf(
desc.data, desc.size, kUpb_MiniTablePlatform_Native, ctx->arena,
scratch_data, scratch_size, ctx->status);
if (!ret) _upb_DefBuilder_FailJmp(ctx);
return ret;
}
void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) {
for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) {
for (int i = 0; i < m->field_count; i++) {
upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i);
_upb_FieldDef_Resolve(ctx, upb_MessageDef_FullName(m), f);
}
if (!ctx->layout) {
m->layout = _upb_MessageDef_MakeMiniTable(ctx, m);
if (!m->layout) _upb_DefBuilder_OomErr(ctx);
}
m->in_message_set = false;
for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) {
upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i);
@ -334,8 +380,6 @@ void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) {
}
}
if (!ctx->layout) _upb_FieldDef_MakeLayout(ctx, m);
for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) {
upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i);
_upb_MessageDef_Resolve(ctx, n);
@ -385,42 +429,50 @@ void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m,
if (!ok) _upb_DefBuilder_OomErr(ctx);
}
static void msgdef_create_nested(upb_DefBuilder* ctx,
const google_protobuf_DescriptorProto* msg_proto,
upb_MessageDef* m) {
size_t n;
const google_protobuf_EnumDescriptorProto* const* enums =
google_protobuf_DescriptorProto_enum_type(msg_proto, &n);
m->nested_enum_count = n;
m->nested_enums = _upb_EnumDefs_New(ctx, n, enums, m);
const google_protobuf_FieldDescriptorProto* const* exts =
google_protobuf_DescriptorProto_extension(msg_proto, &n);
m->nested_ext_count = n;
m->nested_exts = _upb_FieldDefs_New(ctx, n, exts, m->full_name, m, true);
void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx,
const upb_MessageDef* m) {
for (int i = 0; i < m->field_count; i++) {
const upb_FieldDef* f = upb_MessageDef_Field(m, i);
const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f);
const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f);
const int layout_index = _upb_FieldDef_LayoutIndex(f);
upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m);
UPB_ASSERT(layout_index < m->field_count);
upb_MiniTable_Field* mt_f =
(upb_MiniTable_Field*)&m->layout->fields[layout_index];
if (sub_m) {
if (!mt->subs) {
_upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name);
}
UPB_ASSERT(mt_f);
UPB_ASSERT(sub_m->layout);
upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout);
} else if (_upb_FieldDef_IsClosedEnum(f)) {
upb_MiniTable_SetSubEnum(mt, mt_f, _upb_EnumDef_MiniTable(sub_e));
}
}
const google_protobuf_DescriptorProto* const* msgs =
google_protobuf_DescriptorProto_nested_type(msg_proto, &n);
m->nested_msg_count = n;
m->nested_msgs = _upb_MessageDefs_New(ctx, n, msgs, m);
for (int i = 0; i < m->nested_msg_count; i++) {
_upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i));
}
}
static void create_msgdef(upb_DefBuilder* ctx, const char* prefix,
const google_protobuf_DescriptorProto* msg_proto,
const upb_MessageDef* containing_type,
const upb_MessageDef* _m) {
upb_MessageDef* m = (upb_MessageDef*)_m;
upb_MessageDef* m) {
const google_protobuf_OneofDescriptorProto* const* oneofs;
const google_protobuf_FieldDescriptorProto* const* fields;
const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges;
size_t n_oneof, n_field, n_ext_range;
size_t n_oneof, n_field, n_ext_range, n_enum, n_ext, n_msg;
upb_StringView name;
// Must happen before _upb_DefBuilder_Add()
m->file = _upb_DefBuilder_File(ctx);
m->containing_type = containing_type;
m->is_sorted = true;
name = google_protobuf_DescriptorProto_name(msg_proto);
_upb_DefBuilder_CheckIdentNotFull(ctx, name);
@ -430,8 +482,7 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix,
oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof);
fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field);
ext_ranges =
google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range);
ext_ranges = google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range);
bool ok = upb_inttable_init(&m->itof, ctx->arena);
if (!ok) _upb_DefBuilder_OomErr(ctx);
@ -456,7 +507,8 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix,
m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m);
m->field_count = n_field;
m->fields = _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, false);
m->fields =
_upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted);
m->ext_range_count = n_ext_range;
m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m);
@ -466,7 +518,21 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix,
assign_msg_wellknowntype(m);
upb_inttable_compact(&m->itof, ctx->arena);
msgdef_create_nested(ctx, msg_proto, m);
const google_protobuf_EnumDescriptorProto* const* enums =
google_protobuf_DescriptorProto_enum_type(msg_proto, &n_enum);
m->nested_enum_count = n_enum;
m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m);
const google_protobuf_FieldDescriptorProto* const* exts =
google_protobuf_DescriptorProto_extension(msg_proto, &n_ext);
m->nested_ext_count = n_ext;
m->nested_exts = _upb_FieldDefs_New(ctx, n_ext, exts, m->full_name, m, NULL);
const google_protobuf_DescriptorProto* const* msgs =
google_protobuf_DescriptorProto_nested_type(msg_proto, &n_msg);
m->nested_msg_count = n_msg;
m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m);
}
// Allocate and initialize an array of |n| message defs.
@ -477,6 +543,7 @@ upb_MessageDef* _upb_MessageDefs_New(
const char* name = containing_type ? containing_type->full_name
: _upb_FileDef_RawPackage(ctx->file);
upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n);
for (int i = 0; i < n; i++) {
create_msgdef(ctx, name, protos[i], containing_type, &m[i]);

@ -157,6 +157,10 @@ bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t size,
upb_value v, upb_Arena* a);
void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m,
const upb_FieldDef* f);
bool _upb_MessageDef_IsSorted(const upb_MessageDef* m);
bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n);
void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx,
const upb_MessageDef* m);
void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m);
// Allocate and initialize an array of |n| message defs.

@ -121,21 +121,18 @@ static uint64_t upb_Message_Modifiers(const upb_MessageDef* m) {
/******************************************************************************/
// Sort by field number.
static int upb_MiniDescriptor_CompareFields(const void* a, const void* b) {
const upb_FieldDef* A = *(void**)a;
const upb_FieldDef* B = *(void**)b;
if (upb_FieldDef_Number(A) < upb_FieldDef_Number(B)) return -1;
if (upb_FieldDef_Number(A) > upb_FieldDef_Number(B)) return 1;
return 0;
}
bool _upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e,
const upb_EnumValueDef** sorted,
upb_Arena* a, upb_StringView* out) {
bool upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e, upb_Arena* a,
upb_StringView* out) {
DescState s;
upb_DescState_Init(&s);
const upb_EnumValueDef** sorted = NULL;
if (!_upb_EnumDef_IsSorted(e)) {
sorted = _upb_EnumValueDefs_Sorted(upb_EnumDef_Value(e, 0),
upb_EnumDef_ValueCount(e), a);
if (!sorted) return false;
}
upb_MtDataEncoder_StartEnum(&s.e);
// Duplicate values are allowed but we only encode each value once.
@ -165,8 +162,8 @@ bool _upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e,
return true;
}
bool _upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, upb_Arena* a,
upb_StringView* out) {
bool upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, upb_Arena* a,
upb_StringView* out) {
UPB_ASSERT(upb_FieldDef_IsExtension(f));
DescState s;
@ -190,28 +187,27 @@ bool _upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, upb_Arena* a,
return true;
}
bool _upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, upb_Arena* a,
upb_StringView* out) {
// If the field numbers happen to be defined in ascending order then |sorted|
// should be NULL. Otherwise it must point to an array containing pointers to
// the field defs in sorted order.
bool upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, upb_Arena* a,
upb_StringView* out) {
DescState s;
upb_DescState_Init(&s);
// Make a copy.
const size_t field_count = upb_MessageDef_FieldCount(m);
const upb_FieldDef** sorted =
(const upb_FieldDef**)upb_Arena_Malloc(a, field_count * sizeof(void*));
if (!sorted) return false;
// Sort the copy.
for (size_t i = 0; i < field_count; i++) {
sorted[i] = upb_MessageDef_Field(m, i);
const upb_FieldDef** sorted = NULL;
if (!_upb_MessageDef_IsSorted(m)) {
sorted = _upb_FieldDefs_Sorted(upb_MessageDef_Field(m, 0),
upb_MessageDef_FieldCount(m), a);
if (!sorted) return false;
}
qsort(sorted, field_count, sizeof(void*), upb_MiniDescriptor_CompareFields);
if (!upb_DescState_Grow(&s, a)) return false;
s.ptr = upb_MtDataEncoder_StartMessage(&s.e, s.ptr, upb_Message_Modifiers(m));
for (size_t i = 0; i < field_count; i++) {
const upb_FieldDef* f = sorted[i];
const int field_count = upb_MessageDef_FieldCount(m);
for (int i = 0; i < field_count; i++) {
const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i);
const upb_FieldType type = upb_FieldDef_Type(f);
const int number = upb_FieldDef_Number(f);
const uint64_t modifiers = upb_Field_Modifiers(f);
@ -242,20 +238,3 @@ bool _upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, upb_Arena* a,
out->size = s.ptr - s.buf;
return true;
}
/******************************************************************************/
bool upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e, upb_Arena* a,
upb_StringView* out) {
return _upb_EnumDef_MiniDescriptor(e, a, out);
}
bool upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, upb_Arena* a,
upb_StringView* out) {
return _upb_MiniDescriptor_EncodeField(f, a, out);
}
bool upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, upb_Arena* a,
upb_StringView* out) {
return _upb_MiniDescriptor_EncodeMessage(m, a, out);
}

@ -50,19 +50,6 @@ bool upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, upb_Arena* a,
bool upb_MiniDescriptor_EncodeMessage(const upb_MessageDef* m, upb_Arena* a,
upb_StringView* out);
// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE /////////////////////////
// Creates and returns a mini descriptor string for an enum, or NULL on error.
// If the values in the enum happen to be defined in ascending order (when cast
// to uint32_t) then |sorted| should be NULL. Otherwise it must point to an
// array containing pointers to the enum value defs in sorted order.
bool _upb_MiniDescriptor_EncodeEnum(const upb_EnumDef* e,
const upb_EnumValueDef** sorted,
upb_Arena* a, upb_StringView* out);
bool _upb_MiniDescriptor_EncodeField(const upb_FieldDef* f, upb_Arena* a,
upb_StringView* out);
#ifdef __cplusplus
} /* extern "C" */
#endif

Loading…
Cancel
Save