Introduced a generated extension registry using linker arrays. PiperOrigin-RevId: 640196225
diff --git a/upb/mini_table/extension_registry.c b/upb/mini_table/extension_registry.c index f5b118f..6916f7e 100644 --- a/upb/mini_table/extension_registry.c +++ b/upb/mini_table/extension_registry.c
@@ -70,6 +70,24 @@ return false; } +#ifdef UPB_LINKARR_DECLARE + +UPB_LINKARR_DECLARE(upb_AllExts, const upb_MiniTableExtension*); + +bool upb_ExtensionRegistry_AddAllLinkedExtensions(upb_ExtensionRegistry* r) { + const upb_MiniTableExtension* const* start = UPB_LINKARR_START(upb_AllExts); + const upb_MiniTableExtension* const* stop = UPB_LINKARR_STOP(upb_AllExts); + for (const upb_MiniTableExtension* const* p = start; p < stop; p++) { + // Windows can introduce zero padding, so we have to skip zeroes. + if (*p != 0) { + if (!upb_ExtensionRegistry_Add(r, *p)) return false; + } + } + return true; +} + +#endif // UPB_LINKARR_DECLARE + const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) { char buf[EXTREG_KEY_SIZE];
diff --git a/upb/mini_table/extension_registry.h b/upb/mini_table/extension_registry.h index 0465140..9f5f81a 100644 --- a/upb/mini_table/extension_registry.h +++ b/upb/mini_table/extension_registry.h
@@ -71,6 +71,23 @@ 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 +// shared libraries. +// +// Returns true if all extensions were added successfully, false on out of +// memory or if any extensions were already present. +// +// This API is currently not available on MSVC (though it *is* available on +// Windows using clang-cl). +UPB_API bool upb_ExtensionRegistry_AddAllLinkedExtensions( + upb_ExtensionRegistry* r); + +#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. UPB_API const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup(
diff --git a/upb/port/def.inc b/upb/port/def.inc index 7d23d5c..0480da7 100644 --- a/upb/port/def.inc +++ b/upb/port/def.inc
@@ -350,3 +350,79 @@ error UPB_TRACING_ENABLED Tracing should be disabled in production builds #endif #endif + +// Linker arrays combine elements from multiple translation units into a single +// array that can be iterated over at runtime. +// +// It is an alternative to pre-main "registration" functions. +// +// Usage: +// +// // In N translation units. +// UPB_LINKARR_APPEND(foo_array) static int elems[3] = {1, 2, 3}; +// +// // At runtime: +// UPB_LINKARR_DECLARE(foo_array, int); +// +// void f() { +// const int* start = UPB_LINKARR_START(foo_array); +// const int* stop = UPB_LINKARR_STOP(foo_array); +// for (const int* p = start; p < stop; p++) { +// // Windows can introduce zero padding, so we have to skip zeroes. +// if (*p != 0) { +// vec.push_back(*p); +// } +// } +// } + +#if defined(__ELF__) || defined(__wasm__) + +#define UPB_LINKARR_APPEND(name) \ + __attribute__((retain, used, section("linkarr_" #name))) +#define UPB_LINKARR_DECLARE(name, type) \ + extern type const __start_linkarr_##name; \ + extern type const __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) + +#elif defined(__MACH__) + +/* As described in: https://stackoverflow.com/a/22366882 */ +#define UPB_LINKARR_APPEND(name) \ + __attribute__((retain, used, section("__DATA,la_" #name))) +#define UPB_LINKARR_DECLARE(name, type) \ + extern type const __start_linkarr_##name __asm( \ + "section$start$__DATA$la_" #name); \ + extern type const __stop_linkarr_##name __asm( \ + "section$end$__DATA$" \ + "la_" #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) + +#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 */ + +// 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")) __attribute__((retain, used)) +#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 appends a no-op but +// don't define the other macros. +#define UPB_LINKARR_APPEND(name) + +#endif
diff --git a/upb/port/undef.inc b/upb/port/undef.inc index c715441..d8453ff 100644 --- a/upb/port/undef.inc +++ b/upb/port/undef.inc
@@ -56,3 +56,7 @@ #undef UPB_USE_C11_ATOMICS #undef UPB_PRIVATE #undef UPB_ONLYBITS +#undef UPB_LINKARR_DECLARE +#undef UPB_LINKARR_APPEND +#undef UPB_LINKARR_START +#undef UPB_LINKARR_STOP
diff --git a/upb_generator/protoc-gen-upb_minitable.cc b/upb_generator/protoc-gen-upb_minitable.cc index 86f5b69..7c15308 100644 --- a/upb_generator/protoc-gen-upb_minitable.cc +++ b/upb_generator/protoc-gen-upb_minitable.cc
@@ -519,6 +519,7 @@ output( "\n" + "UPB_LINKARR_APPEND(upb_AllExts)\n" "static const upb_MiniTableExtension *$0[$1] = {\n", kExtensionsInit, exts.size());