Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
458 lines
14 KiB
458 lines
14 KiB
// 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 |
|
|
|
/* |
|
* This is where we define internal portability macros used across upb. |
|
* |
|
* All of these macros are undef'd in undef.inc to avoid leaking them to users. |
|
* |
|
* The correct usage is: |
|
* |
|
* #include "upb/foobar.h" |
|
* #include "upb/baz.h" |
|
* |
|
* // MUST be last included header. |
|
* #include "upb/port/def.inc" |
|
* |
|
* // Code for this file. |
|
* // <...> |
|
* |
|
* // Can be omitted for .c files, required for .h. |
|
* #include "upb/port/undef.inc" |
|
* |
|
* This file is private and must not be included by users! |
|
*/ |
|
|
|
#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ |
|
(defined(__cplusplus) && __cplusplus >= 201402L) || \ |
|
(defined(_MSC_VER) && _MSC_VER >= 1900)) |
|
#error upb requires C99 or C++14 or MSVC >= 2015. |
|
#endif |
|
|
|
// Portable check for GCC minimum version: |
|
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html |
|
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) |
|
#define UPB_GNUC_MIN(x, y) \ |
|
(__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) |
|
#else |
|
#define UPB_GNUC_MIN(x, y) 0 |
|
#endif |
|
|
|
#include <assert.h> |
|
#include <setjmp.h> |
|
#include <stdbool.h> |
|
#include <stdint.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
|
|
#ifndef UINTPTR_MAX |
|
Error, UINTPTR_MAX is undefined |
|
#endif |
|
|
|
#if UINTPTR_MAX == 0xffffffff |
|
#define UPB_SIZE(size32, size64) size32 |
|
#else |
|
#define UPB_SIZE(size32, size64) size64 |
|
#endif |
|
|
|
/* 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))) |
|
|
|
// 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 |
|
// of the struct, and a naive sizeof(base) + sizeof(flex) * count calculation |
|
// will not take into account that overlap, and allocate more than is required. |
|
#define UPB_SIZEOF_FLEX(type, member, count) \ |
|
(UPB_MAX(sizeof(type), \ |
|
(offsetof(type, member) + \ |
|
count * (offsetof(type, member[1]) - offsetof(type, member[0]))))) |
|
|
|
#define UPB_MAPTYPE_STRING 0 |
|
|
|
// UPB_EXPORT: always generate a public symbol. |
|
#if defined(__GNUC__) || defined(__clang__) |
|
#define UPB_EXPORT __attribute__((visibility("default"))) __attribute__((used)) |
|
#else |
|
#define UPB_EXPORT |
|
#endif |
|
|
|
// UPB_INLINE: inline if possible, emit standalone code if required. |
|
#ifdef __cplusplus |
|
#define UPB_INLINE inline |
|
#elif defined (__GNUC__) || defined(__clang__) |
|
#define UPB_INLINE static __inline__ |
|
#else |
|
#define UPB_INLINE static |
|
#endif |
|
|
|
#ifdef UPB_BUILD_API |
|
#define UPB_API UPB_EXPORT |
|
#define UPB_API_INLINE UPB_EXPORT |
|
#else |
|
#define UPB_API |
|
#define UPB_API_INLINE UPB_INLINE |
|
#endif |
|
|
|
#ifdef EXPORT_UPBC |
|
#define UPBC_API UPB_EXPORT |
|
#else |
|
#define UPBC_API |
|
#endif |
|
|
|
#define UPB_MALLOC_ALIGN 8 |
|
#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) |
|
#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) |
|
#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) |
|
#ifdef __clang__ |
|
#define UPB_ALIGN_OF(type) _Alignof(type) |
|
#else |
|
#define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) |
|
#endif |
|
|
|
#ifdef _MSC_VER |
|
// Some versions of our Windows compiler don't support the C11 syntax. |
|
#define UPB_ALIGN_AS(x) __declspec(align(x)) |
|
#else |
|
#define UPB_ALIGN_AS(x) _Alignas(x) |
|
#endif |
|
|
|
// Hints to the compiler about likely/unlikely branches. |
|
#if defined (__GNUC__) || defined(__clang__) |
|
#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) |
|
#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) |
|
#else |
|
#define UPB_LIKELY(x) (x) |
|
#define UPB_UNLIKELY(x) (x) |
|
#endif |
|
|
|
// Macros for function attributes on compilers that support them. |
|
#ifdef __GNUC__ |
|
#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) static |
|
#define UPB_NOINLINE __attribute__((noinline)) |
|
#define UPB_NORETURN __attribute__((__noreturn__)) |
|
#define UPB_PRINTF(str, first_vararg) __attribute__((format (printf, str, first_vararg))) |
|
#elif defined(_MSC_VER) |
|
#define UPB_NOINLINE |
|
#define UPB_FORCEINLINE static |
|
#define UPB_NORETURN __declspec(noreturn) |
|
#define UPB_PRINTF(str, first_vararg) |
|
#else /* !defined(__GNUC__) */ |
|
#define UPB_FORCEINLINE static |
|
#define UPB_NOINLINE |
|
#define UPB_NORETURN |
|
#define UPB_PRINTF(str, first_vararg) |
|
#endif |
|
|
|
#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) |
|
#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) |
|
|
|
#define UPB_UNUSED(var) (void)var |
|
|
|
// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. |
|
#ifdef NDEBUG |
|
#ifdef __GNUC__ |
|
#define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() |
|
#elif defined _MSC_VER |
|
#define UPB_ASSUME(expr) if (!(expr)) __assume(0) |
|
#else |
|
#define UPB_ASSUME(expr) do {} while (false && (expr)) |
|
#endif |
|
#else |
|
#define UPB_ASSUME(expr) assert(expr) |
|
#endif |
|
|
|
/* UPB_ASSERT(): in release mode, we use the expression without letting it be |
|
* evaluated. This prevents "unused variable" warnings. */ |
|
#ifdef NDEBUG |
|
#define UPB_ASSERT(expr) do {} while (false && (expr)) |
|
#else |
|
#define UPB_ASSERT(expr) assert(expr) |
|
#endif |
|
|
|
#if defined(__GNUC__) || defined(__clang__) |
|
#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) |
|
#elif defined(_MSC_VER) |
|
#define UPB_UNREACHABLE() \ |
|
do { \ |
|
assert(0); \ |
|
__assume(0); \ |
|
} while (0) |
|
#else |
|
#define UPB_UNREACHABLE() do { assert(0); } while(0) |
|
#endif |
|
|
|
/* UPB_SETJMP() / UPB_LONGJMP() */ |
|
// Android uses a custom libc that does not implement all of posix, but it has |
|
// had sigsetjmp/siglongjmp forever on arm and since API 12 on x86. Apple has |
|
// sigsetjmp, but does not define the posix feature test macro. |
|
#if defined(__APPLE__) || defined(_POSIX_C_SOURCE) || defined(__ANDROID__) |
|
// avoid setting/restoring signal mask, which involves costly syscalls |
|
#define UPB_SETJMP(buf) sigsetjmp(buf, 0) |
|
#define UPB_LONGJMP(buf, val) siglongjmp(buf, val) |
|
#elif defined(WASM_WAMR) |
|
#define UPB_SETJMP(buf) 0 |
|
#define UPB_LONGJMP(buf, val) abort() |
|
#else |
|
#define UPB_SETJMP(buf) setjmp(buf) |
|
#define UPB_LONGJMP(buf, val) longjmp(buf, val) |
|
#endif |
|
|
|
#ifdef __GNUC__ |
|
#define UPB_USE_C11_ATOMICS |
|
#define UPB_ATOMIC(T) _Atomic(T) |
|
#else |
|
#define UPB_ATOMIC(T) T |
|
#endif |
|
|
|
/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ |
|
#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) |
|
|
|
#define UPB_PRIVATE(x) x##_dont_copy_me__upb_internal_use_only |
|
|
|
#ifdef UPB_ALLOW_PRIVATE_ACCESS__FOR_BITS_ONLY |
|
#define UPB_ONLYBITS(x) x |
|
#else |
|
#define UPB_ONLYBITS(x) UPB_PRIVATE(x) |
|
#endif |
|
|
|
/* Configure whether fasttable is switched on or not. *************************/ |
|
|
|
#ifdef __has_attribute |
|
#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) |
|
#else |
|
#define UPB_HAS_ATTRIBUTE(x) 0 |
|
#endif |
|
|
|
#if UPB_HAS_ATTRIBUTE(musttail) |
|
#define UPB_MUSTTAIL __attribute__((musttail)) |
|
#else |
|
#define UPB_MUSTTAIL |
|
#endif |
|
|
|
#undef UPB_HAS_ATTRIBUTE |
|
|
|
/* This check is not fully robust: it does not require that we have "musttail" |
|
* support available. We need tail calls to avoid consuming arbitrary amounts |
|
* of stack space. |
|
* |
|
* GCC/Clang can mostly be trusted to generate tail calls as long as |
|
* optimization is enabled, but, debug builds will not generate tail calls |
|
* unless "musttail" is available. |
|
* |
|
* We should probably either: |
|
* 1. require that the compiler supports musttail. |
|
* 2. add some fallback code for when musttail isn't available (ie. return |
|
* instead of tail calling). This is safe and portable, but this comes at |
|
* a CPU cost. |
|
*/ |
|
#if (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__) |
|
#define UPB_FASTTABLE_SUPPORTED 1 |
|
#else |
|
#define UPB_FASTTABLE_SUPPORTED 0 |
|
#endif |
|
|
|
/* define UPB_ENABLE_FASTTABLE to force fast table support. |
|
* This is useful when we want to ensure we are really getting fasttable, |
|
* for example for testing or benchmarking. */ |
|
#if defined(UPB_ENABLE_FASTTABLE) |
|
#if !UPB_FASTTABLE_SUPPORTED |
|
#error fasttable is x86-64/ARM64 only and requires GCC or Clang. |
|
#endif |
|
#define UPB_FASTTABLE 1 |
|
/* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. |
|
* This is useful for releasing code that might be used on multiple platforms, |
|
* for example the PHP or Ruby C extensions. */ |
|
#elif defined(UPB_TRY_ENABLE_FASTTABLE) |
|
#define UPB_FASTTABLE UPB_FASTTABLE_SUPPORTED |
|
#else |
|
#define UPB_FASTTABLE 0 |
|
#endif |
|
|
|
/* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully |
|
* degrade to non-fasttable if the runtime or platform do not support it. */ |
|
#if !UPB_FASTTABLE |
|
#define UPB_FASTTABLE_INIT(...) |
|
#define UPB_FASTTABLE_MASK(mask) -1 |
|
#else |
|
#define UPB_FASTTABLE_INIT(...) __VA_ARGS__ |
|
#define UPB_FASTTABLE_MASK(mask) mask |
|
#endif |
|
|
|
#undef UPB_FASTTABLE_SUPPORTED |
|
|
|
/* ASAN poisoning (for arena). |
|
* If using UPB from an interpreted language like Ruby, a build of the |
|
* interpreter compiled with ASAN enabled must be used in order to get sane and |
|
* expected behavior. |
|
*/ |
|
|
|
/* Due to preprocessor limitations, the conditional logic for setting |
|
* UPN_CLANG_ASAN below cannot be consolidated into a portable one-liner. |
|
* See https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html. |
|
*/ |
|
#if defined(__has_feature) |
|
#if __has_feature(address_sanitizer) |
|
#define UPB_CLANG_ASAN 1 |
|
#else |
|
#define UPB_CLANG_ASAN 0 |
|
#endif |
|
#else |
|
#define UPB_CLANG_ASAN 0 |
|
#endif |
|
|
|
#if defined(__SANITIZE_ADDRESS__) || UPB_CLANG_ASAN |
|
#define UPB_ASAN 1 |
|
#define UPB_ASAN_GUARD_SIZE 32 |
|
#ifdef __cplusplus |
|
extern "C" { |
|
#endif |
|
void __asan_poison_memory_region(void const volatile *addr, size_t size); |
|
void __asan_unpoison_memory_region(void const volatile *addr, size_t size); |
|
#ifdef __cplusplus |
|
} /* extern "C" */ |
|
#endif |
|
#define UPB_POISON_MEMORY_REGION(addr, size) \ |
|
__asan_poison_memory_region((addr), (size)) |
|
#define UPB_UNPOISON_MEMORY_REGION(addr, size) \ |
|
__asan_unpoison_memory_region((addr), (size)) |
|
#else |
|
#define UPB_ASAN 0 |
|
#define UPB_ASAN_GUARD_SIZE 0 |
|
#define UPB_POISON_MEMORY_REGION(addr, size) \ |
|
((void)(addr), (void)(size)) |
|
#define UPB_UNPOISON_MEMORY_REGION(addr, size) \ |
|
((void)(addr), (void)(size)) |
|
#endif |
|
|
|
/* Disable proto2 arena behavior (TEMPORARY) **********************************/ |
|
|
|
#ifdef UPB_DISABLE_CLOSED_ENUM_CHECKING |
|
#define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 1 |
|
#else |
|
#define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 0 |
|
#endif |
|
|
|
#if defined(__cplusplus) |
|
#if defined(__clang__) || UPB_GNUC_MIN(6, 0) |
|
// https://gcc.gnu.org/gcc-6/changes.html |
|
#if __cplusplus >= 201402L |
|
#define UPB_DEPRECATED [[deprecated]] |
|
#else |
|
#define UPB_DEPRECATED __attribute__((deprecated)) |
|
#endif |
|
#else |
|
#define UPB_DEPRECATED |
|
#endif |
|
#else |
|
#define UPB_DEPRECATED |
|
#endif |
|
|
|
#if defined(UPB_IS_GOOGLE3) && \ |
|
(!defined(UPB_BOOTSTRAP_STAGE) || UPB_BOOTSTRAP_STAGE != 0) |
|
#define UPB_DESC(sym) proto2_##sym |
|
#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init |
|
#elif defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0 |
|
#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 |
|
|
|
#undef UPB_IS_GOOGLE3 |
|
|
|
// 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), \ |
|
no_sanitize("address"))) |
|
#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] |
|
#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), \ |
|
no_sanitize("address"))) |
|
#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] |
|
#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, 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 appends a no-op but |
|
// don't define the other macros. |
|
#define UPB_LINKARR_APPEND(name) |
|
|
|
#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. |
|
#ifdef UPB_FUTURE_BREAKING_CHANGES |
|
|
|
// Properly enforce closed enums in python. |
|
// Owner: mkruskal@ |
|
#define UPB_FUTURE_PYTHON_CLOSED_ENUM_ENFORCEMENT 1 |
|
|
|
#endif
|
|
|