diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c index 77ef5e5540..63dac7fe1f 100644 --- a/ruby/ext/google/protobuf_c/defs.c +++ b/ruby/ext/google/protobuf_c/defs.c @@ -487,6 +487,9 @@ void Descriptor_mark(void* _self) { Descriptor* self = _self; rb_gc_mark(self->klass); rb_gc_mark(self->descriptor_pool); + if (self->layout && self->layout->empty_template) { + layout_mark(self->layout, self->layout->empty_template); + } } void Descriptor_free(void* _self) { diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c index ad8205fea7..3bf6b924d9 100644 --- a/ruby/ext/google/protobuf_c/encode_decode.c +++ b/ruby/ext/google/protobuf_c/encode_decode.c @@ -690,7 +690,7 @@ void add_handlers_for_message(const void *closure, upb_handlers *h) { // class is actually built, so to work around this, we just create the layout // (and handlers, in the class-building function) on-demand. if (desc->layout == NULL) { - desc->layout = create_layout(desc); + create_layout(desc); } // If this is a mapentry message type, set up a special set of handlers and diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index dfe24c847e..5b64374cdb 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -64,7 +64,7 @@ VALUE Message_alloc(VALUE klass) { VALUE ret; if (desc->layout == NULL) { - desc->layout = create_layout(desc); + create_layout(desc); } msg = (MessageHeader*)ALLOC_N(uint8_t, diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h index b9d1e5a102..84e9e7fd2f 100644 --- a/ruby/ext/google/protobuf_c/protobuf.h +++ b/ruby/ext/google/protobuf_c/protobuf.h @@ -509,11 +509,12 @@ struct MessageField { struct MessageLayout { const Descriptor* desc; const upb_msgdef* msgdef; + void* empty_template; // Can memcpy() onto a layout to clear it. MessageField* fields; size_t size; }; -MessageLayout* create_layout(const 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/storage.c b/ruby/ext/google/protobuf_c/storage.c index 7ce963d151..375b939598 100644 --- a/ruby/ext/google/protobuf_c/storage.c +++ b/ruby/ext/google/protobuf_c/storage.c @@ -473,7 +473,7 @@ static size_t align_up_to(size_t offset, size_t granularity) { return (offset + granularity - 1) & ~(granularity - 1); } -MessageLayout* create_layout(const Descriptor* desc) { +void create_layout(Descriptor* desc) { const upb_msgdef *msgdef = desc->msgdef; MessageLayout* layout = ALLOC(MessageLayout); int nfields = upb_msgdef_numfields(msgdef); @@ -482,7 +482,10 @@ MessageLayout* create_layout(const Descriptor* desc) { size_t off = 0; size_t hasbit = 0; + layout->empty_template = NULL; layout->desc = desc; + desc->layout = layout; + layout->fields = ALLOC_N(MessageField, nfields); for (upb_msg_field_begin(&it, msgdef); @@ -584,10 +587,19 @@ MessageLayout* create_layout(const Descriptor* desc) { layout->size = off; layout->msgdef = msgdef; - return layout; + // Create the empty message template. + layout->empty_template = ALLOC_N(char, layout->size); + memset(layout->empty_template, 0, layout->size); + + for (upb_msg_field_begin(&it, layout->msgdef); + !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + layout_clear(layout, layout->empty_template, upb_msg_iter_field(&it)); + } } void free_layout(MessageLayout* layout) { + xfree(layout->empty_template); xfree(layout->fields); xfree(layout); } @@ -868,15 +880,16 @@ void layout_set(MessageLayout* layout, } } -void layout_init(MessageLayout* layout, - void* storage) { - +void layout_init(MessageLayout* layout, void* storage) { + memcpy(storage, layout->empty_template, layout->size); + /* upb_msg_field_iter it; for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { layout_clear(layout, storage, upb_msg_iter_field(&it)); } + */ } void layout_mark(MessageLayout* layout, void* storage) {