ruby_memprofiler_pprof 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. checksums.yaml +7 -0
  2. data/ext/ruby_memprofiler_pprof/backtrace.c +429 -0
  3. data/ext/ruby_memprofiler_pprof/collector.c +1055 -0
  4. data/ext/ruby_memprofiler_pprof/compat.c +182 -0
  5. data/ext/ruby_memprofiler_pprof/extconf.rb +72 -0
  6. data/ext/ruby_memprofiler_pprof/pprof.upb.c +170 -0
  7. data/ext/ruby_memprofiler_pprof/pprof.upb.h +848 -0
  8. data/ext/ruby_memprofiler_pprof/pprof_out.c +285 -0
  9. data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.c +11 -0
  10. data/ext/ruby_memprofiler_pprof/ruby_memprofiler_pprof.h +301 -0
  11. data/ext/ruby_memprofiler_pprof/strtab.c +391 -0
  12. data/ext/ruby_memprofiler_pprof/vendor/upb/BUILD +719 -0
  13. data/ext/ruby_memprofiler_pprof/vendor/upb/CONTRIBUTING.md +37 -0
  14. data/ext/ruby_memprofiler_pprof/vendor/upb/DESIGN.md +201 -0
  15. data/ext/ruby_memprofiler_pprof/vendor/upb/LICENSE +26 -0
  16. data/ext/ruby_memprofiler_pprof/vendor/upb/README.md +78 -0
  17. data/ext/ruby_memprofiler_pprof/vendor/upb/WORKSPACE +58 -0
  18. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/BUILD +53 -0
  19. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/amalgamate.py +129 -0
  20. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/build_defs.bzl +160 -0
  21. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/lua.BUILD +127 -0
  22. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/protobuf.patch +54 -0
  23. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/py_proto_library.bzl +137 -0
  24. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/python_downloads.bzl +84 -0
  25. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/system_python.bzl +101 -0
  26. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/upb_proto_library.bzl +388 -0
  27. data/ext/ruby_memprofiler_pprof/vendor/upb/bazel/workspace_deps.bzl +89 -0
  28. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD +252 -0
  29. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/BUILD.googleapis +54 -0
  30. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/benchmark.cc +333 -0
  31. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/build_defs.bzl +88 -0
  32. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/compare.py +118 -0
  33. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor.proto +888 -0
  34. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/descriptor_sv.proto +890 -0
  35. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/empty.proto +6 -0
  36. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_protobuf_binary_cc.py +64 -0
  37. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_synthetic_protos.py +118 -0
  38. data/ext/ruby_memprofiler_pprof/vendor/upb/benchmarks/gen_upb_binary_c.py +65 -0
  39. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/BUILD.bazel +102 -0
  40. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/README.md +23 -0
  41. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/build_defs.bzl +73 -0
  42. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/make_cmakelists.py +340 -0
  43. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test.py +57 -0
  44. data/ext/ruby_memprofiler_pprof/vendor/upb/cmake/staleness_test_lib.py +186 -0
  45. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/render.py +43 -0
  46. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/style-guide.md +65 -0
  47. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/vs-cpp-protos.md +255 -0
  48. data/ext/ruby_memprofiler_pprof/vendor/upb/docs/wrapping-upb.md +444 -0
  49. data/ext/ruby_memprofiler_pprof/vendor/upb/python/BUILD +216 -0
  50. data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.c +394 -0
  51. data/ext/ruby_memprofiler_pprof/vendor/upb/python/convert.h +63 -0
  52. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.c +1694 -0
  53. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor.h +80 -0
  54. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.c +704 -0
  55. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_containers.h +114 -0
  56. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.c +650 -0
  57. data/ext/ruby_memprofiler_pprof/vendor/upb/python/descriptor_pool.h +48 -0
  58. data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/BUILD.bazel +193 -0
  59. data/ext/ruby_memprofiler_pprof/vendor/upb/python/dist/dist.bzl +190 -0
  60. data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.c +247 -0
  61. data/ext/ruby_memprofiler_pprof/vendor/upb/python/extension_dict.h +39 -0
  62. data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.c +522 -0
  63. data/ext/ruby_memprofiler_pprof/vendor/upb/python/map.h +66 -0
  64. data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.c +1909 -0
  65. data/ext/ruby_memprofiler_pprof/vendor/upb/python/message.h +101 -0
  66. data/ext/ruby_memprofiler_pprof/vendor/upb/python/minimal_test.py +183 -0
  67. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/BUILD +70 -0
  68. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/README.md +11 -0
  69. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_database_test_wrapper.py +30 -0
  70. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_pool_test_wrapper.py +45 -0
  71. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/descriptor_test_wrapper.py +46 -0
  72. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/generator_test_wrapper.py +30 -0
  73. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/json_format_test_wrapper.py +30 -0
  74. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/keywords_test_wrapper.py +30 -0
  75. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_factory_test_wrapper.py +37 -0
  76. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/message_test_wrapper.py +52 -0
  77. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/proto_builder_test_wrapper.py +32 -0
  78. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/pyproto_test_wrapper.bzl +36 -0
  79. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/reflection_test_wrapper.py +45 -0
  80. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/service_reflection_test_wrapper.py +30 -0
  81. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/symbol_database_test_wrapper.py +30 -0
  82. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_encoding_test_wrapper.py +30 -0
  83. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/text_format_test_wrapper.py +30 -0
  84. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/unknown_fields_test_wrapper.py +30 -0
  85. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/well_known_types_test_wrapper.py +36 -0
  86. data/ext/ruby_memprofiler_pprof/vendor/upb/python/pb_unit_tests/wire_format_test_wrapper.py +30 -0
  87. data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.c +350 -0
  88. data/ext/ruby_memprofiler_pprof/vendor/upb/python/protobuf.h +230 -0
  89. data/ext/ruby_memprofiler_pprof/vendor/upb/python/py_extension.bzl +55 -0
  90. data/ext/ruby_memprofiler_pprof/vendor/upb/python/python_api.h +61 -0
  91. data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.c +828 -0
  92. data/ext/ruby_memprofiler_pprof/vendor/upb/python/repeated.h +69 -0
  93. data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.c +404 -0
  94. data/ext/ruby_memprofiler_pprof/vendor/upb/python/unknown_fields.h +39 -0
  95. data/ext/ruby_memprofiler_pprof/vendor/upb/python/version_script.lds +6 -0
  96. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/LICENSE +32 -0
  97. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/README.google +9 -0
  98. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/console.lua +156 -0
  99. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/lunit/lunit.lua +725 -0
  100. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/BUILD +19 -0
  101. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/LICENSE +21 -0
  102. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/naive.c +92 -0
  103. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-neon.c +157 -0
  104. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/range2-sse.c +170 -0
  105. data/ext/ruby_memprofiler_pprof/vendor/upb/third_party/utf8_range/utf8_range.h +9 -0
  106. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/BUILD.bazel +129 -0
  107. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/README.md +8 -0
  108. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/def.c +939 -0
  109. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/lua_proto_library.bzl +138 -0
  110. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/main.c +83 -0
  111. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/msg.c +1118 -0
  112. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test.proto +69 -0
  113. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/test_upb.lua +846 -0
  114. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.c +258 -0
  115. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.h +132 -0
  116. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upb.lua +58 -0
  117. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/bindings/lua/upbc.cc +134 -0
  118. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.c +192 -0
  119. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/collections.h +174 -0
  120. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb.c +346 -0
  121. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/conformance_upb_failures.txt +1 -0
  122. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.c +1221 -0
  123. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode.h +94 -0
  124. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.c +1055 -0
  125. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_fast.h +153 -0
  126. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/decode_internal.h +211 -0
  127. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.c +3262 -0
  128. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.h +414 -0
  129. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/def.hpp +438 -0
  130. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/empty.proto +1 -0
  131. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.c +604 -0
  132. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/encode.h +71 -0
  133. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/BUILD +13 -0
  134. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/fuzz/file_descriptor_parsenew_fuzzer.cc +43 -0
  135. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.c +1509 -0
  136. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_decode.h +47 -0
  137. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.c +776 -0
  138. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/json_encode.h +62 -0
  139. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.c +1147 -0
  140. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.h +189 -0
  141. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table.hpp +112 -0
  142. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.c +363 -0
  143. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors.h +263 -0
  144. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_internal.h +59 -0
  145. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_accessors_test.cc +425 -0
  146. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/mini_table_test.cc +230 -0
  147. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.c +428 -0
  148. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg.h +114 -0
  149. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_internal.h +836 -0
  150. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.cc +491 -0
  151. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/msg_test.proto +195 -0
  152. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_def.inc +261 -0
  153. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/port_undef.inc +62 -0
  154. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.c +323 -0
  155. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.h +109 -0
  156. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/reflection.hpp +37 -0
  157. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table.c +926 -0
  158. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/table_internal.h +385 -0
  159. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test.proto +74 -0
  160. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.cc +186 -0
  161. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_cpp.proto +12 -0
  162. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_generated_code.cc +977 -0
  163. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/test_table.cc +580 -0
  164. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.c +472 -0
  165. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/text_encode.h +64 -0
  166. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.c +362 -0
  167. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.h +378 -0
  168. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb.hpp +115 -0
  169. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/upb_internal.h +68 -0
  170. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/BUILD +121 -0
  171. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/README.md +7 -0
  172. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.c +300 -0
  173. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare.h +66 -0
  174. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/compare_test.cc +236 -0
  175. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.c +572 -0
  176. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto.h +62 -0
  177. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_public_import_test.proto +32 -0
  178. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_regular_import_test.proto +36 -0
  179. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.cc +143 -0
  180. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_test.proto +119 -0
  181. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_weak_import_test.proto +28 -0
  182. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/def_to_proto_wweak_import_test.proto +28 -0
  183. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.c +311 -0
  184. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields.h +94 -0
  185. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.cc +202 -0
  186. data/ext/ruby_memprofiler_pprof/vendor/upb/upb/util/required_fields_test.proto +48 -0
  187. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/BUILD +78 -0
  188. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.cc +77 -0
  189. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/common.h +112 -0
  190. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upb.cc +1997 -0
  191. data/ext/ruby_memprofiler_pprof/vendor/upb/upbc/protoc-gen-upbdefs.cc +193 -0
  192. data/lib/ruby_memprofiler_pprof/atfork.rb +77 -0
  193. data/lib/ruby_memprofiler_pprof/block_flusher.rb +61 -0
  194. data/lib/ruby_memprofiler_pprof/file_flusher.rb +45 -0
  195. data/lib/ruby_memprofiler_pprof/profile_app.rb +30 -0
  196. data/lib/ruby_memprofiler_pprof/profile_data.rb +18 -0
  197. data/lib/ruby_memprofiler_pprof/version.rb +5 -0
  198. data/lib/ruby_memprofiler_pprof.rb +8 -0
  199. data/libexec/ruby_memprofiler_pprof_profile +16 -0
  200. metadata +257 -0
@@ -0,0 +1,1997 @@
1
+ // Copyright (c) 2009-2021, Google LLC
2
+ // All rights reserved.
3
+ //
4
+ // Redistribution and use in source and binary forms, with or without
5
+ // modification, are permitted provided that the following conditions are met:
6
+ // * Redistributions of source code must retain the above copyright
7
+ // notice, this list of conditions and the following disclaimer.
8
+ // * Redistributions in binary form must reproduce the above copyright
9
+ // notice, this list of conditions and the following disclaimer in the
10
+ // documentation and/or other materials provided with the distribution.
11
+ // * Neither the name of Google LLC nor the
12
+ // names of its contributors may be used to endorse or promote products
13
+ // derived from this software without specific prior written permission.
14
+ //
15
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ // ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
19
+ // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ #include <memory>
27
+
28
+ #include "absl/container/flat_hash_map.h"
29
+ #include "absl/container/flat_hash_set.h"
30
+ #include "absl/strings/ascii.h"
31
+ #include "absl/strings/substitute.h"
32
+ #include "google/protobuf/compiler/code_generator.h"
33
+ #include "google/protobuf/compiler/plugin.h"
34
+ #include "google/protobuf/descriptor.h"
35
+ #include "google/protobuf/descriptor.pb.h"
36
+ #include "google/protobuf/wire_format.h"
37
+ #include "upb/mini_table.hpp"
38
+ #include "upb/upb.hpp"
39
+ #include "upbc/common.h"
40
+
41
+ // Must be last.
42
+ #include "upb/port_def.inc"
43
+
44
+ namespace upbc {
45
+ namespace {
46
+
47
+ namespace protoc = ::google::protobuf::compiler;
48
+ namespace protobuf = ::google::protobuf;
49
+
50
+ // Returns fields in order of "hotness", eg. how frequently they appear in
51
+ // serialized payloads. Ideally this will use a profile. When we don't have
52
+ // that, we assume that fields with smaller numbers are used more frequently.
53
+ inline std::vector<const google::protobuf::FieldDescriptor*> FieldHotnessOrder(
54
+ const google::protobuf::Descriptor* message) {
55
+ std::vector<const google::protobuf::FieldDescriptor*> fields;
56
+ for (int i = 0; i < message->field_count(); i++) {
57
+ fields.push_back(message->field(i));
58
+ }
59
+ std::sort(fields.begin(), fields.end(),
60
+ [](const google::protobuf::FieldDescriptor* a,
61
+ const google::protobuf::FieldDescriptor* b) {
62
+ return std::make_pair(!a->is_required(), a->number()) <
63
+ std::make_pair(!b->is_required(), b->number());
64
+ });
65
+ return fields;
66
+ }
67
+
68
+ std::string SourceFilename(const google::protobuf::FileDescriptor* file) {
69
+ return StripExtension(file->name()) + ".upb.c";
70
+ }
71
+
72
+ std::string MessageInit(const protobuf::Descriptor* descriptor) {
73
+ return MessageName(descriptor) + "_msginit";
74
+ }
75
+
76
+ std::string EnumInit(const protobuf::EnumDescriptor* descriptor) {
77
+ return ToCIdent(descriptor->full_name()) + "_enuminit";
78
+ }
79
+
80
+ std::string ExtensionIdentBase(const protobuf::FieldDescriptor* ext) {
81
+ assert(ext->is_extension());
82
+ std::string ext_scope;
83
+ if (ext->extension_scope()) {
84
+ return MessageName(ext->extension_scope());
85
+ } else {
86
+ return ToCIdent(ext->file()->package());
87
+ }
88
+ }
89
+
90
+ std::string ExtensionLayout(const google::protobuf::FieldDescriptor* ext) {
91
+ return absl::StrCat(ExtensionIdentBase(ext), "_", ext->name(), "_ext");
92
+ }
93
+
94
+ const char* kEnumsInit = "enums_layout";
95
+ const char* kExtensionsInit = "extensions_layout";
96
+ const char* kMessagesInit = "messages_layout";
97
+
98
+ void AddEnums(const protobuf::Descriptor* message,
99
+ std::vector<const protobuf::EnumDescriptor*>* enums) {
100
+ enums->reserve(enums->size() + message->enum_type_count());
101
+ for (int i = 0; i < message->enum_type_count(); i++) {
102
+ enums->push_back(message->enum_type(i));
103
+ }
104
+ for (int i = 0; i < message->nested_type_count(); i++) {
105
+ AddEnums(message->nested_type(i), enums);
106
+ }
107
+ }
108
+
109
+ std::vector<const protobuf::EnumDescriptor*> SortedEnums(
110
+ const protobuf::FileDescriptor* file) {
111
+ std::vector<const protobuf::EnumDescriptor*> enums;
112
+ enums.reserve(file->enum_type_count());
113
+ for (int i = 0; i < file->enum_type_count(); i++) {
114
+ enums.push_back(file->enum_type(i));
115
+ }
116
+ for (int i = 0; i < file->message_type_count(); i++) {
117
+ AddEnums(file->message_type(i), &enums);
118
+ }
119
+ return enums;
120
+ }
121
+
122
+ std::vector<uint32_t> SortedUniqueEnumNumbers(
123
+ const protobuf::EnumDescriptor* e) {
124
+ std::vector<uint32_t> values;
125
+ values.reserve(e->value_count());
126
+ for (int i = 0; i < e->value_count(); i++) {
127
+ values.push_back(static_cast<uint32_t>(e->value(i)->number()));
128
+ }
129
+ std::sort(values.begin(), values.end());
130
+ auto last = std::unique(values.begin(), values.end());
131
+ values.erase(last, values.end());
132
+ return values;
133
+ }
134
+
135
+ void AddMessages(const protobuf::Descriptor* message,
136
+ std::vector<const protobuf::Descriptor*>* messages) {
137
+ messages->push_back(message);
138
+ for (int i = 0; i < message->nested_type_count(); i++) {
139
+ AddMessages(message->nested_type(i), messages);
140
+ }
141
+ }
142
+
143
+ // Ordering must match upb/def.c!
144
+ //
145
+ // The ordering is significant because each upb_MessageDef* will point at the
146
+ // corresponding upb_MiniTable and we just iterate through the list without
147
+ // any search or lookup.
148
+ std::vector<const protobuf::Descriptor*> SortedMessages(
149
+ const protobuf::FileDescriptor* file) {
150
+ std::vector<const protobuf::Descriptor*> messages;
151
+ for (int i = 0; i < file->message_type_count(); i++) {
152
+ AddMessages(file->message_type(i), &messages);
153
+ }
154
+ return messages;
155
+ }
156
+
157
+ void AddExtensionsFromMessage(
158
+ const protobuf::Descriptor* message,
159
+ std::vector<const protobuf::FieldDescriptor*>* exts) {
160
+ for (int i = 0; i < message->extension_count(); i++) {
161
+ exts->push_back(message->extension(i));
162
+ }
163
+ for (int i = 0; i < message->nested_type_count(); i++) {
164
+ AddExtensionsFromMessage(message->nested_type(i), exts);
165
+ }
166
+ }
167
+
168
+ // Ordering must match upb/def.c!
169
+ //
170
+ // The ordering is significant because each upb_FieldDef* will point at the
171
+ // corresponding upb_MiniTable_Extension and we just iterate through the list
172
+ // without any search or lookup.
173
+ std::vector<const protobuf::FieldDescriptor*> SortedExtensions(
174
+ const protobuf::FileDescriptor* file) {
175
+ std::vector<const protobuf::FieldDescriptor*> ret;
176
+ for (int i = 0; i < file->extension_count(); i++) {
177
+ ret.push_back(file->extension(i));
178
+ }
179
+ for (int i = 0; i < file->message_type_count(); i++) {
180
+ AddExtensionsFromMessage(file->message_type(i), &ret);
181
+ }
182
+ return ret;
183
+ }
184
+
185
+ std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder(
186
+ const protobuf::Descriptor* message) {
187
+ std::vector<const protobuf::FieldDescriptor*> fields;
188
+ for (int i = 0; i < message->field_count(); i++) {
189
+ fields.push_back(message->field(i));
190
+ }
191
+ std::sort(fields.begin(), fields.end(),
192
+ [](const protobuf::FieldDescriptor* a,
193
+ const protobuf::FieldDescriptor* b) {
194
+ return a->number() < b->number();
195
+ });
196
+ return fields;
197
+ }
198
+
199
+ std::string EnumValueSymbol(const protobuf::EnumValueDescriptor* value) {
200
+ return ToCIdent(value->full_name());
201
+ }
202
+
203
+ std::string CTypeInternal(const protobuf::FieldDescriptor* field,
204
+ bool is_const) {
205
+ std::string maybe_const = is_const ? "const " : "";
206
+ switch (field->cpp_type()) {
207
+ case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
208
+ std::string maybe_struct =
209
+ field->file() != field->message_type()->file() ? "struct " : "";
210
+ return maybe_const + maybe_struct + MessageName(field->message_type()) +
211
+ "*";
212
+ }
213
+ case protobuf::FieldDescriptor::CPPTYPE_BOOL:
214
+ return "bool";
215
+ case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
216
+ return "float";
217
+ case protobuf::FieldDescriptor::CPPTYPE_INT32:
218
+ case protobuf::FieldDescriptor::CPPTYPE_ENUM:
219
+ return "int32_t";
220
+ case protobuf::FieldDescriptor::CPPTYPE_UINT32:
221
+ return "uint32_t";
222
+ case protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
223
+ return "double";
224
+ case protobuf::FieldDescriptor::CPPTYPE_INT64:
225
+ return "int64_t";
226
+ case protobuf::FieldDescriptor::CPPTYPE_UINT64:
227
+ return "uint64_t";
228
+ case protobuf::FieldDescriptor::CPPTYPE_STRING:
229
+ return "upb_StringView";
230
+ default:
231
+ fprintf(stderr, "Unexpected type");
232
+ abort();
233
+ }
234
+ }
235
+
236
+ std::string SizeLg2(const protobuf::FieldDescriptor* field) {
237
+ switch (field->cpp_type()) {
238
+ case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
239
+ return "UPB_SIZE(2, 3)";
240
+ case protobuf::FieldDescriptor::CPPTYPE_ENUM:
241
+ return std::to_string(2);
242
+ case protobuf::FieldDescriptor::CPPTYPE_BOOL:
243
+ return std::to_string(1);
244
+ case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
245
+ return std::to_string(2);
246
+ case protobuf::FieldDescriptor::CPPTYPE_INT32:
247
+ return std::to_string(2);
248
+ case protobuf::FieldDescriptor::CPPTYPE_UINT32:
249
+ return std::to_string(2);
250
+ case protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
251
+ return std::to_string(3);
252
+ case protobuf::FieldDescriptor::CPPTYPE_INT64:
253
+ return std::to_string(3);
254
+ case protobuf::FieldDescriptor::CPPTYPE_UINT64:
255
+ return std::to_string(3);
256
+ case protobuf::FieldDescriptor::CPPTYPE_STRING:
257
+ return "UPB_SIZE(3, 4)";
258
+ default:
259
+ fprintf(stderr, "Unexpected type");
260
+ abort();
261
+ }
262
+ }
263
+
264
+ bool HasNonZeroDefault(const protobuf::FieldDescriptor* field) {
265
+ switch (field->cpp_type()) {
266
+ case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
267
+ return false;
268
+ case protobuf::FieldDescriptor::CPPTYPE_STRING:
269
+ return !field->default_value_string().empty();
270
+ case protobuf::FieldDescriptor::CPPTYPE_INT32:
271
+ return field->default_value_int32() != 0;
272
+ case protobuf::FieldDescriptor::CPPTYPE_INT64:
273
+ return field->default_value_int64() != 0;
274
+ case protobuf::FieldDescriptor::CPPTYPE_UINT32:
275
+ return field->default_value_uint32() != 0;
276
+ case protobuf::FieldDescriptor::CPPTYPE_UINT64:
277
+ return field->default_value_uint64() != 0;
278
+ case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
279
+ return field->default_value_float() != 0;
280
+ case protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
281
+ return field->default_value_double() != 0;
282
+ case protobuf::FieldDescriptor::CPPTYPE_BOOL:
283
+ return field->default_value_bool() != false;
284
+ case protobuf::FieldDescriptor::CPPTYPE_ENUM:
285
+ // Use a number instead of a symbolic name so that we don't require
286
+ // this enum's header to be included.
287
+ return field->default_value_enum()->number() != 0;
288
+ }
289
+ ABSL_ASSERT(false);
290
+ return false;
291
+ }
292
+
293
+ std::string FieldDefault(const protobuf::FieldDescriptor* field) {
294
+ switch (field->cpp_type()) {
295
+ case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
296
+ return "NULL";
297
+ case protobuf::FieldDescriptor::CPPTYPE_STRING:
298
+ return absl::Substitute("upb_StringView_FromString(\"$0\")",
299
+ absl::CEscape(field->default_value_string()));
300
+ case protobuf::FieldDescriptor::CPPTYPE_INT32:
301
+ return absl::Substitute("_upb_Int32_FromI($0)",
302
+ field->default_value_int32());
303
+ case protobuf::FieldDescriptor::CPPTYPE_INT64:
304
+ return absl::Substitute("_upb_Int64_FromLL($0ll)",
305
+ field->default_value_int64());
306
+ case protobuf::FieldDescriptor::CPPTYPE_UINT32:
307
+ return absl::Substitute("_upb_UInt32_FromU($0u)",
308
+ field->default_value_uint32());
309
+ case protobuf::FieldDescriptor::CPPTYPE_UINT64:
310
+ return absl::Substitute("_upb_UInt64_FromULL($0ull)",
311
+ field->default_value_uint64());
312
+ case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
313
+ return absl::StrCat(field->default_value_float());
314
+ case protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
315
+ return absl::StrCat(field->default_value_double());
316
+ case protobuf::FieldDescriptor::CPPTYPE_BOOL:
317
+ return field->default_value_bool() ? "true" : "false";
318
+ case protobuf::FieldDescriptor::CPPTYPE_ENUM:
319
+ // Use a number instead of a symbolic name so that we don't require
320
+ // this enum's header to be included.
321
+ return absl::StrCat(field->default_value_enum()->number());
322
+ }
323
+ ABSL_ASSERT(false);
324
+ return "XXX";
325
+ }
326
+
327
+ std::string CType(const protobuf::FieldDescriptor* field) {
328
+ return CTypeInternal(field, false);
329
+ }
330
+
331
+ std::string CTypeConst(const protobuf::FieldDescriptor* field) {
332
+ return CTypeInternal(field, true);
333
+ }
334
+
335
+ ////////////////////////////////////////////////////////////////////////////////
336
+ // FilePlatformLayout
337
+ ////////////////////////////////////////////////////////////////////////////////
338
+
339
+ // FilePlatformLayout builds and vends upb MiniTables for a given platform (32
340
+ // or 64 bit).
341
+ class FilePlatformLayout {
342
+ public:
343
+ FilePlatformLayout(const protobuf::FileDescriptor* fd,
344
+ upb_MiniTablePlatform platform)
345
+ : platform_(platform) {
346
+ BuildMiniTables(fd);
347
+ BuildExtensions(fd);
348
+ }
349
+
350
+ // Retrieves a upb MiniTable or Extension given a protobuf descriptor. The
351
+ // descriptor must be from this layout's file.
352
+ upb_MiniTable* GetMiniTable(const protobuf::Descriptor* m) const;
353
+ upb_MiniTable_Enum* GetEnumTable(const protobuf::EnumDescriptor* d) const;
354
+ const upb_MiniTable_Extension* GetExtension(
355
+ const protobuf::FieldDescriptor* fd) const;
356
+
357
+ // Get the initializer for the given sub-message/sub-enum link.
358
+ static std::string GetSub(upb_MiniTable_Sub sub);
359
+
360
+ private:
361
+ // Functions to build mini-tables for this file's messages and extensions.
362
+ void BuildMiniTables(const protobuf::FileDescriptor* fd);
363
+ void BuildExtensions(const protobuf::FileDescriptor* fd);
364
+ upb_MiniTable* MakeMiniTable(const protobuf::Descriptor* m);
365
+ upb_MiniTable* MakeRegularMiniTable(const protobuf::Descriptor* m);
366
+ upb_MiniTable_Enum* MakeMiniTableEnum(const protobuf::EnumDescriptor* d);
367
+ uint64_t GetMessageModifiers(const protobuf::Descriptor* m);
368
+ uint64_t GetFieldModifiers(const protobuf::FieldDescriptor* f);
369
+ void ResolveIntraFileReferences();
370
+
371
+ // When we are generating code, tables are linked to sub-tables via name (ie.
372
+ // a string) rather than by pointer. We need to emit an initializer like
373
+ // `&foo_sub_table`. To do this, we store `const char*` strings in all the
374
+ // links that would normally be pointers:
375
+ // field -> sub-message
376
+ // field -> enum table (proto2 only)
377
+ // extension -> extendee
378
+ //
379
+ // This requires a bit of reinterpret_cast<>(), but it's confined to a few
380
+ // functions. We tag the pointer so we know which member of the union to
381
+ // initialize.
382
+ enum SubTag {
383
+ kNull = 0,
384
+ kMessage = 1,
385
+ kEnum = 2,
386
+ kMask = 3,
387
+ };
388
+
389
+ static upb_MiniTable_Sub PackSub(const char* data, SubTag tag);
390
+ static bool IsNull(upb_MiniTable_Sub sub);
391
+ void SetSubTableStrings();
392
+ upb_MiniTable_Sub PackSubForField(const protobuf::FieldDescriptor* f,
393
+ const upb_MiniTable_Field* mt_f);
394
+ const char* AllocStr(absl::string_view str);
395
+
396
+ private:
397
+ using TableMap =
398
+ absl::flat_hash_map<const protobuf::Descriptor*, upb_MiniTable*>;
399
+ using EnumMap =
400
+ absl::flat_hash_map<const protobuf::EnumDescriptor*, upb_MiniTable_Enum*>;
401
+ using ExtensionMap = absl::flat_hash_map<const protobuf::FieldDescriptor*,
402
+ upb_MiniTable_Extension>;
403
+ upb::Arena arena_;
404
+ TableMap table_map_;
405
+ EnumMap enum_map_;
406
+ ExtensionMap extension_map_;
407
+ upb_MiniTablePlatform platform_;
408
+ };
409
+
410
+ upb_MiniTable* FilePlatformLayout::GetMiniTable(
411
+ const protobuf::Descriptor* m) const {
412
+ auto it = table_map_.find(m);
413
+ assert(it != table_map_.end());
414
+ return it->second;
415
+ }
416
+
417
+ upb_MiniTable_Enum* FilePlatformLayout::GetEnumTable(
418
+ const protobuf::EnumDescriptor* d) const {
419
+ auto it = enum_map_.find(d);
420
+ assert(it != enum_map_.end());
421
+ return it->second;
422
+ }
423
+
424
+ const upb_MiniTable_Extension* FilePlatformLayout::GetExtension(
425
+ const protobuf::FieldDescriptor* fd) const {
426
+ auto it = extension_map_.find(fd);
427
+ assert(it != extension_map_.end());
428
+ return &it->second;
429
+ }
430
+
431
+ void FilePlatformLayout::ResolveIntraFileReferences() {
432
+ // This properly resolves references within a file, in order to set any
433
+ // necessary flags (eg. is a map).
434
+ for (const auto& pair : table_map_) {
435
+ upb_MiniTable* mt = pair.second;
436
+ // First we properly resolve for defs within the file.
437
+ for (const auto* f : FieldNumberOrder(pair.first)) {
438
+ if (f->message_type() && f->message_type()->file() == f->file()) {
439
+ // const_cast is safe because the mini-table is owned exclusively
440
+ // by us, and was allocated from an arena (known-writable memory).
441
+ upb_MiniTable_Field* mt_f = const_cast<upb_MiniTable_Field*>(
442
+ upb_MiniTable_FindFieldByNumber(mt, f->number()));
443
+ upb_MiniTable* sub_mt = GetMiniTable(f->message_type());
444
+ upb_MiniTable_SetSubMessage(mt, mt_f, sub_mt);
445
+ }
446
+ // We don't worry about enums here, because resolving an enum will
447
+ // never alter the mini-table.
448
+ }
449
+ }
450
+ }
451
+
452
+ upb_MiniTable_Sub FilePlatformLayout::PackSub(const char* data, SubTag tag) {
453
+ uintptr_t val = reinterpret_cast<uintptr_t>(data);
454
+ assert((val & kMask) == 0);
455
+ upb_MiniTable_Sub sub;
456
+ sub.submsg = reinterpret_cast<upb_MiniTable*>(val | tag);
457
+ return sub;
458
+ }
459
+
460
+ bool FilePlatformLayout::IsNull(upb_MiniTable_Sub sub) {
461
+ return reinterpret_cast<uintptr_t>(sub.subenum) == 0;
462
+ }
463
+
464
+ std::string FilePlatformLayout::GetSub(upb_MiniTable_Sub sub) {
465
+ uintptr_t as_int = reinterpret_cast<uintptr_t>(sub.submsg);
466
+ const char* str = reinterpret_cast<const char*>(as_int & ~SubTag::kMask);
467
+ switch (as_int & SubTag::kMask) {
468
+ case SubTag::kMessage:
469
+ return absl::Substitute("{.submsg = &$0}", str);
470
+ case SubTag::kEnum:
471
+ return absl::Substitute("{.subenum = &$0}", str);
472
+ default:
473
+ return std::string("{.submsg = NULL}");
474
+ }
475
+ return std::string("ERROR in GetSub");
476
+ }
477
+
478
+ void FilePlatformLayout::SetSubTableStrings() {
479
+ for (const auto& pair : table_map_) {
480
+ upb_MiniTable* mt = pair.second;
481
+ for (const auto* f : FieldNumberOrder(pair.first)) {
482
+ upb_MiniTable_Field* mt_f = const_cast<upb_MiniTable_Field*>(
483
+ upb_MiniTable_FindFieldByNumber(mt, f->number()));
484
+ assert(mt_f);
485
+ upb_MiniTable_Sub sub = PackSubForField(f, mt_f);
486
+ if (IsNull(sub)) continue;
487
+ // const_cast is safe because the mini-table is owned exclusively
488
+ // by us, and was allocated from an arena (known-writable memory).
489
+ *const_cast<upb_MiniTable_Sub*>(&mt->subs[mt_f->submsg_index]) = sub;
490
+ }
491
+ }
492
+ }
493
+
494
+ upb_MiniTable_Sub FilePlatformLayout::PackSubForField(
495
+ const protobuf::FieldDescriptor* f, const upb_MiniTable_Field* mt_f) {
496
+ if (mt_f->submsg_index == kUpb_NoSub) {
497
+ return PackSub(nullptr, SubTag::kNull);
498
+ } else if (f->message_type()) {
499
+ return PackSub(AllocStr(MessageInit(f->message_type())), SubTag::kMessage);
500
+ } else {
501
+ ABSL_ASSERT(f->enum_type());
502
+ return PackSub(AllocStr(EnumInit(f->enum_type())), SubTag::kEnum);
503
+ }
504
+ }
505
+
506
+ const char* FilePlatformLayout::AllocStr(absl::string_view str) {
507
+ char* ret =
508
+ static_cast<char*>(upb_Arena_Malloc(arena_.ptr(), str.size() + 1));
509
+ memcpy(ret, str.data(), str.size());
510
+ ret[str.size()] = '\0';
511
+ return ret;
512
+ }
513
+
514
+ void FilePlatformLayout::BuildMiniTables(const protobuf::FileDescriptor* fd) {
515
+ for (const auto& m : SortedMessages(fd)) {
516
+ table_map_[m] = MakeMiniTable(m);
517
+ }
518
+ for (const auto& e : SortedEnums(fd)) {
519
+ enum_map_[e] = MakeMiniTableEnum(e);
520
+ }
521
+ ResolveIntraFileReferences();
522
+ SetSubTableStrings();
523
+ }
524
+
525
+ void FilePlatformLayout::BuildExtensions(const protobuf::FileDescriptor* fd) {
526
+ std::vector<const protobuf::FieldDescriptor*> sorted = SortedExtensions(fd);
527
+ upb::Status status;
528
+ for (const auto* f : sorted) {
529
+ upb::MtDataEncoder e;
530
+ e.StartMessage(0);
531
+ e.PutField(static_cast<upb_FieldType>(f->type()), f->number(),
532
+ GetFieldModifiers(f));
533
+ upb_MiniTable_Extension& ext = extension_map_[f];
534
+ upb_MiniTable_Sub sub;
535
+ bool ok = upb_MiniTable_BuildExtension(e.data().data(), e.data().size(),
536
+ &ext, sub, status.ptr());
537
+ if (!ok) {
538
+ // TODO(haberman): Use ABSL CHECK() when it is available.
539
+ fprintf(stderr, "Error building mini-table: %s\n",
540
+ status.error_message());
541
+ }
542
+ ABSL_ASSERT(ok);
543
+ ext.extendee = reinterpret_cast<const upb_MiniTable*>(
544
+ AllocStr(MessageInit(f->containing_type())));
545
+ ext.sub = PackSubForField(f, &ext.field);
546
+ }
547
+ }
548
+
549
+ upb_MiniTable* FilePlatformLayout::MakeMiniTable(
550
+ const protobuf::Descriptor* m) {
551
+ if (m->options().message_set_wire_format()) {
552
+ return upb_MiniTable_BuildMessageSet(platform_, arena_.ptr());
553
+ } else if (m->options().map_entry()) {
554
+ return upb_MiniTable_BuildMapEntry(
555
+ static_cast<upb_FieldType>(m->map_key()->type()),
556
+ static_cast<upb_FieldType>(m->map_value()->type()),
557
+ m->map_value()->enum_type() &&
558
+ m->map_value()->enum_type()->file()->syntax() ==
559
+ protobuf::FileDescriptor::SYNTAX_PROTO3,
560
+ platform_, arena_.ptr());
561
+ } else {
562
+ return MakeRegularMiniTable(m);
563
+ }
564
+ }
565
+
566
+ upb_MiniTable* FilePlatformLayout::MakeRegularMiniTable(
567
+ const protobuf::Descriptor* m) {
568
+ upb::MtDataEncoder e;
569
+ e.StartMessage(GetMessageModifiers(m));
570
+ for (const auto* f : FieldNumberOrder(m)) {
571
+ e.PutField(static_cast<upb_FieldType>(f->type()), f->number(),
572
+ GetFieldModifiers(f));
573
+ }
574
+ for (int i = 0; i < m->real_oneof_decl_count(); i++) {
575
+ const protobuf::OneofDescriptor* oneof = m->oneof_decl(i);
576
+ e.StartOneof();
577
+ for (int j = 0; j < oneof->field_count(); j++) {
578
+ const protobuf::FieldDescriptor* f = oneof->field(j);
579
+ e.PutOneofField(f->number());
580
+ }
581
+ }
582
+ absl::string_view str = e.data();
583
+ upb::Status status;
584
+ upb_MiniTable* ret = upb_MiniTable_Build(str.data(), str.size(), platform_,
585
+ arena_.ptr(), status.ptr());
586
+ if (!ret) {
587
+ fprintf(stderr, "Error building mini-table: %s\n", status.error_message());
588
+ }
589
+ assert(ret);
590
+ return ret;
591
+ }
592
+
593
+ upb_MiniTable_Enum* FilePlatformLayout::MakeMiniTableEnum(
594
+ const protobuf::EnumDescriptor* d) {
595
+ upb::Arena arena;
596
+ upb::MtDataEncoder e;
597
+
598
+ e.StartEnum();
599
+ for (uint32_t i : SortedUniqueEnumNumbers(d)) {
600
+ e.PutEnumValue(i);
601
+ }
602
+ e.EndEnum();
603
+
604
+ absl::string_view str = e.data();
605
+ upb::Status status;
606
+ upb_MiniTable_Enum* ret = upb_MiniTable_BuildEnum(str.data(), str.size(),
607
+ arena_.ptr(), status.ptr());
608
+ if (!ret) {
609
+ fprintf(stderr, "Error building mini-table: %s\n", status.error_message());
610
+ }
611
+ assert(ret);
612
+ return ret;
613
+ }
614
+
615
+ uint64_t FilePlatformLayout::GetMessageModifiers(
616
+ const protobuf::Descriptor* m) {
617
+ uint64_t ret = 0;
618
+
619
+ if (m->file()->syntax() == protobuf::FileDescriptor::SYNTAX_PROTO3) {
620
+ ret |= kUpb_MessageModifier_ValidateUtf8;
621
+ ret |= kUpb_MessageModifier_DefaultIsPacked;
622
+ }
623
+
624
+ if (m->extension_range_count() > 0) {
625
+ ret |= kUpb_MessageModifier_IsExtendable;
626
+ }
627
+
628
+ assert(!m->options().map_entry());
629
+ return ret;
630
+ }
631
+
632
+ uint64_t FilePlatformLayout::GetFieldModifiers(
633
+ const protobuf::FieldDescriptor* f) {
634
+ uint64_t ret = 0;
635
+
636
+ if (f->is_repeated()) ret |= kUpb_FieldModifier_IsRepeated;
637
+ if (f->is_required()) ret |= kUpb_FieldModifier_IsRequired;
638
+ if (f->is_packed()) ret |= kUpb_FieldModifier_IsPacked;
639
+ if (f->enum_type() && f->enum_type()->file()->syntax() ==
640
+ protobuf::FileDescriptor::SYNTAX_PROTO2) {
641
+ ret |= kUpb_FieldModifier_IsClosedEnum;
642
+ }
643
+ if (f->is_optional() && !f->has_presence()) {
644
+ ret |= kUpb_FieldModifier_IsProto3Singular;
645
+ }
646
+
647
+ return ret;
648
+ }
649
+
650
+ ////////////////////////////////////////////////////////////////////////////////
651
+ // FileLayout
652
+ ////////////////////////////////////////////////////////////////////////////////
653
+
654
+ // FileLayout is a pair of platform layouts: one for 32-bit and one for 64-bit.
655
+ class FileLayout {
656
+ public:
657
+ FileLayout(const protobuf::FileDescriptor* fd)
658
+ : descriptor_(fd),
659
+ layout32_(fd, kUpb_MiniTablePlatform_32Bit),
660
+ layout64_(fd, kUpb_MiniTablePlatform_64Bit) {}
661
+
662
+ const protobuf::FileDescriptor* descriptor() const { return descriptor_; }
663
+
664
+ const upb_MiniTable* GetMiniTable32(const protobuf::Descriptor* m) const {
665
+ return layout32_.GetMiniTable(m);
666
+ }
667
+
668
+ const upb_MiniTable* GetMiniTable64(const protobuf::Descriptor* m) const {
669
+ return layout64_.GetMiniTable(m);
670
+ }
671
+
672
+ const upb_MiniTable_Enum* GetEnumTable(
673
+ const protobuf::EnumDescriptor* d) const {
674
+ return layout64_.GetEnumTable(d);
675
+ }
676
+
677
+ std::string GetFieldOffset(const protobuf::FieldDescriptor* f) const {
678
+ const upb_MiniTable_Field* f_32 = upb_MiniTable_FindFieldByNumber(
679
+ GetMiniTable32(f->containing_type()), f->number());
680
+ const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber(
681
+ GetMiniTable64(f->containing_type()), f->number());
682
+ return absl::Substitute("UPB_SIZE($0, $1)", f_32->offset, f_64->offset);
683
+ }
684
+
685
+ std::string GetOneofCaseOffset(const protobuf::OneofDescriptor* o) const {
686
+ const protobuf::FieldDescriptor* f = o->field(0);
687
+ const upb_MiniTable_Field* f_32 = upb_MiniTable_FindFieldByNumber(
688
+ GetMiniTable32(f->containing_type()), f->number());
689
+ const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber(
690
+ GetMiniTable64(f->containing_type()), f->number());
691
+ return absl::Substitute("UPB_SIZE($0, $1)", ~f_32->presence,
692
+ ~f_64->presence);
693
+ }
694
+
695
+ std::string GetMessageSize(const protobuf::Descriptor* d) const {
696
+ return absl::Substitute("UPB_SIZE($0, $1)", GetMiniTable32(d)->size,
697
+ GetMiniTable64(d)->size);
698
+ }
699
+
700
+ int GetHasbitIndex(const protobuf::FieldDescriptor* f) const {
701
+ const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber(
702
+ GetMiniTable64(f->containing_type()), f->number());
703
+ return f_64->presence;
704
+ }
705
+
706
+ bool HasHasbit(const protobuf::FieldDescriptor* f) const {
707
+ return GetHasbitIndex(f) > 0;
708
+ }
709
+
710
+ const upb_MiniTable_Extension* GetExtension(
711
+ const protobuf::FieldDescriptor* f) const {
712
+ return layout64_.GetExtension(f);
713
+ }
714
+
715
+ private:
716
+ const protobuf::FileDescriptor* descriptor_;
717
+ FilePlatformLayout layout32_;
718
+ FilePlatformLayout layout64_;
719
+ };
720
+
721
+ void DumpEnumValues(const protobuf::EnumDescriptor* desc, Output& output) {
722
+ std::vector<const protobuf::EnumValueDescriptor*> values;
723
+ for (int i = 0; i < desc->value_count(); i++) {
724
+ values.push_back(desc->value(i));
725
+ }
726
+ std::sort(values.begin(), values.end(),
727
+ [](const protobuf::EnumValueDescriptor* a,
728
+ const protobuf::EnumValueDescriptor* b) {
729
+ return a->number() < b->number();
730
+ });
731
+
732
+ for (size_t i = 0; i < values.size(); i++) {
733
+ auto value = values[i];
734
+ output(" $0 = $1", EnumValueSymbol(value), value->number());
735
+ if (i != values.size() - 1) {
736
+ output(",");
737
+ }
738
+ output("\n");
739
+ }
740
+ }
741
+
742
+ void GenerateExtensionInHeader(const protobuf::FieldDescriptor* ext,
743
+ Output& output) {
744
+ output(
745
+ R"cc(
746
+ UPB_INLINE bool $0_has_$1(const struct $2* msg) {
747
+ return _upb_Message_Getext(msg, &$3) != NULL;
748
+ }
749
+ )cc",
750
+ ExtensionIdentBase(ext), ext->name(), MessageName(ext->containing_type()),
751
+ ExtensionLayout(ext));
752
+
753
+ output(
754
+ R"cc(
755
+ UPB_INLINE void $0_clear_$1(struct $2* msg) {
756
+ _upb_Message_Clearext(msg, &$3);
757
+ }
758
+ )cc",
759
+ ExtensionIdentBase(ext), ext->name(), MessageName(ext->containing_type()),
760
+ ExtensionLayout(ext));
761
+
762
+ if (ext->is_repeated()) {
763
+ } else if (ext->message_type()) {
764
+ output(
765
+ R"cc(
766
+ UPB_INLINE $0 $1_$2(const struct $3* msg) {
767
+ const upb_Message_Extension* ext = _upb_Message_Getext(msg, &$4);
768
+ UPB_ASSERT(ext);
769
+ return *UPB_PTR_AT(&ext->data, 0, $0);
770
+ }
771
+ )cc",
772
+ CTypeConst(ext), ExtensionIdentBase(ext), ext->name(),
773
+ MessageName(ext->containing_type()), ExtensionLayout(ext),
774
+ FieldDefault(ext));
775
+ output(
776
+ R"cc(
777
+ UPB_INLINE void $1_set_$2(struct $3* msg, $0 ext, upb_Arena* arena) {
778
+ const upb_Message_Extension* msg_ext =
779
+ _upb_Message_GetOrCreateExtension(msg, &$4, arena);
780
+ UPB_ASSERT(msg_ext);
781
+ *UPB_PTR_AT(&msg_ext->data, 0, $0) = ext;
782
+ }
783
+ )cc",
784
+ CTypeConst(ext), ExtensionIdentBase(ext), ext->name(),
785
+ MessageName(ext->containing_type()), ExtensionLayout(ext),
786
+ FieldDefault(ext));
787
+ } else {
788
+ // Returns default if extension field is not a message.
789
+ output(
790
+ R"cc(
791
+ UPB_INLINE $0 $1_$2(const struct $3* msg) {
792
+ const upb_Message_Extension* ext = _upb_Message_Getext(msg, &$4);
793
+ return ext ? *UPB_PTR_AT(&ext->data, 0, $0) : $5;
794
+ }
795
+ )cc",
796
+ CTypeConst(ext), ExtensionIdentBase(ext), ext->name(),
797
+ MessageName(ext->containing_type()), ExtensionLayout(ext),
798
+ FieldDefault(ext));
799
+ }
800
+ }
801
+
802
+ void GenerateMessageFunctionsInHeader(const protobuf::Descriptor* message,
803
+ Output& output) {
804
+ output(
805
+ R"cc(
806
+ UPB_INLINE $0* $0_new(upb_Arena* arena) {
807
+ return ($0*)_upb_Message_New(&$1, arena);
808
+ }
809
+ UPB_INLINE $0* $0_parse(const char* buf, size_t size, upb_Arena* arena) {
810
+ $0* ret = $0_new(arena);
811
+ if (!ret) return NULL;
812
+ if (upb_Decode(buf, size, ret, &$1, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
813
+ return NULL;
814
+ }
815
+ return ret;
816
+ }
817
+ UPB_INLINE $0* $0_parse_ex(const char* buf, size_t size,
818
+ const upb_ExtensionRegistry* extreg,
819
+ int options, upb_Arena* arena) {
820
+ $0* ret = $0_new(arena);
821
+ if (!ret) return NULL;
822
+ if (upb_Decode(buf, size, ret, &$1, extreg, options, arena) !=
823
+ kUpb_DecodeStatus_Ok) {
824
+ return NULL;
825
+ }
826
+ return ret;
827
+ }
828
+ UPB_INLINE char* $0_serialize(const $0* msg, upb_Arena* arena, size_t* len) {
829
+ return upb_Encode(msg, &$1, 0, arena, len);
830
+ }
831
+ UPB_INLINE char* $0_serialize_ex(const $0* msg, int options,
832
+ upb_Arena* arena, size_t* len) {
833
+ return upb_Encode(msg, &$1, options, arena, len);
834
+ }
835
+ )cc",
836
+ MessageName(message), MessageInit(message));
837
+ }
838
+
839
+ void GenerateOneofInHeader(const protobuf::OneofDescriptor* oneof,
840
+ const FileLayout& layout, absl::string_view msg_name,
841
+ Output& output) {
842
+ std::string fullname = ToCIdent(oneof->full_name());
843
+ output("typedef enum {\n");
844
+ for (int j = 0; j < oneof->field_count(); j++) {
845
+ const protobuf::FieldDescriptor* field = oneof->field(j);
846
+ output(" $0_$1 = $2,\n", fullname, field->name(), field->number());
847
+ }
848
+ output(
849
+ " $0_NOT_SET = 0\n"
850
+ "} $0_oneofcases;\n",
851
+ fullname);
852
+ output(
853
+ R"cc(
854
+ UPB_INLINE $0_oneofcases $1_$2_case(const $1* msg) {
855
+ return ($0_oneofcases)*UPB_PTR_AT(msg, $3, int32_t);
856
+ }
857
+ )cc",
858
+ fullname, msg_name, oneof->name(), layout.GetOneofCaseOffset(oneof));
859
+ }
860
+
861
+ void GenerateHazzer(const protobuf::FieldDescriptor* field,
862
+ const FileLayout& layout, absl::string_view msg_name,
863
+ Output& output) {
864
+ if (layout.HasHasbit(field)) {
865
+ output(
866
+ R"cc(
867
+ UPB_INLINE bool $0_has_$1(const $0* msg) {
868
+ return _upb_hasbit(msg, $2);
869
+ }
870
+ )cc",
871
+ msg_name, field->name(), layout.GetHasbitIndex(field));
872
+ } else if (field->real_containing_oneof()) {
873
+ output(
874
+ R"cc(
875
+ UPB_INLINE bool $0_has_$1(const $0* msg) {
876
+ return _upb_getoneofcase(msg, $2) == $3;
877
+ }
878
+ )cc",
879
+ msg_name, field->name(),
880
+ layout.GetOneofCaseOffset(field->real_containing_oneof()),
881
+ field->number());
882
+ } else if (field->message_type()) {
883
+ output(
884
+ R"cc(
885
+ UPB_INLINE bool $0_has_$1(const $0* msg) {
886
+ return _upb_has_submsg_nohasbit(msg, $2);
887
+ }
888
+ )cc",
889
+ msg_name, field->name(), layout.GetFieldOffset(field));
890
+ }
891
+ }
892
+
893
+ void GenerateClear(const protobuf::FieldDescriptor* field,
894
+ const FileLayout& layout, absl::string_view msg_name,
895
+ Output& output) {
896
+ if (field == field->containing_type()->map_key() ||
897
+ field == field->containing_type()->map_value()) {
898
+ // Cannot be cleared.
899
+ return;
900
+ }
901
+
902
+ if (field->real_containing_oneof()) {
903
+ const protobuf::OneofDescriptor* oneof = field->real_containing_oneof();
904
+ std::string oneof_fullname = ToCIdent(oneof->full_name());
905
+ std::string default_value =
906
+ field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING
907
+ ? "upb_StringView_FromDataAndSize(NULL, 0)"
908
+ : "0";
909
+ output(
910
+ R"cc(
911
+ UPB_INLINE void $0_clear_$1(const $0* msg) {
912
+ UPB_WRITE_ONEOF(msg, $2, $3, $7, $4, $6_NOT_SET);
913
+ }
914
+ )cc",
915
+ msg_name, field->name(), CType(field), layout.GetFieldOffset(field),
916
+ layout.GetOneofCaseOffset(field->real_containing_oneof()),
917
+ field->number(), oneof_fullname, default_value);
918
+ } else {
919
+ if (field->message_type()) {
920
+ output(
921
+ R"cc(
922
+ UPB_INLINE void $0_clear_$1(const $0* msg) {
923
+ *UPB_PTR_AT(msg, $2, const upb_Message*) = NULL;
924
+ }
925
+ )cc",
926
+ msg_name, field->name(), layout.GetFieldOffset(field));
927
+ } else if (layout.HasHasbit(field)) {
928
+ if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
929
+ output(
930
+ R"cc(
931
+ UPB_INLINE void $0_clear_$1(const $0* msg) {
932
+ *UPB_PTR_AT(msg, $3, $2) = upb_StringView_FromDataAndSize(NULL, 0);
933
+ _upb_clearhas(msg, $4);
934
+ }
935
+ )cc",
936
+ msg_name, field->name(), CType(field), layout.GetFieldOffset(field),
937
+ layout.GetHasbitIndex(field));
938
+ } else {
939
+ output(
940
+ R"cc(
941
+ UPB_INLINE void $0_clear_$1(const $0* msg) {
942
+ *UPB_PTR_AT(msg, $3, $2) = 0;
943
+ _upb_clearhas(msg, $4);
944
+ }
945
+ )cc",
946
+ msg_name, field->name(), CType(field), layout.GetFieldOffset(field),
947
+ layout.GetHasbitIndex(field));
948
+ }
949
+ } else {
950
+ if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING) {
951
+ output(
952
+ R"cc(
953
+ UPB_INLINE void $0_clear_$1(const $0* msg) {
954
+ *UPB_PTR_AT(msg, $3, $2) = upb_StringView_FromDataAndSize(NULL, 0);
955
+ }
956
+ )cc",
957
+ msg_name, field->name(), CType(field),
958
+ layout.GetFieldOffset(field));
959
+ } else {
960
+ output(
961
+ R"cc(
962
+ UPB_INLINE void $0_clear_$1(const $0* msg) {
963
+ *UPB_PTR_AT(msg, $3, $2) = 0;
964
+ }
965
+ )cc",
966
+ msg_name, field->name(), CType(field), layout.GetFieldOffset(field),
967
+ layout.GetHasbitIndex(field));
968
+ }
969
+ }
970
+ }
971
+ }
972
+
973
+ void GenerateRepeatedClear(const protobuf::FieldDescriptor* field,
974
+ const FileLayout& layout, absl::string_view msg_name,
975
+ Output& output) {
976
+ output(
977
+ R"cc(
978
+ UPB_INLINE void $0_clear_$1(const $0* msg) {
979
+ _upb_array_detach(msg, $2);
980
+ }
981
+ )cc",
982
+ msg_name, field->name(), layout.GetFieldOffset(field));
983
+ }
984
+
985
+ void GenerateMapGetters(const protobuf::FieldDescriptor* field,
986
+ const FileLayout& layout, absl::string_view msg_name,
987
+ Output& output) {
988
+ const protobuf::Descriptor* entry = field->message_type();
989
+ const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1);
990
+ const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2);
991
+ output(
992
+ R"cc(
993
+ UPB_INLINE size_t $0_$1_size(const $0* msg) {
994
+ return _upb_msg_map_size(msg, $2);
995
+ }
996
+ )cc",
997
+ msg_name, field->name(), layout.GetFieldOffset(field));
998
+ output(
999
+ R"cc(
1000
+ UPB_INLINE bool $0_$1_get(const $0* msg, $2 key, $3* val) {
1001
+ return _upb_msg_map_get(msg, $4, &key, $5, val, $6);
1002
+ }
1003
+ )cc",
1004
+ msg_name, field->name(), CType(key), CType(val),
1005
+ layout.GetFieldOffset(field),
1006
+ key->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING
1007
+ ? "0"
1008
+ : "sizeof(key)",
1009
+ val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING
1010
+ ? "0"
1011
+ : "sizeof(*val)");
1012
+ output(
1013
+ R"cc(
1014
+ UPB_INLINE $0 $1_$2_next(const $1* msg, size_t* iter) {
1015
+ return ($0)_upb_msg_map_next(msg, $3, iter);
1016
+ }
1017
+ )cc",
1018
+ CTypeConst(field), msg_name, field->name(), layout.GetFieldOffset(field));
1019
+ }
1020
+
1021
+ void GenerateMapEntryGetters(const protobuf::FieldDescriptor* field,
1022
+ absl::string_view msg_name, Output& output) {
1023
+ output(
1024
+ R"cc(
1025
+ UPB_INLINE $0 $1_$2(const $1* msg) {
1026
+ $3 ret;
1027
+ _upb_msg_map_$2(msg, &ret, $4);
1028
+ return ret;
1029
+ }
1030
+ )cc",
1031
+ CTypeConst(field), msg_name, field->name(), CType(field),
1032
+ field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING
1033
+ ? "0"
1034
+ : "sizeof(ret)");
1035
+ }
1036
+
1037
+ void GenerateRepeatedGetters(const protobuf::FieldDescriptor* field,
1038
+ const FileLayout& layout,
1039
+ absl::string_view msg_name, Output& output) {
1040
+ output(
1041
+ R"cc(
1042
+ UPB_INLINE $0 const* $1_$2(const $1* msg, size_t* len) {
1043
+ return ($0 const*)_upb_array_accessor(msg, $3, len);
1044
+ }
1045
+ )cc",
1046
+ CTypeConst(field), msg_name, field->name(), layout.GetFieldOffset(field));
1047
+ }
1048
+
1049
+ void GenerateOneofGetters(const protobuf::FieldDescriptor* field,
1050
+ const FileLayout& layout, absl::string_view msg_name,
1051
+ Output& output) {
1052
+ output(
1053
+ R"cc(
1054
+ UPB_INLINE $0 $1_$2(const $1* msg) {
1055
+ return UPB_READ_ONEOF(msg, $0, $3, $4, $5, $6);
1056
+ }
1057
+ )cc",
1058
+ CTypeConst(field), msg_name, field->name(), layout.GetFieldOffset(field),
1059
+ layout.GetOneofCaseOffset(field->real_containing_oneof()),
1060
+ field->number(), FieldDefault(field));
1061
+ }
1062
+
1063
+ void GenerateScalarGetters(const protobuf::FieldDescriptor* field,
1064
+ const FileLayout& layout, absl::string_view msg_name,
1065
+ Output& output) {
1066
+ if (HasNonZeroDefault(field)) {
1067
+ output(
1068
+ R"cc(
1069
+ UPB_INLINE $0 $1_$2(const $1* msg) {
1070
+ return $1_has_$2(msg) ? *UPB_PTR_AT(msg, $3, $0) : $4;
1071
+ }
1072
+ )cc",
1073
+ CTypeConst(field), msg_name, field->name(),
1074
+ layout.GetFieldOffset(field), FieldDefault(field));
1075
+ } else {
1076
+ output(
1077
+ R"cc(
1078
+ UPB_INLINE $0 $1_$2(const $1* msg) {
1079
+ return *UPB_PTR_AT(msg, $3, $0);
1080
+ }
1081
+ )cc",
1082
+ CTypeConst(field), msg_name, field->name(),
1083
+ layout.GetFieldOffset(field));
1084
+ }
1085
+ }
1086
+
1087
+ void GenerateGetters(const protobuf::FieldDescriptor* field,
1088
+ const FileLayout& layout, absl::string_view msg_name,
1089
+ Output& output) {
1090
+ if (field->is_map()) {
1091
+ GenerateMapGetters(field, layout, msg_name, output);
1092
+ } else if (field->containing_type()->options().map_entry()) {
1093
+ GenerateMapEntryGetters(field, msg_name, output);
1094
+ } else if (field->is_repeated()) {
1095
+ GenerateRepeatedGetters(field, layout, msg_name, output);
1096
+ } else if (field->real_containing_oneof()) {
1097
+ GenerateOneofGetters(field, layout, msg_name, output);
1098
+ } else {
1099
+ GenerateScalarGetters(field, layout, msg_name, output);
1100
+ }
1101
+ }
1102
+
1103
+ void GenerateMapSetters(const protobuf::FieldDescriptor* field,
1104
+ const FileLayout& layout, absl::string_view msg_name,
1105
+ Output& output) {
1106
+ const protobuf::Descriptor* entry = field->message_type();
1107
+ const protobuf::FieldDescriptor* key = entry->FindFieldByNumber(1);
1108
+ const protobuf::FieldDescriptor* val = entry->FindFieldByNumber(2);
1109
+ output(
1110
+ R"cc(
1111
+ UPB_INLINE void $0_$1_clear($0* msg) { _upb_msg_map_clear(msg, $2); }
1112
+ )cc",
1113
+ msg_name, field->name(), layout.GetFieldOffset(field));
1114
+ output(
1115
+ R"cc(
1116
+ UPB_INLINE bool $0_$1_set($0* msg, $2 key, $3 val, upb_Arena* a) {
1117
+ return _upb_msg_map_set(msg, $4, &key, $5, &val, $6, a);
1118
+ }
1119
+ )cc",
1120
+ msg_name, field->name(), CType(key), CType(val),
1121
+ layout.GetFieldOffset(field),
1122
+ key->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING
1123
+ ? "0"
1124
+ : "sizeof(key)",
1125
+ val->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING
1126
+ ? "0"
1127
+ : "sizeof(val)");
1128
+ output(
1129
+ R"cc(
1130
+ UPB_INLINE bool $0_$1_delete($0* msg, $2 key) {
1131
+ return _upb_msg_map_delete(msg, $3, &key, $4);
1132
+ }
1133
+ )cc",
1134
+ msg_name, field->name(), CType(key), layout.GetFieldOffset(field),
1135
+ key->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING
1136
+ ? "0"
1137
+ : "sizeof(key)");
1138
+ output(
1139
+ R"cc(
1140
+ UPB_INLINE $0 $1_$2_nextmutable($1* msg, size_t* iter) {
1141
+ return ($0)_upb_msg_map_next(msg, $3, iter);
1142
+ }
1143
+ )cc",
1144
+ CType(field), msg_name, field->name(), layout.GetFieldOffset(field));
1145
+ }
1146
+
1147
+ void GenerateRepeatedSetters(const protobuf::FieldDescriptor* field,
1148
+ const FileLayout& layout,
1149
+ absl::string_view msg_name, Output& output) {
1150
+ output(
1151
+ R"cc(
1152
+ UPB_INLINE $0* $1_mutable_$2($1* msg, size_t* len) {
1153
+ return ($0*)_upb_array_mutable_accessor(msg, $3, len);
1154
+ }
1155
+ )cc",
1156
+ CType(field), msg_name, field->name(), layout.GetFieldOffset(field));
1157
+ output(
1158
+ R"cc(
1159
+ UPB_INLINE $0* $1_resize_$2($1* msg, size_t len, upb_Arena* arena) {
1160
+ return ($0*)_upb_Array_Resize_accessor2(msg, $3, len, $4, arena);
1161
+ }
1162
+ )cc",
1163
+ CType(field), msg_name, field->name(), layout.GetFieldOffset(field),
1164
+ SizeLg2(field));
1165
+ if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
1166
+ output(
1167
+ R"cc(
1168
+ UPB_INLINE struct $0* $1_add_$2($1* msg, upb_Arena* arena) {
1169
+ struct $0* sub = (struct $0*)_upb_Message_New(&$3, arena);
1170
+ bool ok = _upb_Array_Append_accessor2(msg, $4, $5, &sub, arena);
1171
+ if (!ok) return NULL;
1172
+ return sub;
1173
+ }
1174
+ )cc",
1175
+ MessageName(field->message_type()), msg_name, field->name(),
1176
+ MessageInit(field->message_type()), layout.GetFieldOffset(field),
1177
+ SizeLg2(field));
1178
+ } else {
1179
+ output(
1180
+ R"cc(
1181
+ UPB_INLINE bool $1_add_$2($1* msg, $0 val, upb_Arena* arena) {
1182
+ return _upb_Array_Append_accessor2(msg, $3, $4, &val, arena);
1183
+ }
1184
+ )cc",
1185
+ CType(field), msg_name, field->name(), layout.GetFieldOffset(field),
1186
+ SizeLg2(field));
1187
+ }
1188
+ }
1189
+
1190
+ void GenerateNonRepeatedSetters(const protobuf::FieldDescriptor* field,
1191
+ const FileLayout& layout,
1192
+ absl::string_view msg_name, Output& output) {
1193
+ if (field == field->containing_type()->map_key()) {
1194
+ // Key cannot be mutated.
1195
+ return;
1196
+ }
1197
+
1198
+ // The common function signature for all setters. Varying
1199
+ // implementations follow.
1200
+ output("UPB_INLINE void $0_set_$1($0 *msg, $2 value) {\n", msg_name,
1201
+ field->name(), CType(field));
1202
+
1203
+ if (field == field->containing_type()->map_value()) {
1204
+ output(
1205
+ " _upb_msg_map_set_value(msg, &value, $0);\n"
1206
+ "}\n",
1207
+ field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_STRING
1208
+ ? "0"
1209
+ : "sizeof(" + CType(field) + ")");
1210
+ } else if (field->real_containing_oneof()) {
1211
+ output(
1212
+ " UPB_WRITE_ONEOF(msg, $0, $1, value, $2, $3);\n"
1213
+ "}\n",
1214
+ CType(field), layout.GetFieldOffset(field),
1215
+ layout.GetOneofCaseOffset(field->real_containing_oneof()),
1216
+ field->number());
1217
+ } else {
1218
+ if (layout.HasHasbit(field)) {
1219
+ output(" _upb_sethas(msg, $0);\n", layout.GetHasbitIndex(field));
1220
+ }
1221
+ output(
1222
+ " *UPB_PTR_AT(msg, $1, $0) = value;\n"
1223
+ "}\n",
1224
+ CType(field), layout.GetFieldOffset(field));
1225
+ }
1226
+
1227
+ // Message fields also have a Msg_mutable_foo() accessor that will create
1228
+ // the sub-message if it doesn't already exist.
1229
+ if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE &&
1230
+ !field->containing_type()->options().map_entry()) {
1231
+ output(
1232
+ R"cc(
1233
+ UPB_INLINE struct $0* $1_mutable_$2($1* msg, upb_Arena* arena) {
1234
+ struct $0* sub = (struct $0*)$1_$2(msg);
1235
+ if (sub == NULL) {
1236
+ sub = (struct $0*)_upb_Message_New(&$3, arena);
1237
+ if (!sub) return NULL;
1238
+ $1_set_$2(msg, sub);
1239
+ }
1240
+ return sub;
1241
+ }
1242
+ )cc",
1243
+ MessageName(field->message_type()), msg_name, field->name(),
1244
+ MessageInit(field->message_type()));
1245
+ }
1246
+ }
1247
+
1248
+ void GenerateSetters(const protobuf::FieldDescriptor* field,
1249
+ const FileLayout& layout, absl::string_view msg_name,
1250
+ Output& output) {
1251
+ if (field->is_map()) {
1252
+ GenerateMapSetters(field, layout, msg_name, output);
1253
+ } else if (field->is_repeated()) {
1254
+ GenerateRepeatedSetters(field, layout, msg_name, output);
1255
+ } else {
1256
+ GenerateNonRepeatedSetters(field, layout, msg_name, output);
1257
+ }
1258
+ }
1259
+
1260
+ void GenerateMessageInHeader(const protobuf::Descriptor* message,
1261
+ const FileLayout& layout, Output& output) {
1262
+ output("/* $0 */\n\n", message->full_name());
1263
+ std::string msg_name = ToCIdent(message->full_name());
1264
+
1265
+ if (!message->options().map_entry()) {
1266
+ GenerateMessageFunctionsInHeader(message, output);
1267
+ }
1268
+
1269
+ for (int i = 0; i < message->real_oneof_decl_count(); i++) {
1270
+ GenerateOneofInHeader(message->oneof_decl(i), layout, msg_name, output);
1271
+ }
1272
+
1273
+ for (auto field : FieldNumberOrder(message)) {
1274
+ GenerateHazzer(field, layout, msg_name, output);
1275
+ if (field->is_repeated()) {
1276
+ GenerateRepeatedClear(field, layout, msg_name, output);
1277
+ } else {
1278
+ GenerateClear(field, layout, msg_name, output);
1279
+ }
1280
+ GenerateGetters(field, layout, msg_name, output);
1281
+ }
1282
+
1283
+ output("\n");
1284
+
1285
+ for (auto field : FieldNumberOrder(message)) {
1286
+ GenerateSetters(field, layout, msg_name, output);
1287
+ }
1288
+
1289
+ output("\n");
1290
+ }
1291
+
1292
+ void WriteHeader(const FileLayout& layout, Output& output) {
1293
+ const protobuf::FileDescriptor* file = layout.descriptor();
1294
+ EmitFileWarning(file, output);
1295
+ output(
1296
+ "#ifndef $0_UPB_H_\n"
1297
+ "#define $0_UPB_H_\n\n"
1298
+ "#include \"upb/msg_internal.h\"\n"
1299
+ "#include \"upb/decode.h\"\n"
1300
+ "#include \"upb/decode_fast.h\"\n"
1301
+ "#include \"upb/encode.h\"\n\n",
1302
+ ToPreproc(file->name()));
1303
+
1304
+ for (int i = 0; i < file->public_dependency_count(); i++) {
1305
+ if (i == 0) {
1306
+ output("/* Public Imports. */\n");
1307
+ }
1308
+ output("#include \"$0\"\n", HeaderFilename(file));
1309
+ if (i == file->public_dependency_count() - 1) {
1310
+ output("\n");
1311
+ }
1312
+ }
1313
+
1314
+ output(
1315
+ "#include \"upb/port_def.inc\"\n"
1316
+ "\n"
1317
+ "#ifdef __cplusplus\n"
1318
+ "extern \"C\" {\n"
1319
+ "#endif\n"
1320
+ "\n");
1321
+
1322
+ const std::vector<const protobuf::Descriptor*> this_file_messages =
1323
+ SortedMessages(file);
1324
+ const std::vector<const protobuf::FieldDescriptor*> this_file_exts =
1325
+ SortedExtensions(file);
1326
+
1327
+ // Forward-declare types defined in this file.
1328
+ for (auto message : this_file_messages) {
1329
+ output("struct $0;\n", ToCIdent(message->full_name()));
1330
+ }
1331
+ for (auto message : this_file_messages) {
1332
+ output("typedef struct $0 $0;\n", ToCIdent(message->full_name()));
1333
+ }
1334
+ for (auto message : this_file_messages) {
1335
+ output("extern const upb_MiniTable $0;\n", MessageInit(message));
1336
+ }
1337
+ for (auto ext : this_file_exts) {
1338
+ output("extern const upb_MiniTable_Extension $0;\n", ExtensionLayout(ext));
1339
+ }
1340
+
1341
+ // Forward-declare types not in this file, but used as submessages.
1342
+ // Order by full name for consistent ordering.
1343
+ std::map<std::string, const protobuf::Descriptor*> forward_messages;
1344
+
1345
+ for (auto* message : this_file_messages) {
1346
+ for (int i = 0; i < message->field_count(); i++) {
1347
+ const protobuf::FieldDescriptor* field = message->field(i);
1348
+ if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE &&
1349
+ field->file() != field->message_type()->file()) {
1350
+ forward_messages[field->message_type()->full_name()] =
1351
+ field->message_type();
1352
+ }
1353
+ }
1354
+ }
1355
+ for (auto ext : this_file_exts) {
1356
+ if (ext->file() != ext->containing_type()->file()) {
1357
+ forward_messages[ext->containing_type()->full_name()] =
1358
+ ext->containing_type();
1359
+ }
1360
+ }
1361
+ for (const auto& pair : forward_messages) {
1362
+ output("struct $0;\n", MessageName(pair.second));
1363
+ }
1364
+ for (const auto& pair : forward_messages) {
1365
+ output("extern const upb_MiniTable $0;\n", MessageInit(pair.second));
1366
+ }
1367
+
1368
+ if (!this_file_messages.empty()) {
1369
+ output("\n");
1370
+ }
1371
+
1372
+ std::vector<const protobuf::EnumDescriptor*> this_file_enums =
1373
+ SortedEnums(file);
1374
+ std::sort(
1375
+ this_file_enums.begin(), this_file_enums.end(),
1376
+ [](const protobuf::EnumDescriptor* a, const protobuf::EnumDescriptor* b) {
1377
+ return a->full_name() < b->full_name();
1378
+ });
1379
+
1380
+ for (auto enumdesc : this_file_enums) {
1381
+ output("typedef enum {\n");
1382
+ DumpEnumValues(enumdesc, output);
1383
+ output("} $0;\n\n", ToCIdent(enumdesc->full_name()));
1384
+ }
1385
+
1386
+ output("\n");
1387
+
1388
+ if (file->syntax() == protobuf::FileDescriptor::SYNTAX_PROTO2) {
1389
+ for (const auto* enumdesc : this_file_enums) {
1390
+ output("extern const upb_MiniTable_Enum $0;\n", EnumInit(enumdesc));
1391
+ }
1392
+ }
1393
+
1394
+ output("\n");
1395
+
1396
+ for (auto message : this_file_messages) {
1397
+ GenerateMessageInHeader(message, layout, output);
1398
+ }
1399
+
1400
+ for (auto ext : this_file_exts) {
1401
+ GenerateExtensionInHeader(ext, output);
1402
+ }
1403
+
1404
+ output("extern const upb_MiniTable_File $0;\n\n", FileLayoutName(file));
1405
+
1406
+ if (file->name() ==
1407
+ protobuf::FileDescriptorProto::descriptor()->file()->name()) {
1408
+ // This is gratuitously inefficient with how many times it rebuilds
1409
+ // MessageLayout objects for the same message. But we only do this for one
1410
+ // proto (descriptor.proto) so we don't worry about it.
1411
+ const protobuf::Descriptor* max32_message = nullptr;
1412
+ const protobuf::Descriptor* max64_message = nullptr;
1413
+ size_t max32 = 0;
1414
+ size_t max64 = 0;
1415
+ for (const auto* message : this_file_messages) {
1416
+ if (absl::EndsWith(message->name(), "Options")) {
1417
+ size_t size32 = layout.GetMiniTable32(message)->size;
1418
+ size_t size64 = layout.GetMiniTable64(message)->size;
1419
+ if (size32 > max32) {
1420
+ max32 = size32;
1421
+ max32_message = message;
1422
+ }
1423
+ if (size64 > max64) {
1424
+ max64 = size64;
1425
+ max64_message = message;
1426
+ }
1427
+ }
1428
+ }
1429
+
1430
+ output("/* Max size 32 is $0 */\n", max32_message->full_name());
1431
+ output("/* Max size 64 is $0 */\n", max64_message->full_name());
1432
+ output("#define _UPB_MAXOPT_SIZE UPB_SIZE($0, $1)\n\n", max32, max64);
1433
+ }
1434
+
1435
+ output(
1436
+ "#ifdef __cplusplus\n"
1437
+ "} /* extern \"C\" */\n"
1438
+ "#endif\n"
1439
+ "\n"
1440
+ "#include \"upb/port_undef.inc\"\n"
1441
+ "\n"
1442
+ "#endif /* $0_UPB_H_ */\n",
1443
+ ToPreproc(file->name()));
1444
+ }
1445
+
1446
+ typedef std::pair<std::string, uint64_t> TableEntry;
1447
+
1448
+ uint64_t GetEncodedTag(const protobuf::FieldDescriptor* field) {
1449
+ protobuf::internal::WireFormatLite::WireType wire_type =
1450
+ protobuf::internal::WireFormat::WireTypeForField(field);
1451
+ uint32_t unencoded_tag =
1452
+ protobuf::internal::WireFormatLite::MakeTag(field->number(), wire_type);
1453
+ uint8_t tag_bytes[10] = {0};
1454
+ protobuf::io::CodedOutputStream::WriteVarint32ToArray(unencoded_tag,
1455
+ tag_bytes);
1456
+ uint64_t encoded_tag = 0;
1457
+ memcpy(&encoded_tag, tag_bytes, sizeof(encoded_tag));
1458
+ // TODO: byte-swap for big endian.
1459
+ return encoded_tag;
1460
+ }
1461
+
1462
+ int GetTableSlot(const protobuf::FieldDescriptor* field) {
1463
+ uint64_t tag = GetEncodedTag(field);
1464
+ if (tag > 0x7fff) {
1465
+ // Tag must fit within a two-byte varint.
1466
+ return -1;
1467
+ }
1468
+ return (tag & 0xf8) >> 3;
1469
+ }
1470
+
1471
+ bool TryFillTableEntry(const FileLayout& layout,
1472
+ const protobuf::FieldDescriptor* field,
1473
+ TableEntry& ent) {
1474
+ const upb_MiniTable* mt = layout.GetMiniTable64(field->containing_type());
1475
+ const upb_MiniTable_Field* mt_f =
1476
+ upb_MiniTable_FindFieldByNumber(mt, field->number());
1477
+ std::string type = "";
1478
+ std::string cardinality = "";
1479
+ switch (mt_f->descriptortype) {
1480
+ case kUpb_FieldType_Bool:
1481
+ type = "b1";
1482
+ break;
1483
+ case kUpb_FieldType_Enum:
1484
+ // We don't have the means to test proto2 enum fields for valid values.
1485
+ return false;
1486
+ case kUpb_FieldType_Int32:
1487
+ case kUpb_FieldType_UInt32:
1488
+ type = "v4";
1489
+ break;
1490
+ case kUpb_FieldType_Int64:
1491
+ case kUpb_FieldType_UInt64:
1492
+ type = "v8";
1493
+ break;
1494
+ case kUpb_FieldType_Fixed32:
1495
+ case kUpb_FieldType_SFixed32:
1496
+ case kUpb_FieldType_Float:
1497
+ type = "f4";
1498
+ break;
1499
+ case kUpb_FieldType_Fixed64:
1500
+ case kUpb_FieldType_SFixed64:
1501
+ case kUpb_FieldType_Double:
1502
+ type = "f8";
1503
+ break;
1504
+ case kUpb_FieldType_SInt32:
1505
+ type = "z4";
1506
+ break;
1507
+ case kUpb_FieldType_SInt64:
1508
+ type = "z8";
1509
+ break;
1510
+ case kUpb_FieldType_String:
1511
+ type = "s";
1512
+ break;
1513
+ case kUpb_FieldType_Bytes:
1514
+ type = "b";
1515
+ break;
1516
+ case kUpb_FieldType_Message:
1517
+ type = "m";
1518
+ break;
1519
+ default:
1520
+ return false; // Not supported yet.
1521
+ }
1522
+
1523
+ switch (upb_FieldMode_Get(mt_f)) {
1524
+ case kUpb_FieldMode_Map:
1525
+ return false; // Not supported yet (ever?).
1526
+ case kUpb_FieldMode_Array:
1527
+ if (mt_f->mode & kUpb_LabelFlags_IsPacked) {
1528
+ cardinality = "p";
1529
+ } else {
1530
+ cardinality = "r";
1531
+ }
1532
+ break;
1533
+ case kUpb_FieldMode_Scalar:
1534
+ if (mt_f->presence < 0) {
1535
+ cardinality = "o";
1536
+ } else {
1537
+ cardinality = "s";
1538
+ }
1539
+ break;
1540
+ }
1541
+
1542
+ uint64_t expected_tag = GetEncodedTag(field);
1543
+
1544
+ // Data is:
1545
+ //
1546
+ // 48 32 16 0
1547
+ // |--------|--------|--------|--------|--------|--------|--------|--------|
1548
+ // | offset (16) |case offset (16) |presence| submsg | exp. tag (16) |
1549
+ // |--------|--------|--------|--------|--------|--------|--------|--------|
1550
+ //
1551
+ // - |presence| is either hasbit index or field number for oneofs.
1552
+
1553
+ uint64_t data = static_cast<uint64_t>(mt_f->offset) << 48 | expected_tag;
1554
+
1555
+ if (field->is_repeated()) {
1556
+ // No hasbit/oneof-related fields.
1557
+ }
1558
+ if (field->real_containing_oneof()) {
1559
+ size_t case_offset = ~mt_f->presence;
1560
+ if (case_offset > 0xffff) return false;
1561
+ assert(field->number() < 256);
1562
+ data |= field->number() << 24;
1563
+ data |= case_offset << 32;
1564
+ } else {
1565
+ uint64_t hasbit_index = 63; // No hasbit (set a high, unused bit).
1566
+ if (mt_f->presence) {
1567
+ hasbit_index = mt_f->presence;
1568
+ if (hasbit_index > 31) return false;
1569
+ }
1570
+ data |= hasbit_index << 24;
1571
+ }
1572
+
1573
+ if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
1574
+ uint64_t idx = mt_f->submsg_index;
1575
+ if (idx > 255) return false;
1576
+ data |= idx << 16;
1577
+
1578
+ std::string size_ceil = "max";
1579
+ size_t size = SIZE_MAX;
1580
+ if (field->message_type()->file() == field->file()) {
1581
+ // We can only be guaranteed the size of the sub-message if it is in the
1582
+ // same file as us. We could relax this to increase the speed of
1583
+ // cross-file sub-message parsing if we are comfortable requiring that
1584
+ // users compile all messages at the same time.
1585
+ const upb_MiniTable* sub_mt =
1586
+ layout.GetMiniTable64(field->message_type());
1587
+ size = sub_mt->size + 8;
1588
+ }
1589
+ std::vector<size_t> breaks = {64, 128, 192, 256};
1590
+ for (auto brk : breaks) {
1591
+ if (size <= brk) {
1592
+ size_ceil = std::to_string(brk);
1593
+ break;
1594
+ }
1595
+ }
1596
+ ent.first = absl::Substitute("upb_p$0$1_$2bt_max$3b", cardinality, type,
1597
+ expected_tag > 0xff ? "2" : "1", size_ceil);
1598
+
1599
+ } else {
1600
+ ent.first = absl::Substitute("upb_p$0$1_$2bt", cardinality, type,
1601
+ expected_tag > 0xff ? "2" : "1");
1602
+ }
1603
+ ent.second = data;
1604
+ return true;
1605
+ }
1606
+
1607
+ std::vector<TableEntry> FastDecodeTable(const protobuf::Descriptor* message,
1608
+ const FileLayout& layout) {
1609
+ std::vector<TableEntry> table;
1610
+ for (const auto field : FieldHotnessOrder(message)) {
1611
+ TableEntry ent;
1612
+ int slot = GetTableSlot(field);
1613
+ // std::cerr << "table slot: " << field->number() << ": " << slot << "\n";
1614
+ if (slot < 0) {
1615
+ // Tag can't fit in the table.
1616
+ continue;
1617
+ }
1618
+ if (!TryFillTableEntry(layout, field, ent)) {
1619
+ // Unsupported field type or offset, hasbit index, etc. doesn't fit.
1620
+ continue;
1621
+ }
1622
+ while ((size_t)slot >= table.size()) {
1623
+ size_t size = std::max(static_cast<size_t>(1), table.size() * 2);
1624
+ table.resize(size, TableEntry{"fastdecode_generic", 0});
1625
+ }
1626
+ if (table[slot].first != "fastdecode_generic") {
1627
+ // A hotter field already filled this slot.
1628
+ continue;
1629
+ }
1630
+ table[slot] = ent;
1631
+ }
1632
+ return table;
1633
+ }
1634
+
1635
+ // Returns the field mode as a string initializer.
1636
+ //
1637
+ // We could just emit this as a number (and we may yet go in that direction) but
1638
+ // for now emitting symbolic constants gives this better readability and
1639
+ // debuggability.
1640
+ std::string GetModeInit(uint8_t mode) {
1641
+ std::string ret;
1642
+ switch (mode & kUpb_FieldMode_Mask) {
1643
+ case kUpb_FieldMode_Map:
1644
+ ret = "kUpb_FieldMode_Map";
1645
+ break;
1646
+ case kUpb_FieldMode_Array:
1647
+ ret = "kUpb_FieldMode_Array";
1648
+ break;
1649
+ case kUpb_FieldMode_Scalar:
1650
+ ret = "kUpb_FieldMode_Scalar";
1651
+ break;
1652
+ default:
1653
+ break;
1654
+ }
1655
+
1656
+ if (mode & kUpb_LabelFlags_IsPacked) {
1657
+ absl::StrAppend(&ret, " | kUpb_LabelFlags_IsPacked");
1658
+ }
1659
+
1660
+ if (mode & kUpb_LabelFlags_IsExtension) {
1661
+ absl::StrAppend(&ret, " | kUpb_LabelFlags_IsExtension");
1662
+ }
1663
+
1664
+ std::string rep;
1665
+ switch (mode >> kUpb_FieldRep_Shift) {
1666
+ case kUpb_FieldRep_1Byte:
1667
+ rep = "kUpb_FieldRep_1Byte";
1668
+ break;
1669
+ case kUpb_FieldRep_4Byte:
1670
+ rep = "kUpb_FieldRep_4Byte";
1671
+ break;
1672
+ case kUpb_FieldRep_Pointer:
1673
+ rep = "kUpb_FieldRep_Pointer";
1674
+ break;
1675
+ case kUpb_FieldRep_StringView:
1676
+ rep = "kUpb_FieldRep_StringView";
1677
+ break;
1678
+ case kUpb_FieldRep_8Byte:
1679
+ rep = "kUpb_FieldRep_8Byte";
1680
+ break;
1681
+ }
1682
+
1683
+ absl::StrAppend(&ret, " | (", rep, " << kUpb_FieldRep_Shift)");
1684
+ return ret;
1685
+ }
1686
+
1687
+ void WriteField(const upb_MiniTable_Field* field64,
1688
+ const upb_MiniTable_Field* field32, Output& output) {
1689
+ output("{$0, UPB_SIZE($1, $2), UPB_SIZE($3, $4), $5, $6, $7}",
1690
+ field64->number, field32->offset, field64->offset, field32->presence,
1691
+ field64->presence,
1692
+ field64->submsg_index == kUpb_NoSub
1693
+ ? "kUpb_NoSub"
1694
+ : absl::StrCat(field64->submsg_index).c_str(),
1695
+ field64->descriptortype, GetModeInit(field64->mode));
1696
+ }
1697
+
1698
+ // Writes a single field into a .upb.c source file.
1699
+ void WriteMessageField(const upb_MiniTable_Field* field64,
1700
+ const upb_MiniTable_Field* field32, Output& output) {
1701
+ output(" ");
1702
+ WriteField(field64, field32, output);
1703
+ output(",\n");
1704
+ }
1705
+
1706
+ // Writes a single message into a .upb.c source file.
1707
+ void WriteMessage(const protobuf::Descriptor* message, const FileLayout& layout,
1708
+ Output& output, bool fasttable_enabled) {
1709
+ std::string msg_name = ToCIdent(message->full_name());
1710
+ std::string fields_array_ref = "NULL";
1711
+ std::string submsgs_array_ref = "NULL";
1712
+ std::string subenums_array_ref = "NULL";
1713
+ const upb_MiniTable* mt_32 = layout.GetMiniTable32(message);
1714
+ const upb_MiniTable* mt_64 = layout.GetMiniTable64(message);
1715
+ std::vector<std::string> subs;
1716
+
1717
+ for (int i = 0; i < mt_64->field_count; i++) {
1718
+ const upb_MiniTable_Field* f = &mt_64->fields[i];
1719
+ if (f->submsg_index != kUpb_NoSub) {
1720
+ subs.push_back(FilePlatformLayout::GetSub(mt_64->subs[f->submsg_index]));
1721
+ }
1722
+ }
1723
+
1724
+ if (!subs.empty()) {
1725
+ std::string submsgs_array_name = msg_name + "_submsgs";
1726
+ submsgs_array_ref = "&" + submsgs_array_name + "[0]";
1727
+ output("static const upb_MiniTable_Sub $0[$1] = {\n", submsgs_array_name,
1728
+ subs.size());
1729
+
1730
+ for (const auto& sub : subs) {
1731
+ output(" $0,\n", sub);
1732
+ }
1733
+
1734
+ output("};\n\n");
1735
+ }
1736
+
1737
+ if (mt_64->field_count > 0) {
1738
+ std::string fields_array_name = msg_name + "__fields";
1739
+ fields_array_ref = "&" + fields_array_name + "[0]";
1740
+ output("static const upb_MiniTable_Field $0[$1] = {\n", fields_array_name,
1741
+ mt_64->field_count);
1742
+ for (int i = 0; i < mt_64->field_count; i++) {
1743
+ WriteMessageField(&mt_64->fields[i], &mt_32->fields[i], output);
1744
+ }
1745
+ output("};\n\n");
1746
+ }
1747
+
1748
+ std::vector<TableEntry> table;
1749
+ uint8_t table_mask = -1;
1750
+
1751
+ if (fasttable_enabled) {
1752
+ table = FastDecodeTable(message, layout);
1753
+ }
1754
+
1755
+ if (table.size() > 1) {
1756
+ assert((table.size() & (table.size() - 1)) == 0);
1757
+ table_mask = (table.size() - 1) << 3;
1758
+ }
1759
+
1760
+ std::string msgext = "kUpb_ExtMode_NonExtendable";
1761
+
1762
+ if (message->extension_range_count()) {
1763
+ if (message->options().message_set_wire_format()) {
1764
+ msgext = "kUpb_ExtMode_IsMessageSet";
1765
+ } else {
1766
+ msgext = "kUpb_ExtMode_Extendable";
1767
+ }
1768
+ }
1769
+
1770
+ output("const upb_MiniTable $0 = {\n", MessageInit(message));
1771
+ output(" $0,\n", submsgs_array_ref);
1772
+ output(" $0,\n", fields_array_ref);
1773
+ output(" $0, $1, $2, $3, $4, $5,\n", layout.GetMessageSize(message),
1774
+ mt_64->field_count, msgext, mt_64->dense_below, table_mask,
1775
+ mt_64->required_count);
1776
+ if (!table.empty()) {
1777
+ output(" UPB_FASTTABLE_INIT({\n");
1778
+ for (const auto& ent : table) {
1779
+ output(" {0x$1, &$0},\n", ent.first,
1780
+ absl::StrCat(absl::Hex(ent.second, absl::kZeroPad16)));
1781
+ }
1782
+ output(" }),\n");
1783
+ }
1784
+ output("};\n\n");
1785
+ }
1786
+
1787
+ void WriteEnum(const upb_MiniTable_Enum* mt, const protobuf::EnumDescriptor* e,
1788
+ Output& output) {
1789
+ std::string values_init = "NULL";
1790
+
1791
+ if (mt->value_count) {
1792
+ values_init = EnumInit(e) + "_values";
1793
+ output("static const int32_t $0[$1] = {\n", values_init, mt->value_count);
1794
+ for (int i = 0; i < mt->value_count; i++) {
1795
+ output(" $0,\n", mt->values[i]);
1796
+ }
1797
+ output("};\n\n");
1798
+ }
1799
+
1800
+ output(
1801
+ R"cc(
1802
+ const upb_MiniTable_Enum $0 = {
1803
+ $1,
1804
+ $2,
1805
+ $3,
1806
+ };
1807
+ )cc",
1808
+ EnumInit(e), values_init, absl::StrCat("0x", absl::Hex(mt->mask), "ULL"),
1809
+ mt->value_count);
1810
+ output("\n");
1811
+ }
1812
+
1813
+ int WriteEnums(const FileLayout& layout, Output& output) {
1814
+ const protobuf::FileDescriptor* file = layout.descriptor();
1815
+
1816
+ if (file->syntax() != protobuf::FileDescriptor::SYNTAX_PROTO2) {
1817
+ return 0;
1818
+ }
1819
+
1820
+ std::vector<const protobuf::EnumDescriptor*> this_file_enums =
1821
+ SortedEnums(file);
1822
+
1823
+ for (const auto* e : this_file_enums) {
1824
+ WriteEnum(layout.GetEnumTable(e), e, output);
1825
+ }
1826
+
1827
+ if (!this_file_enums.empty()) {
1828
+ output("static const upb_MiniTable_Enum *$0[$1] = {\n", kEnumsInit,
1829
+ this_file_enums.size());
1830
+ for (const auto* e : this_file_enums) {
1831
+ output(" &$0,\n", EnumInit(e));
1832
+ }
1833
+ output("};\n");
1834
+ output("\n");
1835
+ }
1836
+
1837
+ return this_file_enums.size();
1838
+ }
1839
+
1840
+ int WriteMessages(const FileLayout& layout, Output& output,
1841
+ bool fasttable_enabled) {
1842
+ const protobuf::FileDescriptor* file = layout.descriptor();
1843
+ std::vector<const protobuf::Descriptor*> file_messages = SortedMessages(file);
1844
+
1845
+ if (file_messages.empty()) return 0;
1846
+
1847
+ for (auto message : file_messages) {
1848
+ WriteMessage(message, layout, output, fasttable_enabled);
1849
+ }
1850
+
1851
+ output("static const upb_MiniTable *$0[$1] = {\n", kMessagesInit,
1852
+ file_messages.size());
1853
+ for (auto message : file_messages) {
1854
+ output(" &$0,\n", MessageInit(message));
1855
+ }
1856
+ output("};\n");
1857
+ output("\n");
1858
+ return file_messages.size();
1859
+ }
1860
+
1861
+ void WriteExtension(const upb_MiniTable_Extension* ext, Output& output) {
1862
+ WriteField(&ext->field, &ext->field, output);
1863
+ output(",\n");
1864
+ output(" &$0,\n", reinterpret_cast<const char*>(ext->extendee));
1865
+ output(" $0,\n", FilePlatformLayout::GetSub(ext->sub));
1866
+ }
1867
+
1868
+ int WriteExtensions(const FileLayout& layout, Output& output) {
1869
+ auto exts = SortedExtensions(layout.descriptor());
1870
+ absl::flat_hash_set<const protobuf::Descriptor*> forward_decls;
1871
+
1872
+ if (exts.empty()) return 0;
1873
+
1874
+ // Order by full name for consistent ordering.
1875
+ std::map<std::string, const protobuf::Descriptor*> forward_messages;
1876
+
1877
+ for (auto ext : exts) {
1878
+ forward_messages[ext->containing_type()->full_name()] =
1879
+ ext->containing_type();
1880
+ if (ext->message_type()) {
1881
+ forward_messages[ext->message_type()->full_name()] = ext->message_type();
1882
+ }
1883
+ }
1884
+
1885
+ for (const auto& decl : forward_messages) {
1886
+ output("extern const upb_MiniTable $0;\n", MessageInit(decl.second));
1887
+ }
1888
+
1889
+ for (auto ext : exts) {
1890
+ output("const upb_MiniTable_Extension $0 = {\n ", ExtensionLayout(ext));
1891
+ WriteExtension(layout.GetExtension(ext), output);
1892
+ output("\n};\n");
1893
+ }
1894
+
1895
+ output(
1896
+ "\n"
1897
+ "static const upb_MiniTable_Extension *$0[$1] = {\n",
1898
+ kExtensionsInit, exts.size());
1899
+
1900
+ for (auto ext : exts) {
1901
+ output(" &$0,\n", ExtensionLayout(ext));
1902
+ }
1903
+
1904
+ output(
1905
+ "};\n"
1906
+ "\n");
1907
+ return exts.size();
1908
+ }
1909
+
1910
+ // Writes a .upb.c source file.
1911
+ void WriteSource(const FileLayout& layout, Output& output,
1912
+ bool fasttable_enabled) {
1913
+ const protobuf::FileDescriptor* file = layout.descriptor();
1914
+ EmitFileWarning(file, output);
1915
+
1916
+ output(
1917
+ "#include <stddef.h>\n"
1918
+ "#include \"upb/msg_internal.h\"\n"
1919
+ "#include \"$0\"\n",
1920
+ HeaderFilename(file));
1921
+
1922
+ for (int i = 0; i < file->dependency_count(); i++) {
1923
+ output("#include \"$0\"\n", HeaderFilename(file->dependency(i)));
1924
+ }
1925
+
1926
+ output(
1927
+ "\n"
1928
+ "#include \"upb/port_def.inc\"\n"
1929
+ "\n");
1930
+
1931
+ int msg_count = WriteMessages(layout, output, fasttable_enabled);
1932
+ int ext_count = WriteExtensions(layout, output);
1933
+ int enum_count = WriteEnums(layout, output);
1934
+
1935
+ output("const upb_MiniTable_File $0 = {\n", FileLayoutName(file));
1936
+ output(" $0,\n", msg_count ? kMessagesInit : "NULL");
1937
+ output(" $0,\n", enum_count ? kEnumsInit : "NULL");
1938
+ output(" $0,\n", ext_count ? kExtensionsInit : "NULL");
1939
+ output(" $0,\n", msg_count);
1940
+ output(" $0,\n", enum_count);
1941
+ output(" $0,\n", ext_count);
1942
+ output("};\n\n");
1943
+
1944
+ output("#include \"upb/port_undef.inc\"\n");
1945
+ output("\n");
1946
+ }
1947
+
1948
+ class Generator : public protoc::CodeGenerator {
1949
+ ~Generator() override {}
1950
+ bool Generate(const protobuf::FileDescriptor* file,
1951
+ const std::string& parameter, protoc::GeneratorContext* context,
1952
+ std::string* error) const override;
1953
+ uint64_t GetSupportedFeatures() const override {
1954
+ return FEATURE_PROTO3_OPTIONAL;
1955
+ }
1956
+ };
1957
+
1958
+ bool Generator::Generate(const protobuf::FileDescriptor* file,
1959
+ const std::string& parameter,
1960
+ protoc::GeneratorContext* context,
1961
+ std::string* error) const {
1962
+ bool fasttable_enabled = false;
1963
+ std::vector<std::pair<std::string, std::string>> params;
1964
+ google::protobuf::compiler::ParseGeneratorParameter(parameter, &params);
1965
+
1966
+ for (const auto& pair : params) {
1967
+ if (pair.first == "fasttable") {
1968
+ fasttable_enabled = true;
1969
+ } else {
1970
+ *error = "Unknown parameter: " + pair.first;
1971
+ return false;
1972
+ }
1973
+ }
1974
+
1975
+ FileLayout layout(file);
1976
+
1977
+ std::unique_ptr<protobuf::io::ZeroCopyOutputStream> h_output_stream(
1978
+ context->Open(HeaderFilename(file)));
1979
+ Output h_output(h_output_stream.get());
1980
+ WriteHeader(layout, h_output);
1981
+
1982
+ std::unique_ptr<protobuf::io::ZeroCopyOutputStream> c_output_stream(
1983
+ context->Open(SourceFilename(file)));
1984
+ Output c_output(c_output_stream.get());
1985
+ WriteSource(layout, c_output, fasttable_enabled);
1986
+
1987
+ return true;
1988
+ }
1989
+
1990
+ } // namespace
1991
+ } // namespace upbc
1992
+
1993
+ int main(int argc, char** argv) {
1994
+ std::unique_ptr<google::protobuf::compiler::CodeGenerator> generator(
1995
+ new upbc::Generator());
1996
+ return google::protobuf::compiler::PluginMain(argc, argv, generator.get());
1997
+ }