|
|
|
@ -473,10 +473,16 @@ static size_t align_up_to(size_t offset, size_t granularity) { |
|
|
|
|
return (offset + granularity - 1) & ~(granularity - 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void create_layout(Descriptor* desc) { |
|
|
|
|
bool is_value_field(const upb_fielddef* f) { |
|
|
|
|
return upb_fielddef_isseq(f) || upb_fielddef_issubmsg(f) || |
|
|
|
|
upb_fielddef_isstring(f); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
MessageLayout* create_layout(Descriptor* desc) { |
|
|
|
|
const upb_msgdef *msgdef = desc->msgdef; |
|
|
|
|
MessageLayout* layout = ALLOC(MessageLayout); |
|
|
|
|
int nfields = upb_msgdef_numfields(msgdef); |
|
|
|
|
int noneofs = upb_msgdef_numoneofs(msgdef); |
|
|
|
|
upb_msg_field_iter it; |
|
|
|
|
upb_msg_oneof_iter oit; |
|
|
|
|
size_t off = 0; |
|
|
|
@ -487,6 +493,11 @@ void create_layout(Descriptor* desc) { |
|
|
|
|
desc->layout = layout; |
|
|
|
|
|
|
|
|
|
layout->fields = ALLOC_N(MessageField, nfields); |
|
|
|
|
layout->oneofs = NULL; |
|
|
|
|
|
|
|
|
|
if (noneofs > 0) { |
|
|
|
|
layout->oneofs = ALLOC_N(MessageOneof, noneofs); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (upb_msg_field_begin(&it, msgdef); |
|
|
|
|
!upb_msg_field_done(&it); |
|
|
|
@ -504,29 +515,41 @@ void create_layout(Descriptor* desc) { |
|
|
|
|
off += (hasbit + 8 - 1) / 8; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
off = align_up_to(off, sizeof(VALUE)); |
|
|
|
|
layout->value_offset = off; |
|
|
|
|
layout->value_count = 0; |
|
|
|
|
|
|
|
|
|
// Place all (non-oneof) VALUE fields first.
|
|
|
|
|
for (upb_msg_field_begin(&it, msgdef); |
|
|
|
|
!upb_msg_field_done(&it); |
|
|
|
|
upb_msg_field_next(&it)) { |
|
|
|
|
const upb_fielddef* field = upb_msg_iter_field(&it); |
|
|
|
|
if (upb_fielddef_containingoneof(field) || !is_value_field(field)) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
layout->fields[upb_fielddef_index(field)].offset = off; |
|
|
|
|
off += sizeof(VALUE); |
|
|
|
|
layout->value_count++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Now place all other (non-oneof) fields.
|
|
|
|
|
for (upb_msg_field_begin(&it, msgdef); |
|
|
|
|
!upb_msg_field_done(&it); |
|
|
|
|
upb_msg_field_next(&it)) { |
|
|
|
|
const upb_fielddef* field = upb_msg_iter_field(&it); |
|
|
|
|
size_t field_size; |
|
|
|
|
|
|
|
|
|
if (upb_fielddef_containingoneof(field)) { |
|
|
|
|
// Oneofs are handled separately below.
|
|
|
|
|
if (upb_fielddef_containingoneof(field) || is_value_field(field)) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Allocate |field_size| bytes for this field in the layout.
|
|
|
|
|
field_size = 0; |
|
|
|
|
if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { |
|
|
|
|
field_size = sizeof(VALUE); |
|
|
|
|
} else { |
|
|
|
|
field_size = native_slot_size(upb_fielddef_type(field)); |
|
|
|
|
} |
|
|
|
|
field_size = native_slot_size(upb_fielddef_type(field)); |
|
|
|
|
|
|
|
|
|
// Align current offset up to |size| granularity.
|
|
|
|
|
off = align_up_to(off, field_size); |
|
|
|
|
layout->fields[upb_fielddef_index(field)].offset = off; |
|
|
|
|
layout->fields[upb_fielddef_index(field)].case_offset = |
|
|
|
|
MESSAGE_FIELD_NO_CASE; |
|
|
|
|
off += field_size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -560,6 +583,7 @@ void create_layout(Descriptor* desc) { |
|
|
|
|
upb_oneof_next(&fit)) { |
|
|
|
|
const upb_fielddef* field = upb_oneof_iter_field(&fit); |
|
|
|
|
layout->fields[upb_fielddef_index(field)].offset = off; |
|
|
|
|
layout->oneofs[upb_oneofdef_index(oneof)].offset = off; |
|
|
|
|
} |
|
|
|
|
off += field_size; |
|
|
|
|
} |
|
|
|
@ -569,18 +593,10 @@ void create_layout(Descriptor* desc) { |
|
|
|
|
!upb_msg_oneof_done(&oit); |
|
|
|
|
upb_msg_oneof_next(&oit)) { |
|
|
|
|
const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); |
|
|
|
|
upb_oneof_iter fit; |
|
|
|
|
|
|
|
|
|
size_t field_size = sizeof(uint32_t); |
|
|
|
|
// Align the offset.
|
|
|
|
|
off = (off + field_size - 1) & ~(field_size - 1); |
|
|
|
|
// Assign all fields in the oneof this same offset.
|
|
|
|
|
for (upb_oneof_begin(&fit, oneof); |
|
|
|
|
!upb_oneof_done(&fit); |
|
|
|
|
upb_oneof_next(&fit)) { |
|
|
|
|
const upb_fielddef* field = upb_oneof_iter_field(&fit); |
|
|
|
|
layout->fields[upb_fielddef_index(field)].case_offset = off; |
|
|
|
|
} |
|
|
|
|
layout->oneofs[upb_oneofdef_index(oneof)].case_offset = off; |
|
|
|
|
off += field_size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -601,6 +617,7 @@ void create_layout(Descriptor* desc) { |
|
|
|
|
void free_layout(MessageLayout* layout) { |
|
|
|
|
xfree(layout->empty_template); |
|
|
|
|
xfree(layout->fields); |
|
|
|
|
xfree(layout->oneofs); |
|
|
|
|
xfree(layout); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -627,9 +644,15 @@ static void* slot_memory(MessageLayout* layout, |
|
|
|
|
|
|
|
|
|
static uint32_t* slot_oneof_case(MessageLayout* layout, |
|
|
|
|
const void* storage, |
|
|
|
|
const upb_fielddef* field) { |
|
|
|
|
return (uint32_t *)(((uint8_t *)storage) + |
|
|
|
|
layout->fields[upb_fielddef_index(field)].case_offset); |
|
|
|
|
const upb_oneofdef* oneof) { |
|
|
|
|
return (uint32_t*)(((uint8_t*)storage) + |
|
|
|
|
layout->oneofs[upb_oneofdef_index(oneof)].case_offset); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint32_t slot_read_oneof_case(MessageLayout* layout, const void* storage, |
|
|
|
|
const upb_oneofdef* oneof) { |
|
|
|
|
uint32_t* ptr = slot_oneof_case(layout, storage, oneof); |
|
|
|
|
return *ptr & ~ONEOF_CASE_MASK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void slot_set_hasbit(MessageLayout* layout, |
|
|
|
@ -672,13 +695,14 @@ void layout_clear(MessageLayout* layout, |
|
|
|
|
const void* storage, |
|
|
|
|
const upb_fielddef* field) { |
|
|
|
|
void* memory = slot_memory(layout, storage, field); |
|
|
|
|
uint32_t* oneof_case = slot_oneof_case(layout, storage, field); |
|
|
|
|
const upb_oneofdef* oneof = upb_fielddef_containingoneof(field); |
|
|
|
|
|
|
|
|
|
if (field_contains_hasbit(layout, field)) { |
|
|
|
|
slot_clear_hasbit(layout, storage, field); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (upb_fielddef_containingoneof(field)) { |
|
|
|
|
if (oneof) { |
|
|
|
|
uint32_t* oneof_case = slot_oneof_case(layout, storage, oneof); |
|
|
|
|
memset(memory, 0, NATIVE_SLOT_MAX_SIZE); |
|
|
|
|
*oneof_case = ONEOF_CASE_NONE; |
|
|
|
|
} else if (is_map_field(field)) { |
|
|
|
@ -764,8 +788,7 @@ VALUE layout_get(MessageLayout* layout, |
|
|
|
|
const void* storage, |
|
|
|
|
const upb_fielddef* field) { |
|
|
|
|
void* memory = slot_memory(layout, storage, field); |
|
|
|
|
uint32_t* oneof_case = slot_oneof_case(layout, storage, field); |
|
|
|
|
|
|
|
|
|
const upb_oneofdef* oneof = upb_fielddef_containingoneof(field); |
|
|
|
|
bool field_set; |
|
|
|
|
if (field_contains_hasbit(layout, field)) { |
|
|
|
|
field_set = slot_is_hasbit_set(layout, storage, field); |
|
|
|
@ -773,8 +796,9 @@ VALUE layout_get(MessageLayout* layout, |
|
|
|
|
field_set = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (upb_fielddef_containingoneof(field)) { |
|
|
|
|
if (*oneof_case != upb_fielddef_number(field)) { |
|
|
|
|
if (oneof) { |
|
|
|
|
uint32_t oneof_case = slot_read_oneof_case(layout, storage, oneof); |
|
|
|
|
if (oneof_case != upb_fielddef_number(field)) { |
|
|
|
|
return layout_get_default(field); |
|
|
|
|
} |
|
|
|
|
return native_slot_get(upb_fielddef_type(field), |
|
|
|
@ -837,9 +861,10 @@ void layout_set(MessageLayout* layout, |
|
|
|
|
const upb_fielddef* field, |
|
|
|
|
VALUE val) { |
|
|
|
|
void* memory = slot_memory(layout, storage, field); |
|
|
|
|
uint32_t* oneof_case = slot_oneof_case(layout, storage, field); |
|
|
|
|
const upb_oneofdef* oneof = upb_fielddef_containingoneof(field); |
|
|
|
|
|
|
|
|
|
if (upb_fielddef_containingoneof(field)) { |
|
|
|
|
if (oneof) { |
|
|
|
|
uint32_t* oneof_case = slot_oneof_case(layout, storage, oneof); |
|
|
|
|
if (val == Qnil) { |
|
|
|
|
// Assigning nil to a oneof field clears the oneof completely.
|
|
|
|
|
*oneof_case = ONEOF_CASE_NONE; |
|
|
|
@ -857,11 +882,14 @@ void layout_set(MessageLayout* layout, |
|
|
|
|
// sync with the value slot whenever the Ruby VM has been called. Thus, we
|
|
|
|
|
// use native_slot_set_value_and_case(), which ensures that both the value
|
|
|
|
|
// and case number are altered atomically (w.r.t. the Ruby VM).
|
|
|
|
|
uint32_t case_value = upb_fielddef_number(field); |
|
|
|
|
if (upb_fielddef_issubmsg(field) || upb_fielddef_isstring(field)) { |
|
|
|
|
case_value |= ONEOF_CASE_MASK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
native_slot_set_value_and_case( |
|
|
|
|
upb_fielddef_name(field), |
|
|
|
|
upb_fielddef_type(field), field_type_class(layout, field), |
|
|
|
|
memory, val, |
|
|
|
|
oneof_case, upb_fielddef_number(field)); |
|
|
|
|
upb_fielddef_name(field), upb_fielddef_type(field), |
|
|
|
|
field_type_class(layout, field), memory, val, oneof_case, case_value); |
|
|
|
|
} |
|
|
|
|
} else if (is_map_field(field)) { |
|
|
|
|
check_map_field_type(layout, val, field); |
|
|
|
@ -893,22 +921,19 @@ void layout_init(MessageLayout* layout, void* storage) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void layout_mark(MessageLayout* layout, void* storage) { |
|
|
|
|
upb_msg_field_iter it; |
|
|
|
|
for (upb_msg_field_begin(&it, layout->msgdef); |
|
|
|
|
!upb_msg_field_done(&it); |
|
|
|
|
upb_msg_field_next(&it)) { |
|
|
|
|
const upb_fielddef* field = upb_msg_iter_field(&it); |
|
|
|
|
void* memory = slot_memory(layout, storage, field); |
|
|
|
|
uint32_t* oneof_case = slot_oneof_case(layout, storage, field); |
|
|
|
|
VALUE* values = (VALUE*)CHARPTR_AT(storage, layout->value_offset); |
|
|
|
|
int noneofs = upb_msgdef_numoneofs(layout->msgdef); |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
if (upb_fielddef_containingoneof(field)) { |
|
|
|
|
if (*oneof_case == upb_fielddef_number(field)) { |
|
|
|
|
native_slot_mark(upb_fielddef_type(field), memory); |
|
|
|
|
} |
|
|
|
|
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { |
|
|
|
|
rb_gc_mark(DEREF(memory, VALUE)); |
|
|
|
|
} else { |
|
|
|
|
native_slot_mark(upb_fielddef_type(field), memory); |
|
|
|
|
for (i = 0; i < layout->value_count; i++) { |
|
|
|
|
rb_gc_mark(values[i]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i = 0; i < noneofs; i++) { |
|
|
|
|
MessageOneof* oneof = &layout->oneofs[i]; |
|
|
|
|
uint32_t* case_ptr = (uint32_t*)CHARPTR_AT(storage, oneof->case_offset); |
|
|
|
|
if (*case_ptr & ONEOF_CASE_MASK) { |
|
|
|
|
rb_gc_mark(DEREF_OFFSET(storage, oneof->offset, VALUE)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -919,14 +944,16 @@ void layout_dup(MessageLayout* layout, void* to, void* from) { |
|
|
|
|
!upb_msg_field_done(&it); |
|
|
|
|
upb_msg_field_next(&it)) { |
|
|
|
|
const upb_fielddef* field = upb_msg_iter_field(&it); |
|
|
|
|
const upb_oneofdef* oneof = upb_fielddef_containingoneof(field); |
|
|
|
|
|
|
|
|
|
void* to_memory = slot_memory(layout, to, field); |
|
|
|
|
uint32_t* to_oneof_case = slot_oneof_case(layout, to, field); |
|
|
|
|
void* from_memory = slot_memory(layout, from, field); |
|
|
|
|
uint32_t* from_oneof_case = slot_oneof_case(layout, from, field); |
|
|
|
|
|
|
|
|
|
if (upb_fielddef_containingoneof(field)) { |
|
|
|
|
if (*from_oneof_case == upb_fielddef_number(field)) { |
|
|
|
|
if (oneof) { |
|
|
|
|
uint32_t* to_oneof_case = slot_oneof_case(layout, to, oneof); |
|
|
|
|
uint32_t* from_oneof_case = slot_oneof_case(layout, from, oneof); |
|
|
|
|
if (slot_read_oneof_case(layout, from, oneof) == |
|
|
|
|
upb_fielddef_number(field)) { |
|
|
|
|
*to_oneof_case = *from_oneof_case; |
|
|
|
|
native_slot_dup(upb_fielddef_type(field), to_memory, from_memory); |
|
|
|
|
} |
|
|
|
@ -951,14 +978,16 @@ void layout_deep_copy(MessageLayout* layout, void* to, void* from) { |
|
|
|
|
!upb_msg_field_done(&it); |
|
|
|
|
upb_msg_field_next(&it)) { |
|
|
|
|
const upb_fielddef* field = upb_msg_iter_field(&it); |
|
|
|
|
const upb_oneofdef* oneof = upb_fielddef_containingoneof(field); |
|
|
|
|
|
|
|
|
|
void* to_memory = slot_memory(layout, to, field); |
|
|
|
|
uint32_t* to_oneof_case = slot_oneof_case(layout, to, field); |
|
|
|
|
void* from_memory = slot_memory(layout, from, field); |
|
|
|
|
uint32_t* from_oneof_case = slot_oneof_case(layout, from, field); |
|
|
|
|
|
|
|
|
|
if (upb_fielddef_containingoneof(field)) { |
|
|
|
|
if (*from_oneof_case == upb_fielddef_number(field)) { |
|
|
|
|
if (oneof) { |
|
|
|
|
uint32_t* to_oneof_case = slot_oneof_case(layout, to, oneof); |
|
|
|
|
uint32_t* from_oneof_case = slot_oneof_case(layout, from, oneof); |
|
|
|
|
if (slot_read_oneof_case(layout, from, oneof) == |
|
|
|
|
upb_fielddef_number(field)) { |
|
|
|
|
*to_oneof_case = *from_oneof_case; |
|
|
|
|
native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory); |
|
|
|
|
} |
|
|
|
@ -985,17 +1014,18 @@ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) { |
|
|
|
|
!upb_msg_field_done(&it); |
|
|
|
|
upb_msg_field_next(&it)) { |
|
|
|
|
const upb_fielddef* field = upb_msg_iter_field(&it); |
|
|
|
|
const upb_oneofdef* oneof = upb_fielddef_containingoneof(field); |
|
|
|
|
|
|
|
|
|
void* msg1_memory = slot_memory(layout, msg1, field); |
|
|
|
|
uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field); |
|
|
|
|
void* msg2_memory = slot_memory(layout, msg2, field); |
|
|
|
|
uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field); |
|
|
|
|
|
|
|
|
|
if (upb_fielddef_containingoneof(field)) { |
|
|
|
|
if (oneof) { |
|
|
|
|
uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, oneof); |
|
|
|
|
uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, oneof); |
|
|
|
|
if (*msg1_oneof_case != *msg2_oneof_case || |
|
|
|
|
(*msg1_oneof_case == upb_fielddef_number(field) && |
|
|
|
|
!native_slot_eq(upb_fielddef_type(field), |
|
|
|
|
msg1_memory, |
|
|
|
|
(slot_read_oneof_case(layout, msg1, oneof) == |
|
|
|
|
upb_fielddef_number(field) && |
|
|
|
|
!native_slot_eq(upb_fielddef_type(field), msg1_memory, |
|
|
|
|
msg2_memory))) { |
|
|
|
|
return Qfalse; |
|
|
|
|
} |
|
|
|
@ -1011,9 +1041,8 @@ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) { |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (slot_is_hasbit_set(layout, msg1, field) != |
|
|
|
|
slot_is_hasbit_set(layout, msg2, field) || |
|
|
|
|
!native_slot_eq(upb_fielddef_type(field), |
|
|
|
|
msg1_memory, msg2_memory)) { |
|
|
|
|
slot_is_hasbit_set(layout, msg2, field) || |
|
|
|
|
!native_slot_eq(upb_fielddef_type(field), msg1_memory, msg2_memory)) { |
|
|
|
|
return Qfalse; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|