mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
parent
c657b59bf6
commit
efacad9581
29 changed files with 177 additions and 975 deletions
25
.github/workflows/test_upb.yml
vendored
25
.github/workflows/test_upb.yml
vendored
|
|
@ -30,8 +30,6 @@ jobs:
|
|||
config:
|
||||
- { name: "Fastbuild" }
|
||||
- { name: "Optimized", flags: "-c opt", continuous-only: true }
|
||||
- { name: "GCC Optimized", flags: "-c opt --force_pic --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-12.2-12e21b8dda91028bc14212a3ab582c7c4d149fac" }
|
||||
- { name: "GCC Static", flags: "-c opt --dynamic_mode=off --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-12.2-12e21b8dda91028bc14212a3ab582c7c4d149fac", continuous-only: true }
|
||||
- { name: "ASAN", flags: "--config=asan -c dbg", exclude-targets: "-//benchmarks:benchmark -//python/...", runner: ubuntu-22-4core }
|
||||
- { name: "UBSAN", flags: "--config=ubsan -c dbg", exclude-targets: "-//benchmarks:benchmark -//python/... -//lua/...", continuous-only: true }
|
||||
- { name: "32-bit", flags: "--copt=-m32 --linkopt=-m32", exclude-targets: "-//benchmarks:benchmark -//python/..." }
|
||||
|
|
@ -51,12 +49,33 @@ jobs:
|
|||
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: ${{ matrix.config.image || 'us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:8.0.1-12e21b8dda91028bc14212a3ab582c7c4d149fac' }}
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:${{ matrix.config.bazel_version || '8.0.1' }}-12e21b8dda91028bc14212a3ab582c7c4d149fac
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: upb-bazel
|
||||
bazel: test //bazel/... //benchmarks/... //lua/... //python/... //upb/... //upb_generator/... ${{ matrix.config.flags }}
|
||||
exclude-targets: ${{ matrix.config.exclude-targets }}
|
||||
|
||||
linux-gcc:
|
||||
strategy:
|
||||
fail-fast: false # Don't cancel all jobs if one fails.
|
||||
name: GCC Optimized
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout pending changes
|
||||
uses: protocolbuffers/protobuf-ci/checkout@v5
|
||||
with:
|
||||
ref: ${{ inputs.safe-checkout }}
|
||||
- name: Run tests
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-12.2-12e21b8dda91028bc14212a3ab582c7c4d149fac"
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: "upb-bazel-gcc"
|
||||
bazel: >-
|
||||
test -c opt
|
||||
--copt="-Wno-error=maybe-uninitialized" --java_runtime_version=remotejdk_11
|
||||
//bazel/... //benchmarks/... //lua/... //python/... //upb/... //upb_generator/...
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
fail-fast: false # Don't cancel all jobs if one fails.
|
||||
|
|
|
|||
|
|
@ -185,14 +185,12 @@ upb/message/value.h
|
|||
upb/mini_descriptor/build_enum.h
|
||||
upb/mini_descriptor/decode.h
|
||||
upb/mini_descriptor/link.h
|
||||
upb/mini_table/compat.h
|
||||
upb/mini_table/debug_string.h
|
||||
upb/mini_table/enum.h
|
||||
upb/mini_table/extension.h
|
||||
upb/mini_table/extension_registry.h
|
||||
upb/mini_table/field.h
|
||||
upb/mini_table/file.h
|
||||
upb/mini_table/generated_registry.h
|
||||
upb/mini_table/message.h
|
||||
upb/mini_table/sub.h
|
||||
upb/port/atomic.h
|
||||
|
|
|
|||
|
|
@ -249,7 +249,6 @@ cc_dist_library(
|
|||
"//upb/json",
|
||||
"//upb/message:compare",
|
||||
"//upb/message:copy",
|
||||
"//upb/mini_table:compat",
|
||||
"//upb/mini_table:debug_string",
|
||||
"//upb/text",
|
||||
"//upb/text:debug",
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ cc_library(
|
|||
"//upb/message:internal",
|
||||
"//upb/mini_descriptor",
|
||||
"//upb/mini_table",
|
||||
"//upb/mini_table:internal",
|
||||
"//upb/wire",
|
||||
] + select({
|
||||
":fasttable_enabled_setting": [
|
||||
|
|
@ -309,13 +308,9 @@ filegroup(
|
|||
filegroup(
|
||||
name = "test_srcs",
|
||||
srcs = [
|
||||
"//upb/hash:test_srcs",
|
||||
"//upb/json:test_srcs",
|
||||
"//upb/lex:test_srcs",
|
||||
"//upb/mem:test_srcs",
|
||||
"//upb/message:test_srcs",
|
||||
"//upb/mini_descriptor:test_srcs",
|
||||
"//upb/mini_table:test_srcs",
|
||||
"//upb/test:test_srcs",
|
||||
"//upb/util:test_srcs",
|
||||
"//upb/wire:test_srcs",
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
#include "upb/mini_table/extension_registry.h"
|
||||
#include "upb/mini_table/field.h"
|
||||
#include "upb/mini_table/file.h"
|
||||
#include "upb/mini_table/internal/generated_registry.h"
|
||||
#include "upb/mini_table/message.h"
|
||||
#include "upb/mini_table/sub.h"
|
||||
#include "upb/wire/decode.h"
|
||||
|
|
|
|||
|
|
@ -65,5 +65,5 @@ filegroup(
|
|||
"**/*test.cc",
|
||||
],
|
||||
),
|
||||
visibility = ["//upb:__pkg__"],
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -72,5 +72,5 @@ filegroup(
|
|||
"**/*test.cc",
|
||||
],
|
||||
),
|
||||
visibility = ["//upb:__pkg__"],
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -105,5 +105,5 @@ filegroup(
|
|||
"**/*test.cc",
|
||||
],
|
||||
),
|
||||
visibility = ["//upb:__pkg__"],
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ cc_library(
|
|||
name = "mini_table",
|
||||
srcs = [
|
||||
"extension_registry.c",
|
||||
"generated_registry.c",
|
||||
"message.c",
|
||||
],
|
||||
hdrs = [
|
||||
|
|
@ -37,7 +36,6 @@ cc_library(
|
|||
"extension_registry.h",
|
||||
"field.h",
|
||||
"file.h",
|
||||
"generated_registry.h",
|
||||
"message.h",
|
||||
"sub.h",
|
||||
],
|
||||
|
|
@ -86,7 +84,6 @@ cc_library(
|
|||
"internal/extension.h",
|
||||
"internal/field.h",
|
||||
"internal/file.h",
|
||||
"internal/generated_registry.h",
|
||||
"internal/message.h",
|
||||
"internal/size_log2.h",
|
||||
"internal/sub.h",
|
||||
|
|
@ -95,6 +92,7 @@ cc_library(
|
|||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//upb/base",
|
||||
"//upb/hash",
|
||||
"//upb/mem",
|
||||
"//upb/message:types",
|
||||
"//upb/port",
|
||||
|
|
@ -133,21 +131,6 @@ cc_test(
|
|||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "generated_registry_test",
|
||||
srcs = ["generated_registry_test.cc"],
|
||||
deps = [
|
||||
":mini_table",
|
||||
"//src/google/protobuf:descriptor_upb_minitable_proto",
|
||||
"//upb/test:custom_options_upb_minitable_proto",
|
||||
"//upb/test:editions_test_upb_minitable_proto",
|
||||
"//upb/test:test_multiple_files_upb_minitable_proto",
|
||||
"@abseil-cpp//absl/synchronization",
|
||||
"@googletest//:gtest",
|
||||
"@googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "message_benchmark_proto",
|
||||
testonly = 1,
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
#include "upb/hash/str_table.h"
|
||||
#include "upb/mem/arena.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/generated_registry.h"
|
||||
#include "upb/mini_table/internal/generated_registry.h"
|
||||
#include "upb/mini_table/message.h"
|
||||
|
||||
// Must be last.
|
||||
|
|
@ -91,46 +89,25 @@ failure:
|
|||
return status;
|
||||
}
|
||||
|
||||
const UPB_PRIVATE(upb_GeneratedExtensionListEntry) *
|
||||
UPB_PRIVATE(upb_generated_extension_list) = NULL;
|
||||
#ifdef UPB_LINKARR_DECLARE
|
||||
|
||||
UPB_LINKARR_DECLARE(upb_AllExts, const upb_MiniTableExtension);
|
||||
|
||||
bool upb_ExtensionRegistry_AddAllLinkedExtensions(upb_ExtensionRegistry* r) {
|
||||
const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* entry =
|
||||
UPB_PRIVATE(upb_generated_extension_list);
|
||||
while (entry != NULL) {
|
||||
// Comparing pointers to different objects is undefined behavior, so we
|
||||
// convert them to uintptr_t and compare their values.
|
||||
uintptr_t begin = (uintptr_t)entry->start;
|
||||
uintptr_t end = (uintptr_t)entry->stop;
|
||||
uintptr_t current = begin;
|
||||
while (current < end) {
|
||||
const upb_MiniTableExtension* ext =
|
||||
(const upb_MiniTableExtension*)current;
|
||||
// Sentinels and padding introduced by the linker can result in zeroed
|
||||
// entries, so simply skip them.
|
||||
if (upb_MiniTableExtension_Number(ext) == 0) {
|
||||
// MSVC introduces padding that might not be sized exactly the same as
|
||||
// upb_MiniTableExtension, so we can't iterate by sizeof. This is a
|
||||
// valid thing for any linker to do, so it's safer to just always do it.
|
||||
current += UPB_ALIGN_OF(upb_MiniTableExtension);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (upb_ExtensionRegistry_Add(r, ext) !=
|
||||
kUpb_ExtensionRegistryStatus_Ok) {
|
||||
const upb_MiniTableExtension* start = UPB_LINKARR_START(upb_AllExts);
|
||||
const upb_MiniTableExtension* stop = UPB_LINKARR_STOP(upb_AllExts);
|
||||
for (const upb_MiniTableExtension* p = start; p < stop; p++) {
|
||||
// Windows can introduce zero padding, so we have to skip zeroes.
|
||||
if (upb_MiniTableExtension_Number(p) != 0) {
|
||||
if (upb_ExtensionRegistry_Add(r, p) != kUpb_ExtensionRegistryStatus_Ok) {
|
||||
return false;
|
||||
}
|
||||
current += sizeof(upb_MiniTableExtension);
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const upb_ExtensionRegistry* upb_ExtensionRegistry_GetGenerated(
|
||||
const upb_GeneratedRegistryRef* genreg) {
|
||||
return genreg != NULL ? genreg->registry : NULL;
|
||||
}
|
||||
#endif // UPB_LINKARR_DECLARE
|
||||
|
||||
const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup(
|
||||
const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include "upb/mem/arena.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/generated_registry.h"
|
||||
#include "upb/mini_table/message.h"
|
||||
|
||||
// Must be last.
|
||||
|
|
@ -80,6 +79,8 @@ UPB_API upb_ExtensionRegistryStatus upb_ExtensionRegistry_Add(
|
|||
upb_ExtensionRegistryStatus upb_ExtensionRegistry_AddArray(
|
||||
upb_ExtensionRegistry* r, const upb_MiniTableExtension** e, size_t count);
|
||||
|
||||
#ifdef UPB_LINKARR_DECLARE
|
||||
|
||||
// Adds all extensions linked into the binary into the registry. The set of
|
||||
// linked extensions is assembled by the linker using linker arrays. This
|
||||
// will likely not work properly if the extensions are split across multiple
|
||||
|
|
@ -93,14 +94,7 @@ upb_ExtensionRegistryStatus upb_ExtensionRegistry_AddArray(
|
|||
UPB_API bool upb_ExtensionRegistry_AddAllLinkedExtensions(
|
||||
upb_ExtensionRegistry* r);
|
||||
|
||||
// Returns the extension registry contained by a reference to the generated
|
||||
// registry. The reference must be held for the lifetime of the registry.
|
||||
//
|
||||
// TODO This should actually be moved to generated_registry.h, but
|
||||
// can't because of the current location of
|
||||
// upb_ExtensionRegistry_AddAllLinkedExtensions.
|
||||
UPB_API const upb_ExtensionRegistry* upb_ExtensionRegistry_GetGenerated(
|
||||
const upb_GeneratedRegistryRef* genreg);
|
||||
#endif // UPB_LINKARR_DECLARE
|
||||
|
||||
// Looks up the extension (if any) defined for message type |t| and field
|
||||
// number |num|. Returns the extension if found, otherwise NULL.
|
||||
|
|
|
|||
|
|
@ -1,140 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2025 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
|
||||
|
||||
#include "upb/mini_table/generated_registry.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "upb/mem/alloc.h"
|
||||
#include "upb/mem/arena.h"
|
||||
#include "upb/mini_table/extension_registry.h"
|
||||
#include "upb/mini_table/internal/generated_registry.h" // IWYU pragma: keep
|
||||
#include "upb/port/atomic.h"
|
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
||||
#if UPB_TSAN
|
||||
#include <sched.h>
|
||||
#endif // UPB_TSAN
|
||||
|
||||
typedef struct upb_GeneratedRegistry {
|
||||
UPB_ATOMIC(upb_GeneratedRegistryRef*) ref;
|
||||
UPB_ATOMIC(int32_t) ref_count;
|
||||
} upb_GeneratedRegistry;
|
||||
|
||||
static upb_GeneratedRegistry* _upb_generated_registry(void) {
|
||||
static upb_GeneratedRegistry r = {NULL, 0};
|
||||
return &r;
|
||||
}
|
||||
|
||||
// Constructs a new GeneratedRegistryRef, adding all linked extensions to the
|
||||
// registry or returning NULL on failure.
|
||||
static upb_GeneratedRegistryRef* _upb_GeneratedRegistry_New(void) {
|
||||
upb_Arena* arena = NULL;
|
||||
upb_ExtensionRegistry* extreg = NULL;
|
||||
upb_GeneratedRegistryRef* ref = upb_gmalloc(sizeof(upb_GeneratedRegistryRef));
|
||||
if (ref == NULL) goto err;
|
||||
arena = upb_Arena_New();
|
||||
if (arena == NULL) goto err;
|
||||
extreg = upb_ExtensionRegistry_New(arena);
|
||||
if (extreg == NULL) goto err;
|
||||
|
||||
ref->arena = arena;
|
||||
ref->registry = extreg;
|
||||
|
||||
if (!upb_ExtensionRegistry_AddAllLinkedExtensions(extreg)) goto err;
|
||||
|
||||
return ref;
|
||||
|
||||
err:
|
||||
if (arena != NULL) upb_Arena_Free(arena);
|
||||
if (ref != NULL) upb_gfree(ref);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const upb_GeneratedRegistryRef* upb_GeneratedRegistry_Load(void) {
|
||||
upb_GeneratedRegistry* registry = _upb_generated_registry();
|
||||
|
||||
// Loop until we successfully acquire a reference. This loop should only
|
||||
// kick in under extremely high contention, and it should be guaranteed to
|
||||
// succeed.
|
||||
while (true) {
|
||||
int32_t count = upb_Atomic_Load(®istry->ref_count, memory_order_acquire);
|
||||
|
||||
// Try to increment the refcount, but only if it's not zero.
|
||||
while (count > 0) {
|
||||
if (upb_Atomic_CompareExchangeStrong(®istry->ref_count, &count,
|
||||
count + 1, memory_order_acquire,
|
||||
memory_order_relaxed)) {
|
||||
// Successfully incremented. We can now safely load and return the
|
||||
// pointer.
|
||||
const upb_GeneratedRegistryRef* ref =
|
||||
upb_Atomic_Load(®istry->ref, memory_order_acquire);
|
||||
UPB_ASSERT(ref != NULL);
|
||||
return ref;
|
||||
}
|
||||
// CAS failed, `count` was updated. Loop will retry.
|
||||
}
|
||||
|
||||
// If we're here, the count was 0. Time for the slow path.
|
||||
// Double-check that the pointer is NULL before trying to create.
|
||||
upb_GeneratedRegistryRef* ref =
|
||||
upb_Atomic_Load(®istry->ref, memory_order_acquire);
|
||||
if (ref == NULL) {
|
||||
// Pointer is NULL, try to create and publish a new registry.
|
||||
upb_GeneratedRegistryRef* new_ref = _upb_GeneratedRegistry_New();
|
||||
if (new_ref == NULL) return NULL; // OOM
|
||||
|
||||
// Try to CAS the pointer from NULL to our new_ref.
|
||||
if (upb_Atomic_CompareExchangeStrong(®istry->ref, &ref, new_ref,
|
||||
memory_order_release,
|
||||
memory_order_acquire)) {
|
||||
// We won the race. Set the ref count to 1.
|
||||
upb_Atomic_Store(®istry->ref_count, 1, memory_order_release);
|
||||
return new_ref;
|
||||
} else {
|
||||
// We lost the race. `ref` now holds the pointer from the winning
|
||||
// thread. Clean up our unused one and loop to try again to get a
|
||||
// reference.
|
||||
upb_Arena_Free(new_ref->arena);
|
||||
upb_gfree(new_ref);
|
||||
}
|
||||
}
|
||||
// If we are here, either we lost the CAS race, or the pointer was already
|
||||
// non-NULL. In either case, we loop to the top and try to increment the
|
||||
// refcount of the existing object.
|
||||
|
||||
#if UPB_TSAN
|
||||
// Yield to give other threads a chance to increment the refcount. This is
|
||||
// especially an issue for TSAN builds, which are prone to locking up from
|
||||
// the thread with the upb_Atomic_Store call above getting starved.
|
||||
sched_yield();
|
||||
#endif // UPB_TSAN
|
||||
}
|
||||
}
|
||||
|
||||
void upb_GeneratedRegistry_Release(const upb_GeneratedRegistryRef* r) {
|
||||
if (r == NULL) return;
|
||||
|
||||
upb_GeneratedRegistry* registry = _upb_generated_registry();
|
||||
|
||||
int ref_count = upb_Atomic_Sub(®istry->ref_count, 1, memory_order_acq_rel);
|
||||
UPB_ASSERT(registry->ref_count >= 0);
|
||||
|
||||
// A ref_count of 1 means that we decremented the refcount to 0.
|
||||
if (ref_count == 1) {
|
||||
upb_GeneratedRegistryRef* ref =
|
||||
upb_Atomic_Exchange(®istry->ref, NULL, memory_order_acq_rel);
|
||||
if (ref != NULL) {
|
||||
// This is the last reference and we won any potential race to store NULL,
|
||||
// so we need to clean up.
|
||||
upb_Arena_Free(ref->arena);
|
||||
upb_gfree(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2025 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_MINI_TABLE_GENERATED_REGISTRY_H_
|
||||
#define UPB_MINI_TABLE_GENERATED_REGISTRY_H_
|
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Generated registry: a global singleton that gathers all extensions linked
|
||||
* into the binary.
|
||||
*
|
||||
* This singleton is thread-safe and lock-free, implemented using atomics. The
|
||||
* registry is lazily initialized the first time it is loaded. When all
|
||||
* references are released, the registry will be destroyed. New loads
|
||||
* afterwards will simply reload the same registry as needed.
|
||||
*
|
||||
* The extension minitables are registered in gencode using linker arrays. Each
|
||||
* .proto file produces a weak, hidden, constructor function that adds all
|
||||
* visible extensions from the array into the registry. In each binary, only
|
||||
* one copy of the constructor will actually be preserved by the linker, and
|
||||
* that copy will add all of the extensions for the entire binary. All of these
|
||||
* are added to a global linked list of minitables pre-main, which are then used
|
||||
* to construct this singleton as needed.
|
||||
*/
|
||||
|
||||
typedef struct upb_GeneratedRegistryRef upb_GeneratedRegistryRef;
|
||||
|
||||
// Loads the generated registry, returning a reference to it. The reference
|
||||
// must be held for the lifetime of any ExtensionRegistry obtained from it.
|
||||
//
|
||||
// Returns NULL on failure.
|
||||
UPB_API const upb_GeneratedRegistryRef* upb_GeneratedRegistry_Load(void);
|
||||
|
||||
// Releases a reference to the generated registry. This may destroy the
|
||||
// registry if there are no other references to it.
|
||||
//
|
||||
// NULL is a valid argument and is simply ignored for easier error handling in
|
||||
// callers.
|
||||
UPB_API void upb_GeneratedRegistry_Release(const upb_GeneratedRegistryRef* r);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#include "upb/port/undef.inc"
|
||||
|
||||
#endif // UPB_MINI_TABLE_GENERATED_REGISTRY_H_
|
||||
|
|
@ -1,186 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2025 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
|
||||
|
||||
#include "upb/mini_table/generated_registry.h"
|
||||
|
||||
#include <array>
|
||||
#include <thread> // NOLINT
|
||||
#include <vector>
|
||||
|
||||
#include "google/protobuf/descriptor.upb_minitable.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include "absl/synchronization/barrier.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/extension_registry.h"
|
||||
#include "upb/test/custom_options.upb_minitable.h"
|
||||
#include "upb/test/editions_test.upb_minitable.h"
|
||||
#include "upb/test/test_multiple_files.upb_minitable.h"
|
||||
#include "upb/test/test_multiple_files2.upb_minitable.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class GeneratedRegistryTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ref_ = upb_GeneratedRegistry_Load();
|
||||
ASSERT_NE(ref_, nullptr);
|
||||
reg_ = upb_ExtensionRegistry_GetGenerated(ref_);
|
||||
ASSERT_NE(reg_, nullptr);
|
||||
}
|
||||
|
||||
void TearDown() override { upb_GeneratedRegistry_Release(ref_); }
|
||||
|
||||
const upb_GeneratedRegistryRef* ref_ = nullptr;
|
||||
const upb_ExtensionRegistry* reg_ = nullptr;
|
||||
};
|
||||
|
||||
TEST_F(GeneratedRegistryTest, LocalExtensionExists) {
|
||||
// Test an arbitrary extension defined in the same .proto file that we expect
|
||||
// to be linked in.
|
||||
|
||||
// Force linkage and sanity check extension numbers.
|
||||
ASSERT_EQ(upb_MiniTableExtension_Number(&upb_test_2023_ext_ext), 100);
|
||||
|
||||
EXPECT_NE(upb_ExtensionRegistry_Lookup(
|
||||
reg_, &upb__test_02023__EditionsMessage_msg_init, 100),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GeneratedRegistryTest, ForeignExtensionExists) {
|
||||
// Test an arbitrary extension defined by an import that we expect to be
|
||||
// linked in.
|
||||
|
||||
// Force linkage and sanity check extension numbers.
|
||||
ASSERT_EQ(upb_MiniTableExtension_Number(&upb_message_opt_ext), 7739036);
|
||||
|
||||
EXPECT_NE(upb_ExtensionRegistry_Lookup(reg_, &google__protobuf__MessageOptions_msg_init,
|
||||
7739036),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GeneratedRegistryTest, UnlinkedExtensionDoesNotExist) {
|
||||
// Test an arbitrary extension defined by an option import that we do not
|
||||
// expect to be linked in.
|
||||
|
||||
// Corresponds to upb.message_opt_unlinked in custom_options_unlinked.proto.
|
||||
EXPECT_EQ(upb_ExtensionRegistry_Lookup(reg_, &google__protobuf__MessageOptions_msg_init,
|
||||
7739037),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GeneratedRegistryTest, MultipleFilesExtensionExists) {
|
||||
// Test that multiple .proto files from the same proto_library can be linked
|
||||
// in and registered.
|
||||
|
||||
// Force linkage and sanity check extension numbers.
|
||||
ASSERT_EQ(upb_MiniTableExtension_Number(&upb_multiple_files_ext1_ext), 100);
|
||||
ASSERT_EQ(upb_MiniTableExtension_Number(&upb_multiple_files_ext2_ext), 100);
|
||||
|
||||
EXPECT_NE(upb_ExtensionRegistry_Lookup(
|
||||
reg_, &upb__MultipleFilesMessage1_msg_init, 100),
|
||||
nullptr);
|
||||
EXPECT_NE(upb_ExtensionRegistry_Lookup(
|
||||
reg_, &upb__MultipleFilesMessage2_msg_init, 100),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GeneratedRegistryTest, ReleaseOnError) {
|
||||
upb_GeneratedRegistry_Release(nullptr);
|
||||
}
|
||||
|
||||
// On 32-bit systems, the stack size is smaller, so we can't run too many
|
||||
// concurrent threads without overflowing the stack.
|
||||
constexpr int kRaceIterations = sizeof(void*) < 8 ? 100 : 2000;
|
||||
|
||||
TEST(GeneratedRegistryRaceTest, Load) {
|
||||
absl::Barrier barrier(kRaceIterations);
|
||||
std::vector<std::thread> threads;
|
||||
std::array<const upb_GeneratedRegistryRef*, kRaceIterations> refs;
|
||||
for (int i = 0; i < kRaceIterations; ++i) {
|
||||
threads.push_back(std::thread([&, i]() {
|
||||
barrier.Block();
|
||||
const upb_GeneratedRegistryRef* ref = upb_GeneratedRegistry_Load();
|
||||
EXPECT_NE(upb_ExtensionRegistry_GetGenerated(ref), nullptr);
|
||||
refs[i] = ref;
|
||||
}));
|
||||
}
|
||||
|
||||
for (auto& t : threads) t.join();
|
||||
|
||||
for (int i = 0; i < kRaceIterations; ++i) {
|
||||
EXPECT_NE(refs[i], nullptr);
|
||||
upb_GeneratedRegistry_Release(refs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(GeneratedRegistryRaceTest, Release) {
|
||||
absl::Barrier barrier(kRaceIterations);
|
||||
std::vector<std::thread> threads;
|
||||
std::array<const upb_GeneratedRegistryRef*, kRaceIterations> refs;
|
||||
|
||||
for (int i = 0; i < kRaceIterations; ++i) {
|
||||
refs[i] = upb_GeneratedRegistry_Load();
|
||||
ASSERT_NE(refs[i], nullptr);
|
||||
}
|
||||
|
||||
for (int i = 0; i < kRaceIterations; ++i) {
|
||||
threads.push_back(std::thread([&, i]() {
|
||||
EXPECT_NE(upb_ExtensionRegistry_GetGenerated(refs[i]), nullptr);
|
||||
barrier.Block();
|
||||
upb_GeneratedRegistry_Release(refs[i]);
|
||||
}));
|
||||
}
|
||||
|
||||
for (auto& t : threads) t.join();
|
||||
}
|
||||
|
||||
TEST(GeneratedRegistryRaceTest, LoadRelease) {
|
||||
absl::Barrier barrier(kRaceIterations);
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for (int i = 0; i < kRaceIterations; ++i) {
|
||||
threads.push_back(std::thread([&]() {
|
||||
barrier.Block();
|
||||
const upb_GeneratedRegistryRef* ref = upb_GeneratedRegistry_Load();
|
||||
EXPECT_NE(upb_ExtensionRegistry_GetGenerated(ref), nullptr);
|
||||
upb_GeneratedRegistry_Release(ref);
|
||||
}));
|
||||
}
|
||||
|
||||
for (auto& t : threads) t.join();
|
||||
}
|
||||
|
||||
TEST(GeneratedRegistryRaceTest, ReleaseLastAndLoadMultiple) {
|
||||
for (int i = 0; i < kRaceIterations; ++i) {
|
||||
// Load one reference. The registry is now alive with ref_count == 1.
|
||||
const upb_GeneratedRegistryRef* ref = upb_GeneratedRegistry_Load();
|
||||
ASSERT_NE(ref, nullptr);
|
||||
|
||||
constexpr int kNumLoaders = 4;
|
||||
absl::Barrier barrier(kNumLoaders + 1);
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
threads.push_back(std::thread([&]() {
|
||||
barrier.Block();
|
||||
// This release should bring the ref_count to 0 and trigger cleanup.
|
||||
upb_GeneratedRegistry_Release(ref);
|
||||
}));
|
||||
|
||||
for (int j = 0; j < kNumLoaders; ++j) {
|
||||
threads.push_back(std::thread([&]() {
|
||||
barrier.Block();
|
||||
const upb_GeneratedRegistryRef* ref2 = upb_GeneratedRegistry_Load();
|
||||
EXPECT_NE(upb_ExtensionRegistry_GetGenerated(ref2), nullptr);
|
||||
upb_GeneratedRegistry_Release(ref2);
|
||||
}));
|
||||
}
|
||||
|
||||
for (auto& t : threads) t.join();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -81,7 +81,7 @@ UPB_API_INLINE bool upb_MiniTableExtension_SetSubEnum(
|
|||
return true;
|
||||
}
|
||||
|
||||
UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTableExtension_ToField(
|
||||
UPB_API_INLINE const upb_MiniTableField* upb_MiniTableExtension_ToField(
|
||||
const struct upb_MiniTableExtension* e) {
|
||||
return &e->UPB_PRIVATE(field);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2025 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_MINI_TABLE_INTERNAL_GENERATED_EXTENSION_REGISTRY_H_
|
||||
#define UPB_MINI_TABLE_INTERNAL_GENERATED_EXTENSION_REGISTRY_H_
|
||||
|
||||
#include "upb/mini_table/internal/extension.h"
|
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct UPB_PRIVATE(upb_GeneratedExtensionListEntry) {
|
||||
const struct upb_MiniTableExtension* start;
|
||||
const struct upb_MiniTableExtension* stop;
|
||||
const struct UPB_PRIVATE(upb_GeneratedExtensionListEntry) * next;
|
||||
} UPB_PRIVATE(upb_GeneratedExtensionListEntry);
|
||||
|
||||
struct upb_GeneratedRegistryRef {
|
||||
struct upb_Arena* arena;
|
||||
const struct upb_ExtensionRegistry* registry;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#include "upb/port/undef.inc"
|
||||
|
||||
#endif /* UPB_MINI_TABLE_INTERNAL_GENERATED_EXTENSION_REGISTRY_H_ */
|
||||
|
|
@ -31,10 +31,6 @@
|
|||
failure_order) \
|
||||
atomic_compare_exchange_weak_explicit(addr, expected, desired, \
|
||||
success_order, failure_order)
|
||||
#define upb_Atomic_Add(addr, val, order) \
|
||||
atomic_fetch_add_explicit(addr, val, order)
|
||||
#define upb_Atomic_Sub(addr, val, order) \
|
||||
atomic_fetch_sub_explicit(addr, val, order)
|
||||
|
||||
#elif defined(UPB_USE_MSC_ATOMICS)
|
||||
#include <intrin.h>
|
||||
|
|
@ -43,41 +39,49 @@
|
|||
|
||||
#define upb_Atomic_Init(addr, val) (*(addr) = val)
|
||||
|
||||
#pragma intrinsic(_InterlockedExchange)
|
||||
static int32_t upb_Atomic_LoadMsc32(int32_t volatile* addr) {
|
||||
// Compare exchange with an unlikely value reduces the risk of a spurious
|
||||
// (but harmless) store
|
||||
return _InterlockedCompareExchange(addr, 0xDEADC0DE, 0xDEADC0DE);
|
||||
}
|
||||
|
||||
#pragma intrinsic(_InterlockedCompareExchange)
|
||||
static bool upb_Atomic_CompareExchangeMscP32(int32_t volatile* addr,
|
||||
int32_t* expected,
|
||||
int32_t desired) {
|
||||
int32_t expect_val = *expected;
|
||||
int32_t actual_val = _InterlockedCompareExchange(addr, desired, expect_val);
|
||||
if (expect_val != actual_val) {
|
||||
*expected = actual_val;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
// MSVC, without C11 atomics, does not have any way in pure C to force
|
||||
// load-acquire store-release behavior, so we hack it with exchanges.
|
||||
#pragma intrinsic(_InterlockedExchange64)
|
||||
#define upb_Atomic_Store(addr, val, order) \
|
||||
(void)_InterlockedExchange64((uint64_t volatile *)addr, (uint64_t)val)
|
||||
|
||||
#pragma intrinsic(_InterlockedCompareExchange64)
|
||||
static uintptr_t upb_Atomic_LoadMsc64(uint64_t volatile* addr) {
|
||||
static uintptr_t upb_Atomic_LoadMsc(uint64_t volatile *addr) {
|
||||
// Compare exchange with an unlikely value reduces the risk of a spurious
|
||||
// (but harmless) store
|
||||
return _InterlockedCompareExchange64(addr, 0xDEADC0DEBAADF00D,
|
||||
0xDEADC0DEBAADF00D);
|
||||
}
|
||||
// If _Generic is available, use it to avoid emitting a "'uintptr_t' differs in
|
||||
// levels of indirection from 'void *'" or -Wint-conversion compiler warning.
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define upb_Atomic_Load(addr, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(uintptr_t) *: upb_Atomic_LoadMsc( \
|
||||
(uint64_t volatile *)(addr)), \
|
||||
default: (void *)upb_Atomic_LoadMsc((uint64_t volatile *)(addr)))
|
||||
|
||||
#define upb_Atomic_Exchange(addr, val, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(uintptr_t) *: _InterlockedExchange64( \
|
||||
(uint64_t volatile *)(addr), (uint64_t)val), \
|
||||
default: (void *)_InterlockedExchange64((uint64_t volatile *)addr, \
|
||||
(uint64_t)val))
|
||||
#else
|
||||
// Compare exchange with an unlikely value reduces the risk of a spurious
|
||||
// (but harmless) store
|
||||
#define upb_Atomic_Load(addr, order) \
|
||||
(void *)upb_Atomic_LoadMsc((uint64_t volatile *)(addr))
|
||||
|
||||
#define upb_Atomic_Exchange(addr, val, order) \
|
||||
(void *)_InterlockedExchange64((uint64_t volatile *)addr, (uint64_t)val)
|
||||
#endif
|
||||
|
||||
#pragma intrinsic(_InterlockedCompareExchange64)
|
||||
static bool upb_Atomic_CompareExchangeMscP64(uint64_t volatile* addr,
|
||||
uint64_t* expected,
|
||||
uint64_t desired) {
|
||||
static bool upb_Atomic_CompareExchangeMscP(uint64_t volatile *addr,
|
||||
uint64_t *expected,
|
||||
uint64_t desired) {
|
||||
uint64_t expect_val = *expected;
|
||||
uint64_t actual_val =
|
||||
_InterlockedCompareExchange64(addr, desired, expect_val);
|
||||
|
|
@ -88,173 +92,72 @@ static bool upb_Atomic_CompareExchangeMscP64(uint64_t volatile* addr,
|
|||
return true;
|
||||
}
|
||||
|
||||
#pragma intrinsic(_InterlockedExchange64)
|
||||
// If _Generic is available, use it to avoid emitting a "'uintptr_t' differs in
|
||||
// levels of indirection from 'void *'" or -Wint-conversion compiler warning.
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define upb_Atomic_Store(addr, val, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(uintptr_t)*: (void)_InterlockedExchange64( \
|
||||
(uint64_t volatile*)(addr), (uint64_t)val), \
|
||||
UPB_ATOMIC(int32_t)*: (void)_InterlockedExchange( \
|
||||
(int32_t volatile*)(addr), (int32_t)val), \
|
||||
default: (void)_InterlockedExchange64((uint64_t volatile*)addr, \
|
||||
(uint64_t)val))
|
||||
|
||||
#define upb_Atomic_Load(addr, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(uintptr_t)*: upb_Atomic_LoadMsc64( \
|
||||
(uint64_t volatile*)(addr)), \
|
||||
UPB_ATOMIC(int32_t)*: upb_Atomic_LoadMsc32((int32_t volatile*)(addr)), \
|
||||
default: (void*)upb_Atomic_LoadMsc64((uint64_t volatile*)(addr)))
|
||||
|
||||
#define upb_Atomic_Exchange(addr, val, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(uintptr_t)*: _InterlockedExchange64( \
|
||||
(uint64_t volatile*)(addr), (uint64_t)val), \
|
||||
UPB_ATOMIC(int32_t)*: _InterlockedExchange((int32_t volatile*)(addr), \
|
||||
(int32_t)val), \
|
||||
default: (void*)_InterlockedExchange64((uint64_t volatile*)addr, \
|
||||
(uint64_t)val))
|
||||
|
||||
#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \
|
||||
success_order, failure_order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(int32_t)*: upb_Atomic_CompareExchangeMscP32( \
|
||||
(int32_t volatile*)(addr), (int32_t*)expected, \
|
||||
(int32_t)desired), \
|
||||
default: upb_Atomic_CompareExchangeMscP64((uint64_t volatile*)(addr), \
|
||||
(uint64_t*)expected, \
|
||||
(uint64_t)desired))
|
||||
|
||||
#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \
|
||||
failure_order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(int32_t)*: upb_Atomic_CompareExchangeMscP32( \
|
||||
(int32_t volatile*)(addr), (int32_t*)expected, \
|
||||
(int32_t)desired), \
|
||||
default: upb_Atomic_CompareExchangeMscP64((uint64_t volatile*)(addr), \
|
||||
(uint64_t*)expected, \
|
||||
(uint64_t)desired))
|
||||
|
||||
#else
|
||||
|
||||
UPB_INLINE void _upb_Atomic_StoreP(void* addr, uint64_t val, size_t size) {
|
||||
if (size == sizeof(int32_t)) {
|
||||
(void)_InterlockedExchange((int32_t volatile*)addr, (int32_t)val);
|
||||
} else {
|
||||
(void)_InterlockedExchange64((uint64_t volatile*)addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
#define upb_Atomic_Store(addr, val, order) \
|
||||
_upb_Atomic_StoreP(addr, val, sizeof(*addr))
|
||||
|
||||
UPB_INLINE int64_t _upb_Atomic_LoadP(void* addr, size_t size) {
|
||||
if (size == sizeof(int32_t)) {
|
||||
return (int64_t)upb_Atomic_LoadMsc32((int32_t volatile*)addr);
|
||||
} else {
|
||||
return upb_Atomic_LoadMsc64((uint64_t volatile*)addr);
|
||||
}
|
||||
}
|
||||
|
||||
#define upb_Atomic_Load(addr, order) _upb_Atomic_LoadP(addr, sizeof(*addr))
|
||||
|
||||
UPB_INLINE int64_t _upb_Atomic_ExchangeP(void* addr, uint64_t val,
|
||||
size_t size) {
|
||||
if (size == sizeof(int32_t)) {
|
||||
return (int64_t)_InterlockedExchange((int32_t volatile*)addr, (int32_t)val);
|
||||
} else {
|
||||
return (int64_t)_InterlockedExchange64((uint64_t volatile*)addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
#define upb_Atomic_Exchange(addr, val, order) \
|
||||
_upb_Atomic_ExchangeP(addr, val, sizeof(*addr))
|
||||
|
||||
UPB_INLINE bool _upb_Atomic_CompareExchangeMscP(void* addr, void* expected,
|
||||
uint64_t desired, size_t size) {
|
||||
if (size == sizeof(int32_t)) {
|
||||
return upb_Atomic_CompareExchangeMscP32(
|
||||
(int32_t volatile*)addr, (int32_t*)expected, (int32_t)desired);
|
||||
} else {
|
||||
return upb_Atomic_CompareExchangeMscP64((uint64_t volatile*)addr,
|
||||
(uint64_t*)expected, desired);
|
||||
}
|
||||
}
|
||||
|
||||
#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \
|
||||
success_order, failure_order) \
|
||||
_upb_Atomic_CompareExchangeMscP(addr, expected, desired, sizeof(*addr))
|
||||
upb_Atomic_CompareExchangeMscP((uint64_t volatile *)addr, \
|
||||
(uint64_t *)expected, (uint64_t)desired)
|
||||
|
||||
#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \
|
||||
failure_order) \
|
||||
_upb_Atomic_CompareExchangeMscP(addr, expected, desired, sizeof(*addr))
|
||||
|
||||
#endif
|
||||
upb_Atomic_CompareExchangeMscP((uint64_t volatile *)addr, \
|
||||
(uint64_t *)expected, (uint64_t)desired)
|
||||
|
||||
#else // 32 bit pointers
|
||||
#pragma intrinsic(_InterlockedExchange)
|
||||
#define upb_Atomic_Store(addr, val, order) \
|
||||
(void)_InterlockedExchange((uint32_t volatile*)addr, (uint32_t)val)
|
||||
(void)_InterlockedExchange((uint32_t volatile *)addr, (uint32_t)val)
|
||||
|
||||
#pragma intrinsic(_InterlockedCompareExchange)
|
||||
static uintptr_t upb_Atomic_LoadMsc(uint32_t volatile *addr) {
|
||||
// Compare exchange with an unlikely value reduces the risk of a spurious
|
||||
// (but harmless) store
|
||||
return _InterlockedCompareExchange(addr, 0xDEADC0DE, 0xDEADC0DE);
|
||||
}
|
||||
// If _Generic is available, use it to avoid emitting 'uintptr_t' differs in
|
||||
// levels of indirection from 'void *'
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define upb_Atomic_Load(addr, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(uintptr_t)*: (uintptr_t)upb_Atomic_LoadMsc32( \
|
||||
(uint32_t volatile*)(addr)), \
|
||||
UPB_ATOMIC(int32_t)*: upb_Atomic_LoadMsc32((int32_t volatile*)(addr)), \
|
||||
default: (void*)upb_Atomic_LoadMsc32((uint32_t volatile*)(addr)))
|
||||
#define upb_Atomic_Load(addr, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(uintptr_t) *: upb_Atomic_LoadMsc( \
|
||||
(uint32_t volatile *)(addr)), \
|
||||
default: (void *)upb_Atomic_LoadMsc((uint32_t volatile *)(addr)))
|
||||
|
||||
#define upb_Atomic_Exchange(addr, val, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(uintptr_t)*: _InterlockedExchange((uint32_t volatile*)(addr), \
|
||||
(uint32_t)val), \
|
||||
default: (void*)_InterlockedExchange((uint32_t volatile*)addr, \
|
||||
(uint32_t)val))
|
||||
#define upb_Atomic_Exchange(addr, val, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(uintptr_t) *: _InterlockedExchange( \
|
||||
(uint32_t volatile *)(addr), (uint32_t)val), \
|
||||
default: (void *)_InterlockedExchange64((uint32_t volatile *)addr, \
|
||||
(uint32_t)val))
|
||||
#else
|
||||
#define upb_Atomic_Load(addr, order) \
|
||||
(void*)upb_Atomic_LoadMsc32((uint32_t volatile*)(addr))
|
||||
(void *)upb_Atomic_LoadMsc((uint32_t volatile *)(addr))
|
||||
|
||||
#define upb_Atomic_Exchange(addr, val, order) \
|
||||
(void*)_InterlockedExchange((uint32_t volatile*)addr, (uint32_t)val)
|
||||
(void *)_InterlockedExchange((uint32_t volatile *)addr, (uint32_t)val)
|
||||
#endif
|
||||
|
||||
#pragma intrinsic(_InterlockedCompareExchange)
|
||||
static bool upb_Atomic_CompareExchangeMscP(uint32_t volatile *addr,
|
||||
uint32_t *expected,
|
||||
uint32_t desired) {
|
||||
uint32_t expect_val = *expected;
|
||||
uint32_t actual_val = _InterlockedCompareExchange(addr, desired, expect_val);
|
||||
if (expect_val != actual_val) {
|
||||
*expected = actual_val;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \
|
||||
success_order, failure_order) \
|
||||
upb_Atomic_CompareExchangeMscP32((uint32_t volatile*)addr, \
|
||||
(uint32_t*)expected, (uint32_t)desired)
|
||||
upb_Atomic_CompareExchangeMscP((uint32_t volatile *)addr, \
|
||||
(uint32_t *)expected, (uint32_t)desired)
|
||||
|
||||
#define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \
|
||||
failure_order) \
|
||||
upb_Atomic_CompareExchangeMscP32((uint32_t volatile*)addr, \
|
||||
(uint32_t*)expected, (uint32_t)desired)
|
||||
#endif
|
||||
|
||||
#pragma intrinsic(_InterlockedExchangeAdd)
|
||||
#pragma intrinsic(_InterlockedExchangeAdd64)
|
||||
|
||||
// If _Generic is available, use it to switch between 32 and 64 bit types.
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define upb_Atomic_Add(addr, val, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(int64_t)*: _InterlockedExchangeAdd64(addr, (int64_t)val), \
|
||||
UPB_ATOMIC(int32_t)*: _InterlockedExchangeAdd(addr, (int32_t)val))
|
||||
#define upb_Atomic_Sub(addr, val, order) \
|
||||
_Generic(addr, \
|
||||
UPB_ATOMIC(int64_t)*: _InterlockedExchangeAdd64(addr, -(int64_t)val), \
|
||||
UPB_ATOMIC(int32_t)*: _InterlockedExchangeAdd(addr, -(int32_t)val))
|
||||
#else
|
||||
#define upb_Atomic_Add(addr, val, order) \
|
||||
sizeof(*addr) == sizeof(int32_t) \
|
||||
? _InterlockedExchangeAdd((uint32_t volatile*)addr, (int32_t)val) \
|
||||
: _InterlockedExchangeAdd64((uint64_t volatile*)addr, (int64_t)val)
|
||||
#define upb_Atomic_Sub(addr, val, order) \
|
||||
sizeof(*addr) == sizeof(int32_t) \
|
||||
? _InterlockedExchangeAdd((uint32_t volatile*)addr, -(int32_t)val) \
|
||||
: _InterlockedExchangeAdd64((uint64_t volatile*)addr, -(int64_t)val)
|
||||
upb_Atomic_CompareExchangeMscP((uint32_t volatile *)addr, \
|
||||
(uint32_t *)expected, (uint32_t)desired)
|
||||
#endif
|
||||
|
||||
#else // No atomics
|
||||
|
|
@ -300,9 +203,6 @@ UPB_INLINE bool _upb_NonAtomic_CompareExchangeStrongP(void* addr,
|
|||
failure_order) \
|
||||
upb_Atomic_CompareExchangeStrong(addr, expected, desired, 0, 0)
|
||||
|
||||
#define upb_Atomic_Add(addr, val, order) (*addr += val)
|
||||
#define upb_Atomic_Sub(addr, val, order) (*addr -= val)
|
||||
|
||||
#endif
|
||||
|
||||
#include "upb/port/undef.inc"
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ Error, UINTPTR_MAX is undefined
|
|||
/* If we always read/write as a consistent type to each address, this shouldn't
|
||||
* violate aliasing.
|
||||
*/
|
||||
#define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs)))
|
||||
#define UPB_PTR_AT(msg, ofs, type) ((type *)((char *)(msg) + (ofs)))
|
||||
|
||||
// A flexible array member may have lower alignment requirements than the struct
|
||||
// overall - in that case, it can overlap with the trailing padding of the rest
|
||||
|
|
@ -496,12 +496,6 @@ Error, UINTPTR_MAX is undefined
|
|||
#define UPB_NO_SANITIZE_ADDRESS
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (defined(__clang__) || UPB_GNUC_MIN(11, 0))
|
||||
#define UPB_RETAIN __attribute__((retain))
|
||||
#else
|
||||
#define UPB_RETAIN
|
||||
#endif
|
||||
|
||||
// Linker arrays combine elements from multiple translation units into a single
|
||||
// array that can be iterated over at runtime.
|
||||
//
|
||||
|
|
@ -526,20 +520,14 @@ Error, UINTPTR_MAX is undefined
|
|||
// }
|
||||
// }
|
||||
|
||||
#define UPB_LINKARR_ATTR
|
||||
|
||||
#define UPB_LINKARR_SENTINEL UPB_RETAIN __attribute__((weak, used))
|
||||
|
||||
#if defined(__ELF__) || defined(__wasm__)
|
||||
|
||||
#define UPB_LINKARR_APPEND(name) \
|
||||
__attribute__(( \
|
||||
section("linkarr_" #name))) UPB_LINKARR_ATTR UPB_NO_SANITIZE_ADDRESS
|
||||
__attribute__((section("linkarr_" #name))) UPB_NO_SANITIZE_ADDRESS
|
||||
#define UPB_LINKARR_DECLARE(name, type) \
|
||||
extern type __start_linkarr_##name; \
|
||||
extern type __stop_linkarr_##name; \
|
||||
UPB_LINKARR_APPEND(name) \
|
||||
UPB_LINKARR_SENTINEL type UPB_linkarr_internal_empty_##name[1]
|
||||
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1]
|
||||
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
|
||||
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
|
||||
|
||||
|
|
@ -547,85 +535,43 @@ Error, UINTPTR_MAX is undefined
|
|||
|
||||
/* As described in: https://stackoverflow.com/a/22366882 */
|
||||
#define UPB_LINKARR_APPEND(name) \
|
||||
__attribute__(( \
|
||||
section("__DATA,__la_" #name))) UPB_LINKARR_ATTR UPB_NO_SANITIZE_ADDRESS
|
||||
__attribute__((section("__DATA,__la_" #name))) UPB_NO_SANITIZE_ADDRESS
|
||||
#define UPB_LINKARR_DECLARE(name, type) \
|
||||
extern type __start_linkarr_##name __asm( \
|
||||
"section$start$__DATA$__la_" #name); \
|
||||
extern type __stop_linkarr_##name __asm( \
|
||||
"section$end$__DATA$" \
|
||||
"__la_" #name); \
|
||||
UPB_LINKARR_APPEND(name) \
|
||||
UPB_LINKARR_SENTINEL type UPB_linkarr_internal_empty_##name[1]
|
||||
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1]
|
||||
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
|
||||
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
#elif defined(_MSC_VER) && defined(__clang__)
|
||||
|
||||
/* See:
|
||||
* https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155
|
||||
* https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165
|
||||
* https://devblogs.microsoft.com/oldnewthing/20181109-00/?p=100175 */
|
||||
#define UPB_STRINGIFY_INTERNAL(x) #x
|
||||
#define UPB_STRINGIFY(x) UPB_STRINGIFY_INTERNAL(x)
|
||||
#define UPB_CONCAT(a, b, c) a##b##c
|
||||
#define UPB_LINKARR_NAME(name, index) \
|
||||
UPB_STRINGIFY(UPB_CONCAT(la_, name, index))
|
||||
#define UPB_LINKARR_APPEND(name) \
|
||||
__pragma(section(UPB_LINKARR_NAME(name, $j), read)) \
|
||||
__declspec(allocate(UPB_LINKARR_NAME(name, $j)))
|
||||
// clang-format off
|
||||
#define UPB_LINKARR_DECLARE(name, type) \
|
||||
__pragma(message(UPB_LINKARR_NAME(name, $j))) \
|
||||
__pragma(section(UPB_LINKARR_NAME(name, $a), read)) \
|
||||
__pragma(section(UPB_LINKARR_NAME(name, $z), read)) \
|
||||
__declspec(allocate(UPB_LINKARR_NAME(name, $a)), selectany) \
|
||||
type __start_linkarr_##name; \
|
||||
__declspec(allocate(UPB_LINKARR_NAME(name, $z)), selectany) \
|
||||
type __stop_linkarr_##name; \
|
||||
UPB_LINKARR_APPEND(name) \
|
||||
__declspec(selectany) type UPB_linkarr_internal_empty_##name[1] = {0}
|
||||
// clang-format on
|
||||
|
||||
// Usage of __attribute__ here probably means this is Clang-specific, and would
|
||||
// not work on MSVC.
|
||||
#define UPB_LINKARR_APPEND(name) \
|
||||
__declspec(allocate("la_" #name "$j")) UPB_NO_SANITIZE_ADDRESS
|
||||
#define UPB_LINKARR_DECLARE(name, type) \
|
||||
__declspec(allocate("la_" #name "$a")) type __start_linkarr_##name; \
|
||||
__declspec(allocate("la_" #name "$z")) type __stop_linkarr_##name; \
|
||||
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] = {0}
|
||||
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
|
||||
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
|
||||
|
||||
#else
|
||||
|
||||
// Linker arrays are not supported on this platform. Make macros no-ops.
|
||||
// Linker arrays are not supported on this platform. Make appends a no-op but
|
||||
// don't define the other macros.
|
||||
#define UPB_LINKARR_APPEND(name)
|
||||
#define UPB_LINKARR_DECLARE(name, type)
|
||||
#define UPB_LINKARR_START(name) (NULL)
|
||||
#define UPB_LINKARR_STOP(name) (NULL)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__ELF__) || defined(__wasm__) || defined(__MACH__)
|
||||
#define UPB_CONSTRUCTOR(name) \
|
||||
__attribute__((weak, visibility("hidden"), constructor)) void UPB_PRIVATE( \
|
||||
name)(void)
|
||||
#elif defined(_MSC_VER)
|
||||
/*
|
||||
* See: https://stackoverflow.com/questions/1113409
|
||||
*
|
||||
* The /include pragma suggested in the link above doesn't work in our case
|
||||
* because it requires globally unique names. We need a different solution
|
||||
* to prevent optimizers from removing the constructor. Our solution is to
|
||||
* create a dummy exported weak symbol that prevent this stripping.
|
||||
*/
|
||||
#pragma section(".CRT$XCU", long, read)
|
||||
#define UPB_CONSTRUCTOR(name) \
|
||||
static void __cdecl UPB_PRIVATE(name)(void); \
|
||||
__declspec(allocate(".CRT$XCU"), selectany) void( \
|
||||
__cdecl * UPB_PRIVATE(name##_))(void) = UPB_PRIVATE(name); \
|
||||
__declspec(selectany, dllexport) void* UPB_PRIVATE(name##_force_linkage) = \
|
||||
&UPB_PRIVATE(name##_); \
|
||||
static void __cdecl UPB_PRIVATE(name)(void)
|
||||
|
||||
#else
|
||||
// No constructor support, nothing we can do except not break builds.
|
||||
#define UPB_CONSTRUCTOR(name) static void UPB_PRIVATE(name)(void)
|
||||
#endif
|
||||
|
||||
// Future versions of upb will include breaking changes to some APIs.
|
||||
// This macro can be set to enable these API changes ahead of time, so that
|
||||
// user code can be updated before upgrading versions of protobuf.
|
||||
|
|
|
|||
|
|
@ -149,8 +149,8 @@ cc_library(
|
|||
],
|
||||
deps = [
|
||||
":internal",
|
||||
"//upb/mem",
|
||||
"//upb/mini_descriptor",
|
||||
"//upb/mini_table",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,35 +7,25 @@
|
|||
|
||||
#include "upb/reflection/internal/def_pool.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "upb/base/status.h"
|
||||
#include "upb/base/string_view.h"
|
||||
#include "upb/hash/common.h"
|
||||
#include "upb/hash/int_table.h"
|
||||
#include "upb/hash/str_table.h"
|
||||
#include "upb/mem/alloc.h"
|
||||
#include "upb/mem/arena.h"
|
||||
#include "upb/mini_descriptor/decode.h"
|
||||
#include "upb/mini_table/extension.h"
|
||||
#include "upb/mini_table/extension_registry.h"
|
||||
#include "upb/mini_table/file.h"
|
||||
#include "upb/mini_table/generated_registry.h"
|
||||
#include "upb/mini_table/message.h"
|
||||
#include "upb/reflection/def.h"
|
||||
#include "upb/reflection/def_type.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/enum_value_def.h"
|
||||
#include "upb/reflection/internal/field_def.h"
|
||||
#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"
|
||||
#include "upb/wire/decode.h"
|
||||
|
||||
struct upb_DefPool {
|
||||
upb_Arena* arena;
|
||||
|
|
@ -43,7 +33,6 @@ struct upb_DefPool {
|
|||
upb_strtable files; // file_name -> (upb_FileDef*)
|
||||
upb_inttable exts; // (upb_MiniTableExtension*) -> (upb_FieldDef*)
|
||||
upb_ExtensionRegistry* extreg;
|
||||
const upb_GeneratedRegistryRef* generated_extreg;
|
||||
const UPB_DESC(FeatureSetDefaults) * feature_set_defaults;
|
||||
upb_MiniTablePlatform platform;
|
||||
void* scratch_data;
|
||||
|
|
@ -52,7 +41,6 @@ struct upb_DefPool {
|
|||
};
|
||||
|
||||
void upb_DefPool_Free(upb_DefPool* s) {
|
||||
upb_GeneratedRegistry_Release(s->generated_extreg);
|
||||
upb_Arena_Free(s->arena);
|
||||
upb_gfree(s->scratch_data);
|
||||
upb_gfree(s);
|
||||
|
|
@ -78,9 +66,6 @@ upb_DefPool* upb_DefPool_New(void) {
|
|||
s->extreg = upb_ExtensionRegistry_New(s->arena);
|
||||
if (!s->extreg) goto err;
|
||||
|
||||
s->generated_extreg = upb_GeneratedRegistry_Load();
|
||||
if (!s->generated_extreg) goto err;
|
||||
|
||||
s->platform = kUpb_MiniTablePlatform_Native;
|
||||
|
||||
upb_Status status;
|
||||
|
|
@ -542,8 +527,3 @@ const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s,
|
|||
bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) {
|
||||
return _upb_DefPool_LoadDefInitEx(s, init, false);
|
||||
}
|
||||
|
||||
const upb_ExtensionRegistry* _upb_DefPool_GeneratedExtensionRegistry(
|
||||
const upb_DefPool* s) {
|
||||
return upb_ExtensionRegistry_GetGenerated(s->generated_extreg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,18 +29,17 @@
|
|||
|
||||
// We want to copy the options verbatim into the destination options proto.
|
||||
// We use serialize+parse as our deep copy.
|
||||
#define UPB_DEF_SET_OPTIONS(target, desc_type, options_type, proto) \
|
||||
if (UPB_DESC(desc_type##_has_options)(proto)) { \
|
||||
size_t size; \
|
||||
char* pb = UPB_DESC(options_type##_serialize)( \
|
||||
UPB_DESC(desc_type##_options)(proto), ctx->tmp_arena, &size); \
|
||||
if (!pb) _upb_DefBuilder_OomErr(ctx); \
|
||||
target = UPB_DESC(options_type##_parse_ex)( \
|
||||
pb, size, _upb_DefPool_GeneratedExtensionRegistry(ctx->symtab), 0, \
|
||||
_upb_DefBuilder_Arena(ctx)); \
|
||||
if (!target) _upb_DefBuilder_OomErr(ctx); \
|
||||
} else { \
|
||||
target = (const UPB_DESC(options_type)*)kUpbDefOptDefault; \
|
||||
#define UPB_DEF_SET_OPTIONS(target, desc_type, options_type, proto) \
|
||||
if (UPB_DESC(desc_type##_has_options)(proto)) { \
|
||||
size_t size; \
|
||||
char* pb = UPB_DESC(options_type##_serialize)( \
|
||||
UPB_DESC(desc_type##_options)(proto), ctx->tmp_arena, &size); \
|
||||
if (!pb) _upb_DefBuilder_OomErr(ctx); \
|
||||
target = \
|
||||
UPB_DESC(options_type##_parse)(pb, size, _upb_DefBuilder_Arena(ctx)); \
|
||||
if (!target) _upb_DefBuilder_OomErr(ctx); \
|
||||
} else { \
|
||||
target = (const UPB_DESC(options_type)*)kUpbDefOptDefault; \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@
|
|||
#define UPB_REFLECTION_DEF_POOL_INTERNAL_H_
|
||||
|
||||
#include "upb/mini_descriptor/decode.h"
|
||||
#include "upb/mini_table/extension_registry.h"
|
||||
#include "upb/reflection/def.h"
|
||||
#include "upb/reflection/def_pool.h"
|
||||
|
||||
// Must be last.
|
||||
#include "upb/port/def.inc"
|
||||
|
|
@ -49,9 +48,6 @@ bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init);
|
|||
bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init,
|
||||
bool rebuild_minitable);
|
||||
|
||||
const upb_ExtensionRegistry* _upb_DefPool_GeneratedExtensionRegistry(
|
||||
const upb_DefPool* s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ proto_library(
|
|||
":custom_options_proto",
|
||||
":custom_options_unlinked_proto",
|
||||
],
|
||||
deps = ["//:descriptor_proto"],
|
||||
)
|
||||
|
||||
upb_c_proto_library(
|
||||
|
|
@ -103,41 +102,12 @@ upb_c_proto_library(
|
|||
deps = [":editions_test_proto"],
|
||||
)
|
||||
|
||||
upb_minitable_proto_library(
|
||||
name = "editions_test_upb_minitable_proto",
|
||||
testonly = 1,
|
||||
visibility = ["//upb:__subpackages__"],
|
||||
deps = [":editions_test_proto"],
|
||||
)
|
||||
|
||||
upb_proto_reflection_library(
|
||||
name = "editions_test_upb_proto_reflection",
|
||||
testonly = 1,
|
||||
deps = [":editions_test_proto"],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "test_multiple_files_proto",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"test_multiple_files.proto",
|
||||
"test_multiple_files2.proto",
|
||||
],
|
||||
)
|
||||
|
||||
upb_c_proto_library(
|
||||
name = "test_multiple_files_upb_c_proto",
|
||||
testonly = 1,
|
||||
deps = [":test_multiple_files_proto"],
|
||||
)
|
||||
|
||||
upb_minitable_proto_library(
|
||||
name = "test_multiple_files_upb_minitable_proto",
|
||||
testonly = 1,
|
||||
visibility = ["//upb:__subpackages__"],
|
||||
deps = [":test_multiple_files_proto"],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "test_cpp_proto",
|
||||
srcs = ["test_cpp.proto"],
|
||||
|
|
@ -227,6 +197,8 @@ cc_test(
|
|||
copts = UPB_DEFAULT_CPPOPTS,
|
||||
deps = [
|
||||
":custom_options_upb_c_proto",
|
||||
":custom_options_upb_minitable_proto",
|
||||
":custom_options_upb_proto_reflection",
|
||||
":editions_test_upb_c_proto",
|
||||
":editions_test_upb_proto_reflection",
|
||||
"//upb/base",
|
||||
|
|
@ -367,7 +339,6 @@ upb_c_proto_library(
|
|||
upb_minitable_proto_library(
|
||||
name = "custom_options_upb_minitable_proto",
|
||||
testonly = 1,
|
||||
visibility = ["//upb:__subpackages__"],
|
||||
deps = [":custom_options_proto"],
|
||||
)
|
||||
|
||||
|
|
@ -427,9 +398,6 @@ filegroup(
|
|||
[
|
||||
"**/*.proto",
|
||||
],
|
||||
exclude = [
|
||||
"custom_options_unlinked.proto",
|
||||
],
|
||||
),
|
||||
visibility = ["//upb:__pkg__"],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,18 +7,14 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "upb/base/descriptor_constants.h"
|
||||
#include "upb/base/string_view.h"
|
||||
#include "upb/base/upcast.h"
|
||||
#include "upb/mem/arena.hpp"
|
||||
#include "upb/message/message.h"
|
||||
#include "upb/port/def.inc"
|
||||
#include "upb/reflection/def.hpp"
|
||||
#include "upb/reflection/descriptor_bootstrap.h"
|
||||
#include "upb/test/custom_options.upb.h"
|
||||
#include "upb/test/editions_test.upb.h"
|
||||
#include "upb/test/editions_test.upbdefs.h"
|
||||
|
||||
|
|
@ -73,25 +69,7 @@ TEST(EditionsTest, ImportOptionUnlinked) {
|
|||
upb::MessageDefPtr md(upb_test_2023_EditionsMessage_getmsgdef(defpool.ptr()));
|
||||
const google_protobuf_MessageOptions* options = md.options();
|
||||
|
||||
upb_StringView data;
|
||||
uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
ASSERT_TRUE(upb_Message_NextUnknown(UPB_UPCAST(options), &data, &iter));
|
||||
EXPECT_EQ(std::string(data.data, data.size),
|
||||
// 7739037: 9
|
||||
"\xE8\xE9\xC2\x1D\011");
|
||||
EXPECT_FALSE(upb_Message_NextUnknown(UPB_UPCAST(options), &data, &iter));
|
||||
}
|
||||
|
||||
TEST(EditionsTest, ImportOptionLinked) {
|
||||
// Test that linked option dependencies don't show up in unknown fields. This
|
||||
// also actually *uses* the linked options to guarantee linkage and make the
|
||||
// previous test pass.
|
||||
|
||||
upb::Arena arena;
|
||||
upb::DefPool defpool;
|
||||
upb::MessageDefPtr md(upb_test_2023_EditionsMessage_getmsgdef(defpool.ptr()));
|
||||
const google_protobuf_MessageOptions* options = md.options();
|
||||
EXPECT_EQ(upb_message_opt(options), 87);
|
||||
EXPECT_TRUE(upb_Message_HasUnknown(UPB_UPCAST(options)));
|
||||
}
|
||||
|
||||
TEST(EditionsTest, ConstructProto) {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ edition = "2024";
|
|||
|
||||
package upb.test_2023;
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
import option "upb/test/custom_options.proto";
|
||||
import option "upb/test/custom_options_unlinked.proto";
|
||||
|
||||
|
|
@ -27,8 +25,6 @@ message EditionsMessage {
|
|||
EditionsEnum enum_field = 5;
|
||||
repeated int32 unpacked_field = 6
|
||||
[features.repeated_field_encoding = EXPANDED];
|
||||
|
||||
extensions 100 to 199;
|
||||
}
|
||||
|
||||
enum EditionsEnum {
|
||||
|
|
@ -36,7 +32,3 @@ enum EditionsEnum {
|
|||
|
||||
ONE = 1;
|
||||
}
|
||||
|
||||
extend EditionsMessage {
|
||||
int32 ext = 100;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2025 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
|
||||
|
||||
// This test is meant to handle the case where two .proto files are build in the
|
||||
// same proto_library. With dynamic linkage, they will end up in the same
|
||||
// shared library.
|
||||
|
||||
edition = "2024";
|
||||
|
||||
package upb;
|
||||
|
||||
message MultipleFilesMessage1 {
|
||||
int32 field1 = 1;
|
||||
|
||||
extensions 100 to 199;
|
||||
}
|
||||
|
||||
extend MultipleFilesMessage1 {
|
||||
int32 multiple_files_ext1 = 100;
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2025 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
|
||||
|
||||
// This test is meant to handle the case where two .proto files are build in the
|
||||
// same proto_library. With dynamic linkage, they will end up in the same
|
||||
// shared library.
|
||||
|
||||
edition = "2024";
|
||||
|
||||
package upb;
|
||||
|
||||
message MultipleFilesMessage2 {
|
||||
int32 field1 = 1;
|
||||
|
||||
extensions 100 to 199;
|
||||
}
|
||||
|
||||
extend MultipleFilesMessage2 {
|
||||
int32 multiple_files_ext2 = 100;
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
#include "upb/reflection/def.h"
|
||||
#include "upb/reflection/enum_reserved_range.h"
|
||||
#include "upb/reflection/extension_range.h"
|
||||
#include "upb/reflection/internal/def_pool.h"
|
||||
#include "upb/reflection/internal/field_def.h"
|
||||
#include "upb/reflection/internal/file_def.h"
|
||||
#include "upb/reflection/message.h"
|
||||
|
|
@ -35,16 +34,16 @@ typedef struct {
|
|||
|
||||
// We want to copy the options verbatim into the destination options proto.
|
||||
// We use serialize+parse as our deep copy.
|
||||
#define SET_OPTIONS(proto, desc_type, options_type, src, extreg) \
|
||||
{ \
|
||||
size_t size; \
|
||||
/* MEM: could use a temporary arena here instead. */ \
|
||||
char* pb = google_protobuf_##options_type##_serialize(src, ctx->arena, &size); \
|
||||
CHK_OOM(pb); \
|
||||
google_protobuf_##options_type* dst = \
|
||||
google_protobuf_##options_type##_parse_ex(pb, size, extreg, 0, ctx->arena); \
|
||||
CHK_OOM(dst); \
|
||||
google_protobuf_##desc_type##_set_options(proto, dst); \
|
||||
#define SET_OPTIONS(proto, desc_type, options_type, src) \
|
||||
{ \
|
||||
size_t size; \
|
||||
/* MEM: could use a temporary arena here instead. */ \
|
||||
char* pb = google_protobuf_##options_type##_serialize(src, ctx->arena, &size); \
|
||||
CHK_OOM(pb); \
|
||||
google_protobuf_##options_type* dst = \
|
||||
google_protobuf_##options_type##_parse(pb, size, ctx->arena); \
|
||||
CHK_OOM(dst); \
|
||||
google_protobuf_##desc_type##_set_options(proto, dst); \
|
||||
}
|
||||
|
||||
static upb_StringView strviewdup2(upb_ToProto_Context* ctx,
|
||||
|
|
@ -273,9 +272,7 @@ static google_protobuf_FieldDescriptorProto* fielddef_toproto(upb_ToProto_Contex
|
|||
|
||||
if (upb_FieldDef_HasOptions(f)) {
|
||||
SET_OPTIONS(proto, FieldDescriptorProto, FieldOptions,
|
||||
upb_FieldDef_Options(f),
|
||||
_upb_DefPool_GeneratedExtensionRegistry(
|
||||
upb_FileDef_Pool(upb_FieldDef_File(f))));
|
||||
upb_FieldDef_Options(f));
|
||||
}
|
||||
|
||||
return proto;
|
||||
|
|
@ -292,9 +289,7 @@ static google_protobuf_OneofDescriptorProto* oneofdef_toproto(upb_ToProto_Contex
|
|||
|
||||
if (upb_OneofDef_HasOptions(o)) {
|
||||
SET_OPTIONS(proto, OneofDescriptorProto, OneofOptions,
|
||||
upb_OneofDef_Options(o),
|
||||
_upb_DefPool_GeneratedExtensionRegistry(upb_FileDef_Pool(
|
||||
upb_MessageDef_File(upb_OneofDef_ContainingType(o)))));
|
||||
upb_OneofDef_Options(o));
|
||||
}
|
||||
|
||||
return proto;
|
||||
|
|
@ -312,9 +307,7 @@ static google_protobuf_EnumValueDescriptorProto* enumvaldef_toproto(
|
|||
|
||||
if (upb_EnumValueDef_HasOptions(e)) {
|
||||
SET_OPTIONS(proto, EnumValueDescriptorProto, EnumValueOptions,
|
||||
upb_EnumValueDef_Options(e),
|
||||
_upb_DefPool_GeneratedExtensionRegistry(upb_FileDef_Pool(
|
||||
upb_EnumDef_File(upb_EnumValueDef_Enum(e)))));
|
||||
upb_EnumValueDef_Options(e));
|
||||
}
|
||||
|
||||
return proto;
|
||||
|
|
@ -352,9 +345,8 @@ static google_protobuf_EnumDescriptorProto* enumdef_toproto(upb_ToProto_Context*
|
|||
}
|
||||
|
||||
if (upb_EnumDef_HasOptions(e)) {
|
||||
SET_OPTIONS(proto, EnumDescriptorProto, EnumOptions, upb_EnumDef_Options(e),
|
||||
_upb_DefPool_GeneratedExtensionRegistry(
|
||||
upb_FileDef_Pool(upb_EnumDef_File(e))));
|
||||
SET_OPTIONS(proto, EnumDescriptorProto, EnumOptions,
|
||||
upb_EnumDef_Options(e));
|
||||
}
|
||||
|
||||
UPB_DESC(SymbolVisibility) visibility = upb_EnumDef_Visibility(e);
|
||||
|
|
@ -366,8 +358,7 @@ static google_protobuf_EnumDescriptorProto* enumdef_toproto(upb_ToProto_Context*
|
|||
}
|
||||
|
||||
static google_protobuf_DescriptorProto_ExtensionRange* extrange_toproto(
|
||||
upb_ToProto_Context* ctx, const upb_MessageDef* m,
|
||||
const upb_ExtensionRange* e) {
|
||||
upb_ToProto_Context* ctx, const upb_ExtensionRange* e) {
|
||||
google_protobuf_DescriptorProto_ExtensionRange* proto =
|
||||
google_protobuf_DescriptorProto_ExtensionRange_new(ctx->arena);
|
||||
CHK_OOM(proto);
|
||||
|
|
@ -379,9 +370,7 @@ static google_protobuf_DescriptorProto_ExtensionRange* extrange_toproto(
|
|||
|
||||
if (upb_ExtensionRange_HasOptions(e)) {
|
||||
SET_OPTIONS(proto, DescriptorProto_ExtensionRange, ExtensionRangeOptions,
|
||||
upb_ExtensionRange_Options(e),
|
||||
_upb_DefPool_GeneratedExtensionRegistry(
|
||||
upb_FileDef_Pool(upb_MessageDef_File(m))));
|
||||
upb_ExtensionRange_Options(e));
|
||||
}
|
||||
|
||||
return proto;
|
||||
|
|
@ -438,8 +427,7 @@ static google_protobuf_DescriptorProto* msgdef_toproto(upb_ToProto_Context* ctx,
|
|||
google_protobuf_DescriptorProto_ExtensionRange** ext_ranges =
|
||||
google_protobuf_DescriptorProto_resize_extension_range(proto, n, ctx->arena);
|
||||
for (int i = 0; i < n; i++) {
|
||||
ext_ranges[i] =
|
||||
extrange_toproto(ctx, m, upb_MessageDef_ExtensionRange(m, i));
|
||||
ext_ranges[i] = extrange_toproto(ctx, upb_MessageDef_ExtensionRange(m, i));
|
||||
}
|
||||
|
||||
n = upb_MessageDef_ReservedRangeCount(m);
|
||||
|
|
@ -458,9 +446,7 @@ static google_protobuf_DescriptorProto* msgdef_toproto(upb_ToProto_Context* ctx,
|
|||
|
||||
if (upb_MessageDef_HasOptions(m)) {
|
||||
SET_OPTIONS(proto, DescriptorProto, MessageOptions,
|
||||
upb_MessageDef_Options(m),
|
||||
_upb_DefPool_GeneratedExtensionRegistry(
|
||||
upb_FileDef_Pool(upb_MessageDef_File(m))));
|
||||
upb_MessageDef_Options(m));
|
||||
}
|
||||
|
||||
UPB_DESC(SymbolVisibility) visibility = upb_MessageDef_Visibility(m);
|
||||
|
|
@ -496,10 +482,8 @@ static google_protobuf_MethodDescriptorProto* methoddef_toproto(upb_ToProto_Cont
|
|||
}
|
||||
|
||||
if (upb_MethodDef_HasOptions(m)) {
|
||||
SET_OPTIONS(
|
||||
proto, MethodDescriptorProto, MethodOptions, upb_MethodDef_Options(m),
|
||||
_upb_DefPool_GeneratedExtensionRegistry(
|
||||
upb_FileDef_Pool(upb_ServiceDef_File(upb_MethodDef_Service(m)))));
|
||||
SET_OPTIONS(proto, MethodDescriptorProto, MethodOptions,
|
||||
upb_MethodDef_Options(m));
|
||||
}
|
||||
|
||||
return proto;
|
||||
|
|
@ -523,9 +507,7 @@ static google_protobuf_ServiceDescriptorProto* servicedef_toproto(
|
|||
|
||||
if (upb_ServiceDef_HasOptions(s)) {
|
||||
SET_OPTIONS(proto, ServiceDescriptorProto, ServiceOptions,
|
||||
upb_ServiceDef_Options(s),
|
||||
_upb_DefPool_GeneratedExtensionRegistry(
|
||||
upb_FileDef_Pool(upb_ServiceDef_File(s))));
|
||||
upb_ServiceDef_Options(s));
|
||||
}
|
||||
|
||||
return proto;
|
||||
|
|
@ -607,8 +589,8 @@ static google_protobuf_FileDescriptorProto* filedef_toproto(upb_ToProto_Context*
|
|||
}
|
||||
|
||||
if (upb_FileDef_HasOptions(f)) {
|
||||
SET_OPTIONS(proto, FileDescriptorProto, FileOptions, upb_FileDef_Options(f),
|
||||
_upb_DefPool_GeneratedExtensionRegistry(upb_FileDef_Pool(f)));
|
||||
SET_OPTIONS(proto, FileDescriptorProto, FileOptions,
|
||||
upb_FileDef_Options(f));
|
||||
}
|
||||
|
||||
return proto;
|
||||
|
|
|
|||
|
|
@ -243,27 +243,6 @@ void WriteExtension(const DefPoolPair& pools, upb::FieldDefPtr ext,
|
|||
output("\n};\n");
|
||||
}
|
||||
|
||||
void RegisterExtensions(Output& output) {
|
||||
output("UPB_LINKARR_DECLARE(upb_AllExts, const upb_MiniTableExtension);\n");
|
||||
output("UPB_CONSTRUCTOR(upb_GeneratedRegistry_Constructor) {\n");
|
||||
// TODO Although we define this function as weak and only one
|
||||
// copy will ever exist in any binary, every instance will get registered as a
|
||||
// separate constructor call. To avoid duplicate registrations, we use a
|
||||
// static variable to ensure that the function is only executed once.
|
||||
output(" static bool finished = false;\n");
|
||||
output(" if (finished) return;\n");
|
||||
output(" finished = true;\n");
|
||||
output(" static UPB_PRIVATE(upb_GeneratedExtensionListEntry) entry = {\n");
|
||||
output(" UPB_LINKARR_START(upb_AllExts),\n");
|
||||
output(" UPB_LINKARR_STOP(upb_AllExts),\n");
|
||||
output(" NULL\n");
|
||||
output(" };\n");
|
||||
output(" UPB_ASSERT(entry.next == NULL);\n");
|
||||
output(" entry.next = UPB_PRIVATE(upb_generated_extension_list);\n");
|
||||
output(" UPB_PRIVATE(upb_generated_extension_list) = &entry;\n");
|
||||
output("}\n");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void WriteMiniTableHeader(const DefPoolPair& pools, upb::FileDefPtr file,
|
||||
|
|
@ -361,10 +340,6 @@ void WriteMiniTableSourceIncludes(upb::FileDefPtr file,
|
|||
output(
|
||||
"extern const struct upb_MiniTable "
|
||||
"UPB_PRIVATE(_kUpb_MiniTable_StaticallyTreeShaken);\n");
|
||||
|
||||
output(
|
||||
"extern const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* "
|
||||
"UPB_PRIVATE(upb_generated_extension_list);\n");
|
||||
}
|
||||
|
||||
void WriteMiniTableSource(const DefPoolPair& pools, upb::FileDefPtr file,
|
||||
|
|
@ -437,10 +412,6 @@ void WriteMiniTableSource(const DefPoolPair& pools, upb::FileDefPtr file,
|
|||
"\n");
|
||||
}
|
||||
|
||||
if (!extensions.empty()) {
|
||||
RegisterExtensions(output);
|
||||
}
|
||||
|
||||
output("const upb_MiniTableFile $0 = {\n", FileVarName(file));
|
||||
output(" $0,\n", messages.empty() ? "NULL" : kMessagesInit);
|
||||
output(" $0,\n", enums.empty() ? "NULL" : kEnumsInit);
|
||||
|
|
@ -486,19 +457,12 @@ void WriteMiniTableMultipleSources(
|
|||
context->Open(MultipleSourceFilename(file, e.full_name(), &i)));
|
||||
ABSL_CHECK(stream->WriteCord(absl::Cord(output.output())));
|
||||
}
|
||||
if (!extensions.empty()) {
|
||||
// All extensions can be written to a single file because none of the
|
||||
// symbols are retain, and the only weak symbols exist for deduping. It's
|
||||
// most efficient to write them all together, especially with
|
||||
// upb_RegisterExtensionList getting called once per weak definition.
|
||||
for (const auto ext : extensions) {
|
||||
Output output;
|
||||
WriteMiniTableSourceIncludes(file, options, output);
|
||||
for (const auto ext : extensions) {
|
||||
WriteExtension(pools, ext, output);
|
||||
}
|
||||
RegisterExtensions(output);
|
||||
WriteExtension(pools, ext, output);
|
||||
auto stream = absl::WrapUnique(
|
||||
context->Open(MultipleSourceFilename(file, "extensions", &i)));
|
||||
context->Open(MultipleSourceFilename(file, ext.full_name(), &i)));
|
||||
ABSL_CHECK(stream->WriteCord(absl::Cord(output.output())));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue