1
2 #include "upb/msgfactory.h"
3
4 #include "upb/port_def.inc"
5
is_power_of_two(size_t val)6 static bool is_power_of_two(size_t val) {
7 return (val & (val - 1)) == 0;
8 }
9
10 /* Align up to the given power of 2. */
align_up(size_t val,size_t align)11 static size_t align_up(size_t val, size_t align) {
12 UPB_ASSERT(is_power_of_two(align));
13 return (val + align - 1) & ~(align - 1);
14 }
15
div_round_up(size_t n,size_t d)16 static size_t div_round_up(size_t n, size_t d) {
17 return (n + d - 1) / d;
18 }
19
upb_msgval_sizeof2(upb_fieldtype_t type)20 static size_t upb_msgval_sizeof2(upb_fieldtype_t type) {
21 switch (type) {
22 case UPB_TYPE_DOUBLE:
23 case UPB_TYPE_INT64:
24 case UPB_TYPE_UINT64:
25 return 8;
26 case UPB_TYPE_ENUM:
27 case UPB_TYPE_INT32:
28 case UPB_TYPE_UINT32:
29 case UPB_TYPE_FLOAT:
30 return 4;
31 case UPB_TYPE_BOOL:
32 return 1;
33 case UPB_TYPE_MESSAGE:
34 return sizeof(void*);
35 case UPB_TYPE_BYTES:
36 case UPB_TYPE_STRING:
37 return sizeof(upb_strview);
38 }
39 UPB_UNREACHABLE();
40 }
41
upb_msg_fielddefsize(const upb_fielddef * f)42 static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) {
43 if (upb_fielddef_isseq(f)) {
44 return sizeof(void*);
45 } else {
46 return upb_msgval_sizeof2(upb_fielddef_type(f));
47 }
48 }
49
50
51 /** upb_msglayout *************************************************************/
52
upb_msglayout_free(upb_msglayout * l)53 static void upb_msglayout_free(upb_msglayout *l) {
54 upb_gfree(l);
55 }
56
upb_msglayout_place(upb_msglayout * l,size_t size)57 static size_t upb_msglayout_place(upb_msglayout *l, size_t size) {
58 size_t ret;
59
60 l->size = align_up(l->size, size);
61 ret = l->size;
62 l->size += size;
63 return ret;
64 }
65
upb_msglayout_init(const upb_msgdef * m,upb_msglayout * l,upb_msgfactory * factory)66 static bool upb_msglayout_init(const upb_msgdef *m,
67 upb_msglayout *l,
68 upb_msgfactory *factory) {
69 upb_msg_field_iter it;
70 upb_msg_oneof_iter oit;
71 size_t hasbit;
72 size_t submsg_count = 0;
73 const upb_msglayout **submsgs;
74 upb_msglayout_field *fields;
75
76 for (upb_msg_field_begin(&it, m);
77 !upb_msg_field_done(&it);
78 upb_msg_field_next(&it)) {
79 const upb_fielddef* f = upb_msg_iter_field(&it);
80 if (upb_fielddef_issubmsg(f)) {
81 submsg_count++;
82 }
83 }
84
85 memset(l, 0, sizeof(*l));
86
87 fields = upb_gmalloc(upb_msgdef_numfields(m) * sizeof(*fields));
88 submsgs = upb_gmalloc(submsg_count * sizeof(*submsgs));
89
90 if ((!fields && upb_msgdef_numfields(m)) ||
91 (!submsgs && submsg_count)) {
92 /* OOM. */
93 upb_gfree(fields);
94 upb_gfree(submsgs);
95 return false;
96 }
97
98 l->field_count = upb_msgdef_numfields(m);
99 l->fields = fields;
100 l->submsgs = submsgs;
101
102 /* Allocate data offsets in three stages:
103 *
104 * 1. hasbits.
105 * 2. regular fields.
106 * 3. oneof fields.
107 *
108 * OPT: There is a lot of room for optimization here to minimize the size.
109 */
110
111 /* Allocate hasbits and set basic field attributes. */
112 submsg_count = 0;
113 for (upb_msg_field_begin(&it, m), hasbit = 0;
114 !upb_msg_field_done(&it);
115 upb_msg_field_next(&it)) {
116 const upb_fielddef* f = upb_msg_iter_field(&it);
117 upb_msglayout_field *field = &fields[upb_fielddef_index(f)];
118
119 field->number = upb_fielddef_number(f);
120 field->descriptortype = upb_fielddef_descriptortype(f);
121 field->label = upb_fielddef_label(f);
122
123 if (upb_fielddef_issubmsg(f)) {
124 const upb_msglayout *sub_layout =
125 upb_msgfactory_getlayout(factory, upb_fielddef_msgsubdef(f));
126 field->submsg_index = submsg_count++;
127 submsgs[field->submsg_index] = sub_layout;
128 }
129
130 if (upb_fielddef_haspresence(f) && !upb_fielddef_containingoneof(f)) {
131 field->presence = (hasbit++);
132 } else {
133 field->presence = 0;
134 }
135 }
136
137 /* Account for space used by hasbits. */
138 l->size = div_round_up(hasbit, 8);
139
140 /* Allocate non-oneof fields. */
141 for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it);
142 upb_msg_field_next(&it)) {
143 const upb_fielddef* f = upb_msg_iter_field(&it);
144 size_t field_size = upb_msg_fielddefsize(f);
145 size_t index = upb_fielddef_index(f);
146
147 if (upb_fielddef_containingoneof(f)) {
148 /* Oneofs are handled separately below. */
149 continue;
150 }
151
152 fields[index].offset = upb_msglayout_place(l, field_size);
153 }
154
155 /* Allocate oneof fields. Each oneof field consists of a uint32 for the case
156 * and space for the actual data. */
157 for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit);
158 upb_msg_oneof_next(&oit)) {
159 const upb_oneofdef* o = upb_msg_iter_oneof(&oit);
160 upb_oneof_iter fit;
161
162 size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */
163 size_t field_size = 0;
164 uint32_t case_offset;
165 uint32_t data_offset;
166
167 /* Calculate field size: the max of all field sizes. */
168 for (upb_oneof_begin(&fit, o);
169 !upb_oneof_done(&fit);
170 upb_oneof_next(&fit)) {
171 const upb_fielddef* f = upb_oneof_iter_field(&fit);
172 field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f));
173 }
174
175 /* Align and allocate case offset. */
176 case_offset = upb_msglayout_place(l, case_size);
177 data_offset = upb_msglayout_place(l, field_size);
178
179 for (upb_oneof_begin(&fit, o);
180 !upb_oneof_done(&fit);
181 upb_oneof_next(&fit)) {
182 const upb_fielddef* f = upb_oneof_iter_field(&fit);
183 fields[upb_fielddef_index(f)].offset = data_offset;
184 fields[upb_fielddef_index(f)].presence = ~case_offset;
185 }
186 }
187
188 /* Size of the entire structure should be a multiple of its greatest
189 * alignment. TODO: track overall alignment for real? */
190 l->size = align_up(l->size, 8);
191
192 return true;
193 }
194
195
196 /** upb_msgfactory ************************************************************/
197
198 struct upb_msgfactory {
199 const upb_symtab *symtab; /* We own a ref. */
200 upb_inttable layouts;
201 };
202
upb_msgfactory_new(const upb_symtab * symtab)203 upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab) {
204 upb_msgfactory *ret = upb_gmalloc(sizeof(*ret));
205
206 ret->symtab = symtab;
207 upb_inttable_init(&ret->layouts, UPB_CTYPE_PTR);
208
209 return ret;
210 }
211
upb_msgfactory_free(upb_msgfactory * f)212 void upb_msgfactory_free(upb_msgfactory *f) {
213 upb_inttable_iter i;
214 upb_inttable_begin(&i, &f->layouts);
215 for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
216 upb_msglayout *l = upb_value_getptr(upb_inttable_iter_value(&i));
217 upb_msglayout_free(l);
218 }
219
220 upb_inttable_uninit(&f->layouts);
221 upb_gfree(f);
222 }
223
upb_msgfactory_symtab(const upb_msgfactory * f)224 const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f) {
225 return f->symtab;
226 }
227
upb_msgfactory_getlayout(upb_msgfactory * f,const upb_msgdef * m)228 const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f,
229 const upb_msgdef *m) {
230 upb_value v;
231 UPB_ASSERT(upb_symtab_lookupmsg(f->symtab, upb_msgdef_fullname(m)) == m);
232 UPB_ASSERT(!upb_msgdef_mapentry(m));
233
234 if (upb_inttable_lookupptr(&f->layouts, m, &v)) {
235 UPB_ASSERT(upb_value_getptr(v));
236 return upb_value_getptr(v);
237 } else {
238 /* In case of circular dependency, layout has to be inserted first. */
239 upb_msglayout *l = upb_gmalloc(sizeof(*l));
240 upb_msgfactory *mutable_f = (void*)f;
241 upb_inttable_insertptr(&mutable_f->layouts, m, upb_value_ptr(l));
242 UPB_ASSERT(l);
243 if (!upb_msglayout_init(m, l, f)) {
244 upb_msglayout_free(l);
245 }
246 return l;
247 }
248 }
249