diff options
author | arcadia-devtools <arcadia-devtools@yandex-team.ru> | 2022-03-15 21:33:41 +0300 |
---|---|---|
committer | arcadia-devtools <arcadia-devtools@yandex-team.ru> | 2022-03-15 21:33:41 +0300 |
commit | 3dd665b514943f69657b593eb51af90b99b1206b (patch) | |
tree | 0eb633e628bb1fe6c639574b1184d43def7c0a73 /contrib/libs/grpc/third_party | |
parent | a68afc731202027f105bc5723ee11788017c29e2 (diff) | |
download | ydb-3dd665b514943f69657b593eb51af90b99b1206b.tar.gz |
intermediate changes
ref:953ca886ec160075b38c0f3614de029b423f0a9e
Diffstat (limited to 'contrib/libs/grpc/third_party')
32 files changed, 6927 insertions, 811 deletions
diff --git a/contrib/libs/grpc/third_party/ABSEIL_MANUAL.md b/contrib/libs/grpc/third_party/ABSEIL_MANUAL.md new file mode 100644 index 0000000000..0fd4181199 --- /dev/null +++ b/contrib/libs/grpc/third_party/ABSEIL_MANUAL.md @@ -0,0 +1,32 @@ +# Abseil in gRPC + +This document explains how to use Abseil throughout gRPC. Note that this isn't +supposed to explain general usage of Abseil. + +## The version of Abseil + +gRPC intends to use the LTS versions of Abseil only because it simplifies +dependency management. Abseil is being distributed via package distribution +systems such as vcpkg and cocoapods. If gRPC depends on the certain version +that aren't registered, gRPC in that system cannot get the right version of +Abseil when being built, resulting in a build failure. +Therefore, gRPC will use the LTS version only, preferably the latest one. + +## Libraries that are not ready to use + +Most of Abseil libraries are okay to use but there are some exceptions +because they're not going well yet on some of our test machinaries or +platforms it supports. The following is a list of targets that are NOT +ready to use. + +- `y_absl/synchronization:*`: This will be ready from the LTS version in 2021. +- `y_absl/random`: [WIP](https://github.com/grpc/grpc/pull/23346). +- `y_absl/types:variant`: [WIP](https://github.com/grpc/grpc/pull/22961). + +## Implemetation only + +You can use Abseil in gRPC Core and gRPC C++. But you cannot use it in +the public interface of gRPC C++ because i) it doesn't gurantee no breaking +API changes like gRPC C++ does and ii) it may make users change their build +system to address Abseil. +
\ No newline at end of file diff --git a/contrib/libs/grpc/third_party/README.md b/contrib/libs/grpc/third_party/README.md index 9bf04831bc..473b542644 100644 --- a/contrib/libs/grpc/third_party/README.md +++ b/contrib/libs/grpc/third_party/README.md @@ -48,6 +48,14 @@ Usually the process is Updating some dependencies requires extra care. +### Updating third_party/abseil-cpp + +- Two additional steps should be done before running `generate_projects.sh` above. + - Running `src/abseil-cpp/preprocessed_builds.yaml.gen.py`. + - Updating `abseil_version =` scripts in `templates/gRPC-C++.podspec.template` and + `templates/gRPC-Core.podspec.template`. +- You can see an example of previous [upgrade](https://github.com/grpc/grpc/pull/24270). + ### Updating third_party/boringssl-with-bazel - Update the `third_party/boringssl-with-bazel` submodule to the latest [`master-with-bazel`](https://github.com/google/boringssl/tree/master-with-bazel) branch diff --git a/contrib/libs/grpc/third_party/address_sorting/include/address_sorting/address_sorting.h b/contrib/libs/grpc/third_party/address_sorting/include/address_sorting/address_sorting.h index c58fafe3f7..074fc7554e 100644 --- a/contrib/libs/grpc/third_party/address_sorting/include/address_sorting/address_sorting.h +++ b/contrib/libs/grpc/third_party/address_sorting/include/address_sorting/address_sorting.h @@ -41,6 +41,8 @@ #ifndef ADDRESS_SORTING_H #define ADDRESS_SORTING_H +#include <stddef.h> + #ifdef __cplusplus extern "C" { #endif diff --git a/contrib/libs/grpc/third_party/upb/.yandex_meta/licenses.list.txt b/contrib/libs/grpc/third_party/upb/.yandex_meta/licenses.list.txt index b1f339a11d..fb787bff11 100644 --- a/contrib/libs/grpc/third_party/upb/.yandex_meta/licenses.list.txt +++ b/contrib/libs/grpc/third_party/upb/.yandex_meta/licenses.list.txt @@ -23,9 +23,344 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ====================COPYRIGHT==================== +/* Copyright 2020 王一 Wang Yi <godspeed_china@yeah.net> + This is free and unencumbered software released into the public domain. http://unlicense.org/ + See github.com/wangyi-fudan/wyhash/ LICENSE + + +====================COPYRIGHT==================== Copyright (c) 2009-2011, Google Inc. All rights reserved. +====================File: AUTHORS==================== +Dropbox, Inc. +Google Inc. +Skyscanner Ltd. +WeWork Companies Inc. + + +====================File: LICENSE==================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +====================File: third_party/address_sorting/LICENSE==================== +Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + +====================File: third_party/upb/LICENSE==================== + +Copyright (c) 2009-2011, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Google Inc. nor the names of any other + contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL GOOGLE INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +====================File: third_party/upb/third_party/wyhash/LICENSE==================== +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> + + + ====================Public-Domain==================== - * MurmurHash2, by Austin Appleby (released as public domain). + This is free and unencumbered software released into the public domain. http://unlicense.org/ + + +====================Unlicense==================== + This is free and unencumbered software released into the public domain. http://unlicense.org/ + + +====================Unlicense==================== +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/contrib/libs/grpc/third_party/upb/CMakeLists.txt b/contrib/libs/grpc/third_party/upb/CMakeLists.txt index d3c68ad50f..e038006314 100644 --- a/contrib/libs/grpc/third_party/upb/CMakeLists.txt +++ b/contrib/libs/grpc/third_party/upb/CMakeLists.txt @@ -14,13 +14,20 @@ target_compile_options(grpc-third_party-upb PRIVATE target_include_directories(grpc-third_party-upb PRIVATE ${CMAKE_BINARY_DIR}/contrib/libs/grpc ${CMAKE_SOURCE_DIR}/contrib/libs/grpc + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/src/core/ext/upb-generated + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/src/core/ext/upbdefs-generated ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb ) target_sources(grpc-third_party-upb PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/src/core/ext/upbdefs-generated/google/protobuf/descriptor.upbdefs.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode_fast.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/def.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/encode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/msg.c - ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/port.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/reflection.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/table.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/text_encode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/upb.c ) diff --git a/contrib/libs/grpc/third_party/upb/third_party/wyhash/LICENSE b/contrib/libs/grpc/third_party/upb/third_party/wyhash/LICENSE new file mode 100644 index 0000000000..471f09f4cf --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/third_party/wyhash/LICENSE @@ -0,0 +1,25 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> + diff --git a/contrib/libs/grpc/third_party/upb/third_party/wyhash/wyhash.h b/contrib/libs/grpc/third_party/upb/third_party/wyhash/wyhash.h new file mode 100644 index 0000000000..5658f02df3 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/third_party/wyhash/wyhash.h @@ -0,0 +1,145 @@ +/* Copyright 2020 王一 Wang Yi <godspeed_china@yeah.net> + This is free and unencumbered software released into the public domain. http://unlicense.org/ + See github.com/wangyi-fudan/wyhash/ LICENSE + */ +#ifndef wyhash_final_version +#define wyhash_final_version +//defines that change behavior +#ifndef WYHASH_CONDOM +#define WYHASH_CONDOM 1 //0: read 8 bytes before and after boundaries, dangerous but fastest. 1: normal valid behavior 2: extra protection against entropy loss (probability=2^-63), aka. "blind multiplication" +#endif +#define WYHASH_32BIT_MUM 0 //faster on 32 bit system +//includes +#include <stdint.h> +#include <string.h> +#if defined(_MSC_VER) && defined(_M_X64) + #include <intrin.h> + #pragma intrinsic(_umul128) +#endif +#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) + #define _likely_(x) __builtin_expect(x,1) + #define _unlikely_(x) __builtin_expect(x,0) +#else + #define _likely_(x) (x) + #define _unlikely_(x) (x) +#endif +//mum function +static inline uint64_t _wyrot(uint64_t x) { return (x>>32)|(x<<32); } +static inline void _wymum(uint64_t *A, uint64_t *B){ +#if(WYHASH_32BIT_MUM) + uint64_t hh=(*A>>32)*(*B>>32), hl=(*A>>32)*(unsigned)*B, lh=(unsigned)*A*(*B>>32), ll=(uint64_t)(unsigned)*A*(unsigned)*B; + #if(WYHASH_CONDOM>1) + *A^=_wyrot(hl)^hh; *B^=_wyrot(lh)^ll; + #else + *A=_wyrot(hl)^hh; *B=_wyrot(lh)^ll; + #endif +#elif defined(__SIZEOF_INT128__) + __uint128_t r=*A; r*=*B; + #if(WYHASH_CONDOM>1) + *A^=(uint64_t)r; *B^=(uint64_t)(r>>64); + #else + *A=(uint64_t)r; *B=(uint64_t)(r>>64); + #endif +#elif defined(_MSC_VER) && defined(_M_X64) + #if(WYHASH_CONDOM>1) + uint64_t a, b; + a=_umul128(*A,*B,&b); + *A^=a; *B^=b; + #else + *A=_umul128(*A,*B,B); + #endif +#else + uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo; + uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl; + lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c; + #if(WYHASH_CONDOM>1) + *A^=lo; *B^=hi; + #else + *A=lo; *B=hi; + #endif +#endif +} +static inline uint64_t _wymix(uint64_t A, uint64_t B){ _wymum(&A,&B); return A^B; } +//read functions +#ifndef WYHASH_LITTLE_ENDIAN + #if defined(_WIN32) || defined(__LITTLE_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + #define WYHASH_LITTLE_ENDIAN 1 + #elif defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + #define WYHASH_LITTLE_ENDIAN 0 + #endif +#endif +#if (WYHASH_LITTLE_ENDIAN) +static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return v;} +static inline uint64_t _wyr4(const uint8_t *p) { unsigned v; memcpy(&v, p, 4); return v;} +#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) +static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return __builtin_bswap64(v);} +static inline uint64_t _wyr4(const uint8_t *p) { unsigned v; memcpy(&v, p, 4); return __builtin_bswap32(v);} +#elif defined(_MSC_VER) +static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return _byteswap_uint64(v);} +static inline uint64_t _wyr4(const uint8_t *p) { unsigned v; memcpy(&v, p, 4); return _byteswap_ulong(v);} +#endif +static inline uint64_t _wyr3(const uint8_t *p, unsigned k) { return (((uint64_t)p[0])<<16)|(((uint64_t)p[k>>1])<<8)|p[k-1];} +//wyhash function +static inline uint64_t _wyfinish16(const uint8_t *p, uint64_t len, uint64_t seed, const uint64_t *secret, uint64_t i){ +#if(WYHASH_CONDOM>0) + uint64_t a, b; + if(_likely_(i<=8)){ + if(_likely_(i>=4)){ a=_wyr4(p); b=_wyr4(p+i-4); } + else if (_likely_(i)){ a=_wyr3(p,i); b=0; } + else a=b=0; + } + else{ a=_wyr8(p); b=_wyr8(p+i-8); } + return _wymix(secret[1]^len,_wymix(a^secret[1], b^seed)); +#else + #define oneshot_shift ((i<8)*((8-i)<<3)) + return _wymix(secret[1]^len,_wymix((_wyr8(p)<<oneshot_shift)^secret[1],(_wyr8(p+i-8)>>oneshot_shift)^seed)); +#endif +} + +static inline uint64_t _wyfinish(const uint8_t *p, uint64_t len, uint64_t seed, const uint64_t *secret, uint64_t i){ + if(_likely_(i<=16)) return _wyfinish16(p,len,seed,secret,i); + return _wyfinish(p+16,len,_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed),secret,i-16); +} + +static inline uint64_t wyhash(const void *key, uint64_t len, uint64_t seed, const uint64_t *secret){ + const uint8_t *p=(const uint8_t *)key; + uint64_t i=len; seed^=*secret; + if(_unlikely_(i>64)){ + uint64_t see1=seed; + do{ + seed=_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed)^_wymix(_wyr8(p+16)^secret[2],_wyr8(p+24)^seed); + see1=_wymix(_wyr8(p+32)^secret[3],_wyr8(p+40)^see1)^_wymix(_wyr8(p+48)^secret[4],_wyr8(p+56)^see1); + p+=64; i-=64; + }while(i>64); + seed^=see1; + } + return _wyfinish(p,len,seed,secret,i); +} +//utility functions +const uint64_t _wyp[5] = {0xa0761d6478bd642full, 0xe7037ed1a0b428dbull, 0x8ebc6af09c88c6e3ull, 0x589965cc75374cc3ull, 0x1d8e4e27c47d124full}; +static inline uint64_t wyhash64(uint64_t A, uint64_t B){ A^=_wyp[0]; B^=_wyp[1]; _wymum(&A,&B); return _wymix(A^_wyp[0],B^_wyp[1]);} +static inline uint64_t wyrand(uint64_t *seed){ *seed+=_wyp[0]; return _wymix(*seed,*seed^_wyp[1]);} +static inline double wy2u01(uint64_t r){ const double _wynorm=1.0/(1ull<<52); return (r>>12)*_wynorm;} +static inline double wy2gau(uint64_t r){ const double _wynorm=1.0/(1ull<<20); return ((r&0x1fffff)+((r>>21)&0x1fffff)+((r>>42)&0x1fffff))*_wynorm-3.0;} +static inline uint64_t wy2u0k(uint64_t r, uint64_t k){ _wymum(&r,&k); return k; } + +static inline void make_secret(uint64_t seed, uint64_t *secret){ + uint8_t c[] = {15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, 57, 58, 60, 71, 75, 77, 78, 83, 85, 86, 89, 90, 92, 99, 101, 102, 105, 106, 108, 113, 114, 116, 120, 135, 139, 141, 142, 147, 149, 150, 153, 154, 156, 163, 165, 166, 169, 170, 172, 177, 178, 180, 184, 195, 197, 198, 201, 202, 204, 209, 210, 212, 216, 225, 226, 228, 232, 240 }; + for(size_t i=0;i<5;i++){ + uint8_t ok; + do{ + ok=1; secret[i]=0; + for(size_t j=0;j<64;j+=8) secret[i]|=((uint64_t)c[wyrand(&seed)%sizeof(c)])<<j; + if(secret[i]%2==0){ ok=0; continue; } + for(size_t j=0;j<i;j++) +#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) + if(__builtin_popcountll(secret[j]^secret[i])!=32){ ok=0; break; } +#elif defined(_MSC_VER) && defined(_M_X64) + if(_mm_popcnt_u64(secret[j]^secret[i])!=32){ ok=0; break; } +#endif + if(!ok)continue; + for(uint64_t j=3;j<0x100000000ull;j+=2) if(secret[i]%j==0){ ok=0; break; } + }while(!ok); + } +} +#endif diff --git a/contrib/libs/grpc/third_party/upb/upb/decode.c b/contrib/libs/grpc/third_party/upb/upb/decode.c index a9f1cf548a..a5f0666fa8 100644 --- a/contrib/libs/grpc/third_party/upb/upb/decode.c +++ b/contrib/libs/grpc/third_party/upb/upb/decode.c @@ -1,33 +1,37 @@ +#include "upb/decode.h" + #include <setjmp.h> #include <string.h> -#include "upb/decode.h" +#include "upb/decode.int.h" #include "upb/upb.h" +#include "upb/upb.int.h" +/* Must be last. */ #include "upb/port_def.inc" -/* Maps descriptor type -> upb field type. */ -static const uint8_t desctype_to_fieldtype[] = { +/* Maps descriptor type -> elem_size_lg2. */ +static const uint8_t desctype_to_elem_size_lg2[] = { -1, /* invalid descriptor type */ - UPB_TYPE_DOUBLE, /* DOUBLE */ - UPB_TYPE_FLOAT, /* FLOAT */ - UPB_TYPE_INT64, /* INT64 */ - UPB_TYPE_UINT64, /* UINT64 */ - UPB_TYPE_INT32, /* INT32 */ - UPB_TYPE_UINT64, /* FIXED64 */ - UPB_TYPE_UINT32, /* FIXED32 */ - UPB_TYPE_BOOL, /* BOOL */ - UPB_TYPE_STRING, /* STRING */ - UPB_TYPE_MESSAGE, /* GROUP */ - UPB_TYPE_MESSAGE, /* MESSAGE */ - UPB_TYPE_BYTES, /* BYTES */ - UPB_TYPE_UINT32, /* UINT32 */ - UPB_TYPE_ENUM, /* ENUM */ - UPB_TYPE_INT32, /* SFIXED32 */ - UPB_TYPE_INT64, /* SFIXED64 */ - UPB_TYPE_INT32, /* SINT32 */ - UPB_TYPE_INT64, /* SINT64 */ + 3, /* DOUBLE */ + 2, /* FLOAT */ + 3, /* INT64 */ + 3, /* UINT64 */ + 2, /* INT32 */ + 3, /* FIXED64 */ + 2, /* FIXED32 */ + 0, /* BOOL */ + UPB_SIZE(3, 4), /* STRING */ + UPB_SIZE(2, 3), /* GROUP */ + UPB_SIZE(2, 3), /* MESSAGE */ + UPB_SIZE(3, 4), /* BYTES */ + 2, /* UINT32 */ + 2, /* ENUM */ + 2, /* SFIXED32 */ + 3, /* SFIXED64 */ + 2, /* SINT32 */ + 3, /* SINT64 */ }; /* Maps descriptor type -> upb map size. */ @@ -134,106 +138,101 @@ static const int8_t delim_ops[37] = { OP_VARPCK_LG2(3), /* REPEATED SINT64 */ }; -/* Data pertaining to the parse. */ -typedef struct { - const char *limit; /* End of delimited region or end of buffer. */ - upb_arena *arena; - int depth; - uint32_t end_group; /* Set to field number of END_GROUP tag, if any. */ - jmp_buf err; -} upb_decstate; - typedef union { bool bool_val; uint32_t uint32_val; uint64_t uint64_val; - upb_strview str_val; + uint32_t size; } wireval; static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, const upb_msglayout *layout); -UPB_NORETURN static void decode_err(upb_decstate *d) { longjmp(d->err, 1); } - -void decode_verifyutf8(upb_decstate *d, const char *buf, int len) { - static const uint8_t utf8_offset[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, - }; - - int i, j; - uint8_t offset; - - i = 0; - while (i < len) { - offset = utf8_offset[(uint8_t)buf[i]]; - if (offset == 0 || i + offset > len) { - decode_err(d); - } - for (j = i + 1; j < i + offset; j++) { - if ((buf[j] & 0xc0) != 0x80) { - decode_err(d); - } - } - i += offset; - } - if (i != len) decode_err(d); +UPB_NORETURN static void decode_err(upb_decstate *d) { UPB_LONGJMP(d->err, 1); } + +const char *fastdecode_err(upb_decstate *d) { + longjmp(d->err, 1); + return NULL; +} + +const uint8_t upb_utf8_offsets[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static void decode_verifyutf8(upb_decstate *d, const char *buf, int len) { + if (!decode_verifyutf8_inl(buf, len)) decode_err(d); } static bool decode_reserve(upb_decstate *d, upb_array *arr, size_t elem) { bool need_realloc = arr->size - arr->len < elem; - if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, d->arena)) { + if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, &d->arena)) { decode_err(d); } return need_realloc; } +typedef struct { + const char *ptr; + uint64_t val; +} decode_vret; + UPB_NOINLINE -static const char *decode_longvarint64(upb_decstate *d, const char *ptr, - const char *limit, uint64_t *val) { - uint8_t byte; - int bitpos = 0; - uint64_t out = 0; - - do { - if (bitpos >= 70 || ptr == limit) decode_err(d); - byte = *ptr; - out |= (uint64_t)(byte & 0x7F) << bitpos; - ptr++; - bitpos += 7; - } while (byte & 0x80); - - *val = out; - return ptr; +static decode_vret decode_longvarint64(const char *ptr, uint64_t val) { + decode_vret ret = {NULL, 0}; + uint64_t byte; + int i; + for (i = 1; i < 10; i++) { + byte = (uint8_t)ptr[i]; + val += (byte - 1) << (i * 7); + if (!(byte & 0x80)) { + ret.ptr = ptr + i + 1; + ret.val = val; + return ret; + } + } + return ret; } UPB_FORCEINLINE static const char *decode_varint64(upb_decstate *d, const char *ptr, - const char *limit, uint64_t *val) { - if (UPB_LIKELY(ptr < limit && (*ptr & 0x80) == 0)) { - *val = (uint8_t)*ptr; + uint64_t *val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; return ptr + 1; } else { - return decode_longvarint64(d, ptr, limit, val); + decode_vret res = decode_longvarint64(ptr, byte); + if (!res.ptr) decode_err(d); + *val = res.val; + return res.ptr; } } -static const char *decode_varint32(upb_decstate *d, const char *ptr, - const char *limit, uint32_t *val) { - uint64_t u64; - ptr = decode_varint64(d, ptr, limit, &u64); - if (u64 > UINT32_MAX) decode_err(d); - *val = (uint32_t)u64; - return ptr; +UPB_FORCEINLINE +static const char *decode_tag(upb_decstate *d, const char *ptr, + uint32_t *val) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = byte; + return ptr + 1; + } else { + const char *start = ptr; + decode_vret res = decode_longvarint64(ptr, byte); + ptr = res.ptr; + *val = res.val; + if (!ptr || *val > UINT32_MAX || ptr - start > 5) decode_err(d); + return ptr; + } } static void decode_munge(int type, wireval *val) { @@ -280,33 +279,65 @@ static const upb_msglayout_field *upb_find_field(const upb_msglayout *l, static upb_msg *decode_newsubmsg(upb_decstate *d, const upb_msglayout *layout, const upb_msglayout_field *field) { const upb_msglayout *subl = layout->submsgs[field->submsg_index]; - return _upb_msg_new(subl, d->arena); + return _upb_msg_new_inl(subl, &d->arena); +} + +UPB_NOINLINE +const char *decode_isdonefallback(upb_decstate *d, const char *ptr, + int overrun) { + ptr = decode_isdonefallback_inl(d, ptr, overrun); + if (ptr == NULL) { + decode_err(d); + } + return ptr; +} + +static const char *decode_readstr(upb_decstate *d, const char *ptr, int size, + upb_strview *str) { + if (d->alias) { + str->data = ptr; + } else { + char *data = upb_arena_malloc(&d->arena, size); + if (!data) decode_err(d); + memcpy(data, ptr, size); + str->data = data; + } + str->size = size; + return ptr + size; } -static void decode_tosubmsg(upb_decstate *d, upb_msg *submsg, - const upb_msglayout *layout, - const upb_msglayout_field *field, upb_strview val) { +UPB_FORCEINLINE +static const char *decode_tosubmsg(upb_decstate *d, const char *ptr, + upb_msg *submsg, const upb_msglayout *layout, + const upb_msglayout_field *field, int size) { const upb_msglayout *subl = layout->submsgs[field->submsg_index]; - const char *saved_limit = d->limit; + int saved_delta = decode_pushlimit(d, ptr, size); if (--d->depth < 0) decode_err(d); - d->limit = val.data + val.size; - decode_msg(d, val.data, submsg, subl); - d->limit = saved_limit; - if (d->end_group != 0) decode_err(d); + if (!decode_isdone(d, &ptr)) { + ptr = decode_msg(d, ptr, submsg, subl); + } + if (d->end_group != DECODE_NOGROUP) decode_err(d); + decode_poplimit(d, ptr, saved_delta); d->depth++; + return ptr; } +UPB_FORCEINLINE static const char *decode_group(upb_decstate *d, const char *ptr, upb_msg *submsg, const upb_msglayout *subl, uint32_t number) { if (--d->depth < 0) decode_err(d); + if (decode_isdone(d, &ptr)) { + decode_err(d); + } ptr = decode_msg(d, ptr, submsg, subl); if (d->end_group != number) decode_err(d); - d->end_group = 0; + d->end_group = DECODE_NOGROUP; d->depth++; return ptr; } +UPB_FORCEINLINE static const char *decode_togroup(upb_decstate *d, const char *ptr, upb_msg *submsg, const upb_msglayout *layout, const upb_msglayout_field *field) { @@ -322,15 +353,15 @@ static const char *decode_toarray(upb_decstate *d, const char *ptr, upb_array *arr = *arrp; void *mem; - if (!arr) { - upb_fieldtype_t type = desctype_to_fieldtype[field->descriptortype]; - arr = _upb_array_new(d->arena, type); + if (arr) { + decode_reserve(d, arr, 1); + } else { + size_t lg2 = desctype_to_elem_size_lg2[field->descriptortype]; + arr = _upb_array_new(&d->arena, 4, lg2); if (!arr) decode_err(d); *arrp = arr; } - decode_reserve(d, arr, 1); - switch (op) { case OP_SCALAR_LG2(0): case OP_SCALAR_LG2(2): @@ -341,15 +372,14 @@ static const char *decode_toarray(upb_decstate *d, const char *ptr, memcpy(mem, &val, 1 << op); return ptr; case OP_STRING: - decode_verifyutf8(d, val.str_val.data, val.str_val.size); + decode_verifyutf8(d, ptr, val.size); /* Fallthrough. */ - case OP_BYTES: + case OP_BYTES: { /* Append bytes. */ - mem = - UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(upb_strview), void); + upb_strview *str = (upb_strview*)_upb_array_ptr(arr) + arr->len; arr->len++; - memcpy(mem, &val, sizeof(upb_strview)); - return ptr; + return decode_readstr(d, ptr, val.size, str); + } case OP_SUBMSG: { /* Append submessage / group. */ upb_msg *submsg = decode_newsubmsg(d, layout, field); @@ -357,26 +387,25 @@ static const char *decode_toarray(upb_decstate *d, const char *ptr, submsg; arr->len++; if (UPB_UNLIKELY(field->descriptortype == UPB_DTYPE_GROUP)) { - ptr = decode_togroup(d, ptr, submsg, layout, field); + return decode_togroup(d, ptr, submsg, layout, field); } else { - decode_tosubmsg(d, submsg, layout, field, val.str_val); + return decode_tosubmsg(d, ptr, submsg, layout, field, val.size); } - return ptr; } case OP_FIXPCK_LG2(2): case OP_FIXPCK_LG2(3): { /* Fixed packed. */ int lg2 = op - OP_FIXPCK_LG2(0); int mask = (1 << lg2) - 1; - size_t count = val.str_val.size >> lg2; - if ((val.str_val.size & mask) != 0) { + size_t count = val.size >> lg2; + if ((val.size & mask) != 0) { decode_err(d); /* Length isn't a round multiple of elem size. */ } decode_reserve(d, arr, count); mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); arr->len += count; - memcpy(mem, val.str_val.data, val.str_val.size); - return ptr; + memcpy(mem, ptr, val.size); /* XXX: ptr boundary. */ + return ptr + val.size; } case OP_VARPCK_LG2(0): case OP_VARPCK_LG2(2): @@ -384,12 +413,11 @@ static const char *decode_toarray(upb_decstate *d, const char *ptr, /* Varint packed. */ int lg2 = op - OP_VARPCK_LG2(0); int scale = 1 << lg2; - const char *ptr = val.str_val.data; - const char *end = ptr + val.str_val.size; + int saved_limit = decode_pushlimit(d, ptr, val.size); char *out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - while (ptr < end) { + while (!decode_isdone(d, &ptr)) { wireval elem; - ptr = decode_varint64(d, ptr, end, &elem.uint64_val); + ptr = decode_varint64(d, ptr, &elem.uint64_val); decode_munge(field->descriptortype, &elem); if (decode_reserve(d, arr, 1)) { out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); @@ -398,7 +426,7 @@ static const char *decode_toarray(upb_decstate *d, const char *ptr, memcpy(out, &elem, scale); out += scale; } - if (ptr != end) decode_err(d); + decode_poplimit(d, ptr, saved_limit); return ptr; } default: @@ -406,9 +434,9 @@ static const char *decode_toarray(upb_decstate *d, const char *ptr, } } -static void decode_tomap(upb_decstate *d, upb_msg *msg, - const upb_msglayout *layout, - const upb_msglayout_field *field, wireval val) { +static const char *decode_tomap(upb_decstate *d, const char *ptr, upb_msg *msg, + const upb_msglayout *layout, + const upb_msglayout_field *field, wireval val) { upb_map **map_p = UPB_PTR_AT(msg, field->offset, upb_map *); upb_map *map = *map_p; upb_map_entry ent; @@ -423,7 +451,7 @@ static void decode_tomap(upb_decstate *d, upb_msg *msg, char val_size = desctype_to_mapsize[val_field->descriptortype]; UPB_ASSERT(key_field->offset == 0); UPB_ASSERT(val_field->offset == sizeof(upb_strview)); - map = _upb_map_new(d->arena, key_size, val_size); + map = _upb_map_new(&d->arena, key_size, val_size); *map_p = map; } @@ -433,13 +461,12 @@ static void decode_tomap(upb_decstate *d, upb_msg *msg, if (entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_GROUP) { /* Create proactively to handle the case where it doesn't appear. */ - ent.v.val = upb_value_ptr(_upb_msg_new(entry->submsgs[0], d->arena)); + ent.v.val = upb_value_ptr(_upb_msg_new(entry->submsgs[0], &d->arena)); } - decode_tosubmsg(d, &ent.k, layout, field, val.str_val); - - /* Insert into map. */ - _upb_map_set(map, &ent.k, map->key_size, &ent.v, map->val_size, d->arena); + ptr = decode_tosubmsg(d, ptr, &ent.k, layout, field, val.size); + _upb_map_set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena); + return ptr; } static const char *decode_tomsg(upb_decstate *d, const char *ptr, upb_msg *msg, @@ -473,16 +500,15 @@ static const char *decode_tomsg(upb_decstate *d, const char *ptr, upb_msg *msg, if (UPB_UNLIKELY(type == UPB_DTYPE_GROUP)) { ptr = decode_togroup(d, ptr, submsg, layout, field); } else { - decode_tosubmsg(d, submsg, layout, field, val.str_val); + ptr = decode_tosubmsg(d, ptr, submsg, layout, field, val.size); } break; } case OP_STRING: - decode_verifyutf8(d, val.str_val.data, val.str_val.size); + decode_verifyutf8(d, ptr, val.size); /* Fallthrough. */ case OP_BYTES: - memcpy(mem, &val, sizeof(upb_strview)); - break; + return decode_readstr(d, ptr, val.size, mem); case OP_SCALAR_LG2(3): memcpy(mem, &val, 8); break; @@ -499,9 +525,24 @@ static const char *decode_tomsg(upb_decstate *d, const char *ptr, upb_msg *msg, return ptr; } +UPB_FORCEINLINE +static bool decode_tryfastdispatch(upb_decstate *d, const char **ptr, + upb_msg *msg, const upb_msglayout *layout) { +#if UPB_FASTTABLE + if (layout && layout->table_mask != (unsigned char)-1) { + uint16_t tag = fastdecode_loadtag(*ptr); + intptr_t table = decode_totable(layout); + *ptr = fastdecode_tagdispatch(d, *ptr, msg, table, 0, tag); + return true; + } +#endif + return false; +} + +UPB_NOINLINE static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, const upb_msglayout *layout) { - while (ptr < d->limit) { + while (true) { uint32_t tag; const upb_msglayout_field *field; int field_number; @@ -510,7 +551,8 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, wireval val; int op; - ptr = decode_varint32(d, ptr, d->limit, &tag); + UPB_ASSERT(ptr < d->limit_ptr); + ptr = decode_tag(d, ptr, &tag); field_number = tag >> 3; wire_type = tag & 7; @@ -518,12 +560,11 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, switch (wire_type) { case UPB_WIRE_TYPE_VARINT: - ptr = decode_varint64(d, ptr, d->limit, &val.uint64_val); + ptr = decode_varint64(d, ptr, &val.uint64_val); op = varint_ops[field->descriptortype]; decode_munge(field->descriptortype, &val); break; case UPB_WIRE_TYPE_32BIT: - if (d->limit - ptr < 4) decode_err(d); memcpy(&val.uint32_val, ptr, 4); val.uint32_val = _upb_be_swap32(val.uint32_val); ptr += 4; @@ -531,7 +572,6 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, if (((1 << field->descriptortype) & fixed32_ok) == 0) goto unknown; break; case UPB_WIRE_TYPE_64BIT: - if (d->limit - ptr < 8) decode_err(d); memcpy(&val.uint64_val, ptr, 8); val.uint64_val = _upb_be_swap64(val.uint64_val); ptr += 8; @@ -539,17 +579,16 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, if (((1 << field->descriptortype) & fixed64_ok) == 0) goto unknown; break; case UPB_WIRE_TYPE_DELIMITED: { - uint32_t size; int ndx = field->descriptortype; + uint64_t size; if (_upb_isrepeated(field)) ndx += 18; - ptr = decode_varint32(d, ptr, d->limit, &size); - if (size >= INT32_MAX || (size_t)(d->limit - ptr) < size) { + ptr = decode_varint64(d, ptr, &size); + if (size >= INT32_MAX || + ptr - d->end + (int32_t)size > d->limit) { decode_err(d); /* Length overflow. */ } - val.str_val.data = ptr; - val.str_val.size = size; - ptr += size; op = delim_ops[ndx]; + val.size = size; break; } case UPB_WIRE_TYPE_START_GROUP: @@ -572,7 +611,7 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, ptr = decode_toarray(d, ptr, msg, layout, field, val, op); break; case _UPB_LABEL_MAP: - decode_tomap(d, msg, layout, field, val); + ptr = decode_tomap(d, ptr, msg, layout, field, val); break; default: ptr = decode_tomsg(d, ptr, msg, layout, field, val, op); @@ -582,36 +621,78 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, unknown: /* Skip unknown field. */ if (field_number == 0) decode_err(d); - if (wire_type == UPB_WIRE_TYPE_START_GROUP) { - ptr = decode_group(d, ptr, NULL, NULL, field_number); - } + if (wire_type == UPB_WIRE_TYPE_DELIMITED) ptr += val.size; if (msg) { + if (wire_type == UPB_WIRE_TYPE_START_GROUP) { + d->unknown = field_start; + d->unknown_msg = msg; + ptr = decode_group(d, ptr, NULL, NULL, field_number); + d->unknown_msg = NULL; + field_start = d->unknown; + } if (!_upb_msg_addunknown(msg, field_start, ptr - field_start, - d->arena)) { + &d->arena)) { decode_err(d); } + } else if (wire_type == UPB_WIRE_TYPE_START_GROUP) { + ptr = decode_group(d, ptr, NULL, NULL, field_number); } } + + if (decode_isdone(d, &ptr)) return ptr; + if (decode_tryfastdispatch(d, &ptr, msg, layout)) return ptr; } +} - if (ptr != d->limit) decode_err(d); - return ptr; +const char *fastdecode_generic(struct upb_decstate *d, const char *ptr, + upb_msg *msg, intptr_t table, uint64_t hasbits, + uint64_t data) { + (void)data; + *(uint32_t*)msg |= hasbits; + return decode_msg(d, ptr, msg, decode_totablep(table)); } -bool upb_decode(const char *buf, size_t size, void *msg, const upb_msglayout *l, - upb_arena *arena) { +bool _upb_decode(const char *buf, size_t size, void *msg, + const upb_msglayout *l, upb_arena *arena, int options) { + bool ok; upb_decstate state; - state.limit = buf + size; - state.arena = arena; - state.depth = 64; - state.end_group = 0; + unsigned depth = (unsigned)options >> 16; + + if (size == 0) { + return true; + } else if (size <= 16) { + memset(&state.patch, 0, 32); + memcpy(&state.patch, buf, size); + buf = state.patch; + state.end = buf + size; + state.limit = 0; + state.alias = false; + } else { + state.end = buf + size - 16; + state.limit = 16; + state.alias = options & UPB_DECODE_ALIAS; + } - if (setjmp(state.err)) return false; + state.limit_ptr = state.end; + state.unknown_msg = NULL; + state.depth = depth ? depth : 64; + state.end_group = DECODE_NOGROUP; + state.arena.head = arena->head; + state.arena.last_size = arena->last_size; + state.arena.parent = arena; - if (size == 0) return true; - decode_msg(&state, buf, msg, l); + if (UPB_UNLIKELY(UPB_SETJMP(state.err))) { + ok = false; + } else { + if (!decode_tryfastdispatch(&state, &buf, msg, l)) { + decode_msg(&state, buf, msg, l); + } + ok = state.end_group == DECODE_NOGROUP; + } - return state.end_group == 0; + arena->head.ptr = state.arena.head.ptr; + arena->head.end = state.arena.head.end; + return ok; } #undef OP_SCALAR_LG2 diff --git a/contrib/libs/grpc/third_party/upb/upb/decode.h b/contrib/libs/grpc/third_party/upb/upb/decode.h index 9de8638de5..eff4b8bd3d 100644 --- a/contrib/libs/grpc/third_party/upb/upb/decode.h +++ b/contrib/libs/grpc/third_party/upb/upb/decode.h @@ -7,15 +7,34 @@ #include "upb/msg.h" +/* Must be last. */ +#include "upb/port_def.inc" + #ifdef __cplusplus extern "C" { #endif +enum { + /* If set, strings will alias the input buffer instead of copying into the + * arena. */ + UPB_DECODE_ALIAS = 1, +}; + +#define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16) + +bool _upb_decode(const char *buf, size_t size, upb_msg *msg, + const upb_msglayout *l, upb_arena *arena, int options); + +UPB_INLINE bool upb_decode(const char *buf, size_t size, upb_msg *msg, - const upb_msglayout *l, upb_arena *arena); + const upb_msglayout *l, upb_arena *arena) { + return _upb_decode(buf, size, msg, l, arena, 0); +} #ifdef __cplusplus } /* extern "C" */ #endif +#include "upb/port_undef.inc" + #endif /* UPB_DECODE_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/decode.int.h b/contrib/libs/grpc/third_party/upb/upb/decode.int.h new file mode 100644 index 0000000000..e286b9cdd5 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/decode.int.h @@ -0,0 +1,163 @@ +/* +** Internal implementation details of the decoder that are shared between +** decode.c and decode_fast.c. +*/ + +#ifndef UPB_DECODE_INT_H_ +#define UPB_DECODE_INT_H_ + +#include <setjmp.h> + +#include "upb/msg.h" +#include "upb/upb.int.h" + +/* Must be last. */ +#include "upb/port_def.inc" + +#define DECODE_NOGROUP -1 + +typedef struct upb_decstate { + const char *end; /* Can read up to 16 bytes slop beyond this. */ + const char *limit_ptr; /* = end + UPB_MIN(limit, 0) */ + upb_msg *unknown_msg; /* If non-NULL, add unknown data at buffer flip. */ + const char *unknown; /* Start of unknown data. */ + int limit; /* Submessage limit relative to end. */ + int depth; + uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */ + bool alias; + char patch[32]; + upb_arena arena; + jmp_buf err; +} upb_decstate; + +/* Error function that will abort decoding with longjmp(). We can't declare this + * UPB_NORETURN, even though it is appropriate, because if we do then compilers + * will "helpfully" refuse to tailcall to it + * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal + * of our optimizations. That is also why we must declare it in a separate file, + * otherwise the compiler will see that it calls longjmp() and deduce that it is + * noreturn. */ +const char *fastdecode_err(upb_decstate *d); + +extern const uint8_t upb_utf8_offsets[]; + +UPB_INLINE +bool decode_verifyutf8_inl(const char *buf, int len) { + int i, j; + uint8_t offset; + + i = 0; + while (i < len) { + offset = upb_utf8_offsets[(uint8_t)buf[i]]; + if (offset == 0 || i + offset > len) { + return false; + } + for (j = i + 1; j < i + offset; j++) { + if ((buf[j] & 0xc0) != 0x80) { + return false; + } + } + i += offset; + } + return i == len; +} + +/* x86-64 pointers always have the high 16 bits matching. So we can shift + * left 8 and right 8 without loss of information. */ +UPB_INLINE intptr_t decode_totable(const upb_msglayout *tablep) { + return ((intptr_t)tablep << 8) | tablep->table_mask; +} + +UPB_INLINE const upb_msglayout *decode_totablep(intptr_t table) { + return (const upb_msglayout*)(table >> 8); +} + +UPB_INLINE +const char *decode_isdonefallback_inl(upb_decstate *d, const char *ptr, + int overrun) { + if (overrun < d->limit) { + /* Need to copy remaining data into patch buffer. */ + UPB_ASSERT(overrun < 16); + if (d->unknown_msg) { + if (!_upb_msg_addunknown(d->unknown_msg, d->unknown, ptr - d->unknown, + &d->arena)) { + return NULL; + } + d->unknown = &d->patch[0] + overrun; + } + memset(d->patch + 16, 0, 16); + memcpy(d->patch, d->end, 16); + ptr = &d->patch[0] + overrun; + d->end = &d->patch[16]; + d->limit -= 16; + d->limit_ptr = d->end + d->limit; + d->alias = false; + UPB_ASSERT(ptr < d->limit_ptr); + return ptr; + } else { + return NULL; + } +} + +const char *decode_isdonefallback(upb_decstate *d, const char *ptr, + int overrun); + +UPB_INLINE +bool decode_isdone(upb_decstate *d, const char **ptr) { + int overrun = *ptr - d->end; + if (UPB_LIKELY(*ptr < d->limit_ptr)) { + return false; + } else if (UPB_LIKELY(overrun == d->limit)) { + return true; + } else { + *ptr = decode_isdonefallback(d, *ptr, overrun); + return false; + } +} + +UPB_INLINE +const char *fastdecode_tagdispatch(upb_decstate *d, const char *ptr, + upb_msg *msg, intptr_t table, + uint64_t hasbits, uint32_t tag) { + const upb_msglayout *table_p = decode_totablep(table); + uint8_t mask = table; + uint64_t data; + size_t idx = tag & mask; + UPB_ASSUME((idx & 7) == 0); + idx >>= 3; + data = table_p->fasttable[idx].field_data ^ tag; + return table_p->fasttable[idx].field_parser(d, ptr, msg, table, hasbits, data); +} + +UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) { + uint16_t tag; + memcpy(&tag, ptr, 2); + return tag; +} + +UPB_INLINE void decode_checklimit(upb_decstate *d) { + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); +} + +UPB_INLINE int decode_pushlimit(upb_decstate *d, const char *ptr, int size) { + int limit = size + (int)(ptr - d->end); + int delta = d->limit - limit; + decode_checklimit(d); + d->limit = limit; + d->limit_ptr = d->end + UPB_MIN(0, limit); + decode_checklimit(d); + return delta; +} + +UPB_INLINE void decode_poplimit(upb_decstate *d, const char *ptr, + int saved_delta) { + UPB_ASSERT(ptr - d->end == d->limit); + decode_checklimit(d); + d->limit += saved_delta; + d->limit_ptr = d->end + UPB_MIN(0, d->limit); + decode_checklimit(d); +} + +#include "upb/port_undef.inc" + +#endif /* UPB_DECODE_INT_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/decode_fast.c b/contrib/libs/grpc/third_party/upb/upb/decode_fast.c new file mode 100644 index 0000000000..f628e6dbd4 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/decode_fast.c @@ -0,0 +1,1040 @@ +// Fast decoder: ~3x the speed of decode.c, but x86-64 specific. +// Also the table size grows by 2x. +// +// Could potentially be ported to ARM64 or other 64-bit archs that pass at +// least six arguments in registers. +// +// The overall design is to create specialized functions for every possible +// field type (eg. oneof boolean field with a 1 byte tag) and then dispatch +// to the specialized function as quickly as possible. + +#include "upb/decode_fast.h" + +#include "upb/decode.int.h" + +/* Must be last. */ +#include "upb/port_def.inc" + +#if UPB_FASTTABLE + +// The standard set of arguments passed to each parsing function. +// Thanks to x86-64 calling conventions, these will stay in registers. +#define UPB_PARSE_PARAMS \ + upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data + +#define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data + +#define RETURN_GENERIC(m) \ + /* fprintf(stderr, m); */ \ + return fastdecode_generic(d, ptr, msg, table, hasbits, 0); + +typedef enum { + CARD_s = 0, /* Singular (optional, non-repeated) */ + CARD_o = 1, /* Oneof */ + CARD_r = 2, /* Repeated */ + CARD_p = 3 /* Packed Repeated */ +} upb_card; + +UPB_NOINLINE +static const char *fastdecode_isdonefallback(upb_decstate *d, const char *ptr, + upb_msg *msg, intptr_t table, + uint64_t hasbits, int overrun) { + ptr = decode_isdonefallback_inl(d, ptr, overrun); + if (ptr == NULL) { + return fastdecode_err(d); + } + uint16_t tag = fastdecode_loadtag(ptr); + return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, tag); +} + +UPB_FORCEINLINE +static const char *fastdecode_dispatch(upb_decstate *d, const char *ptr, + upb_msg *msg, intptr_t table, + uint64_t hasbits) { + if (UPB_UNLIKELY(ptr >= d->limit_ptr)) { + int overrun = ptr - d->end; + if (UPB_LIKELY(overrun == d->limit)) { + // Parse is finished. + *(uint32_t*)msg |= hasbits; // Sync hasbits. + return ptr; + } else { + return fastdecode_isdonefallback(d, ptr, msg, table, hasbits, overrun); + } + } + + // Read two bytes of tag data (for a one-byte tag, the high byte is junk). + uint16_t tag = fastdecode_loadtag(ptr); + return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, tag); +} + +UPB_FORCEINLINE +static bool fastdecode_checktag(uint64_t data, int tagbytes) { + if (tagbytes == 1) { + return (data & 0xff) == 0; + } else { + return (data & 0xffff) == 0; + } +} + +UPB_FORCEINLINE +static const char *fastdecode_longsize(const char *ptr, int *size) { + int i; + UPB_ASSERT(*size & 0x80); + *size &= 0xff; + for (i = 0; i < 3; i++) { + ptr++; + size_t byte = (uint8_t)ptr[-1]; + *size += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) return ptr; + } + ptr++; + size_t byte = (uint8_t)ptr[-1]; + // len is limited by 2gb not 4gb, hence 8 and not 16 as normally expected + // for a 32 bit varint. + if (UPB_UNLIKELY(byte >= 8)) return NULL; + *size += (byte - 1) << 28; + return ptr; +} + +UPB_FORCEINLINE +static bool fastdecode_boundscheck(const char *ptr, size_t len, + const char *end) { + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end + 16; + uintptr_t res = uptr + len; + return res < uptr || res > uend; +} + +UPB_FORCEINLINE +static bool fastdecode_boundscheck2(const char *ptr, size_t len, + const char *end) { + // This is one extra branch compared to the more normal: + // return (size_t)(end - ptr) < size; + // However it is one less computation if we are just about to use "ptr + len": + // https://godbolt.org/z/35YGPz + // In microbenchmarks this shows an overall 4% improvement. + uintptr_t uptr = (uintptr_t)ptr; + uintptr_t uend = (uintptr_t)end; + uintptr_t res = uptr + len; + return res < uptr || res > uend; +} + +typedef const char *fastdecode_delimfunc(upb_decstate *d, const char *ptr, + void *ctx); + +UPB_FORCEINLINE +static const char *fastdecode_delimited(upb_decstate *d, const char *ptr, + fastdecode_delimfunc *func, void *ctx) { + ptr++; + int len = (int8_t)ptr[-1]; + if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) { + // Slow case: Sub-message is >=128 bytes and/or exceeds the current buffer. + // If it exceeds the buffer limit, limit/limit_ptr will change during + // sub-message parsing, so we need to preserve delta, not limit. + if (UPB_UNLIKELY(len & 0x80)) { + // Size varint >1 byte (length >= 128). + ptr = fastdecode_longsize(ptr, &len); + if (!ptr) { + // Corrupt wire format: size exceeded INT_MAX. + return NULL; + } + } + if (ptr - d->end + (int)len > d->limit) { + // Corrupt wire format: invalid limit. + return NULL; + } + int delta = decode_pushlimit(d, ptr, len); + ptr = func(d, ptr, ctx); + decode_poplimit(d, ptr, delta); + } else { + // Fast case: Sub-message is <128 bytes and fits in the current buffer. + // This means we can preserve limit/limit_ptr verbatim. + const char *saved_limit_ptr = d->limit_ptr; + int saved_limit = d->limit; + d->limit_ptr = ptr + len; + d->limit = d->limit_ptr - d->end; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); + ptr = func(d, ptr, ctx); + d->limit_ptr = saved_limit_ptr; + d->limit = saved_limit; + UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit)); + } + return ptr; +} + +/* singular, oneof, repeated field handling ***********************************/ + +typedef struct { + upb_array *arr; + void *end; +} fastdecode_arr; + +typedef enum { + FD_NEXT_ATLIMIT, + FD_NEXT_SAMEFIELD, + FD_NEXT_OTHERFIELD +} fastdecode_next; + +typedef struct { + void *dst; + fastdecode_next next; + uint32_t tag; +} fastdecode_nextret; + +UPB_FORCEINLINE +static void *fastdecode_resizearr(upb_decstate *d, void *dst, + fastdecode_arr *farr, int valbytes) { + if (UPB_UNLIKELY(dst == farr->end)) { + size_t old_size = farr->arr->size; + size_t old_bytes = old_size * valbytes; + size_t new_size = old_size * 2; + size_t new_bytes = new_size * valbytes; + char *old_ptr = _upb_array_ptr(farr->arr); + char *new_ptr = upb_arena_realloc(&d->arena, old_ptr, old_bytes, new_bytes); + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + farr->arr->size = new_size; + farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2); + dst = (void*)(new_ptr + (old_size * valbytes)); + farr->end = (void*)(new_ptr + (new_size * valbytes)); + } + return dst; +} + +UPB_FORCEINLINE +static bool fastdecode_tagmatch(uint32_t tag, uint64_t data, int tagbytes) { + if (tagbytes == 1) { + return (uint8_t)tag == (uint8_t)data; + } else { + return (uint16_t)tag == (uint16_t)data; + } +} + +UPB_FORCEINLINE +static void fastdecode_commitarr(void *dst, fastdecode_arr *farr, + int valbytes) { + farr->arr->len = + (size_t)((char *)dst - (char *)_upb_array_ptr(farr->arr)) / valbytes; +} + +UPB_FORCEINLINE +static fastdecode_nextret fastdecode_nextrepeated(upb_decstate *d, void *dst, + const char **ptr, + fastdecode_arr *farr, + uint64_t data, int tagbytes, + int valbytes) { + fastdecode_nextret ret; + dst = (char *)dst + valbytes; + + if (UPB_LIKELY(!decode_isdone(d, ptr))) { + ret.tag = fastdecode_loadtag(*ptr); + if (fastdecode_tagmatch(ret.tag, data, tagbytes)) { + ret.next = FD_NEXT_SAMEFIELD; + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_OTHERFIELD; + } + } else { + fastdecode_commitarr(dst, farr, valbytes); + ret.next = FD_NEXT_ATLIMIT; + } + + ret.dst = dst; + return ret; +} + +UPB_FORCEINLINE +static void *fastdecode_fieldmem(upb_msg *msg, uint64_t data) { + size_t ofs = data >> 48; + return (char *)msg + ofs; +} + +UPB_FORCEINLINE +static void *fastdecode_getfield(upb_decstate *d, const char *ptr, upb_msg *msg, + uint64_t *data, uint64_t *hasbits, + fastdecode_arr *farr, int valbytes, + upb_card card) { + switch (card) { + case CARD_s: { + uint8_t hasbit_index = *data >> 24; + // Set hasbit and return pointer to scalar field. + *hasbits |= 1ull << hasbit_index; + return fastdecode_fieldmem(msg, *data); + } + case CARD_o: { + uint16_t case_ofs = *data >> 32; + uint32_t *oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t); + uint8_t field_number = *data >> 24; + *oneof_case = field_number; + return fastdecode_fieldmem(msg, *data); + } + case CARD_r: { + // Get pointer to upb_array and allocate/expand if necessary. + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + upb_array **arr_p = fastdecode_fieldmem(msg, *data); + char *begin; + *(uint32_t*)msg |= *hasbits; + *hasbits = 0; + if (UPB_LIKELY(!*arr_p)) { + farr->arr = _upb_array_new(&d->arena, 8, elem_size_lg2); + *arr_p = farr->arr; + } else { + farr->arr = *arr_p; + } + begin = _upb_array_ptr(farr->arr); + farr->end = begin + (farr->arr->size * valbytes); + *data = fastdecode_loadtag(ptr); + return begin + (farr->arr->len * valbytes); + } + default: + UPB_UNREACHABLE(); + } +} + +UPB_FORCEINLINE +static bool fastdecode_flippacked(uint64_t *data, int tagbytes) { + *data ^= (0x2 ^ 0x0); // Patch data to match packed wiretype. + return fastdecode_checktag(*data, tagbytes); +} + +/* varint fields **************************************************************/ + +UPB_FORCEINLINE +static uint64_t fastdecode_munge(uint64_t val, int valbytes, bool zigzag) { + if (valbytes == 1) { + return val != 0; + } else if (zigzag) { + if (valbytes == 4) { + uint32_t n = val; + return (n >> 1) ^ -(int32_t)(n & 1); + } else if (valbytes == 8) { + return (val >> 1) ^ -(int64_t)(val & 1); + } + UPB_UNREACHABLE(); + } + return val; +} + +UPB_FORCEINLINE +static const char *fastdecode_varint64(const char *ptr, uint64_t *val) { + ptr++; + *val = (uint8_t)ptr[-1]; + if (UPB_UNLIKELY(*val & 0x80)) { + int i; + for (i = 0; i < 8; i++) { + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + *val += (byte - 1) << (7 + 7 * i); + if (UPB_LIKELY((byte & 0x80) == 0)) goto done; + } + ptr++; + uint64_t byte = (uint8_t)ptr[-1]; + if (byte > 1) { + return NULL; + } + *val += (byte - 1) << 63; + } +done: + UPB_ASSUME(ptr != NULL); + return ptr; +} + +UPB_FORCEINLINE +static const char *fastdecode_unpackedvarint(UPB_PARSE_PARAMS, int tagbytes, + int valbytes, upb_card card, + bool zigzag, + _upb_field_parser *packed) { + uint64_t val; + void *dst; + fastdecode_arr farr; + + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { + if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { + return packed(UPB_PARSE_ARGS); + } + RETURN_GENERIC("varint field tag mismatch\n"); + } + + dst = + fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card); + if (card == CARD_r) { + if (UPB_UNLIKELY(!dst)) { + RETURN_GENERIC("need array resize\n"); + } + } + +again: + if (card == CARD_r) { + dst = fastdecode_resizearr(d, dst, &farr, valbytes); + } + + ptr += tagbytes; + ptr = fastdecode_varint64(ptr, &val); + if (ptr == NULL) return fastdecode_err(d); + val = fastdecode_munge(val, valbytes, zigzag); + memcpy(dst, &val, valbytes); + + if (card == CARD_r) { + fastdecode_nextret ret = + fastdecode_nextrepeated(d, dst, &ptr, &farr, data, tagbytes, valbytes); + switch (ret.next) { + case FD_NEXT_SAMEFIELD: + dst = ret.dst; + goto again; + case FD_NEXT_OTHERFIELD: + return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); + case FD_NEXT_ATLIMIT: + return ptr; + } + } + + return fastdecode_dispatch(d, ptr, msg, table, hasbits); +} + +typedef struct { + uint8_t valbytes; + bool zigzag; + void *dst; + fastdecode_arr farr; +} fastdecode_varintdata; + +UPB_FORCEINLINE +static const char *fastdecode_topackedvarint(upb_decstate *d, const char *ptr, + void *ctx) { + fastdecode_varintdata *data = ctx; + void *dst = data->dst; + uint64_t val; + + while (!decode_isdone(d, &ptr)) { + dst = fastdecode_resizearr(d, dst, &data->farr, data->valbytes); + ptr = fastdecode_varint64(ptr, &val); + if (ptr == NULL) return NULL; + val = fastdecode_munge(val, data->valbytes, data->zigzag); + memcpy(dst, &val, data->valbytes); + dst = (char *)dst + data->valbytes; + } + + fastdecode_commitarr(dst, &data->farr, data->valbytes); + return ptr; +} + +UPB_FORCEINLINE +static const char *fastdecode_packedvarint(UPB_PARSE_PARAMS, int tagbytes, + int valbytes, bool zigzag, + _upb_field_parser *unpacked) { + fastdecode_varintdata ctx = {valbytes, zigzag}; + + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { + if (fastdecode_flippacked(&data, tagbytes)) { + return unpacked(UPB_PARSE_ARGS); + } else { + RETURN_GENERIC("varint field tag mismatch\n"); + } + } + + ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr, + valbytes, CARD_r); + if (UPB_UNLIKELY(!ctx.dst)) { + RETURN_GENERIC("need array resize\n"); + } + + ptr += tagbytes; + ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx); + + if (UPB_UNLIKELY(ptr == NULL)) { + return fastdecode_err(d); + } + + return fastdecode_dispatch(d, ptr, msg, table, hasbits); +} + +UPB_FORCEINLINE +static const char *fastdecode_varint(UPB_PARSE_PARAMS, int tagbytes, + int valbytes, upb_card card, bool zigzag, + _upb_field_parser *unpacked, + _upb_field_parser *packed) { + if (card == CARD_p) { + return fastdecode_packedvarint(UPB_PARSE_ARGS, tagbytes, valbytes, zigzag, + unpacked); + } else { + return fastdecode_unpackedvarint(UPB_PARSE_ARGS, tagbytes, valbytes, card, + zigzag, packed); + } +} + +#define z_ZZ true +#define b_ZZ false +#define v_ZZ false + +/* Generate all combinations: + * {s,o,r,p} x {b1,v4,z4,v8,z8} x {1bt,2bt} */ + +#define F(card, type, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char *upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + return fastdecode_varint(UPB_PARSE_ARGS, tagbytes, valbytes, CARD_##card, \ + type##_ZZ, \ + &upb_pr##type##valbytes##_##tagbytes##bt, \ + &upb_pp##type##valbytes##_##tagbytes##bt); \ + } + +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef z_ZZ +#undef b_ZZ +#undef v_ZZ +#undef o_ONEOF +#undef s_ONEOF +#undef r_ONEOF +#undef F +#undef TYPES +#undef TAGBYTES + + +/* fixed fields ***************************************************************/ + +UPB_FORCEINLINE +static const char *fastdecode_unpackedfixed(UPB_PARSE_PARAMS, int tagbytes, + int valbytes, upb_card card, + _upb_field_parser *packed) { + void *dst; + fastdecode_arr farr; + + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { + if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { + return packed(UPB_PARSE_ARGS); + } + RETURN_GENERIC("fixed field tag mismatch\n"); + } + + dst = + fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes, card); + if (card == CARD_r) { + if (UPB_UNLIKELY(!dst)) { + RETURN_GENERIC("couldn't allocate array in arena\n"); + } + } + + +again: + if (card == CARD_r) { + dst = fastdecode_resizearr(d, dst, &farr, valbytes); + } + + ptr += tagbytes; + memcpy(dst, ptr, valbytes); + ptr += valbytes; + + if (card == CARD_r) { + fastdecode_nextret ret = + fastdecode_nextrepeated(d, dst, &ptr, &farr, data, tagbytes, valbytes); + switch (ret.next) { + case FD_NEXT_SAMEFIELD: + dst = ret.dst; + goto again; + case FD_NEXT_OTHERFIELD: + return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); + case FD_NEXT_ATLIMIT: + return ptr; + } + } + + return fastdecode_dispatch(d, ptr, msg, table, hasbits); +} + +UPB_FORCEINLINE +static const char *fastdecode_packedfixed(UPB_PARSE_PARAMS, int tagbytes, + int valbytes, + _upb_field_parser *unpacked) { + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { + if (fastdecode_flippacked(&data, tagbytes)) { + return unpacked(UPB_PARSE_ARGS); + } else { + RETURN_GENERIC("varint field tag mismatch\n"); + } + } + + ptr += tagbytes; + int size = (uint8_t)ptr[0]; + ptr++; + if (size & 0x80) { + ptr = fastdecode_longsize(ptr, &size); + } + + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr)) || + (size % valbytes) != 0) { + return fastdecode_err(d); + } + + upb_array **arr_p = fastdecode_fieldmem(msg, data); + upb_array *arr = *arr_p; + uint8_t elem_size_lg2 = __builtin_ctz(valbytes); + int elems = size / valbytes; + + if (UPB_LIKELY(!arr)) { + *arr_p = arr = _upb_array_new(&d->arena, elems, elem_size_lg2); + if (!arr) { + return fastdecode_err(d); + } + } else { + _upb_array_resize(arr, elems, &d->arena); + } + + char *dst = _upb_array_ptr(arr); + memcpy(dst, ptr, size); + arr->len = elems; + + return fastdecode_dispatch(d, ptr + size, msg, table, hasbits); +} + +UPB_FORCEINLINE +static const char *fastdecode_fixed(UPB_PARSE_PARAMS, int tagbytes, + int valbytes, upb_card card, + _upb_field_parser *unpacked, + _upb_field_parser *packed) { + if (card == CARD_p) { + return fastdecode_packedfixed(UPB_PARSE_ARGS, tagbytes, valbytes, unpacked); + } else { + return fastdecode_unpackedfixed(UPB_PARSE_ARGS, tagbytes, valbytes, card, + packed); + } +} + +/* Generate all combinations: + * {s,o,r,p} x {f4,f8} x {1bt,2bt} */ + +#define F(card, valbytes, tagbytes) \ + UPB_NOINLINE \ + const char *upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + return fastdecode_fixed(UPB_PARSE_ARGS, tagbytes, valbytes, CARD_##card, \ + &upb_ppf##valbytes##_##tagbytes##bt, \ + &upb_prf##valbytes##_##tagbytes##bt); \ + } + +#define TYPES(card, tagbytes) \ + F(card, 4, tagbytes) \ + F(card, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef F +#undef TYPES +#undef TAGBYTES + +/* string fields **************************************************************/ + +typedef const char *fastdecode_copystr_func(struct upb_decstate *d, + const char *ptr, upb_msg *msg, + const upb_msglayout *table, + uint64_t hasbits, upb_strview *dst); + +UPB_NOINLINE +static const char *fastdecode_verifyutf8(upb_decstate *d, const char *ptr, + upb_msg *msg, intptr_t table, + uint64_t hasbits, upb_strview *dst) { + if (!decode_verifyutf8_inl(dst->data, dst->size)) { + return fastdecode_err(d); + } + return fastdecode_dispatch(d, ptr, msg, table, hasbits); +} + +UPB_FORCEINLINE +static const char *fastdecode_longstring(struct upb_decstate *d, + const char *ptr, upb_msg *msg, + intptr_t table, uint64_t hasbits, + upb_strview *dst, + bool validate_utf8) { + int size = (uint8_t)ptr[0]; // Could plumb through hasbits. + ptr++; + if (size & 0x80) { + ptr = fastdecode_longsize(ptr, &size); + } + + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) { + dst->size = 0; + return fastdecode_err(d); + } + + if (d->alias) { + dst->data = ptr; + dst->size = size; + } else { + char *data = upb_arena_malloc(&d->arena, size); + if (!data) { + return fastdecode_err(d); + } + memcpy(data, ptr, size); + dst->data = data; + dst->size = size; + } + + if (validate_utf8) { + return fastdecode_verifyutf8(d, ptr + size, msg, table, hasbits, dst); + } else { + return fastdecode_dispatch(d, ptr + size, msg, table, hasbits); + } +} + +UPB_NOINLINE +static const char *fastdecode_longstring_utf8(struct upb_decstate *d, + const char *ptr, upb_msg *msg, + intptr_t table, uint64_t hasbits, + upb_strview *dst) { + return fastdecode_longstring(d, ptr, msg, table, hasbits, dst, true); +} + +UPB_NOINLINE +static const char *fastdecode_longstring_noutf8(struct upb_decstate *d, + const char *ptr, upb_msg *msg, + intptr_t table, + uint64_t hasbits, + upb_strview *dst) { + return fastdecode_longstring(d, ptr, msg, table, hasbits, dst, false); +} + +UPB_FORCEINLINE +static void fastdecode_docopy(upb_decstate *d, const char *ptr, uint32_t size, + int copy, char *data, upb_strview *dst) { + d->arena.head.ptr += copy; + dst->data = data; + UPB_UNPOISON_MEMORY_REGION(data, copy); + memcpy(data, ptr, copy); + UPB_POISON_MEMORY_REGION(data + size, copy - size); +} + +UPB_FORCEINLINE +static const char *fastdecode_copystring(UPB_PARSE_PARAMS, int tagbytes, + upb_card card, bool validate_utf8) { + upb_strview *dst; + fastdecode_arr farr; + int64_t size; + size_t arena_has; + size_t common_has; + char *buf; + + UPB_ASSERT(!d->alias); + UPB_ASSERT(fastdecode_checktag(data, tagbytes)); + + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, + sizeof(upb_strview), card); + +again: + if (card == CARD_r) { + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); + } + + size = (uint8_t)ptr[tagbytes]; + ptr += tagbytes + 1; + dst->size = size; + + buf = d->arena.head.ptr; + arena_has = _upb_arenahas(&d->arena); + common_has = UPB_MIN(arena_has, (d->end - ptr) + 16); + + if (UPB_LIKELY(size <= 15 - tagbytes)) { + if (arena_has < 16) goto longstr; + d->arena.head.ptr += 16; + memcpy(buf, ptr - tagbytes - 1, 16); + dst->data = buf + tagbytes + 1; + } else if (UPB_LIKELY(size <= 32)) { + if (UPB_UNLIKELY(common_has < 32)) goto longstr; + fastdecode_docopy(d, ptr, size, 32, buf, dst); + } else if (UPB_LIKELY(size <= 64)) { + if (UPB_UNLIKELY(common_has < 64)) goto longstr; + fastdecode_docopy(d, ptr, size, 64, buf, dst); + } else if (UPB_LIKELY(size < 128)) { + if (UPB_UNLIKELY(common_has < 128)) goto longstr; + fastdecode_docopy(d, ptr, size, 128, buf, dst); + } else { + goto longstr; + } + + ptr += size; + + if (card == CARD_r) { + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { + return fastdecode_err(d); + } + fastdecode_nextret ret = fastdecode_nextrepeated( + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); + switch (ret.next) { + case FD_NEXT_SAMEFIELD: + dst = ret.dst; + goto again; + case FD_NEXT_OTHERFIELD: + return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); + case FD_NEXT_ATLIMIT: + return ptr; + } + } + + if (card != CARD_r && validate_utf8) { + return fastdecode_verifyutf8(d, ptr, msg, table, hasbits, dst); + } + + return fastdecode_dispatch(d, ptr, msg, table, hasbits); + +longstr: + ptr--; + if (validate_utf8) { + return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, dst); + } else { + return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, dst); + } +} + +UPB_FORCEINLINE +static const char *fastdecode_string(UPB_PARSE_PARAMS, int tagbytes, + upb_card card, _upb_field_parser *copyfunc, + bool validate_utf8) { + upb_strview *dst; + fastdecode_arr farr; + int64_t size; + + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { + RETURN_GENERIC("string field tag mismatch\n"); + } + + if (UPB_UNLIKELY(!d->alias)) { + return copyfunc(UPB_PARSE_ARGS); + } + + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, + sizeof(upb_strview), card); + +again: + if (card == CARD_r) { + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview)); + } + + size = (int8_t)ptr[tagbytes]; + ptr += tagbytes + 1; + dst->data = ptr; + dst->size = size; + + if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->end))) { + ptr--; + if (validate_utf8) { + return fastdecode_longstring_utf8(d, ptr, msg, table, hasbits, dst); + } else { + return fastdecode_longstring_noutf8(d, ptr, msg, table, hasbits, dst); + } + } + + ptr += size; + + if (card == CARD_r) { + if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) { + return fastdecode_err(d); + } + fastdecode_nextret ret = fastdecode_nextrepeated( + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview)); + switch (ret.next) { + case FD_NEXT_SAMEFIELD: + dst = ret.dst; + if (UPB_UNLIKELY(!d->alias)) { + // Buffer flipped and we can't alias any more. Bounce to copyfunc(), + // but via dispatch since we need to reload table data also. + fastdecode_commitarr(dst, &farr, sizeof(upb_strview)); + return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); + } + goto again; + case FD_NEXT_OTHERFIELD: + return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); + case FD_NEXT_ATLIMIT: + return ptr; + } + } + + if (card != CARD_r && validate_utf8) { + return fastdecode_verifyutf8(d, ptr, msg, table, hasbits, dst); + } + + return fastdecode_dispatch(d, ptr, msg, table, hasbits); +} + +/* Generate all combinations: + * {p,c} x {s,o,r} x {s, b} x {1bt,2bt} */ + +#define s_VALIDATE true +#define b_VALIDATE false + +#define F(card, tagbytes, type) \ + UPB_NOINLINE \ + const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + return fastdecode_copystring(UPB_PARSE_ARGS, tagbytes, CARD_##card, \ + type##_VALIDATE); \ + } \ + const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) { \ + return fastdecode_string(UPB_PARSE_ARGS, tagbytes, CARD_##card, \ + &upb_c##card##type##_##tagbytes##bt, \ + type##_VALIDATE); \ + } + +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) + +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef s_VALIDATE +#undef b_VALIDATE +#undef F +#undef TAGBYTES + +/* message fields *************************************************************/ + +UPB_INLINE +upb_msg *decode_newmsg_ceil(upb_decstate *d, const upb_msglayout *l, + int msg_ceil_bytes) { + size_t size = l->size + sizeof(upb_msg_internal); + char *msg_data; + if (UPB_LIKELY(msg_ceil_bytes > 0 && + _upb_arenahas(&d->arena) >= msg_ceil_bytes)) { + UPB_ASSERT(size <= (size_t)msg_ceil_bytes); + msg_data = d->arena.head.ptr; + d->arena.head.ptr += size; + UPB_UNPOISON_MEMORY_REGION(msg_data, msg_ceil_bytes); + memset(msg_data, 0, msg_ceil_bytes); + UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size); + } else { + msg_data = (char*)upb_arena_malloc(&d->arena, size); + memset(msg_data, 0, size); + } + return msg_data + sizeof(upb_msg_internal); +} + +typedef struct { + intptr_t table; + upb_msg *msg; +} fastdecode_submsgdata; + +UPB_FORCEINLINE +static const char *fastdecode_tosubmsg(upb_decstate *d, const char *ptr, + void *ctx) { + fastdecode_submsgdata *submsg = ctx; + ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0); + UPB_ASSUME(ptr != NULL); + return ptr; +} + +UPB_FORCEINLINE +static const char *fastdecode_submsg(UPB_PARSE_PARAMS, int tagbytes, + int msg_ceil_bytes, upb_card card) { + + if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) { + RETURN_GENERIC("submessage field tag mismatch\n"); + } + + if (--d->depth == 0) return fastdecode_err(d); + + upb_msg **dst; + uint32_t submsg_idx = (data >> 16) & 0xff; + const upb_msglayout *tablep = decode_totablep(table); + const upb_msglayout *subtablep = tablep->submsgs[submsg_idx]; + fastdecode_submsgdata submsg = {decode_totable(subtablep)}; + fastdecode_arr farr; + + if (subtablep->table_mask == (uint8_t)-1) { + RETURN_GENERIC("submessage doesn't have fast tables."); + } + + dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, + sizeof(upb_msg *), card); + + if (card == CARD_s) { + *(uint32_t*)msg |= hasbits; + hasbits = 0; + } + +again: + if (card == CARD_r) { + dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_msg*)); + } + + submsg.msg = *dst; + + if (card == CARD_r || UPB_LIKELY(!submsg.msg)) { + *dst = submsg.msg = decode_newmsg_ceil(d, subtablep, msg_ceil_bytes); + } + + ptr += tagbytes; + ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg); + + if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) { + return fastdecode_err(d); + } + + if (card == CARD_r) { + fastdecode_nextret ret = fastdecode_nextrepeated( + d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_msg *)); + switch (ret.next) { + case FD_NEXT_SAMEFIELD: + dst = ret.dst; + goto again; + case FD_NEXT_OTHERFIELD: + d->depth++; + return fastdecode_tagdispatch(d, ptr, msg, table, hasbits, ret.tag); + case FD_NEXT_ATLIMIT: + d->depth++; + return ptr; + } + } + + d->depth++; + return fastdecode_dispatch(d, ptr, msg, table, hasbits); +} + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b( \ + UPB_PARSE_PARAMS) { \ + return fastdecode_submsg(UPB_PARSE_ARGS, tagbytes, ceil_arg, CARD_##card); \ + } + +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) + +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef TAGBYTES +#undef SIZES +#undef F + +#endif /* UPB_FASTTABLE */ diff --git a/contrib/libs/grpc/third_party/upb/upb/decode_fast.h b/contrib/libs/grpc/third_party/upb/upb/decode_fast.h new file mode 100644 index 0000000000..6d56d12477 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/decode_fast.h @@ -0,0 +1,126 @@ +// These are the specialized field parser functions for the fast parser. +// Generated tables will refer to these by name. +// +// The function names are encoded with names like: +// +// // 123 4 +// upb_pss_1bt(); // Parse singular string, 1 byte tag. +// +// In position 1: +// - 'p' for parse, most function use this +// - 'c' for copy, for when we are copying strings instead of aliasing +// +// In position 2 (cardinality): +// - 's' for singular, with or without hasbit +// - 'o' for oneof +// - 'r' for non-packed repeated +// - 'p' for packed repeated +// +// In position 3 (type): +// - 'b1' for bool +// - 'v4' for 4-byte varint +// - 'v8' for 8-byte varint +// - 'z4' for zig-zag-encoded 4-byte varint +// - 'z8' for zig-zag-encoded 8-byte varint +// - 'f4' for 4-byte fixed +// - 'f8' for 8-byte fixed +// - 'm' for sub-message +// - 's' for string (validate UTF-8) +// - 'b' for bytes +// +// In position 4 (tag length): +// - '1' for one-byte tags (field numbers 1-15) +// - '2' for two-byte tags (field numbers 16-2048) + +#ifndef UPB_DECODE_FAST_H_ +#define UPB_DECODE_FAST_H_ + +#include "upb/msg.h" + +struct upb_decstate; + +// The fallback, generic parsing function that can handle any field type. +// This just uses the regular (non-fast) parser to parse a single field. +const char *fastdecode_generic(struct upb_decstate *d, const char *ptr, + upb_msg *msg, intptr_t table, uint64_t hasbits, + uint64_t data); + +#define UPB_PARSE_PARAMS \ + struct upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, \ + uint64_t hasbits, uint64_t data + +/* primitive fields ***********************************************************/ + +#define F(card, type, valbytes, tagbytes) \ + const char *upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS); + +#define TYPES(card, tagbytes) \ + F(card, b, 1, tagbytes) \ + F(card, v, 4, tagbytes) \ + F(card, v, 8, tagbytes) \ + F(card, z, 4, tagbytes) \ + F(card, z, 8, tagbytes) \ + F(card, f, 4, tagbytes) \ + F(card, f, 8, tagbytes) + +#define TAGBYTES(card) \ + TYPES(card, 1) \ + TYPES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) +TAGBYTES(p) + +#undef F +#undef TYPES +#undef TAGBYTES + +/* string fields **************************************************************/ + +#define F(card, tagbytes, type) \ + const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); \ + const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); + +#define UTF8(card, tagbytes) \ + F(card, tagbytes, s) \ + F(card, tagbytes, b) + +#define TAGBYTES(card) \ + UTF8(card, 1) \ + UTF8(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef F +#undef TAGBYTES + +/* sub-message fields *********************************************************/ + +#define F(card, tagbytes, size_ceil, ceil_arg) \ + const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b(UPB_PARSE_PARAMS); + +#define SIZES(card, tagbytes) \ + F(card, tagbytes, 64, 64) \ + F(card, tagbytes, 128, 128) \ + F(card, tagbytes, 192, 192) \ + F(card, tagbytes, 256, 256) \ + F(card, tagbytes, max, -1) + +#define TAGBYTES(card) \ + SIZES(card, 1) \ + SIZES(card, 2) + +TAGBYTES(s) +TAGBYTES(o) +TAGBYTES(r) + +#undef TAGBYTES +#undef SIZES +#undef F + +#undef UPB_PARSE_PARAMS + +#endif /* UPB_DECODE_FAST_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/def.c b/contrib/libs/grpc/third_party/upb/upb/def.c new file mode 100644 index 0000000000..4ba553a69c --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/def.c @@ -0,0 +1,2178 @@ + +#include "upb/def.h" + +#include <ctype.h> +#include <errno.h> +#include <setjmp.h> +#include <stdlib.h> +#include <string.h> + +#include "google/protobuf/descriptor.upb.h" +#include "upb/port_def.inc" + +typedef struct { + size_t len; + char str[1]; /* Null-terminated string data follows. */ +} str_t; + +struct upb_fielddef { + const upb_filedef *file; + const upb_msgdef *msgdef; + const char *full_name; + const char *json_name; + union { + int64_t sint; + uint64_t uint; + double dbl; + float flt; + bool boolean; + str_t *str; + } defaultval; + const upb_oneofdef *oneof; + union { + const upb_msgdef *msgdef; + const upb_enumdef *enumdef; + const google_protobuf_FieldDescriptorProto *unresolved; + } sub; + uint32_t number_; + uint16_t index_; + uint16_t layout_index; + uint32_t selector_base; /* Used to index into a upb::Handlers table. */ + bool is_extension_; + bool lazy_; + bool packed_; + bool proto3_optional_; + upb_descriptortype_t type_; + upb_label_t label_; +}; + +struct upb_msgdef { + const upb_msglayout *layout; + const upb_filedef *file; + const char *full_name; + uint32_t selector_count; + uint32_t submsg_field_count; + + /* Tables for looking up fields by number and name. */ + upb_inttable itof; + upb_strtable ntof; + + const upb_fielddef *fields; + const upb_oneofdef *oneofs; + int field_count; + int oneof_count; + int real_oneof_count; + + /* Is this a map-entry message? */ + bool map_entry; + upb_wellknowntype_t well_known_type; + + /* TODO(haberman): proper extension ranges (there can be multiple). */ +}; + +struct upb_enumdef { + const upb_filedef *file; + const char *full_name; + upb_strtable ntoi; + upb_inttable iton; + int32_t defaultval; +}; + +struct upb_oneofdef { + const upb_msgdef *parent; + const char *full_name; + int field_count; + bool synthetic; + const upb_fielddef **fields; + upb_strtable ntof; + upb_inttable itof; +}; + +struct upb_filedef { + const char *name; + const char *package; + const char *phpprefix; + const char *phpnamespace; + + const upb_filedef **deps; + const upb_msgdef *msgs; + const upb_enumdef *enums; + const upb_fielddef *exts; + const upb_symtab *symtab; + + int dep_count; + int msg_count; + int enum_count; + int ext_count; + upb_syntax_t syntax; +}; + +struct upb_symtab { + upb_arena *arena; + upb_strtable syms; /* full_name -> packed def ptr */ + upb_strtable files; /* file_name -> upb_filedef* */ + size_t bytes_loaded; +}; + +/* Inside a symtab we store tagged pointers to specific def types. */ +typedef enum { + UPB_DEFTYPE_FIELD = 0, + + /* Only inside symtab table. */ + UPB_DEFTYPE_MSG = 1, + UPB_DEFTYPE_ENUM = 2, + + /* Only inside message table. */ + UPB_DEFTYPE_ONEOF = 1, + UPB_DEFTYPE_FIELD_JSONNAME = 2 +} upb_deftype_t; + +static const void *unpack_def(upb_value v, upb_deftype_t type) { + uintptr_t num = (uintptr_t)upb_value_getconstptr(v); + return (num & 3) == type ? (const void*)(num & ~3) : NULL; +} + +static upb_value pack_def(const void *ptr, upb_deftype_t type) { + uintptr_t num = (uintptr_t)ptr | type; + return upb_value_constptr((const void*)num); +} + +/* isalpha() etc. from <ctype.h> are locale-dependent, which we don't want. */ +static bool upb_isbetween(char c, char low, char high) { + return c >= low && c <= high; +} + +static bool upb_isletter(char c) { + return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_'; +} + +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} + +static const char *shortdefname(const char *fullname) { + const char *p; + + if (fullname == NULL) { + return NULL; + } else if ((p = strrchr(fullname, '.')) == NULL) { + /* No '.' in the name, return the full string. */ + return fullname; + } else { + /* Return one past the last '.'. */ + return p + 1; + } +} + +/* All submessage fields are lower than all other fields. + * Secondly, fields are increasing in order. */ +uint32_t field_rank(const upb_fielddef *f) { + uint32_t ret = upb_fielddef_number(f); + const uint32_t high_bit = 1 << 30; + UPB_ASSERT(ret < high_bit); + if (!upb_fielddef_issubmsg(f)) + ret |= high_bit; + return ret; +} + +int cmp_fields(const void *p1, const void *p2) { + const upb_fielddef *f1 = *(upb_fielddef*const*)p1; + const upb_fielddef *f2 = *(upb_fielddef*const*)p2; + return field_rank(f1) - field_rank(f2); +} + +/* A few implementation details of handlers. We put these here to avoid + * a def -> handlers dependency. */ + +#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/handlers.h. */ + +static uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { + return upb_fielddef_isseq(f) ? 2 : 0; +} + +static uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { + uint32_t ret = 1; + if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */ + if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */ + if (upb_fielddef_issubmsg(f)) { + /* ENDSUBMSG (STARTSUBMSG is at table beginning) */ + ret += 0; + if (upb_fielddef_lazy(f)) { + /* STARTSTR/ENDSTR/STRING (for lazy) */ + ret += 3; + } + } + return ret; +} + +static void upb_status_setoom(upb_status *status) { + upb_status_seterrmsg(status, "out of memory"); +} + +static void assign_msg_wellknowntype(upb_msgdef *m) { + const char *name = upb_msgdef_fullname(m); + if (name == NULL) { + m->well_known_type = UPB_WELLKNOWN_UNSPECIFIED; + return; + } + if (!strcmp(name, "google.protobuf.Any")) { + m->well_known_type = UPB_WELLKNOWN_ANY; + } else if (!strcmp(name, "google.protobuf.FieldMask")) { + m->well_known_type = UPB_WELLKNOWN_FIELDMASK; + } else if (!strcmp(name, "google.protobuf.Duration")) { + m->well_known_type = UPB_WELLKNOWN_DURATION; + } else if (!strcmp(name, "google.protobuf.Timestamp")) { + m->well_known_type = UPB_WELLKNOWN_TIMESTAMP; + } else if (!strcmp(name, "google.protobuf.DoubleValue")) { + m->well_known_type = UPB_WELLKNOWN_DOUBLEVALUE; + } else if (!strcmp(name, "google.protobuf.FloatValue")) { + m->well_known_type = UPB_WELLKNOWN_FLOATVALUE; + } else if (!strcmp(name, "google.protobuf.Int64Value")) { + m->well_known_type = UPB_WELLKNOWN_INT64VALUE; + } else if (!strcmp(name, "google.protobuf.UInt64Value")) { + m->well_known_type = UPB_WELLKNOWN_UINT64VALUE; + } else if (!strcmp(name, "google.protobuf.Int32Value")) { + m->well_known_type = UPB_WELLKNOWN_INT32VALUE; + } else if (!strcmp(name, "google.protobuf.UInt32Value")) { + m->well_known_type = UPB_WELLKNOWN_UINT32VALUE; + } else if (!strcmp(name, "google.protobuf.BoolValue")) { + m->well_known_type = UPB_WELLKNOWN_BOOLVALUE; + } else if (!strcmp(name, "google.protobuf.StringValue")) { + m->well_known_type = UPB_WELLKNOWN_STRINGVALUE; + } else if (!strcmp(name, "google.protobuf.BytesValue")) { + m->well_known_type = UPB_WELLKNOWN_BYTESVALUE; + } else if (!strcmp(name, "google.protobuf.Value")) { + m->well_known_type = UPB_WELLKNOWN_VALUE; + } else if (!strcmp(name, "google.protobuf.ListValue")) { + m->well_known_type = UPB_WELLKNOWN_LISTVALUE; + } else if (!strcmp(name, "google.protobuf.Struct")) { + m->well_known_type = UPB_WELLKNOWN_STRUCT; + } else { + m->well_known_type = UPB_WELLKNOWN_UNSPECIFIED; + } +} + + +/* upb_enumdef ****************************************************************/ + +const char *upb_enumdef_fullname(const upb_enumdef *e) { + return e->full_name; +} + +const char *upb_enumdef_name(const upb_enumdef *e) { + return shortdefname(e->full_name); +} + +const upb_filedef *upb_enumdef_file(const upb_enumdef *e) { + return e->file; +} + +int32_t upb_enumdef_default(const upb_enumdef *e) { + UPB_ASSERT(upb_enumdef_iton(e, e->defaultval)); + return e->defaultval; +} + +int upb_enumdef_numvals(const upb_enumdef *e) { + return (int)upb_strtable_count(&e->ntoi); +} + +void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) { + /* We iterate over the ntoi table, to account for duplicate numbers. */ + upb_strtable_begin(i, &e->ntoi); +} + +void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); } +bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); } + +bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name, + size_t len, int32_t *num) { + upb_value v; + if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) { + return false; + } + if (num) *num = upb_value_getint32(v); + return true; +} + +const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) { + upb_value v; + return upb_inttable_lookup32(&def->iton, num, &v) ? + upb_value_getcstr(v) : NULL; +} + +const char *upb_enum_iter_name(upb_enum_iter *iter) { + return upb_strtable_iter_key(iter).data; +} + +int32_t upb_enum_iter_number(upb_enum_iter *iter) { + return upb_value_getint32(upb_strtable_iter_value(iter)); +} + + +/* upb_fielddef ***************************************************************/ + +const char *upb_fielddef_fullname(const upb_fielddef *f) { + return f->full_name; +} + +upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) { + switch (f->type_) { + case UPB_DESCRIPTOR_TYPE_DOUBLE: + return UPB_TYPE_DOUBLE; + case UPB_DESCRIPTOR_TYPE_FLOAT: + return UPB_TYPE_FLOAT; + case UPB_DESCRIPTOR_TYPE_INT64: + case UPB_DESCRIPTOR_TYPE_SINT64: + case UPB_DESCRIPTOR_TYPE_SFIXED64: + return UPB_TYPE_INT64; + case UPB_DESCRIPTOR_TYPE_INT32: + case UPB_DESCRIPTOR_TYPE_SFIXED32: + case UPB_DESCRIPTOR_TYPE_SINT32: + return UPB_TYPE_INT32; + case UPB_DESCRIPTOR_TYPE_UINT64: + case UPB_DESCRIPTOR_TYPE_FIXED64: + return UPB_TYPE_UINT64; + case UPB_DESCRIPTOR_TYPE_UINT32: + case UPB_DESCRIPTOR_TYPE_FIXED32: + return UPB_TYPE_UINT32; + case UPB_DESCRIPTOR_TYPE_ENUM: + return UPB_TYPE_ENUM; + case UPB_DESCRIPTOR_TYPE_BOOL: + return UPB_TYPE_BOOL; + case UPB_DESCRIPTOR_TYPE_STRING: + return UPB_TYPE_STRING; + case UPB_DESCRIPTOR_TYPE_BYTES: + return UPB_TYPE_BYTES; + case UPB_DESCRIPTOR_TYPE_GROUP: + case UPB_DESCRIPTOR_TYPE_MESSAGE: + return UPB_TYPE_MESSAGE; + } + UPB_UNREACHABLE(); +} + +upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) { + return f->type_; +} + +uint32_t upb_fielddef_index(const upb_fielddef *f) { + return f->index_; +} + +upb_label_t upb_fielddef_label(const upb_fielddef *f) { + return f->label_; +} + +uint32_t upb_fielddef_number(const upb_fielddef *f) { + return f->number_; +} + +bool upb_fielddef_isextension(const upb_fielddef *f) { + return f->is_extension_; +} + +bool upb_fielddef_lazy(const upb_fielddef *f) { + return f->lazy_; +} + +bool upb_fielddef_packed(const upb_fielddef *f) { + return f->packed_; +} + +const char *upb_fielddef_name(const upb_fielddef *f) { + return shortdefname(f->full_name); +} + +const char *upb_fielddef_jsonname(const upb_fielddef *f) { + return f->json_name; +} + +uint32_t upb_fielddef_selectorbase(const upb_fielddef *f) { + return f->selector_base; +} + +const upb_filedef *upb_fielddef_file(const upb_fielddef *f) { + return f->file; +} + +const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) { + return f->msgdef; +} + +const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) { + return f->oneof; +} + +const upb_oneofdef *upb_fielddef_realcontainingoneof(const upb_fielddef *f) { + if (!f->oneof || upb_oneofdef_issynthetic(f->oneof)) return NULL; + return f->oneof; +} + +static void chkdefaulttype(const upb_fielddef *f, int ctype) { + UPB_UNUSED(f); + UPB_UNUSED(ctype); +} + +int64_t upb_fielddef_defaultint64(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_INT64); + return f->defaultval.sint; +} + +int32_t upb_fielddef_defaultint32(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_INT32); + return (int32_t)f->defaultval.sint; +} + +uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_UINT64); + return f->defaultval.uint; +} + +uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_UINT32); + return (uint32_t)f->defaultval.uint; +} + +bool upb_fielddef_defaultbool(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_BOOL); + return f->defaultval.boolean; +} + +float upb_fielddef_defaultfloat(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_FLOAT); + return f->defaultval.flt; +} + +double upb_fielddef_defaultdouble(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_DOUBLE); + return f->defaultval.dbl; +} + +const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) { + str_t *str = f->defaultval.str; + UPB_ASSERT(upb_fielddef_type(f) == UPB_TYPE_STRING || + upb_fielddef_type(f) == UPB_TYPE_BYTES || + upb_fielddef_type(f) == UPB_TYPE_ENUM); + if (str) { + if (len) *len = str->len; + return str->str; + } else { + if (len) *len = 0; + return NULL; + } +} + +const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) { + return upb_fielddef_type(f) == UPB_TYPE_MESSAGE ? f->sub.msgdef : NULL; +} + +const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) { + return upb_fielddef_type(f) == UPB_TYPE_ENUM ? f->sub.enumdef : NULL; +} + +const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f) { + return &f->msgdef->layout->fields[f->layout_index]; +} + +bool upb_fielddef_issubmsg(const upb_fielddef *f) { + return upb_fielddef_type(f) == UPB_TYPE_MESSAGE; +} + +bool upb_fielddef_isstring(const upb_fielddef *f) { + return upb_fielddef_type(f) == UPB_TYPE_STRING || + upb_fielddef_type(f) == UPB_TYPE_BYTES; +} + +bool upb_fielddef_isseq(const upb_fielddef *f) { + return upb_fielddef_label(f) == UPB_LABEL_REPEATED; +} + +bool upb_fielddef_isprimitive(const upb_fielddef *f) { + return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f); +} + +bool upb_fielddef_ismap(const upb_fielddef *f) { + return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) && + upb_msgdef_mapentry(upb_fielddef_msgsubdef(f)); +} + +bool upb_fielddef_hassubdef(const upb_fielddef *f) { + return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM; +} + +bool upb_fielddef_haspresence(const upb_fielddef *f) { + if (upb_fielddef_isseq(f)) return false; + return upb_fielddef_issubmsg(f) || upb_fielddef_containingoneof(f) || + f->file->syntax == UPB_SYNTAX_PROTO2; +} + +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; +} + +bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); } +bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); } +bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } + +bool upb_fielddef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); +} + +/* upb_msgdef *****************************************************************/ + +const char *upb_msgdef_fullname(const upb_msgdef *m) { + return m->full_name; +} + +const upb_filedef *upb_msgdef_file(const upb_msgdef *m) { + return m->file; +} + +const char *upb_msgdef_name(const upb_msgdef *m) { + return shortdefname(m->full_name); +} + +upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) { + return m->file->syntax; +} + +size_t upb_msgdef_selectorcount(const upb_msgdef *m) { + return m->selector_count; +} + +uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m) { + return m->submsg_field_count; +} + +const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) { + upb_value val; + return upb_inttable_lookup32(&m->itof, i, &val) ? + upb_value_getconstptr(val) : NULL; +} + +const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, + size_t len) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return NULL; + } + + return unpack_def(val, UPB_DEFTYPE_FIELD); +} + +const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, + size_t len) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return NULL; + } + + return unpack_def(val, UPB_DEFTYPE_ONEOF); +} + +bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len, + const upb_fielddef **f, const upb_oneofdef **o) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; + } + + *o = unpack_def(val, UPB_DEFTYPE_ONEOF); + *f = unpack_def(val, UPB_DEFTYPE_FIELD); + return *o || *f; /* False if this was a JSON name. */ +} + +const upb_fielddef *upb_msgdef_lookupjsonname(const upb_msgdef *m, + const char *name, size_t len) { + upb_value val; + const upb_fielddef* f; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return NULL; + } + + f = unpack_def(val, UPB_DEFTYPE_FIELD); + if (!f) f = unpack_def(val, UPB_DEFTYPE_FIELD_JSONNAME); + + return f; +} + +int upb_msgdef_numfields(const upb_msgdef *m) { + return m->field_count; +} + +int upb_msgdef_numoneofs(const upb_msgdef *m) { + return m->oneof_count; +} + +int upb_msgdef_numrealoneofs(const upb_msgdef *m) { + return m->real_oneof_count; +} + +int upb_msgdef_fieldcount(const upb_msgdef *m) { + return m->field_count; +} + +int upb_msgdef_oneofcount(const upb_msgdef *m) { + return m->oneof_count; +} + +int upb_msgdef_realoneofcount(const upb_msgdef *m) { + return m->real_oneof_count; +} + +const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m) { + return m->layout; +} + +const upb_fielddef *upb_msgdef_field(const upb_msgdef *m, int i) { + UPB_ASSERT(i >= 0 && i < m->field_count); + return &m->fields[i]; +} + +const upb_oneofdef *upb_msgdef_oneof(const upb_msgdef *m, int i) { + UPB_ASSERT(i >= 0 && i < m->oneof_count); + return &m->oneofs[i]; +} + +bool upb_msgdef_mapentry(const upb_msgdef *m) { + return m->map_entry; +} + +upb_wellknowntype_t upb_msgdef_wellknowntype(const upb_msgdef *m) { + return m->well_known_type; +} + +bool upb_msgdef_isnumberwrapper(const upb_msgdef *m) { + upb_wellknowntype_t type = upb_msgdef_wellknowntype(m); + return type >= UPB_WELLKNOWN_DOUBLEVALUE && + type <= UPB_WELLKNOWN_UINT32VALUE; +} + +bool upb_msgdef_iswrapper(const upb_msgdef *m) { + upb_wellknowntype_t type = upb_msgdef_wellknowntype(m); + return type >= UPB_WELLKNOWN_DOUBLEVALUE && + type <= UPB_WELLKNOWN_BOOLVALUE; +} + +void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) { + upb_inttable_begin(iter, &m->itof); +} + +void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); } + +bool upb_msg_field_done(const upb_msg_field_iter *iter) { + return upb_inttable_done(iter); +} + +upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) { + return (upb_fielddef *)upb_value_getconstptr(upb_inttable_iter_value(iter)); +} + +void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) { + upb_inttable_iter_setdone(iter); +} + +bool upb_msg_field_iter_isequal(const upb_msg_field_iter * iter1, + const upb_msg_field_iter * iter2) { + return upb_inttable_iter_isequal(iter1, iter2); +} + +void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) { + upb_strtable_begin(iter, &m->ntof); + /* We need to skip past any initial fields. */ + while (!upb_strtable_done(iter) && + !unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF)) { + upb_strtable_next(iter); + } +} + +void upb_msg_oneof_next(upb_msg_oneof_iter *iter) { + /* We need to skip past fields to return only oneofs. */ + do { + upb_strtable_next(iter); + } while (!upb_strtable_done(iter) && + !unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF)); +} + +bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) { + return upb_strtable_done(iter); +} + +const upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) { + return unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF); +} + +void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) { + upb_strtable_iter_setdone(iter); +} + +bool upb_msg_oneof_iter_isequal(const upb_msg_oneof_iter *iter1, + const upb_msg_oneof_iter *iter2) { + return upb_strtable_iter_isequal(iter1, iter2); +} + +/* upb_oneofdef ***************************************************************/ + +const char *upb_oneofdef_name(const upb_oneofdef *o) { + return shortdefname(o->full_name); +} + +const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) { + return o->parent; +} + +int upb_oneofdef_fieldcount(const upb_oneofdef *o) { + return o->field_count; +} + +const upb_fielddef *upb_oneofdef_field(const upb_oneofdef *o, int i) { + UPB_ASSERT(i < o->field_count); + return o->fields[i]; +} + +int upb_oneofdef_numfields(const upb_oneofdef *o) { + return o->field_count; +} + +uint32_t upb_oneofdef_index(const upb_oneofdef *o) { + return o - o->parent->oneofs; +} + +bool upb_oneofdef_issynthetic(const upb_oneofdef *o) { + return o->synthetic; +} + +const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, + const char *name, size_t length) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, length, &val) ? + upb_value_getptr(val) : NULL; +} + +const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) { + upb_value val; + return upb_inttable_lookup32(&o->itof, num, &val) ? + upb_value_getptr(val) : NULL; +} + +void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) { + upb_inttable_begin(iter, &o->itof); +} + +void upb_oneof_next(upb_oneof_iter *iter) { + upb_inttable_next(iter); +} + +bool upb_oneof_done(upb_oneof_iter *iter) { + return upb_inttable_done(iter); +} + +upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) { + return (upb_fielddef *)upb_value_getconstptr(upb_inttable_iter_value(iter)); +} + +void upb_oneof_iter_setdone(upb_oneof_iter *iter) { + upb_inttable_iter_setdone(iter); +} + +/* upb_filedef ****************************************************************/ + +const char *upb_filedef_name(const upb_filedef *f) { + return f->name; +} + +const char *upb_filedef_package(const upb_filedef *f) { + return f->package; +} + +const char *upb_filedef_phpprefix(const upb_filedef *f) { + return f->phpprefix; +} + +const char *upb_filedef_phpnamespace(const upb_filedef *f) { + return f->phpnamespace; +} + +upb_syntax_t upb_filedef_syntax(const upb_filedef *f) { + return f->syntax; +} + +int upb_filedef_msgcount(const upb_filedef *f) { + return f->msg_count; +} + +int upb_filedef_depcount(const upb_filedef *f) { + return f->dep_count; +} + +int upb_filedef_enumcount(const upb_filedef *f) { + return f->enum_count; +} + +const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i) { + return i < 0 || i >= f->dep_count ? NULL : f->deps[i]; +} + +const upb_msgdef *upb_filedef_msg(const upb_filedef *f, int i) { + return i < 0 || i >= f->msg_count ? NULL : &f->msgs[i]; +} + +const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i) { + return i < 0 || i >= f->enum_count ? NULL : &f->enums[i]; +} + +const upb_symtab *upb_filedef_symtab(const upb_filedef *f) { + return f->symtab; +} + +void upb_symtab_free(upb_symtab *s) { + upb_arena_free(s->arena); + upb_gfree(s); +} + +upb_symtab *upb_symtab_new(void) { + upb_symtab *s = upb_gmalloc(sizeof(*s)); + upb_alloc *alloc; + + if (!s) { + return NULL; + } + + s->arena = upb_arena_new(); + s->bytes_loaded = 0; + alloc = upb_arena_alloc(s->arena); + + if (!upb_strtable_init2(&s->syms, UPB_CTYPE_CONSTPTR, 32, alloc) || + !upb_strtable_init2(&s->files, UPB_CTYPE_CONSTPTR, 4, alloc)) { + upb_arena_free(s->arena); + upb_gfree(s); + s = NULL; + } + return s; +} + +const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) { + upb_value v; + return upb_strtable_lookup(&s->syms, sym, &v) ? + unpack_def(v, UPB_DEFTYPE_MSG) : NULL; +} + +const upb_msgdef *upb_symtab_lookupmsg2(const upb_symtab *s, const char *sym, + size_t len) { + upb_value v; + return upb_strtable_lookup2(&s->syms, sym, len, &v) ? + unpack_def(v, UPB_DEFTYPE_MSG) : NULL; +} + +const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) { + upb_value v; + return upb_strtable_lookup(&s->syms, sym, &v) ? + unpack_def(v, UPB_DEFTYPE_ENUM) : NULL; +} + +const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name) { + upb_value v; + return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) + : NULL; +} + +const upb_filedef *upb_symtab_lookupfile2( + const upb_symtab *s, const char *name, size_t len) { + upb_value v; + return upb_strtable_lookup2(&s->files, name, len, &v) ? + upb_value_getconstptr(v) : NULL; +} + +int upb_symtab_filecount(const upb_symtab *s) { + return (int)upb_strtable_count(&s->files); +} + +/* Code to build defs from descriptor protos. *********************************/ + +/* There is a question of how much validation to do here. It will be difficult + * to perfectly match the amount of validation performed by proto2. But since + * this code is used to directly build defs from Ruby (for example) we do need + * to validate important constraints like uniqueness of names and numbers. */ + +#define CHK_OOM(x) if (!(x)) { symtab_oomerr(ctx); } + +typedef struct { + upb_symtab *symtab; + upb_filedef *file; /* File we are building. */ + upb_arena *file_arena; /* Allocate defs here. */ + upb_alloc *alloc; /* Alloc of file_arena, for tables. */ + const upb_msglayout **layouts; /* NULL if we should build layouts. */ + upb_status *status; /* Record errors here. */ + jmp_buf err; /* longjmp() on error. */ +} symtab_addctx; + +UPB_NORETURN UPB_NOINLINE +static void symtab_errf(symtab_addctx *ctx, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_status_vseterrf(ctx->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(ctx->err, 1); +} + +UPB_NORETURN UPB_NOINLINE +static void symtab_oomerr(symtab_addctx *ctx) { + upb_status_setoom(ctx->status); + UPB_LONGJMP(ctx->err, 1); +} + +void *symtab_alloc(symtab_addctx *ctx, size_t bytes) { + void *ret = upb_arena_malloc(ctx->file_arena, bytes); + if (!ret) symtab_oomerr(ctx); + return ret; +} + +static void check_ident(symtab_addctx *ctx, upb_strview name, bool full) { + const char *str = name.data; + size_t len = name.size; + bool start = true; + size_t i; + for (i = 0; i < len; i++) { + char c = str[i]; + if (c == '.') { + if (start || !full) { + symtab_errf(ctx, "invalid name: unexpected '.' (%.*s)", (int)len, str); + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + symtab_errf( + ctx, + "invalid name: path components must start with a letter (%.*s)", + (int)len, str); + } + start = false; + } else { + if (!upb_isalphanum(c)) { + symtab_errf(ctx, "invalid name: non-alphanumeric character (%.*s)", + (int)len, str); + } + } + } + if (start) { + symtab_errf(ctx, "invalid name: empty part (%.*s)", (int)len, str); + } +} + +static size_t div_round_up(size_t n, size_t d) { + return (n + d - 1) / d; +} + +static size_t upb_msgval_sizeof(upb_fieldtype_t type) { + switch (type) { + case UPB_TYPE_DOUBLE: + case UPB_TYPE_INT64: + case UPB_TYPE_UINT64: + return 8; + case UPB_TYPE_ENUM: + case UPB_TYPE_INT32: + case UPB_TYPE_UINT32: + case UPB_TYPE_FLOAT: + return 4; + case UPB_TYPE_BOOL: + return 1; + case UPB_TYPE_MESSAGE: + return sizeof(void*); + case UPB_TYPE_BYTES: + case UPB_TYPE_STRING: + return sizeof(upb_strview); + } + UPB_UNREACHABLE(); +} + +static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { + if (upb_msgdef_mapentry(upb_fielddef_containingtype(f))) { + upb_map_entry ent; + UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); + return sizeof(ent.k); + } else if (upb_fielddef_isseq(f)) { + return sizeof(void*); + } else { + return upb_msgval_sizeof(upb_fielddef_type(f)); + } +} + +static uint32_t upb_msglayout_place(upb_msglayout *l, size_t size) { + uint32_t ret; + + l->size = UPB_ALIGN_UP(l->size, size); + ret = l->size; + l->size += size; + return ret; +} + +static int field_number_cmp(const void *p1, const void *p2) { + const upb_msglayout_field *f1 = p1; + const upb_msglayout_field *f2 = p2; + return f1->number - f2->number; +} + +static void assign_layout_indices(const upb_msgdef *m, upb_msglayout_field *fields) { + int i; + int n = upb_msgdef_numfields(m); + for (i = 0; i < n; i++) { + upb_fielddef *f = (upb_fielddef*)upb_msgdef_itof(m, fields[i].number); + UPB_ASSERT(f); + f->layout_index = i; + } +} + +/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. + * It computes a dynamic layout for all of the fields in |m|. */ +static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { + upb_msglayout *l = (upb_msglayout*)m->layout; + upb_msg_field_iter it; + upb_msg_oneof_iter oit; + size_t hasbit; + size_t submsg_count = m->submsg_field_count; + const upb_msglayout **submsgs; + upb_msglayout_field *fields; + + memset(l, 0, sizeof(*l) + sizeof(_upb_fasttable_entry)); + + fields = symtab_alloc(ctx, upb_msgdef_numfields(m) * sizeof(*fields)); + submsgs = symtab_alloc(ctx, submsg_count * sizeof(*submsgs)); + + l->field_count = upb_msgdef_numfields(m); + l->fields = fields; + l->submsgs = submsgs; + l->table_mask = 0; + + /* TODO(haberman): initialize fast tables so that reflection-based parsing + * can get the same speeds as linked-in types. */ + l->fasttable[0].field_parser = &fastdecode_generic; + l->fasttable[0].field_data = 0; + + if (upb_msgdef_mapentry(m)) { + /* TODO(haberman): refactor this method so this special case is more + * elegant. */ + const upb_fielddef *key = upb_msgdef_itof(m, 1); + const upb_fielddef *val = upb_msgdef_itof(m, 2); + fields[0].number = 1; + fields[1].number = 2; + fields[0].label = UPB_LABEL_OPTIONAL; + fields[1].label = UPB_LABEL_OPTIONAL; + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].descriptortype = upb_fielddef_descriptortype(key); + fields[1].descriptortype = upb_fielddef_descriptortype(val); + fields[0].offset = 0; + fields[1].offset = sizeof(upb_strview); + fields[1].submsg_index = 0; + + if (upb_fielddef_type(val) == UPB_TYPE_MESSAGE) { + submsgs[0] = upb_fielddef_msgsubdef(val)->layout; + } + + l->field_count = 2; + l->size = 2 * sizeof(upb_strview); + l->size = UPB_ALIGN_UP(l->size, 8); + return; + } + + /* Allocate data offsets in three stages: + * + * 1. hasbits. + * 2. regular fields. + * 3. oneof fields. + * + * OPT: There is a lot of room for optimization here to minimize the size. + */ + + /* Allocate hasbits and set basic field attributes. */ + submsg_count = 0; + for (upb_msg_field_begin(&it, m), hasbit = 0; + !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + upb_fielddef* f = upb_msg_iter_field(&it); + upb_msglayout_field *field = &fields[upb_fielddef_index(f)]; + + field->number = upb_fielddef_number(f); + field->descriptortype = upb_fielddef_descriptortype(f); + field->label = upb_fielddef_label(f); + + if (field->descriptortype == UPB_DTYPE_STRING && + f->file->syntax == UPB_SYNTAX_PROTO2) { + /* See TableDescriptorType() in upbc/generator.cc for details and + * rationale. */ + field->descriptortype = UPB_DTYPE_BYTES; + } + + if (upb_fielddef_ismap(f)) { + field->label = _UPB_LABEL_MAP; + } else if (upb_fielddef_packed(f)) { + field->label = _UPB_LABEL_PACKED; + } + + if (upb_fielddef_issubmsg(f)) { + const upb_msgdef *subm = upb_fielddef_msgsubdef(f); + field->submsg_index = submsg_count++; + submsgs[field->submsg_index] = subm->layout; + } + + if (upb_fielddef_haspresence(f) && !upb_fielddef_realcontainingoneof(f)) { + /* We don't use hasbit 0, so that 0 can indicate "no presence" in the + * table. This wastes one hasbit, but we don't worry about it for now. */ + field->presence = ++hasbit; + } else { + field->presence = 0; + } + } + + /* Account for space used by hasbits. */ + l->size = div_round_up(hasbit, 8); + + /* Allocate non-oneof fields. */ + for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + const upb_fielddef* f = upb_msg_iter_field(&it); + size_t field_size = upb_msg_fielddefsize(f); + size_t index = upb_fielddef_index(f); + + if (upb_fielddef_realcontainingoneof(f)) { + /* Oneofs are handled separately below. */ + continue; + } + + fields[index].offset = upb_msglayout_place(l, field_size); + } + + /* Allocate oneof fields. Each oneof field consists of a uint32 for the case + * and space for the actual data. */ + for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit); + upb_msg_oneof_next(&oit)) { + const upb_oneofdef* o = upb_msg_iter_oneof(&oit); + upb_oneof_iter fit; + + size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ + size_t field_size = 0; + uint32_t case_offset; + uint32_t data_offset; + + if (upb_oneofdef_issynthetic(o)) continue; + + /* Calculate field size: the max of all field sizes. */ + for (upb_oneof_begin(&fit, o); + !upb_oneof_done(&fit); + upb_oneof_next(&fit)) { + const upb_fielddef* f = upb_oneof_iter_field(&fit); + field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); + } + + /* Align and allocate case offset. */ + case_offset = upb_msglayout_place(l, case_size); + data_offset = upb_msglayout_place(l, field_size); + + for (upb_oneof_begin(&fit, o); + !upb_oneof_done(&fit); + upb_oneof_next(&fit)) { + const upb_fielddef* f = upb_oneof_iter_field(&fit); + fields[upb_fielddef_index(f)].offset = data_offset; + fields[upb_fielddef_index(f)].presence = ~case_offset; + } + } + + /* Size of the entire structure should be a multiple of its greatest + * alignment. TODO: track overall alignment for real? */ + l->size = UPB_ALIGN_UP(l->size, 8); + + /* Sort fields by number. */ + qsort(fields, upb_msgdef_numfields(m), sizeof(*fields), field_number_cmp); + assign_layout_indices(m, fields); +} + +static void assign_msg_indices(symtab_addctx *ctx, upb_msgdef *m) { + /* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the + * lowest indexes, but we do not publicly guarantee this. */ + upb_msg_field_iter j; + int i; + uint32_t selector; + int n = upb_msgdef_numfields(m); + upb_fielddef **fields; + + if (n == 0) { + m->selector_count = UPB_STATIC_SELECTOR_COUNT; + m->submsg_field_count = 0; + return; + } + + fields = upb_gmalloc(n * sizeof(*fields)); + + m->submsg_field_count = 0; + for(i = 0, upb_msg_field_begin(&j, m); + !upb_msg_field_done(&j); + upb_msg_field_next(&j), i++) { + upb_fielddef *f = upb_msg_iter_field(&j); + UPB_ASSERT(f->msgdef == m); + if (upb_fielddef_issubmsg(f)) { + m->submsg_field_count++; + } + fields[i] = f; + } + + qsort(fields, n, sizeof(*fields), cmp_fields); + + selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count; + for (i = 0; i < n; i++) { + upb_fielddef *f = fields[i]; + f->index_ = i; + f->selector_base = selector + upb_handlers_selectorbaseoffset(f); + selector += upb_handlers_selectorcount(f); + } + m->selector_count = selector; + + upb_gfree(fields); +} + +static char *strviewdup(symtab_addctx *ctx, upb_strview view) { + return upb_strdup2(view.data, view.size, ctx->alloc); +} + +static bool streql2(const char *a, size_t n, const char *b) { + return n == strlen(b) && memcmp(a, b, n) == 0; +} + +static bool streql_view(upb_strview view, const char *b) { + return streql2(view.data, view.size, b); +} + +static const char *makefullname(symtab_addctx *ctx, const char *prefix, + upb_strview name) { + if (prefix) { + /* ret = prefix + '.' + name; */ + size_t n = strlen(prefix); + char *ret = symtab_alloc(ctx, n + name.size + 2); + strcpy(ret, prefix); + ret[n] = '.'; + memcpy(&ret[n + 1], name.data, name.size); + ret[n + 1 + name.size] = '\0'; + return ret; + } else { + return strviewdup(ctx, name); + } +} + +static void finalize_oneofs(symtab_addctx *ctx, upb_msgdef *m) { + int i; + int synthetic_count = 0; + upb_oneofdef *mutable_oneofs = (upb_oneofdef*)m->oneofs; + + for (i = 0; i < m->oneof_count; i++) { + upb_oneofdef *o = &mutable_oneofs[i]; + + if (o->synthetic && o->field_count != 1) { + symtab_errf(ctx, "Synthetic oneofs must have one field, not %d: %s", + o->field_count, upb_oneofdef_name(o)); + } + + if (o->synthetic) { + synthetic_count++; + } else if (synthetic_count != 0) { + symtab_errf(ctx, "Synthetic oneofs must be after all other oneofs: %s", + upb_oneofdef_name(o)); + } + + o->fields = symtab_alloc(ctx, sizeof(upb_fielddef *) * o->field_count); + o->field_count = 0; + } + + for (i = 0; i < m->field_count; i++) { + const upb_fielddef *f = &m->fields[i]; + upb_oneofdef *o = (upb_oneofdef*)f->oneof; + if (o) { + o->fields[o->field_count++] = f; + } + } + + m->real_oneof_count = m->oneof_count - synthetic_count; +} + +size_t getjsonname(const char *name, char *buf, size_t len) { + size_t src, dst = 0; + bool ucase_next = false; + +#define WRITE(byte) \ + ++dst; \ + if (dst < len) buf[dst - 1] = byte; \ + else if (dst == len) buf[dst - 1] = '\0' + + if (!name) { + WRITE('\0'); + return 0; + } + + /* Implement the transformation as described in the spec: + * 1. upper case all letters after an underscore. + * 2. remove all underscores. + */ + for (src = 0; name[src]; src++) { + if (name[src] == '_') { + ucase_next = true; + continue; + } + + if (ucase_next) { + WRITE(toupper(name[src])); + ucase_next = false; + } else { + WRITE(name[src]); + } + } + + WRITE('\0'); + return dst; + +#undef WRITE +} + +static char* makejsonname(symtab_addctx *ctx, const char* name) { + size_t size = getjsonname(name, NULL, 0); + char* json_name = symtab_alloc(ctx, size); + getjsonname(name, json_name, size); + return json_name; +} + +static void symtab_add(symtab_addctx *ctx, const char *name, upb_value v) { + if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) { + symtab_errf(ctx, "duplicate symbol '%s'", name); + } + upb_alloc *alloc = upb_arena_alloc(ctx->symtab->arena); + size_t len = strlen(name); + CHK_OOM(upb_strtable_insert3(&ctx->symtab->syms, name, len, v, alloc)); +} + +/* Given a symbol and the base symbol inside which it is defined, find the + * symbol's definition in t. */ +static const void *symtab_resolve(symtab_addctx *ctx, const upb_fielddef *f, + const char *base, upb_strview sym, + upb_deftype_t type) { + const upb_strtable *t = &ctx->symtab->syms; + if(sym.size == 0) goto notfound; + if(sym.data[0] == '.') { + /* Symbols starting with '.' are absolute, so we do a single lookup. + * Slice to omit the leading '.' */ + upb_value v; + if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) { + goto notfound; + } + + const void *ret = unpack_def(v, type); + if (!ret) { + symtab_errf(ctx, "type mismatch when resolving field %s, name %s", + f->full_name, sym.data); + } + return ret; + } else { + /* Remove components from base until we find an entry or run out. + * TODO: This branch is totally broken, but currently not used. */ + (void)base; + UPB_ASSERT(false); + goto notfound; + } + +notfound: + symtab_errf(ctx, "couldn't resolve name '%s'", sym.data); +} + +static void create_oneofdef( + symtab_addctx *ctx, upb_msgdef *m, + const google_protobuf_OneofDescriptorProto *oneof_proto) { + upb_oneofdef *o; + upb_strview name = google_protobuf_OneofDescriptorProto_name(oneof_proto); + upb_value v; + + o = (upb_oneofdef*)&m->oneofs[m->oneof_count++]; + o->parent = m; + o->full_name = makefullname(ctx, m->full_name, name); + o->field_count = 0; + o->synthetic = false; + + v = pack_def(o, UPB_DEFTYPE_ONEOF); + symtab_add(ctx, o->full_name, v); + CHK_OOM(upb_strtable_insert3(&m->ntof, name.data, name.size, v, ctx->alloc)); + + CHK_OOM(upb_inttable_init2(&o->itof, UPB_CTYPE_CONSTPTR, ctx->alloc)); + CHK_OOM(upb_strtable_init2(&o->ntof, UPB_CTYPE_CONSTPTR, 4, ctx->alloc)); +} + +static str_t *newstr(symtab_addctx *ctx, const char *data, size_t len) { + str_t *ret = symtab_alloc(ctx, sizeof(*ret) + len); + if (!ret) return NULL; + ret->len = len; + if (len) memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; +} + +static void parse_default(symtab_addctx *ctx, const char *str, size_t len, + upb_fielddef *f) { + char *end; + char nullz[64]; + errno = 0; + + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + case UPB_TYPE_INT64: + case UPB_TYPE_UINT32: + case UPB_TYPE_UINT64: + case UPB_TYPE_DOUBLE: + case UPB_TYPE_FLOAT: + /* Standard C number parsing functions expect null-terminated strings. */ + if (len >= sizeof(nullz) - 1) { + symtab_errf(ctx, "Default too long: %.*s", (int)len, str); + } + memcpy(nullz, str, len); + nullz[len] = '\0'; + str = nullz; + break; + default: + break; + } + + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case UPB_TYPE_ENUM: { + const upb_enumdef *e = f->sub.enumdef; + int32_t val; + if (!upb_enumdef_ntoi(e, str, len, &val)) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case UPB_TYPE_INT64: { + /* XXX: Need to write our own strtoll, since it's not available in c89. */ + int64_t val = strtol(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.sint = val; + break; + } + case UPB_TYPE_UINT32: { + unsigned long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case UPB_TYPE_UINT64: { + /* XXX: Need to write our own strtoull, since it's not available in c89. */ + uint64_t val = strtoul(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.uint = val; + break; + } + case UPB_TYPE_DOUBLE: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.dbl = val; + break; + } + case UPB_TYPE_FLOAT: { + /* XXX: Need to write our own strtof, since it's not available in c89. */ + float val = strtod(str, &end); + if (errno == ERANGE || *end) { + goto invalid; + } + f->defaultval.flt = val; + break; + } + case UPB_TYPE_BOOL: { + if (streql2(str, len, "false")) { + f->defaultval.boolean = false; + } else if (streql2(str, len, "true")) { + f->defaultval.boolean = true; + } else { + } + break; + } + case UPB_TYPE_STRING: + f->defaultval.str = newstr(ctx, str, len); + break; + case UPB_TYPE_BYTES: + /* XXX: need to interpret the C-escaped value. */ + f->defaultval.str = newstr(ctx, str, len); + break; + case UPB_TYPE_MESSAGE: + /* Should not have a default value. */ + symtab_errf(ctx, "Message should not have a default (%s)", + upb_fielddef_fullname(f)); + } + + return; + +invalid: + symtab_errf(ctx, "Invalid default '%.*s' for field %f", (int)len, str, + upb_fielddef_fullname(f)); +} + +static void set_default_default(symtab_addctx *ctx, upb_fielddef *f) { + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + case UPB_TYPE_INT64: + case UPB_TYPE_ENUM: + f->defaultval.sint = 0; + break; + case UPB_TYPE_UINT64: + case UPB_TYPE_UINT32: + f->defaultval.uint = 0; + break; + case UPB_TYPE_DOUBLE: + case UPB_TYPE_FLOAT: + f->defaultval.dbl = 0; + break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + f->defaultval.str = newstr(ctx, NULL, 0); + break; + case UPB_TYPE_BOOL: + f->defaultval.boolean = false; + break; + case UPB_TYPE_MESSAGE: + break; + } +} + +static void create_fielddef( + symtab_addctx *ctx, const char *prefix, upb_msgdef *m, + const google_protobuf_FieldDescriptorProto *field_proto) { + upb_alloc *alloc = ctx->alloc; + upb_fielddef *f; + const google_protobuf_FieldOptions *options; + upb_strview name; + const char *full_name; + const char *json_name; + const char *shortname; + uint32_t field_number; + + if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { + symtab_errf(ctx, "field has no name (%s)", upb_msgdef_fullname(m)); + } + + name = google_protobuf_FieldDescriptorProto_name(field_proto); + check_ident(ctx, name, false); + full_name = makefullname(ctx, prefix, name); + shortname = shortdefname(full_name); + + if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { + json_name = strviewdup( + ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto)); + } else { + json_name = makejsonname(ctx, shortname); + } + + field_number = google_protobuf_FieldDescriptorProto_number(field_proto); + + if (field_number == 0 || field_number > UPB_MAX_FIELDNUMBER) { + symtab_errf(ctx, "invalid field number (%u)", field_number); + } + + if (m) { + /* direct message field. */ + upb_value v, field_v, json_v; + size_t json_size; + + f = (upb_fielddef*)&m->fields[m->field_count++]; + f->msgdef = m; + f->is_extension_ = false; + + if (upb_strtable_lookup(&m->ntof, shortname, NULL)) { + symtab_errf(ctx, "duplicate field name (%s)", shortname); + } + + if (upb_strtable_lookup(&m->ntof, json_name, NULL)) { + symtab_errf(ctx, "duplicate json_name (%s)", json_name); + } + + if (upb_inttable_lookup(&m->itof, field_number, NULL)) { + symtab_errf(ctx, "duplicate field number (%u)", field_number); + } + + field_v = pack_def(f, UPB_DEFTYPE_FIELD); + json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME); + v = upb_value_constptr(f); + json_size = strlen(json_name); + + CHK_OOM( + upb_strtable_insert3(&m->ntof, name.data, name.size, field_v, alloc)); + CHK_OOM(upb_inttable_insert2(&m->itof, field_number, v, alloc)); + + if (strcmp(shortname, json_name) != 0) { + upb_strtable_insert3(&m->ntof, json_name, json_size, json_v, alloc); + } + + if (ctx->layouts) { + const upb_msglayout_field *fields = m->layout->fields; + int count = m->layout->field_count; + bool found = false; + int i; + for (i = 0; i < count; i++) { + if (fields[i].number == field_number) { + f->layout_index = i; + found = true; + break; + } + } + UPB_ASSERT(found); + } + } else { + /* extension field. */ + f = (upb_fielddef*)&ctx->file->exts[ctx->file->ext_count++]; + f->is_extension_ = true; + symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_FIELD)); + } + + f->full_name = full_name; + f->json_name = json_name; + f->file = ctx->file; + f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); + f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); + f->number_ = field_number; + f->oneof = NULL; + f->proto3_optional_ = + google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); + + /* We can't resolve the subdef or (in the case of extensions) the containing + * message yet, because it may not have been defined yet. We stash a pointer + * to the field_proto until later when we can properly resolve it. */ + f->sub.unresolved = field_proto; + + if (f->label_ == UPB_LABEL_REQUIRED && f->file->syntax == UPB_SYNTAX_PROTO3) { + symtab_errf(ctx, "proto3 fields cannot be required (%s)", f->full_name); + } + + if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { + int oneof_index = + google_protobuf_FieldDescriptorProto_oneof_index(field_proto); + upb_oneofdef *oneof; + upb_value v = upb_value_constptr(f); + + if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) { + symtab_errf(ctx, "fields in oneof must have OPTIONAL label (%s)", + f->full_name); + } + + if (!m) { + symtab_errf(ctx, "oneof_index provided for extension field (%s)", + f->full_name); + } + + if (oneof_index >= m->oneof_count) { + symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name); + } + + oneof = (upb_oneofdef*)&m->oneofs[oneof_index]; + f->oneof = oneof; + + oneof->field_count++; + if (f->proto3_optional_) { + oneof->synthetic = true; + } + CHK_OOM(upb_inttable_insert2(&oneof->itof, f->number_, v, alloc)); + CHK_OOM(upb_strtable_insert3(&oneof->ntof, name.data, name.size, v, alloc)); + } else { + f->oneof = NULL; + if (f->proto3_optional_) { + symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)", + f->full_name); + } + } + + options = google_protobuf_FieldDescriptorProto_has_options(field_proto) ? + google_protobuf_FieldDescriptorProto_options(field_proto) : NULL; + + if (options && google_protobuf_FieldOptions_has_packed(options)) { + f->packed_ = google_protobuf_FieldOptions_packed(options); + } else { + /* Repeated fields default to packed for proto3 only. */ + f->packed_ = upb_fielddef_isprimitive(f) && + f->label_ == UPB_LABEL_REPEATED && f->file->syntax == UPB_SYNTAX_PROTO3; + } + + if (options) { + f->lazy_ = google_protobuf_FieldOptions_lazy(options); + } else { + f->lazy_ = false; + } +} + +static void create_enumdef( + symtab_addctx *ctx, const char *prefix, + const google_protobuf_EnumDescriptorProto *enum_proto) { + upb_enumdef *e; + const google_protobuf_EnumValueDescriptorProto *const *values; + upb_strview name; + size_t i, n; + + name = google_protobuf_EnumDescriptorProto_name(enum_proto); + check_ident(ctx, name, false); + + e = (upb_enumdef*)&ctx->file->enums[ctx->file->enum_count++]; + e->full_name = makefullname(ctx, prefix, name); + symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM)); + + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); + CHK_OOM(upb_strtable_init2(&e->ntoi, UPB_CTYPE_INT32, n, ctx->alloc)); + CHK_OOM(upb_inttable_init2(&e->iton, UPB_CTYPE_CSTR, ctx->alloc)); + + e->file = ctx->file; + e->defaultval = 0; + + if (n == 0) { + symtab_errf(ctx, "enums must contain at least one value (%s)", + e->full_name); + } + + for (i = 0; i < n; i++) { + const google_protobuf_EnumValueDescriptorProto *value = values[i]; + upb_strview name = google_protobuf_EnumValueDescriptorProto_name(value); + char *name2 = strviewdup(ctx, name); + int32_t num = google_protobuf_EnumValueDescriptorProto_number(value); + upb_value v = upb_value_int32(num); + + if (i == 0 && e->file->syntax == UPB_SYNTAX_PROTO3 && num != 0) { + symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)", + e->full_name); + } + + if (upb_strtable_lookup(&e->ntoi, name2, NULL)) { + symtab_errf(ctx, "duplicate enum label '%s'", name2); + } + + CHK_OOM(name2) + CHK_OOM( + upb_strtable_insert3(&e->ntoi, name2, strlen(name2), v, ctx->alloc)); + + if (!upb_inttable_lookup(&e->iton, num, NULL)) { + upb_value v = upb_value_cstr(name2); + CHK_OOM(upb_inttable_insert2(&e->iton, num, v, ctx->alloc)); + } + } + + upb_inttable_compact2(&e->iton, ctx->alloc); +} + +static void create_msgdef(symtab_addctx *ctx, const char *prefix, + const google_protobuf_DescriptorProto *msg_proto) { + upb_msgdef *m; + const google_protobuf_MessageOptions *options; + const google_protobuf_OneofDescriptorProto *const *oneofs; + const google_protobuf_FieldDescriptorProto *const *fields; + const google_protobuf_EnumDescriptorProto *const *enums; + const google_protobuf_DescriptorProto *const *msgs; + size_t i, n_oneof, n_field, n; + upb_strview name; + + name = google_protobuf_DescriptorProto_name(msg_proto); + check_ident(ctx, name, false); + + m = (upb_msgdef*)&ctx->file->msgs[ctx->file->msg_count++]; + m->full_name = makefullname(ctx, prefix, name); + symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG)); + + oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); + fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); + + CHK_OOM(upb_inttable_init2(&m->itof, UPB_CTYPE_CONSTPTR, ctx->alloc)); + CHK_OOM(upb_strtable_init2(&m->ntof, UPB_CTYPE_CONSTPTR, n_oneof + n_field, + ctx->alloc)); + + m->file = ctx->file; + m->map_entry = false; + + options = google_protobuf_DescriptorProto_options(msg_proto); + + if (options) { + m->map_entry = google_protobuf_MessageOptions_map_entry(options); + } + + if (ctx->layouts) { + m->layout = *ctx->layouts; + ctx->layouts++; + } else { + /* Allocate now (to allow cross-linking), populate later. */ + m->layout = symtab_alloc( + ctx, sizeof(*m->layout) + sizeof(_upb_fasttable_entry)); + } + + m->oneof_count = 0; + m->oneofs = symtab_alloc(ctx, sizeof(*m->oneofs) * n_oneof); + for (i = 0; i < n_oneof; i++) { + create_oneofdef(ctx, m, oneofs[i]); + } + + m->field_count = 0; + m->fields = symtab_alloc(ctx, sizeof(*m->fields) * n_field); + for (i = 0; i < n_field; i++) { + create_fielddef(ctx, m->full_name, m, fields[i]); + } + + assign_msg_indices(ctx, m); + finalize_oneofs(ctx, m); + assign_msg_wellknowntype(m); + upb_inttable_compact2(&m->itof, ctx->alloc); + + /* This message is built. Now build nested messages and enums. */ + + enums = google_protobuf_DescriptorProto_enum_type(msg_proto, &n); + for (i = 0; i < n; i++) { + create_enumdef(ctx, m->full_name, enums[i]); + } + + msgs = google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + for (i = 0; i < n; i++) { + create_msgdef(ctx, m->full_name, msgs[i]); + } +} + +static void count_types_in_msg(const google_protobuf_DescriptorProto *msg_proto, + upb_filedef *file) { + const google_protobuf_DescriptorProto *const *msgs; + size_t i, n; + + file->msg_count++; + + msgs = google_protobuf_DescriptorProto_nested_type(msg_proto, &n); + for (i = 0; i < n; i++) { + count_types_in_msg(msgs[i], file); + } + + google_protobuf_DescriptorProto_enum_type(msg_proto, &n); + file->enum_count += n; + + google_protobuf_DescriptorProto_extension(msg_proto, &n); + file->ext_count += n; +} + +static void count_types_in_file( + const google_protobuf_FileDescriptorProto *file_proto, + upb_filedef *file) { + const google_protobuf_DescriptorProto *const *msgs; + size_t i, n; + + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + for (i = 0; i < n; i++) { + count_types_in_msg(msgs[i], file); + } + + google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + file->enum_count += n; + + google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->ext_count += n; +} + +static void resolve_fielddef(symtab_addctx *ctx, const char *prefix, + upb_fielddef *f) { + upb_strview name; + const google_protobuf_FieldDescriptorProto *field_proto = f->sub.unresolved; + + if (f->is_extension_) { + if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { + symtab_errf(ctx, "extension for field '%s' had no extendee", + f->full_name); + } + + name = google_protobuf_FieldDescriptorProto_extendee(field_proto); + f->msgdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_MSG); + } + + if ((upb_fielddef_issubmsg(f) || f->type_ == UPB_DESCRIPTOR_TYPE_ENUM) && + !google_protobuf_FieldDescriptorProto_has_type_name(field_proto)) { + symtab_errf(ctx, "field '%s' is missing type name", f->full_name); + } + + name = google_protobuf_FieldDescriptorProto_type_name(field_proto); + + if (upb_fielddef_issubmsg(f)) { + f->sub.msgdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_MSG); + } else if (f->type_ == UPB_DESCRIPTOR_TYPE_ENUM) { + f->sub.enumdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_ENUM); + } + + /* Have to delay resolving of the default value until now because of the enum + * case, since enum defaults are specified with a label. */ + if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { + upb_strview defaultval = + google_protobuf_FieldDescriptorProto_default_value(field_proto); + + if (f->file->syntax == UPB_SYNTAX_PROTO3) { + symtab_errf(ctx, "proto3 fields cannot have explicit defaults (%s)", + f->full_name); + } + + if (upb_fielddef_issubmsg(f)) { + symtab_errf(ctx, "message fields cannot have explicit defaults (%s)", + f->full_name); + } + + parse_default(ctx, defaultval.data, defaultval.size, f); + } else { + set_default_default(ctx, f); + } +} + +static void build_filedef( + symtab_addctx *ctx, upb_filedef *file, + const google_protobuf_FileDescriptorProto *file_proto) { + const google_protobuf_FileOptions *file_options_proto; + const google_protobuf_DescriptorProto *const *msgs; + const google_protobuf_EnumDescriptorProto *const *enums; + const google_protobuf_FieldDescriptorProto *const *exts; + const upb_strview* strs; + size_t i, n; + + count_types_in_file(file_proto, file); + + file->msgs = symtab_alloc(ctx, sizeof(*file->msgs) * file->msg_count); + file->enums = symtab_alloc(ctx, sizeof(*file->enums) * file->enum_count); + file->exts = symtab_alloc(ctx, sizeof(*file->exts) * file->ext_count); + + /* We increment these as defs are added. */ + file->msg_count = 0; + file->enum_count = 0; + file->ext_count = 0; + + if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { + symtab_errf(ctx, "File has no name"); + } + + file->name = + strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); + file->phpprefix = NULL; + file->phpnamespace = NULL; + + if (google_protobuf_FileDescriptorProto_has_package(file_proto)) { + upb_strview package = + google_protobuf_FileDescriptorProto_package(file_proto); + check_ident(ctx, package, true); + file->package = strviewdup(ctx, package); + } else { + file->package = NULL; + } + + if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { + upb_strview syntax = + google_protobuf_FileDescriptorProto_syntax(file_proto); + + if (streql_view(syntax, "proto2")) { + file->syntax = UPB_SYNTAX_PROTO2; + } else if (streql_view(syntax, "proto3")) { + file->syntax = UPB_SYNTAX_PROTO3; + } else { + symtab_errf(ctx, "Invalid syntax '" UPB_STRVIEW_FORMAT "'", + UPB_STRVIEW_ARGS(syntax)); + } + } else { + file->syntax = UPB_SYNTAX_PROTO2; + } + + /* Read options. */ + file_options_proto = google_protobuf_FileDescriptorProto_options(file_proto); + if (file_options_proto) { + if (google_protobuf_FileOptions_has_php_class_prefix(file_options_proto)) { + file->phpprefix = strviewdup( + ctx, + google_protobuf_FileOptions_php_class_prefix(file_options_proto)); + } + if (google_protobuf_FileOptions_has_php_namespace(file_options_proto)) { + file->phpnamespace = strviewdup( + ctx, google_protobuf_FileOptions_php_namespace(file_options_proto)); + } + } + + /* Verify dependencies. */ + strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); + file->deps = symtab_alloc(ctx, sizeof(*file->deps) * n); + + for (i = 0; i < n; i++) { + upb_strview dep_name = strs[i]; + upb_value v; + if (!upb_strtable_lookup2(&ctx->symtab->files, dep_name.data, + dep_name.size, &v)) { + symtab_errf(ctx, + "Depends on file '" UPB_STRVIEW_FORMAT + "', but it has not been loaded", + UPB_STRVIEW_ARGS(dep_name)); + } + file->deps[i] = upb_value_getconstptr(v); + } + + /* Create messages. */ + msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); + for (i = 0; i < n; i++) { + create_msgdef(ctx, file->package, msgs[i]); + } + + /* Create enums. */ + enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); + for (i = 0; i < n; i++) { + create_enumdef(ctx, file->package, enums[i]); + } + + /* Create extensions. */ + exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); + file->exts = symtab_alloc(ctx, sizeof(*file->exts) * n); + for (i = 0; i < n; i++) { + create_fielddef(ctx, file->package, NULL, exts[i]); + } + + /* Now that all names are in the table, build layouts and resolve refs. */ + for (i = 0; i < (size_t)file->ext_count; i++) { + resolve_fielddef(ctx, file->package, (upb_fielddef*)&file->exts[i]); + } + + for (i = 0; i < (size_t)file->msg_count; i++) { + const upb_msgdef *m = &file->msgs[i]; + int j; + for (j = 0; j < m->field_count; j++) { + resolve_fielddef(ctx, m->full_name, (upb_fielddef*)&m->fields[j]); + } + } + + if (!ctx->layouts) { + for (i = 0; i < (size_t)file->msg_count; i++) { + const upb_msgdef *m = &file->msgs[i]; + make_layout(ctx, m); + } + } +} + +static void remove_filedef(upb_symtab *s, upb_filedef *file) { + upb_alloc *alloc = upb_arena_alloc(s->arena); + int i; + for (i = 0; i < file->msg_count; i++) { + const char *name = file->msgs[i].full_name; + upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc); + } + for (i = 0; i < file->enum_count; i++) { + const char *name = file->enums[i].full_name; + upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc); + } + for (i = 0; i < file->ext_count; i++) { + const char *name = file->exts[i].full_name; + upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc); + } +} + +static const upb_filedef *_upb_symtab_addfile( + upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto, + const upb_msglayout **layouts, upb_status *status) { + upb_arena *file_arena = upb_arena_new(); + upb_filedef *file; + symtab_addctx ctx; + + if (!file_arena) return NULL; + + file = upb_arena_malloc(file_arena, sizeof(*file)); + if (!file) goto done; + + ctx.file = file; + ctx.symtab = s; + ctx.file_arena = file_arena; + ctx.alloc = upb_arena_alloc(file_arena); + ctx.layouts = layouts; + ctx.status = status; + + file->msg_count = 0; + file->enum_count = 0; + file->ext_count = 0; + file->symtab = s; + + if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) { + UPB_ASSERT(!upb_ok(status)); + remove_filedef(s, file); + file = NULL; + } else { + build_filedef(&ctx, file, file_proto); + upb_strtable_insert3(&s->files, file->name, strlen(file->name), + upb_value_constptr(file), ctx.alloc); + UPB_ASSERT(upb_ok(status)); + upb_arena_fuse(s->arena, file_arena); + } + +done: + upb_arena_free(file_arena); + return file; +} + +const upb_filedef *upb_symtab_addfile( + upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto, + upb_status *status) { + return _upb_symtab_addfile(s, file_proto, NULL, status); +} + +/* Include here since we want most of this file to be stdio-free. */ +#include <stdio.h> + +bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init) { + /* Since this function should never fail (it would indicate a bug in upb) we + * print errors to stderr instead of returning error status to the user. */ + upb_def_init **deps = init->deps; + google_protobuf_FileDescriptorProto *file; + upb_arena *arena; + upb_status status; + + upb_status_clear(&status); + + if (upb_strtable_lookup(&s->files, init->filename, NULL)) { + return true; + } + + arena = upb_arena_new(); + + for (; *deps; deps++) { + if (!_upb_symtab_loaddefinit(s, *deps)) goto err; + } + + file = google_protobuf_FileDescriptorProto_parse_ex( + init->descriptor.data, init->descriptor.size, arena, UPB_DECODE_ALIAS); + s->bytes_loaded += init->descriptor.size; + + if (!file) { + upb_status_seterrf( + &status, + "Failed to parse compiled-in descriptor for file '%s'. This should " + "never happen.", + init->filename); + goto err; + } + + if (!_upb_symtab_addfile(s, file, init->layouts, &status)) goto err; + + upb_arena_free(arena); + return true; + +err: + fprintf(stderr, "Error loading compiled-in descriptor: %s\n", + upb_status_errmsg(&status)); + upb_arena_free(arena); + return false; +} + +size_t _upb_symtab_bytesloaded(const upb_symtab *s) { + return s->bytes_loaded; +} + +#undef CHK_OOM diff --git a/contrib/libs/grpc/third_party/upb/upb/def.h b/contrib/libs/grpc/third_party/upb/upb/def.h new file mode 100644 index 0000000000..7206ec0d3e --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/def.h @@ -0,0 +1,315 @@ +/* +** Defs are upb's internal representation of the constructs that can appear +** in a .proto file: +** +** - upb_msgdef: describes a "message" construct. +** - upb_fielddef: describes a message field. +** - upb_filedef: describes a .proto file and its defs. +** - upb_enumdef: describes an enum. +** - upb_oneofdef: describes a oneof. +** +** TODO: definitions of services. +*/ + +#ifndef UPB_DEF_H_ +#define UPB_DEF_H_ + +#include "upb/upb.h" +#include "upb/table.int.h" +#include "google/protobuf/descriptor.upb.h" + +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct upb_enumdef; +typedef struct upb_enumdef upb_enumdef; +struct upb_fielddef; +typedef struct upb_fielddef upb_fielddef; +struct upb_filedef; +typedef struct upb_filedef upb_filedef; +struct upb_msgdef; +typedef struct upb_msgdef upb_msgdef; +struct upb_oneofdef; +typedef struct upb_oneofdef upb_oneofdef; +struct upb_symtab; +typedef struct upb_symtab upb_symtab; + +typedef enum { + UPB_SYNTAX_PROTO2 = 2, + UPB_SYNTAX_PROTO3 = 3 +} upb_syntax_t; + +/* All the different kind of well known type messages. For simplicity of check, + * number wrappers and string wrappers are grouped together. Make sure the + * order and merber of these groups are not changed. + */ +typedef enum { + UPB_WELLKNOWN_UNSPECIFIED, + UPB_WELLKNOWN_ANY, + UPB_WELLKNOWN_FIELDMASK, + UPB_WELLKNOWN_DURATION, + UPB_WELLKNOWN_TIMESTAMP, + /* number wrappers */ + UPB_WELLKNOWN_DOUBLEVALUE, + UPB_WELLKNOWN_FLOATVALUE, + UPB_WELLKNOWN_INT64VALUE, + UPB_WELLKNOWN_UINT64VALUE, + UPB_WELLKNOWN_INT32VALUE, + UPB_WELLKNOWN_UINT32VALUE, + /* string wrappers */ + UPB_WELLKNOWN_STRINGVALUE, + UPB_WELLKNOWN_BYTESVALUE, + UPB_WELLKNOWN_BOOLVALUE, + UPB_WELLKNOWN_VALUE, + UPB_WELLKNOWN_LISTVALUE, + UPB_WELLKNOWN_STRUCT +} upb_wellknowntype_t; + +/* upb_fielddef ***************************************************************/ + +/* Maximum field number allowed for FieldDefs. This is an inherent limit of the + * protobuf wire format. */ +#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1) + +const char *upb_fielddef_fullname(const upb_fielddef *f); +upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f); +upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f); +upb_label_t upb_fielddef_label(const upb_fielddef *f); +uint32_t upb_fielddef_number(const upb_fielddef *f); +const char *upb_fielddef_name(const upb_fielddef *f); +const char *upb_fielddef_jsonname(const upb_fielddef *f); +bool upb_fielddef_isextension(const upb_fielddef *f); +bool upb_fielddef_lazy(const upb_fielddef *f); +bool upb_fielddef_packed(const upb_fielddef *f); +const upb_filedef *upb_fielddef_file(const upb_fielddef *f); +const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f); +const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f); +const upb_oneofdef *upb_fielddef_realcontainingoneof(const upb_fielddef *f); +uint32_t upb_fielddef_index(const upb_fielddef *f); +bool upb_fielddef_issubmsg(const upb_fielddef *f); +bool upb_fielddef_isstring(const upb_fielddef *f); +bool upb_fielddef_isseq(const upb_fielddef *f); +bool upb_fielddef_isprimitive(const upb_fielddef *f); +bool upb_fielddef_ismap(const upb_fielddef *f); +int64_t upb_fielddef_defaultint64(const upb_fielddef *f); +int32_t upb_fielddef_defaultint32(const upb_fielddef *f); +uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f); +uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f); +bool upb_fielddef_defaultbool(const upb_fielddef *f); +float upb_fielddef_defaultfloat(const upb_fielddef *f); +double upb_fielddef_defaultdouble(const upb_fielddef *f); +const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len); +bool upb_fielddef_hassubdef(const upb_fielddef *f); +bool upb_fielddef_haspresence(const upb_fielddef *f); +const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f); +const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f); +const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f); + +/* Internal only. */ +uint32_t upb_fielddef_selectorbase(const upb_fielddef *f); + +/* upb_oneofdef ***************************************************************/ + +typedef upb_inttable_iter upb_oneof_iter; + +const char *upb_oneofdef_name(const upb_oneofdef *o); +const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o); +uint32_t upb_oneofdef_index(const upb_oneofdef *o); +bool upb_oneofdef_issynthetic(const upb_oneofdef *o); +int upb_oneofdef_fieldcount(const upb_oneofdef *o); +const upb_fielddef *upb_oneofdef_field(const upb_oneofdef *o, int i); + +/* Oneof lookups: + * - ntof: look up a field by name. + * - ntofz: look up a field by name (as a null-terminated string). + * - itof: look up a field by number. */ +const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, + const char *name, size_t length); +UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o, + const char *name) { + return upb_oneofdef_ntof(o, name, strlen(name)); +} +const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num); + +/* DEPRECATED, slated for removal. */ +int upb_oneofdef_numfields(const upb_oneofdef *o); +void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o); +void upb_oneof_next(upb_oneof_iter *iter); +bool upb_oneof_done(upb_oneof_iter *iter); +upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter); +void upb_oneof_iter_setdone(upb_oneof_iter *iter); +bool upb_oneof_iter_isequal(const upb_oneof_iter *iter1, + const upb_oneof_iter *iter2); +/* END DEPRECATED */ + +/* upb_msgdef *****************************************************************/ + +typedef upb_inttable_iter upb_msg_field_iter; +typedef upb_strtable_iter upb_msg_oneof_iter; + +/* Well-known field tag numbers for map-entry messages. */ +#define UPB_MAPENTRY_KEY 1 +#define UPB_MAPENTRY_VALUE 2 + +/* Well-known field tag numbers for Any messages. */ +#define UPB_ANY_TYPE 1 +#define UPB_ANY_VALUE 2 + +/* Well-known field tag numbers for timestamp messages. */ +#define UPB_DURATION_SECONDS 1 +#define UPB_DURATION_NANOS 2 + +/* Well-known field tag numbers for duration messages. */ +#define UPB_TIMESTAMP_SECONDS 1 +#define UPB_TIMESTAMP_NANOS 2 + +const char *upb_msgdef_fullname(const upb_msgdef *m); +const upb_filedef *upb_msgdef_file(const upb_msgdef *m); +const char *upb_msgdef_name(const upb_msgdef *m); +upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m); +bool upb_msgdef_mapentry(const upb_msgdef *m); +upb_wellknowntype_t upb_msgdef_wellknowntype(const upb_msgdef *m); +bool upb_msgdef_iswrapper(const upb_msgdef *m); +bool upb_msgdef_isnumberwrapper(const upb_msgdef *m); +int upb_msgdef_fieldcount(const upb_msgdef *m); +int upb_msgdef_oneofcount(const upb_msgdef *m); +const upb_fielddef *upb_msgdef_field(const upb_msgdef *m, int i); +const upb_oneofdef *upb_msgdef_oneof(const upb_msgdef *m, int i); +const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i); +const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, + size_t len); +const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, + size_t len); +const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m); + +UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m, + const char *name) { + return upb_msgdef_ntoo(m, name, strlen(name)); +} + +UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m, + const char *name) { + return upb_msgdef_ntof(m, name, strlen(name)); +} + +/* Internal-only. */ +size_t upb_msgdef_selectorcount(const upb_msgdef *m); +uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m); + +/* Lookup of either field or oneof by name. Returns whether either was found. + * If the return is true, then the found def will be set, and the non-found + * one set to NULL. */ +bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len, + const upb_fielddef **f, const upb_oneofdef **o); + +UPB_INLINE bool upb_msgdef_lookupnamez(const upb_msgdef *m, const char *name, + const upb_fielddef **f, + const upb_oneofdef **o) { + return upb_msgdef_lookupname(m, name, strlen(name), f, o); +} + +/* Returns a field by either JSON name or regular proto name. */ +const upb_fielddef *upb_msgdef_lookupjsonname(const upb_msgdef *m, + const char *name, size_t len); + +/* DEPRECATED, slated for removal */ +int upb_msgdef_numfields(const upb_msgdef *m); +int upb_msgdef_numoneofs(const upb_msgdef *m); +int upb_msgdef_numrealoneofs(const upb_msgdef *m); +void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m); +void upb_msg_field_next(upb_msg_field_iter *iter); +bool upb_msg_field_done(const upb_msg_field_iter *iter); +upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter); +void upb_msg_field_iter_setdone(upb_msg_field_iter *iter); +bool upb_msg_field_iter_isequal(const upb_msg_field_iter * iter1, + const upb_msg_field_iter * iter2); +void upb_msg_oneof_begin(upb_msg_oneof_iter * iter, const upb_msgdef *m); +void upb_msg_oneof_next(upb_msg_oneof_iter * iter); +bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter); +const upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter); +void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter * iter); +bool upb_msg_oneof_iter_isequal(const upb_msg_oneof_iter *iter1, + const upb_msg_oneof_iter *iter2); +/* END DEPRECATED */ + +/* upb_enumdef ****************************************************************/ + +typedef upb_strtable_iter upb_enum_iter; + +const char *upb_enumdef_fullname(const upb_enumdef *e); +const char *upb_enumdef_name(const upb_enumdef *e); +const upb_filedef *upb_enumdef_file(const upb_enumdef *e); +int32_t upb_enumdef_default(const upb_enumdef *e); +int upb_enumdef_numvals(const upb_enumdef *e); + +/* Enum lookups: + * - ntoi: look up a name with specified length. + * - ntoiz: look up a name provided as a null-terminated string. + * - iton: look up an integer, returning the name as a null-terminated + * string. */ +bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len, + int32_t *num); +UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e, + const char *name, int32_t *num) { + return upb_enumdef_ntoi(e, name, strlen(name), num); +} +const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num); + +void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e); +void upb_enum_next(upb_enum_iter *iter); +bool upb_enum_done(upb_enum_iter *iter); +const char *upb_enum_iter_name(upb_enum_iter *iter); +int32_t upb_enum_iter_number(upb_enum_iter *iter); + +/* upb_filedef ****************************************************************/ + +const char *upb_filedef_name(const upb_filedef *f); +const char *upb_filedef_package(const upb_filedef *f); +const char *upb_filedef_phpprefix(const upb_filedef *f); +const char *upb_filedef_phpnamespace(const upb_filedef *f); +upb_syntax_t upb_filedef_syntax(const upb_filedef *f); +int upb_filedef_depcount(const upb_filedef *f); +int upb_filedef_msgcount(const upb_filedef *f); +int upb_filedef_enumcount(const upb_filedef *f); +const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i); +const upb_msgdef *upb_filedef_msg(const upb_filedef *f, int i); +const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i); +const upb_symtab *upb_filedef_symtab(const upb_filedef *f); + +/* upb_symtab *****************************************************************/ + +upb_symtab *upb_symtab_new(void); +void upb_symtab_free(upb_symtab* s); +const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym); +const upb_msgdef *upb_symtab_lookupmsg2( + const upb_symtab *s, const char *sym, size_t len); +const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym); +const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name); +const upb_filedef *upb_symtab_lookupfile2( + const upb_symtab *s, const char *name, size_t len); +int upb_symtab_filecount(const upb_symtab *s); +const upb_filedef *upb_symtab_addfile( + upb_symtab *s, const google_protobuf_FileDescriptorProto *file, + upb_status *status); +size_t _upb_symtab_bytesloaded(const upb_symtab *s); + +/* For generated code only: loads a generated descriptor. */ +typedef struct upb_def_init { + struct upb_def_init **deps; /* Dependencies of this file. */ + const upb_msglayout **layouts; /* Pre-order layouts of all messages. */ + const char *filename; + upb_strview descriptor; /* Serialized descriptor. */ +} upb_def_init; + +bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init); + +#include "upb/port_undef.inc" + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* UPB_DEF_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/def.hpp b/contrib/libs/grpc/third_party/upb/upb/def.hpp new file mode 100644 index 0000000000..7e304aae7c --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/def.hpp @@ -0,0 +1,439 @@ + +#ifndef UPB_DEF_HPP_ +#define UPB_DEF_HPP_ + +#include <cstring> +#include <memory> +#include <util/generic/string.h> +#include <vector> + +#include "upb/def.h" +#include "upb/upb.hpp" + +namespace upb { + +class EnumDefPtr; +class MessageDefPtr; +class OneofDefPtr; + +// A upb::FieldDefPtr describes a single field in a message. It is most often +// found as a part of a upb_msgdef, but can also stand alone to represent +// an extension. +class FieldDefPtr { + public: + FieldDefPtr() : ptr_(nullptr) {} + explicit FieldDefPtr(const upb_fielddef* ptr) : ptr_(ptr) {} + + const upb_fielddef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + typedef upb_fieldtype_t Type; + typedef upb_label_t Label; + typedef upb_descriptortype_t DescriptorType; + + const char* full_name() const { return upb_fielddef_fullname(ptr_); } + + Type type() const { return upb_fielddef_type(ptr_); } + Label label() const { return upb_fielddef_label(ptr_); } + const char* name() const { return upb_fielddef_name(ptr_); } + const char* json_name() const { return upb_fielddef_jsonname(ptr_); } + uint32_t number() const { return upb_fielddef_number(ptr_); } + bool is_extension() const { return upb_fielddef_isextension(ptr_); } + + // For UPB_TYPE_MESSAGE fields only where is_tag_delimited() == false, + // indicates whether this field should have lazy parsing handlers that yield + // the unparsed string for the submessage. + // + // TODO(haberman): I think we want to move this into a FieldOptions container + // when we add support for custom options (the FieldOptions struct will + // contain both regular FieldOptions like "lazy" *and* custom options). + bool lazy() const { return upb_fielddef_lazy(ptr_); } + + // For non-string, non-submessage fields, this indicates whether binary + // protobufs are encoded in packed or non-packed format. + // + // TODO(haberman): see note above about putting options like this into a + // FieldOptions container. + bool packed() const { return upb_fielddef_packed(ptr_); } + + // An integer that can be used as an index into an array of fields for + // whatever message this field belongs to. Guaranteed to be less than + // f->containing_type()->field_count(). May only be accessed once the def has + // been finalized. + uint32_t index() const { return upb_fielddef_index(ptr_); } + + // The MessageDef to which this field belongs. + // + // If this field has been added to a MessageDef, that message can be retrieved + // directly (this is always the case for frozen FieldDefs). + // + // If the field has not yet been added to a MessageDef, you can set the name + // of the containing type symbolically instead. This is mostly useful for + // extensions, where the extension is declared separately from the message. + MessageDefPtr containing_type() const; + + // The OneofDef to which this field belongs, or NULL if this field is not part + // of a oneof. + OneofDefPtr containing_oneof() const; + + // The field's type according to the enum in descriptor.proto. This is not + // the same as UPB_TYPE_*, because it distinguishes between (for example) + // INT32 and SINT32, whereas our "type" enum does not. This return of + // descriptor_type() is a function of type(), integer_format(), and + // is_tag_delimited(). + DescriptorType descriptor_type() const { + return upb_fielddef_descriptortype(ptr_); + } + + // Convenient field type tests. + bool IsSubMessage() const { return upb_fielddef_issubmsg(ptr_); } + bool IsString() const { return upb_fielddef_isstring(ptr_); } + bool IsSequence() const { return upb_fielddef_isseq(ptr_); } + bool IsPrimitive() const { return upb_fielddef_isprimitive(ptr_); } + bool IsMap() const { return upb_fielddef_ismap(ptr_); } + + // Returns the non-string default value for this fielddef, which may either + // be something the client set explicitly or the "default default" (0 for + // numbers, empty for strings). The field's type indicates the type of the + // returned value, except for enum fields that are still mutable. + // + // Requires that the given function matches the field's current type. + int64_t default_int64() const { return upb_fielddef_defaultint64(ptr_); } + int32_t default_int32() const { return upb_fielddef_defaultint32(ptr_); } + uint64_t default_uint64() const { return upb_fielddef_defaultuint64(ptr_); } + uint32_t default_uint32() const { return upb_fielddef_defaultuint32(ptr_); } + bool default_bool() const { return upb_fielddef_defaultbool(ptr_); } + float default_float() const { return upb_fielddef_defaultfloat(ptr_); } + double default_double() const { return upb_fielddef_defaultdouble(ptr_); } + + // The resulting string is always NULL-terminated. If non-NULL, the length + // will be stored in *len. + const char* default_string(size_t* len) const { + return upb_fielddef_defaultstr(ptr_, len); + } + + // Returns the enum or submessage def for this field, if any. The field's + // type must match (ie. you may only call enum_subdef() for fields where + // type() == UPB_TYPE_ENUM). + EnumDefPtr enum_subdef() const; + MessageDefPtr message_subdef() const; + + private: + const upb_fielddef* ptr_; +}; + +// Class that represents a oneof. +class OneofDefPtr { + public: + OneofDefPtr() : ptr_(nullptr) {} + explicit OneofDefPtr(const upb_oneofdef* ptr) : ptr_(ptr) {} + + const upb_oneofdef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + // Returns the MessageDef that contains this OneofDef. + MessageDefPtr containing_type() const; + + // Returns the name of this oneof. + const char* name() const { return upb_oneofdef_name(ptr_); } + + // Returns the number of fields in the oneof. + int field_count() const { return upb_oneofdef_numfields(ptr_); } + FieldDefPtr field(int i) const { return FieldDefPtr(upb_oneofdef_field(ptr_, i)); } + + // Looks up by name. + FieldDefPtr FindFieldByName(const char* name, size_t len) const { + return FieldDefPtr(upb_oneofdef_ntof(ptr_, name, len)); + } + FieldDefPtr FindFieldByName(const char* name) const { + return FieldDefPtr(upb_oneofdef_ntofz(ptr_, name)); + } + + template <class T> + FieldDefPtr FindFieldByName(const T& str) const { + return FindFieldByName(str.c_str(), str.size()); + } + + // Looks up by tag number. + FieldDefPtr FindFieldByNumber(uint32_t num) const { + return FieldDefPtr(upb_oneofdef_itof(ptr_, num)); + } + + private: + const upb_oneofdef* ptr_; +}; + +// Structure that describes a single .proto message type. +class MessageDefPtr { + public: + MessageDefPtr() : ptr_(nullptr) {} + explicit MessageDefPtr(const upb_msgdef* ptr) : ptr_(ptr) {} + + const upb_msgdef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + const char* full_name() const { return upb_msgdef_fullname(ptr_); } + const char* name() const { return upb_msgdef_name(ptr_); } + + // The number of fields that belong to the MessageDef. + int field_count() const { return upb_msgdef_numfields(ptr_); } + FieldDefPtr field(int i) const { return FieldDefPtr(upb_msgdef_field(ptr_, i)); } + + // The number of oneofs that belong to the MessageDef. + int oneof_count() const { return upb_msgdef_numoneofs(ptr_); } + OneofDefPtr oneof(int i) const { return OneofDefPtr(upb_msgdef_oneof(ptr_, i)); } + + upb_syntax_t syntax() const { return upb_msgdef_syntax(ptr_); } + + // These return null pointers if the field is not found. + FieldDefPtr FindFieldByNumber(uint32_t number) const { + return FieldDefPtr(upb_msgdef_itof(ptr_, number)); + } + FieldDefPtr FindFieldByName(const char* name, size_t len) const { + return FieldDefPtr(upb_msgdef_ntof(ptr_, name, len)); + } + FieldDefPtr FindFieldByName(const char* name) const { + return FieldDefPtr(upb_msgdef_ntofz(ptr_, name)); + } + + template <class T> + FieldDefPtr FindFieldByName(const T& str) const { + return FindFieldByName(str.c_str(), str.size()); + } + + OneofDefPtr FindOneofByName(const char* name, size_t len) const { + return OneofDefPtr(upb_msgdef_ntoo(ptr_, name, len)); + } + + OneofDefPtr FindOneofByName(const char* name) const { + return OneofDefPtr(upb_msgdef_ntooz(ptr_, name)); + } + + template <class T> + OneofDefPtr FindOneofByName(const T& str) const { + return FindOneofByName(str.c_str(), str.size()); + } + + // Is this message a map entry? + bool mapentry() const { return upb_msgdef_mapentry(ptr_); } + + // Return the type of well known type message. UPB_WELLKNOWN_UNSPECIFIED for + // non-well-known message. + upb_wellknowntype_t wellknowntype() const { + return upb_msgdef_wellknowntype(ptr_); + } + + // Whether is a number wrapper. + bool isnumberwrapper() const { return upb_msgdef_isnumberwrapper(ptr_); } + + private: + class FieldIter { + public: + explicit FieldIter(const upb_msgdef *m, int i) : m_(m), i_(i) {} + void operator++() { i_++; } + + FieldDefPtr operator*() { return FieldDefPtr(upb_msgdef_field(m_, i_)); } + bool operator!=(const FieldIter& other) { return i_ != other.i_; } + bool operator==(const FieldIter& other) { return i_ == other.i_; } + + private: + const upb_msgdef *m_; + int i_; + }; + + class FieldAccessor { + public: + explicit FieldAccessor(const upb_msgdef* md) : md_(md) {} + FieldIter begin() { return FieldIter(md_, 0); } + FieldIter end() { return FieldIter(md_, upb_msgdef_fieldcount(md_)); } + + private: + const upb_msgdef* md_; + }; + + class OneofIter { + public: + explicit OneofIter(const upb_msgdef *m, int i) : m_(m), i_(i) {} + void operator++() { i_++; } + + OneofDefPtr operator*() { return OneofDefPtr(upb_msgdef_oneof(m_, i_)); } + bool operator!=(const OneofIter& other) { return i_ != other.i_; } + bool operator==(const OneofIter& other) { return i_ == other.i_; } + + private: + const upb_msgdef *m_; + int i_; + }; + + class OneofAccessor { + public: + explicit OneofAccessor(const upb_msgdef* md) : md_(md) {} + OneofIter begin() { return OneofIter(md_, 0); } + OneofIter end() { return OneofIter(md_, upb_msgdef_oneofcount(md_)); } + + private: + const upb_msgdef* md_; + }; + + public: + FieldAccessor fields() const { return FieldAccessor(ptr()); } + OneofAccessor oneofs() const { return OneofAccessor(ptr()); } + + private: + const upb_msgdef* ptr_; +}; + +class EnumDefPtr { + public: + EnumDefPtr() : ptr_(nullptr) {} + explicit EnumDefPtr(const upb_enumdef* ptr) : ptr_(ptr) {} + + const upb_enumdef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + const char* full_name() const { return upb_enumdef_fullname(ptr_); } + const char* name() const { return upb_enumdef_name(ptr_); } + + // The value that is used as the default when no field default is specified. + // If not set explicitly, the first value that was added will be used. + // The default value must be a member of the enum. + // Requires that value_count() > 0. + int32_t default_value() const { return upb_enumdef_default(ptr_); } + + // Returns the number of values currently defined in the enum. Note that + // multiple names can refer to the same number, so this may be greater than + // the total number of unique numbers. + int value_count() const { return upb_enumdef_numvals(ptr_); } + + // Lookups from name to integer, returning true if found. + bool FindValueByName(const char* name, int32_t* num) const { + return upb_enumdef_ntoiz(ptr_, name, num); + } + + // Finds the name corresponding to the given number, or NULL if none was + // found. If more than one name corresponds to this number, returns the + // first one that was added. + const char* FindValueByNumber(int32_t num) const { + return upb_enumdef_iton(ptr_, num); + } + + // Iteration over name/value pairs. The order is undefined. + // Adding an enum val invalidates any iterators. + // + // TODO: make compatible with range-for, with elements as pairs? + class Iterator { + public: + explicit Iterator(EnumDefPtr e) { upb_enum_begin(&iter_, e.ptr()); } + + int32_t number() { return upb_enum_iter_number(&iter_); } + const char* name() { return upb_enum_iter_name(&iter_); } + bool Done() { return upb_enum_done(&iter_); } + void Next() { return upb_enum_next(&iter_); } + + private: + upb_enum_iter iter_; + }; + + private: + const upb_enumdef* ptr_; +}; + +// Class that represents a .proto file with some things defined in it. +// +// Many users won't care about FileDefs, but they are necessary if you want to +// read the values of file-level options. +class FileDefPtr { + public: + explicit FileDefPtr(const upb_filedef* ptr) : ptr_(ptr) {} + + const upb_filedef* ptr() const { return ptr_; } + explicit operator bool() const { return ptr_ != nullptr; } + + // Get/set name of the file (eg. "foo/bar.proto"). + const char* name() const { return upb_filedef_name(ptr_); } + + // Package name for definitions inside the file (eg. "foo.bar"). + const char* package() const { return upb_filedef_package(ptr_); } + + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + const char* phpprefix() const { return upb_filedef_phpprefix(ptr_); } + + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + const char* phpnamespace() const { return upb_filedef_phpnamespace(ptr_); } + + // Syntax for the file. Defaults to proto2. + upb_syntax_t syntax() const { return upb_filedef_syntax(ptr_); } + + // Get the list of dependencies from the file. These are returned in the + // order that they were added to the FileDefPtr. + int dependency_count() const { return upb_filedef_depcount(ptr_); } + const FileDefPtr dependency(int index) const { + return FileDefPtr(upb_filedef_dep(ptr_, index)); + } + + private: + const upb_filedef* ptr_; +}; + +// Non-const methods in upb::SymbolTable are NOT thread-safe. +class SymbolTable { + public: + SymbolTable() : ptr_(upb_symtab_new(), upb_symtab_free) {} + explicit SymbolTable(upb_symtab* s) : ptr_(s, upb_symtab_free) {} + + const upb_symtab* ptr() const { return ptr_.get(); } + upb_symtab* ptr() { return ptr_.get(); } + + // Finds an entry in the symbol table with this exact name. If not found, + // returns NULL. + MessageDefPtr LookupMessage(const char* sym) const { + return MessageDefPtr(upb_symtab_lookupmsg(ptr_.get(), sym)); + } + + EnumDefPtr LookupEnum(const char* sym) const { + return EnumDefPtr(upb_symtab_lookupenum(ptr_.get(), sym)); + } + + FileDefPtr LookupFile(const char* name) const { + return FileDefPtr(upb_symtab_lookupfile(ptr_.get(), name)); + } + + // TODO: iteration? + + // Adds the given serialized FileDescriptorProto to the pool. + FileDefPtr AddFile(const google_protobuf_FileDescriptorProto* file_proto, + Status* status) { + return FileDefPtr( + upb_symtab_addfile(ptr_.get(), file_proto, status->ptr())); + } + + private: + std::unique_ptr<upb_symtab, decltype(&upb_symtab_free)> ptr_; +}; + +inline MessageDefPtr FieldDefPtr::message_subdef() const { + return MessageDefPtr(upb_fielddef_msgsubdef(ptr_)); +} + +inline MessageDefPtr FieldDefPtr::containing_type() const { + return MessageDefPtr(upb_fielddef_containingtype(ptr_)); +} + +inline MessageDefPtr OneofDefPtr::containing_type() const { + return MessageDefPtr(upb_oneofdef_containingtype(ptr_)); +} + +inline OneofDefPtr FieldDefPtr::containing_oneof() const { + return OneofDefPtr(upb_fielddef_containingoneof(ptr_)); +} + +inline EnumDefPtr FieldDefPtr::enum_subdef() const { + return EnumDefPtr(upb_fielddef_enumsubdef(ptr_)); +} + +} // namespace upb + +#endif // UPB_DEF_HPP_ diff --git a/contrib/libs/grpc/third_party/upb/upb/encode.c b/contrib/libs/grpc/third_party/upb/upb/encode.c index a6ce62bfa5..f73ff09f8e 100644 --- a/contrib/libs/grpc/third_party/upb/upb/encode.c +++ b/contrib/libs/grpc/third_party/upb/upb/encode.c @@ -2,35 +2,39 @@ #include "upb/encode.h" +#include <setjmp.h> #include <string.h> #include "upb/msg.h" #include "upb/upb.h" +/* Must be last. */ #include "upb/port_def.inc" #define UPB_PB_VARINT_MAX_LEN 10 -#define CHK(x) do { if (!(x)) { return false; } } while(0) -static size_t upb_encode_varint(uint64_t val, char *buf) { - size_t i; - if (val < 128) { buf[0] = val; return 1; } - i = 0; - while (val) { +UPB_NOINLINE +static size_t encode_varint64(uint64_t val, char *buf) { + size_t i = 0; + do { uint8_t byte = val & 0x7fU; val >>= 7; if (val) byte |= 0x80U; buf[i++] = byte; - } + } while (val); return i; } -static uint32_t upb_zzencode_32(int32_t n) { return ((uint32_t)n << 1) ^ (n >> 31); } -static uint64_t upb_zzencode_64(int64_t n) { return ((uint64_t)n << 1) ^ (n >> 63); } +static uint32_t encode_zz32(int32_t n) { return ((uint32_t)n << 1) ^ (n >> 31); } +static uint64_t encode_zz64(int64_t n) { return ((uint64_t)n << 1) ^ (n >> 63); } typedef struct { + jmp_buf err; upb_alloc *alloc; char *buf, *ptr, *limit; + int options; + int depth; + _upb_mapsorter sorter; } upb_encstate; static size_t upb_roundup_pow2(size_t bytes) { @@ -41,11 +45,17 @@ static size_t upb_roundup_pow2(size_t bytes) { return ret; } -static bool upb_encode_growbuffer(upb_encstate *e, size_t bytes) { +UPB_NORETURN static void encode_err(upb_encstate *e) { + UPB_LONGJMP(e->err, 1); +} + +UPB_NOINLINE +static void encode_growbuffer(upb_encstate *e, size_t bytes) { size_t old_size = e->limit - e->buf; size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); char *new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); - CHK(new_buf); + + if (!new_buf) encode_err(e); /* We want previous data at the end, realloc() put it at the beginning. */ if (old_size > 0) { @@ -55,99 +65,116 @@ static bool upb_encode_growbuffer(upb_encstate *e, size_t bytes) { e->ptr = new_buf + new_size - (e->limit - e->ptr); e->limit = new_buf + new_size; e->buf = new_buf; - return true; + + e->ptr -= bytes; } /* Call to ensure that at least "bytes" bytes are available for writing at * e->ptr. Returns false if the bytes could not be allocated. */ -static bool upb_encode_reserve(upb_encstate *e, size_t bytes) { - CHK(UPB_LIKELY((size_t)(e->ptr - e->buf) >= bytes) || - upb_encode_growbuffer(e, bytes)); +UPB_FORCEINLINE +static void encode_reserve(upb_encstate *e, size_t bytes) { + if ((size_t)(e->ptr - e->buf) < bytes) { + encode_growbuffer(e, bytes); + return; + } e->ptr -= bytes; - return true; } /* Writes the given bytes to the buffer, handling reserve/advance. */ -static bool upb_put_bytes(upb_encstate *e, const void *data, size_t len) { - if (len == 0) return true; - CHK(upb_encode_reserve(e, len)); +static void encode_bytes(upb_encstate *e, const void *data, size_t len) { + if (len == 0) return; /* memcpy() with zero size is UB */ + encode_reserve(e, len); memcpy(e->ptr, data, len); - return true; } -static bool upb_put_fixed64(upb_encstate *e, uint64_t val) { +static void encode_fixed64(upb_encstate *e, uint64_t val) { val = _upb_be_swap64(val); - return upb_put_bytes(e, &val, sizeof(uint64_t)); + encode_bytes(e, &val, sizeof(uint64_t)); } -static bool upb_put_fixed32(upb_encstate *e, uint32_t val) { +static void encode_fixed32(upb_encstate *e, uint32_t val) { val = _upb_be_swap32(val); - return upb_put_bytes(e, &val, sizeof(uint32_t)); + encode_bytes(e, &val, sizeof(uint32_t)); } -static bool upb_put_varint(upb_encstate *e, uint64_t val) { +UPB_NOINLINE +static void encode_longvarint(upb_encstate *e, uint64_t val) { size_t len; char *start; - CHK(upb_encode_reserve(e, UPB_PB_VARINT_MAX_LEN)); - len = upb_encode_varint(val, e->ptr); + + encode_reserve(e, UPB_PB_VARINT_MAX_LEN); + len = encode_varint64(val, e->ptr); start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; memmove(start, e->ptr, len); e->ptr = start; - return true; } -static bool upb_put_double(upb_encstate *e, double d) { +UPB_FORCEINLINE +static void encode_varint(upb_encstate *e, uint64_t val) { + if (val < 128 && e->ptr != e->buf) { + --e->ptr; + *e->ptr = val; + } else { + encode_longvarint(e, val); + } +} + +static void encode_double(upb_encstate *e, double d) { uint64_t u64; UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); memcpy(&u64, &d, sizeof(uint64_t)); - return upb_put_fixed64(e, u64); + encode_fixed64(e, u64); } -static bool upb_put_float(upb_encstate *e, float d) { +static void encode_float(upb_encstate *e, float d) { uint32_t u32; UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); memcpy(&u32, &d, sizeof(uint32_t)); - return upb_put_fixed32(e, u32); + encode_fixed32(e, u32); } -static bool upb_put_tag(upb_encstate *e, int field_number, int wire_type) { - return upb_put_varint(e, (field_number << 3) | wire_type); +static void encode_tag(upb_encstate *e, uint32_t field_number, + uint8_t wire_type) { + encode_varint(e, (field_number << 3) | wire_type); } -static bool upb_put_fixedarray(upb_encstate *e, const upb_array *arr, +static void encode_fixedarray(upb_encstate *e, const upb_array *arr, size_t elem_size, uint32_t tag) { size_t bytes = arr->len * elem_size; const char* data = _upb_array_constptr(arr); const char* ptr = data + bytes - elem_size; if (tag) { while (true) { - CHK(upb_put_bytes(e, ptr, elem_size) && upb_put_varint(e, tag)); + encode_bytes(e, ptr, elem_size); + encode_varint(e, tag); if (ptr == data) break; ptr -= elem_size; } - return true; } else { - return upb_put_bytes(e, data, bytes) && upb_put_varint(e, bytes); + encode_bytes(e, data, bytes); } } -bool upb_encode_message(upb_encstate *e, const char *msg, - const upb_msglayout *m, size_t *size); +static void encode_message(upb_encstate *e, const char *msg, + const upb_msglayout *m, size_t *size); -static bool upb_encode_scalarfield(upb_encstate *e, const void *_field_mem, - const upb_msglayout *m, - const upb_msglayout_field *f, - bool skip_zero_value) { +static void encode_scalar(upb_encstate *e, const void *_field_mem, + const upb_msglayout *m, const upb_msglayout_field *f, + bool skip_zero_value) { const char *field_mem = _field_mem; -#define CASE(ctype, type, wire_type, encodeval) do { \ - ctype val = *(ctype*)field_mem; \ - if (skip_zero_value && val == 0) { \ - return true; \ - } \ - return upb_put_ ## type(e, encodeval) && \ - upb_put_tag(e, f->number, wire_type); \ -} while(0) + int wire_type; + +#define CASE(ctype, type, wtype, encodeval) \ + { \ + ctype val = *(ctype *)field_mem; \ + if (skip_zero_value && val == 0) { \ + return; \ + } \ + encode_##type(e, encodeval); \ + wire_type = wtype; \ + break; \ + } switch (f->descriptortype) { case UPB_DESCRIPTOR_TYPE_DOUBLE: @@ -171,90 +198,95 @@ static bool upb_encode_scalarfield(upb_encstate *e, const void *_field_mem, case UPB_DESCRIPTOR_TYPE_BOOL: CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val); case UPB_DESCRIPTOR_TYPE_SINT32: - CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_32(val)); + CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, encode_zz32(val)); case UPB_DESCRIPTOR_TYPE_SINT64: - CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_64(val)); + CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, encode_zz64(val)); case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_BYTES: { upb_strview view = *(upb_strview*)field_mem; if (skip_zero_value && view.size == 0) { - return true; + return; } - return upb_put_bytes(e, view.data, view.size) && - upb_put_varint(e, view.size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); + encode_bytes(e, view.data, view.size); + encode_varint(e, view.size); + wire_type = UPB_WIRE_TYPE_DELIMITED; + break; } case UPB_DESCRIPTOR_TYPE_GROUP: { size_t size; void *submsg = *(void **)field_mem; const upb_msglayout *subm = m->submsgs[f->submsg_index]; if (submsg == NULL) { - return true; + return; } - return upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) && - upb_encode_message(e, submsg, subm, &size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP); + if (--e->depth == 0) encode_err(e); + encode_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP); + encode_message(e, submsg, subm, &size); + wire_type = UPB_WIRE_TYPE_START_GROUP; + e->depth++; + break; } case UPB_DESCRIPTOR_TYPE_MESSAGE: { size_t size; void *submsg = *(void **)field_mem; const upb_msglayout *subm = m->submsgs[f->submsg_index]; if (submsg == NULL) { - return true; + return; } - return upb_encode_message(e, submsg, subm, &size) && - upb_put_varint(e, size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); + if (--e->depth == 0) encode_err(e); + encode_message(e, submsg, subm, &size); + encode_varint(e, size); + wire_type = UPB_WIRE_TYPE_DELIMITED; + e->depth++; + break; } + default: + UPB_UNREACHABLE(); } #undef CASE - UPB_UNREACHABLE(); + + encode_tag(e, f->number, wire_type); } -static bool upb_encode_array(upb_encstate *e, const char *field_mem, - const upb_msglayout *m, - const upb_msglayout_field *f) { +static void encode_array(upb_encstate *e, const char *field_mem, + const upb_msglayout *m, const upb_msglayout_field *f) { const upb_array *arr = *(const upb_array**)field_mem; bool packed = f->label == _UPB_LABEL_PACKED; + size_t pre_len = e->limit - e->ptr; if (arr == NULL || arr->len == 0) { - return true; + return; } #define VARINT_CASE(ctype, encode) \ { \ const ctype *start = _upb_array_constptr(arr); \ const ctype *ptr = start + arr->len; \ - size_t pre_len = e->limit - e->ptr; \ uint32_t tag = packed ? 0 : (f->number << 3) | UPB_WIRE_TYPE_VARINT; \ do { \ ptr--; \ - CHK(upb_put_varint(e, encode)); \ - if (tag) CHK(upb_put_varint(e, tag)); \ + encode_varint(e, encode); \ + if (tag) encode_varint(e, tag); \ } while (ptr != start); \ - if (!tag) CHK(upb_put_varint(e, e->limit - e->ptr - pre_len)); \ } \ - break; \ - do { \ - ; \ - } while (0) + break; #define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) switch (f->descriptortype) { case UPB_DESCRIPTOR_TYPE_DOUBLE: - CHK(upb_put_fixedarray(e, arr, sizeof(double), TAG(UPB_WIRE_TYPE_64BIT))); + encode_fixedarray(e, arr, sizeof(double), TAG(UPB_WIRE_TYPE_64BIT)); break; case UPB_DESCRIPTOR_TYPE_FLOAT: - CHK(upb_put_fixedarray(e, arr, sizeof(float), TAG(UPB_WIRE_TYPE_32BIT))); + encode_fixedarray(e, arr, sizeof(float), TAG(UPB_WIRE_TYPE_32BIT)); break; case UPB_DESCRIPTOR_TYPE_SFIXED64: case UPB_DESCRIPTOR_TYPE_FIXED64: - CHK(upb_put_fixedarray(e, arr, sizeof(uint64_t), TAG(UPB_WIRE_TYPE_64BIT))); + encode_fixedarray(e, arr, sizeof(uint64_t), TAG(UPB_WIRE_TYPE_64BIT)); break; case UPB_DESCRIPTOR_TYPE_FIXED32: case UPB_DESCRIPTOR_TYPE_SFIXED32: - CHK(upb_put_fixedarray(e, arr, sizeof(uint32_t), TAG(UPB_WIRE_TYPE_32BIT))); + encode_fixedarray(e, arr, sizeof(uint32_t), TAG(UPB_WIRE_TYPE_32BIT)); break; case UPB_DESCRIPTOR_TYPE_INT64: case UPB_DESCRIPTOR_TYPE_UINT64: @@ -267,154 +299,180 @@ static bool upb_encode_array(upb_encstate *e, const char *field_mem, case UPB_DESCRIPTOR_TYPE_BOOL: VARINT_CASE(bool, *ptr); case UPB_DESCRIPTOR_TYPE_SINT32: - VARINT_CASE(int32_t, upb_zzencode_32(*ptr)); + VARINT_CASE(int32_t, encode_zz32(*ptr)); case UPB_DESCRIPTOR_TYPE_SINT64: - VARINT_CASE(int64_t, upb_zzencode_64(*ptr)); + VARINT_CASE(int64_t, encode_zz64(*ptr)); case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_BYTES: { const upb_strview *start = _upb_array_constptr(arr); const upb_strview *ptr = start + arr->len; do { ptr--; - CHK(upb_put_bytes(e, ptr->data, ptr->size) && - upb_put_varint(e, ptr->size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); + encode_bytes(e, ptr->data, ptr->size); + encode_varint(e, ptr->size); + encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); } while (ptr != start); - return true; + return; } case UPB_DESCRIPTOR_TYPE_GROUP: { const void *const*start = _upb_array_constptr(arr); const void *const*ptr = start + arr->len; const upb_msglayout *subm = m->submsgs[f->submsg_index]; + if (--e->depth == 0) encode_err(e); do { size_t size; ptr--; - CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) && - upb_encode_message(e, *ptr, subm, &size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP)); + encode_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP); + encode_message(e, *ptr, subm, &size); + encode_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP); } while (ptr != start); - return true; + e->depth++; + return; } case UPB_DESCRIPTOR_TYPE_MESSAGE: { const void *const*start = _upb_array_constptr(arr); const void *const*ptr = start + arr->len; const upb_msglayout *subm = m->submsgs[f->submsg_index]; + if (--e->depth == 0) encode_err(e); do { size_t size; ptr--; - CHK(upb_encode_message(e, *ptr, subm, &size) && - upb_put_varint(e, size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); + encode_message(e, *ptr, subm, &size); + encode_varint(e, size); + encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); } while (ptr != start); - return true; + e->depth++; + return; } } #undef VARINT_CASE if (packed) { - CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); + encode_varint(e, e->limit - e->ptr - pre_len); + encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); } - return true; } -static bool upb_encode_map(upb_encstate *e, const char *field_mem, - const upb_msglayout *m, - const upb_msglayout_field *f) { +static void encode_mapentry(upb_encstate *e, uint32_t number, + const upb_msglayout *layout, + const upb_map_entry *ent) { + const upb_msglayout_field *key_field = &layout->fields[0]; + const upb_msglayout_field *val_field = &layout->fields[1]; + size_t pre_len = e->limit - e->ptr; + size_t size; + encode_scalar(e, &ent->v, layout, val_field, false); + encode_scalar(e, &ent->k, layout, key_field, false); + size = (e->limit - e->ptr) - pre_len; + encode_varint(e, size); + encode_tag(e, number, UPB_WIRE_TYPE_DELIMITED); +} + +static void encode_map(upb_encstate *e, const char *field_mem, + const upb_msglayout *m, const upb_msglayout_field *f) { const upb_map *map = *(const upb_map**)field_mem; - const upb_msglayout *entry = m->submsgs[f->submsg_index]; - const upb_msglayout_field *key_field = &entry->fields[0]; - const upb_msglayout_field *val_field = &entry->fields[1]; - upb_strtable_iter i; - if (map == NULL) { - return true; - } + const upb_msglayout *layout = m->submsgs[f->submsg_index]; + UPB_ASSERT(layout->field_count == 2); + + if (map == NULL) return; - upb_strtable_begin(&i, &map->table); - for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { - size_t pre_len = e->limit - e->ptr; - size_t size; - upb_strview key = upb_strtable_iter_key(&i); - const upb_value val = upb_strtable_iter_value(&i); + if (e->options & UPB_ENCODE_DETERMINISTIC) { + _upb_sortedmap sorted; + _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, + &sorted); upb_map_entry ent; - _upb_map_fromkey(key, &ent.k, map->key_size); - _upb_map_fromvalue(val, &ent.v, map->val_size); - CHK(upb_encode_scalarfield(e, &ent.v, entry, val_field, false)); - CHK(upb_encode_scalarfield(e, &ent.k, entry, key_field, false)); - size = (e->limit - e->ptr) - pre_len; - CHK(upb_put_varint(e, size)); - CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); + while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { + encode_mapentry(e, f->number, layout, &ent); + } + _upb_mapsorter_popmap(&e->sorter, &sorted); + } else { + upb_strtable_iter i; + upb_strtable_begin(&i, &map->table); + for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_strview key = upb_strtable_iter_key(&i); + const upb_value val = upb_strtable_iter_value(&i); + upb_map_entry ent; + _upb_map_fromkey(key, &ent.k, map->key_size); + _upb_map_fromvalue(val, &ent.v, map->val_size); + encode_mapentry(e, f->number, layout, &ent); + } } - - return true; } +static void encode_scalarfield(upb_encstate *e, const char *msg, + const upb_msglayout *m, + const upb_msglayout_field *f) { + bool skip_empty = false; + if (f->presence == 0) { + /* Proto3 presence. */ + skip_empty = true; + } else if (f->presence > 0) { + /* Proto2 presence: hasbit. */ + if (!_upb_hasbit_field(msg, f)) return; + } else { + /* Field is in a oneof. */ + if (_upb_getoneofcase_field(msg, f) != f->number) return; + } + encode_scalar(e, msg + f->offset, m, f, skip_empty); +} -bool upb_encode_message(upb_encstate *e, const char *msg, - const upb_msglayout *m, size_t *size) { - int i; +static void encode_message(upb_encstate *e, const char *msg, + const upb_msglayout *m, size_t *size) { size_t pre_len = e->limit - e->ptr; - const char *unknown; - size_t unknown_size; + const upb_msglayout_field *f = &m->fields[m->field_count]; + const upb_msglayout_field *first = &m->fields[0]; - unknown = upb_msg_getunknown(msg, &unknown_size); + if ((e->options & UPB_ENCODE_SKIPUNKNOWN) == 0) { + size_t unknown_size; + const char *unknown = upb_msg_getunknown(msg, &unknown_size); - if (unknown) { - upb_put_bytes(e, unknown, unknown_size); + if (unknown) { + encode_bytes(e, unknown, unknown_size); + } } - for (i = m->field_count - 1; i >= 0; i--) { - const upb_msglayout_field *f = &m->fields[i]; - + while (f != first) { + f--; if (_upb_isrepeated(f)) { - CHK(upb_encode_array(e, msg + f->offset, m, f)); + encode_array(e, msg + f->offset, m, f); } else if (f->label == _UPB_LABEL_MAP) { - CHK(upb_encode_map(e, msg + f->offset, m, f)); + encode_map(e, msg + f->offset, m, f); } else { - bool skip_empty = false; - if (f->presence == 0) { - /* Proto3 presence. */ - skip_empty = true; - } else if (f->presence > 0) { - /* Proto2 presence: hasbit. */ - if (!_upb_hasbit_field(msg, f)) { - continue; - } - } else { - /* Field is in a oneof. */ - if (_upb_getoneofcase_field(msg, f) != f->number) { - continue; - } - } - CHK(upb_encode_scalarfield(e, msg + f->offset, m, f, skip_empty)); + encode_scalarfield(e, msg, m, f); } } *size = (e->limit - e->ptr) - pre_len; - return true; } -char *upb_encode(const void *msg, const upb_msglayout *m, upb_arena *arena, - size_t *size) { +char *upb_encode_ex(const void *msg, const upb_msglayout *m, int options, + upb_arena *arena, size_t *size) { upb_encstate e; + unsigned depth = (unsigned)options >> 16; + e.alloc = upb_arena_alloc(arena); e.buf = NULL; e.limit = NULL; e.ptr = NULL; + e.depth = depth ? depth : 64; + e.options = options; + _upb_mapsorter_init(&e.sorter); + char *ret = NULL; - if (!upb_encode_message(&e, msg, m, size)) { + if (UPB_SETJMP(e.err)) { *size = 0; - return NULL; - } - - *size = e.limit - e.ptr; - - if (*size == 0) { - static char ch; - return &ch; + ret = NULL; } else { - UPB_ASSERT(e.ptr); - return e.ptr; + encode_message(&e, msg, m, size); + *size = e.limit - e.ptr; + if (*size == 0) { + static char ch; + ret = &ch; + } else { + UPB_ASSERT(e.ptr); + ret = e.ptr; + } } -} -#undef CHK + _upb_mapsorter_destroy(&e.sorter); + return ret; +} diff --git a/contrib/libs/grpc/third_party/upb/upb/encode.h b/contrib/libs/grpc/third_party/upb/upb/encode.h index 6842777058..d3c1dc9606 100644 --- a/contrib/libs/grpc/third_party/upb/upb/encode.h +++ b/contrib/libs/grpc/third_party/upb/upb/encode.h @@ -7,12 +7,37 @@ #include "upb/msg.h" +/* Must be last. */ +#include "upb/port_def.inc" + #ifdef __cplusplus extern "C" { #endif -char *upb_encode(const void *msg, const upb_msglayout *l, upb_arena *arena, - size_t *size); +enum { + /* If set, the results of serializing will be deterministic across all + * instances of this binary. There are no guarantees across different + * binary builds. + * + * If your proto contains maps, the encoder will need to malloc()/free() + * memory during encode. */ + UPB_ENCODE_DETERMINISTIC = 1, + + /* When set, unknown fields are not printed. */ + UPB_ENCODE_SKIPUNKNOWN = 2, +}; + +#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) + +char *upb_encode_ex(const void *msg, const upb_msglayout *l, int options, + upb_arena *arena, size_t *size); + +UPB_INLINE char *upb_encode(const void *msg, const upb_msglayout *l, + upb_arena *arena, size_t *size) { + return upb_encode_ex(msg, l, 0, arena, size); +} + +#include "upb/port_undef.inc" #ifdef __cplusplus } /* extern "C" */ diff --git a/contrib/libs/grpc/third_party/upb/upb/msg.c b/contrib/libs/grpc/third_party/upb/upb/msg.c index 25747c8481..876a06d6fa 100644 --- a/contrib/libs/grpc/third_party/upb/upb/msg.c +++ b/contrib/libs/grpc/third_party/upb/upb/msg.c @@ -7,106 +7,67 @@ /** upb_msg *******************************************************************/ -static const char _upb_fieldtype_to_sizelg2[12] = { - 0, - 0, /* UPB_TYPE_BOOL */ - 2, /* UPB_TYPE_FLOAT */ - 2, /* UPB_TYPE_INT32 */ - 2, /* UPB_TYPE_UINT32 */ - 2, /* UPB_TYPE_ENUM */ - UPB_SIZE(2, 3), /* UPB_TYPE_MESSAGE */ - 3, /* UPB_TYPE_DOUBLE */ - 3, /* UPB_TYPE_INT64 */ - 3, /* UPB_TYPE_UINT64 */ - UPB_SIZE(3, 4), /* UPB_TYPE_STRING */ - UPB_SIZE(3, 4), /* UPB_TYPE_BYTES */ -}; - -static uintptr_t tag_arrptr(void* ptr, int elem_size_lg2) { - UPB_ASSERT(elem_size_lg2 <= 4); - return (uintptr_t)ptr | elem_size_lg2; -} - -static int upb_msg_internalsize(const upb_msglayout *l) { - return sizeof(upb_msg_internal) - l->extendable * sizeof(void *); -} - -static size_t upb_msg_sizeof(const upb_msglayout *l) { - return l->size + upb_msg_internalsize(l); -} +static const size_t overhead = sizeof(upb_msg_internal); static const upb_msg_internal *upb_msg_getinternal_const(const upb_msg *msg) { ptrdiff_t size = sizeof(upb_msg_internal); - return UPB_PTR_AT(msg, -size, upb_msg_internal); + return (upb_msg_internal*)((char*)msg - size); } -static upb_msg_internal *upb_msg_getinternal(upb_msg *msg) { - return (upb_msg_internal*)upb_msg_getinternal_const(msg); +upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a) { + return _upb_msg_new_inl(l, a); } void _upb_msg_clear(upb_msg *msg, const upb_msglayout *l) { - ptrdiff_t internal = upb_msg_internalsize(l); - void *mem = UPB_PTR_AT(msg, -internal, char); - memset(mem, 0, l->size + internal); -} - -upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a) { - void *mem = upb_arena_malloc(a, upb_msg_sizeof(l)); - upb_msg *msg; - - if (!mem) { - return NULL; - } - - msg = UPB_PTR_AT(mem, upb_msg_internalsize(l), upb_msg); - _upb_msg_clear(msg, l); - return msg; + void *mem = UPB_PTR_AT(msg, -sizeof(upb_msg_internal), char); + memset(mem, 0, upb_msg_sizeof(l)); } bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, upb_arena *arena) { + upb_msg_internal *in = upb_msg_getinternal(msg); - if (len > in->unknown_size - in->unknown_len) { - upb_alloc *alloc = upb_arena_alloc(arena); - size_t need = in->unknown_size + len; - size_t newsize = UPB_MAX(in->unknown_size * 2, need); - void *mem = upb_realloc(alloc, in->unknown, in->unknown_size, newsize); - if (!mem) return false; - in->unknown = mem; - in->unknown_size = newsize; + if (!in->unknown) { + size_t size = 128; + while (size < len) size *= 2; + in->unknown = upb_arena_malloc(arena, size + overhead); + if (!in->unknown) return false; + in->unknown->size = size; + in->unknown->len = 0; + } else if (in->unknown->size - in->unknown->len < len) { + size_t need = in->unknown->len + len; + size_t size = in->unknown->size; + while (size < need) size *= 2; + in->unknown = upb_arena_realloc( + arena, in->unknown, in->unknown->size + overhead, size + overhead); + if (!in->unknown) return false; + in->unknown->size = size; } - memcpy(in->unknown + in->unknown_len, data, len); - in->unknown_len += len; + memcpy(UPB_PTR_AT(in->unknown + 1, in->unknown->len, char), data, len); + in->unknown->len += len; return true; } void _upb_msg_discardunknown_shallow(upb_msg *msg) { upb_msg_internal *in = upb_msg_getinternal(msg); - in->unknown_len = 0; + if (in->unknown) { + in->unknown->len = 0; + } } const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) { const upb_msg_internal *in = upb_msg_getinternal_const(msg); - *len = in->unknown_len; - return in->unknown; -} - -/** upb_array *****************************************************************/ - -upb_array *_upb_array_new(upb_arena *a, upb_fieldtype_t type) { - upb_array *arr = upb_arena_malloc(a, sizeof(upb_array)); - - if (!arr) { + if (in->unknown) { + *len = in->unknown->len; + return (char*)(in->unknown + 1); + } else { + *len = 0; return NULL; } - - arr->data = tag_arrptr(NULL, _upb_fieldtype_to_sizelg2[type]); - arr->len = 0; - arr->size = 0; - - return arr; } +/** upb_array *****************************************************************/ + bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena) { size_t new_size = UPB_MAX(arr->size, 4); int elem_size_lg2 = arr->data & 7; @@ -124,16 +85,16 @@ bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena) { return false; } - arr->data = tag_arrptr(ptr, elem_size_lg2); + arr->data = _upb_tag_arrptr(ptr, elem_size_lg2); arr->size = new_size; return true; } -static upb_array *getorcreate_array(upb_array **arr_ptr, upb_fieldtype_t type, +static upb_array *getorcreate_array(upb_array **arr_ptr, int elem_size_lg2, upb_arena *arena) { upb_array *arr = *arr_ptr; if (!arr) { - arr = _upb_array_new(arena, type); + arr = _upb_array_new(arena, 4, elem_size_lg2); if (!arr) return NULL; *arr_ptr = arr; } @@ -141,22 +102,25 @@ static upb_array *getorcreate_array(upb_array **arr_ptr, upb_fieldtype_t type, } void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, - upb_fieldtype_t type, upb_arena *arena) { - upb_array *arr = getorcreate_array(arr_ptr, type, arena); - return arr && _upb_array_resize(arr, size, arena) ? _upb_array_ptr(arr) : NULL; + int elem_size_lg2, upb_arena *arena) { + upb_array *arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + return arr && _upb_array_resize(arr, size, arena) ? _upb_array_ptr(arr) + : NULL; } bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value, - upb_fieldtype_t type, upb_arena *arena) { - upb_array *arr = getorcreate_array(arr_ptr, type, arena); - size_t elem = arr->len; - int lg2 = _upb_fieldtype_to_sizelg2[type]; - char *data; + int elem_size_lg2, upb_arena *arena) { + upb_array *arr = getorcreate_array(arr_ptr, elem_size_lg2, arena); + if (!arr) return false; + + size_t elems = arr->len; - if (!arr || !_upb_array_resize(arr, elem + 1, arena)) return false; + if (!_upb_array_resize(arr, elems + 1, arena)) { + return false; + } - data = _upb_array_ptr(arr); - memcpy(data + (elem << lg2), value, 1 << lg2); + char *data = _upb_array_ptr(arr); + memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2); return true; } @@ -169,9 +133,124 @@ upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size) { return NULL; } - upb_strtable_init2(&map->table, UPB_CTYPE_INT32, upb_arena_alloc(a)); + upb_strtable_init2(&map->table, UPB_CTYPE_INT32, 4, upb_arena_alloc(a)); map->key_size = key_size; map->val_size = value_size; return map; } + +static void _upb_mapsorter_getkeys(const void *_a, const void *_b, void *a_key, + void *b_key, size_t size) { + const upb_tabent *const*a = _a; + const upb_tabent *const*b = _b; + upb_strview a_tabkey = upb_tabstrview((*a)->key); + upb_strview b_tabkey = upb_tabstrview((*b)->key); + _upb_map_fromkey(a_tabkey, a_key, size); + _upb_map_fromkey(b_tabkey, b_key, size); +} + +static int _upb_mapsorter_cmpi64(const void *_a, const void *_b) { + int64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a - b; +} + +static int _upb_mapsorter_cmpu64(const void *_a, const void *_b) { + uint64_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); + return a - b; +} + +static int _upb_mapsorter_cmpi32(const void *_a, const void *_b) { + int32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a - b; +} + +static int _upb_mapsorter_cmpu32(const void *_a, const void *_b) { + uint32_t a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); + return a - b; +} + +static int _upb_mapsorter_cmpbool(const void *_a, const void *_b) { + bool a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); + return a - b; +} + +static int _upb_mapsorter_cmpstr(const void *_a, const void *_b) { + upb_strview a, b; + _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); + size_t common_size = UPB_MIN(a.size, b.size); + int cmp = memcmp(a.data, b.data, common_size); + if (cmp) return cmp; + return a.size - b.size; +} + +bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type, + const upb_map *map, _upb_sortedmap *sorted) { + int map_size = _upb_map_size(map); + sorted->start = s->size; + sorted->pos = sorted->start; + sorted->end = sorted->start + map_size; + + /* Grow s->entries if necessary. */ + if (sorted->end > s->cap) { + s->cap = _upb_lg2ceilsize(sorted->end); + s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); + if (!s->entries) return false; + } + + s->size = sorted->end; + + /* Copy non-empty entries from the table to s->entries. */ + upb_tabent const**dst = &s->entries[sorted->start]; + const upb_tabent *src = map->table.t.entries; + const upb_tabent *end = src + upb_table_size(&map->table.t); + for (; src < end; src++) { + if (!upb_tabent_isempty(src)) { + *dst = src; + dst++; + } + } + UPB_ASSERT(dst == &s->entries[sorted->end]); + + /* Sort entries according to the key type. */ + + int (*compar)(const void *, const void *); + + switch (key_type) { + case UPB_DESCRIPTOR_TYPE_INT64: + case UPB_DESCRIPTOR_TYPE_SFIXED64: + case UPB_DESCRIPTOR_TYPE_SINT64: + compar = _upb_mapsorter_cmpi64; + break; + case UPB_DESCRIPTOR_TYPE_UINT64: + case UPB_DESCRIPTOR_TYPE_FIXED64: + compar = _upb_mapsorter_cmpu64; + break; + case UPB_DESCRIPTOR_TYPE_INT32: + case UPB_DESCRIPTOR_TYPE_SINT32: + case UPB_DESCRIPTOR_TYPE_SFIXED32: + case UPB_DESCRIPTOR_TYPE_ENUM: + compar = _upb_mapsorter_cmpi32; + break; + case UPB_DESCRIPTOR_TYPE_UINT32: + case UPB_DESCRIPTOR_TYPE_FIXED32: + compar = _upb_mapsorter_cmpu32; + break; + case UPB_DESCRIPTOR_TYPE_BOOL: + compar = _upb_mapsorter_cmpbool; + break; + case UPB_DESCRIPTOR_TYPE_STRING: + compar = _upb_mapsorter_cmpstr; + break; + default: + UPB_UNREACHABLE(); + } + + qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); + return true; +} diff --git a/contrib/libs/grpc/third_party/upb/upb/msg.h b/contrib/libs/grpc/third_party/upb/upb/msg.h index 695c278b21..9b4557ac18 100644 --- a/contrib/libs/grpc/third_party/upb/upb/msg.h +++ b/contrib/libs/grpc/third_party/upb/upb/msg.h @@ -9,11 +9,13 @@ #define UPB_MSG_H_ #include <stdint.h> +#include <stdlib.h> #include <string.h> #include "upb/table.int.h" #include "upb/upb.h" +/* Must be last. */ #include "upb/port_def.inc" #ifdef __cplusplus @@ -46,6 +48,18 @@ typedef struct { uint8_t label; /* google.protobuf.Label or _UPB_LABEL_* above. */ } upb_msglayout_field; +struct upb_decstate; +struct upb_msglayout; + +typedef const char *_upb_field_parser(struct upb_decstate *d, const char *ptr, + upb_msg *msg, intptr_t table, + uint64_t hasbits, uint64_t data); + +typedef struct { + uint64_t field_data; + _upb_field_parser *field_parser; +} _upb_fasttable_entry; + typedef struct upb_msglayout { const struct upb_msglayout *const* submsgs; const upb_msglayout_field *fields; @@ -54,6 +68,10 @@ typedef struct upb_msglayout { uint16_t size; uint16_t field_count; bool extendable; + uint8_t table_mask; + /* To constant-initialize the tables of variable length, we need a flexible + * array member, and we need to compile in C99 mode. */ + _upb_fasttable_entry fasttable[]; } upb_msglayout; /** upb_msg *******************************************************************/ @@ -62,25 +80,42 @@ typedef struct upb_msglayout { * compatibility. We put these before the user's data. The user's upb_msg* * points after the upb_msg_internal. */ -/* Used when a message is not extendable. */ typedef struct { - char *unknown; - size_t unknown_len; - size_t unknown_size; -} upb_msg_internal; + uint32_t len; + uint32_t size; + /* Data follows. */ +} upb_msg_unknowndata; -/* Used when a message is extendable. */ +/* Used when a message is not extendable. */ typedef struct { - upb_inttable *extdict; - upb_msg_internal base; -} upb_msg_internal_withext; + upb_msg_unknowndata *unknown; +} upb_msg_internal; /* Maps upb_fieldtype_t -> memory size. */ extern char _upb_fieldtype_to_size[12]; +UPB_INLINE size_t upb_msg_sizeof(const upb_msglayout *l) { + return l->size + sizeof(upb_msg_internal); +} + +UPB_INLINE upb_msg *_upb_msg_new_inl(const upb_msglayout *l, upb_arena *a) { + size_t size = upb_msg_sizeof(l); + void *mem = upb_arena_malloc(a, size); + upb_msg *msg; + if (UPB_UNLIKELY(!mem)) return NULL; + msg = UPB_PTR_AT(mem, sizeof(upb_msg_internal), upb_msg); + memset(mem, 0, size); + return msg; +} + /* Creates a new messages with the given layout on the given arena. */ upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a); +UPB_INLINE upb_msg_internal *upb_msg_getinternal(upb_msg *msg) { + ptrdiff_t size = sizeof(upb_msg_internal); + return (upb_msg_internal*)((char*)msg - size); +} + /* Clears the given message. */ void _upb_msg_clear(upb_msg *msg, const upb_msglayout *l); @@ -173,27 +208,49 @@ typedef struct { uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ size_t len; /* Measured in elements. */ size_t size; /* Measured in elements. */ + uint64_t junk; } upb_array; UPB_INLINE const void *_upb_array_constptr(const upb_array *arr) { + UPB_ASSERT((arr->data & 7) <= 4); return (void*)(arr->data & ~(uintptr_t)7); } +UPB_INLINE uintptr_t _upb_array_tagptr(void* ptr, int elem_size_lg2) { + UPB_ASSERT(elem_size_lg2 <= 4); + return (uintptr_t)ptr | elem_size_lg2; +} + UPB_INLINE void *_upb_array_ptr(upb_array *arr) { return (void*)_upb_array_constptr(arr); } -/* Creates a new array on the given arena. */ -upb_array *_upb_array_new(upb_arena *a, upb_fieldtype_t type); +UPB_INLINE uintptr_t _upb_tag_arrptr(void* ptr, int elem_size_lg2) { + UPB_ASSERT(elem_size_lg2 <= 4); + UPB_ASSERT(((uintptr_t)ptr & 7) == 0); + return (uintptr_t)ptr | (unsigned)elem_size_lg2; +} + +UPB_INLINE upb_array *_upb_array_new(upb_arena *a, size_t init_size, + int elem_size_lg2) { + const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_array), 8); + const size_t bytes = sizeof(upb_array) + (init_size << elem_size_lg2); + upb_array *arr = (upb_array*)upb_arena_malloc(a, bytes); + if (!arr) return NULL; + arr->data = _upb_tag_arrptr(UPB_PTR_AT(arr, arr_size, void), elem_size_lg2); + arr->len = 0; + arr->size = init_size; + return arr; +} /* Resizes the capacity of the array to be at least min_size. */ bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena); /* Fallback functions for when the accessors require a resize. */ void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, - upb_fieldtype_t type, upb_arena *arena); + int elem_size_lg2, upb_arena *arena); bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value, - upb_fieldtype_t type, upb_arena *arena); + int elem_size_lg2, upb_arena *arena); UPB_INLINE bool _upb_array_reserve(upb_array *arr, size_t size, upb_arena *arena) { @@ -232,29 +289,28 @@ UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, } } -UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size, - upb_fieldtype_t type, - upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); +UPB_INLINE void *_upb_array_resize_accessor2(void *msg, size_t ofs, size_t size, + int elem_size_lg2, + upb_arena *arena) { + upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array *); upb_array *arr = *arr_ptr; if (!arr || arr->size < size) { - return _upb_array_resize_fallback(arr_ptr, size, type, arena); + return _upb_array_resize_fallback(arr_ptr, size, elem_size_lg2, arena); } arr->len = size; return _upb_array_ptr(arr); } - -UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs, - size_t elem_size, - upb_fieldtype_t type, - const void *value, - upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); +UPB_INLINE bool _upb_array_append_accessor2(void *msg, size_t ofs, + int elem_size_lg2, + const void *value, + upb_arena *arena) { + upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array *); + size_t elem_size = 1 << elem_size_lg2; upb_array *arr = *arr_ptr; - void* ptr; + void *ptr; if (!arr || arr->len == arr->size) { - return _upb_array_append_fallback(arr_ptr, value, type, arena); + return _upb_array_append_fallback(arr_ptr, value, elem_size_lg2, arena); } ptr = _upb_array_ptr(arr); memcpy(PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); @@ -262,6 +318,42 @@ UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs, return true; } +/* Used by old generated code, remove once all code has been regenerated. */ +UPB_INLINE int _upb_sizelg2(upb_fieldtype_t type) { + switch (type) { + case UPB_TYPE_BOOL: + return 0; + case UPB_TYPE_FLOAT: + case UPB_TYPE_INT32: + case UPB_TYPE_UINT32: + case UPB_TYPE_ENUM: + return 2; + case UPB_TYPE_MESSAGE: + return UPB_SIZE(2, 3); + case UPB_TYPE_DOUBLE: + case UPB_TYPE_INT64: + case UPB_TYPE_UINT64: + return 3; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + return UPB_SIZE(3, 4); + } + UPB_UNREACHABLE(); +} +UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size, + upb_fieldtype_t type, + upb_arena *arena) { + return _upb_array_resize_accessor2(msg, ofs, size, _upb_sizelg2(type), arena); +} +UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs, + size_t elem_size, upb_fieldtype_t type, + const void *value, + upb_arena *arena) { + (void)elem_size; + return _upb_array_append_accessor2(msg, ofs, _upb_sizelg2(type), value, + arena); +} + /** upb_map *******************************************************************/ /* Right now we use strmaps for everything. We'll likely want to use @@ -318,17 +410,17 @@ UPB_INLINE void _upb_map_fromkey(upb_strview key, void* out, size_t size) { } } -UPB_INLINE upb_value _upb_map_tovalue(const void *val, size_t size, - upb_arena *a) { - upb_value ret = {0}; +UPB_INLINE bool _upb_map_tovalue(const void *val, size_t size, upb_value *msgval, + upb_arena *a) { if (size == UPB_MAPTYPE_STRING) { upb_strview *strp = (upb_strview*)upb_arena_malloc(a, sizeof(*strp)); + if (!strp) return false; *strp = *(upb_strview*)val; - ret = upb_value_ptr(strp); + *msgval = upb_value_ptr(strp); } else { - memcpy(&ret, val, size); + memcpy(msgval, val, size); } - return ret; + return true; } UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { @@ -370,7 +462,8 @@ UPB_INLINE void* _upb_map_next(const upb_map *map, size_t *iter) { UPB_INLINE bool _upb_map_set(upb_map *map, const void *key, size_t key_size, void *val, size_t val_size, upb_arena *arena) { upb_strview strkey = _upb_map_tokey(key, key_size); - upb_value tabval = _upb_map_tovalue(val, val_size, arena); + upb_value tabval = {0}; + if (!_upb_map_tovalue(val, val_size, &tabval, arena)) return false; upb_alloc *a = upb_arena_alloc(arena); /* TODO(haberman): add overwrite operation to minimize number of lookups. */ @@ -462,6 +555,53 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size) } } +/** _upb_mapsorter *************************************************************/ + +/* _upb_mapsorter sorts maps and provides ordered iteration over the entries. + * Since maps can be recursive (map values can be messages which contain other maps). + * _upb_mapsorter can contain a stack of maps. */ + +typedef struct { + upb_tabent const**entries; + int size; + int cap; +} _upb_mapsorter; + +typedef struct { + int start; + int pos; + int end; +} _upb_sortedmap; + +UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter *s) { + s->entries = NULL; + s->size = 0; + s->cap = 0; +} + +UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter *s) { + if (s->entries) free(s->entries); +} + +bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type, + const upb_map *map, _upb_sortedmap *sorted); + +UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter *s, _upb_sortedmap *sorted) { + s->size = sorted->start; +} + +UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter *s, const upb_map *map, + _upb_sortedmap *sorted, + upb_map_entry *ent) { + if (sorted->pos == sorted->end) return false; + const upb_tabent *tabent = s->entries[sorted->pos++]; + upb_strview key = upb_tabstrview(tabent->key); + _upb_map_fromkey(key, &ent->k, map->key_size); + upb_value val = {tabent->val.val}; + _upb_map_fromvalue(val, &ent->v, map->val_size); + return true; +} + #undef PTR_AT #ifdef __cplusplus diff --git a/contrib/libs/grpc/third_party/upb/upb/port.c b/contrib/libs/grpc/third_party/upb/upb/port.c deleted file mode 100644 index 9ecf135167..0000000000 --- a/contrib/libs/grpc/third_party/upb/upb/port.c +++ /dev/null @@ -1,26 +0,0 @@ - -#include "upb/port_def.inc" - -#ifdef UPB_MSVC_VSNPRINTF -/* Visual C++ earlier than 2015 doesn't have standard C99 snprintf and - * vsnprintf. To support them, missing functions are manually implemented - * using the existing secure functions. */ -int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg) { - if (!s) { - return _vscprintf(format, arg); - } - int ret = _vsnprintf_s(s, n, _TRUNCATE, format, arg); - if (ret < 0) { - ret = _vscprintf(format, arg); - } - return ret; -} - -int msvc_snprintf(char* s, size_t n, const char* format, ...) { - va_list arg; - va_start(arg, format); - int ret = msvc_vsnprintf(s, n, format, arg); - va_end(arg); - return ret; -} -#endif diff --git a/contrib/libs/grpc/third_party/upb/upb/port_def.inc b/contrib/libs/grpc/third_party/upb/upb/port_def.inc index 2c144dc066..2cd1bb6985 100644 --- a/contrib/libs/grpc/third_party/upb/upb/port_def.inc +++ b/contrib/libs/grpc/third_party/upb/upb/port_def.inc @@ -20,6 +20,13 @@ * * This file is private and must not be included by users! */ + +#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ + (defined(__cplusplus) && __cplusplus >= 201103L) || \ + (defined(_MSC_VER) && _MSC_VER >= 1900)) +#error upb requires C99 or C++11 or MSVC >= 2015. +#endif + #include <stdint.h> #include <stddef.h> @@ -68,66 +75,21 @@ #define UPB_UNLIKELY(x) (x) #endif -/* Define UPB_BIG_ENDIAN manually if you're on big endian and your compiler - * doesn't provide these preprocessor symbols. */ -#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#define UPB_BIG_ENDIAN -#endif - /* Macros for function attributes on compilers that support them. */ #ifdef __GNUC__ #define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) #define UPB_NOINLINE __attribute__((noinline)) #define UPB_NORETURN __attribute__((__noreturn__)) +#elif defined(_MSC_VER) +#define UPB_NOINLINE +#define UPB_FORCEINLINE +#define UPB_NORETURN __declspec(noreturn) #else /* !defined(__GNUC__) */ #define UPB_FORCEINLINE #define UPB_NOINLINE #define UPB_NORETURN #endif -#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L -/* C99/C++11 versions. */ -#include <stdio.h> -#define _upb_snprintf snprintf -#define _upb_vsnprintf vsnprintf -#define _upb_va_copy(a, b) va_copy(a, b) -#elif defined(_MSC_VER) -/* Microsoft C/C++ versions. */ -#include <stdarg.h> -#include <stdio.h> -#if _MSC_VER < 1900 -int msvc_snprintf(char* s, size_t n, const char* format, ...); -int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg); -#define UPB_MSVC_VSNPRINTF -#define _upb_snprintf msvc_snprintf -#define _upb_vsnprintf msvc_vsnprintf -#else -#define _upb_snprintf snprintf -#define _upb_vsnprintf vsnprintf -#endif -#define _upb_va_copy(a, b) va_copy(a, b) -#elif defined __GNUC__ -/* A few hacky workarounds for functions not in C89. - * For internal use only! - * TODO(haberman): fix these by including our own implementations, or finding - * another workaround. - */ -#define _upb_snprintf __builtin_snprintf -#define _upb_vsnprintf __builtin_vsnprintf -#define _upb_va_copy(a, b) __va_copy(a, b) -#else -#error Need implementations of [v]snprintf and va_copy -#endif - -#ifdef __cplusplus -#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || \ - (defined(_MSC_VER) && _MSC_VER >= 1900) -/* C++11 is present */ -#else -#error upb requires C++11 for C++ support -#endif -#endif - #define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) #define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) @@ -155,25 +117,76 @@ int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg); #define UPB_ASSERT(expr) assert(expr) #endif -/* UPB_ASSERT_DEBUGVAR(): assert that uses functions or variables that only - * exist in debug mode. This turns into regular assert. */ -#define UPB_ASSERT_DEBUGVAR(expr) assert(expr) - #if defined(__GNUC__) || defined(__clang__) #define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) #else #define UPB_UNREACHABLE() do { assert(0); } while(0) #endif -/* UPB_INFINITY representing floating-point positive infinity. */ -#include <math.h> -#ifdef INFINITY -#define UPB_INFINITY INFINITY +/* UPB_SETJMP() / UPB_LONGJMP(): avoid setting/restoring signal mask. */ +#ifdef __APPLE__ +#define UPB_SETJMP(buf) _setjmp(buf) +#define UPB_LONGJMP(buf, val) _longjmp(buf, val) +#else +#define UPB_SETJMP(buf) setjmp(buf) +#define UPB_LONGJMP(buf, val) longjmp(buf, val) +#endif + +/* Configure whether fasttable is switched on or not. *************************/ + +#if defined(__x86_64__) && 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 + Clang/GCC only +#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_INFINITY (1.0 / 0.0) +#define UPB_FASTTABLE 0 #endif -#ifdef NAN -#define UPB_NAN NAN + +/* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully + * degrade to non-fasttable if we are using UPB_TRY_ENABLE_FASTTABLE. */ +#if !UPB_FASTTABLE && defined(UPB_TRY_ENABLE_FASTTABLE) +#define UPB_FASTTABLE_INIT(...) #else -#define UPB_NAN (0.0 / 0.0) +#define UPB_FASTTABLE_INIT(...) __VA_ARGS__ #endif + +#undef UPB_FASTTABLE_SUPPORTED + +/* ASAN poisoning (for arena) *************************************************/ + +#if defined(__SANITIZE_ADDRESS__) +#define UPB_ASAN 1 +#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_POISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#define UPB_UNPOISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#endif diff --git a/contrib/libs/grpc/third_party/upb/upb/port_undef.inc b/contrib/libs/grpc/third_party/upb/upb/port_undef.inc index c2b5f4a322..b7be52cc98 100644 --- a/contrib/libs/grpc/third_party/upb/upb/port_undef.inc +++ b/contrib/libs/grpc/third_party/upb/upb/port_undef.inc @@ -18,11 +18,7 @@ #undef UPB_UNUSED #undef UPB_ASSUME #undef UPB_ASSERT -#undef UPB_ASSERT_DEBUGVAR #undef UPB_UNREACHABLE -#undef UPB_INFINITY -#undef UPB_NAN -#undef UPB_MSVC_VSNPRINTF -#undef _upb_snprintf -#undef _upb_vsnprintf -#undef _upb_va_copy +#undef UPB_POISON_MEMORY_REGION +#undef UPB_UNPOISON_MEMORY_REGION +#undef UPB_ASAN diff --git a/contrib/libs/grpc/third_party/upb/upb/reflection.c b/contrib/libs/grpc/third_party/upb/upb/reflection.c new file mode 100644 index 0000000000..a233d964e9 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/reflection.c @@ -0,0 +1,408 @@ + +#include "upb/reflection.h" + +#include <string.h> +#include "upb/table.int.h" +#include "upb/msg.h" + +#include "upb/port_def.inc" + +static size_t get_field_size(const upb_msglayout_field *f) { + static unsigned char sizes[] = { + 0,/* 0 */ + 8, /* UPB_DESCRIPTOR_TYPE_DOUBLE */ + 4, /* UPB_DESCRIPTOR_TYPE_FLOAT */ + 8, /* UPB_DESCRIPTOR_TYPE_INT64 */ + 8, /* UPB_DESCRIPTOR_TYPE_UINT64 */ + 4, /* UPB_DESCRIPTOR_TYPE_INT32 */ + 8, /* UPB_DESCRIPTOR_TYPE_FIXED64 */ + 4, /* UPB_DESCRIPTOR_TYPE_FIXED32 */ + 1, /* UPB_DESCRIPTOR_TYPE_BOOL */ + sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_STRING */ + sizeof(void*), /* UPB_DESCRIPTOR_TYPE_GROUP */ + sizeof(void*), /* UPB_DESCRIPTOR_TYPE_MESSAGE */ + sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_BYTES */ + 4, /* UPB_DESCRIPTOR_TYPE_UINT32 */ + 4, /* UPB_DESCRIPTOR_TYPE_ENUM */ + 4, /* UPB_DESCRIPTOR_TYPE_SFIXED32 */ + 8, /* UPB_DESCRIPTOR_TYPE_SFIXED64 */ + 4, /* UPB_DESCRIPTOR_TYPE_SINT32 */ + 8, /* UPB_DESCRIPTOR_TYPE_SINT64 */ + }; + return _upb_repeated_or_map(f) ? sizeof(void *) : sizes[f->descriptortype]; +} + +/* Strings/bytes are special-cased in maps. */ +static char _upb_fieldtype_to_mapsize[12] = { + 0, + 1, /* UPB_TYPE_BOOL */ + 4, /* UPB_TYPE_FLOAT */ + 4, /* UPB_TYPE_INT32 */ + 4, /* UPB_TYPE_UINT32 */ + 4, /* UPB_TYPE_ENUM */ + sizeof(void*), /* UPB_TYPE_MESSAGE */ + 8, /* UPB_TYPE_DOUBLE */ + 8, /* UPB_TYPE_INT64 */ + 8, /* UPB_TYPE_UINT64 */ + 0, /* UPB_TYPE_STRING */ + 0, /* UPB_TYPE_BYTES */ +}; + +static const char _upb_fieldtype_to_sizelg2[12] = { + 0, + 0, /* UPB_TYPE_BOOL */ + 2, /* UPB_TYPE_FLOAT */ + 2, /* UPB_TYPE_INT32 */ + 2, /* UPB_TYPE_UINT32 */ + 2, /* UPB_TYPE_ENUM */ + UPB_SIZE(2, 3), /* UPB_TYPE_MESSAGE */ + 3, /* UPB_TYPE_DOUBLE */ + 3, /* UPB_TYPE_INT64 */ + 3, /* UPB_TYPE_UINT64 */ + UPB_SIZE(3, 4), /* UPB_TYPE_STRING */ + UPB_SIZE(3, 4), /* UPB_TYPE_BYTES */ +}; + +/** upb_msg *******************************************************************/ + +upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a) { + return _upb_msg_new(upb_msgdef_layout(m), a); +} + +static bool in_oneof(const upb_msglayout_field *field) { + return field->presence < 0; +} + +static upb_msgval _upb_msg_getraw(const upb_msg *msg, const upb_fielddef *f) { + const upb_msglayout_field *field = upb_fielddef_layout(f); + const char *mem = UPB_PTR_AT(msg, field->offset, char); + upb_msgval val = {0}; + memcpy(&val, mem, get_field_size(field)); + return val; +} + +bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f) { + const upb_msglayout_field *field = upb_fielddef_layout(f); + if (in_oneof(field)) { + return _upb_getoneofcase_field(msg, field) == field->number; + } else if (field->presence > 0) { + return _upb_hasbit_field(msg, field); + } else { + UPB_ASSERT(field->descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || + field->descriptortype == UPB_DESCRIPTOR_TYPE_GROUP); + return _upb_msg_getraw(msg, f).msg_val != NULL; + } +} + +const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg, + const upb_oneofdef *o) { + const upb_fielddef *f = upb_oneofdef_field(o, 0); + if (upb_oneofdef_issynthetic(o)) { + UPB_ASSERT(upb_oneofdef_fieldcount(o) == 1); + return upb_msg_has(msg, f) ? f : NULL; + } else { + const upb_msglayout_field *field = upb_fielddef_layout(f); + uint32_t oneof_case = _upb_getoneofcase_field(msg, field); + f = oneof_case ? upb_oneofdef_itof(o, oneof_case) : NULL; + UPB_ASSERT((f != NULL) == (oneof_case != 0)); + return f; + } +} + +upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) { + if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) { + return _upb_msg_getraw(msg, f); + } else { + /* TODO(haberman): change upb_fielddef to not require this switch(). */ + upb_msgval val = {0}; + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + case UPB_TYPE_ENUM: + val.int32_val = upb_fielddef_defaultint32(f); + break; + case UPB_TYPE_INT64: + val.int64_val = upb_fielddef_defaultint64(f); + break; + case UPB_TYPE_UINT32: + val.uint32_val = upb_fielddef_defaultuint32(f); + break; + case UPB_TYPE_UINT64: + val.uint64_val = upb_fielddef_defaultuint64(f); + break; + case UPB_TYPE_FLOAT: + val.float_val = upb_fielddef_defaultfloat(f); + break; + case UPB_TYPE_DOUBLE: + val.double_val = upb_fielddef_defaultdouble(f); + break; + case UPB_TYPE_BOOL: + val.bool_val = upb_fielddef_defaultbool(f); + break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + val.str_val.data = upb_fielddef_defaultstr(f, &val.str_val.size); + break; + case UPB_TYPE_MESSAGE: + val.msg_val = NULL; + break; + } + return val; + } +} + +upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, + upb_arena *a) { + const upb_msglayout_field *field = upb_fielddef_layout(f); + upb_mutmsgval ret; + char *mem = UPB_PTR_AT(msg, field->offset, char); + bool wrong_oneof = + in_oneof(field) && _upb_getoneofcase_field(msg, field) != field->number; + + memcpy(&ret, mem, sizeof(void*)); + + if (a && (!ret.msg || wrong_oneof)) { + if (upb_fielddef_ismap(f)) { + const upb_msgdef *entry = upb_fielddef_msgsubdef(f); + const upb_fielddef *key = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); + const upb_fielddef *value = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); + ret.map = upb_map_new(a, upb_fielddef_type(key), upb_fielddef_type(value)); + } else if (upb_fielddef_isseq(f)) { + ret.array = upb_array_new(a, upb_fielddef_type(f)); + } else { + UPB_ASSERT(upb_fielddef_issubmsg(f)); + ret.msg = upb_msg_new(upb_fielddef_msgsubdef(f), a); + } + + memcpy(mem, &ret, sizeof(void*)); + + if (wrong_oneof) { + *_upb_oneofcase_field(msg, field) = field->number; + } else if (field->presence > 0) { + _upb_sethas_field(msg, field); + } + } + return ret; +} + +void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, + upb_arena *a) { + const upb_msglayout_field *field = upb_fielddef_layout(f); + char *mem = UPB_PTR_AT(msg, field->offset, char); + UPB_UNUSED(a); /* We reserve the right to make set insert into a map. */ + memcpy(mem, &val, get_field_size(field)); + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (in_oneof(field)) { + *_upb_oneofcase_field(msg, field) = field->number; + } +} + +void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f) { + const upb_msglayout_field *field = upb_fielddef_layout(f); + char *mem = UPB_PTR_AT(msg, field->offset, char); + + if (field->presence > 0) { + _upb_clearhas_field(msg, field); + } else if (in_oneof(field)) { + uint32_t *oneof_case = _upb_oneofcase_field(msg, field); + if (*oneof_case != field->number) return; + *oneof_case = 0; + } + + memset(mem, 0, get_field_size(field)); +} + +void upb_msg_clear(upb_msg *msg, const upb_msgdef *m) { + _upb_msg_clear(msg, upb_msgdef_layout(m)); +} + +bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m, + const upb_symtab *ext_pool, const upb_fielddef **out_f, + upb_msgval *out_val, size_t *iter) { + int i = *iter; + int n = upb_msgdef_fieldcount(m); + const upb_msgval zero = {0}; + UPB_UNUSED(ext_pool); + while (++i < n) { + const upb_fielddef *f = upb_msgdef_field(m, i); + upb_msgval val = _upb_msg_getraw(msg, f); + + /* Skip field if unset or empty. */ + if (upb_fielddef_haspresence(f)) { + if (!upb_msg_has(msg, f)) continue; + } else { + upb_msgval test = val; + if (upb_fielddef_isstring(f) && !upb_fielddef_isseq(f)) { + /* Clear string pointer, only size matters (ptr could be non-NULL). */ + test.str_val.data = NULL; + } + /* Continue if NULL or 0. */ + if (memcmp(&test, &zero, sizeof(test)) == 0) continue; + + /* Continue on empty array or map. */ + if (upb_fielddef_ismap(f)) { + if (upb_map_size(test.map_val) == 0) continue; + } else if (upb_fielddef_isseq(f)) { + if (upb_array_size(test.array_val) == 0) continue; + } + } + + *out_val = val; + *out_f = f; + *iter = i; + return true; + } + *iter = i; + return false; +} + +bool _upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int depth) { + size_t iter = UPB_MSG_BEGIN; + const upb_fielddef *f; + upb_msgval val; + bool ret = true; + + if (--depth == 0) return false; + + _upb_msg_discardunknown_shallow(msg); + + while (upb_msg_next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) { + const upb_msgdef *subm = upb_fielddef_msgsubdef(f); + if (!subm) continue; + if (upb_fielddef_ismap(f)) { + const upb_fielddef *val_f = upb_msgdef_itof(subm, 2); + const upb_msgdef *val_m = upb_fielddef_msgsubdef(val_f); + upb_map *map = (upb_map*)val.map_val; + size_t iter = UPB_MAP_BEGIN; + + if (!val_m) continue; + + while (upb_mapiter_next(map, &iter)) { + upb_msgval map_val = upb_mapiter_value(map, iter); + if (!_upb_msg_discardunknown((upb_msg*)map_val.msg_val, val_m, depth)) { + ret = false; + } + } + } else if (upb_fielddef_isseq(f)) { + const upb_array *arr = val.array_val; + size_t i, n = upb_array_size(arr); + for (i = 0; i < n; i++) { + upb_msgval elem = upb_array_get(arr, i); + if (!_upb_msg_discardunknown((upb_msg*)elem.msg_val, subm, depth)) { + ret = false; + } + } + } else { + if (!_upb_msg_discardunknown((upb_msg*)val.msg_val, subm, depth)) { + ret = false; + } + } + } + + return ret; +} + +bool upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int maxdepth) { + return _upb_msg_discardunknown(msg, m, maxdepth); +} + +/** upb_array *****************************************************************/ + +upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type) { + return _upb_array_new(a, 4, _upb_fieldtype_to_sizelg2[type]); +} + +size_t upb_array_size(const upb_array *arr) { + return arr->len; +} + +upb_msgval upb_array_get(const upb_array *arr, size_t i) { + upb_msgval ret; + const char* data = _upb_array_constptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); + memcpy(&ret, data + (i << lg2), 1 << lg2); + return ret; +} + +void upb_array_set(upb_array *arr, size_t i, upb_msgval val) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); + memcpy(data + (i << lg2), &val, 1 << lg2); +} + +bool upb_array_append(upb_array *arr, upb_msgval val, upb_arena *arena) { + if (!_upb_array_realloc(arr, arr->len + 1, arena)) { + return false; + } + arr->len++; + upb_array_set(arr, arr->len - 1, val); + return true; +} + +bool upb_array_resize(upb_array *arr, size_t size, upb_arena *arena) { + return _upb_array_resize(arr, size, arena); +} + +/** upb_map *******************************************************************/ + +upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, + upb_fieldtype_t value_type) { + return _upb_map_new(a, _upb_fieldtype_to_mapsize[key_type], + _upb_fieldtype_to_mapsize[value_type]); +} + +size_t upb_map_size(const upb_map *map) { + return _upb_map_size(map); +} + +bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { + return _upb_map_get(map, &key, map->key_size, val, map->val_size); +} + +void upb_map_clear(upb_map *map) { + _upb_map_clear(map); +} + +bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, + upb_arena *arena) { + return _upb_map_set(map, &key, map->key_size, &val, map->val_size, arena); +} + +bool upb_map_delete(upb_map *map, upb_msgval key) { + return _upb_map_delete(map, &key, map->key_size); +} + +bool upb_mapiter_next(const upb_map *map, size_t *iter) { + return _upb_map_next(map, iter); +} + +bool upb_mapiter_done(const upb_map *map, size_t iter) { + upb_strtable_iter i; + UPB_ASSERT(iter != UPB_MAP_BEGIN); + i.t = &map->table; + i.index = iter; + return upb_strtable_done(&i); +} + +/* Returns the key and value for this entry of the map. */ +upb_msgval upb_mapiter_key(const upb_map *map, size_t iter) { + upb_strtable_iter i; + upb_msgval ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); + return ret; +} + +upb_msgval upb_mapiter_value(const upb_map *map, size_t iter) { + upb_strtable_iter i; + upb_msgval ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); + return ret; +} + +/* void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); */ diff --git a/contrib/libs/grpc/third_party/upb/upb/reflection.h b/contrib/libs/grpc/third_party/upb/upb/reflection.h new file mode 100644 index 0000000000..0133630c58 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/reflection.h @@ -0,0 +1,168 @@ + +#ifndef UPB_REFLECTION_H_ +#define UPB_REFLECTION_H_ + +#include "upb/def.h" +#include "upb/msg.h" +#include "upb/upb.h" + +#include "upb/port_def.inc" + +typedef union { + bool bool_val; + float float_val; + double double_val; + int32_t int32_val; + int64_t int64_val; + uint32_t uint32_val; + uint64_t uint64_val; + const upb_map* map_val; + const upb_msg* msg_val; + const upb_array* array_val; + upb_strview str_val; +} upb_msgval; + +typedef union { + upb_map* map; + upb_msg* msg; + upb_array* array; +} upb_mutmsgval; + +/** upb_msg *******************************************************************/ + +/* Creates a new message of the given type in the given arena. */ +upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a); + +/* Returns the value associated with this field. */ +upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f); + +/* Returns a mutable pointer to a map, array, or submessage value. If the given + * arena is non-NULL this will construct a new object if it was not previously + * present. May not be called for primitive fields. */ +upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, upb_arena *a); + +/* May only be called for fields where upb_fielddef_haspresence(f) == true. */ +bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f); + +/* Returns the field that is set in the oneof, or NULL if none are set. */ +const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg, + const upb_oneofdef *o); + +/* Sets the given field to the given value. For a msg/array/map/string, the + * value must be in the same arena. */ +void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, + upb_arena *a); + +/* Clears any field presence and sets the value back to its default. */ +void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f); + +/* Clear all data and unknown fields. */ +void upb_msg_clear(upb_msg *msg, const upb_msgdef *m); + +/* Iterate over present fields. + * + * size_t iter = UPB_MSG_BEGIN; + * const upb_fielddef *f; + * upb_msgval val; + * while (upb_msg_next(msg, m, ext_pool, &f, &val, &iter)) { + * process_field(f, val); + * } + * + * If ext_pool is NULL, no extensions will be returned. If the given symtab + * returns extensions that don't match what is in this message, those extensions + * will be skipped. + */ + +#define UPB_MSG_BEGIN -1 +bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m, + const upb_symtab *ext_pool, const upb_fielddef **f, + upb_msgval *val, size_t *iter); + +/* Adds unknown data (serialized protobuf data) to the given message. The data + * is copied into the message instance. */ +void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, + upb_arena *arena); + +/* Clears all unknown field data from this message and all submessages. */ +bool upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int maxdepth); + +/* Returns a reference to the message's unknown data. */ +const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); + +/** upb_array *****************************************************************/ + +/* Creates a new array on the given arena that holds elements of this type. */ +upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type); + +/* Returns the size of the array. */ +size_t upb_array_size(const upb_array *arr); + +/* Returns the given element, which must be within the array's current size. */ +upb_msgval upb_array_get(const upb_array *arr, size_t i); + +/* Sets the given element, which must be within the array's current size. */ +void upb_array_set(upb_array *arr, size_t i, upb_msgval val); + +/* Appends an element to the array. Returns false on allocation failure. */ +bool upb_array_append(upb_array *array, upb_msgval val, upb_arena *arena); + +/* Changes the size of a vector. New elements are initialized to empty/0. + * Returns false on allocation failure. */ +bool upb_array_resize(upb_array *array, size_t size, upb_arena *arena); + +/** upb_map *******************************************************************/ + +/* Creates a new map on the given arena with the given key/value size. */ +upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, + upb_fieldtype_t value_type); + +/* Returns the number of entries in the map. */ +size_t upb_map_size(const upb_map *map); + +/* Stores a value for the given key into |*val| (or the zero value if the key is + * not present). Returns whether the key was present. The |val| pointer may be + * NULL, in which case the function tests whether the given key is present. */ +bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val); + +/* Removes all entries in the map. */ +void upb_map_clear(upb_map *map); + +/* Sets the given key to the given value. Returns true if this was a new key in + * the map, or false if an existing key was replaced. */ +bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, + upb_arena *arena); + +/* Deletes this key from the table. Returns true if the key was present. */ +bool upb_map_delete(upb_map *map, upb_msgval key); + +/* Map iteration: + * + * size_t iter = UPB_MAP_BEGIN; + * while (upb_mapiter_next(map, &iter)) { + * upb_msgval key = upb_mapiter_key(map, iter); + * upb_msgval val = upb_mapiter_value(map, iter); + * + * // If mutating is desired. + * upb_mapiter_setvalue(map, iter, value2); + * } + */ + +/* Advances to the next entry. Returns false if no more entries are present. */ +bool upb_mapiter_next(const upb_map *map, size_t *iter); + +/* Returns true if the iterator still points to a valid entry, or false if the + * iterator is past the last element. It is an error to call this function with + * UPB_MAP_BEGIN (you must call next() at least once first). */ +bool upb_mapiter_done(const upb_map *map, size_t iter); + +/* Returns the key and value for this entry of the map. */ +upb_msgval upb_mapiter_key(const upb_map *map, size_t iter); +upb_msgval upb_mapiter_value(const upb_map *map, size_t iter); + +/* Sets the value for this entry. The iterator must not be done, and the + * iterator must not have been initialized const. */ +void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); + +#include "upb/port_undef.inc" + +#endif /* UPB_REFLECTION_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/table.c b/contrib/libs/grpc/third_party/upb/upb/table.c index 34a20530d8..8837047659 100644 --- a/contrib/libs/grpc/third_party/upb/upb/table.c +++ b/contrib/libs/grpc/third_party/upb/upb/table.c @@ -4,10 +4,12 @@ ** Implementation is heavily inspired by Lua's ltable.c. */ -#include "upb/table.int.h" - #include <string.h> +#include "third_party/wyhash/wyhash.h" +#include "upb/table.int.h" + +/* Must be last. */ #include "upb/port_def.inc" #define UPB_MAXARRSIZE 16 /* 64k. */ @@ -87,11 +89,7 @@ static upb_tabent *mutable_entries(upb_table *t) { } static bool isfull(upb_table *t) { - if (upb_table_size(t) == 0) { - return true; - } else { - return ((double)(t->count + 1) / upb_table_size(t)) > MAX_LOAD; - } + return t->count == t->max_count; } static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) { @@ -100,6 +98,7 @@ static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) { t->count = 0; t->size_lg2 = size_lg2; t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; + t->max_count = upb_table_size(t) * MAX_LOAD; bytes = upb_table_size(t) * sizeof(upb_tabent); if (bytes > 0) { t->entries = upb_malloc(a, bytes); @@ -115,9 +114,17 @@ static void uninit(upb_table *t, upb_alloc *a) { upb_free(a, mutable_entries(t)); } -static upb_tabent *emptyent(upb_table *t) { - upb_tabent *e = mutable_entries(t) + upb_table_size(t); - while (1) { if (upb_tabent_isempty(--e)) return e; UPB_ASSERT(e > t->entries); } +static upb_tabent *emptyent(upb_table *t, upb_tabent *e) { + upb_tabent *begin = mutable_entries(t); + upb_tabent *end = begin + upb_table_size(t); + for (e = e + 1; e < end; e++) { + if (upb_tabent_isempty(e)) return e; + } + for (e = begin; e < end; e++) { + if (upb_tabent_isempty(e)) return e; + } + UPB_ASSERT(false); + return NULL; } static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) { @@ -173,11 +180,11 @@ static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey, our_e->next = NULL; } else { /* Collision. */ - upb_tabent *new_e = emptyent(t); + upb_tabent *new_e = emptyent(t, mainpos_e); /* Head of collider's chain. */ upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key)); if (chain == mainpos_e) { - /* Existing ent is in its main posisiton (it has the same hash as us, and + /* Existing ent is in its main position (it has the same hash as us, and * is the head of our chain). Insert to new ent and append to this chain. */ new_e->next = mainpos_e->next; mainpos_e->next = new_e; @@ -268,10 +275,14 @@ static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) { return (uintptr_t)str; } +static uint32_t table_hash(const char *p, size_t n) { + return wyhash(p, n, 0, _wyp); +} + static uint32_t strhash(upb_tabkey key) { uint32_t len; char *str = upb_tabstr(key, &len); - return upb_murmur_hash2(str, len, 0); + return table_hash(str, len); } static bool streql(upb_tabkey k1, lookupkey_t k2) { @@ -280,9 +291,14 @@ static bool streql(upb_tabkey k1, lookupkey_t k2) { return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0); } -bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, upb_alloc *a) { +bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, + size_t expected_size, upb_alloc *a) { UPB_UNUSED(ctype); /* TODO(haberman): rm */ - return init(&t->t, 2, a); + // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 denominator. + size_t need_entries = (expected_size + 1) * 1204 / 1024; + UPB_ASSERT(need_entries >= expected_size * 0.85); + int size_lg2 = _upb_lg2ceil(need_entries); + return init(&t->t, size_lg2, a); } void upb_strtable_clear(upb_strtable *t) { @@ -333,20 +349,20 @@ bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len, tabkey = strcopy(key, a); if (tabkey == 0) return false; - hash = upb_murmur_hash2(key.str.str, key.str.len, 0); + hash = table_hash(key.str.str, key.str.len); insert(&t->t, key, tabkey, v, hash, &strhash, &streql); return true; } bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, upb_value *v) { - uint32_t hash = upb_murmur_hash2(key, len, 0); + uint32_t hash = table_hash(key, len); return lookup(&t->t, strkey2(key, len), v, hash, &streql); } bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, upb_value *val, upb_alloc *alloc) { - uint32_t hash = upb_murmur_hash2(key, len, 0); + uint32_t hash = table_hash(key, len); upb_tabkey tabkey; if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) { if (alloc) { @@ -699,182 +715,3 @@ bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, return i1->t == i2->t && i1->index == i2->index && i1->array_part == i2->array_part; } - -#if defined(UPB_UNALIGNED_READS_OK) || defined(__s390x__) -/* ----------------------------------------------------------------------------- - * MurmurHash2, by Austin Appleby (released as public domain). - * Reformatted and C99-ified by Joshua Haberman. - * Note - This code makes a few assumptions about how your machine behaves - - * 1. We can read a 4-byte value from any address without crashing - * 2. sizeof(int) == 4 (in upb this limitation is removed by using uint32_t - * And it has a few limitations - - * 1. It will not work incrementally. - * 2. It will not produce the same results on little-endian and big-endian - * machines. */ -uint32_t upb_murmur_hash2(const void *key, size_t len, uint32_t seed) { - /* 'm' and 'r' are mixing constants generated offline. - * They're not really 'magic', they just happen to work well. */ - const uint32_t m = 0x5bd1e995; - const int32_t r = 24; - - /* Initialize the hash to a 'random' value */ - uint32_t h = seed ^ len; - - /* Mix 4 bytes at a time into the hash */ - const uint8_t * data = (const uint8_t *)key; - while(len >= 4) { - uint32_t k; - memcpy(&k, data, sizeof(k)); - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - data += 4; - len -= 4; - } - - /* Handle the last few bytes of the input array */ - switch(len) { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; h *= m; - }; - - /* Do a few final mixes of the hash to ensure the last few - * bytes are well-incorporated. */ - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} - -#else /* !UPB_UNALIGNED_READS_OK */ - -/* ----------------------------------------------------------------------------- - * MurmurHashAligned2, by Austin Appleby - * Same algorithm as MurmurHash2, but only does aligned reads - should be safer - * on certain platforms. - * Performance will be lower than MurmurHash2 */ - -#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; } - -uint32_t upb_murmur_hash2(const void * key, size_t len, uint32_t seed) { - const uint32_t m = 0x5bd1e995; - const int32_t r = 24; - const uint8_t * data = (const uint8_t *)key; - uint32_t h = (uint32_t)(seed ^ len); - uint8_t align = (uintptr_t)data & 3; - - if(align && (len >= 4)) { - /* Pre-load the temp registers */ - uint32_t t = 0, d = 0; - int32_t sl; - int32_t sr; - - switch(align) { - case 1: t |= data[2] << 16; /* fallthrough */ - case 2: t |= data[1] << 8; /* fallthrough */ - case 3: t |= data[0]; - } - - t <<= (8 * align); - - data += 4-align; - len -= 4-align; - - sl = 8 * (4-align); - sr = 8 * align; - - /* Mix */ - - while(len >= 4) { - uint32_t k; - - d = *(uint32_t *)data; - t = (t >> sr) | (d << sl); - - k = t; - - MIX(h,k,m); - - t = d; - - data += 4; - len -= 4; - } - - /* Handle leftover data in temp registers */ - - d = 0; - - if(len >= align) { - uint32_t k; - - switch(align) { - case 3: d |= data[2] << 16; /* fallthrough */ - case 2: d |= data[1] << 8; /* fallthrough */ - case 1: d |= data[0]; /* fallthrough */ - } - - k = (t >> sr) | (d << sl); - MIX(h,k,m); - - data += align; - len -= align; - - /* ---------- - * Handle tail bytes */ - - switch(len) { - case 3: h ^= data[2] << 16; /* fallthrough */ - case 2: h ^= data[1] << 8; /* fallthrough */ - case 1: h ^= data[0]; h *= m; /* fallthrough */ - }; - } else { - switch(len) { - case 3: d |= data[2] << 16; /* fallthrough */ - case 2: d |= data[1] << 8; /* fallthrough */ - case 1: d |= data[0]; /* fallthrough */ - case 0: h ^= (t >> sr) | (d << sl); h *= m; - } - } - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; - } else { - while(len >= 4) { - uint32_t k = *(uint32_t *)data; - - MIX(h,k,m); - - data += 4; - len -= 4; - } - - /* ---------- - * Handle tail bytes */ - - switch(len) { - case 3: h ^= data[2] << 16; /* fallthrough */ - case 2: h ^= data[1] << 8; /* fallthrough */ - case 1: h ^= data[0]; h *= m; - }; - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; - } -} -#undef MIX - -#endif /* UPB_UNALIGNED_READS_OK */ diff --git a/contrib/libs/grpc/third_party/upb/upb/table.int.h b/contrib/libs/grpc/third_party/upb/upb/table.int.h index 600637eef2..49caac463e 100644 --- a/contrib/libs/grpc/third_party/upb/upb/table.int.h +++ b/contrib/libs/grpc/third_party/upb/upb/table.int.h @@ -13,7 +13,7 @@ ** store pointers or integers of at least 32 bits (upb isn't really useful on ** systems where sizeof(void*) < 4). ** -** The table must be homogenous (all values of the same type). In debug +** The table must be homogeneous (all values of the same type). In debug ** mode, we check this on insert and lookup. */ @@ -147,10 +147,17 @@ UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) { return mem + sizeof(*len); } +UPB_INLINE upb_strview upb_tabstrview(upb_tabkey key) { + upb_strview ret; + uint32_t len; + ret.data = upb_tabstr(key, &len); + ret.size = len; + return ret; +} /* upb_tabval *****************************************************************/ -typedef struct { +typedef struct upb_tabval { uint64_t val; } upb_tabval; @@ -171,7 +178,8 @@ typedef struct _upb_tabent { typedef struct { size_t count; /* Number of entries in the hash part. */ - size_t mask; /* Mask to turn hash value -> bucket. */ + uint32_t mask; /* Mask to turn hash value -> bucket. */ + uint32_t max_count; /* Max count before we hit our load limit. */ uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ /* Hash table entries. @@ -230,7 +238,8 @@ UPB_INLINE bool upb_arrhas(upb_tabval key) { /* Initialize and uninitialize a table, respectively. If memory allocation * failed, false is returned that the table is uninitialized. */ bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a); -bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, upb_alloc *a); +bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, + size_t expected_size, upb_alloc *a); void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a); void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a); @@ -239,7 +248,7 @@ UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) { } UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) { - return upb_strtable_init2(table, ctype, &upb_alloc_global); + return upb_strtable_init2(table, ctype, 4, &upb_alloc_global); } UPB_INLINE void upb_inttable_uninit(upb_inttable *table) { diff --git a/contrib/libs/grpc/third_party/upb/upb/text_encode.c b/contrib/libs/grpc/third_party/upb/upb/text_encode.c new file mode 100644 index 0000000000..028cc29e09 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/text_encode.c @@ -0,0 +1,421 @@ + +#include "upb/text_encode.h" + +#include <ctype.h> +#include <float.h> +#include <inttypes.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include "upb/reflection.h" +#include "upb/port_def.inc" + +typedef struct { + char *buf, *ptr, *end; + size_t overflow; + int indent_depth; + int options; + const upb_symtab *ext_pool; + _upb_mapsorter sorter; +} txtenc; + +static void txtenc_msg(txtenc *e, const upb_msg *msg, const upb_msgdef *m); + +static void txtenc_putbytes(txtenc *e, const void *data, size_t len) { + size_t have = e->end - e->ptr; + if (UPB_LIKELY(have >= len)) { + memcpy(e->ptr, data, len); + e->ptr += len; + } else { + if (have) memcpy(e->ptr, data, have); + e->ptr += have; + e->overflow += (len - have); + } +} + +static void txtenc_putstr(txtenc *e, const char *str) { + txtenc_putbytes(e, str, strlen(str)); +} + +static void txtenc_printf(txtenc *e, const char *fmt, ...) { + size_t n; + size_t have = e->end - e->ptr; + va_list args; + + va_start(args, fmt); + n = vsnprintf(e->ptr, have, fmt, args); + va_end(args); + + if (UPB_LIKELY(have > n)) { + e->ptr += n; + } else { + e->ptr += have; + e->overflow += (n - have); + } +} + +static void txtenc_indent(txtenc *e) { + if ((e->options & UPB_TXTENC_SINGLELINE) == 0) { + int i = e->indent_depth; + while (i-- > 0) { + txtenc_putstr(e, " "); + } + } +} + +static void txtenc_endfield(txtenc *e) { + if (e->options & UPB_TXTENC_SINGLELINE) { + txtenc_putstr(e, " "); + } else { + txtenc_putstr(e, "\n"); + } +} + +static void txtenc_enum(int32_t val, const upb_fielddef *f, txtenc *e) { + const upb_enumdef *e_def = upb_fielddef_enumsubdef(f); + const char *name = upb_enumdef_iton(e_def, val); + + if (name) { + txtenc_printf(e, "%s", name); + } else { + txtenc_printf(e, "%" PRId32, val); + } +} + +static void txtenc_string(txtenc *e, upb_strview str, bool bytes) { + const char *ptr = str.data; + const char *end = ptr + str.size; + txtenc_putstr(e, "\""); + + while (ptr < end) { + switch (*ptr) { + case '\n': + txtenc_putstr(e, "\\n"); + break; + case '\r': + txtenc_putstr(e, "\\r"); + break; + case '\t': + txtenc_putstr(e, "\\t"); + break; + case '\"': + txtenc_putstr(e, "\\\""); + break; + case '\'': + txtenc_putstr(e, "\\'"); + break; + case '\\': + txtenc_putstr(e, "\\\\"); + break; + default: + if ((bytes || (uint8_t)*ptr < 0x80) && !isprint(*ptr)) { + txtenc_printf(e, "\\%03o", (int)(uint8_t)*ptr); + } else { + txtenc_putbytes(e, ptr, 1); + } + break; + } + ptr++; + } + + txtenc_putstr(e, "\""); +} + +static void txtenc_field(txtenc *e, upb_msgval val, const upb_fielddef *f) { + txtenc_indent(e); + txtenc_printf(e, "%s: ", upb_fielddef_name(f)); + + switch (upb_fielddef_type(f)) { + case UPB_TYPE_BOOL: + txtenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case UPB_TYPE_FLOAT: + txtenc_printf(e, "%f", val.float_val); + break; + case UPB_TYPE_DOUBLE: + txtenc_printf(e, "%f", val.double_val); + break; + case UPB_TYPE_INT32: + txtenc_printf(e, "%" PRId32, val.int32_val); + break; + case UPB_TYPE_UINT32: + txtenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case UPB_TYPE_INT64: + txtenc_printf(e, "%" PRId64, val.int64_val); + break; + case UPB_TYPE_UINT64: + txtenc_printf(e, "%" PRIu64, val.uint64_val); + break; + case UPB_TYPE_STRING: + txtenc_string(e, val.str_val, false); + break; + case UPB_TYPE_BYTES: + txtenc_string(e, val.str_val, true); + break; + case UPB_TYPE_ENUM: + txtenc_enum(val.int32_val, f, e); + break; + case UPB_TYPE_MESSAGE: + txtenc_putstr(e, "{"); + txtenc_endfield(e); + e->indent_depth++; + txtenc_msg(e, val.msg_val, upb_fielddef_msgsubdef(f)); + e->indent_depth--; + txtenc_indent(e); + txtenc_putstr(e, "}"); + break; + } + + txtenc_endfield(e); +} + +/* + * Arrays print as simple repeated elements, eg. + * + * foo_field: 1 + * foo_field: 2 + * foo_field: 3 + */ +static void txtenc_array(txtenc *e, const upb_array *arr, + const upb_fielddef *f) { + size_t i; + size_t size = upb_array_size(arr); + + for (i = 0; i < size; i++) { + txtenc_field(e, upb_array_get(arr, i), f); + } +} + +static void txtenc_mapentry(txtenc *e, upb_msgval key, upb_msgval val, + const upb_fielddef *f) { + const upb_msgdef *entry = upb_fielddef_msgsubdef(f); + const upb_fielddef *key_f = upb_msgdef_field(entry, 0); + const upb_fielddef *val_f = upb_msgdef_field(entry, 1); + txtenc_indent(e); + txtenc_printf(e, "%s: {", upb_fielddef_name(f)); + txtenc_endfield(e); + e->indent_depth++; + + txtenc_field(e, key, key_f); + txtenc_field(e, val, val_f); + + e->indent_depth--; + txtenc_indent(e); + txtenc_putstr(e, "}"); + txtenc_endfield(e); +} + +/* + * Maps print as messages of key/value, etc. + * + * foo_map: { + * key: "abc" + * value: 123 + * } + * foo_map: { + * key: "def" + * value: 456 + * } + */ +static void txtenc_map(txtenc *e, const upb_map *map, const upb_fielddef *f) { + if (e->options & UPB_TXTENC_NOSORT) { + size_t iter = UPB_MAP_BEGIN; + while (upb_mapiter_next(map, &iter)) { + upb_msgval key = upb_mapiter_key(map, iter); + upb_msgval val = upb_mapiter_value(map, iter); + txtenc_mapentry(e, key, val, f); + } + } else { + const upb_msgdef *entry = upb_fielddef_msgsubdef(f); + const upb_fielddef *key_f = upb_msgdef_field(entry, 0); + _upb_sortedmap sorted; + upb_map_entry ent; + + _upb_mapsorter_pushmap(&e->sorter, upb_fielddef_descriptortype(key_f), map, + &sorted); + while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { + upb_msgval key, val; + memcpy(&key, &ent.k, sizeof(key)); + memcpy(&val, &ent.v, sizeof(val)); + txtenc_mapentry(e, key, val, f); + } + _upb_mapsorter_popmap(&e->sorter, &sorted); + } +} + +#define CHK(x) do { if (!(x)) { return false; } } while(0) + +static const char *txtenc_parsevarint(const char *ptr, const char *limit, + uint64_t *val) { + uint8_t byte; + int bitpos = 0; + *val = 0; + + do { + CHK(bitpos < 70 && ptr < limit); + byte = *ptr; + *val |= (uint64_t)(byte & 0x7F) << bitpos; + ptr++; + bitpos += 7; + } while (byte & 0x80); + + return ptr; +} + +/* + * Unknown fields are printed by number. + * + * 1001: 123 + * 1002: "hello" + * 1006: 0xdeadbeef + * 1003: { + * 1: 111 + * } + */ +static const char *txtenc_unknown(txtenc *e, const char *ptr, const char *end, + int groupnum) { + while (ptr < end) { + uint64_t tag_64; + uint32_t tag; + CHK(ptr = txtenc_parsevarint(ptr, end, &tag_64)); + CHK(tag_64 < UINT32_MAX); + tag = (uint32_t)tag_64; + + if ((tag & 7) == UPB_WIRE_TYPE_END_GROUP) { + CHK((tag >> 3) == (uint32_t)groupnum); + return ptr; + } + + txtenc_indent(e); + txtenc_printf(e, "%d: ", (int)(tag >> 3)); + + switch (tag & 7) { + case UPB_WIRE_TYPE_VARINT: { + uint64_t val; + CHK(ptr = txtenc_parsevarint(ptr, end, &val)); + txtenc_printf(e, "%" PRIu64, val); + break; + } + case UPB_WIRE_TYPE_32BIT: { + uint32_t val; + CHK(end - ptr >= 4); + memcpy(&val, ptr, 4); + ptr += 4; + txtenc_printf(e, "0x%08" PRIu32, val); + break; + } + case UPB_WIRE_TYPE_64BIT: { + uint64_t val; + CHK(end - ptr >= 8); + memcpy(&val, ptr, 8); + ptr += 8; + txtenc_printf(e, "0x%016" PRIu64, val); + break; + } + case UPB_WIRE_TYPE_DELIMITED: { + uint64_t len; + size_t avail = end - ptr; + char *start = e->ptr; + size_t start_overflow = e->overflow; + CHK(ptr = txtenc_parsevarint(ptr, end, &len)); + CHK(avail >= len); + + /* Speculatively try to parse as message. */ + txtenc_putstr(e, "{"); + txtenc_endfield(e); + e->indent_depth++; + if (txtenc_unknown(e, ptr, end, -1)) { + e->indent_depth--; + txtenc_indent(e); + txtenc_putstr(e, "}"); + } else { + /* Didn't work out, print as raw bytes. */ + upb_strview str; + e->indent_depth--; + e->ptr = start; + e->overflow = start_overflow; + str.data = ptr; + str.size = len; + txtenc_string(e, str, true); + } + ptr += len; + break; + } + case UPB_WIRE_TYPE_START_GROUP: + txtenc_putstr(e, "{"); + txtenc_endfield(e); + e->indent_depth++; + CHK(ptr = txtenc_unknown(e, ptr, end, tag >> 3)); + e->indent_depth--; + txtenc_indent(e); + txtenc_putstr(e, "}"); + break; + } + txtenc_endfield(e); + } + + return groupnum == -1 ? ptr : NULL; +} + +#undef CHK + +static void txtenc_msg(txtenc *e, const upb_msg *msg, + const upb_msgdef *m) { + size_t iter = UPB_MSG_BEGIN; + const upb_fielddef *f; + upb_msgval val; + + while (upb_msg_next(msg, m, e->ext_pool, &f, &val, &iter)) { + if (upb_fielddef_ismap(f)) { + txtenc_map(e, val.map_val, f); + } else if (upb_fielddef_isseq(f)) { + txtenc_array(e, val.array_val, f); + } else { + txtenc_field(e, val, f); + } + } + + if ((e->options & UPB_TXTENC_SKIPUNKNOWN) == 0) { + size_t len; + const char *ptr = upb_msg_getunknown(msg, &len); + char *start = e->ptr; + if (ptr) { + if (!txtenc_unknown(e, ptr, ptr + len, -1)) { + /* Unknown failed to parse, back up and don't print it at all. */ + e->ptr = start; + } + } + } +} + +size_t txtenc_nullz(txtenc *e, size_t size) { + size_t ret = e->ptr - e->buf + e->overflow; + + if (size > 0) { + if (e->ptr == e->end) e->ptr--; + *e->ptr = '\0'; + } + + return ret; +} + +size_t upb_text_encode(const upb_msg *msg, const upb_msgdef *m, + const upb_symtab *ext_pool, int options, char *buf, + size_t size) { + txtenc e; + + e.buf = buf; + e.ptr = buf; + e.end = buf + size; + e.overflow = 0; + e.indent_depth = 0; + e.options = options; + e.ext_pool = ext_pool; + _upb_mapsorter_init(&e.sorter); + + txtenc_msg(&e, msg, m); + _upb_mapsorter_destroy(&e.sorter); + return txtenc_nullz(&e, size); +} diff --git a/contrib/libs/grpc/third_party/upb/upb/text_encode.h b/contrib/libs/grpc/third_party/upb/upb/text_encode.h new file mode 100644 index 0000000000..4ad3d1c4d7 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/text_encode.h @@ -0,0 +1,38 @@ + +#ifndef UPB_TEXTENCODE_H_ +#define UPB_TEXTENCODE_H_ + +#include "upb/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* When set, prints everything on a single line. */ + UPB_TXTENC_SINGLELINE = 1, + + /* When set, unknown fields are not printed. */ + UPB_TXTENC_SKIPUNKNOWN = 2, + + /* When set, maps are *not* sorted (this avoids allocating tmp mem). */ + UPB_TXTENC_NOSORT = 4 +}; + +/* Encodes the given |msg| to text format. The message's reflection is given in + * |m|. The symtab in |symtab| is used to find extensions (if NULL, extensions + * will not be printed). + * + * Output is placed in the given buffer, and always NULL-terminated. The output + * size (excluding NULL) is returned. This means that a return value >= |size| + * implies that the output was truncated. (These are the same semantics as + * snprintf()). */ +size_t upb_text_encode(const upb_msg *msg, const upb_msgdef *m, + const upb_symtab *ext_pool, int options, char *buf, + size_t size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_TEXTENCODE_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/upb.c b/contrib/libs/grpc/third_party/upb/upb/upb.c index 3089c059e1..a12656973d 100644 --- a/contrib/libs/grpc/third_party/upb/upb/upb.c +++ b/contrib/libs/grpc/third_party/upb/upb/upb.c @@ -1,5 +1,5 @@ -#include "upb/upb.h" +#include "upb/upb.int.h" #include <errno.h> #include <stdarg.h> @@ -40,7 +40,7 @@ void upb_status_seterrf(upb_status *status, const char *fmt, ...) { void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) { if (!status) return; status->ok = false; - _upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args); + vsnprintf(status->msg, sizeof(status->msg), fmt, args); status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0'; } @@ -49,7 +49,7 @@ void upb_status_vappenderrf(upb_status *status, const char *fmt, va_list args) { if (!status) return; status->ok = false; len = strlen(status->msg); - _upb_vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); + vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0'; } @@ -73,37 +73,18 @@ upb_alloc upb_alloc_global = {&upb_global_allocfunc}; /* Be conservative and choose 16 in case anyone is using SSE. */ -typedef struct mem_block { +struct mem_block { struct mem_block *next; uint32_t size; uint32_t cleanups; /* Data follows. */ -} mem_block; +}; typedef struct cleanup_ent { upb_cleanup_func *cleanup; void *ud; } cleanup_ent; -struct upb_arena { - _upb_arena_head head; - uint32_t *cleanups; - - /* Allocator to allocate arena blocks. We are responsible for freeing these - * when we are destroyed. */ - upb_alloc *block_alloc; - uint32_t last_size; - - /* When multiple arenas are fused together, each arena points to a parent - * arena (root points to itself). The root tracks how many live arenas - * reference it. */ - uint32_t refcount; /* Only used when a->parent == a */ - struct upb_arena *parent; - - /* Linked list of blocks to free/cleanup. */ - mem_block *freelist, *freelist_tail; -}; - static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16); static upb_arena *arena_findroot(upb_arena *a) { @@ -117,9 +98,9 @@ static upb_arena *arena_findroot(upb_arena *a) { return a; } -static void upb_arena_addblock(upb_arena *a, void *ptr, size_t size) { +static void upb_arena_addblock(upb_arena *a, upb_arena *root, void *ptr, + size_t size) { mem_block *block = ptr; - upb_arena *root = arena_findroot(a); /* The block is for arena |a|, but should appear in the freelist of |root|. */ block->next = root->freelist; @@ -133,26 +114,22 @@ static void upb_arena_addblock(upb_arena *a, void *ptr, size_t size) { a->head.end = UPB_PTR_AT(block, size, char); a->cleanups = &block->cleanups; - /* TODO(haberman): ASAN poison. */ + UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); } static bool upb_arena_allocblock(upb_arena *a, size_t size) { + upb_arena *root = arena_findroot(a); size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; - mem_block *block = upb_malloc(a->block_alloc, block_size); + mem_block *block = upb_malloc(root->block_alloc, block_size); if (!block) return false; - upb_arena_addblock(a, block, block_size); + upb_arena_addblock(a, root, block, block_size); return true; } -static bool arena_has(upb_arena *a, size_t size) { - _upb_arena_head *h = (_upb_arena_head*)a; - return (size_t)(h->end - h->ptr) >= size; -} - void *_upb_arena_slowmalloc(upb_arena *a, size_t size) { if (!upb_arena_allocblock(a, size)) return NULL; /* Out of memory. */ - UPB_ASSERT(arena_has(a, size)); + UPB_ASSERT(_upb_arenahas(a) >= size); return upb_arena_malloc(a, size); } @@ -184,7 +161,7 @@ upb_arena *arena_initslow(void *mem, size_t n, upb_alloc *alloc) { a->freelist = NULL; a->freelist_tail = NULL; - upb_arena_addblock(a, mem, n); + upb_arena_addblock(a, a, mem, n); return a; } @@ -201,15 +178,14 @@ upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc) { } a = UPB_PTR_AT(mem, n - sizeof(*a), upb_arena); - n -= sizeof(*a); a->head.alloc.func = &upb_arena_doalloc; a->block_alloc = alloc; a->parent = a; a->refcount = 1; - a->last_size = 128; + a->last_size = UPB_MAX(128, n); a->head.ptr = mem; - a->head.end = UPB_PTR_AT(mem, n, char); + a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); a->freelist = NULL; a->cleanups = NULL; @@ -247,14 +223,15 @@ void upb_arena_free(upb_arena *a) { bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) { cleanup_ent *ent; - if (!a->cleanups || !arena_has(a, sizeof(cleanup_ent))) { + if (!a->cleanups || _upb_arenahas(a) < sizeof(cleanup_ent)) { if (!upb_arena_allocblock(a, 128)) return false; /* Out of memory. */ - UPB_ASSERT(arena_has(a, sizeof(cleanup_ent))); + UPB_ASSERT(_upb_arenahas(a) >= sizeof(cleanup_ent)); } a->head.end -= sizeof(cleanup_ent); ent = (cleanup_ent*)a->head.end; (*a->cleanups)++; + UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); ent->cleanup = func; ent->ud = ud; diff --git a/contrib/libs/grpc/third_party/upb/upb/upb.h b/contrib/libs/grpc/third_party/upb/upb/upb.h index e1d9d8cfd3..11c0e4dc99 100644 --- a/contrib/libs/grpc/third_party/upb/upb/upb.h +++ b/contrib/libs/grpc/third_party/upb/upb/upb.h @@ -161,17 +161,35 @@ void *_upb_arena_slowmalloc(upb_arena *a, size_t size); UPB_INLINE upb_alloc *upb_arena_alloc(upb_arena *a) { return (upb_alloc*)a; } +UPB_INLINE size_t _upb_arenahas(upb_arena *a) { + _upb_arena_head *h = (_upb_arena_head*)a; + return (size_t)(h->end - h->ptr); +} + UPB_INLINE void *upb_arena_malloc(upb_arena *a, size_t size) { _upb_arena_head *h = (_upb_arena_head*)a; void* ret; size = UPB_ALIGN_MALLOC(size); - if (UPB_UNLIKELY((size_t)(h->end - h->ptr) < size)) { + if (UPB_UNLIKELY(_upb_arenahas(a) < size)) { return _upb_arena_slowmalloc(a, size); } ret = h->ptr; h->ptr += size; + UPB_UNPOISON_MEMORY_REGION(ret, size); + +#if UPB_ASAN + { + size_t guard_size = 32; + if (_upb_arenahas(a) >= guard_size) { + h->ptr += guard_size; + } else { + h->ptr = h->end; + } + } +#endif + return ret; } @@ -283,7 +301,7 @@ UPB_INLINE uint32_t _upb_be_swap32(uint32_t val) { return val; } else { return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | - ((val & 0xff0000ULL) >> 8) | ((val & 0xff000000ULL) >> 24); + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); } } @@ -291,14 +309,25 @@ UPB_INLINE uint64_t _upb_be_swap64(uint64_t val) { if (_upb_isle()) { return val; } else { - return ((val & 0xff) << 56) | ((val & 0xff00) << 40) | - ((val & 0xff0000) << 24) | ((val & 0xff000000) << 8) | - ((val & 0xff00000000ULL) >> 8) | ((val & 0xff0000000000ULL) >> 24) | - ((val & 0xff000000000000ULL) >> 40) | - ((val & 0xff00000000000000ULL) >> 56); + return ((uint64_t)_upb_be_swap32(val) << 32) | _upb_be_swap32(val >> 32); } } +UPB_INLINE int _upb_lg2ceil(int x) { + if (x <= 1) return 0; +#ifdef __GNUC__ + return 32 - __builtin_clz(x - 1); +#else + int lg2 = 0; + while (1 << lg2 < x) lg2++; + return lg2; +#endif +} + +UPB_INLINE int _upb_lg2ceilsize(int x) { + return 1 << _upb_lg2ceil(x); +} + #include "upb/port_undef.inc" #ifdef __cplusplus diff --git a/contrib/libs/grpc/third_party/upb/upb/upb.hpp b/contrib/libs/grpc/third_party/upb/upb/upb.hpp index a3ec5faff8..b7b99761fb 100644 --- a/contrib/libs/grpc/third_party/upb/upb/upb.hpp +++ b/contrib/libs/grpc/third_party/upb/upb/upb.hpp @@ -41,6 +41,9 @@ class Arena { public: // A simple arena with no initial memory block and the default allocator. Arena() : ptr_(upb_arena_new(), upb_arena_free) {} + Arena(char *initial_block, size_t size) + : ptr_(upb_arena_init(initial_block, size, &upb_alloc_global), + upb_arena_free) {} upb_arena* ptr() { return ptr_.get(); } @@ -71,15 +74,12 @@ class Arena { template <int N> class InlinedArena : public Arena { public: - InlinedArena() : ptr_(upb_arena_new(&initial_block_, N, &upb_alloc_global)) {} - - upb_arena* ptr() { return ptr_.get(); } + InlinedArena() : Arena(initial_block_, N) {} private: InlinedArena(const InlinedArena*) = delete; InlinedArena& operator=(const InlinedArena*) = delete; - std::unique_ptr<upb_arena, decltype(&upb_arena_free)> ptr_; char initial_block_[N]; }; diff --git a/contrib/libs/grpc/third_party/upb/upb/upb.int.h b/contrib/libs/grpc/third_party/upb/upb/upb.int.h new file mode 100644 index 0000000000..b857560e4e --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/upb.int.h @@ -0,0 +1,29 @@ + +#ifndef UPB_INT_H_ +#define UPB_INT_H_ + +#include "upb/upb.h" + +struct mem_block; +typedef struct mem_block mem_block; + +struct upb_arena { + _upb_arena_head head; + uint32_t *cleanups; + + /* Allocator to allocate arena blocks. We are responsible for freeing these + * when we are destroyed. */ + upb_alloc *block_alloc; + uint32_t last_size; + + /* When multiple arenas are fused together, each arena points to a parent + * arena (root points to itself). The root tracks how many live arenas + * reference it. */ + uint32_t refcount; /* Only used when a->parent == a */ + struct upb_arena *parent; + + /* Linked list of blocks to free/cleanup. */ + mem_block *freelist, *freelist_tail; +}; + +#endif /* UPB_INT_H_ */ |