blob: 6804cdc1620bdf7696e618d459f1cc63b479fe8e [file] [log] [blame]
Protobuf Team Bot46e306b2022-06-30 10:23:47 -07001// 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 Salod9b6f132022-11-03 11:35:20 -070033#include "upb/mini_table/decode.h"
34#include "upb/mini_table/encode_internal.hpp"
Protobuf Team Bot46e306b2022-06-30 10:23:47 -070035#include "upb/upb.hpp"
36
37namespace upbc {
38
39namespace protoc = ::google::protobuf::compiler;
40namespace protobuf = ::google::protobuf;
41
42std::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.
50std::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.
58std::vector<const protobuf::FieldDescriptor*> SortedExtensions(
59 const protobuf::FileDescriptor* file);
60
61std::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).
70class 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 Salo20310e22022-10-24 13:43:21 -070094 upb_MiniTable* MakeMapMiniTable(const protobuf::Descriptor* m);
Eric Salo5c646802022-10-26 13:39:52 -070095 upb_MiniTable* MakeMessageSetMiniTable(const protobuf::Descriptor* m);
Protobuf Team Bot46e306b2022-06-30 10:23:47 -070096 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.
146class 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