Skip to content

Commit d2d49bf

Browse files
authored
Merge pull request #6547 from haberman/layout_clear
Optimization for layout_init()
2 parents 84241c6 + 671c245 commit d2d49bf

File tree

7 files changed

+82
-27
lines changed

7 files changed

+82
-27
lines changed

ruby/ext/google/protobuf_c/defs.c

+3
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,9 @@ void Descriptor_mark(void* _self) {
487487
Descriptor* self = _self;
488488
rb_gc_mark(self->klass);
489489
rb_gc_mark(self->descriptor_pool);
490+
if (self->layout && self->layout->empty_template) {
491+
layout_mark(self->layout, self->layout->empty_template);
492+
}
490493
}
491494

492495
void Descriptor_free(void* _self) {

ruby/ext/google/protobuf_c/encode_decode.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ void add_handlers_for_message(const void *closure, upb_handlers *h) {
696696
// class is actually built, so to work around this, we just create the layout
697697
// (and handlers, in the class-building function) on-demand.
698698
if (desc->layout == NULL) {
699-
desc->layout = create_layout(desc);
699+
create_layout(desc);
700700
}
701701

702702
// If this is a mapentry message type, set up a special set of handlers and

ruby/ext/google/protobuf_c/map.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ VALUE Map_length(VALUE _self) {
495495
return ULL2NUM(upb_strtable_count(&self->table));
496496
}
497497

498-
static VALUE Map_new_this_type(VALUE _self) {
498+
VALUE Map_new_this_type(VALUE _self) {
499499
Map* self = ruby_to_Map(_self);
500500
VALUE new_map = Qnil;
501501
VALUE key_type = fieldtype_to_ruby(self->key_type);

ruby/ext/google/protobuf_c/message.c

+10-12
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,19 @@ VALUE Message_alloc(VALUE klass) {
6262
Descriptor* desc = ruby_to_Descriptor(descriptor);
6363
MessageHeader* msg;
6464
VALUE ret;
65+
size_t size;
6566

6667
if (desc->layout == NULL) {
67-
desc->layout = create_layout(desc);
68+
create_layout(desc);
6869
}
6970

70-
msg = (MessageHeader*)ALLOC_N(uint8_t,
71-
sizeof(MessageHeader) + desc->layout->size);
72-
73-
memset(Message_data(msg), 0, desc->layout->size);
74-
75-
// We wrap first so that everything in the message object is GC-rooted in case
76-
// a collection happens during object creation in layout_init().
77-
ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
71+
msg = ALLOC_N(uint8_t, sizeof(MessageHeader) + desc->layout->size);
7872
msg->descriptor = desc;
79-
rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
80-
8173
msg->unknown_fields = NULL;
74+
memcpy(Message_data(msg), desc->layout->empty_template, desc->layout->size);
8275

83-
layout_init(desc->layout, Message_data(msg));
76+
ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
77+
rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
8478

8579
return ret;
8680
}
@@ -472,7 +466,11 @@ int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
472466
* Message class are provided on each concrete message class.
473467
*/
474468
VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
469+
MessageHeader* self;
475470
VALUE hash_args;
471+
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
472+
473+
layout_init(self->descriptor->layout, Message_data(self));
476474

477475
if (argc == 0) {
478476
return Qnil;

ruby/ext/google/protobuf_c/protobuf.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ extern VALUE cRepeatedField;
419419

420420
RepeatedField* ruby_to_RepeatedField(VALUE value);
421421

422+
VALUE RepeatedField_new_this_type(VALUE _self);
422423
VALUE RepeatedField_each(VALUE _self);
423424
VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self);
424425
void* RepeatedField_index_native(VALUE _self, int index);
@@ -467,6 +468,7 @@ extern VALUE cMap;
467468

468469
Map* ruby_to_Map(VALUE value);
469470

471+
VALUE Map_new_this_type(VALUE _self);
470472
VALUE Map_each(VALUE _self);
471473
VALUE Map_keys(VALUE _self);
472474
VALUE Map_values(VALUE _self);
@@ -516,16 +518,19 @@ struct MessageOneof {
516518
struct MessageLayout {
517519
const Descriptor* desc;
518520
const upb_msgdef* msgdef;
521+
void* empty_template; // Can memcpy() onto a layout to clear it.
519522
MessageField* fields;
520523
MessageOneof* oneofs;
521524
uint32_t size;
522525
uint32_t value_offset;
523526
int value_count;
527+
int repeated_count;
528+
int map_count;
524529
};
525530

526531
#define ONEOF_CASE_MASK 0x80000000
527532

528-
MessageLayout* create_layout(const Descriptor* desc);
533+
void create_layout(Descriptor* desc);
529534
void free_layout(MessageLayout* layout);
530535
bool field_contains_hasbit(MessageLayout* layout,
531536
const upb_fielddef* field);

ruby/ext/google/protobuf_c/repeated_field.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ VALUE RepeatedField_length(VALUE _self) {
323323
return INT2NUM(self->size);
324324
}
325325

326-
static VALUE RepeatedField_new_this_type(VALUE _self) {
326+
VALUE RepeatedField_new_this_type(VALUE _self) {
327327
RepeatedField* self = ruby_to_RepeatedField(_self);
328328
VALUE new_rptfield = Qnil;
329329
VALUE element_type = fieldtype_to_ruby(self->field_type);

ruby/ext/google/protobuf_c/storage.c

+60-11
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ bool is_value_field(const upb_fielddef* f) {
478478
upb_fielddef_isstring(f);
479479
}
480480

481-
MessageLayout* create_layout(const Descriptor* desc) {
481+
void create_layout(Descriptor* desc) {
482482
const upb_msgdef *msgdef = desc->msgdef;
483483
MessageLayout* layout = ALLOC(MessageLayout);
484484
int nfields = upb_msgdef_numfields(msgdef);
@@ -488,7 +488,10 @@ MessageLayout* create_layout(const Descriptor* desc) {
488488
size_t off = 0;
489489
size_t hasbit = 0;
490490

491+
layout->empty_template = NULL;
491492
layout->desc = desc;
493+
desc->layout = layout;
494+
492495
layout->fields = ALLOC_N(MessageField, nfields);
493496
layout->oneofs = NULL;
494497

@@ -514,14 +517,49 @@ MessageLayout* create_layout(const Descriptor* desc) {
514517

515518
off = align_up_to(off, sizeof(VALUE));
516519
layout->value_offset = off;
520+
layout->repeated_count = 0;
521+
layout->map_count = 0;
517522
layout->value_count = 0;
518523

519-
// Place all (non-oneof) VALUE fields first.
524+
// Place all VALUE fields for repeated fields.
525+
for (upb_msg_field_begin(&it, msgdef);
526+
!upb_msg_field_done(&it);
527+
upb_msg_field_next(&it)) {
528+
const upb_fielddef* field = upb_msg_iter_field(&it);
529+
if (upb_fielddef_containingoneof(field) || !upb_fielddef_isseq(field) ||
530+
upb_fielddef_ismap(field)) {
531+
continue;
532+
}
533+
534+
layout->fields[upb_fielddef_index(field)].offset = off;
535+
off += sizeof(VALUE);
536+
layout->repeated_count++;
537+
}
538+
539+
// Place all VALUE fields for map fields.
540+
for (upb_msg_field_begin(&it, msgdef);
541+
!upb_msg_field_done(&it);
542+
upb_msg_field_next(&it)) {
543+
const upb_fielddef* field = upb_msg_iter_field(&it);
544+
if (upb_fielddef_containingoneof(field) || !upb_fielddef_isseq(field) ||
545+
!upb_fielddef_ismap(field)) {
546+
continue;
547+
}
548+
549+
layout->fields[upb_fielddef_index(field)].offset = off;
550+
off += sizeof(VALUE);
551+
layout->map_count++;
552+
}
553+
554+
layout->value_count = layout->repeated_count + layout->map_count;
555+
556+
// Next place all other (non-oneof) VALUE fields.
520557
for (upb_msg_field_begin(&it, msgdef);
521558
!upb_msg_field_done(&it);
522559
upb_msg_field_next(&it)) {
523560
const upb_fielddef* field = upb_msg_iter_field(&it);
524-
if (upb_fielddef_containingoneof(field) || !is_value_field(field)) {
561+
if (upb_fielddef_containingoneof(field) || !is_value_field(field) ||
562+
upb_fielddef_isseq(field)) {
525563
continue;
526564
}
527565

@@ -600,10 +638,19 @@ MessageLayout* create_layout(const Descriptor* desc) {
600638
layout->size = off;
601639
layout->msgdef = msgdef;
602640

603-
return layout;
641+
// Create the empty message template.
642+
layout->empty_template = ALLOC_N(char, layout->size);
643+
memset(layout->empty_template, 0, layout->size);
644+
645+
for (upb_msg_field_begin(&it, layout->msgdef);
646+
!upb_msg_field_done(&it);
647+
upb_msg_field_next(&it)) {
648+
layout_clear(layout, layout->empty_template, upb_msg_iter_field(&it));
649+
}
604650
}
605651

606652
void free_layout(MessageLayout* layout) {
653+
xfree(layout->empty_template);
607654
xfree(layout->fields);
608655
xfree(layout->oneofs);
609656
xfree(layout);
@@ -896,14 +943,16 @@ void layout_set(MessageLayout* layout,
896943
}
897944
}
898945

899-
void layout_init(MessageLayout* layout,
900-
void* storage) {
946+
void layout_init(MessageLayout* layout, void* storage) {
947+
VALUE* value = (VALUE*)CHARPTR_AT(storage, layout->value_offset);
948+
int i;
901949

902-
upb_msg_field_iter it;
903-
for (upb_msg_field_begin(&it, layout->msgdef);
904-
!upb_msg_field_done(&it);
905-
upb_msg_field_next(&it)) {
906-
layout_clear(layout, storage, upb_msg_iter_field(&it));
950+
for (i = 0; i < layout->repeated_count; i++, value++) {
951+
*value = RepeatedField_new_this_type(*value);
952+
}
953+
954+
for (i = 0; i < layout->map_count; i++, value++) {
955+
*value = Map_new_this_type(*value);
907956
}
908957
}
909958

0 commit comments

Comments
 (0)