From c69dd68fb1d1bbb8bb8d2ec03019e18c12b9e5d7 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 3 Nov 2023 15:24:57 -0700 Subject: [PATCH] Implement feature inheritance and legacy editions for upb. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This switches upb to using legacy editions for all proto2/proto3 logic. This does not yet enable code generation for editions protos (ie. we do not yet turn on `FEATURE_SUPPORTS_EDITIONS`), but with feature inheritance in place, this will be a much smaller follow-on change. There is a ~10% increase in allocations, but only a ~1% increase in peak memory. There are some <5% increases in instructions and cycles, but apparently no increase in time: ``` name old cpu/op new cpu/op delta BM_ArenaOneAlloc 17.8ns ±11% 16.9ns ±17% ~ (p=0.310 n=5+5) BM_ArenaInitialBlockOneAlloc 5.99ns ±13% 5.35ns ± 2% ~ (p=0.421 n=5+5) BM_ArenaFuseUnbalanced/2 71.4ns ±11% 63.1ns ± 3% ~ (p=0.095 n=5+5) BM_ArenaFuseUnbalanced/8 509ns ± 2% 532ns ±15% ~ (p=0.421 n=5+5) BM_ArenaFuseUnbalanced/64 4.73µs ±20% 4.43µs ±10% ~ (p=0.841 n=5+5) BM_ArenaFuseUnbalanced/128 9.77µs ±12% 8.64µs ± 4% ~ (p=0.095 n=5+5) BM_ArenaFuseBalanced/2 67.5ns ±13% 62.6ns ± 3% ~ (p=0.841 n=5+5) BM_ArenaFuseBalanced/8 552ns ±23% 496ns ±25% ~ (p=0.222 n=5+5) BM_ArenaFuseBalanced/64 4.76µs ±14% 4.24µs ± 4% ~ (p=0.421 n=5+5) BM_ArenaFuseBalanced/128 10.2µs ±14% 8.6µs ± 4% -15.61% (p=0.016 n=5+5) BM_LoadAdsDescriptor_Upb 6.20ms ±12% 6.18ms ±16% ~ (p=0.421 n=5+5) BM_LoadAdsDescriptor_Upb 6.91ms ±12% 6.63ms ± 3% ~ (p=0.690 n=5+5) BM_LoadAdsDescriptor_Proto2 15.0ms ±12% 13.7ms ± 3% ~ (p=0.421 n=5+5) BM_LoadAdsDescriptor_Proto2 15.1ms ±13% 13.8ms ± 3% ~ (p=0.548 n=5+5) BM_Parse_Upb_FileDesc 14.4µs ±13% 13.2µs ± 3% ~ (p=0.548 n=5+5) BM_Parse_Upb_FileDesc 12.8µs ±12% 11.8µs ± 3% ~ (p=0.222 n=5+5) BM_Parse_Upb_FileDesc 13.7µs ±12% 12.9µs ± 3% ~ (p=1.000 n=5+5) BM_Parse_Upb_FileDesc 13.1µs ±11% 11.6µs ± 3% ~ (p=0.056 n=5+5) BM_Parse_Proto2 24.7µs ±12% 22.6µs ± 8% ~ (p=0.310 n=5+5) BM_Parse_Proto2 11.6µs ±13% 10.9µs ± 2% ~ (p=1.000 n=5+5) BM_Parse_Proto2 11.7µs ±10% 10.6µs ± 3% ~ (p=0.310 n=5+5) BM_Parse_Proto2 13.4µs ±12% 12.3µs ± 4% ~ (p=0.310 n=5+5) BM_SerializeDescriptor_Proto2 6.62µs ±13% 6.00µs ± 6% ~ (p=0.056 n=5+5) BM_SerializeDescriptor_Upb 11.1µs ±13% 10.3µs ± 3% ~ (p=1.000 n=5+5) name old time/op new time/op delta BM_ArenaOneAlloc 17.9ns ±12% 17.0ns ±17% ~ (p=0.310 n=5+5) BM_ArenaInitialBlockOneAlloc 6.03ns ±14% 5.36ns ± 2% ~ (p=0.421 n=5+5) BM_ArenaFuseUnbalanced/2 71.9ns ±12% 63.3ns ± 3% ~ (p=0.095 n=5+5) BM_ArenaFuseUnbalanced/8 511ns ± 2% 533ns ±15% ~ (p=0.421 n=5+5) BM_ArenaFuseUnbalanced/64 4.75µs ±20% 4.44µs ±10% ~ (p=0.841 n=5+5) BM_ArenaFuseUnbalanced/128 9.83µs ±12% 8.66µs ± 4% ~ (p=0.151 n=5+5) BM_ArenaFuseBalanced/2 67.8ns ±13% 62.7ns ± 3% ~ (p=0.841 n=5+5) BM_ArenaFuseBalanced/8 555ns ±24% 497ns ±26% ~ (p=0.222 n=5+5) BM_ArenaFuseBalanced/64 4.79µs ±14% 4.25µs ± 4% ~ (p=0.310 n=5+5) BM_ArenaFuseBalanced/128 10.3µs ±14% 8.6µs ± 4% -15.93% (p=0.016 n=5+5) BM_LoadAdsDescriptor_Upb 6.25ms ±12% 6.20ms ±16% ~ (p=0.421 n=5+5) BM_LoadAdsDescriptor_Upb 6.96ms ±13% 6.65ms ± 3% ~ (p=0.690 n=5+5) BM_LoadAdsDescriptor_Proto2 15.2ms ±12% 13.7ms ± 3% ~ (p=0.421 n=5+5) BM_LoadAdsDescriptor_Proto2 15.3ms ±14% 13.8ms ± 3% ~ (p=0.548 n=5+5) BM_Parse_Upb_FileDesc 14.5µs ±14% 13.2µs ± 3% ~ (p=0.690 n=5+5) BM_Parse_Upb_FileDesc 12.8µs ±12% 11.8µs ± 3% ~ (p=0.222 n=5+5) BM_Parse_Upb_FileDesc 13.8µs ±13% 13.0µs ± 3% ~ (p=1.000 n=5+5) BM_Parse_Upb_FileDesc 13.2µs ±12% 11.6µs ± 3% ~ (p=0.056 n=5+5) BM_Parse_Proto2 24.9µs ±12% 22.6µs ± 8% ~ (p=0.310 n=5+5) BM_Parse_Proto2 11.7µs ±14% 10.9µs ± 2% ~ (p=1.000 n=5+5) BM_Parse_Proto2 11.7µs ±11% 10.7µs ± 3% ~ (p=0.222 n=5+5) BM_Parse_Proto2 13.5µs ±12% 12.3µs ± 4% ~ (p=0.310 n=5+5) BM_SerializeDescriptor_Proto2 6.65µs ±13% 6.01µs ± 6% ~ (p=0.056 n=5+5) BM_SerializeDescriptor_Upb 11.2µs ±13% 10.3µs ± 3% ~ (p=1.000 n=5+5) name old INSTRUCTIONS/op new INSTRUCTIONS/op delta BM_ArenaOneAlloc 189 ± 0% 189 ± 0% ~ (p=0.881 n=5+5) BM_ArenaInitialBlockOneAlloc 69.0 ± 0% 69.0 ± 0% ~ (all samples are equal) BM_ArenaFuseUnbalanced/2 458 ± 0% 458 ± 0% ~ (p=1.000 n=5+5) BM_ArenaFuseUnbalanced/8 3.28k ±15% 3.60k ± 0% ~ (p=0.286 n=5+4) BM_ArenaFuseUnbalanced/64 28.6k ± 2% 29.2k ± 0% +2.17% (p=0.032 n=5+4) BM_ArenaFuseUnbalanced/128 57.9k ± 1% 57.9k ± 1% ~ (p=1.000 n=5+5) BM_ArenaFuseBalanced/2 482 ± 0% 482 ± 0% ~ (p=0.421 n=5+5) BM_ArenaFuseBalanced/8 3.35k ±14% 3.35k ±14% ~ (p=0.841 n=5+5) BM_ArenaFuseBalanced/64 29.2k ± 2% 29.3k ± 1% ~ (p=0.421 n=5+5) BM_ArenaFuseBalanced/128 59.2k ± 1% 59.3k ± 1% ~ (p=0.556 n=4+5) BM_LoadAdsDescriptor_Upb 37.3M ± 0% 38.2M ± 0% +2.39% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Upb 40.9M ± 0% 41.7M ± 0% +2.02% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Proto2 87.2M ± 0% 88.3M ± 1% +1.25% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Proto2 88.0M ± 0% 88.9M ± 1% +1.13% (p=0.016 n=5+5) BM_Parse_Upb_FileDesc 154k ± 0% 154k ± 0% ~ (p=1.000 n=5+5) BM_Parse_Upb_FileDesc 143k ± 0% 143k ± 0% ~ (p=0.310 n=5+5) BM_Parse_Upb_FileDesc 153k ± 0% 153k ± 0% ~ (p=1.016 n=5+4) BM_Parse_Upb_FileDesc 142k ± 0% 142k ± 0% ~ (p=0.127 n=5+5) BM_Parse_Proto2 213k ± 1% 217k ± 5% ~ (p=1.000 n=5+5) BM_Parse_Proto2 122k ± 0% 123k ± 0% +0.86% (p=0.008 n=5+5) BM_Parse_Proto2 120k ± 0% 120k ± 0% ~ (p=0.421 n=5+5) BM_Parse_Proto2 124k ± 0% 124k ± 0% ~ (p=0.587 n=5+5) BM_SerializeDescriptor_Proto2 63.5k ± 0% 63.5k ± 0% ~ (p=0.278 n=5+5) BM_SerializeDescriptor_Upb 111k ± 0% 111k ± 0% ~ (p=1.000 n=5+5) name old CYCLES/op new CYCLES/op delta BM_ArenaOneAlloc 53.5 ± 0% 53.4 ± 0% ~ (p=0.095 n=5+5) BM_ArenaInitialBlockOneAlloc 17.5 ± 1% 17.4 ± 0% ~ (p=0.087 n=5+5) BM_ArenaFuseUnbalanced/2 206 ± 0% 206 ± 0% ~ (p=0.548 n=5+5) BM_ArenaFuseUnbalanced/8 1.55k ±12% 1.67k ± 1% ~ (p=0.548 n=5+5) BM_ArenaFuseUnbalanced/64 14.1k ± 8% 14.1k ± 1% ~ (p=0.222 n=5+5) BM_ArenaFuseUnbalanced/128 28.2k ± 1% 28.3k ± 1% ~ (p=0.548 n=5+5) BM_ArenaFuseBalanced/2 205 ± 0% 204 ± 0% ~ (p=0.548 n=5+5) BM_ArenaFuseBalanced/8 1.57k ±12% 1.56k ±12% ~ (p=0.421 n=5+5) BM_ArenaFuseBalanced/64 13.9k ± 2% 13.9k ± 1% ~ (p=1.000 n=5+5) BM_ArenaFuseBalanced/128 28.1k ± 1% 28.2k ± 1% ~ (p=0.730 n=4+5) BM_LoadAdsDescriptor_Upb 18.7M ± 0% 19.3M ± 1% +3.38% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Upb 20.9M ± 0% 21.6M ± 0% +3.09% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Proto2 43.4M ± 0% 44.4M ± 1% +2.33% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Proto2 44.0M ± 0% 44.9M ± 2% +1.92% (p=0.016 n=5+5) BM_Parse_Upb_FileDesc 42.0k ± 1% 43.0k ± 1% +2.32% (p=0.008 n=5+5) BM_Parse_Upb_FileDesc 38.2k ± 1% 38.4k ± 0% +0.74% (p=0.032 n=5+5) BM_Parse_Upb_FileDesc 41.6k ± 0% 42.6k ± 1% +2.51% (p=0.008 n=5+5) BM_Parse_Upb_FileDesc 37.6k ± 0% 38.1k ± 0% +1.34% (p=0.008 n=5+5) BM_Parse_Proto2 71.9k ± 1% 74.1k ± 6% ~ (p=1.000 n=5+5) BM_Parse_Proto2 35.4k ± 1% 35.8k ± 0% +1.10% (p=0.008 n=5+5) BM_Parse_Proto2 34.6k ± 1% 34.9k ± 1% ~ (p=0.095 n=5+5) BM_Parse_Proto2 40.5k ± 0% 40.0k ± 1% -1.36% (p=0.008 n=5+5) BM_SerializeDescriptor_Proto2 20.1k ± 1% 19.7k ± 4% ~ (p=0.421 n=5+5) BM_SerializeDescriptor_Upb 33.7k ± 0% 33.7k ± 0% ~ (p=0.222 n=5+5) name old allocs/op new allocs/op delta BM_ArenaOneAlloc 1.00 ± 0% 1.00 ± 0% ~ (all samples are equal) BM_ArenaFuseUnbalanced/2 2.00 ± 0% 2.00 ± 0% ~ (all samples are equal) BM_ArenaFuseUnbalanced/8 8.00 ± 0% 8.00 ± 0% ~ (all samples are equal) BM_ArenaFuseUnbalanced/64 64.0 ± 0% 64.0 ± 0% ~ (all samples are equal) BM_ArenaFuseUnbalanced/128 128 ± 0% 128 ± 0% ~ (all samples are equal) BM_ArenaFuseBalanced/2 2.00 ± 0% 2.00 ± 0% ~ (all samples are equal) BM_ArenaFuseBalanced/8 8.00 ± 0% 8.00 ± 0% ~ (all samples are equal) BM_ArenaFuseBalanced/64 64.0 ± 0% 64.0 ± 0% ~ (all samples are equal) BM_ArenaFuseBalanced/128 128 ± 0% 128 ± 0% ~ (all samples are equal) BM_LoadAdsDescriptor_Upb 6.21k ± 0% 6.93k ± 0% +11.54% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Upb 6.54k ± 0% 6.96k ± 0% +6.34% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Proto2 124k ± 0% 124k ± 0% +0.00% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Proto2 126k ± 0% 126k ± 0% +0.00% (p=0.008 n=5+5) BM_Parse_Upb_FileDesc 7.00 ± 0% 7.00 ± 0% ~ (all samples are equal) BM_Parse_Upb_FileDesc 7.00 ± 0% 7.00 ± 0% ~ (all samples are equal) BM_Parse_Proto2 709 ± 0% 709 ± 0% ~ (all samples are equal) BM_Parse_Proto2 8.00 ± 0% 8.00 ± 0% ~ (all samples are equal) name old peak-mem(Bytes)/op new peak-mem(Bytes)/op delta BM_ArenaOneAlloc 328 ± 0% 328 ± 0% ~ (all samples are equal) BM_ArenaFuseUnbalanced/2 656 ± 0% 656 ± 0% ~ (all samples are equal) BM_ArenaFuseUnbalanced/8 2.62k ± 0% 2.62k ± 0% ~ (all samples are equal) BM_ArenaFuseUnbalanced/64 21.0k ± 0% 21.0k ± 0% ~ (all samples are equal) BM_ArenaFuseUnbalanced/128 42.0k ± 0% 42.0k ± 0% ~ (all samples are equal) BM_ArenaFuseBalanced/2 656 ± 0% 656 ± 0% ~ (all samples are equal) BM_ArenaFuseBalanced/8 2.62k ± 0% 2.62k ± 0% ~ (all samples are equal) BM_ArenaFuseBalanced/64 21.0k ± 0% 21.0k ± 0% ~ (all samples are equal) BM_ArenaFuseBalanced/128 42.0k ± 0% 42.0k ± 0% ~ (all samples are equal) BM_LoadAdsDescriptor_Upb 10.2M ± 0% 10.4M ± 0% +1.15% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Upb 10.5M ± 0% 10.5M ± 0% +0.11% (p=0.008 n=5+5) BM_LoadAdsDescriptor_Proto2 7.14M ± 0% 7.14M ± 0% ~ (p=0.317 n=4+5) BM_LoadAdsDescriptor_Proto2 7.18M ± 0% 7.18M ± 0% ~ (p=0.159 n=5+4) BM_Parse_Upb_FileDesc 36.5k ± 0% 36.5k ± 0% ~ (all samples are equal) BM_Parse_Upb_FileDesc 36.5k ± 0% 36.5k ± 0% ~ (all samples are equal) BM_Parse_Proto2 35.4k ± 0% 35.4k ± 0% ~ (all samples are equal) BM_Parse_Proto2 65.3k ± 0% 65.3k ± 0% ~ (all samples are equal) name old items/s new items/s delta BM_ArenaFuseUnbalanced/2 28.2M ±12% 31.7M ± 3% ~ (p=0.095 n=5+5) BM_ArenaFuseUnbalanced/8 15.7M ± 2% 15.1M ±14% ~ (p=0.421 n=5+5) BM_ArenaFuseUnbalanced/64 13.7M ±18% 14.5M ± 9% ~ (p=0.841 n=5+5) BM_ArenaFuseUnbalanced/128 13.2M ±12% 14.8M ± 5% ~ (p=0.095 n=5+5) BM_ArenaFuseBalanced/2 29.9M ±12% 32.0M ± 3% ~ (p=0.841 n=5+5) BM_ArenaFuseBalanced/8 14.8M ±28% 16.5M ±22% ~ (p=0.222 n=5+5) BM_ArenaFuseBalanced/64 13.6M ±15% 15.1M ± 4% ~ (p=0.421 n=5+5) BM_ArenaFuseBalanced/128 12.6M ±15% 14.9M ± 4% +17.88% (p=0.016 n=5+5) name old speed new speed delta BM_LoadAdsDescriptor_Upb 128MB/s ±11% 128MB/s ±14% ~ (p=0.421 n=5+5) BM_LoadAdsDescriptor_Upb 115MB/s ±12% 119MB/s ± 3% ~ (p=0.690 n=5+5) BM_LoadAdsDescriptor_Proto2 52.9MB/s ±12% 57.6MB/s ± 3% ~ (p=0.421 n=5+5) BM_LoadAdsDescriptor_Proto2 52.6MB/s ±14% 57.2MB/s ± 2% ~ (p=0.548 n=5+5) BM_Parse_Upb_FileDesc 527MB/s ±14% 571MB/s ± 3% ~ (p=0.548 n=5+5) BM_Parse_Upb_FileDesc 595MB/s ±11% 640MB/s ± 3% ~ (p=0.222 n=5+5) BM_Parse_Upb_FileDesc 553MB/s ±12% 582MB/s ± 3% ~ (p=1.000 n=5+5) BM_Parse_Upb_FileDesc 576MB/s ±12% 649MB/s ± 3% ~ (p=0.056 n=5+5) BM_Parse_Proto2 307MB/s ±13% 334MB/s ± 8% ~ (p=0.310 n=5+5) BM_Parse_Proto2 653MB/s ±13% 689MB/s ± 2% ~ (p=1.000 n=5+5) BM_Parse_Proto2 650MB/s ±10% 708MB/s ± 3% ~ (p=0.310 n=5+5) BM_Parse_Proto2 564MB/s ±12% 614MB/s ± 4% ~ (p=0.310 n=5+5) BM_SerializeDescriptor_Proto2 1.15GB/s ±12% 1.25GB/s ± 5% ~ (p=0.056 n=5+5) BM_SerializeDescriptor_Upb 684MB/s ±12% 730MB/s ± 3% ~ (p=1.000 n=5+5) ``` This adds about 5Ki of code size. Some of this likely comes from the fact that we now link in `message/copy.c` to perform a deep copy of a FeatureSet proto. ``` $ /google/bin/releases/protobuf-team/bloaty/bloaty-google3-diff --blaze-build-opts="-c opt" third_party/upb/upb/conformance/conformance_upb FILE SIZE VM SIZE -------------- -------------- +0.5% +4.19Ki +0.5% +4.19Ki .text +0.4% +656 +0.4% +656 .rodata +0.1% +504 [ = ] 0 .strtab +0.2% +384 [ = ] 0 .symtab +0.2% +280 +0.2% +280 .eh_frame +0.2% +216 +0.2% +216 .rela.dyn +0.3% +96 +0.3% +96 .data.rel.ro +0.2% +64 +0.2% +64 .eh_frame_hdr +1.1% +16 [ = ] 0 .got.plt +0.2% +8 +0.2% +8 .rela.plt -4.6% -8 -4.6% -8 [LOAD #2 [RX]] -50.0% -48 [ = ] 0 [Unmapped] [ = ] 0 -81.7% -1.47Ki .relro_padding +0.1% +6.30Ki +0.0% +4.00Ki TOTAL ``` PiperOrigin-RevId: 579321454 --- src/google/protobuf/compiler/BUILD.bazel | 1 + upb/BUILD | 3 + upb/port/def.inc | 5 + upb/port/undef.inc | 1 + upb/reflection/BUILD | 36 ++++ upb/reflection/def_pool.c | 21 +- upb/reflection/def_pool.h | 3 + upb/reflection/enum_def.c | 40 ++-- upb/reflection/enum_def.h | 1 + upb/reflection/enum_value_def.c | 52 +++-- upb/reflection/enum_value_def.h | 2 + upb/reflection/extension_range.c | 18 +- upb/reflection/extension_range.h | 2 + upb/reflection/field_def.c | 184 +++++++++++------- upb/reflection/field_def.h | 2 + upb/reflection/file_def.c | 62 +++++- upb/reflection/file_def.h | 1 + upb/reflection/internal/def_builder.c | 74 +++++++ upb/reflection/internal/def_builder.h | 23 +++ upb/reflection/internal/enum_def.h | 9 +- upb/reflection/internal/enum_reserved_range.h | 2 +- upb/reflection/internal/enum_value_def.h | 3 +- upb/reflection/internal/extension_range.h | 4 +- upb/reflection/internal/field_def.h | 19 +- upb/reflection/internal/message_def.h | 9 +- upb/reflection/internal/method_def.h | 8 +- upb/reflection/internal/oneof_def.h | 8 +- upb/reflection/internal/service_def.h | 8 +- .../internal/upb_edition_defaults.h | 20 ++ .../internal/upb_edition_defaults.h.template | 20 ++ upb/reflection/message_def.c | 53 +++-- upb/reflection/message_def.h | 2 + upb/reflection/method_def.c | 24 ++- upb/reflection/method_def.h | 2 + upb/reflection/oneof_def.c | 26 +-- upb/reflection/oneof_def.h | 4 +- upb/reflection/service_def.c | 33 ++-- upb/reflection/service_def.h | 2 + upb/util/required_fields.c | 2 +- 39 files changed, 593 insertions(+), 196 deletions(-) create mode 100644 upb/reflection/internal/upb_edition_defaults.h create mode 100644 upb/reflection/internal/upb_edition_defaults.h.template diff --git a/src/google/protobuf/compiler/BUILD.bazel b/src/google/protobuf/compiler/BUILD.bazel index f98c31785bec..45afef2a933a 100644 --- a/src/google/protobuf/compiler/BUILD.bazel +++ b/src/google/protobuf/compiler/BUILD.bazel @@ -164,6 +164,7 @@ cc_binary( copts = COPTS, visibility = [ "//src/google/protobuf:__subpackages__", + "//upb:__subpackages__", ], deps = [ ":command_line_interface", diff --git a/upb/BUILD b/upb/BUILD index 1e52a8092b14..ff5d6defc704 100644 --- a/upb/BUILD +++ b/upb/BUILD @@ -406,6 +406,7 @@ upb_amalgamation( ":mem_internal", ":message", ":message_accessors", + ":message_copy", ":message_internal", ":message_internal_types", ":message_tagged_ptr", @@ -456,6 +457,7 @@ upb_amalgamation( ":mem_internal", ":message", ":message_accessors", + ":message_copy", ":message_internal", ":message_internal_types", ":message_tagged_ptr", @@ -506,6 +508,7 @@ upb_amalgamation( ":mem_internal", ":message", ":message_accessors", + ":message_copy", ":message_internal", ":message_internal_types", ":message_tagged_ptr", diff --git a/upb/port/def.inc b/upb/port/def.inc index f32082138463..aa335c8c869b 100644 --- a/upb/port/def.inc +++ b/upb/port/def.inc @@ -323,6 +323,11 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #if defined(UPB_IS_GOOGLE3) && !defined(UPB_BOOTSTRAP_STAGE0) #define UPB_DESC(sym) proto2_##sym +#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init +#elif defined(UPB_BOOTSTRAP_STAGE0) +#define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() #else #define UPB_DESC(sym) google_protobuf_##sym +#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init #endif diff --git a/upb/port/undef.inc b/upb/port/undef.inc index eb0e1654f8fb..5a1429e34c49 100644 --- a/upb/port/undef.inc +++ b/upb/port/undef.inc @@ -49,6 +49,7 @@ #undef UPB_GNUC_MIN #undef UPB_DESCRIPTOR_UPB_H_FILENAME #undef UPB_DESC +#undef UPB_DESC_MINITABLE #undef UPB_IS_GOOGLE3 #undef UPB_ATOMIC #undef UPB_USE_C11_ATOMICS diff --git a/upb/reflection/BUILD b/upb/reflection/BUILD index bf0c0e4dbeb7..f6ea369d0661 100644 --- a/upb/reflection/BUILD +++ b/upb/reflection/BUILD @@ -5,6 +5,15 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd +load( + "//upb/cmake:build_defs.bzl", + "staleness_test", +) +load( + "//src/google/protobuf/editions:defaults.bzl", + "compile_edition_defaults", + "embed_edition_defaults", +) load("//bazel:build_defs.bzl", "UPB_DEFAULT_COPTS") load("//bazel:upb_minitable_proto_library.bzl", "upb_minitable_proto_library") load("//bazel:upb_proto_library.bzl", "upb_proto_reflection_library") @@ -108,6 +117,7 @@ bootstrap_cc_library( "internal/method_def.h", "internal/oneof_def.h", "internal/service_def.h", + "internal/upb_edition_defaults.h", "message.h", "message.hpp", "message_def.h", @@ -125,11 +135,13 @@ bootstrap_cc_library( "//upb:mem", "//upb:message", "//upb:message_accessors", + "//upb:message_copy", "//upb:message_value", "//upb:mini_descriptor", "//upb:mini_descriptor_internal", "//upb:mini_table", "//upb:port", + "//upb/base:internal", ], ) @@ -171,6 +183,30 @@ cc_test( ], ) +compile_edition_defaults( + name = "upb_edition_defaults", + srcs = [ + "//:descriptor_proto", + ], + maximum_edition = "2023", + minimum_edition = "PROTO2", +) + +embed_edition_defaults( + name = "embedded_upb_edition_defaults_generate", + defaults = "upb_edition_defaults", + output = "generated/internal/upb_edition_defaults.h", + placeholder = "DEFAULTS_VALUE", + template = "internal/upb_edition_defaults.h.template", +) + +staleness_test( + name = "bootstrap_upb_defaults_staleness_test", + outs = ["internal/upb_edition_defaults.h"], + generated_pattern = "generated/%s", + target_files = ["internal/upb_edition_defaults.h"], +) + # begin:github_only filegroup( name = "source_files", diff --git a/upb/reflection/def_pool.c b/upb/reflection/def_pool.c index 90d3beadf57e..88e42ded15b1 100644 --- a/upb/reflection/def_pool.c +++ b/upb/reflection/def_pool.c @@ -17,6 +17,7 @@ #include "upb/reflection/internal/file_def.h" #include "upb/reflection/internal/message_def.h" #include "upb/reflection/internal/service_def.h" +#include "upb/reflection/internal/upb_edition_defaults.h" // Must be last. #include "upb/port/def.inc" @@ -27,6 +28,7 @@ struct upb_DefPool { upb_strtable files; // file_name -> (upb_FileDef*) upb_inttable exts; // (upb_MiniTableExtension*) -> (upb_FieldDef*) upb_ExtensionRegistry* extreg; + const UPB_DESC(FeatureSetDefaults) * feature_set_defaults; upb_MiniTablePlatform platform; void* scratch_data; size_t scratch_size; @@ -39,6 +41,8 @@ void upb_DefPool_Free(upb_DefPool* s) { upb_gfree(s); } +static const char serialized_defaults[] = UPB_INTERNAL_UPB_EDITION_DEFAULTS; + upb_DefPool* upb_DefPool_New(void) { upb_DefPool* s = upb_gmalloc(sizeof(*s)); if (!s) return NULL; @@ -58,6 +62,10 @@ upb_DefPool* upb_DefPool_New(void) { if (!s->extreg) goto err; s->platform = kUpb_MiniTablePlatform_Native; + s->feature_set_defaults = UPB_DESC(FeatureSetDefaults_parse)( + serialized_defaults, sizeof(serialized_defaults) - 1, s->arena); + + if (!s->feature_set_defaults) goto err; return s; @@ -66,6 +74,11 @@ upb_DefPool* upb_DefPool_New(void) { return NULL; } +const UPB_DESC(FeatureSetDefaults) * + upb_DefPool_FeatureSetDefaults(const upb_DefPool* s) { + return s->feature_set_defaults; +} + bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, const upb_FieldDef* f) { return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), @@ -279,7 +292,11 @@ static const upb_FileDef* upb_DefBuilder_AddFileToPool( remove_filedef(s, builder->file); builder->file = NULL; } - } else if (!builder->arena || !builder->tmp_arena) { + } else if (!builder->arena || !builder->tmp_arena || + !upb_strtable_init(&builder->feature_cache, 16, + builder->tmp_arena) || + !(builder->legacy_features = + UPB_DESC(FeatureSet_new)(builder->tmp_arena))) { _upb_DefBuilder_OomErr(builder); } else { _upb_FileDef_Create(builder, file_proto); @@ -312,6 +329,8 @@ static const upb_FileDef* _upb_DefPool_AddFile( upb_DefBuilder ctx = { .symtab = s, + .tmp_buf = NULL, + .tmp_buf_size = 0, .layout = layout, .platform = s->platform, .msg_count = 0, diff --git a/upb/reflection/def_pool.h b/upb/reflection/def_pool.h index f21a0dbd2db7..63cce8a08074 100644 --- a/upb/reflection/def_pool.h +++ b/upb/reflection/def_pool.h @@ -26,6 +26,9 @@ UPB_API void upb_DefPool_Free(upb_DefPool* s); UPB_API upb_DefPool* upb_DefPool_New(void); +UPB_API const UPB_DESC(FeatureSetDefaults) * + upb_DefPool_FeatureSetDefaults(const upb_DefPool* s); + UPB_API const upb_MessageDef* upb_DefPool_FindMessageByName( const upb_DefPool* s, const char* sym); diff --git a/upb/reflection/enum_def.c b/upb/reflection/enum_def.c index 97fc63e9acea..8ba894f21d66 100644 --- a/upb/reflection/enum_def.c +++ b/upb/reflection/enum_def.c @@ -23,7 +23,8 @@ #include "upb/port/def.inc" struct upb_EnumDef { - const UPB_DESC(EnumOptions) * opts; + const UPB_DESC(EnumOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_MiniTableEnum* layout; // Only for proto2. const upb_FileDef* file; const upb_MessageDef* containing_type; // Could be merged with "file". @@ -37,8 +38,10 @@ struct upb_EnumDef { int res_range_count; int res_name_count; int32_t defaultval; - bool is_closed; bool is_sorted; // Whether all of the values are defined in ascending order. +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { @@ -140,7 +143,11 @@ const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { return _upb_EnumValueDef_At(e->values, i); } -bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { return e->is_closed; } +bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) return false; + return UPB_DESC(FeatureSet_enum_type)(e->resolved_features) == + UPB_DESC(FeatureSet_CLOSED); +} bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, upb_StringView* out) { @@ -209,6 +216,7 @@ static upb_StringView* _upb_EnumReservedNames_New( static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, const UPB_DESC(EnumDescriptorProto) * enum_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e) { const UPB_DESC(EnumValueDescriptorProto)* const* values; const UPB_DESC(EnumDescriptorProto_EnumReservedRange)* const* res_ranges; @@ -216,6 +224,10 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, upb_StringView name; size_t n_value, n_res_range, n_res_name; + UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); + e->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(EnumOptions_features)(e->opts)); + // Must happen before _upb_DefBuilder_Add() e->file = _upb_DefBuilder_File(ctx); @@ -225,9 +237,6 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, _upb_DefBuilder_Add(ctx, e->full_name, _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); - e->is_closed = (!UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3) && - (upb_FileDef_Syntax(e->file) == kUpb_Syntax_Proto2); - values = UPB_DESC(EnumDescriptorProto_value)(enum_proto, &n_value); bool ok = upb_strtable_init(&e->ntoi, n_value, ctx->arena); @@ -238,8 +247,8 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, e->defaultval = 0; e->value_count = n_value; - e->values = - _upb_EnumValueDefs_New(ctx, prefix, n_value, values, e, &e->is_sorted); + e->values = _upb_EnumValueDefs_New(ctx, prefix, n_value, values, + e->resolved_features, e, &e->is_sorted); if (n_value == 0) { _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", @@ -256,11 +265,9 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, e->res_name_count = n_res_name; e->res_names = _upb_EnumReservedNames_New(ctx, n_res_name, res_names); - UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); - upb_inttable_compact(&e->iton, ctx->arena); - if (e->is_closed) { + if (upb_EnumDef_IsClosed(e)) { if (ctx->layout) { UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); e->layout = ctx->layout->enums[ctx->enum_count++]; @@ -272,10 +279,11 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, } } -upb_EnumDef* _upb_EnumDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(EnumDescriptorProto) * const* protos, - const upb_MessageDef* containing_type) { +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const upb_MessageDef* containing_type) { _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); // If a containing type is defined then get the full name from that. @@ -285,7 +293,7 @@ upb_EnumDef* _upb_EnumDefs_New( upb_EnumDef* e = _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumDef) * n); for (int i = 0; i < n; i++) { - create_enumdef(ctx, name, protos[i], &e[i]); + create_enumdef(ctx, name, protos[i], parent_features, &e[i]); e[i].containing_type = containing_type; } return e; diff --git a/upb/reflection/enum_def.h b/upb/reflection/enum_def.h index 6f406f54bb07..a81ce5fd1171 100644 --- a/upb/reflection/enum_def.h +++ b/upb/reflection/enum_def.h @@ -40,6 +40,7 @@ bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, const char* upb_EnumDef_Name(const upb_EnumDef* e); const UPB_DESC(EnumOptions) * upb_EnumDef_Options(const upb_EnumDef* e); +const UPB_DESC(FeatureSet) * upb_EnumDef_ResolvedFeatures(const upb_EnumDef* e); upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i); int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e); diff --git a/upb/reflection/enum_value_def.c b/upb/reflection/enum_value_def.c index d06c9331075c..d250daade6e5 100644 --- a/upb/reflection/enum_value_def.c +++ b/upb/reflection/enum_value_def.c @@ -7,19 +7,27 @@ #include "upb/reflection/internal/enum_value_def.h" +#include + #include "upb/reflection/def_type.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/enum_value_def.h" +#include "upb/reflection/file_def.h" #include "upb/reflection/internal/def_builder.h" #include "upb/reflection/internal/enum_def.h" -#include "upb/reflection/internal/file_def.h" // Must be last. #include "upb/port/def.inc" struct upb_EnumValueDef { - const UPB_DESC(EnumValueOptions) * opts; + const UPB_DESC(EnumValueOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_EnumDef* parent; const char* full_name; int32_t number; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { @@ -76,9 +84,15 @@ uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { } static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(EnumValueDescriptorProto) * + const UPB_DESC(EnumValueDescriptorProto*) val_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, upb_EnumValueDef* v) { + UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, + val_proto); + v->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(EnumValueOptions_features)(v->opts)); + upb_StringView name = UPB_DESC(EnumValueDescriptorProto_name)(val_proto); v->parent = e; // Must happen prior to _upb_DefBuilder_Add() @@ -87,17 +101,32 @@ static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, _upb_DefBuilder_Add(ctx, v->full_name, _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); - UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, - val_proto); - bool ok = _upb_EnumDef_Insert(e, v, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); } +static void _upb_EnumValueDef_CheckZeroValue(upb_DefBuilder* ctx, + const upb_EnumDef* e, + const upb_EnumValueDef* v, int n) { + if (upb_EnumDef_IsClosed(e) || n == 0 || v[0].number == 0) return; + + // When the special UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 is enabled, we have to + // exempt proto2 enums from this check, even when we are treating them as + // open. + if (UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 && + upb_FileDef_Syntax(upb_EnumDef_File(e)) == kUpb_Syntax_Proto2) { + return; + } + + _upb_DefBuilder_Errf(ctx, "for open enums, the first value must be zero (%s)", + upb_EnumDef_FullName(e)); +} + // Allocate and initialize an array of |n| enum value defs owned by |e|. upb_EnumValueDef* _upb_EnumValueDefs_New( upb_DefBuilder* ctx, const char* prefix, int n, - const UPB_DESC(EnumValueDescriptorProto) * const* protos, upb_EnumDef* e, + const UPB_DESC(EnumValueDescriptorProto*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, bool* is_sorted) { _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); @@ -107,19 +136,14 @@ upb_EnumValueDef* _upb_EnumValueDefs_New( *is_sorted = true; uint32_t previous = 0; for (int i = 0; i < n; i++) { - create_enumvaldef(ctx, prefix, protos[i], e, &v[i]); + create_enumvaldef(ctx, prefix, protos[i], parent_features, e, &v[i]); const uint32_t current = v[i].number; if (previous > current) *is_sorted = false; previous = current; } - if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 && - v[0].number != 0) { - _upb_DefBuilder_Errf(ctx, - "for proto3, the first enum value must be zero (%s)", - upb_EnumDef_FullName(e)); - } + _upb_EnumValueDef_CheckZeroValue(ctx, e, v, n); return v; } diff --git a/upb/reflection/enum_value_def.h b/upb/reflection/enum_value_def.h index e95232847a16..4fbbade19d02 100644 --- a/upb/reflection/enum_value_def.h +++ b/upb/reflection/enum_value_def.h @@ -27,6 +27,8 @@ UPB_API const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v); UPB_API int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v); const UPB_DESC(EnumValueOptions) * upb_EnumValueDef_Options(const upb_EnumValueDef* v); +const UPB_DESC(FeatureSet) * + upb_EnumValueDef_ResolvedFeatures(const upb_EnumValueDef* e); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/reflection/extension_range.c b/upb/reflection/extension_range.c index b088ba92ede6..83382de35623 100644 --- a/upb/reflection/extension_range.c +++ b/upb/reflection/extension_range.c @@ -7,6 +7,9 @@ #include "upb/reflection/internal/extension_range.h" +#include + +#include "upb/reflection/extension_range.h" #include "upb/reflection/field_def.h" #include "upb/reflection/internal/def_builder.h" #include "upb/reflection/message_def.h" @@ -15,7 +18,8 @@ #include "upb/port/def.inc" struct upb_ExtensionRange { - const UPB_DESC(ExtensionRangeOptions) * opts; + const UPB_DESC(ExtensionRangeOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; int32_t start; int32_t end; }; @@ -41,12 +45,18 @@ int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } upb_ExtensionRange* _upb_ExtensionRanges_New( upb_DefBuilder* ctx, int n, - const UPB_DESC(DescriptorProto_ExtensionRange) * const* protos, - const upb_MessageDef* m) { + const UPB_DESC(DescriptorProto_ExtensionRange*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* m) { upb_ExtensionRange* r = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ExtensionRange) * n); for (int i = 0; i < n; i++) { + UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, + ExtensionRangeOptions, protos[i]); + r[i].resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, + UPB_DESC(ExtensionRangeOptions_features)(r[i].opts)); + const int32_t start = UPB_DESC(DescriptorProto_ExtensionRange_start)(protos[i]); const int32_t end = UPB_DESC(DescriptorProto_ExtensionRange_end)(protos[i]); @@ -66,8 +76,6 @@ upb_ExtensionRange* _upb_ExtensionRanges_New( r[i].start = start; r[i].end = end; - UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, - ExtensionRangeOptions, protos[i]); } return r; diff --git a/upb/reflection/extension_range.h b/upb/reflection/extension_range.h index 7c3e19f005b1..3ddd5340e740 100644 --- a/upb/reflection/extension_range.h +++ b/upb/reflection/extension_range.h @@ -25,6 +25,8 @@ int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r); bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r); const UPB_DESC(ExtensionRangeOptions) * upb_ExtensionRange_Options(const upb_ExtensionRange* r); +const UPB_DESC(FeatureSet) * + upb_ExtensionRange_ResolvedFeatures(const upb_ExtensionRange* e); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/reflection/field_def.c b/upb/reflection/field_def.c index 537d05ef85a7..5b67e209ccb3 100644 --- a/upb/reflection/field_def.c +++ b/upb/reflection/field_def.c @@ -12,6 +12,7 @@ #include #include "upb/base/descriptor_constants.h" +#include "upb/message/accessors.h" #include "upb/mini_descriptor/decode.h" #include "upb/mini_descriptor/internal/modifiers.h" #include "upb/reflection/def.h" @@ -35,7 +36,8 @@ typedef struct { } str_t; struct upb_FieldDef { - const UPB_DESC(FieldOptions) * opts; + const UPB_DESC(FieldOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_FileDef* file; const upb_MessageDef* msgdef; const char* full_name; @@ -65,13 +67,9 @@ struct upb_FieldDef { bool has_json_name; bool has_presence; bool is_extension; - bool is_packed; bool is_proto3_optional; upb_FieldType type_; upb_Label label_; -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif }; upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { @@ -140,7 +138,9 @@ bool _upb_FieldDef_IsPackable(const upb_FieldDef* f) { } bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { - return _upb_FieldDef_IsPackable(f) && f->is_packed; + return _upb_FieldDef_IsPackable(f) && + UPB_DESC(FeatureSet_repeated_field_encoding(f->resolved_features)) == + UPB_DESC(FeatureSet_PACKED); } const char* upb_FieldDef_Name(const upb_FieldDef* f) { @@ -253,44 +253,21 @@ bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } -// begin:google_only -// static bool _upb_FieldDef_EnforceUtf8Option(const upb_FieldDef* f) { -// #if defined(UPB_BOOTSTRAP_STAGE0) -// return true; -// #else -// return UPB_DESC(FieldOptions_enforce_utf8)(f->opts); -// #endif -// } -// end:google_only - -// begin:github_only -static bool _upb_FieldDef_EnforceUtf8Option(const upb_FieldDef* f) { - return true; -} -// end:github_only - bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) { if (upb_FieldDef_Type(f) != kUpb_FieldType_String) return false; - return upb_FileDef_Syntax(upb_FieldDef_File(f)) == kUpb_Syntax_Proto3 - ? _upb_FieldDef_EnforceUtf8Option(f) - : false; + return UPB_DESC(FeatureSet_utf8_validation(f->resolved_features)) == + UPB_DESC(FeatureSet_VERIFY); } uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { uint64_t out = upb_FieldDef_IsPacked(f) ? kUpb_FieldModifier_IsPacked : 0; - switch (f->label_) { - case kUpb_Label_Optional: - if (!upb_FieldDef_HasPresence(f)) { - out |= kUpb_FieldModifier_IsProto3Singular; - } - break; - case kUpb_Label_Repeated: - out |= kUpb_FieldModifier_IsRepeated; - break; - case kUpb_Label_Required: - out |= kUpb_FieldModifier_IsRequired; - break; + if (upb_FieldDef_IsRepeated(f)) { + out |= kUpb_FieldModifier_IsRepeated; + } else if (upb_FieldDef_IsRequired(f)) { + out |= kUpb_FieldModifier_IsRequired; + } else if (!upb_FieldDef_HasPresence(f)) { + out |= kUpb_FieldModifier_IsProto3Singular; } if (_upb_FieldDef_IsClosedEnum(f)) { @@ -330,7 +307,8 @@ bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { } bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { - return upb_FieldDef_Label(f) == kUpb_Label_Required; + return UPB_DESC(FeatureSet_field_presence)(f->resolved_features) == + UPB_DESC(FeatureSet_LEGACY_REQUIRED); } bool upb_FieldDef_IsString(const upb_FieldDef* f) { @@ -554,19 +532,63 @@ static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f) { } } +static bool _upb_FieldDef_InferLegacyFeatures( + upb_DefBuilder* ctx, upb_FieldDef* f, + const UPB_DESC(FieldDescriptorProto*) proto, + const UPB_DESC(FieldOptions*) options, upb_Syntax syntax, + UPB_DESC(FeatureSet*) features) { + bool ret = false; + + if (UPB_DESC(FieldDescriptorProto_label)(proto) == kUpb_Label_Required) { + if (syntax == kUpb_Syntax_Proto3) { + _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", + f->full_name); + } + int val = UPB_DESC(FeatureSet_LEGACY_REQUIRED); + UPB_DESC(FeatureSet_set_field_presence(features, val)); + ret = true; + } + + if (UPB_DESC(FieldDescriptorProto_type)(proto) == kUpb_FieldType_Group) { + int val = UPB_DESC(FeatureSet_DELIMITED); + UPB_DESC(FeatureSet_set_message_encoding(features, val)); + ret = true; + } + + if (UPB_DESC(FieldOptions_has_packed)(options)) { + int val = UPB_DESC(FieldOptions_packed)(options) + ? UPB_DESC(FeatureSet_PACKED) + : UPB_DESC(FeatureSet_EXPANDED); + UPB_DESC(FeatureSet_set_repeated_field_encoding(features, val)); + ret = true; + } + +// begin:google_only +// #ifndef UPB_BOOTSTRAP_STAGE0 +// if (syntax == kUpb_Syntax_Proto3 && +// UPB_DESC(FieldOptions_has_enforce_utf8)(options) && +// !UPB_DESC(FieldOptions_enforce_utf8)(options)) { +// int val = UPB_DESC(FeatureSet_UNVERIFIED); +// UPB_DESC(FeatureSet_set_utf8_validation(features, val)); +// ret = true; +// } +// #endif +// // clang-format off +// end:google_only + // clang-format on + + return ret; +} + static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(FieldDescriptorProto) * + const UPB_DESC(FeatureSet*) parent_features, + const UPB_DESC(FieldDescriptorProto*) field_proto, upb_MessageDef* m, upb_FieldDef* f) { // Must happen before _upb_DefBuilder_Add() f->file = _upb_DefBuilder_File(ctx); - if (!UPB_DESC(FieldDescriptorProto_has_name)(field_proto)) { - _upb_DefBuilder_Errf(ctx, "field has no name"); - } - const upb_StringView name = UPB_DESC(FieldDescriptorProto_name)(field_proto); - f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); f->label_ = (int)UPB_DESC(FieldDescriptorProto_label)(field_proto); f->number_ = UPB_DESC(FieldDescriptorProto_number)(field_proto); @@ -575,6 +597,29 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, f->msgdef = m; f->scope.oneof = NULL; + UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); + + upb_Syntax syntax = upb_FileDef_Syntax(f->file); + const UPB_DESC(FeatureSet*) unresolved_features = + UPB_DESC(FieldOptions_features)(f->opts); + bool implicit = false; + + if (syntax != kUpb_Syntax_Editions) { + upb_Message_Clear(ctx->legacy_features, UPB_DESC_MINITABLE(FeatureSet)); + if (_upb_FieldDef_InferLegacyFeatures(ctx, f, field_proto, f->opts, syntax, + ctx->legacy_features)) { + implicit = true; + unresolved_features = ctx->legacy_features; + } + } + + f->resolved_features = _upb_DefBuilder_DoResolveFeatures( + ctx, parent_features, unresolved_features, implicit); + + if (!UPB_DESC(FieldDescriptorProto_has_name)(field_proto)) { + _upb_DefBuilder_Errf(ctx, "field has no name"); + } + f->has_json_name = UPB_DESC(FieldDescriptorProto_has_json_name)(field_proto); if (f->has_json_name) { const upb_StringView sv = @@ -630,12 +675,6 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, * to the field_proto until later when we can properly resolve it. */ f->sub.unresolved = field_proto; - if (f->label_ == kUpb_Label_Required && - upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3) { - _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", - f->full_name); - } - if (UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { int oneof_index = UPB_DESC(FieldDescriptorProto_oneof_index)(field_proto); @@ -659,27 +698,21 @@ static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, _upb_OneofDef_Insert(ctx, oneof, f, name.data, name.size); } - UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); - - if (UPB_DESC(FieldOptions_has_packed)(f->opts)) { - f->is_packed = UPB_DESC(FieldOptions_packed)(f->opts); - } else { - f->is_packed = upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto3; - } - f->has_presence = (!upb_FieldDef_IsRepeated(f)) && (f->type_ == kUpb_FieldType_Message || f->type_ == kUpb_FieldType_Group || upb_FieldDef_ContainingOneof(f) || - (upb_FileDef_Syntax(f->file) == kUpb_Syntax_Proto2)); + UPB_DESC(FeatureSet_field_presence)(f->resolved_features) != + UPB_DESC(FeatureSet_IMPLICIT)); } static void _upb_FieldDef_CreateExt(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(FieldDescriptorProto) * + const UPB_DESC(FeatureSet*) parent_features, + const UPB_DESC(FieldDescriptorProto*) field_proto, upb_MessageDef* m, upb_FieldDef* f) { f->is_extension = true; - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); if (UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", @@ -696,11 +729,13 @@ static void _upb_FieldDef_CreateExt(upb_DefBuilder* ctx, const char* prefix, } static void _upb_FieldDef_CreateNotExt(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(FieldDescriptorProto) * + const UPB_DESC(FeatureSet*) + parent_features, + const UPB_DESC(FieldDescriptorProto*) field_proto, upb_MessageDef* m, upb_FieldDef* f) { f->is_extension = false; - _upb_FieldDef_Create(ctx, prefix, field_proto, m, f); + _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); if (!UPB_DESC(FieldDescriptorProto_has_oneof_index)(field_proto)) { if (f->is_proto3_optional) { @@ -714,10 +749,11 @@ static void _upb_FieldDef_CreateNotExt(upb_DefBuilder* ctx, const char* prefix, _upb_MessageDef_InsertField(ctx, m, f); } -upb_FieldDef* _upb_Extensions_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m) { +upb_FieldDef* _upb_Extensions_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m) { _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); upb_FieldDef* defs = (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); @@ -725,17 +761,19 @@ upb_FieldDef* _upb_Extensions_New( for (int i = 0; i < n; i++) { upb_FieldDef* f = &defs[i]; - _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f); + _upb_FieldDef_CreateExt(ctx, prefix, parent_features, protos[i], m, f); f->index_ = i; } return defs; } -upb_FieldDef* _upb_FieldDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m, bool* is_sorted) { +upb_FieldDef* _upb_FieldDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m, + bool* is_sorted) { _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); upb_FieldDef* defs = (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n); @@ -744,7 +782,7 @@ upb_FieldDef* _upb_FieldDefs_New( for (int i = 0; i < n; i++) { upb_FieldDef* f = &defs[i]; - _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f); + _upb_FieldDef_CreateNotExt(ctx, prefix, parent_features, protos[i], m, f); f->index_ = i; if (!ctx->layout) { // Speculate that the def fields are sorted. We will always sort the diff --git a/upb/reflection/field_def.h b/upb/reflection/field_def.h index b3305bc1f29d..35c3e702ede5 100644 --- a/upb/reflection/field_def.h +++ b/upb/reflection/field_def.h @@ -61,6 +61,8 @@ const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f); UPB_API const char* upb_FieldDef_Name(const upb_FieldDef* f); UPB_API uint32_t upb_FieldDef_Number(const upb_FieldDef* f); const UPB_DESC(FieldOptions) * upb_FieldDef_Options(const upb_FieldDef* f); +const UPB_DESC(FeatureSet) * + upb_FieldDef_ResolvedFeatures(const upb_FieldDef* f); UPB_API const upb_OneofDef* upb_FieldDef_RealContainingOneof( const upb_FieldDef* f); UPB_API upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f); diff --git a/upb/reflection/file_def.c b/upb/reflection/file_def.c index bd4b254cac43..abdbd3523e84 100644 --- a/upb/reflection/file_def.c +++ b/upb/reflection/file_def.c @@ -7,6 +7,8 @@ #include "upb/reflection/internal/file_def.h" +#include + #include "upb/reflection/def_pool.h" #include "upb/reflection/internal/def_builder.h" #include "upb/reflection/internal/enum_def.h" @@ -19,7 +21,8 @@ #include "upb/port/def.inc" struct upb_FileDef { - const UPB_DESC(FileOptions) * opts; + const UPB_DESC(FileOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const char* name; const char* package; UPB_DESC(Edition) edition; @@ -49,6 +52,11 @@ const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f) { return f->opts; } +const UPB_DESC(FeatureSet) * + upb_FileDef_ResolvedFeatures(const upb_FileDef* f) { + return f->resolved_features; +} + bool upb_FileDef_HasOptions(const upb_FileDef* f) { return f->opts != (void*)kUpbDefOptDefault; } @@ -165,6 +173,34 @@ static int count_exts_in_msg(const UPB_DESC(DescriptorProto) * msg_proto) { return ext_count; } +const UPB_DESC(FeatureSet*) + _upb_FileDef_FindEdition(upb_DefBuilder* ctx, int edition) { + const UPB_DESC(FeatureSetDefaults)* defaults = + upb_DefPool_FeatureSetDefaults(ctx->symtab); + + int min = UPB_DESC(FeatureSetDefaults_minimum_edition)(defaults); + int max = UPB_DESC(FeatureSetDefaults_maximum_edition)(defaults); + if (edition < min || edition > max) { + _upb_DefBuilder_Errf(ctx, + "Edition %d is outside the supported range [%d, %d] " + "given in the defaults", + edition, min, max); + } + + size_t n; + const UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault)* const* d = + UPB_DESC(FeatureSetDefaults_defaults)(defaults, &n); + const UPB_DESC(FeatureSet)* ret = NULL; + for (size_t i = 0; i < n; i++) { + if (UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault_edition)(d[i]) > + edition) { + break; + } + ret = UPB_DESC(FeatureSetDefaults_FeatureSetEditionDefault_features)(d[i]); + } + return ret; +} + // Allocate and initialize one file def, and add it to the context object. void _upb_FileDef_Create(upb_DefBuilder* ctx, const UPB_DESC(FileDescriptorProto) * file_proto) { @@ -233,21 +269,33 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx, if (streql_view(syntax, "proto2")) { file->syntax = kUpb_Syntax_Proto2; + file->edition = UPB_DESC(EDITION_PROTO2); } else if (streql_view(syntax, "proto3")) { file->syntax = kUpb_Syntax_Proto3; + file->edition = UPB_DESC(EDITION_PROTO3); } else if (streql_view(syntax, "editions")) { file->syntax = kUpb_Syntax_Editions; + file->edition = UPB_DESC(FileDescriptorProto_edition)(file_proto); } else { _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", UPB_STRINGVIEW_ARGS(syntax)); } } else { file->syntax = kUpb_Syntax_Proto2; + file->edition = UPB_DESC(EDITION_PROTO2); } // Read options. UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); + // Resolve features. + const UPB_DESC(FeatureSet*) edition_defaults = + _upb_FileDef_FindEdition(ctx, file->edition); + const UPB_DESC(FeatureSet*) unresolved = + UPB_DESC(FileOptions_features)(file->opts); + file->resolved_features = + _upb_DefBuilder_ResolveFeatures(ctx, edition_defaults, unresolved); + // Verify dependencies. strs = UPB_DESC(FileDescriptorProto_dependency)(file_proto, &n); file->dep_count = n; @@ -293,22 +341,26 @@ void _upb_FileDef_Create(upb_DefBuilder* ctx, // Create enums. enums = UPB_DESC(FileDescriptorProto_enum_type)(file_proto, &n); file->top_lvl_enum_count = n; - file->top_lvl_enums = _upb_EnumDefs_New(ctx, n, enums, NULL); + file->top_lvl_enums = + _upb_EnumDefs_New(ctx, n, enums, file->resolved_features, NULL); // Create extensions. exts = UPB_DESC(FileDescriptorProto_extension)(file_proto, &n); file->top_lvl_ext_count = n; - file->top_lvl_exts = _upb_Extensions_New(ctx, n, exts, file->package, NULL); + file->top_lvl_exts = _upb_Extensions_New( + ctx, n, exts, file->resolved_features, file->package, NULL); // Create messages. msgs = UPB_DESC(FileDescriptorProto_message_type)(file_proto, &n); file->top_lvl_msg_count = n; - file->top_lvl_msgs = _upb_MessageDefs_New(ctx, n, msgs, NULL); + file->top_lvl_msgs = + _upb_MessageDefs_New(ctx, n, msgs, file->resolved_features, NULL); // Create services. services = UPB_DESC(FileDescriptorProto_service)(file_proto, &n); file->service_count = n; - file->services = _upb_ServiceDefs_New(ctx, n, services); + file->services = + _upb_ServiceDefs_New(ctx, n, services, file->resolved_features); // Now that all names are in the table, build layouts and resolve refs. diff --git a/upb/reflection/file_def.h b/upb/reflection/file_def.h index f338c25f92e5..912d0081d986 100644 --- a/upb/reflection/file_def.h +++ b/upb/reflection/file_def.h @@ -24,6 +24,7 @@ int upb_FileDef_DependencyCount(const upb_FileDef* f); bool upb_FileDef_HasOptions(const upb_FileDef* f); UPB_API const char* upb_FileDef_Name(const upb_FileDef* f); const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f); +const UPB_DESC(FeatureSet) * upb_FileDef_ResolvedFeatures(const upb_FileDef* f); const char* upb_FileDef_Package(const upb_FileDef* f); UPB_DESC(Edition) upb_FileDef_Edition(const upb_FileDef* f); UPB_API const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f); diff --git a/upb/reflection/internal/def_builder.c b/upb/reflection/internal/def_builder.c index 2ab16f27deef..d6737982caa3 100644 --- a/upb/reflection/internal/def_builder.c +++ b/upb/reflection/internal/def_builder.c @@ -9,9 +9,12 @@ #include +#include "upb/base/internal/log2.h" +#include "upb/message/copy.h" #include "upb/reflection/def_pool.h" #include "upb/reflection/def_type.h" #include "upb/reflection/field_def.h" +#include "upb/reflection/file_def.h" #include "upb/reflection/internal/strdup2.h" // Must be last. @@ -337,3 +340,74 @@ void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, // We should never reach this point. UPB_ASSERT(false); } + +upb_StringView _upb_DefBuilder_MakeKey(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key) { + size_t need = key.size + sizeof(void*); + if (ctx->tmp_buf_size < need) { + ctx->tmp_buf_size = UPB_MAX(64, upb_Log2Ceiling(need)); + ctx->tmp_buf = upb_Arena_Malloc(ctx->tmp_arena, ctx->tmp_buf_size); + if (!ctx->tmp_buf) _upb_DefBuilder_OomErr(ctx); + } + + memcpy(ctx->tmp_buf, &parent, sizeof(void*)); + memcpy(ctx->tmp_buf + sizeof(void*), key.data, key.size); + return upb_StringView_FromDataAndSize(ctx->tmp_buf, need); +} + +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key, + UPB_DESC(FeatureSet**) set) { + upb_StringView k = _upb_DefBuilder_MakeKey(ctx, parent, key); + upb_value v; + if (upb_strtable_lookup2(&ctx->feature_cache, k.data, k.size, &v)) { + *set = upb_value_getptr(v); + return false; + } + + *set = + upb_Message_DeepClone(parent, UPB_DESC_MINITABLE(FeatureSet), ctx->arena); + if (!*set) _upb_DefBuilder_OomErr(ctx); + + v = upb_value_ptr(*set); + if (!upb_strtable_insert(&ctx->feature_cache, k.data, k.size, v, + ctx->tmp_arena)) { + _upb_DefBuilder_OomErr(ctx); + } + + return true; +} + +const UPB_DESC(FeatureSet*) + _upb_DefBuilder_DoResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child, + bool is_implicit) { + assert(parent); + if (!child) return parent; + + if (child && !is_implicit && + upb_FileDef_Syntax(ctx->file) != kUpb_Syntax_Editions) { + _upb_DefBuilder_Errf(ctx, "Features can only be specified for editions"); + } + + UPB_DESC(FeatureSet*) resolved; + size_t child_size; + const char* child_bytes = + UPB_DESC(FeatureSet_serialize)(child, ctx->tmp_arena, &child_size); + if (!child_bytes) _upb_DefBuilder_OomErr(ctx); + + upb_StringView key = upb_StringView_FromDataAndSize(child_bytes, child_size); + if (!_upb_DefBuilder_GetOrCreateFeatureSet(ctx, parent, key, &resolved)) { + return resolved; + } + + upb_DecodeStatus dec_status = + upb_Decode(child_bytes, child_size, resolved, + UPB_DESC_MINITABLE(FeatureSet), NULL, 0, ctx->arena); + if (dec_status != kUpb_DecodeStatus_Ok) _upb_DefBuilder_OomErr(ctx); + + return resolved; +} diff --git a/upb/reflection/internal/def_builder.h b/upb/reflection/internal/def_builder.h index 584553214dea..b9a0bff5f8f7 100644 --- a/upb/reflection/internal/def_builder.h +++ b/upb/reflection/internal/def_builder.h @@ -36,6 +36,10 @@ extern "C" { struct upb_DefBuilder { upb_DefPool* symtab; + upb_strtable feature_cache; // Caches features by identity. + UPB_DESC(FeatureSet*) legacy_features; // For computing legacy features. + char* tmp_buf; // Temporary buffer in tmp_arena. + size_t tmp_buf_size; // Size of temporary buffer. upb_FileDef* file; // File we are building. upb_Arena* arena; // Allocate defs here. upb_Arena* tmp_arena; // For temporary allocations. @@ -128,6 +132,25 @@ UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx, if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, true); } +// Returns true if the returned feature set is new and must be populated. +bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + upb_StringView key, + UPB_DESC(FeatureSet**) set); + +const UPB_DESC(FeatureSet*) + _upb_DefBuilder_DoResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child, + bool is_implicit); + +UPB_INLINE const UPB_DESC(FeatureSet*) + _upb_DefBuilder_ResolveFeatures(upb_DefBuilder* ctx, + const UPB_DESC(FeatureSet*) parent, + const UPB_DESC(FeatureSet*) child) { + return _upb_DefBuilder_DoResolveFeatures(ctx, parent, child, false); +} + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/upb/reflection/internal/enum_def.h b/upb/reflection/internal/enum_def.h index 8f6b22011203..d8912a08c4d4 100644 --- a/upb/reflection/internal/enum_def.h +++ b/upb/reflection/internal/enum_def.h @@ -22,10 +22,11 @@ bool _upb_EnumDef_Insert(upb_EnumDef* e, upb_EnumValueDef* v, upb_Arena* a); const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e); // Allocate and initialize an array of |n| enum defs. -upb_EnumDef* _upb_EnumDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(EnumDescriptorProto) * const* protos, - const upb_MessageDef* containing_type); +upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(EnumDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const upb_MessageDef* containing_type); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/reflection/internal/enum_reserved_range.h b/upb/reflection/internal/enum_reserved_range.h index fe30604a1a86..6b988ee2458d 100644 --- a/upb/reflection/internal/enum_reserved_range.h +++ b/upb/reflection/internal/enum_reserved_range.h @@ -23,7 +23,7 @@ upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, // Allocate and initialize an array of |n| reserved ranges owned by |e|. upb_EnumReservedRange* _upb_EnumReservedRanges_New( upb_DefBuilder* ctx, int n, - const UPB_DESC(EnumDescriptorProto_EnumReservedRange) * const* protos, + const UPB_DESC(EnumDescriptorProto_EnumReservedRange*) const* protos, const upb_EnumDef* e); #ifdef __cplusplus diff --git a/upb/reflection/internal/enum_value_def.h b/upb/reflection/internal/enum_value_def.h index 2484567febac..e75e48a6e25a 100644 --- a/upb/reflection/internal/enum_value_def.h +++ b/upb/reflection/internal/enum_value_def.h @@ -22,7 +22,8 @@ upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i); // Allocate and initialize an array of |n| enum value defs owned by |e|. upb_EnumValueDef* _upb_EnumValueDefs_New( upb_DefBuilder* ctx, const char* prefix, int n, - const UPB_DESC(EnumValueDescriptorProto) * const* protos, upb_EnumDef* e, + const UPB_DESC(EnumValueDescriptorProto*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e, bool* is_sorted); const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, diff --git a/upb/reflection/internal/extension_range.h b/upb/reflection/internal/extension_range.h index 09901b41ff81..2432701c5f9c 100644 --- a/upb/reflection/internal/extension_range.h +++ b/upb/reflection/internal/extension_range.h @@ -22,8 +22,8 @@ upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i); // Allocate and initialize an array of |n| extension ranges owned by |m|. upb_ExtensionRange* _upb_ExtensionRanges_New( upb_DefBuilder* ctx, int n, - const UPB_DESC(DescriptorProto_ExtensionRange) * const* protos, - const upb_MessageDef* m); + const UPB_DESC(DescriptorProto_ExtensionRange*) const* protos, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* m); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/reflection/internal/field_def.h b/upb/reflection/internal/field_def.h index 838f3b607028..f41a8226a637 100644 --- a/upb/reflection/internal/field_def.h +++ b/upb/reflection/internal/field_def.h @@ -31,16 +31,19 @@ void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx, const upb_FieldDef* f); // Allocate and initialize an array of |n| extensions (field defs). -upb_FieldDef* _upb_Extensions_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m); +upb_FieldDef* _upb_Extensions_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m); // Allocate and initialize an array of |n| field defs. -upb_FieldDef* _upb_FieldDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix, - upb_MessageDef* m, bool* is_sorted); +upb_FieldDef* _upb_FieldDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(FieldDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + const char* prefix, upb_MessageDef* m, + bool* is_sorted); // Allocate and return a list of pointers to the |n| field defs in |ff|, // sorted by field number. diff --git a/upb/reflection/internal/message_def.h b/upb/reflection/internal/message_def.h index 6cc9686a7415..a8bcec244f48 100644 --- a/upb/reflection/internal/message_def.h +++ b/upb/reflection/internal/message_def.h @@ -30,9 +30,12 @@ void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m); // Allocate and initialize an array of |n| message defs. -upb_MessageDef* _upb_MessageDefs_New( - upb_DefBuilder* ctx, int n, const UPB_DESC(DescriptorProto) * const* protos, - const upb_MessageDef* containing_type); +upb_MessageDef* _upb_MessageDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features, + const upb_MessageDef* containing_type); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/reflection/internal/method_def.h b/upb/reflection/internal/method_def.h index a7e8ef8a37a1..b2b628d64227 100644 --- a/upb/reflection/internal/method_def.h +++ b/upb/reflection/internal/method_def.h @@ -20,9 +20,11 @@ extern "C" { upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i); // Allocate and initialize an array of |n| method defs owned by |s|. -upb_MethodDef* _upb_MethodDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(MethodDescriptorProto) * const* protos, upb_ServiceDef* s); +upb_MethodDef* _upb_MethodDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(MethodDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/reflection/internal/oneof_def.h b/upb/reflection/internal/oneof_def.h index 9cd6713efd32..7d803d592cd8 100644 --- a/upb/reflection/internal/oneof_def.h +++ b/upb/reflection/internal/oneof_def.h @@ -22,9 +22,11 @@ void _upb_OneofDef_Insert(upb_DefBuilder* ctx, upb_OneofDef* o, const upb_FieldDef* f, const char* name, size_t size); // Allocate and initialize an array of |n| oneof defs owned by |m|. -upb_OneofDef* _upb_OneofDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(OneofDescriptorProto) * const* protos, upb_MessageDef* m); +upb_OneofDef* _upb_OneofDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(OneofDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_MessageDef* m); size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m); diff --git a/upb/reflection/internal/service_def.h b/upb/reflection/internal/service_def.h index 2845b879070c..b95b53b842f7 100644 --- a/upb/reflection/internal/service_def.h +++ b/upb/reflection/internal/service_def.h @@ -20,9 +20,11 @@ extern "C" { upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int i); // Allocate and initialize an array of |n| service defs. -upb_ServiceDef* _upb_ServiceDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(ServiceDescriptorProto) * const* protos); +upb_ServiceDef* _upb_ServiceDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(ServiceDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/reflection/internal/upb_edition_defaults.h b/upb/reflection/internal/upb_edition_defaults.h new file mode 100644 index 000000000000..587d3b13d184 --- /dev/null +++ b/upb/reflection/internal/upb_edition_defaults.h @@ -0,0 +1,20 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ +#define UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + +// This file contains the serialized FeatureSetDefaults object for +// language-independent features and (possibly at some point) for upb-specific +// features. This is used for feature resolution under Editions. +// NOLINTBEGIN +// clang-format off +#define UPB_INTERNAL_UPB_EDITION_DEFAULTS "\n\021\022\014\010\001\020\002\030\002 \001(\0010\002\030\346\007\n\021\022\014\010\002\020\001\030\001 \002(\0010\001\030\347\007\n\021\022\014\010\001\020\001\030\001 \002(\0010\001\030\350\007 \346\007(\350\007" +// clang-format on +// NOLINTEND + +#endif // UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ diff --git a/upb/reflection/internal/upb_edition_defaults.h.template b/upb/reflection/internal/upb_edition_defaults.h.template new file mode 100644 index 000000000000..58ff7f1eb39f --- /dev/null +++ b/upb/reflection/internal/upb_edition_defaults.h.template @@ -0,0 +1,20 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ +#define UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ + +// This file contains the serialized FeatureSetDefaults object for +// language-independent features and (possibly at some point) for upb-specific +// features. This is used for feature resolution under Editions. +// NOLINTBEGIN +// clang-format off +#define UPB_INTERNAL_UPB_EDITION_DEFAULTS "DEFAULTS_VALUE" +// clang-format on +// NOLINTEND + +#endif // UPB_REFLECTION_UPB_EDITION_DEFAULTS_H_ diff --git a/upb/reflection/message_def.c b/upb/reflection/message_def.c index 9e55d612a4ca..96037d18633d 100644 --- a/upb/reflection/message_def.c +++ b/upb/reflection/message_def.c @@ -28,7 +28,8 @@ #include "upb/port/def.inc" struct upb_MessageDef { - const UPB_DESC(MessageOptions) * opts; + const UPB_DESC(MessageOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_MiniTable* layout; const upb_FileDef* file; const upb_MessageDef* containing_type; @@ -66,6 +67,9 @@ struct upb_MessageDef { bool in_message_set; bool is_sorted; upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; static void assign_msg_wellknowntype(upb_MessageDef* m) { @@ -397,10 +401,9 @@ void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); - // TODO: Once editions is supported this should turn into a - // check on LEGACY_BEST_EFFORT if (strcmp(shortname, json_name) != 0 && - upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3 && + UPB_DESC(FeatureSet_json_format)(m->resolved_features) == + UPB_DESC(FeatureSet_ALLOW) && upb_strtable_lookup(&m->ntof, json_name, &v)) { _upb_DefBuilder_Errf( ctx, "duplicate json_name for (%s) with original field name (%s)", @@ -517,7 +520,8 @@ static bool _upb_MessageDef_ValidateUtf8(const upb_MessageDef* m) { static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { uint64_t out = 0; - if (upb_FileDef_Syntax(m->file) == kUpb_Syntax_Proto3) { + if (UPB_DESC(FeatureSet_repeated_field_encoding(m->resolved_features)) == + UPB_DESC(FeatureSet_PACKED)) { out |= kUpb_MessageModifier_DefaultIsPacked; } @@ -631,7 +635,8 @@ static upb_StringView* _upb_ReservedNames_New(upb_DefBuilder* ctx, int n, } static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, - const UPB_DESC(DescriptorProto) * msg_proto, + const UPB_DESC(DescriptorProto*) msg_proto, + const UPB_DESC(FeatureSet*) parent_features, const upb_MessageDef* containing_type, upb_MessageDef* m) { const UPB_DESC(OneofDescriptorProto)* const* oneofs; @@ -643,6 +648,10 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, size_t n_ext_range, n_res_range, n_res_name; upb_StringView name; + UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(MessageOptions_features)(m->opts)); + // Must happen before _upb_DefBuilder_Add() m->file = _upb_DefBuilder_File(ctx); @@ -671,14 +680,12 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, ok = upb_strtable_init(&m->jtof, n_field, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); - UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); - m->oneof_count = n_oneof; - m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m); + m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m->resolved_features, m); m->field_count = n_field; - m->fields = - _upb_FieldDefs_New(ctx, n_field, fields, m->full_name, m, &m->is_sorted); + m->fields = _upb_FieldDefs_New(ctx, n_field, fields, m->resolved_features, + m->full_name, m, &m->is_sorted); // Message Sets may not contain fields. if (UPB_UNLIKELY(UPB_DESC(MessageOptions_message_set_wire_format)(m->opts))) { @@ -688,7 +695,8 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, } m->ext_range_count = n_ext_range; - m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); + m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, + m->resolved_features, m); m->res_range_count = n_res_range; m->res_ranges = @@ -706,23 +714,29 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, const UPB_DESC(EnumDescriptorProto)* const* enums = UPB_DESC(DescriptorProto_enum_type)(msg_proto, &n_enum); m->nested_enum_count = n_enum; - m->nested_enums = _upb_EnumDefs_New(ctx, n_enum, enums, m); + m->nested_enums = + _upb_EnumDefs_New(ctx, n_enum, enums, m->resolved_features, m); const UPB_DESC(FieldDescriptorProto)* const* exts = UPB_DESC(DescriptorProto_extension)(msg_proto, &n_ext); m->nested_ext_count = n_ext; - m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->full_name, m); + m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->resolved_features, + m->full_name, m); const UPB_DESC(DescriptorProto)* const* msgs = UPB_DESC(DescriptorProto_nested_type)(msg_proto, &n_msg); m->nested_msg_count = n_msg; - m->nested_msgs = _upb_MessageDefs_New(ctx, n_msg, msgs, m); + m->nested_msgs = + _upb_MessageDefs_New(ctx, n_msg, msgs, m->resolved_features, m); } // Allocate and initialize an array of |n| message defs. -upb_MessageDef* _upb_MessageDefs_New( - upb_DefBuilder* ctx, int n, const UPB_DESC(DescriptorProto) * const* protos, - const upb_MessageDef* containing_type) { +upb_MessageDef* _upb_MessageDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(DescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features, + const upb_MessageDef* containing_type) { _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); const char* name = containing_type ? containing_type->full_name @@ -730,7 +744,8 @@ upb_MessageDef* _upb_MessageDefs_New( upb_MessageDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageDef) * n); for (int i = 0; i < n; i++) { - create_msgdef(ctx, name, protos[i], containing_type, &m[i]); + create_msgdef(ctx, name, protos[i], parent_features, containing_type, + &m[i]); } return m; } diff --git a/upb/reflection/message_def.h b/upb/reflection/message_def.h index a5c85efe23c6..1a92ed4349a2 100644 --- a/upb/reflection/message_def.h +++ b/upb/reflection/message_def.h @@ -136,6 +136,8 @@ int upb_MessageDef_RealOneofCount(const upb_MessageDef* m); const UPB_DESC(MessageOptions) * upb_MessageDef_Options(const upb_MessageDef* m); +const UPB_DESC(FeatureSet) * + upb_MessageDef_ResolvedFeatures(const upb_MessageDef* m); upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i); int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m); diff --git a/upb/reflection/method_def.c b/upb/reflection/method_def.c index 049ef4a81d17..ee4e06efff8a 100644 --- a/upb/reflection/method_def.c +++ b/upb/reflection/method_def.c @@ -15,7 +15,8 @@ #include "upb/port/def.inc" struct upb_MethodDef { - const UPB_DESC(MethodOptions) * opts; + const UPB_DESC(MethodOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; upb_ServiceDef* service; const char* full_name; const upb_MessageDef* input_type; @@ -68,8 +69,14 @@ bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { } static void create_method(upb_DefBuilder* ctx, - const UPB_DESC(MethodDescriptorProto) * method_proto, + const UPB_DESC(MethodDescriptorProto*) method_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_ServiceDef* s, upb_MethodDef* m) { + UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, + method_proto); + m->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(MethodOptions_features)(m->opts)); + upb_StringView name = UPB_DESC(MethodDescriptorProto_name)(method_proto); m->service = s; @@ -87,18 +94,17 @@ static void create_method(upb_DefBuilder* ctx, ctx, m->full_name, m->full_name, UPB_DESC(MethodDescriptorProto_output_type)(method_proto), UPB_DEFTYPE_MSG); - - UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, - method_proto); } // Allocate and initialize an array of |n| method defs belonging to |s|. -upb_MethodDef* _upb_MethodDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(MethodDescriptorProto) * const* protos, upb_ServiceDef* s) { +upb_MethodDef* _upb_MethodDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(MethodDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_ServiceDef* s) { upb_MethodDef* m = _upb_DefBuilder_Alloc(ctx, sizeof(upb_MethodDef) * n); for (int i = 0; i < n; i++) { - create_method(ctx, protos[i], s, &m[i]); + create_method(ctx, protos[i], parent_features, s, &m[i]); m[i].index = i; } return m; diff --git a/upb/reflection/method_def.h b/upb/reflection/method_def.h index 64b88a66832e..4abfb69e0f60 100644 --- a/upb/reflection/method_def.h +++ b/upb/reflection/method_def.h @@ -26,6 +26,8 @@ int upb_MethodDef_Index(const upb_MethodDef* m); const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); const char* upb_MethodDef_Name(const upb_MethodDef* m); const UPB_DESC(MethodOptions) * upb_MethodDef_Options(const upb_MethodDef* m); +const UPB_DESC(FeatureSet) * + upb_MethodDef_ResolvedFeatures(const upb_MethodDef* m); const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m); bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m); const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); diff --git a/upb/reflection/oneof_def.c b/upb/reflection/oneof_def.c index 869ca16b96c4..8f639df2842c 100644 --- a/upb/reflection/oneof_def.c +++ b/upb/reflection/oneof_def.c @@ -22,7 +22,8 @@ #include "upb/port/def.inc" struct upb_OneofDef { - const UPB_DESC(OneofOptions) * opts; + const UPB_DESC(OneofOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_MessageDef* parent; const char* full_name; int field_count; @@ -30,9 +31,6 @@ struct upb_OneofDef { const upb_FieldDef** fields; upb_strtable ntof; // lookup a field by name upb_inttable itof; // lookup a field by number (index) -#if UINTPTR_MAX == 0xffffffff - uint32_t padding; // Increase size to a multiple of 8. -#endif }; upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { @@ -166,9 +164,15 @@ size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { } static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, - const UPB_DESC(OneofDescriptorProto) * oneof_proto, + const UPB_DESC(OneofDescriptorProto*) oneof_proto, + const UPB_DESC(FeatureSet*) parent_features, const upb_OneofDef* _o) { upb_OneofDef* o = (upb_OneofDef*)_o; + + UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + o->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(OneofOptions_features)(o->opts)); + upb_StringView name = UPB_DESC(OneofDescriptorProto_name)(oneof_proto); o->parent = m; @@ -177,8 +181,6 @@ static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, o->field_count = 0; o->synthetic = false; - UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); - if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); } @@ -195,14 +197,16 @@ static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, } // Allocate and initialize an array of |n| oneof defs. -upb_OneofDef* _upb_OneofDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(OneofDescriptorProto) * const* protos, upb_MessageDef* m) { +upb_OneofDef* _upb_OneofDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(OneofDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) parent_features, + upb_MessageDef* m) { _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); upb_OneofDef* o = _upb_DefBuilder_Alloc(ctx, sizeof(upb_OneofDef) * n); for (int i = 0; i < n; i++) { - create_oneofdef(ctx, m, protos[i], &o[i]); + create_oneofdef(ctx, m, protos[i], parent_features, &o[i]); } return o; } diff --git a/upb/reflection/oneof_def.h b/upb/reflection/oneof_def.h index 38c7a7002f32..1a62f3dc8b7b 100644 --- a/upb/reflection/oneof_def.h +++ b/upb/reflection/oneof_def.h @@ -36,7 +36,9 @@ const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, uint32_t num); UPB_API const char* upb_OneofDef_Name(const upb_OneofDef* o); int upb_OneofDef_numfields(const upb_OneofDef* o); -const UPB_DESC(OneofOptions) * upb_OneofDef_Options(const upb_OneofDef* o); +const UPB_DESC(OneofOptions*) upb_OneofDef_Options(const upb_OneofDef* o); +const UPB_DESC(FeatureSet*) + upb_OneofDef_ResolvedFeatures(const upb_OneofDef* o); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/reflection/service_def.c b/upb/reflection/service_def.c index 7a0cbc7a09b8..34ea9c9ca533 100644 --- a/upb/reflection/service_def.c +++ b/upb/reflection/service_def.c @@ -16,12 +16,16 @@ #include "upb/port/def.inc" struct upb_ServiceDef { - const UPB_DESC(ServiceOptions) * opts; + const UPB_DESC(ServiceOptions*) opts; + const UPB_DESC(FeatureSet*) resolved_features; const upb_FileDef* file; const char* full_name; upb_MethodDef* methods; int method_count; int index; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { @@ -72,37 +76,40 @@ const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, } static void create_service(upb_DefBuilder* ctx, - const UPB_DESC(ServiceDescriptorProto) * svc_proto, + const UPB_DESC(ServiceDescriptorProto*) svc_proto, + const UPB_DESC(FeatureSet*) parent_features, upb_ServiceDef* s) { - upb_StringView name; - size_t n; + UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, + svc_proto); + s->resolved_features = _upb_DefBuilder_ResolveFeatures( + ctx, parent_features, UPB_DESC(ServiceOptions_features)(s->opts)); // Must happen before _upb_DefBuilder_Add() s->file = _upb_DefBuilder_File(ctx); - name = UPB_DESC(ServiceDescriptorProto_name)(svc_proto); + upb_StringView name = UPB_DESC(ServiceDescriptorProto_name)(svc_proto); const char* package = _upb_FileDef_RawPackage(s->file); s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); _upb_DefBuilder_Add(ctx, s->full_name, _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); + size_t n; const UPB_DESC(MethodDescriptorProto)* const* methods = UPB_DESC(ServiceDescriptorProto_method)(svc_proto, &n); s->method_count = n; - s->methods = _upb_MethodDefs_New(ctx, n, methods, s); - - UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, - svc_proto); + s->methods = _upb_MethodDefs_New(ctx, n, methods, s->resolved_features, s); } -upb_ServiceDef* _upb_ServiceDefs_New( - upb_DefBuilder* ctx, int n, - const UPB_DESC(ServiceDescriptorProto) * const* protos) { +upb_ServiceDef* _upb_ServiceDefs_New(upb_DefBuilder* ctx, int n, + const UPB_DESC(ServiceDescriptorProto*) + const* protos, + const UPB_DESC(FeatureSet*) + parent_features) { _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); upb_ServiceDef* s = _upb_DefBuilder_Alloc(ctx, sizeof(upb_ServiceDef) * n); for (int i = 0; i < n; i++) { - create_service(ctx, protos[i], &s[i]); + create_service(ctx, protos[i], parent_features, &s[i]); s[i].index = i; } return s; diff --git a/upb/reflection/service_def.h b/upb/reflection/service_def.h index 98cd993b4d72..781932e176fc 100644 --- a/upb/reflection/service_def.h +++ b/upb/reflection/service_def.h @@ -30,6 +30,8 @@ int upb_ServiceDef_MethodCount(const upb_ServiceDef* s); const char* upb_ServiceDef_Name(const upb_ServiceDef* s); const UPB_DESC(ServiceOptions) * upb_ServiceDef_Options(const upb_ServiceDef* s); +const UPB_DESC(FeatureSet) * + upb_ServiceDef_ResolvedFeatures(const upb_ServiceDef* s); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/util/required_fields.c b/upb/util/required_fields.c index c6616ecdd3f7..b93adc0d9958 100644 --- a/upb/util/required_fields.c +++ b/upb/util/required_fields.c @@ -196,7 +196,7 @@ static void upb_util_FindUnsetInMessage(upb_FindContext* ctx, // Iterate over all fields to see if any required fields are missing. for (int i = 0, n = upb_MessageDef_FieldCount(m); i < n; i++) { const upb_FieldDef* f = upb_MessageDef_Field(m, i); - if (upb_FieldDef_Label(f) != kUpb_Label_Required) continue; + if (!upb_FieldDef_IsRequired(f)) continue; if (!msg || !upb_Message_HasFieldByDef(msg, f)) { // A required field is missing.