|
|
|
@ -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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|