Protobuf Team Bot | 46e306b | 2022-06-30 10:23:47 -0700 | [diff] [blame] | 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 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 21 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 | |
| 25 | #ifndef UPBC_FILE_LAYOUT_H |
| 26 | #define UPBC_FILE_LAYOUT_H |
| 27 | |
| 28 | #include <string> |
| 29 | |
| 30 | #include "google/protobuf/descriptor.pb.h" |
| 31 | #include "absl/container/flat_hash_map.h" |
| 32 | #include "absl/strings/substitute.h" |
Eric Salo | d9b6f13 | 2022-11-03 11:35:20 -0700 | [diff] [blame] | 33 | #include "upb/mini_table/decode.h" |
| 34 | #include "upb/mini_table/encode_internal.hpp" |
Protobuf Team Bot | 46e306b | 2022-06-30 10:23:47 -0700 | [diff] [blame] | 35 | #include "upb/upb.hpp" |
| 36 | |
| 37 | namespace upbc { |
| 38 | |
| 39 | namespace protoc = ::google::protobuf::compiler; |
| 40 | namespace protobuf = ::google::protobuf; |
| 41 | |
| 42 | std::vector<const protobuf::EnumDescriptor*> SortedEnums( |
| 43 | const protobuf::FileDescriptor* file); |
| 44 | |
| 45 | // Ordering must match upb/def.c! |
| 46 | // |
| 47 | // The ordering is significant because each upb_MessageDef* will point at the |
| 48 | // corresponding upb_MiniTable and we just iterate through the list without |
| 49 | // any search or lookup. |
| 50 | std::vector<const protobuf::Descriptor*> SortedMessages( |
| 51 | const protobuf::FileDescriptor* file); |
| 52 | |
| 53 | // Ordering must match upb/def.c! |
| 54 | // |
| 55 | // The ordering is significant because each upb_FieldDef* will point at the |
| 56 | // corresponding upb_MiniTable_Extension and we just iterate through the list |
| 57 | // without any search or lookup. |
| 58 | std::vector<const protobuf::FieldDescriptor*> SortedExtensions( |
| 59 | const protobuf::FileDescriptor* file); |
| 60 | |
| 61 | std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder( |
| 62 | const protobuf::Descriptor* message); |
| 63 | |
| 64 | //////////////////////////////////////////////////////////////////////////////// |
| 65 | // FilePlatformLayout |
| 66 | //////////////////////////////////////////////////////////////////////////////// |
| 67 | |
| 68 | // FilePlatformLayout builds and vends upb MiniTables for a given platform (32 |
| 69 | // or 64 bit). |
| 70 | class FilePlatformLayout { |
| 71 | public: |
| 72 | FilePlatformLayout(const protobuf::FileDescriptor* fd, |
| 73 | upb_MiniTablePlatform platform) |
| 74 | : platform_(platform) { |
| 75 | BuildMiniTables(fd); |
| 76 | BuildExtensions(fd); |
| 77 | } |
| 78 | |
| 79 | // Retrieves a upb MiniTable or Extension given a protobuf descriptor. The |
| 80 | // descriptor must be from this layout's file. |
| 81 | upb_MiniTable* GetMiniTable(const protobuf::Descriptor* m) const; |
| 82 | upb_MiniTable_Enum* GetEnumTable(const protobuf::EnumDescriptor* d) const; |
| 83 | const upb_MiniTable_Extension* GetExtension( |
| 84 | const protobuf::FieldDescriptor* fd) const; |
| 85 | |
| 86 | // Get the initializer for the given sub-message/sub-enum link. |
| 87 | static std::string GetSub(upb_MiniTable_Sub sub); |
| 88 | |
| 89 | private: |
| 90 | // Functions to build mini-tables for this file's messages and extensions. |
| 91 | void BuildMiniTables(const protobuf::FileDescriptor* fd); |
| 92 | void BuildExtensions(const protobuf::FileDescriptor* fd); |
| 93 | upb_MiniTable* MakeMiniTable(const protobuf::Descriptor* m); |
Eric Salo | 20310e2 | 2022-10-24 13:43:21 -0700 | [diff] [blame] | 94 | upb_MiniTable* MakeMapMiniTable(const protobuf::Descriptor* m); |
Eric Salo | 5c64680 | 2022-10-26 13:39:52 -0700 | [diff] [blame] | 95 | upb_MiniTable* MakeMessageSetMiniTable(const protobuf::Descriptor* m); |
Protobuf Team Bot | 46e306b | 2022-06-30 10:23:47 -0700 | [diff] [blame] | 96 | upb_MiniTable* MakeRegularMiniTable(const protobuf::Descriptor* m); |
| 97 | upb_MiniTable_Enum* MakeMiniTableEnum(const protobuf::EnumDescriptor* d); |
| 98 | uint64_t GetMessageModifiers(const protobuf::Descriptor* m); |
| 99 | uint64_t GetFieldModifiers(const protobuf::FieldDescriptor* f); |
| 100 | void ResolveIntraFileReferences(); |
| 101 | |
| 102 | // When we are generating code, tables are linked to sub-tables via name (ie. |
| 103 | // a string) rather than by pointer. We need to emit an initializer like |
| 104 | // `&foo_sub_table`. To do this, we store `const char*` strings in all the |
| 105 | // links that would normally be pointers: |
| 106 | // field -> sub-message |
| 107 | // field -> enum table (proto2 only) |
| 108 | // extension -> extendee |
| 109 | // |
| 110 | // This requires a bit of reinterpret_cast<>(), but it's confined to a few |
| 111 | // functions. We tag the pointer so we know which member of the union to |
| 112 | // initialize. |
| 113 | enum SubTag { |
| 114 | kNull = 0, |
| 115 | kMessage = 1, |
| 116 | kEnum = 2, |
| 117 | kMask = 3, |
| 118 | }; |
| 119 | |
| 120 | static upb_MiniTable_Sub PackSub(const char* data, SubTag tag); |
| 121 | static bool IsNull(upb_MiniTable_Sub sub); |
| 122 | void SetSubTableStrings(); |
| 123 | upb_MiniTable_Sub PackSubForField(const protobuf::FieldDescriptor* f, |
| 124 | const upb_MiniTable_Field* mt_f); |
| 125 | const char* AllocStr(absl::string_view str); |
| 126 | |
| 127 | private: |
| 128 | using TableMap = |
| 129 | absl::flat_hash_map<const protobuf::Descriptor*, upb_MiniTable*>; |
| 130 | using EnumMap = |
| 131 | absl::flat_hash_map<const protobuf::EnumDescriptor*, upb_MiniTable_Enum*>; |
| 132 | using ExtensionMap = absl::flat_hash_map<const protobuf::FieldDescriptor*, |
| 133 | upb_MiniTable_Extension>; |
| 134 | upb::Arena arena_; |
| 135 | TableMap table_map_; |
| 136 | EnumMap enum_map_; |
| 137 | ExtensionMap extension_map_; |
| 138 | upb_MiniTablePlatform platform_; |
| 139 | }; |
| 140 | |
| 141 | //////////////////////////////////////////////////////////////////////////////// |
| 142 | // FileLayout |
| 143 | //////////////////////////////////////////////////////////////////////////////// |
| 144 | |
| 145 | // FileLayout is a pair of platform layouts: one for 32-bit and one for 64-bit. |
| 146 | class FileLayout { |
| 147 | public: |
| 148 | FileLayout(const protobuf::FileDescriptor* fd) |
| 149 | : descriptor_(fd), |
| 150 | layout32_(fd, kUpb_MiniTablePlatform_32Bit), |
| 151 | layout64_(fd, kUpb_MiniTablePlatform_64Bit) {} |
| 152 | |
| 153 | const protobuf::FileDescriptor* descriptor() const { return descriptor_; } |
| 154 | |
| 155 | const upb_MiniTable* GetMiniTable32(const protobuf::Descriptor* m) const { |
| 156 | return layout32_.GetMiniTable(m); |
| 157 | } |
| 158 | |
| 159 | const upb_MiniTable* GetMiniTable64(const protobuf::Descriptor* m) const { |
| 160 | return layout64_.GetMiniTable(m); |
| 161 | } |
| 162 | |
| 163 | const upb_MiniTable_Enum* GetEnumTable( |
| 164 | const protobuf::EnumDescriptor* d) const { |
| 165 | return layout64_.GetEnumTable(d); |
| 166 | } |
| 167 | |
| 168 | std::string GetFieldOffset(const protobuf::FieldDescriptor* f) const { |
| 169 | const upb_MiniTable_Field* f_32 = upb_MiniTable_FindFieldByNumber( |
| 170 | GetMiniTable32(f->containing_type()), f->number()); |
| 171 | const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber( |
| 172 | GetMiniTable64(f->containing_type()), f->number()); |
| 173 | return absl::Substitute("UPB_SIZE($0, $1)", f_32->offset, f_64->offset); |
| 174 | } |
| 175 | |
| 176 | std::string GetOneofCaseOffset(const protobuf::OneofDescriptor* o) const { |
| 177 | const protobuf::FieldDescriptor* f = o->field(0); |
| 178 | const upb_MiniTable_Field* f_32 = upb_MiniTable_FindFieldByNumber( |
| 179 | GetMiniTable32(f->containing_type()), f->number()); |
| 180 | const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber( |
| 181 | GetMiniTable64(f->containing_type()), f->number()); |
| 182 | return absl::Substitute("UPB_SIZE($0, $1)", ~f_32->presence, |
| 183 | ~f_64->presence); |
| 184 | } |
| 185 | |
| 186 | std::string GetMessageSize(const protobuf::Descriptor* d) const { |
| 187 | return absl::Substitute("UPB_SIZE($0, $1)", GetMiniTable32(d)->size, |
| 188 | GetMiniTable64(d)->size); |
| 189 | } |
| 190 | |
| 191 | int GetHasbitIndex(const protobuf::FieldDescriptor* f) const { |
| 192 | const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber( |
| 193 | GetMiniTable64(f->containing_type()), f->number()); |
| 194 | return f_64->presence; |
| 195 | } |
| 196 | |
| 197 | bool HasHasbit(const protobuf::FieldDescriptor* f) const { |
| 198 | return GetHasbitIndex(f) > 0; |
| 199 | } |
| 200 | |
| 201 | const upb_MiniTable_Extension* GetExtension( |
| 202 | const protobuf::FieldDescriptor* f) const { |
| 203 | return layout64_.GetExtension(f); |
| 204 | } |
| 205 | |
| 206 | private: |
| 207 | const protobuf::FileDescriptor* descriptor_; |
| 208 | FilePlatformLayout layout32_; |
| 209 | FilePlatformLayout layout64_; |
| 210 | }; |
| 211 | |
| 212 | } // namespace upbc |
| 213 | |
| 214 | #endif // UPBC_FILE_LAYOUT_H |