Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: third_party/protobuf/ruby/ext/google/protobuf_c/storage.c

Issue 1322483002: Revert https://codereview.chromium.org/1291903002 (protobuf roll). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2014 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #include "protobuf.h"
32
33 #include <math.h>
34
35 #include <ruby/encoding.h>
36
37 // -----------------------------------------------------------------------------
38 // Ruby <-> native slot management.
39 // -----------------------------------------------------------------------------
40
41 #define DEREF(memory, type) *(type*)(memory)
42
43 size_t native_slot_size(upb_fieldtype_t type) {
44 switch (type) {
45 case UPB_TYPE_FLOAT: return 4;
46 case UPB_TYPE_DOUBLE: return 8;
47 case UPB_TYPE_BOOL: return 1;
48 case UPB_TYPE_STRING: return sizeof(VALUE);
49 case UPB_TYPE_BYTES: return sizeof(VALUE);
50 case UPB_TYPE_MESSAGE: return sizeof(VALUE);
51 case UPB_TYPE_ENUM: return 4;
52 case UPB_TYPE_INT32: return 4;
53 case UPB_TYPE_INT64: return 8;
54 case UPB_TYPE_UINT32: return 4;
55 case UPB_TYPE_UINT64: return 8;
56 default: return 0;
57 }
58 }
59
60 static bool is_ruby_num(VALUE value) {
61 return (TYPE(value) == T_FLOAT ||
62 TYPE(value) == T_FIXNUM ||
63 TYPE(value) == T_BIGNUM);
64 }
65
66 void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
67 if (!is_ruby_num(val)) {
68 rb_raise(rb_eTypeError, "Expected number type for integral field.");
69 }
70
71 // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
72 // bound; we just need to do precision checks (i.e., disallow rounding) and
73 // check for < 0 on unsigned types.
74 if (TYPE(val) == T_FLOAT) {
75 double dbl_val = NUM2DBL(val);
76 if (floor(dbl_val) != dbl_val) {
77 rb_raise(rb_eRangeError,
78 "Non-integral floating point value assigned to integer field.");
79 }
80 }
81 if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
82 if (NUM2DBL(val) < 0) {
83 rb_raise(rb_eRangeError,
84 "Assigning negative value to unsigned integer field.");
85 }
86 }
87 }
88
89 void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value) {
90 bool bad_encoding = false;
91 rb_encoding* string_encoding = rb_enc_from_index(ENCODING_GET(value));
92 if (type == UPB_TYPE_STRING) {
93 bad_encoding =
94 string_encoding != kRubyStringUtf8Encoding &&
95 string_encoding != kRubyStringASCIIEncoding;
96 } else {
97 bad_encoding =
98 string_encoding != kRubyString8bitEncoding;
99 }
100 // Check that encoding is UTF-8 or ASCII (for string fields) or ASCII-8BIT
101 // (for bytes fields).
102 if (bad_encoding) {
103 rb_raise(rb_eTypeError, "Encoding for '%s' fields must be %s (was %s)",
104 (type == UPB_TYPE_STRING) ? "string" : "bytes",
105 (type == UPB_TYPE_STRING) ? "UTF-8 or ASCII" : "ASCII-8BIT",
106 rb_enc_name(string_encoding));
107 }
108 }
109
110 void native_slot_set(upb_fieldtype_t type, VALUE type_class,
111 void* memory, VALUE value) {
112 native_slot_set_value_and_case(type, type_class, memory, value, NULL, 0);
113 }
114
115 void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
116 void* memory, VALUE value,
117 uint32_t* case_memory,
118 uint32_t case_number) {
119 // Note that in order to atomically change the value in memory and the case
120 // value (w.r.t. Ruby VM calls), we must set the value at |memory| only after
121 // all Ruby VM calls are complete. The case is then set at the bottom of this
122 // function.
123 switch (type) {
124 case UPB_TYPE_FLOAT:
125 if (!is_ruby_num(value)) {
126 rb_raise(rb_eTypeError, "Expected number type for float field.");
127 }
128 DEREF(memory, float) = NUM2DBL(value);
129 break;
130 case UPB_TYPE_DOUBLE:
131 if (!is_ruby_num(value)) {
132 rb_raise(rb_eTypeError, "Expected number type for double field.");
133 }
134 DEREF(memory, double) = NUM2DBL(value);
135 break;
136 case UPB_TYPE_BOOL: {
137 int8_t val = -1;
138 if (value == Qtrue) {
139 val = 1;
140 } else if (value == Qfalse) {
141 val = 0;
142 } else {
143 rb_raise(rb_eTypeError, "Invalid argument for boolean field.");
144 }
145 DEREF(memory, int8_t) = val;
146 break;
147 }
148 case UPB_TYPE_STRING:
149 case UPB_TYPE_BYTES: {
150 if (CLASS_OF(value) != rb_cString) {
151 rb_raise(rb_eTypeError, "Invalid argument for string field.");
152 }
153 native_slot_validate_string_encoding(type, value);
154 DEREF(memory, VALUE) = value;
155 break;
156 }
157 case UPB_TYPE_MESSAGE: {
158 if (CLASS_OF(value) == CLASS_OF(Qnil)) {
159 value = Qnil;
160 } else if (CLASS_OF(value) != type_class) {
161 rb_raise(rb_eTypeError,
162 "Invalid type %s to assign to submessage field.",
163 rb_class2name(CLASS_OF(value)));
164 }
165 DEREF(memory, VALUE) = value;
166 break;
167 }
168 case UPB_TYPE_ENUM: {
169 if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
170 rb_raise(rb_eTypeError,
171 "Expected number or symbol type for enum field.");
172 }
173 int32_t int_val = 0;
174 if (TYPE(value) == T_SYMBOL) {
175 // Ensure that the given symbol exists in the enum module.
176 VALUE lookup = rb_funcall(type_class, rb_intern("resolve"), 1, value);
177 if (lookup == Qnil) {
178 rb_raise(rb_eRangeError, "Unknown symbol value for enum field.");
179 } else {
180 int_val = NUM2INT(lookup);
181 }
182 } else {
183 native_slot_check_int_range_precision(UPB_TYPE_INT32, value);
184 int_val = NUM2INT(value);
185 }
186 DEREF(memory, int32_t) = int_val;
187 break;
188 }
189 case UPB_TYPE_INT32:
190 case UPB_TYPE_INT64:
191 case UPB_TYPE_UINT32:
192 case UPB_TYPE_UINT64:
193 native_slot_check_int_range_precision(type, value);
194 switch (type) {
195 case UPB_TYPE_INT32:
196 DEREF(memory, int32_t) = NUM2INT(value);
197 break;
198 case UPB_TYPE_INT64:
199 DEREF(memory, int64_t) = NUM2LL(value);
200 break;
201 case UPB_TYPE_UINT32:
202 DEREF(memory, uint32_t) = NUM2UINT(value);
203 break;
204 case UPB_TYPE_UINT64:
205 DEREF(memory, uint64_t) = NUM2ULL(value);
206 break;
207 default:
208 break;
209 }
210 break;
211 default:
212 break;
213 }
214
215 if (case_memory != NULL) {
216 *case_memory = case_number;
217 }
218 }
219
220 VALUE native_slot_get(upb_fieldtype_t type,
221 VALUE type_class,
222 const void* memory) {
223 switch (type) {
224 case UPB_TYPE_FLOAT:
225 return DBL2NUM(DEREF(memory, float));
226 case UPB_TYPE_DOUBLE:
227 return DBL2NUM(DEREF(memory, double));
228 case UPB_TYPE_BOOL:
229 return DEREF(memory, int8_t) ? Qtrue : Qfalse;
230 case UPB_TYPE_STRING:
231 case UPB_TYPE_BYTES:
232 case UPB_TYPE_MESSAGE:
233 return DEREF(memory, VALUE);
234 case UPB_TYPE_ENUM: {
235 int32_t val = DEREF(memory, int32_t);
236 VALUE symbol = enum_lookup(type_class, INT2NUM(val));
237 if (symbol == Qnil) {
238 return INT2NUM(val);
239 } else {
240 return symbol;
241 }
242 }
243 case UPB_TYPE_INT32:
244 return INT2NUM(DEREF(memory, int32_t));
245 case UPB_TYPE_INT64:
246 return LL2NUM(DEREF(memory, int64_t));
247 case UPB_TYPE_UINT32:
248 return UINT2NUM(DEREF(memory, uint32_t));
249 case UPB_TYPE_UINT64:
250 return ULL2NUM(DEREF(memory, uint64_t));
251 default:
252 return Qnil;
253 }
254 }
255
256 void native_slot_init(upb_fieldtype_t type, void* memory) {
257 switch (type) {
258 case UPB_TYPE_FLOAT:
259 DEREF(memory, float) = 0.0;
260 break;
261 case UPB_TYPE_DOUBLE:
262 DEREF(memory, double) = 0.0;
263 break;
264 case UPB_TYPE_BOOL:
265 DEREF(memory, int8_t) = 0;
266 break;
267 case UPB_TYPE_STRING:
268 case UPB_TYPE_BYTES:
269 DEREF(memory, VALUE) = rb_str_new2("");
270 rb_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES) ?
271 kRubyString8bitEncoding : kRubyStringUtf8Encoding);
272 break;
273 case UPB_TYPE_MESSAGE:
274 DEREF(memory, VALUE) = Qnil;
275 break;
276 case UPB_TYPE_ENUM:
277 case UPB_TYPE_INT32:
278 DEREF(memory, int32_t) = 0;
279 break;
280 case UPB_TYPE_INT64:
281 DEREF(memory, int64_t) = 0;
282 break;
283 case UPB_TYPE_UINT32:
284 DEREF(memory, uint32_t) = 0;
285 break;
286 case UPB_TYPE_UINT64:
287 DEREF(memory, uint64_t) = 0;
288 break;
289 default:
290 break;
291 }
292 }
293
294 void native_slot_mark(upb_fieldtype_t type, void* memory) {
295 switch (type) {
296 case UPB_TYPE_STRING:
297 case UPB_TYPE_BYTES:
298 case UPB_TYPE_MESSAGE:
299 rb_gc_mark(DEREF(memory, VALUE));
300 break;
301 default:
302 break;
303 }
304 }
305
306 void native_slot_dup(upb_fieldtype_t type, void* to, void* from) {
307 memcpy(to, from, native_slot_size(type));
308 }
309
310 void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from) {
311 switch (type) {
312 case UPB_TYPE_STRING:
313 case UPB_TYPE_BYTES: {
314 VALUE from_val = DEREF(from, VALUE);
315 DEREF(to, VALUE) = (from_val != Qnil) ?
316 rb_funcall(from_val, rb_intern("dup"), 0) : Qnil;
317 break;
318 }
319 case UPB_TYPE_MESSAGE: {
320 VALUE from_val = DEREF(from, VALUE);
321 DEREF(to, VALUE) = (from_val != Qnil) ?
322 Message_deep_copy(from_val) : Qnil;
323 break;
324 }
325 default:
326 memcpy(to, from, native_slot_size(type));
327 }
328 }
329
330 bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2) {
331 switch (type) {
332 case UPB_TYPE_STRING:
333 case UPB_TYPE_BYTES:
334 case UPB_TYPE_MESSAGE: {
335 VALUE val1 = DEREF(mem1, VALUE);
336 VALUE val2 = DEREF(mem2, VALUE);
337 VALUE ret = rb_funcall(val1, rb_intern("=="), 1, val2);
338 return ret == Qtrue;
339 }
340 default:
341 return !memcmp(mem1, mem2, native_slot_size(type));
342 }
343 }
344
345 // -----------------------------------------------------------------------------
346 // Map field utilities.
347 // -----------------------------------------------------------------------------
348
349 bool is_map_field(const upb_fielddef* field) {
350 if (upb_fielddef_label(field) != UPB_LABEL_REPEATED ||
351 upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
352 return false;
353 }
354 const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
355 return upb_msgdef_mapentry(subdef);
356 }
357
358 const upb_fielddef* map_field_key(const upb_fielddef* field) {
359 assert(is_map_field(field));
360 const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
361 return map_entry_key(subdef);
362 }
363
364 const upb_fielddef* map_field_value(const upb_fielddef* field) {
365 assert(is_map_field(field));
366 const upb_msgdef* subdef = upb_fielddef_msgsubdef(field);
367 return map_entry_value(subdef);
368 }
369
370 const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) {
371 const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD);
372 assert(key_field != NULL);
373 return key_field;
374 }
375
376 const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) {
377 const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD);
378 assert(value_field != NULL);
379 return value_field;
380 }
381
382 // -----------------------------------------------------------------------------
383 // Memory layout management.
384 // -----------------------------------------------------------------------------
385
386 static size_t align_up_to(size_t offset, size_t granularity) {
387 // Granularity must be a power of two.
388 return (offset + granularity - 1) & ~(granularity - 1);
389 }
390
391 MessageLayout* create_layout(const upb_msgdef* msgdef) {
392 MessageLayout* layout = ALLOC(MessageLayout);
393 int nfields = upb_msgdef_numfields(msgdef);
394 layout->fields = ALLOC_N(MessageField, nfields);
395
396 upb_msg_field_iter it;
397 size_t off = 0;
398 for (upb_msg_field_begin(&it, msgdef);
399 !upb_msg_field_done(&it);
400 upb_msg_field_next(&it)) {
401 const upb_fielddef* field = upb_msg_iter_field(&it);
402
403 if (upb_fielddef_containingoneof(field)) {
404 // Oneofs are handled separately below.
405 continue;
406 }
407
408 // Allocate |field_size| bytes for this field in the layout.
409 size_t field_size = 0;
410 if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
411 field_size = sizeof(VALUE);
412 } else {
413 field_size = native_slot_size(upb_fielddef_type(field));
414 }
415 // Align current offset up to |size| granularity.
416 off = align_up_to(off, field_size);
417 layout->fields[upb_fielddef_index(field)].offset = off;
418 layout->fields[upb_fielddef_index(field)].case_offset =
419 MESSAGE_FIELD_NO_CASE;
420 off += field_size;
421 }
422
423 // Handle oneofs now -- we iterate over oneofs specifically and allocate only
424 // one slot per oneof.
425 //
426 // We assign all value slots first, then pack the 'case' fields at the end,
427 // since in the common case (modern 64-bit platform) these are 8 bytes and 4
428 // bytes respectively and we want to avoid alignment overhead.
429 //
430 // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value
431 // space for oneof cases is conceptually as wide as field tag numbers. In
432 // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K
433 // members (8 or 16 bits respectively), so conceivably we could assign
434 // consecutive case numbers and then pick a smaller oneof case slot size, but
435 // the complexity to implement this indirection is probably not worthwhile.
436 upb_msg_oneof_iter oit;
437 for (upb_msg_oneof_begin(&oit, msgdef);
438 !upb_msg_oneof_done(&oit);
439 upb_msg_oneof_next(&oit)) {
440 const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
441
442 // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between
443 // all fields.
444 size_t field_size = NATIVE_SLOT_MAX_SIZE;
445 // Align the offset.
446 off = align_up_to(off, field_size);
447 // Assign all fields in the oneof this same offset.
448 upb_oneof_iter fit;
449 for (upb_oneof_begin(&fit, oneof);
450 !upb_oneof_done(&fit);
451 upb_oneof_next(&fit)) {
452 const upb_fielddef* field = upb_oneof_iter_field(&fit);
453 layout->fields[upb_fielddef_index(field)].offset = off;
454 }
455 off += field_size;
456 }
457
458 // Now the case fields.
459 for (upb_msg_oneof_begin(&oit, msgdef);
460 !upb_msg_oneof_done(&oit);
461 upb_msg_oneof_next(&oit)) {
462 const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
463
464 size_t field_size = sizeof(uint32_t);
465 // Align the offset.
466 off = (off + field_size - 1) & ~(field_size - 1);
467 // Assign all fields in the oneof this same offset.
468 upb_oneof_iter fit;
469 for (upb_oneof_begin(&fit, oneof);
470 !upb_oneof_done(&fit);
471 upb_oneof_next(&fit)) {
472 const upb_fielddef* field = upb_oneof_iter_field(&fit);
473 layout->fields[upb_fielddef_index(field)].case_offset = off;
474 }
475 off += field_size;
476 }
477
478 layout->size = off;
479
480 layout->msgdef = msgdef;
481 upb_msgdef_ref(layout->msgdef, &layout->msgdef);
482
483 return layout;
484 }
485
486 void free_layout(MessageLayout* layout) {
487 xfree(layout->fields);
488 upb_msgdef_unref(layout->msgdef, &layout->msgdef);
489 xfree(layout);
490 }
491
492 VALUE field_type_class(const upb_fielddef* field) {
493 VALUE type_class = Qnil;
494 if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
495 VALUE submsgdesc =
496 get_def_obj(upb_fielddef_subdef(field));
497 type_class = Descriptor_msgclass(submsgdesc);
498 } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
499 VALUE subenumdesc =
500 get_def_obj(upb_fielddef_subdef(field));
501 type_class = EnumDescriptor_enummodule(subenumdesc);
502 }
503 return type_class;
504 }
505
506 static void* slot_memory(MessageLayout* layout,
507 const void* storage,
508 const upb_fielddef* field) {
509 return ((uint8_t *)storage) +
510 layout->fields[upb_fielddef_index(field)].offset;
511 }
512
513 static uint32_t* slot_oneof_case(MessageLayout* layout,
514 const void* storage,
515 const upb_fielddef* field) {
516 return (uint32_t *)(((uint8_t *)storage) +
517 layout->fields[upb_fielddef_index(field)].case_offset);
518 }
519
520
521 VALUE layout_get(MessageLayout* layout,
522 const void* storage,
523 const upb_fielddef* field) {
524 void* memory = slot_memory(layout, storage, field);
525 uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
526
527 if (upb_fielddef_containingoneof(field)) {
528 if (*oneof_case != upb_fielddef_number(field)) {
529 return Qnil;
530 }
531 return native_slot_get(upb_fielddef_type(field),
532 field_type_class(field),
533 memory);
534 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
535 return *((VALUE *)memory);
536 } else {
537 return native_slot_get(upb_fielddef_type(field),
538 field_type_class(field),
539 memory);
540 }
541 }
542
543 static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
544 assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);
545
546 if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
547 RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
548 rb_raise(rb_eTypeError, "Expected repeated field array");
549 }
550
551 RepeatedField* self = ruby_to_RepeatedField(val);
552 if (self->field_type != upb_fielddef_type(field)) {
553 rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
554 }
555
556 if (self->field_type == UPB_TYPE_MESSAGE ||
557 self->field_type == UPB_TYPE_ENUM) {
558 if (self->field_type_class !=
559 get_def_obj(upb_fielddef_subdef(field))) {
560 rb_raise(rb_eTypeError,
561 "Repeated field array has wrong message/enum class");
562 }
563 }
564 }
565
566 static void check_map_field_type(VALUE val, const upb_fielddef* field) {
567 assert(is_map_field(field));
568 const upb_fielddef* key_field = map_field_key(field);
569 const upb_fielddef* value_field = map_field_value(field);
570
571 if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
572 RTYPEDDATA_TYPE(val) != &Map_type) {
573 rb_raise(rb_eTypeError, "Expected Map instance");
574 }
575
576 Map* self = ruby_to_Map(val);
577 if (self->key_type != upb_fielddef_type(key_field)) {
578 rb_raise(rb_eTypeError, "Map key type does not match field's key type");
579 }
580 if (self->value_type != upb_fielddef_type(value_field)) {
581 rb_raise(rb_eTypeError, "Map value type does not match field's value type");
582 }
583 if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
584 upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
585 if (self->value_type_class !=
586 get_def_obj(upb_fielddef_subdef(value_field))) {
587 rb_raise(rb_eTypeError,
588 "Map value type has wrong message/enum class");
589 }
590 }
591 }
592
593
594 void layout_set(MessageLayout* layout,
595 void* storage,
596 const upb_fielddef* field,
597 VALUE val) {
598 void* memory = slot_memory(layout, storage, field);
599 uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
600
601 if (upb_fielddef_containingoneof(field)) {
602 if (val == Qnil) {
603 // Assigning nil to a oneof field clears the oneof completely.
604 *oneof_case = ONEOF_CASE_NONE;
605 memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
606 } else {
607 // The transition between field types for a single oneof (union) slot is
608 // somewhat complex because we need to ensure that a GC triggered at any
609 // point by a call into the Ruby VM sees a valid state for this field and
610 // does not either go off into the weeds (following what it thinks is a
611 // VALUE but is actually a different field type) or miss an object (seeing
612 // what it thinks is a primitive field but is actually a VALUE for the new
613 // field type).
614 //
615 // In order for the transition to be safe, the oneof case slot must be in
616 // sync with the value slot whenever the Ruby VM has been called. Thus, we
617 // use native_slot_set_value_and_case(), which ensures that both the value
618 // and case number are altered atomically (w.r.t. the Ruby VM).
619 native_slot_set_value_and_case(
620 upb_fielddef_type(field), field_type_class(field),
621 memory, val,
622 oneof_case, upb_fielddef_number(field));
623 }
624 } else if (is_map_field(field)) {
625 check_map_field_type(val, field);
626 DEREF(memory, VALUE) = val;
627 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
628 check_repeated_field_type(val, field);
629 DEREF(memory, VALUE) = val;
630 } else {
631 native_slot_set(upb_fielddef_type(field), field_type_class(field),
632 memory, val);
633 }
634 }
635
636 void layout_init(MessageLayout* layout,
637 void* storage) {
638 upb_msg_field_iter it;
639 for (upb_msg_field_begin(&it, layout->msgdef);
640 !upb_msg_field_done(&it);
641 upb_msg_field_next(&it)) {
642 const upb_fielddef* field = upb_msg_iter_field(&it);
643 void* memory = slot_memory(layout, storage, field);
644 uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
645
646 if (upb_fielddef_containingoneof(field)) {
647 memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
648 *oneof_case = ONEOF_CASE_NONE;
649 } else if (is_map_field(field)) {
650 VALUE map = Qnil;
651
652 const upb_fielddef* key_field = map_field_key(field);
653 const upb_fielddef* value_field = map_field_value(field);
654 VALUE type_class = field_type_class(value_field);
655
656 if (type_class != Qnil) {
657 VALUE args[3] = {
658 fieldtype_to_ruby(upb_fielddef_type(key_field)),
659 fieldtype_to_ruby(upb_fielddef_type(value_field)),
660 type_class,
661 };
662 map = rb_class_new_instance(3, args, cMap);
663 } else {
664 VALUE args[2] = {
665 fieldtype_to_ruby(upb_fielddef_type(key_field)),
666 fieldtype_to_ruby(upb_fielddef_type(value_field)),
667 };
668 map = rb_class_new_instance(2, args, cMap);
669 }
670
671 DEREF(memory, VALUE) = map;
672 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
673 VALUE ary = Qnil;
674
675 VALUE type_class = field_type_class(field);
676
677 if (type_class != Qnil) {
678 VALUE args[2] = {
679 fieldtype_to_ruby(upb_fielddef_type(field)),
680 type_class,
681 };
682 ary = rb_class_new_instance(2, args, cRepeatedField);
683 } else {
684 VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) };
685 ary = rb_class_new_instance(1, args, cRepeatedField);
686 }
687
688 DEREF(memory, VALUE) = ary;
689 } else {
690 native_slot_init(upb_fielddef_type(field), memory);
691 }
692 }
693 }
694
695 void layout_mark(MessageLayout* layout, void* storage) {
696 upb_msg_field_iter it;
697 for (upb_msg_field_begin(&it, layout->msgdef);
698 !upb_msg_field_done(&it);
699 upb_msg_field_next(&it)) {
700 const upb_fielddef* field = upb_msg_iter_field(&it);
701 void* memory = slot_memory(layout, storage, field);
702 uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
703
704 if (upb_fielddef_containingoneof(field)) {
705 if (*oneof_case == upb_fielddef_number(field)) {
706 native_slot_mark(upb_fielddef_type(field), memory);
707 }
708 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
709 rb_gc_mark(DEREF(memory, VALUE));
710 } else {
711 native_slot_mark(upb_fielddef_type(field), memory);
712 }
713 }
714 }
715
716 void layout_dup(MessageLayout* layout, void* to, void* from) {
717 upb_msg_field_iter it;
718 for (upb_msg_field_begin(&it, layout->msgdef);
719 !upb_msg_field_done(&it);
720 upb_msg_field_next(&it)) {
721 const upb_fielddef* field = upb_msg_iter_field(&it);
722
723 void* to_memory = slot_memory(layout, to, field);
724 uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
725 void* from_memory = slot_memory(layout, from, field);
726 uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
727
728 if (upb_fielddef_containingoneof(field)) {
729 if (*from_oneof_case == upb_fielddef_number(field)) {
730 *to_oneof_case = *from_oneof_case;
731 native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
732 }
733 } else if (is_map_field(field)) {
734 DEREF(to_memory, VALUE) = Map_dup(DEREF(from_memory, VALUE));
735 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
736 DEREF(to_memory, VALUE) = RepeatedField_dup(DEREF(from_memory, VALUE));
737 } else {
738 native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
739 }
740 }
741 }
742
743 void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
744 upb_msg_field_iter it;
745 for (upb_msg_field_begin(&it, layout->msgdef);
746 !upb_msg_field_done(&it);
747 upb_msg_field_next(&it)) {
748 const upb_fielddef* field = upb_msg_iter_field(&it);
749
750 void* to_memory = slot_memory(layout, to, field);
751 uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
752 void* from_memory = slot_memory(layout, from, field);
753 uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
754
755 if (upb_fielddef_containingoneof(field)) {
756 if (*from_oneof_case == upb_fielddef_number(field)) {
757 *to_oneof_case = *from_oneof_case;
758 native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
759 }
760 } else if (is_map_field(field)) {
761 DEREF(to_memory, VALUE) =
762 Map_deep_copy(DEREF(from_memory, VALUE));
763 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
764 DEREF(to_memory, VALUE) =
765 RepeatedField_deep_copy(DEREF(from_memory, VALUE));
766 } else {
767 native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
768 }
769 }
770 }
771
772 VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
773 upb_msg_field_iter it;
774 for (upb_msg_field_begin(&it, layout->msgdef);
775 !upb_msg_field_done(&it);
776 upb_msg_field_next(&it)) {
777 const upb_fielddef* field = upb_msg_iter_field(&it);
778
779 void* msg1_memory = slot_memory(layout, msg1, field);
780 uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field);
781 void* msg2_memory = slot_memory(layout, msg2, field);
782 uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field);
783
784 if (upb_fielddef_containingoneof(field)) {
785 if (*msg1_oneof_case != *msg2_oneof_case ||
786 (*msg1_oneof_case == upb_fielddef_number(field) &&
787 !native_slot_eq(upb_fielddef_type(field),
788 msg1_memory,
789 msg2_memory))) {
790 return Qfalse;
791 }
792 } else if (is_map_field(field)) {
793 if (!Map_eq(DEREF(msg1_memory, VALUE),
794 DEREF(msg2_memory, VALUE))) {
795 return Qfalse;
796 }
797 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
798 if (!RepeatedField_eq(DEREF(msg1_memory, VALUE),
799 DEREF(msg2_memory, VALUE))) {
800 return Qfalse;
801 }
802 } else {
803 if (!native_slot_eq(upb_fielddef_type(field),
804 msg1_memory, msg2_memory)) {
805 return Qfalse;
806 }
807 }
808 }
809 return Qtrue;
810 }
811
812 VALUE layout_hash(MessageLayout* layout, void* storage) {
813 upb_msg_field_iter it;
814 st_index_t h = rb_hash_start(0);
815 VALUE hash_sym = rb_intern("hash");
816 for (upb_msg_field_begin(&it, layout->msgdef);
817 !upb_msg_field_done(&it);
818 upb_msg_field_next(&it)) {
819 const upb_fielddef* field = upb_msg_iter_field(&it);
820 VALUE field_val = layout_get(layout, storage, field);
821 h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0)));
822 }
823 h = rb_hash_end(h);
824
825 return INT2FIX(h);
826 }
827
828 VALUE layout_inspect(MessageLayout* layout, void* storage) {
829 VALUE str = rb_str_new2("");
830
831 upb_msg_field_iter it;
832 bool first = true;
833 for (upb_msg_field_begin(&it, layout->msgdef);
834 !upb_msg_field_done(&it);
835 upb_msg_field_next(&it)) {
836 const upb_fielddef* field = upb_msg_iter_field(&it);
837 VALUE field_val = layout_get(layout, storage, field);
838
839 if (!first) {
840 str = rb_str_cat2(str, ", ");
841 } else {
842 first = false;
843 }
844 str = rb_str_cat2(str, upb_fielddef_name(field));
845 str = rb_str_cat2(str, ": ");
846
847 str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0));
848 }
849
850 return str;
851 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698