From ce012b7b55f038394d142bf8a09827bdfdccf64b Mon Sep 17 00:00:00 2001 From: Joshua Haberman <jhaberman@gmail.com> Date: Fri, 1 Oct 2021 16:34:42 -0700 Subject: [PATCH] Added support for extensions. --- BUILD | 21 ++ README.md | 6 +- cmake/google/protobuf/descriptor.upb.c | 457 +++++++++++++------------ cmake/google/protobuf/descriptor.upb.h | 2 + tests/conformance_upb_failures.txt | 1 - upb/decode.c | 96 ++++-- upb/decode_internal.h | 1 + upb/def.c | 247 ++++++++++--- upb/def.h | 20 +- upb/encode.c | 119 ++++--- upb/json_decode.c | 23 +- upb/json_decode.h | 2 +- upb/json_encode.c | 16 +- upb/msg.c | 31 +- upb/msg_internal.h | 78 ++++- upb/reflection.c | 156 +++++---- upb/reflection.h | 3 +- upbc/BUILD | 1 + upbc/common.cc | 25 +- upbc/common.h | 5 +- upbc/protoc-gen-upb.cc | 259 +++++++++++++- upbc/protoc-gen-upbdefs.cc | 24 +- 22 files changed, 1103 insertions(+), 490 deletions(-) diff --git a/BUILD b/BUILD index 1ddf4d3a0c..97928110b8 100644 --- a/BUILD +++ b/BUILD @@ -215,6 +215,27 @@ cc_library( ], ) +cc_test( + name = "msg_test", + srcs = ["upb/msg_test.cc"], + deps = [ + "@com_google_googletest//:gtest_main", + ":msg_test_upb_proto_reflection", + ":json", + ], +) + +proto_library( + name = "msg_test_proto", + srcs = ["upb/msg_test.proto"], + deps = ["@com_google_protobuf//:test_messages_proto3_proto"], +) + +upb_proto_reflection_library( + name = "msg_test_upb_proto_reflection", + deps = [":msg_test_proto"], +) + # Internal C/C++ libraries ##################################################### cc_library( diff --git a/README.md b/README.md index c59340c16f..92a081bbef 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,8 @@ Like the main protobuf implementation in C++, it supports: - reflection - binary & JSON wire formats - text format serialization -- all standard features of protobufs (oneofs, maps, unknown fields, etc.) +- all standard features of protobufs (oneofs, maps, unknown fields, extensions, + etc.) - full conformance with the protobuf conformance tests upb also supports some features that C++ does not: @@ -36,9 +37,8 @@ upb also supports some features that C++ does not: - **fast reflection-based parsing:** messages loaded at runtime parse just as fast as compiled-in messages. -However there are some features it does not support: +However there are a few features it does not support: -- proto2 extensions (coming soon!) - text format parsing - deep descriptor verification: upb's descriptor validation is not as exhaustive as `protoc`. diff --git a/cmake/google/protobuf/descriptor.upb.c b/cmake/google/protobuf/descriptor.upb.c index a6b9af9132..fdbf23b9d1 100644 --- a/cmake/google/protobuf/descriptor.upb.c +++ b/cmake/google/protobuf/descriptor.upb.c @@ -12,474 +12,511 @@ #include "upb/port_def.inc" -static const upb_msglayout *const google_protobuf_FileDescriptorSet_submsgs[1] = { - &google_protobuf_FileDescriptorProto_msginit, +static const upb_msglayout_sub google_protobuf_FileDescriptorSet_submsgs[1] = { + {.submsg = &google_protobuf_FileDescriptorProto_msginit}, }; static const upb_msglayout_field google_protobuf_FileDescriptorSet__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_FileDescriptorSet_msginit = { &google_protobuf_FileDescriptorSet_submsgs[0], &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(8, 8), 1, false, 1, 255, + UPB_SIZE(8, 8), 1, _UPB_MSGEXT_NONE, 1, 255, }; -static const upb_msglayout *const google_protobuf_FileDescriptorProto_submsgs[6] = { - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_FileOptions_msginit, - &google_protobuf_ServiceDescriptorProto_msginit, - &google_protobuf_SourceCodeInfo_msginit, +static const upb_msglayout_sub google_protobuf_FileDescriptorProto_submsgs[6] = { + {.submsg = &google_protobuf_DescriptorProto_msginit}, + {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, + {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, + {.submsg = &google_protobuf_FileOptions_msginit}, + {.submsg = &google_protobuf_ServiceDescriptorProto_msginit}, + {.submsg = &google_protobuf_SourceCodeInfo_msginit}, }; static const upb_msglayout_field google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(12, 24), 2, 0, 12, _UPB_MODE_SCALAR}, - {3, UPB_SIZE(36, 72), 0, 0, 12, _UPB_MODE_ARRAY}, - {4, UPB_SIZE(40, 80), 0, 0, 11, _UPB_MODE_ARRAY}, - {5, UPB_SIZE(44, 88), 0, 1, 11, _UPB_MODE_ARRAY}, - {6, UPB_SIZE(48, 96), 0, 4, 11, _UPB_MODE_ARRAY}, - {7, UPB_SIZE(52, 104), 0, 2, 11, _UPB_MODE_ARRAY}, - {8, UPB_SIZE(28, 56), 3, 3, 11, _UPB_MODE_SCALAR}, - {9, UPB_SIZE(32, 64), 4, 5, 11, _UPB_MODE_SCALAR}, - {10, UPB_SIZE(56, 112), 0, 0, 5, _UPB_MODE_ARRAY}, - {11, UPB_SIZE(60, 120), 0, 0, 5, _UPB_MODE_ARRAY}, - {12, UPB_SIZE(20, 40), 5, 0, 12, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {2, UPB_SIZE(12, 24), 2, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {3, UPB_SIZE(36, 72), 0, 0, 12, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {4, UPB_SIZE(40, 80), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {5, UPB_SIZE(44, 88), 0, 1, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {6, UPB_SIZE(48, 96), 0, 4, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {7, UPB_SIZE(52, 104), 0, 2, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {8, UPB_SIZE(28, 56), 3, 3, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, + {9, UPB_SIZE(32, 64), 4, 5, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, + {10, UPB_SIZE(56, 112), 0, 0, 5, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {11, UPB_SIZE(60, 120), 0, 0, 5, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {12, UPB_SIZE(20, 40), 5, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, }; const upb_msglayout google_protobuf_FileDescriptorProto_msginit = { &google_protobuf_FileDescriptorProto_submsgs[0], &google_protobuf_FileDescriptorProto__fields[0], - UPB_SIZE(64, 128), 12, false, 12, 255, + UPB_SIZE(64, 128), 12, _UPB_MSGEXT_NONE, 12, 255, }; -static const upb_msglayout *const google_protobuf_DescriptorProto_submsgs[7] = { - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_DescriptorProto_ExtensionRange_msginit, - &google_protobuf_DescriptorProto_ReservedRange_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_MessageOptions_msginit, - &google_protobuf_OneofDescriptorProto_msginit, +static const upb_msglayout_sub google_protobuf_DescriptorProto_submsgs[7] = { + {.submsg = &google_protobuf_DescriptorProto_msginit}, + {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msginit}, + {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msginit}, + {.submsg = &google_protobuf_EnumDescriptorProto_msginit}, + {.submsg = &google_protobuf_FieldDescriptorProto_msginit}, + {.submsg = &google_protobuf_MessageOptions_msginit}, + {.submsg = &google_protobuf_OneofDescriptorProto_msginit}, }; static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(16, 32), 0, 4, 11, _UPB_MODE_ARRAY}, - {3, UPB_SIZE(20, 40), 0, 0, 11, _UPB_MODE_ARRAY}, - {4, UPB_SIZE(24, 48), 0, 3, 11, _UPB_MODE_ARRAY}, - {5, UPB_SIZE(28, 56), 0, 1, 11, _UPB_MODE_ARRAY}, - {6, UPB_SIZE(32, 64), 0, 4, 11, _UPB_MODE_ARRAY}, - {7, UPB_SIZE(12, 24), 2, 5, 11, _UPB_MODE_SCALAR}, - {8, UPB_SIZE(36, 72), 0, 6, 11, _UPB_MODE_ARRAY}, - {9, UPB_SIZE(40, 80), 0, 2, 11, _UPB_MODE_ARRAY}, - {10, UPB_SIZE(44, 88), 0, 0, 12, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {2, UPB_SIZE(16, 32), 0, 4, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {3, UPB_SIZE(20, 40), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {4, UPB_SIZE(24, 48), 0, 3, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {5, UPB_SIZE(28, 56), 0, 1, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {6, UPB_SIZE(32, 64), 0, 4, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {7, UPB_SIZE(12, 24), 2, 5, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, + {8, UPB_SIZE(36, 72), 0, 6, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {9, UPB_SIZE(40, 80), 0, 2, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {10, UPB_SIZE(44, 88), 0, 0, 12, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_DescriptorProto_msginit = { &google_protobuf_DescriptorProto_submsgs[0], &google_protobuf_DescriptorProto__fields[0], - UPB_SIZE(48, 96), 10, false, 10, 255, + UPB_SIZE(48, 96), 10, _UPB_MSGEXT_NONE, 10, 255, }; -static const upb_msglayout *const google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { - &google_protobuf_ExtensionRangeOptions_msginit, +static const upb_msglayout_sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { + {.submsg = &google_protobuf_ExtensionRangeOptions_msginit}, }; static const upb_msglayout_field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(8, 8), 2, 0, 5, _UPB_MODE_SCALAR}, - {3, UPB_SIZE(12, 16), 3, 0, 11, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(4, 4), 1, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {2, UPB_SIZE(8, 8), 2, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {3, UPB_SIZE(12, 16), 3, 0, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_DescriptorProto_ExtensionRange_msginit = { &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], &google_protobuf_DescriptorProto_ExtensionRange__fields[0], - UPB_SIZE(16, 24), 3, false, 3, 255, + UPB_SIZE(16, 24), 3, _UPB_MSGEXT_NONE, 3, 255, }; static const upb_msglayout_field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(8, 8), 2, 0, 5, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(4, 4), 1, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {2, UPB_SIZE(8, 8), 2, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, }; const upb_msglayout google_protobuf_DescriptorProto_ReservedRange_msginit = { NULL, &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(16, 16), 2, false, 2, 255, + UPB_SIZE(16, 16), 2, _UPB_MSGEXT_NONE, 2, 255, }; -static const upb_msglayout *const google_protobuf_ExtensionRangeOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, +static const upb_msglayout_sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, }; static const upb_msglayout_field google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY}, + {999, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit = { &google_protobuf_ExtensionRangeOptions_submsgs[0], &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(8, 8), 1, false, 0, 255, + UPB_SIZE(8, 8), 1, _UPB_MSGEXT_EXTENDABLE, 0, 255, }; -static const upb_msglayout *const google_protobuf_FieldDescriptorProto_submsgs[1] = { - &google_protobuf_FieldOptions_msginit, +static const upb_msglayout_sub google_protobuf_FieldDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_FieldOptions_msginit}, }; static const upb_msglayout_field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(24, 24), 1, 0, 12, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(32, 40), 2, 0, 12, _UPB_MODE_SCALAR}, - {3, UPB_SIZE(12, 12), 3, 0, 5, _UPB_MODE_SCALAR}, - {4, UPB_SIZE(4, 4), 4, 0, 14, _UPB_MODE_SCALAR}, - {5, UPB_SIZE(8, 8), 5, 0, 14, _UPB_MODE_SCALAR}, - {6, UPB_SIZE(40, 56), 6, 0, 12, _UPB_MODE_SCALAR}, - {7, UPB_SIZE(48, 72), 7, 0, 12, _UPB_MODE_SCALAR}, - {8, UPB_SIZE(64, 104), 8, 0, 11, _UPB_MODE_SCALAR}, - {9, UPB_SIZE(16, 16), 9, 0, 5, _UPB_MODE_SCALAR}, - {10, UPB_SIZE(56, 88), 10, 0, 12, _UPB_MODE_SCALAR}, - {17, UPB_SIZE(20, 20), 11, 0, 8, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(24, 24), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {2, UPB_SIZE(32, 40), 2, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {3, UPB_SIZE(12, 12), 3, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {4, UPB_SIZE(4, 4), 4, 0, 14, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {5, UPB_SIZE(8, 8), 5, 0, 14, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {6, UPB_SIZE(40, 56), 6, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {7, UPB_SIZE(48, 72), 7, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {8, UPB_SIZE(64, 104), 8, 0, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, + {9, UPB_SIZE(16, 16), 9, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {10, UPB_SIZE(56, 88), 10, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {17, UPB_SIZE(20, 20), 11, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, }; const upb_msglayout google_protobuf_FieldDescriptorProto_msginit = { &google_protobuf_FieldDescriptorProto_submsgs[0], &google_protobuf_FieldDescriptorProto__fields[0], - UPB_SIZE(72, 112), 11, false, 10, 255, + UPB_SIZE(72, 112), 11, _UPB_MSGEXT_NONE, 10, 255, }; -static const upb_msglayout *const google_protobuf_OneofDescriptorProto_submsgs[1] = { - &google_protobuf_OneofOptions_msginit, +static const upb_msglayout_sub google_protobuf_OneofDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_OneofOptions_msginit}, }; static const upb_msglayout_field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(12, 24), 2, 0, 11, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {2, UPB_SIZE(12, 24), 2, 0, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_OneofDescriptorProto_msginit = { &google_protobuf_OneofDescriptorProto_submsgs[0], &google_protobuf_OneofDescriptorProto__fields[0], - UPB_SIZE(16, 32), 2, false, 2, 255, + UPB_SIZE(16, 32), 2, _UPB_MSGEXT_NONE, 2, 255, }; -static const upb_msglayout *const google_protobuf_EnumDescriptorProto_submsgs[3] = { - &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, - &google_protobuf_EnumOptions_msginit, - &google_protobuf_EnumValueDescriptorProto_msginit, +static const upb_msglayout_sub google_protobuf_EnumDescriptorProto_submsgs[3] = { + {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit}, + {.submsg = &google_protobuf_EnumOptions_msginit}, + {.submsg = &google_protobuf_EnumValueDescriptorProto_msginit}, }; static const upb_msglayout_field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(16, 32), 0, 2, 11, _UPB_MODE_ARRAY}, - {3, UPB_SIZE(12, 24), 2, 1, 11, _UPB_MODE_SCALAR}, - {4, UPB_SIZE(20, 40), 0, 0, 11, _UPB_MODE_ARRAY}, - {5, UPB_SIZE(24, 48), 0, 0, 12, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {2, UPB_SIZE(16, 32), 0, 2, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {3, UPB_SIZE(12, 24), 2, 1, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, + {4, UPB_SIZE(20, 40), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {5, UPB_SIZE(24, 48), 0, 0, 12, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_EnumDescriptorProto_msginit = { &google_protobuf_EnumDescriptorProto_submsgs[0], &google_protobuf_EnumDescriptorProto__fields[0], - UPB_SIZE(32, 64), 5, false, 5, 255, + UPB_SIZE(32, 64), 5, _UPB_MSGEXT_NONE, 5, 255, }; static const upb_msglayout_field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(8, 8), 2, 0, 5, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(4, 4), 1, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {2, UPB_SIZE(8, 8), 2, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, }; const upb_msglayout google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { NULL, &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(16, 16), 2, false, 2, 255, + UPB_SIZE(16, 16), 2, _UPB_MSGEXT_NONE, 2, 255, }; -static const upb_msglayout *const google_protobuf_EnumValueDescriptorProto_submsgs[1] = { - &google_protobuf_EnumValueOptions_msginit, +static const upb_msglayout_sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_EnumValueOptions_msginit}, }; static const upb_msglayout_field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 8), 1, 0, 12, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(4, 4), 2, 0, 5, _UPB_MODE_SCALAR}, - {3, UPB_SIZE(16, 24), 3, 0, 11, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(8, 8), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {2, UPB_SIZE(4, 4), 2, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {3, UPB_SIZE(16, 24), 3, 0, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit = { &google_protobuf_EnumValueDescriptorProto_submsgs[0], &google_protobuf_EnumValueDescriptorProto__fields[0], - UPB_SIZE(24, 32), 3, false, 3, 255, + UPB_SIZE(24, 32), 3, _UPB_MSGEXT_NONE, 3, 255, }; -static const upb_msglayout *const google_protobuf_ServiceDescriptorProto_submsgs[2] = { - &google_protobuf_MethodDescriptorProto_msginit, - &google_protobuf_ServiceOptions_msginit, +static const upb_msglayout_sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { + {.submsg = &google_protobuf_MethodDescriptorProto_msginit}, + {.submsg = &google_protobuf_ServiceOptions_msginit}, }; static const upb_msglayout_field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(16, 32), 0, 0, 11, _UPB_MODE_ARRAY}, - {3, UPB_SIZE(12, 24), 2, 1, 11, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {2, UPB_SIZE(16, 32), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {3, UPB_SIZE(12, 24), 2, 1, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit = { &google_protobuf_ServiceDescriptorProto_submsgs[0], &google_protobuf_ServiceDescriptorProto__fields[0], - UPB_SIZE(24, 48), 3, false, 3, 255, + UPB_SIZE(24, 48), 3, _UPB_MSGEXT_NONE, 3, 255, }; -static const upb_msglayout *const google_protobuf_MethodDescriptorProto_submsgs[1] = { - &google_protobuf_MethodOptions_msginit, +static const upb_msglayout_sub google_protobuf_MethodDescriptorProto_submsgs[1] = { + {.submsg = &google_protobuf_MethodOptions_msginit}, }; static const upb_msglayout_field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(12, 24), 2, 0, 12, _UPB_MODE_SCALAR}, - {3, UPB_SIZE(20, 40), 3, 0, 12, _UPB_MODE_SCALAR}, - {4, UPB_SIZE(28, 56), 4, 0, 11, _UPB_MODE_SCALAR}, - {5, UPB_SIZE(1, 1), 5, 0, 8, _UPB_MODE_SCALAR}, - {6, UPB_SIZE(2, 2), 6, 0, 8, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {2, UPB_SIZE(12, 24), 2, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {3, UPB_SIZE(20, 40), 3, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {4, UPB_SIZE(28, 56), 4, 0, 11, _UPB_MODE_SCALAR | (_UPB_REP_PTR << 6)}, + {5, UPB_SIZE(1, 1), 5, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {6, UPB_SIZE(2, 2), 6, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, }; const upb_msglayout google_protobuf_MethodDescriptorProto_msginit = { &google_protobuf_MethodDescriptorProto_submsgs[0], &google_protobuf_MethodDescriptorProto__fields[0], - UPB_SIZE(32, 64), 6, false, 6, 255, + UPB_SIZE(32, 64), 6, _UPB_MSGEXT_NONE, 6, 255, }; -static const upb_msglayout *const google_protobuf_FileOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, +static const upb_msglayout_sub google_protobuf_FileOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, }; static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(20, 24), 1, 0, 12, _UPB_MODE_SCALAR}, - {8, UPB_SIZE(28, 40), 2, 0, 12, _UPB_MODE_SCALAR}, - {9, UPB_SIZE(4, 4), 3, 0, 14, _UPB_MODE_SCALAR}, - {10, UPB_SIZE(8, 8), 4, 0, 8, _UPB_MODE_SCALAR}, - {11, UPB_SIZE(36, 56), 5, 0, 12, _UPB_MODE_SCALAR}, - {16, UPB_SIZE(9, 9), 6, 0, 8, _UPB_MODE_SCALAR}, - {17, UPB_SIZE(10, 10), 7, 0, 8, _UPB_MODE_SCALAR}, - {18, UPB_SIZE(11, 11), 8, 0, 8, _UPB_MODE_SCALAR}, - {20, UPB_SIZE(12, 12), 9, 0, 8, _UPB_MODE_SCALAR}, - {23, UPB_SIZE(13, 13), 10, 0, 8, _UPB_MODE_SCALAR}, - {27, UPB_SIZE(14, 14), 11, 0, 8, _UPB_MODE_SCALAR}, - {31, UPB_SIZE(15, 15), 12, 0, 8, _UPB_MODE_SCALAR}, - {36, UPB_SIZE(44, 72), 13, 0, 12, _UPB_MODE_SCALAR}, - {37, UPB_SIZE(52, 88), 14, 0, 12, _UPB_MODE_SCALAR}, - {39, UPB_SIZE(60, 104), 15, 0, 12, _UPB_MODE_SCALAR}, - {40, UPB_SIZE(68, 120), 16, 0, 12, _UPB_MODE_SCALAR}, - {41, UPB_SIZE(76, 136), 17, 0, 12, _UPB_MODE_SCALAR}, - {42, UPB_SIZE(16, 16), 18, 0, 8, _UPB_MODE_SCALAR}, - {44, UPB_SIZE(84, 152), 19, 0, 12, _UPB_MODE_SCALAR}, - {45, UPB_SIZE(92, 168), 20, 0, 12, _UPB_MODE_SCALAR}, - {999, UPB_SIZE(100, 184), 0, 0, 11, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(20, 24), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {8, UPB_SIZE(28, 40), 2, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {9, UPB_SIZE(4, 4), 3, 0, 14, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {10, UPB_SIZE(8, 8), 4, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {11, UPB_SIZE(36, 56), 5, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {16, UPB_SIZE(9, 9), 6, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {17, UPB_SIZE(10, 10), 7, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {18, UPB_SIZE(11, 11), 8, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {20, UPB_SIZE(12, 12), 9, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {23, UPB_SIZE(13, 13), 10, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {27, UPB_SIZE(14, 14), 11, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {31, UPB_SIZE(15, 15), 12, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {36, UPB_SIZE(44, 72), 13, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {37, UPB_SIZE(52, 88), 14, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {39, UPB_SIZE(60, 104), 15, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {40, UPB_SIZE(68, 120), 16, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {41, UPB_SIZE(76, 136), 17, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {42, UPB_SIZE(16, 16), 18, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {44, UPB_SIZE(84, 152), 19, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {45, UPB_SIZE(92, 168), 20, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {999, UPB_SIZE(100, 184), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_FileOptions_msginit = { &google_protobuf_FileOptions_submsgs[0], &google_protobuf_FileOptions__fields[0], - UPB_SIZE(104, 192), 21, false, 1, 255, + UPB_SIZE(104, 192), 21, _UPB_MSGEXT_EXTENDABLE, 1, 255, }; -static const upb_msglayout *const google_protobuf_MessageOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, +static const upb_msglayout_sub google_protobuf_MessageOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, }; static const upb_msglayout_field google_protobuf_MessageOptions__fields[5] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(2, 2), 2, 0, 8, _UPB_MODE_SCALAR}, - {3, UPB_SIZE(3, 3), 3, 0, 8, _UPB_MODE_SCALAR}, - {7, UPB_SIZE(4, 4), 4, 0, 8, _UPB_MODE_SCALAR}, - {999, UPB_SIZE(8, 8), 0, 0, 11, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {2, UPB_SIZE(2, 2), 2, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {3, UPB_SIZE(3, 3), 3, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {7, UPB_SIZE(4, 4), 4, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {999, UPB_SIZE(8, 8), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_MessageOptions_msginit = { &google_protobuf_MessageOptions_submsgs[0], &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(16, 16), 5, false, 3, 255, + UPB_SIZE(16, 16), 5, _UPB_MSGEXT_EXTENDABLE, 3, 255, }; -static const upb_msglayout *const google_protobuf_FieldOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, +static const upb_msglayout_sub google_protobuf_FieldOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, }; static const upb_msglayout_field google_protobuf_FieldOptions__fields[7] = { - {1, UPB_SIZE(4, 4), 1, 0, 14, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(12, 12), 2, 0, 8, _UPB_MODE_SCALAR}, - {3, UPB_SIZE(13, 13), 3, 0, 8, _UPB_MODE_SCALAR}, - {5, UPB_SIZE(14, 14), 4, 0, 8, _UPB_MODE_SCALAR}, - {6, UPB_SIZE(8, 8), 5, 0, 14, _UPB_MODE_SCALAR}, - {10, UPB_SIZE(15, 15), 6, 0, 8, _UPB_MODE_SCALAR}, - {999, UPB_SIZE(16, 16), 0, 0, 11, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(4, 4), 1, 0, 14, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {2, UPB_SIZE(12, 12), 2, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {3, UPB_SIZE(13, 13), 3, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {5, UPB_SIZE(14, 14), 4, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {6, UPB_SIZE(8, 8), 5, 0, 14, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {10, UPB_SIZE(15, 15), 6, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {999, UPB_SIZE(16, 16), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_FieldOptions_msginit = { &google_protobuf_FieldOptions_submsgs[0], &google_protobuf_FieldOptions__fields[0], - UPB_SIZE(24, 24), 7, false, 3, 255, + UPB_SIZE(24, 24), 7, _UPB_MSGEXT_EXTENDABLE, 3, 255, }; -static const upb_msglayout *const google_protobuf_OneofOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, +static const upb_msglayout_sub google_protobuf_OneofOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, }; static const upb_msglayout_field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY}, + {999, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_OneofOptions_msginit = { &google_protobuf_OneofOptions_submsgs[0], &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(8, 8), 1, false, 0, 255, + UPB_SIZE(8, 8), 1, _UPB_MSGEXT_EXTENDABLE, 0, 255, }; -static const upb_msglayout *const google_protobuf_EnumOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, +static const upb_msglayout_sub google_protobuf_EnumOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, }; static const upb_msglayout_field google_protobuf_EnumOptions__fields[3] = { - {2, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR}, - {3, UPB_SIZE(2, 2), 2, 0, 8, _UPB_MODE_SCALAR}, - {999, UPB_SIZE(4, 8), 0, 0, 11, _UPB_MODE_ARRAY}, + {2, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {3, UPB_SIZE(2, 2), 2, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_EnumOptions_msginit = { &google_protobuf_EnumOptions_submsgs[0], &google_protobuf_EnumOptions__fields[0], - UPB_SIZE(8, 16), 3, false, 0, 255, + UPB_SIZE(8, 16), 3, _UPB_MSGEXT_EXTENDABLE, 0, 255, }; -static const upb_msglayout *const google_protobuf_EnumValueOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, +static const upb_msglayout_sub google_protobuf_EnumValueOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, }; static const upb_msglayout_field google_protobuf_EnumValueOptions__fields[2] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR}, - {999, UPB_SIZE(4, 8), 0, 0, 11, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_EnumValueOptions_msginit = { &google_protobuf_EnumValueOptions_submsgs[0], &google_protobuf_EnumValueOptions__fields[0], - UPB_SIZE(8, 16), 2, false, 1, 255, + UPB_SIZE(8, 16), 2, _UPB_MSGEXT_EXTENDABLE, 1, 255, }; -static const upb_msglayout *const google_protobuf_ServiceOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, +static const upb_msglayout_sub google_protobuf_ServiceOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, }; static const upb_msglayout_field google_protobuf_ServiceOptions__fields[2] = { - {33, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR}, - {999, UPB_SIZE(4, 8), 0, 0, 11, _UPB_MODE_ARRAY}, + {33, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_ServiceOptions_msginit = { &google_protobuf_ServiceOptions_submsgs[0], &google_protobuf_ServiceOptions__fields[0], - UPB_SIZE(8, 16), 2, false, 0, 255, + UPB_SIZE(8, 16), 2, _UPB_MSGEXT_EXTENDABLE, 0, 255, }; -static const upb_msglayout *const google_protobuf_MethodOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, +static const upb_msglayout_sub google_protobuf_MethodOptions_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_msginit}, }; static const upb_msglayout_field google_protobuf_MethodOptions__fields[3] = { - {33, UPB_SIZE(8, 8), 1, 0, 8, _UPB_MODE_SCALAR}, - {34, UPB_SIZE(4, 4), 2, 0, 14, _UPB_MODE_SCALAR}, - {999, UPB_SIZE(12, 16), 0, 0, 11, _UPB_MODE_ARRAY}, + {33, UPB_SIZE(8, 8), 1, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, + {34, UPB_SIZE(4, 4), 2, 0, 14, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {999, UPB_SIZE(12, 16), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_MethodOptions_msginit = { &google_protobuf_MethodOptions_submsgs[0], &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(16, 24), 3, false, 0, 255, + UPB_SIZE(16, 24), 3, _UPB_MSGEXT_EXTENDABLE, 0, 255, }; -static const upb_msglayout *const google_protobuf_UninterpretedOption_submsgs[1] = { - &google_protobuf_UninterpretedOption_NamePart_msginit, +static const upb_msglayout_sub google_protobuf_UninterpretedOption_submsgs[1] = { + {.submsg = &google_protobuf_UninterpretedOption_NamePart_msginit}, }; static const upb_msglayout_field google_protobuf_UninterpretedOption__fields[7] = { - {2, UPB_SIZE(56, 80), 0, 0, 11, _UPB_MODE_ARRAY}, - {3, UPB_SIZE(32, 32), 1, 0, 12, _UPB_MODE_SCALAR}, - {4, UPB_SIZE(8, 8), 2, 0, 4, _UPB_MODE_SCALAR}, - {5, UPB_SIZE(16, 16), 3, 0, 3, _UPB_MODE_SCALAR}, - {6, UPB_SIZE(24, 24), 4, 0, 1, _UPB_MODE_SCALAR}, - {7, UPB_SIZE(40, 48), 5, 0, 12, _UPB_MODE_SCALAR}, - {8, UPB_SIZE(48, 64), 6, 0, 12, _UPB_MODE_SCALAR}, + {2, UPB_SIZE(56, 80), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, + {3, UPB_SIZE(32, 32), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {4, UPB_SIZE(8, 8), 2, 0, 4, _UPB_MODE_SCALAR | (_UPB_REP_8BYTE << 6)}, + {5, UPB_SIZE(16, 16), 3, 0, 3, _UPB_MODE_SCALAR | (_UPB_REP_8BYTE << 6)}, + {6, UPB_SIZE(24, 24), 4, 0, 1, _UPB_MODE_SCALAR | (_UPB_REP_8BYTE << 6)}, + {7, UPB_SIZE(40, 48), 5, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {8, UPB_SIZE(48, 64), 6, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, }; const upb_msglayout google_protobuf_UninterpretedOption_msginit = { &google_protobuf_UninterpretedOption_submsgs[0], &google_protobuf_UninterpretedOption__fields[0], - UPB_SIZE(64, 96), 7, false, 0, 255, + UPB_SIZE(64, 96), 7, _UPB_MSGEXT_NONE, 0, 255, }; static const upb_msglayout_field google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR}, - {2, UPB_SIZE(1, 1), 2, 0, 8, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {2, UPB_SIZE(1, 1), 2, 0, 8, _UPB_MODE_SCALAR | (_UPB_REP_1BYTE << 6)}, }; const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit = { NULL, &google_protobuf_UninterpretedOption_NamePart__fields[0], - UPB_SIZE(16, 32), 2, false, 2, 255, + UPB_SIZE(16, 32), 2, _UPB_MSGEXT_NONE, 2, 255, }; -static const upb_msglayout *const google_protobuf_SourceCodeInfo_submsgs[1] = { - &google_protobuf_SourceCodeInfo_Location_msginit, +static const upb_msglayout_sub google_protobuf_SourceCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_SourceCodeInfo_Location_msginit}, }; static const upb_msglayout_field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_SourceCodeInfo_msginit = { &google_protobuf_SourceCodeInfo_submsgs[0], &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, false, 1, 255, + UPB_SIZE(8, 8), 1, _UPB_MSGEXT_NONE, 1, 255, }; static const upb_msglayout_field google_protobuf_SourceCodeInfo_Location__fields[5] = { - {1, UPB_SIZE(20, 40), 0, 0, 5, _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED}, - {2, UPB_SIZE(24, 48), 0, 0, 5, _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED}, - {3, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR}, - {4, UPB_SIZE(12, 24), 2, 0, 12, _UPB_MODE_SCALAR}, - {6, UPB_SIZE(28, 56), 0, 0, 12, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(20, 40), 0, 0, 5, _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED | (_UPB_REP_PTR << 6)}, + {2, UPB_SIZE(24, 48), 0, 0, 5, _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED | (_UPB_REP_PTR << 6)}, + {3, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {4, UPB_SIZE(12, 24), 2, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {6, UPB_SIZE(28, 56), 0, 0, 12, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit = { NULL, &google_protobuf_SourceCodeInfo_Location__fields[0], - UPB_SIZE(32, 64), 5, false, 4, 255, + UPB_SIZE(32, 64), 5, _UPB_MSGEXT_NONE, 4, 255, }; -static const upb_msglayout *const google_protobuf_GeneratedCodeInfo_submsgs[1] = { - &google_protobuf_GeneratedCodeInfo_Annotation_msginit, +static const upb_msglayout_sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { + {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msginit}, }; static const upb_msglayout_field google_protobuf_GeneratedCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY}, + {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6)}, }; const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit = { &google_protobuf_GeneratedCodeInfo_submsgs[0], &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, false, 1, 255, + UPB_SIZE(8, 8), 1, _UPB_MSGEXT_NONE, 1, 255, }; static const upb_msglayout_field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { - {1, UPB_SIZE(20, 32), 0, 0, 5, _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED}, - {2, UPB_SIZE(12, 16), 1, 0, 12, _UPB_MODE_SCALAR}, - {3, UPB_SIZE(4, 4), 2, 0, 5, _UPB_MODE_SCALAR}, - {4, UPB_SIZE(8, 8), 3, 0, 5, _UPB_MODE_SCALAR}, + {1, UPB_SIZE(20, 32), 0, 0, 5, _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED | (_UPB_REP_PTR << 6)}, + {2, UPB_SIZE(12, 16), 1, 0, 12, _UPB_MODE_SCALAR | (_UPB_REP_STRVIEW << 6)}, + {3, UPB_SIZE(4, 4), 2, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, + {4, UPB_SIZE(8, 8), 3, 0, 5, _UPB_MODE_SCALAR | (_UPB_REP_4BYTE << 6)}, }; const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit = { NULL, &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], - UPB_SIZE(24, 48), 4, false, 4, 255, + UPB_SIZE(24, 48), 4, _UPB_MSGEXT_NONE, 4, 255, +}; + +static const upb_msglayout *messages_layout[27] = { + &google_protobuf_FileDescriptorSet_msginit, + &google_protobuf_FileDescriptorProto_msginit, + &google_protobuf_DescriptorProto_msginit, + &google_protobuf_DescriptorProto_ExtensionRange_msginit, + &google_protobuf_DescriptorProto_ReservedRange_msginit, + &google_protobuf_ExtensionRangeOptions_msginit, + &google_protobuf_FieldDescriptorProto_msginit, + &google_protobuf_OneofDescriptorProto_msginit, + &google_protobuf_EnumDescriptorProto_msginit, + &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, + &google_protobuf_EnumValueDescriptorProto_msginit, + &google_protobuf_ServiceDescriptorProto_msginit, + &google_protobuf_MethodDescriptorProto_msginit, + &google_protobuf_FileOptions_msginit, + &google_protobuf_MessageOptions_msginit, + &google_protobuf_FieldOptions_msginit, + &google_protobuf_OneofOptions_msginit, + &google_protobuf_EnumOptions_msginit, + &google_protobuf_EnumValueOptions_msginit, + &google_protobuf_ServiceOptions_msginit, + &google_protobuf_MethodOptions_msginit, + &google_protobuf_UninterpretedOption_msginit, + &google_protobuf_UninterpretedOption_NamePart_msginit, + &google_protobuf_SourceCodeInfo_msginit, + &google_protobuf_SourceCodeInfo_Location_msginit, + &google_protobuf_GeneratedCodeInfo_msginit, + &google_protobuf_GeneratedCodeInfo_Annotation_msginit, +}; + +const upb_msglayout_file google_protobuf_descriptor_proto_upb_file_layout = { + messages_layout, + NULL, + 27, + 0, }; #include "upb/port_undef.inc" diff --git a/cmake/google/protobuf/descriptor.upb.h b/cmake/google/protobuf/descriptor.upb.h index 4767b3af68..2416bc1060 100644 --- a/cmake/google/protobuf/descriptor.upb.h +++ b/cmake/google/protobuf/descriptor.upb.h @@ -2038,6 +2038,8 @@ UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_prot *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; } +extern const upb_msglayout_file google_protobuf_descriptor_proto_upb_file_layout; + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/tests/conformance_upb_failures.txt b/tests/conformance_upb_failures.txt index d9290df987..e69de29bb2 100644 --- a/tests/conformance_upb_failures.txt +++ b/tests/conformance_upb_failures.txt @@ -1 +0,0 @@ -Recommended.Proto2.JsonInput.FieldNameExtension.Validator diff --git a/upb/decode.c b/upb/decode.c index 2739be86e7..f7992c7165 100644 --- a/upb/decode.c +++ b/upb/decode.c @@ -298,7 +298,8 @@ static void decode_munge(int type, wireval *val) { } } -static const upb_msglayout_field *upb_find_field(const upb_msglayout *l, +static const upb_msglayout_field *upb_find_field(upb_decstate *d, + const upb_msglayout *l, uint32_t field_number, int *last_field_index) { static upb_msglayout_field none = {0, 0, 0, 0, 0, 0}; @@ -307,23 +308,32 @@ static const upb_msglayout_field *upb_find_field(const upb_msglayout *l, size_t idx = ((size_t)field_number) - 1; // 0 wraps to SIZE_MAX if (idx < l->dense_below) { + /* Fastest case: index into dense fields. */ goto found; } - /* Resume scanning from last_field_index since fields are usually in order. */ - int last = *last_field_index; - for (idx = last; idx < l->field_count; idx++) { - if (l->fields[idx].number == field_number) { - goto found; + if (l->dense_below < l->field_count) { + /* Linear search non-dense fields. Resume scanning from last_field_index + * since fields are usually in order. */ + int last = *last_field_index; + for (idx = last; idx < l->field_count; idx++) { + if (l->fields[idx].number == field_number) { + goto found; + } } - } - for (idx = 0; idx < last; idx++) { - if (l->fields[idx].number == field_number) { - goto found; + for (idx = 0; idx < last; idx++) { + if (l->fields[idx].number == field_number) { + goto found; + } } } + if (l->ext == _UPB_MSGEXT_EXTENDABLE && d->extreg) { + const upb_msglayout_ext *ext = _upb_extreg_get(d->extreg, l, field_number); + if (ext) return &ext->field; + } + return &none; /* Unknown field. */ found: @@ -332,10 +342,9 @@ static const upb_msglayout_field *upb_find_field(const upb_msglayout *l, return &l->fields[idx]; } -static upb_msg *decode_newsubmsg(upb_decstate *d, - upb_msglayout const *const *submsgs, +static upb_msg *decode_newsubmsg(upb_decstate *d, const upb_msglayout_sub *subs, const upb_msglayout_field *field) { - const upb_msglayout *subl = submsgs[field->submsg_index]; + const upb_msglayout *subl = subs[field->submsg_index].submsg; return _upb_msg_new_inl(subl, &d->arena); } @@ -365,10 +374,10 @@ static const char *decode_readstr(upb_decstate *d, const char *ptr, int size, UPB_FORCEINLINE static const char *decode_tosubmsg(upb_decstate *d, const char *ptr, - upb_msg *submsg, - upb_msglayout const *const *submsgs, + upb_msg *submsg, + const upb_msglayout_sub *subs, const upb_msglayout_field *field, int size) { - const upb_msglayout *subl = submsgs[field->submsg_index]; + const upb_msglayout *subl = subs[field->submsg_index].submsg; int saved_delta = decode_pushlimit(d, ptr, size); if (--d->depth < 0) decode_err(d); if (!decode_isdone(d, &ptr)) { @@ -398,15 +407,15 @@ static const char *decode_group(upb_decstate *d, const char *ptr, UPB_FORCEINLINE static const char *decode_togroup(upb_decstate *d, const char *ptr, upb_msg *submsg, - upb_msglayout const *const *submsgs, + const upb_msglayout_sub *subs, const upb_msglayout_field *field) { - const upb_msglayout *subl = submsgs[field->submsg_index]; + const upb_msglayout *subl = subs[field->submsg_index].submsg; return decode_group(d, ptr, submsg, subl, field->number); } static const char *decode_toarray(upb_decstate *d, const char *ptr, upb_msg *msg, - upb_msglayout const *const *submsgs, + const upb_msglayout_sub *subs, const upb_msglayout_field *field, wireval *val, int op) { upb_array **arrp = UPB_PTR_AT(msg, field->offset, void); @@ -442,14 +451,14 @@ static const char *decode_toarray(upb_decstate *d, const char *ptr, } case OP_SUBMSG: { /* Append submessage / group. */ - upb_msg *submsg = decode_newsubmsg(d, submsgs, field); + upb_msg *submsg = decode_newsubmsg(d, subs, field); *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void *), upb_msg *) = submsg; arr->len++; if (UPB_UNLIKELY(field->descriptortype == UPB_DTYPE_GROUP)) { - return decode_togroup(d, ptr, submsg, submsgs, field); + return decode_togroup(d, ptr, submsg, subs, field); } else { - return decode_tosubmsg(d, ptr, submsg, submsgs, field, val->size); + return decode_tosubmsg(d, ptr, submsg, subs, field, val->size); } } case OP_FIXPCK_LG2(2): @@ -495,12 +504,13 @@ static const char *decode_toarray(upb_decstate *d, const char *ptr, } static const char *decode_tomap(upb_decstate *d, const char *ptr, upb_msg *msg, - upb_msglayout const *const *submsgs, - const upb_msglayout_field *field, wireval *val) { + const upb_msglayout_sub *subs, + const upb_msglayout_field *field, + wireval *val) { upb_map **map_p = UPB_PTR_AT(msg, field->offset, upb_map *); upb_map *map = *map_p; upb_map_entry ent; - const upb_msglayout *entry = submsgs[field->submsg_index]; + const upb_msglayout *entry = subs[field->submsg_index].submsg; if (!map) { /* Lazily create map. */ @@ -520,16 +530,16 @@ static const char *decode_tomap(upb_decstate *d, const char *ptr, upb_msg *msg, if (entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_GROUP) { /* Create proactively to handle the case where it doesn't appear. */ - ent.v.val = upb_value_ptr(_upb_msg_new(entry->submsgs[0], &d->arena)); + ent.v.val = upb_value_ptr(_upb_msg_new(entry->subs[0].submsg, &d->arena)); } - ptr = decode_tosubmsg(d, ptr, &ent.k, submsgs, field, val->size); + ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size); _upb_map_set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena); return ptr; } static const char *decode_tomsg(upb_decstate *d, const char *ptr, upb_msg *msg, - upb_msglayout const *const *submsgs, + const upb_msglayout_sub *subs, const upb_msglayout_field *field, wireval *val, int op) { void *mem = UPB_PTR_AT(msg, field->offset, void); @@ -553,13 +563,13 @@ static const char *decode_tomsg(upb_decstate *d, const char *ptr, upb_msg *msg, upb_msg **submsgp = mem; upb_msg *submsg = *submsgp; if (!submsg) { - submsg = decode_newsubmsg(d, submsgs, field); + submsg = decode_newsubmsg(d, subs, field); *submsgp = submsg; } if (UPB_UNLIKELY(type == UPB_DTYPE_GROUP)) { - ptr = decode_togroup(d, ptr, submsg, submsgs, field); + ptr = decode_togroup(d, ptr, submsg, subs, field); } else { - ptr = decode_tosubmsg(d, ptr, submsg, submsgs, field, val->size); + ptr = decode_tosubmsg(d, ptr, submsg, subs, field, val->size); } break; } @@ -616,7 +626,7 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, field_number = tag >> 3; wire_type = tag & 7; - field = upb_find_field(layout, field_number, &last_field_index); + field = upb_find_field(d, layout, field_number, &last_field_index); switch (wire_type) { case UPB_WIRE_TYPE_VARINT: @@ -664,16 +674,29 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, } if (op >= 0) { + /* Known field, possibly an extension. */ + upb_msg *field_msg = msg; + const upb_msglayout_sub *subs = layout->subs; + uint8_t mode = field->mode; + + if (UPB_UNLIKELY(mode & _UPB_MODE_IS_EXTENSION)) { + const upb_msglayout_ext *ext_layout = (const upb_msglayout_ext*)field; + upb_msg_ext *ext = _upb_msg_getorcreateext(msg, ext_layout, &d->arena); + if (UPB_UNLIKELY(!ext)) decode_err(d); + field_msg = &ext->data; + subs = &ext->ext->sub; + } + /* Parse, using op for dispatch. */ - switch (_upb_getmode(field)) { + switch (mode & 3) { case _UPB_MODE_ARRAY: - ptr = decode_toarray(d, ptr, msg, layout->submsgs, field, &val, op); + ptr = decode_toarray(d, ptr, field_msg, subs, field, &val, op); break; case _UPB_MODE_MAP: - ptr = decode_tomap(d, ptr, msg, layout->submsgs, field, &val); + ptr = decode_tomap(d, ptr, field_msg, subs, field, &val); break; case _UPB_MODE_SCALAR: - ptr = decode_tomsg(d, ptr, msg, layout->submsgs, field, &val, op); + ptr = decode_tomsg(d, ptr, field_msg, subs, field, &val, op); break; default: UPB_UNREACHABLE(); @@ -743,6 +766,7 @@ bool _upb_decode(const char *buf, size_t size, void *msg, state.alias = options & UPB_DECODE_ALIAS; } + state.extreg = extreg; state.limit_ptr = state.end; state.unknown_msg = NULL; state.depth = depth ? depth : 64; diff --git a/upb/decode_internal.h b/upb/decode_internal.h index 0492363725..6d03084b37 100644 --- a/upb/decode_internal.h +++ b/upb/decode_internal.h @@ -48,6 +48,7 @@ typedef struct upb_decstate { const char *limit_ptr; /* = end + UPB_MIN(limit, 0) */ upb_msg *unknown_msg; /* If non-NULL, add unknown data at buffer flip. */ const char *unknown; /* Start of unknown data. */ + const upb_extreg *extreg; /* For looking up extensions during the parse. */ int limit; /* Submessage limit relative to end. */ int depth; uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ diff --git a/upb/def.c b/upb/def.c index de41dcdb17..d1f3466978 100644 --- a/upb/def.c +++ b/upb/def.c @@ -74,6 +74,12 @@ struct upb_fielddef { upb_label_t label_; }; +struct upb_extrange { + const google_protobuf_ExtensionRangeOptions *opts; + int32_t start; + int32_t end; +}; + struct upb_msgdef { const upb_msglayout *layout; const upb_filedef *file; @@ -83,17 +89,17 @@ struct upb_msgdef { upb_inttable itof; upb_strtable ntof; + const upb_extrange *ext_ranges; const upb_fielddef *fields; const upb_oneofdef *oneofs; int field_count; int oneof_count; int real_oneof_count; + int ext_range_count; /* Is this a map-entry message? */ bool map_entry; upb_wellknowntype_t well_known_type; - - /* TODO(haberman): proper extension ranges (there can be multiple). */ }; struct upb_enumdef { @@ -132,6 +138,7 @@ struct upb_filedef { const upb_msgdef *msgs; const upb_enumdef *enums; const upb_fielddef *exts; + const upb_msglayout_ext **ext_layouts; const upb_symtab *symtab; int dep_count; @@ -145,6 +152,8 @@ struct upb_symtab { upb_arena *arena; upb_strtable syms; /* full_name -> packed def ptr */ upb_strtable files; /* file_name -> upb_filedef* */ + upb_inttable exts; /* upb_msglayout_ext* -> upb_fielddef* */ + upb_extreg *extreg; size_t bytes_loaded; }; @@ -518,9 +527,15 @@ const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) { } const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f) { + UPB_ASSERT(!upb_fielddef_isextension(f)); return &f->msgdef->layout->fields[f->layout_index]; } +const upb_msglayout_ext *_upb_fielddef_extlayout(const upb_fielddef *f) { + UPB_ASSERT(upb_fielddef_isextension(f)); + return f->file->ext_layouts[f->layout_index]; +} + bool upb_fielddef_issubmsg(const upb_fielddef *f) { return upb_fielddef_type(f) == UPB_TYPE_MESSAGE; } @@ -651,6 +666,10 @@ int upb_msgdef_numrealoneofs(const upb_msgdef *m) { return m->real_oneof_count; } +int upb_msgdef_extrangecount(const upb_msgdef *m) { + return m->ext_range_count; +} + int upb_msgdef_fieldcount(const upb_msgdef *m) { return m->field_count; } @@ -667,6 +686,11 @@ const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m) { return m->layout; } +const upb_extrange *upb_msgdef_extrange(const upb_msgdef *m, int i) { + UPB_ASSERT(i >= 0 && i < m->ext_range_count); + return &m->ext_ranges[i]; +} + const upb_fielddef *upb_msgdef_field(const upb_msgdef *m, int i) { UPB_ASSERT(i >= 0 && i < m->field_count); return &m->fields[i]; @@ -884,12 +908,19 @@ upb_symtab *upb_symtab_new(void) { s->bytes_loaded = 0; if (!upb_strtable_init(&s->syms, 32, s->arena) || - !upb_strtable_init(&s->files, 4, s->arena)) { - upb_arena_free(s->arena); - upb_gfree(s); - s = NULL; + !upb_strtable_init(&s->files, 4, s->arena) || + !upb_inttable_init(&s->exts, s->arena)) { + goto err; } + + s->extreg = upb_extreg_new(s->arena); + if (!s->extreg) goto err; return s; + +err: + upb_arena_free(s->arena); + upb_gfree(s); + return NULL; } const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) { @@ -898,11 +929,16 @@ const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) { unpack_def(v, UPB_DEFTYPE_MSG) : NULL; } +static const void *symtab_lookup2(const upb_symtab *s, const char *sym, + size_t size, upb_deftype_t type) { + upb_value v; + return upb_strtable_lookup2(&s->syms, sym, size, &v) ? unpack_def(v, type) + : NULL; +} + const upb_msgdef *upb_symtab_lookupmsg2(const upb_symtab *s, const char *sym, size_t len) { - upb_value v; - return upb_strtable_lookup2(&s->syms, sym, len, &v) ? - unpack_def(v, UPB_DEFTYPE_MSG) : NULL; + return symtab_lookup2(s, sym, len, UPB_DEFTYPE_MSG); } const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) { @@ -925,6 +961,11 @@ const upb_fielddef *upb_symtab_lookupext(const upb_symtab *s, const char *sym) { unpack_def(v, UPB_DEFTYPE_FIELD) : NULL; } +const upb_fielddef *upb_symtab_lookupext2(const upb_symtab *s, const char *sym, + size_t size) { + return symtab_lookup2(s, sym, size, UPB_DEFTYPE_FIELD); +} + const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name) { upb_value v; return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) @@ -955,7 +996,10 @@ typedef struct { upb_symtab *symtab; upb_filedef *file; /* File we are building. */ upb_arena *arena; /* Allocate defs here. */ - const upb_msglayout **layouts; /* NULL if we should build layouts. */ + const upb_msglayout_file *layout; /* NULL if we should build layouts. */ + int enum_count; /* Count of enums built so far. */ + int msg_count; /* Count of messages built so far. */ + int ext_count; /* Count of extensions built so far. */ upb_status *status; /* Record errors here. */ jmp_buf err; /* longjmp() on error. */ } symtab_addctx; @@ -1095,16 +1139,42 @@ static void fill_fieldlayout(upb_msglayout_field *field, const upb_fielddef *f) } if (upb_fielddef_ismap(f)) { - field->mode = _UPB_MODE_MAP; + field->mode = _UPB_MODE_MAP | (_UPB_REP_PTR << 6); } else if (upb_fielddef_isseq(f)) { - field->mode = _UPB_MODE_ARRAY; + field->mode = _UPB_MODE_ARRAY | (_UPB_REP_PTR << 6); } else { - field->mode = _UPB_MODE_SCALAR; + /* Maps descriptor type -> elem_size_lg2. */ + static const uint8_t sizes[] = { + -1, /* invalid descriptor type */ + _UPB_REP_8BYTE, /* DOUBLE */ + _UPB_REP_4BYTE, /* FLOAT */ + _UPB_REP_8BYTE, /* INT64 */ + _UPB_REP_8BYTE, /* UINT64 */ + _UPB_REP_4BYTE, /* INT32 */ + _UPB_REP_8BYTE, /* FIXED64 */ + _UPB_REP_4BYTE, /* FIXED32 */ + _UPB_REP_1BYTE, /* BOOL */ + _UPB_REP_STRVIEW, /* STRING */ + _UPB_REP_PTR, /* GROUP */ + _UPB_REP_PTR, /* MESSAGE */ + _UPB_REP_STRVIEW, /* BYTES */ + _UPB_REP_4BYTE, /* UINT32 */ + _UPB_REP_4BYTE, /* ENUM */ + _UPB_REP_4BYTE, /* SFIXED32 */ + _UPB_REP_8BYTE, /* SFIXED64 */ + _UPB_REP_4BYTE, /* SINT32 */ + _UPB_REP_8BYTE, /* SINT64 */ + }; + field->mode = _UPB_MODE_SCALAR | (sizes[field->descriptortype] << 6); } if (upb_fielddef_packed(f)) { field->mode |= _UPB_MODE_IS_PACKED; } + + if (upb_fielddef_isextension(f)) { + field->mode |= _UPB_MODE_IS_EXTENSION; + } } /* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. @@ -1115,8 +1185,8 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { upb_msg_oneof_iter oit; size_t hasbit; size_t field_count = upb_msgdef_numfields(m); - size_t submsg_count = 0; - const upb_msglayout **submsgs; + size_t sublayout_count = 0; + upb_msglayout_sub *subs; upb_msglayout_field *fields; memset(l, 0, sizeof(*l) + sizeof(_upb_fasttable_entry)); @@ -1124,18 +1194,24 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { /* Count sub-messages. */ for (size_t i = 0; i < field_count; i++) { if (upb_fielddef_issubmsg(&m->fields[i])) { - submsg_count++; + sublayout_count++; } } fields = symtab_alloc(ctx, field_count * sizeof(*fields)); - submsgs = symtab_alloc(ctx, submsg_count * sizeof(*submsgs)); + subs = symtab_alloc(ctx, sublayout_count * sizeof(*subs)); l->field_count = upb_msgdef_numfields(m); l->fields = fields; - l->submsgs = submsgs; + l->subs = subs; l->table_mask = 0; + if (upb_msgdef_extrangecount(m) > 0) { + l->ext = _UPB_MSGEXT_EXTENDABLE; + } else { + l->ext = _UPB_MSGEXT_NONE; + } + /* TODO(haberman): initialize fast tables so that reflection-based parsing * can get the same speeds as linked-in types. */ l->fasttable[0].field_parser = &fastdecode_generic; @@ -1159,7 +1235,7 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { fields[1].submsg_index = 0; if (upb_fielddef_type(val) == UPB_TYPE_MESSAGE) { - submsgs[0] = upb_fielddef_msgsubdef(val)->layout; + subs[0].submsg = upb_fielddef_msgsubdef(val)->layout; } l->field_count = 2; @@ -1178,7 +1254,7 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { */ /* Allocate hasbits and set basic field attributes. */ - submsg_count = 0; + sublayout_count = 0; for (upb_msg_field_begin(&it, m), hasbit = 0; !upb_msg_field_done(&it); upb_msg_field_next(&it)) { @@ -1189,8 +1265,8 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { if (upb_fielddef_issubmsg(f)) { const upb_msgdef *subm = upb_fielddef_msgsubdef(f); - field->submsg_index = submsg_count++; - submsgs[field->submsg_index] = subm->layout; + field->submsg_index = sublayout_count++; + subs[field->submsg_index].submsg = subm->layout; } if (upb_fielddef_haspresence(f) && !upb_fielddef_realcontainingoneof(f)) { @@ -1656,12 +1732,11 @@ static void create_fielddef( upb_strtable_insert(&m->ntof, json_name, json_size, json_v, ctx->arena); } - if (ctx->layouts) { + if (ctx->layout) { const upb_msglayout_field *fields = m->layout->fields; int count = m->layout->field_count; bool found = false; - int i; - for (i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { if (fields[i].number == field_number) { f->layout_index = i; found = true; @@ -1672,9 +1747,15 @@ static void create_fielddef( } } else { /* extension field. */ - f = (upb_fielddef*)&ctx->file->exts[ctx->file->ext_count++]; + uint16_t layout_index = ctx->ext_count++; + f = (upb_fielddef*)&ctx->file->exts[layout_index]; + f->layout_index = layout_index; f->is_extension_ = true; symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_FIELD)); + if (ctx->layout) { + UPB_ASSERT(ctx->file->ext_layouts[f->layout_index]->field.number == + field_number); + } } f->full_name = full_name; @@ -1763,7 +1844,7 @@ static void create_enumdef( name = google_protobuf_EnumDescriptorProto_name(enum_proto); check_ident(ctx, name, false); - e = (upb_enumdef*)&ctx->file->enums[ctx->file->enum_count++]; + e = (upb_enumdef*)&ctx->file->enums[ctx->enum_count++]; e->full_name = makefullname(ctx, prefix, name); symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); @@ -1816,18 +1897,23 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix, const google_protobuf_FieldDescriptorProto *const *fields; const google_protobuf_EnumDescriptorProto *const *enums; const google_protobuf_DescriptorProto *const *msgs; - size_t i, n_oneof, n_field, n; + const google_protobuf_DescriptorProto_ExtensionRange *const *ext_ranges; + size_t i, n_oneof, n_field, n_ext_range, n; upb_strview name; name = google_protobuf_DescriptorProto_name(msg_proto); check_ident(ctx, name, false); - m = (upb_msgdef*)&ctx->file->msgs[ctx->file->msg_count++]; + int msg_index = ctx->msg_count; + m = (upb_msgdef*)&ctx->file->msgs[msg_index]; m->full_name = makefullname(ctx, prefix, name); + ctx->msg_count++; symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG)); 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); CHK_OOM(upb_inttable_init(&m->itof, ctx->arena)); CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena)); @@ -1841,9 +1927,10 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix, m->map_entry = google_protobuf_MessageOptions_map_entry(options); } - if (ctx->layouts) { - m->layout = *ctx->layouts; - ctx->layouts++; + if (ctx->layout) { + /* create_fielddef() below depends on this being set. */ + m->layout = ctx->layout->msgs[msg_index]; + UPB_ASSERT(n_field == m->layout->field_count); } else { /* Allocate now (to allow cross-linking), populate later. */ m->layout = symtab_alloc( @@ -1862,6 +1949,15 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix, create_fielddef(ctx, m->full_name, m, fields[i]); } + m->ext_range_count = n_ext_range; + m->ext_ranges = symtab_alloc(ctx, sizeof(*m->ext_ranges) * n_ext_range); + for (i = 0; i < n_ext_range; i++) { + const google_protobuf_DescriptorProto_ExtensionRange *r = ext_ranges[i]; + upb_extrange *r_def = (upb_extrange*)&m->ext_ranges[i]; + r_def->start = google_protobuf_DescriptorProto_ExtensionRange_start(r); + r_def->end = google_protobuf_DescriptorProto_ExtensionRange_end(r); + } + finalize_oneofs(ctx, m); assign_msg_wellknowntype(m); upb_inttable_compact(&m->itof, ctx->arena); @@ -1873,6 +1969,11 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix, create_enumdef(ctx, m->full_name, enums[i]); } + fields = google_protobuf_DescriptorProto_extension(msg_proto, &n); + for (i = 0; i < n; i++) { + create_fielddef(ctx, m->full_name, NULL, fields[i]); + } + msgs = google_protobuf_DescriptorProto_nested_type(msg_proto, &n); for (i = 0; i < n; i++) { create_msgdef(ctx, m->full_name, msgs[i]); @@ -1929,6 +2030,22 @@ static void resolve_fielddef(symtab_addctx *ctx, const char *prefix, name = google_protobuf_FieldDescriptorProto_extendee(field_proto); f->msgdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_MSG); + + const upb_msglayout_ext *ext = ctx->file->ext_layouts[f->layout_index]; + if (ctx->layout) { + UPB_ASSERT(upb_fielddef_number(f) == ext->field.number); + } else { + upb_msglayout_ext *mut_ext = (upb_msglayout_ext*)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 = f->msgdef->layout; + mut_ext->sub.submsg = f->sub.msgdef->layout; + } + + CHK_OOM(upb_inttable_insert(&ctx->symtab->exts, (uintptr_t)ext, + upb_value_constptr(f), ctx->arena)); } if ((upb_fielddef_issubmsg(f) || f->type_ == UPB_DESCRIPTOR_TYPE_ENUM) && @@ -1987,10 +2104,26 @@ static void build_filedef( file->enums = symtab_alloc(ctx, sizeof(*file->enums) * file->enum_count); file->exts = symtab_alloc(ctx, sizeof(*file->exts) * file->ext_count); - /* In the second pass we increment these as defs are added. */ - file->msg_count = 0; - file->enum_count = 0; - file->ext_count = 0; + ctx->msg_count = 0; + ctx->enum_count = 0; + ctx->ext_count = 0; + + if (ctx->layout) { + /* We are using the ext layouts that were passed in. */ + file->ext_layouts = ctx->layout->exts; + if (ctx->layout->ext_count != file->ext_count) { + symtab_errf(ctx, "Extension count did not match layout (%d vs %d)", + ctx->layout->ext_count, file->ext_count); + } + } else { + /* We are building ext layouts from scratch. */ + file->ext_layouts = + symtab_alloc(ctx, sizeof(*file->ext_layouts) * file->ext_count); + upb_msglayout_ext *ext = symtab_alloc(ctx, sizeof(*ext) * file->ext_count); + for (int i = 0; i < file->ext_count; i++) { + file->ext_layouts[i] = &ext[i]; + } + } if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { symtab_errf(ctx, "File has no name"); @@ -2071,11 +2204,12 @@ static void build_filedef( /* Create extensions. */ exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); - file->exts = symtab_alloc(ctx, sizeof(*file->exts) * n); for (i = 0; i < n; i++) { create_fielddef(ctx, file->package, NULL, exts[i]); } + UPB_ASSERT(ctx->ext_count == file->ext_count); + /* Now that all names are in the table, build layouts and resolve refs. */ for (i = 0; i < (size_t)file->ext_count; i++) { resolve_fielddef(ctx, file->package, (upb_fielddef*)&file->exts[i]); @@ -2089,25 +2223,28 @@ static void build_filedef( } } - if (!ctx->layouts) { + if (!ctx->layout) { for (i = 0; i < (size_t)file->msg_count; i++) { const upb_msgdef *m = &file->msgs[i]; make_layout(ctx, m); } } + + CHK_OOM( + _upb_extreg_add(ctx->symtab->extreg, file->ext_layouts, file->ext_count)); } -static void remove_filedef(upb_symtab *s, upb_filedef *file) { +static void remove_filedef(symtab_addctx *ctx, upb_symtab *s, upb_filedef *file) { int i; - for (i = 0; i < file->msg_count; i++) { + for (i = 0; i < ctx->msg_count; i++) { const char *name = file->msgs[i].full_name; upb_strtable_remove(&s->syms, name, strlen(name), NULL); } - for (i = 0; i < file->enum_count; i++) { + for (i = 0; i < ctx->enum_count; i++) { const char *name = file->enums[i].full_name; upb_strtable_remove(&s->syms, name, strlen(name), NULL); } - for (i = 0; i < file->ext_count; i++) { + for (i = 0; i < ctx->ext_count; i++) { const char *name = file->exts[i].full_name; upb_strtable_remove(&s->syms, name, strlen(name), NULL); } @@ -2115,7 +2252,7 @@ static void remove_filedef(upb_symtab *s, upb_filedef *file) { static const upb_filedef *_upb_symtab_addfile( upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto, - const upb_msglayout **layouts, upb_status *status) { + const upb_msglayout_file *layout, upb_status *status) { symtab_addctx ctx; upb_strview name = google_protobuf_FileDescriptorProto_name(file_proto); @@ -2126,7 +2263,7 @@ static const upb_filedef *_upb_symtab_addfile( } ctx.symtab = s; - ctx.layouts = layouts; + ctx.layout = layout; ctx.status = status; ctx.file = NULL; ctx.arena = upb_arena_new(); @@ -2139,7 +2276,7 @@ static const upb_filedef *_upb_symtab_addfile( if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) { UPB_ASSERT(!upb_ok(status)); if (ctx.file) { - remove_filedef(s, ctx.file); + remove_filedef(&ctx, s, ctx.file); ctx.file = NULL; } } else { @@ -2198,14 +2335,16 @@ bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init) { goto err; } - if (!_upb_symtab_addfile(s, file, init->layouts, &status)) goto err; + if (!_upb_symtab_addfile(s, file, init->layout, &status)) goto err; upb_arena_free(arena); return true; err: - fprintf(stderr, "Error loading compiled-in descriptor: %s\n", - upb_status_errmsg(&status)); + fprintf(stderr, + "Error loading compiled-in descriptor for file '%s' (this should " + "never happen): %s\n", + init->filename, upb_status_errmsg(&status)); upb_arena_free(arena); return false; } @@ -2218,4 +2357,16 @@ upb_arena *_upb_symtab_arena(const upb_symtab *s) { return s->arena; } +const upb_fielddef *_upb_symtab_lookupextfield(const upb_symtab *s, + const upb_msglayout_ext *ext) { + upb_value v; + bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); + UPB_ASSERT(ok); + return upb_value_getconstptr(v); +} + +const upb_extreg *upb_symtab_extreg(const upb_symtab *s) { + return s->extreg; +} + #undef CHK_OOM diff --git a/upb/def.h b/upb/def.h index 563c946b0c..b548e2b360 100644 --- a/upb/def.h +++ b/upb/def.h @@ -56,6 +56,8 @@ struct upb_enumdef; typedef struct upb_enumdef upb_enumdef; struct upb_enumvaldef; typedef struct upb_enumvaldef upb_enumvaldef; +struct upb_extrange; +typedef struct upb_extrange upb_extrange; struct upb_fielddef; typedef struct upb_fielddef upb_fielddef; struct upb_filedef; @@ -137,6 +139,7 @@ bool upb_fielddef_haspresence(const upb_fielddef *f); const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f); const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f); const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f); +const upb_msglayout_ext *_upb_fielddef_extlayout(const upb_fielddef *f); /* upb_oneofdef ***************************************************************/ @@ -201,8 +204,10 @@ bool upb_msgdef_mapentry(const upb_msgdef *m); upb_wellknowntype_t upb_msgdef_wellknowntype(const upb_msgdef *m); bool upb_msgdef_iswrapper(const upb_msgdef *m); bool upb_msgdef_isnumberwrapper(const upb_msgdef *m); +int upb_msgdef_extrangecount(const upb_msgdef *m); int upb_msgdef_fieldcount(const upb_msgdef *m); int upb_msgdef_oneofcount(const upb_msgdef *m); +const upb_extrange *upb_msgdef_extrange(const upb_msgdef *m, int i); const upb_fielddef *upb_msgdef_field(const upb_msgdef *m, int i); const upb_oneofdef *upb_msgdef_oneof(const upb_msgdef *m, int i); const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i); @@ -258,6 +263,14 @@ bool upb_msg_oneof_iter_isequal(const upb_msg_oneof_iter *iter1, const upb_msg_oneof_iter *iter2); /* END DEPRECATED */ +/* upb_extrange ***************************************************************/ + +const google_protobuf_ExtensionRangeOptions *upb_extrange_options( + const upb_extrange *r); +bool upb_extrange_hasoptions(const upb_extrange *r); +int32_t upb_extrange_start(const upb_extrange *r); +int32_t upb_extrange_end(const upb_extrange *r); + /* upb_enumdef ****************************************************************/ typedef upb_strtable_iter upb_enum_iter; @@ -321,6 +334,8 @@ const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym); const upb_enumvaldef *upb_symtab_lookupenumval(const upb_symtab *s, const char *sym); const upb_fielddef *upb_symtab_lookupext(const upb_symtab *s, const char *sym); +const upb_fielddef *upb_symtab_lookupext2(const upb_symtab *s, const char *sym, + size_t len); const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name); const upb_filedef *upb_symtab_lookupfile2( const upb_symtab *s, const char *name, size_t len); @@ -330,11 +345,14 @@ const upb_filedef *upb_symtab_addfile( upb_status *status); size_t _upb_symtab_bytesloaded(const upb_symtab *s); upb_arena *_upb_symtab_arena(const upb_symtab *s); +const upb_fielddef *_upb_symtab_lookupextfield(const upb_symtab *s, + const upb_msglayout_ext *ext); +const upb_extreg *upb_symtab_extreg(const upb_symtab *s); /* For generated code only: loads a generated descriptor. */ typedef struct upb_def_init { struct upb_def_init **deps; /* Dependencies of this file. */ - const upb_msglayout **layouts; /* Pre-order layouts of all messages. */ + const upb_msglayout_file *layout; const char *filename; upb_strview descriptor; /* Serialized descriptor. */ } upb_def_init; diff --git a/upb/encode.c b/upb/encode.c index 6c5bfaf6ff..25f918afba 100644 --- a/upb/encode.c +++ b/upb/encode.c @@ -187,17 +187,14 @@ static void encode_message(upb_encstate *e, const upb_msg *msg, const upb_msglayout *m, size_t *size); static void encode_scalar(upb_encstate *e, const void *_field_mem, - const upb_msglayout *m, const upb_msglayout_field *f, - bool skip_zero_value) { + const upb_msglayout_sub *subs, + const upb_msglayout_field *f) { const char *field_mem = _field_mem; int wire_type; #define CASE(ctype, type, wtype, encodeval) \ { \ ctype val = *(ctype *)field_mem; \ - if (skip_zero_value && val == 0) { \ - return; \ - } \ encode_##type(e, encodeval); \ wire_type = wtype; \ break; \ @@ -231,9 +228,6 @@ static void encode_scalar(upb_encstate *e, const void *_field_mem, case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_BYTES: { upb_strview view = *(upb_strview*)field_mem; - if (skip_zero_value && view.size == 0) { - return; - } encode_bytes(e, view.data, view.size); encode_varint(e, view.size); wire_type = UPB_WIRE_TYPE_DELIMITED; @@ -242,7 +236,7 @@ static void encode_scalar(upb_encstate *e, const void *_field_mem, case UPB_DESCRIPTOR_TYPE_GROUP: { size_t size; void *submsg = *(void **)field_mem; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; + const upb_msglayout *subm = subs[f->submsg_index].submsg; if (submsg == NULL) { return; } @@ -256,7 +250,7 @@ static void encode_scalar(upb_encstate *e, const void *_field_mem, case UPB_DESCRIPTOR_TYPE_MESSAGE: { size_t size; void *submsg = *(void **)field_mem; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; + const upb_msglayout *subm = subs[f->submsg_index].submsg; if (submsg == NULL) { return; } @@ -276,7 +270,8 @@ static void encode_scalar(upb_encstate *e, const void *_field_mem, } static void encode_array(upb_encstate *e, const upb_msg *msg, - const upb_msglayout *m, const upb_msglayout_field *f) { + const upb_msglayout_sub *subs, + const upb_msglayout_field *f) { const upb_array *arr = *UPB_PTR_AT(msg, f->offset, upb_array*); bool packed = f->mode & _UPB_MODE_IS_PACKED; size_t pre_len = e->limit - e->ptr; @@ -344,7 +339,7 @@ static void encode_array(upb_encstate *e, const upb_msg *msg, case UPB_DESCRIPTOR_TYPE_GROUP: { const void *const*start = _upb_array_constptr(arr); const void *const*ptr = start + arr->len; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; + const upb_msglayout *subm = subs[f->submsg_index].submsg; if (--e->depth == 0) encode_err(e); do { size_t size; @@ -359,7 +354,7 @@ static void encode_array(upb_encstate *e, const upb_msg *msg, case UPB_DESCRIPTOR_TYPE_MESSAGE: { const void *const*start = _upb_array_constptr(arr); const void *const*ptr = start + arr->len; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; + const upb_msglayout *subm = subs[f->submsg_index].submsg; if (--e->depth == 0) encode_err(e); do { size_t size; @@ -387,17 +382,18 @@ static void encode_mapentry(upb_encstate *e, uint32_t number, const upb_msglayout_field *val_field = &layout->fields[1]; size_t pre_len = e->limit - e->ptr; size_t size; - encode_scalar(e, &ent->v, layout, val_field, false); - encode_scalar(e, &ent->k, layout, key_field, false); + encode_scalar(e, &ent->v, layout->subs, val_field); + encode_scalar(e, &ent->k, layout->subs, key_field); size = (e->limit - e->ptr) - pre_len; encode_varint(e, size); encode_tag(e, number, UPB_WIRE_TYPE_DELIMITED); } static void encode_map(upb_encstate *e, const upb_msg *msg, - const upb_msglayout *m, const upb_msglayout_field *f) { + const upb_msglayout_sub *subs, + const upb_msglayout_field *f) { const upb_map *map = *UPB_PTR_AT(msg, f->offset, const upb_map*); - const upb_msglayout *layout = m->submsgs[f->submsg_index]; + const upb_msglayout *layout = subs[f->submsg_index].submsg; UPB_ASSERT(layout->field_count == 2); if (map == NULL) return; @@ -425,28 +421,65 @@ static void encode_map(upb_encstate *e, const upb_msg *msg, } } -static void encode_scalarfield(upb_encstate *e, const char *msg, - const upb_msglayout *m, - const upb_msglayout_field *f) { - bool skip_empty = false; +static bool encode_shouldencode(upb_encstate *e, const upb_msg *msg, + const upb_msglayout_sub *subs, + const upb_msglayout_field *f) { if (f->presence == 0) { - /* Proto3 presence. */ - skip_empty = true; + /* Proto3 presence or map/array. */ + const void *mem = UPB_PTR_AT(msg, f->offset, void); + switch (f->mode >> 6) { + case _UPB_REP_1BYTE: { + char ch; + memcpy(&ch, mem, 1); + return ch != 0; + } + case _UPB_REP_4BYTE: { + uint32_t u32; + memcpy(&u32, mem, 4); + return u32 != 0; + } + case _UPB_REP_8BYTE: { + uint64_t u64; + memcpy(&u64, mem, 8); + return u64 != 0; + } + case _UPB_REP_STRVIEW: { + const upb_strview *str = (const upb_strview*)mem; + return str->size != 0; + } + default: + UPB_UNREACHABLE(); + } } else if (f->presence > 0) { /* Proto2 presence: hasbit. */ - if (!_upb_hasbit_field(msg, f)) return; + return _upb_hasbit_field(msg, f); } else { /* Field is in a oneof. */ - if (_upb_getoneofcase_field(msg, f) != f->number) return; + return _upb_getoneofcase_field(msg, f) == f->number; + } +} + +static void encode_field(upb_encstate *e, const upb_msg *msg, + const upb_msglayout_sub *subs, + const upb_msglayout_field *field) { + switch (_upb_getmode(field)) { + case _UPB_MODE_ARRAY: + encode_array(e, msg, subs, field); + break; + case _UPB_MODE_MAP: + encode_map(e, msg, subs, field); + break; + case _UPB_MODE_SCALAR: + encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field); + break; + default: + UPB_UNREACHABLE(); } - encode_scalar(e, msg + f->offset, m, f, skip_empty); } static void encode_message(upb_encstate *e, const upb_msg *msg, const upb_msglayout *m, size_t *size) { size_t pre_len = e->limit - e->ptr; - const upb_msglayout_field *f = &m->fields[m->field_count]; - const upb_msglayout_field *first = &m->fields[0]; if ((e->options & UPB_ENCODE_SKIPUNKNOWN) == 0) { size_t unknown_size; @@ -457,20 +490,26 @@ static void encode_message(upb_encstate *e, const upb_msg *msg, } } + if (m->ext != _UPB_MSGEXT_NONE) { + /* Encode all extensions together. Unlike C++, we do not attempt to keep + * these in field number order relative to normal fields or even to each + * other. */ + size_t ext_count; + const upb_msg_ext *ext = _upb_msg_getexts(msg, &ext_count); + const upb_msg_ext *end = ext + ext_count; + if (ext_count) { + for (; ext != end; ext++) { + encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); + } + } + } + + const upb_msglayout_field *f = &m->fields[m->field_count]; + const upb_msglayout_field *first = &m->fields[0]; while (f != first) { f--; - switch (_upb_getmode(f)) { - case _UPB_MODE_ARRAY: - encode_array(e, msg, m, f); - break; - case _UPB_MODE_MAP: - encode_map(e, msg, m, f); - break; - case _UPB_MODE_SCALAR: - encode_scalarfield(e, msg, m, f); - break; - default: - UPB_UNREACHABLE(); + if (encode_shouldencode(e, msg, m->subs, f)) { + encode_field(e, msg, m->subs, f); } } diff --git a/upb/json_decode.c b/upb/json_decode.c index f7d1c5b2c4..cc8139e455 100644 --- a/upb/json_decode.c +++ b/upb/json_decode.c @@ -45,7 +45,7 @@ typedef struct { const char *ptr, *end; upb_arena *arena; /* TODO: should we have a tmp arena for tmp data? */ - const upb_symtab *any_pool; + const upb_symtab *symtab; int depth; upb_status *status; jmp_buf err; @@ -931,7 +931,20 @@ static void jsondec_field(jsondec *d, upb_msg *msg, const upb_msgdef *m) { name = jsondec_string(d); jsondec_entrysep(d); - f = upb_msgdef_lookupjsonname(m, name.data, name.size); + + if (name.size >= 2 && name.data[0] == '[' && + name.data[name.size - 1] == ']') { + f = upb_symtab_lookupext2(d->symtab, name.data + 1, name.size - 2); + if (f && upb_fielddef_containingtype(f) != m) { + jsondec_errf( + d, "Extension %s extends message %s, but was seen in message %s", + upb_fielddef_fullname(f), + upb_msgdef_fullname(upb_fielddef_containingtype(f)), + upb_msgdef_fullname(m)); + } + } else { + f = upb_msgdef_lookupjsonname(m, name.data, name.size); + } if (!f) { if ((d->options & UPB_JSONDEC_IGNOREUNKNOWN) == 0) { @@ -1335,7 +1348,7 @@ static const upb_msgdef *jsondec_typeurl(jsondec *d, upb_msg *msg, } ptr++; - type_m = upb_symtab_lookupmsg2(d->any_pool, ptr, end - ptr); + type_m = upb_symtab_lookupmsg2(d->symtab, ptr, end - ptr); if (!type_m) { jsondec_err(d, "Type was not found"); @@ -1453,7 +1466,7 @@ static void jsondec_wellknown(jsondec *d, upb_msg *msg, const upb_msgdef *m) { } bool upb_json_decode(const char *buf, size_t size, upb_msg *msg, - const upb_msgdef *m, const upb_symtab *any_pool, + const upb_msgdef *m, const upb_symtab *symtab, int options, upb_arena *arena, upb_status *status) { jsondec d; @@ -1462,7 +1475,7 @@ bool upb_json_decode(const char *buf, size_t size, upb_msg *msg, d.ptr = buf; d.end = buf + size; d.arena = arena; - d.any_pool = any_pool; + d.symtab = symtab; d.status = status; d.options = options; d.depth = 64; diff --git a/upb/json_decode.h b/upb/json_decode.h index 9ace310454..ea0d2d7c16 100644 --- a/upb/json_decode.h +++ b/upb/json_decode.h @@ -39,7 +39,7 @@ enum { }; bool upb_json_decode(const char *buf, size_t size, upb_msg *msg, - const upb_msgdef *m, const upb_symtab *any_pool, + const upb_msgdef *m, const upb_symtab *symtab, int options, upb_arena *arena, upb_status *status); #ifdef __cplusplus diff --git a/upb/json_encode.c b/upb/json_encode.c index b7d6fa9de8..bdcc9760ab 100644 --- a/upb/json_encode.c +++ b/upb/json_encode.c @@ -670,15 +670,19 @@ static void jsonenc_fieldval(jsonenc *e, const upb_fielddef *f, upb_msgval val, bool *first) { const char *name; - if (e->options & UPB_JSONENC_PROTONAMES) { - name = upb_fielddef_name(f); + jsonenc_putsep(e, ",", first); + + if (upb_fielddef_isextension(f)) { + jsonenc_printf(e, "\"[%s]\":", upb_fielddef_fullname(f)); } else { - name = upb_fielddef_jsonname(f); + if (e->options & UPB_JSONENC_PROTONAMES) { + name = upb_fielddef_name(f); + } else { + name = upb_fielddef_jsonname(f); + } + jsonenc_printf(e, "\"%s\":", name); } - jsonenc_putsep(e, ",", first); - jsonenc_printf(e, "\"%s\":", name); - if (upb_fielddef_ismap(f)) { jsonenc_map(e, val.map_val, f); } else if (upb_fielddef_isseq(f)) { diff --git a/upb/msg.c b/upb/msg.c index ad2d547e21..62580baa89 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -137,6 +137,18 @@ const upb_msg_ext *_upb_msg_getext(const upb_msg *msg, return NULL; } +void _upb_msg_clearext(upb_msg *msg, const upb_msglayout_ext *ext_l) { + upb_msg_internal *in = upb_msg_getinternal(msg); + if (!in->internal) return; + const upb_msg_ext *base = + UPB_PTR_AT(in->internal, in->internal->ext_begin, void); + upb_msg_ext *ext = (void*)_upb_msg_getext(msg, ext_l); + if (ext) { + *ext = *base; + in->internal->ext_begin += sizeof(upb_msg_ext); + } +} + upb_msg_ext *_upb_msg_getorcreateext(upb_msg *msg, const upb_msglayout_ext *e, upb_arena *arena) { upb_msg_ext *ext = (upb_msg_ext*)_upb_msg_getext(msg, e); @@ -361,14 +373,15 @@ upb_extreg *upb_extreg_new(upb_arena *arena) { return r; } -bool _upb_extreg_add(upb_extreg *r, const upb_msglayout_ext *e, size_t count) { +bool _upb_extreg_add(upb_extreg *r, const upb_msglayout_ext **e, size_t count) { char buf[EXTREG_KEY_SIZE]; - const upb_msglayout_ext *start = e; - const upb_msglayout_ext *end = e + count; + const upb_msglayout_ext **start = e; + const upb_msglayout_ext **end = e + count; for (; e < end; e++) { - extreg_key(buf, e->extendee, e->field.number); + const upb_msglayout_ext *ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, - upb_value_constptr(e), r->arena)) { + upb_value_constptr(ext), r->arena)) { goto failure; } } @@ -377,15 +390,15 @@ bool _upb_extreg_add(upb_extreg *r, const upb_msglayout_ext *e, size_t count) { failure: /* Back out the entries previously added. */ for (end = e, e = start; e < end; e++) { - extreg_key(buf, e->extendee, e->field.number); + const upb_msglayout_ext *ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); upb_strtable_remove(&r->exts, buf, EXTREG_KEY_SIZE, NULL); } return false; } -const upb_msglayout_field *_upb_extreg_get(const upb_extreg *r, - const upb_msglayout *l, - uint32_t num) { +const upb_msglayout_ext *_upb_extreg_get(const upb_extreg *r, + const upb_msglayout *l, uint32_t num) { char buf[EXTREG_KEY_SIZE]; upb_value v; extreg_key(buf, l, num); diff --git a/upb/msg_internal.h b/upb/msg_internal.h index 24517002ea..7b9267e01e 100644 --- a/upb/msg_internal.h +++ b/upb/msg_internal.h @@ -1,3 +1,30 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + /* ** Our memory representation for parsing tables and messages themselves. ** Functions in this file are used by generated code and possibly reflection. @@ -42,7 +69,7 @@ typedef struct { int16_t presence; /* If >0, hasbit_index. If <0, ~oneof_index. */ uint16_t submsg_index; /* undefined if descriptortype != MESSAGE or GROUP. */ uint8_t descriptortype; - int8_t mode; /* upb_fieldmode, with flags from upb_labelflags */ + uint8_t mode; /* upb_fieldmode | upb_labelflags | (upb_rep << 6) */ } upb_msglayout_field; typedef enum { @@ -54,6 +81,22 @@ typedef enum { /* Extra flags on the mode field. */ enum upb_labelflags { _UPB_MODE_IS_PACKED = 4, + _UPB_MODE_IS_EXTENSION = 8, +}; + +/* Representation in the message. Derivable from descriptortype and mode, but + * fast access helps the serializer. */ +enum upb_rep { + _UPB_REP_1BYTE = 0, + _UPB_REP_4BYTE = 1, + _UPB_REP_8BYTE = 2, + _UPB_REP_STRVIEW = 3, + +#if UINTPTR_MAX == 0xffffffff + _UPB_REP_PTR = _UPB_REP_4BYTE, +#else + _UPB_REP_PTR = _UPB_REP_8BYTE, +#endif }; UPB_INLINE upb_fieldmode _upb_getmode(const upb_msglayout_field *field) { @@ -82,14 +125,25 @@ typedef struct { _upb_field_parser *field_parser; } _upb_fasttable_entry; +typedef union { + const struct upb_msglayout *submsg; + // TODO: const upb_enumlayout *subenum; +} upb_msglayout_sub; + +typedef enum { + _UPB_MSGEXT_NONE = 0, // Non-extendable message. + _UPB_MSGEXT_EXTENDABLE = 1, // Normal extendable message. + // TODO: MessageSet +} upb_msgext_mode; + struct upb_msglayout { - const struct upb_msglayout *const* submsgs; + const upb_msglayout_sub *subs; const upb_msglayout_field *fields; /* Must be aligned to sizeof(void*). Doesn't include internal members like * unknown fields, extension dict, pointer to msglayout, etc. */ uint16_t size; uint16_t field_count; - bool extendable; + uint8_t ext; // upb_msgext_mode, declared as uint8_t so sizeof(ext) == 1 uint8_t dense_below; uint8_t table_mask; /* To constant-initialize the tables of variable length, we need a flexible @@ -100,22 +154,28 @@ struct upb_msglayout { typedef struct { upb_msglayout_field field; const upb_msglayout *extendee; - const upb_msglayout *submsg; /* NULL for non-submessage fields. */ + upb_msglayout_sub sub; /* NULL unless submessage or proto2 enum */ } upb_msglayout_ext; +typedef struct { + const upb_msglayout **msgs; + const upb_msglayout_ext **exts; + int msg_count; + int ext_count; +} upb_msglayout_file; + /** upb_extreg ****************************************************************/ /* Adds the given extension info for message type |l| and field number |num| * into the registry. Returns false if this message type and field number were * already in the map, or if memory allocation fails. */ -bool _upb_extreg_add(upb_extreg *r, const upb_msglayout_ext *e, size_t count); +bool _upb_extreg_add(upb_extreg *r, const upb_msglayout_ext **e, size_t count); /* Looks up the extension (if any) defined for message type |l| and field * number |num|. If an extension was found, copies the field info into |*ext| * and returns true. Otherwise returns false. */ -const upb_msglayout_field *_upb_extreg_get(const upb_extreg *r, - const upb_msglayout *l, - uint32_t num); +const upb_msglayout_ext *_upb_extreg_get(const upb_extreg *r, + const upb_msglayout *l, uint32_t num); /** upb_msg *******************************************************************/ @@ -216,6 +276,8 @@ const upb_msg_ext *_upb_msg_getexts(const upb_msg *msg, size_t *count); const upb_msg_ext *_upb_msg_getext(const upb_msg *msg, const upb_msglayout_ext *ext); +void _upb_msg_clearext(upb_msg *msg, const upb_msglayout_ext *ext); + /** Hasbit access *************************************************************/ UPB_INLINE bool _upb_hasbit(const upb_msg *msg, size_t idx) { diff --git a/upb/reflection.c b/upb/reflection.c index b562190e30..989ab3af1a 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -108,15 +108,20 @@ static upb_msgval _upb_msg_getraw(const upb_msg *msg, const upb_fielddef *f) { } bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f) { - const upb_msglayout_field *field = upb_fielddef_layout(f); - if (in_oneof(field)) { - return _upb_getoneofcase_field(msg, field) == field->number; - } else if (field->presence > 0) { - return _upb_hasbit_field(msg, field); + if (upb_fielddef_isextension(f)) { + const upb_msglayout_ext *ext = _upb_fielddef_extlayout(f); + return _upb_msg_getext(msg, ext) != NULL; } else { - UPB_ASSERT(field->descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || - field->descriptortype == UPB_DESCRIPTOR_TYPE_GROUP); - return _upb_msg_getraw(msg, f).msg_val != NULL; + const upb_msglayout_field *field = upb_fielddef_layout(f); + if (in_oneof(field)) { + return _upb_getoneofcase_field(msg, field) == field->number; + } else if (field->presence > 0) { + return _upb_hasbit_field(msg, field); + } else { + UPB_ASSERT(field->descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || + field->descriptortype == UPB_DESCRIPTOR_TYPE_GROUP); + return _upb_msg_getraw(msg, f).msg_val != NULL; + } } } @@ -136,73 +141,92 @@ const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg, } upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) { - if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) { + if (upb_fielddef_isextension(f)) { + const upb_msg_ext *ext = _upb_msg_getext(msg, _upb_fielddef_extlayout(f)); + if (ext) { + upb_msgval val; + memcpy(&val, &ext->data, sizeof(val)); + return val; + } else if (upb_fielddef_isseq(f)) { + return (upb_msgval){.array_val = NULL}; + } + } else if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) { return _upb_msg_getraw(msg, f); - } else { - return upb_fielddef_default(f); } + return upb_fielddef_default(f); } upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, upb_arena *a) { - const upb_msglayout_field *field = upb_fielddef_layout(f); - upb_mutmsgval ret; - char *mem = UPB_PTR_AT(msg, field->offset, char); - bool wrong_oneof = - in_oneof(field) && _upb_getoneofcase_field(msg, field) != field->number; + assert(upb_fielddef_issubmsg(f) || upb_fielddef_isseq(f)); + if (upb_fielddef_haspresence(f) && !upb_msg_has(msg, f)) { + // We need to skip the upb_msg_get() call in this case. + goto make; + } - memcpy(&ret, mem, sizeof(void*)); + upb_msgval val = upb_msg_get(msg, f); + if (val.array_val) { + return (upb_mutmsgval){.array = (upb_array*)val.array_val}; + } - if (a && (!ret.msg || wrong_oneof)) { - if (upb_fielddef_ismap(f)) { - const upb_msgdef *entry = upb_fielddef_msgsubdef(f); - const upb_fielddef *key = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); - const upb_fielddef *value = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); - ret.map = upb_map_new(a, upb_fielddef_type(key), upb_fielddef_type(value)); - } else if (upb_fielddef_isseq(f)) { - ret.array = upb_array_new(a, upb_fielddef_type(f)); - } else { - UPB_ASSERT(upb_fielddef_issubmsg(f)); - ret.msg = upb_msg_new(upb_fielddef_msgsubdef(f), a); - } + upb_mutmsgval ret; +make: + if (!a) return (upb_mutmsgval){.array = NULL}; + if (upb_fielddef_ismap(f)) { + const upb_msgdef *entry = upb_fielddef_msgsubdef(f); + const upb_fielddef *key = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); + const upb_fielddef *value = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); + ret.map = upb_map_new(a, upb_fielddef_type(key), upb_fielddef_type(value)); + } else if (upb_fielddef_isseq(f)) { + ret.array = upb_array_new(a, upb_fielddef_type(f)); + } else { + UPB_ASSERT(upb_fielddef_issubmsg(f)); + ret.msg = upb_msg_new(upb_fielddef_msgsubdef(f), a); + } - memcpy(mem, &ret, sizeof(void*)); + val.array_val = ret.array; + upb_msg_set(msg, f, val, a); - if (wrong_oneof) { - *_upb_oneofcase_field(msg, field) = field->number; - } else if (field->presence > 0) { - _upb_sethas_field(msg, field); - } - } return ret; } -void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, +bool upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, upb_arena *a) { - const upb_msglayout_field *field = upb_fielddef_layout(f); - char *mem = UPB_PTR_AT(msg, field->offset, char); - UPB_UNUSED(a); /* We reserve the right to make set insert into a map. */ - memcpy(mem, &val, get_field_size(field)); - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (in_oneof(field)) { - *_upb_oneofcase_field(msg, field) = field->number; + if (upb_fielddef_isextension(f)) { + upb_msg_ext *ext = + _upb_msg_getorcreateext(msg, _upb_fielddef_extlayout(f), a); + if (!ext) return false; + memcpy(&ext->data, &val, sizeof(val)); + } else { + const upb_msglayout_field *field = upb_fielddef_layout(f); + char *mem = UPB_PTR_AT(msg, field->offset, char); + memcpy(mem, &val, get_field_size(field)); + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (in_oneof(field)) { + *_upb_oneofcase_field(msg, field) = field->number; + } } + return true; } void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f) { - const upb_msglayout_field *field = upb_fielddef_layout(f); - char *mem = UPB_PTR_AT(msg, field->offset, char); - - if (field->presence > 0) { - _upb_clearhas_field(msg, field); - } else if (in_oneof(field)) { - uint32_t *oneof_case = _upb_oneofcase_field(msg, field); - if (*oneof_case != field->number) return; - *oneof_case = 0; - } + if (upb_fielddef_isextension(f)) { + _upb_msg_clearext(msg, _upb_fielddef_extlayout(f)); + } else { + const upb_msglayout_field *field = upb_fielddef_layout(f); + char *mem = UPB_PTR_AT(msg, field->offset, char); + + if (field->presence > 0) { + _upb_clearhas_field(msg, field); + } else if (in_oneof(field)) { + uint32_t *oneof_case = _upb_oneofcase_field(msg, field); + if (*oneof_case != field->number) return; + *oneof_case = 0; + } - memset(mem, 0, get_field_size(field)); + memset(mem, 0, get_field_size(field)); + } } void upb_msg_clear(upb_msg *msg, const upb_msgdef *m) { @@ -212,10 +236,12 @@ void upb_msg_clear(upb_msg *msg, const upb_msgdef *m) { bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m, const upb_symtab *ext_pool, const upb_fielddef **out_f, upb_msgval *out_val, size_t *iter) { - int i = *iter; - int n = upb_msgdef_fieldcount(m); + size_t i = *iter; + size_t n = upb_msgdef_fieldcount(m); const upb_msgval zero = {0}; UPB_UNUSED(ext_pool); + + /* Iterate over normal fields, returning the first one that is set. */ while (++i < n) { const upb_fielddef *f = upb_msgdef_field(m, i); upb_msgval val = _upb_msg_getraw(msg, f); @@ -245,6 +271,20 @@ bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m, *iter = i; return true; } + + if (ext_pool) { + /* Return any extensions that are set. */ + size_t count; + const upb_msg_ext *ext = _upb_msg_getexts(msg, &count); + if (i - n < count) { + ext += count - 1 - (i - n); + memcpy(out_val, &ext->data, sizeof(*out_val)); + *out_f = _upb_symtab_lookupextfield(ext_pool, ext->ext); + *iter = i; + return true; + } + } + *iter = i; return false; } diff --git a/upb/reflection.h b/upb/reflection.h index f0eb0d4fb9..5b8f5c2ce7 100644 --- a/upb/reflection.h +++ b/upb/reflection.h @@ -82,9 +82,10 @@ const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg, /* Sets the given field to the given value. For a msg/array/map/string, the * value must be in the same arena. */ -void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, +bool upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, upb_arena *a); + /* Clears any field presence and sets the value back to its default. */ void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f); diff --git a/upbc/BUILD b/upbc/BUILD index 29bb3983c2..8fd69901cb 100644 --- a/upbc/BUILD +++ b/upbc/BUILD @@ -54,6 +54,7 @@ cc_binary( ":common", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/strings", "@com_google_protobuf//:protobuf", "@com_google_protobuf//:protoc_lib", diff --git a/upbc/common.cc b/upbc/common.cc index d2df929c9d..0f2d643d12 100644 --- a/upbc/common.cc +++ b/upbc/common.cc @@ -31,14 +31,6 @@ namespace { namespace protobuf = ::google::protobuf; -void AddMessages(const protobuf::Descriptor* message, - std::vector<const protobuf::Descriptor*>* messages) { - messages->push_back(message); - for (int i = 0; i < message->nested_type_count(); i++) { - AddMessages(message->nested_type(i), messages); - } -} - } // namespace std::string StripExtension(absl::string_view fname) { @@ -69,21 +61,16 @@ void EmitFileWarning(const protobuf::FileDescriptor* file, Output& output) { file->name()); } -std::vector<const protobuf::Descriptor*> SortedMessages( - const protobuf::FileDescriptor* file) { - std::vector<const protobuf::Descriptor*> messages; - for (int i = 0; i < file->message_type_count(); i++) { - AddMessages(file->message_type(i), &messages); - } - return messages; -} - std::string MessageName(const protobuf::Descriptor* descriptor) { return ToCIdent(descriptor->full_name()); } -std::string MessageInit(const protobuf::Descriptor* descriptor) { - return MessageName(descriptor) + "_msginit"; +std::string FileLayoutName(const google::protobuf::FileDescriptor* file) { + return ToCIdent(file->name()) + "_upb_file_layout"; +} + +std::string HeaderFilename(const google::protobuf::FileDescriptor* file) { + return StripExtension(file->name()) + ".upb.h"; } } // namespace upbc diff --git a/upbc/common.h b/upbc/common.h index 1867ae0331..917d850ff2 100644 --- a/upbc/common.h +++ b/upbc/common.h @@ -82,10 +82,9 @@ std::string ToCIdent(absl::string_view str); std::string ToPreproc(absl::string_view str); void EmitFileWarning(const google::protobuf::FileDescriptor* file, Output& output); -std::vector<const google::protobuf::Descriptor*> SortedMessages( - const google::protobuf::FileDescriptor* file); -std::string MessageInit(const google::protobuf::Descriptor* descriptor); std::string MessageName(const google::protobuf::Descriptor* descriptor); +std::string FileLayoutName(const google::protobuf::FileDescriptor* file); +std::string HeaderFilename(const google::protobuf::FileDescriptor* file); } // namespace upbc diff --git a/upbc/protoc-gen-upb.cc b/upbc/protoc-gen-upb.cc index a68a691bd8..2de85b5f4c 100644 --- a/upbc/protoc-gen-upb.cc +++ b/upbc/protoc-gen-upb.cc @@ -26,6 +26,7 @@ #include <memory> #include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" #include "absl/strings/ascii.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/code_generator.h" @@ -42,14 +43,31 @@ namespace { namespace protoc = ::google::protobuf::compiler; namespace protobuf = ::google::protobuf; -std::string HeaderFilename(std::string proto_filename) { - return StripExtension(proto_filename) + ".upb.h"; +std::string SourceFilename(const google::protobuf::FileDescriptor* file) { + return StripExtension(file->name()) + ".upb.c"; } -std::string SourceFilename(std::string proto_filename) { - return StripExtension(proto_filename) + ".upb.c"; +std::string MessageInit(const protobuf::Descriptor* descriptor) { + return MessageName(descriptor) + "_msginit"; } +std::string ExtensionIdentBase(const protobuf::FieldDescriptor* ext) { + assert(ext->is_extension()); + std::string ext_scope; + if (ext->extension_scope()) { + return MessageName(ext->extension_scope()); + } else { + return ToCIdent(ext->file()->package()); + } +} + +std::string ExtensionLayout(const google::protobuf::FieldDescriptor* ext) { + return absl::StrCat(ExtensionIdentBase(ext), "_", ext->name(), "_ext"); +} + +const char *kMessagesInit = "messages_layout"; +const char *kExtensionsInit = "extensions_layout"; + void AddEnums(const protobuf::Descriptor* message, std::vector<const protobuf::EnumDescriptor*>* enums) { for (int i = 0; i < message->enum_type_count(); i++) { @@ -79,6 +97,56 @@ std::vector<const protobuf::EnumDescriptor*> SortedEnums( return enums; } +void AddMessages(const protobuf::Descriptor* message, + std::vector<const protobuf::Descriptor*>* messages) { + messages->push_back(message); + for (int i = 0; i < message->nested_type_count(); i++) { + AddMessages(message->nested_type(i), messages); + } +} + +// Ordering must match upb/def.c! +// +// The ordering is significant because each upb_msgdef* will point at the +// corresponding upb_msglayout and we just iterate through the list without +// any search or lookup. +std::vector<const protobuf::Descriptor*> SortedMessages( + const protobuf::FileDescriptor* file) { + std::vector<const protobuf::Descriptor*> messages; + for (int i = 0; i < file->message_type_count(); i++) { + AddMessages(file->message_type(i), &messages); + } + return messages; +} + +void AddExtensionsFromMessage( + const protobuf::Descriptor* message, + std::vector<const protobuf::FieldDescriptor*>* exts) { + for (int i = 0; i < message->extension_count(); i++) { + exts->push_back(message->extension(i)); + } + for (int i = 0; i < message->nested_type_count(); i++) { + AddExtensionsFromMessage(message->nested_type(i), exts); + } +} + +// Ordering must match upb/def.c! +// +// The ordering is significant because each upb_fielddef* will point at the +// corresponding upb_msglayout_ext and we just iterate through the list without +// any search or lookup. +std::vector<const protobuf::FieldDescriptor*> SortedExtensions( + const protobuf::FileDescriptor* file) { + std::vector<const protobuf::FieldDescriptor*> ret; + for (int i = 0; i < file->message_type_count(); i++) { + AddExtensionsFromMessage(file->message_type(i), &ret); + } + for (int i = 0; i < file->extension_count(); i++) { + ret.push_back(file->extension(i)); + } + return ret; +} + std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder( const protobuf::Descriptor* message) { std::vector<const protobuf::FieldDescriptor*> fields; @@ -180,6 +248,29 @@ std::string SizeLg2(const protobuf::FieldDescriptor* field) { } } +std::string SizeRep(const protobuf::FieldDescriptor* field) { + switch (field->cpp_type()) { + case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + return "_UPB_REP_PTR"; + case protobuf::FieldDescriptor::CPPTYPE_ENUM: + case protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case protobuf::FieldDescriptor::CPPTYPE_INT32: + case protobuf::FieldDescriptor::CPPTYPE_UINT32: + return "_UPB_REP_4BYTE"; + case protobuf::FieldDescriptor::CPPTYPE_BOOL: + return "_UPB_REP_1BYTE"; + case protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case protobuf::FieldDescriptor::CPPTYPE_INT64: + case protobuf::FieldDescriptor::CPPTYPE_UINT64: + return "_UPB_REP_8BYTE"; + case protobuf::FieldDescriptor::CPPTYPE_STRING: + return "_UPB_REP_STRVIEW"; + default: + fprintf(stderr, "Unexpected type"); + abort(); + } +} + std::string FieldDefault(const protobuf::FieldDescriptor* field) { switch (field->cpp_type()) { case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: @@ -239,6 +330,34 @@ void DumpEnumValues(const protobuf::EnumDescriptor* desc, Output& output) { } } +void GenerateExtensionInHeader(const protobuf::FieldDescriptor* ext, + Output& output) { + output( + "UPB_INLINE bool $0_has_$1(const struct $2 *msg) { " + "return _upb_msg_getext(msg, &$3) != NULL; }\n", + ExtensionIdentBase(ext), ext->name(), MessageName(ext->containing_type()), + ExtensionLayout(ext)); + + if (ext->is_repeated()) { + } else if (ext->message_type()) { + output( + "UPB_INLINE $0 $1_$2(const struct $3 *msg) { " + "const upb_msg_ext *ext = _upb_msg_getext(msg, &$4); " + "UPB_ASSERT(ext); return *UPB_PTR_AT(&ext->data, 0, $0); }\n", + CTypeConst(ext), ExtensionIdentBase(ext), ext->name(), + MessageName(ext->containing_type()), ExtensionLayout(ext), + FieldDefault(ext)); + } else { + output( + "UPB_INLINE $0 $1_$2(const struct $3 *msg) { " + "const upb_msg_ext *ext = _upb_msg_getext(msg, &$4); " + "return ext ? *UPB_PTR_AT(&ext->data, 0, $0) : $5; }\n", + CTypeConst(ext), ExtensionIdentBase(ext), ext->name(), + MessageName(ext->containing_type()), ExtensionLayout(ext), + FieldDefault(ext)); + } +} + void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output) { MessageLayout layout(message); @@ -524,11 +643,10 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { ToPreproc(file->name())); for (int i = 0; i < file->public_dependency_count(); i++) { - const auto& name = file->public_dependency(i)->name(); if (i == 0) { output("/* Public Imports. */\n"); } - output("#include \"$0\"\n", HeaderFilename(name)); + output("#include \"$0\"\n", HeaderFilename(file)); if (i == file->public_dependency_count() - 1) { output("\n"); } @@ -544,6 +662,8 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { const std::vector<const protobuf::Descriptor*> this_file_messages = SortedMessages(file); + const std::vector<const protobuf::FieldDescriptor*> this_file_exts = + SortedExtensions(file); // Forward-declare types defined in this file. for (auto message : this_file_messages) { @@ -555,6 +675,9 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { for (auto message : this_file_messages) { output("extern const upb_msglayout $0;\n", MessageInit(message)); } + for (auto ext : this_file_exts) { + output("extern const upb_msglayout_ext $0;\n", ExtensionLayout(ext)); + } // Forward-declare types not in this file, but used as submessages. // Order by full name for consistent ordering. @@ -570,6 +693,12 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { } } } + for (auto ext : this_file_exts) { + if (ext->file() != ext->containing_type()->file()) { + forward_messages[ext->containing_type()->full_name()] = + ext->containing_type(); + } + } for (const auto& pair : forward_messages) { output("struct $0;\n", MessageName(pair.second)); } @@ -596,6 +725,12 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { GenerateMessageInHeader(message, output); } + for (auto ext : this_file_exts) { + GenerateExtensionInHeader(ext, output); + } + + output("extern const upb_msglayout_file $0;\n\n", FileLayoutName(file)); + output( "#ifdef __cplusplus\n" "} /* extern \"C\" */\n" @@ -853,20 +988,28 @@ void WriteField(const protobuf::FieldDescriptor* field, absl::string_view offset, absl::string_view presence, int submsg_index, Output& output) { std::string mode; + std::string rep; if (field->is_map()) { mode = "_UPB_MODE_MAP"; + rep = "_UPB_REP_PTR"; } else if (field->is_repeated()) { mode = "_UPB_MODE_ARRAY"; + rep = "_UPB_REP_PTR"; } else { mode = "_UPB_MODE_SCALAR"; + rep = SizeRep(field); } if (field->is_packed()) { absl::StrAppend(&mode, " | _UPB_MODE_IS_PACKED"); } - output("{$0, $1, $2, $3, $4, $5}", field->number(), offset, presence, - submsg_index, TableDescriptorType(field), mode); + if (field->is_extension()) { + absl::StrAppend(&mode, " | _UPB_MODE_IS_EXTENSION"); + } + + output("{$0, $1, $2, $3, $4, $5 | ($6 << 6)}", field->number(), offset, + presence, submsg_index, TableDescriptorType(field), mode, rep); } // Writes a single field into a .upb.c source file. @@ -913,11 +1056,11 @@ void WriteMessage(const protobuf::Descriptor* message, Output& output, // "submsgs" array for every strongly-connected component. std::string submsgs_array_name = msg_name + "_submsgs"; submsgs_array_ref = "&" + submsgs_array_name + "[0]"; - output("static const upb_msglayout *const $0[$1] = {\n", + output("static const upb_msglayout_sub $0[$1] = {\n", submsgs_array_name, submsg_array.submsgs().size()); for (auto submsg : submsg_array.submsgs()) { - output(" &$0,\n", MessageInit(submsg)); + output(" {.submsg = &$0},\n", MessageInit(submsg)); } output("};\n\n"); @@ -960,12 +1103,19 @@ void WriteMessage(const protobuf::Descriptor* message, Output& output, table_mask = (table.size() - 1) << 3; } + std::string msgext = "_UPB_MSGEXT_NONE"; + + if (message->extension_range_count()) { + msgext = "_UPB_MSGEXT_EXTENDABLE"; + } + output("const upb_msglayout $0 = {\n", MessageInit(message)); output(" $0,\n", submsgs_array_ref); output(" $0,\n", fields_array_ref); - output(" $0, $1, $2, $3, $4,\n", GetSizeInit(layout.message_size()), + output(" $0, $1, $2, $3, $4,\n", + GetSizeInit(layout.message_size()), field_number_order.size(), - "false", // TODO: extendable + msgext, dense_below, table_mask ); @@ -980,11 +1130,74 @@ void WriteMessage(const protobuf::Descriptor* message, Output& output, output("};\n\n"); } -void WriteMessages(const protobuf::FileDescriptor* file, Output& output, +void WriteExtension(const protobuf::FieldDescriptor* ext, Output& output) { + output("const upb_msglayout_ext $0 = {\n ", ExtensionLayout(ext)); + WriteField(ext, "0", "0", 0, output); + output(",\n"); + output(" &$0,\n", MessageInit(ext->containing_type())); + if (ext->message_type()) { + output(" {.submsg = &$0},\n", MessageInit(ext->message_type())); + } else { + output(" {.submsg = NULL},\n"); + } + output("\n};\n"); +} + +int WriteMessages(const protobuf::FileDescriptor* file, Output& output, bool fasttable_enabled) { - for (auto* message : SortedMessages(file)) { + std::vector<const protobuf::Descriptor*> file_messages = + SortedMessages(file); + + if (file_messages.empty()) return 0; + + for (auto message : file_messages) { WriteMessage(message, output, fasttable_enabled); } + + output("static const upb_msglayout *$0[$1] = {\n", kMessagesInit, + file_messages.size()); + for (auto message : file_messages) { + output(" &$0,\n", MessageInit(message)); + } + output("};\n"); + output("\n"); + return file_messages.size(); +} + +int WriteExtensions(const protobuf::FileDescriptor* file, Output& output) { + auto exts = SortedExtensions(file); + absl::flat_hash_set<const protobuf::Descriptor*> forward_decls; + + if (exts.empty()) return 0; + + for (auto ext : exts) { + forward_decls.insert(ext->containing_type()); + if (ext->message_type()) { + forward_decls.insert(ext->message_type()); + } + } + + for (auto ext : exts) { + WriteExtension(ext, output); + } + + for (auto decl : forward_decls) { + output("extern const upb_msglayout $0;\n", MessageInit(decl)); + } + + output( + "\n" + "static const upb_msglayout_ext *$0[$1] = {\n", + kExtensionsInit, exts.size()); + + for (auto ext : exts) { + output(" &$0,\n", ExtensionLayout(ext)); + } + + output( + "};\n" + "\n"); + return exts.size(); } // Writes a .upb.c source file. @@ -996,10 +1209,10 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output, "#include <stddef.h>\n" "#include \"upb/msg_internal.h\"\n" "#include \"$0\"\n", - HeaderFilename(file->name())); + HeaderFilename(file)); for (int i = 0; i < file->dependency_count(); i++) { - output("#include \"$0\"\n", HeaderFilename(file->dependency(i)->name())); + output("#include \"$0\"\n", HeaderFilename(file->dependency(i))); } output( @@ -1007,7 +1220,15 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output, "#include \"upb/port_def.inc\"\n" "\n"); - WriteMessages(file, output, fasttable_enabled); + int msg_count = WriteMessages(file, output, fasttable_enabled); + int ext_count = WriteExtensions(file, output); + + output("const upb_msglayout_file $0 = {\n", FileLayoutName(file)); + output(" $0,\n", msg_count ? kMessagesInit : "NULL"); + output(" $0,\n", ext_count ? kExtensionsInit : "NULL"); + output(" $0,\n", msg_count); + output(" $0,\n", ext_count); + output("};\n\n"); output("#include \"upb/port_undef.inc\"\n"); output("\n"); @@ -1040,10 +1261,10 @@ bool Generator::Generate(const protobuf::FileDescriptor* file, } } - Output h_output(context->Open(HeaderFilename(file->name()))); + Output h_output(context->Open(HeaderFilename(file))); WriteHeader(file, h_output); - Output c_output(context->Open(SourceFilename(file->name()))); + Output c_output(context->Open(SourceFilename(file))); WriteSource(file, c_output, fasttable_enabled); return true; diff --git a/upbc/protoc-gen-upbdefs.cc b/upbc/protoc-gen-upbdefs.cc index 4ec4163f60..39191a8ab9 100644 --- a/upbc/protoc-gen-upbdefs.cc +++ b/upbc/protoc-gen-upbdefs.cc @@ -104,29 +104,13 @@ void WriteDefSource(const protobuf::FileDescriptor* file, Output& output) { output("#include \"upb/def.h\"\n"); output("#include \"$0\"\n", DefHeaderFilename(file->name())); + output("#include \"$0\"\n", HeaderFilename(file)); output("\n"); for (int i = 0; i < file->dependency_count(); i++) { output("extern upb_def_init $0;\n", DefInitSymbol(file->dependency(i))); } - std::vector<const protobuf::Descriptor*> file_messages = - SortedMessages(file); - - for (auto message : file_messages) { - output("extern const upb_msglayout $0;\n", MessageInit(message)); - } - output("\n"); - - if (!file_messages.empty()) { - output("static const upb_msglayout *layouts[$0] = {\n", file_messages.size()); - for (auto message : file_messages) { - output(" &$0,\n", MessageInit(message)); - } - output("};\n"); - output("\n"); - } - protobuf::FileDescriptorProto file_proto; file->CopyTo(&file_proto); std::string file_data; @@ -156,11 +140,7 @@ void WriteDefSource(const protobuf::FileDescriptor* file, Output& output) { output("upb_def_init $0 = {\n", DefInitSymbol(file)); output(" deps,\n"); - if (file_messages.empty()) { - output(" NULL,\n"); - } else { - output(" layouts,\n"); - } + output(" &$0,\n", FileLayoutName(file)); output(" \"$0\",\n", file->name()); output(" UPB_STRVIEW_INIT(descriptor, $0)\n", file_data.size()); output("};\n");