diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c index 4ed80568af..5487a57640 100644 --- a/ruby/ext/google/protobuf_c/map.c +++ b/ruby/ext/google/protobuf_c/map.c @@ -495,7 +495,7 @@ VALUE Map_length(VALUE _self) { return ULL2NUM(upb_strtable_count(&self->table)); } -static VALUE Map_new_this_type(VALUE _self) { +VALUE Map_new_this_type(VALUE _self) { Map* self = ruby_to_Map(_self); VALUE new_map = Qnil; VALUE key_type = fieldtype_to_ruby(self->key_type); diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index 2ba7b2fe47..4dd68f4a20 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -70,8 +70,6 @@ VALUE Message_alloc(VALUE klass) { msg = (MessageHeader*)ALLOC_N(uint8_t, sizeof(MessageHeader) + desc->layout->size); - memset(Message_data(msg), 0, desc->layout->size); - // We wrap first so that everything in the message object is GC-rooted in case // a collection happens during object creation in layout_init(). ret = TypedData_Wrap_Struct(klass, &Message_type, msg); diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h index 5176d59f0c..6314b78810 100644 --- a/ruby/ext/google/protobuf_c/protobuf.h +++ b/ruby/ext/google/protobuf_c/protobuf.h @@ -419,6 +419,7 @@ extern VALUE cRepeatedField; RepeatedField* ruby_to_RepeatedField(VALUE value); +VALUE RepeatedField_new_this_type(VALUE _self); VALUE RepeatedField_each(VALUE _self); VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self); void* RepeatedField_index_native(VALUE _self, int index); @@ -467,6 +468,7 @@ extern VALUE cMap; Map* ruby_to_Map(VALUE value); +VALUE Map_new_this_type(VALUE _self); VALUE Map_each(VALUE _self); VALUE Map_keys(VALUE _self); VALUE Map_values(VALUE _self); @@ -522,11 +524,13 @@ struct MessageLayout { uint32_t size; uint32_t value_offset; int value_count; + int repeated_count; + int map_count; }; #define ONEOF_CASE_MASK 0x80000000 -MessageLayout* create_layout(Descriptor* desc); +void create_layout(Descriptor* desc); void free_layout(MessageLayout* layout); bool field_contains_hasbit(MessageLayout* layout, const upb_fielddef* field); diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c index 2766087504..1c649280fe 100644 --- a/ruby/ext/google/protobuf_c/repeated_field.c +++ b/ruby/ext/google/protobuf_c/repeated_field.c @@ -323,7 +323,7 @@ VALUE RepeatedField_length(VALUE _self) { return INT2NUM(self->size); } -static VALUE RepeatedField_new_this_type(VALUE _self) { +VALUE RepeatedField_new_this_type(VALUE _self) { RepeatedField* self = ruby_to_RepeatedField(_self); VALUE new_rptfield = Qnil; VALUE element_type = fieldtype_to_ruby(self->field_type); diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c index ad76e4f87a..6922cdc456 100644 --- a/ruby/ext/google/protobuf_c/storage.c +++ b/ruby/ext/google/protobuf_c/storage.c @@ -478,7 +478,7 @@ bool is_value_field(const upb_fielddef* f) { upb_fielddef_isstring(f); } -MessageLayout* create_layout(Descriptor* desc) { +void create_layout(Descriptor* desc) { const upb_msgdef *msgdef = desc->msgdef; MessageLayout* layout = ALLOC(MessageLayout); int nfields = upb_msgdef_numfields(msgdef); @@ -517,14 +517,49 @@ MessageLayout* create_layout(Descriptor* desc) { off = align_up_to(off, sizeof(VALUE)); layout->value_offset = off; + layout->repeated_count = 0; + layout->map_count = 0; layout->value_count = 0; - // Place all (non-oneof) VALUE fields first. + // Place all VALUE fields for repeated 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); - if (upb_fielddef_containingoneof(field) || !is_value_field(field)) { + if (upb_fielddef_containingoneof(field) || !upb_fielddef_isseq(field) || + upb_fielddef_ismap(field)) { + continue; + } + + layout->fields[upb_fielddef_index(field)].offset = off; + off += sizeof(VALUE); + layout->repeated_count++; + } + + // Place all VALUE fields for map 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); + if (upb_fielddef_containingoneof(field) || !upb_fielddef_isseq(field) || + !upb_fielddef_ismap(field)) { + continue; + } + + layout->fields[upb_fielddef_index(field)].offset = off; + off += sizeof(VALUE); + layout->map_count++; + } + + layout->value_count = layout->repeated_count + layout->map_count; + + // Next place all other (non-oneof) VALUE 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); + if (upb_fielddef_containingoneof(field) || !is_value_field(field) || + upb_fielddef_isseq(field)) { continue; } @@ -909,7 +944,19 @@ void layout_set(MessageLayout* layout, } void layout_init(MessageLayout* layout, void* storage) { + VALUE* value = (VALUE*)CHARPTR_AT(storage, layout->value_offset); + int i; + memcpy(storage, layout->empty_template, layout->size); + + for (i = 0; i < layout->repeated_count; i++, value++) { + *value = RepeatedField_new_this_type(*value); + } + + for (i = 0; i < layout->map_count; i++, value++) { + *value = Map_new_this_type(*value); + } + /* upb_msg_field_iter it; for (upb_msg_field_begin(&it, layout->msgdef);