ruby-changes:61302
From: Aaron <ko1@a...>
Date: Thu, 21 May 2020 03:17:05 +0900 (JST)
Subject: [ruby-changes:61302] 891e253ee7 (master): Use a pinning list for keeping objects alive during assembly.
https://git.ruby-lang.org/ruby.git/commit/?id=891e253ee7 From 891e253ee71fc5196ef4b4ba4718a16bbe858499 Mon Sep 17 00:00:00 2001 From: Aaron Patterson <tenderlove@r...> Date: Tue, 28 Jan 2020 16:33:04 -0800 Subject: Use a pinning list for keeping objects alive during assembly. The GC will not disassemble incomplete instruction sequences. So it is important that when instructions are being assembled, any objects the instructions point at should not be moved. This patch implements a fixed width array that pins its references. When the instructions are done being assembled, the pinning array goes away and the objects inside the iseqs are allowed to move. diff --git a/compile.c b/compile.c index 574354f..1159a9d 100644 --- a/compile.c +++ b/compile.c @@ -9651,6 +9651,84 @@ struct ibf_load { https://github.com/ruby/ruby/blob/trunk/compile.c#L9651 struct ibf_load_buffer *current_buffer; }; +struct pinned_list { + long size; + VALUE * buffer; +}; + +static void +pinned_list_mark(void *ptr) +{ + long i; + struct pinned_list *list = (struct pinned_list *)ptr; + for (i = 0; i < list->size; i++) { + if (list->buffer[i]) { + rb_gc_mark(list->buffer[i]); + } + } +} + +static void +pinned_list_free(void *ptr) +{ + struct pinned_list *list = (struct pinned_list *)ptr; + xfree(list->buffer); + xfree(ptr); +} + +static size_t +pinned_list_memsize(const void *ptr) +{ + struct pinned_list *list = (struct pinned_list *)ptr; + return sizeof(struct pinned_list) + (list->size * sizeof(VALUE *)); +} + +static const rb_data_type_t pinned_list_type = { + "pinned_list", + {pinned_list_mark, pinned_list_free, pinned_list_memsize,}, + 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY +}; + +static VALUE +pinned_list_fetch(VALUE list, long offset) +{ + struct pinned_list * ptr; + + TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr); + + if (offset >= ptr->size) { + rb_raise(rb_eIndexError, "object index out of range: %ld", offset); + } + + return ptr->buffer[offset]; +} + +static void +pinned_list_store(VALUE list, long offset, VALUE object) +{ + struct pinned_list * ptr; + + TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr); + + if (offset >= ptr->size) { + rb_raise(rb_eIndexError, "object index out of range: %ld", offset); + } + + RB_OBJ_WRITE(list, &ptr->buffer[offset], object); +} + +static VALUE +pinned_list_new(long size) +{ + struct pinned_list * ptr; + + ptr = xmalloc(sizeof(struct pinned_list)); + ptr->size = size; + ptr->buffer = xcalloc(size, sizeof(VALUE)); + + return TypedData_Wrap_Struct(0, &pinned_list_type, ptr); +} + static ibf_offset_t ibf_dump_pos(struct ibf_dump *dump) { @@ -10584,8 +10662,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset) https://github.com/ruby/ruby/blob/trunk/compile.c#L10662 buffer.size = iseq_length_bytes; buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos); buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos); - buffer.obj_list = rb_ary_tmp_new(buffer.obj_list_size); - rb_ary_resize(buffer.obj_list, buffer.obj_list_size); + buffer.obj_list = pinned_list_new(buffer.obj_list_size); load->current_buffer = &buffer; reading_pos = body_offset; @@ -11352,12 +11429,9 @@ ibf_load_object(const struct ibf_load *load, VALUE object_index) https://github.com/ruby/ruby/blob/trunk/compile.c#L11429 if (object_index == 0) { return Qnil; } - else if (object_index >= (VALUE)RARRAY_LEN(load->current_buffer->obj_list)) { - rb_raise(rb_eIndexError, "object index out of range: %"PRIdVALUE, object_index); - } else { - VALUE obj = rb_ary_entry(load->current_buffer->obj_list, (long)object_index); - if (obj == Qnil) { /* TODO: avoid multiple Qnil load */ + VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index); + if (!obj) { ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff); ibf_offset_t offset = offsets[object_index]; const struct ibf_object_header header = ibf_load_object_object_header(load, &offset); @@ -11381,7 +11455,7 @@ ibf_load_object(const struct ibf_load *load, VALUE object_index) https://github.com/ruby/ruby/blob/trunk/compile.c#L11455 obj = (*load_object_functions[header.type])(load, &header, offset); } - rb_ary_store(load->current_buffer->obj_list, (long)object_index, obj); + pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj); } #if IBF_ISEQ_DEBUG fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n", @@ -11588,12 +11662,12 @@ ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq) https://github.com/ruby/ruby/blob/trunk/compile.c#L11662 return NULL; } else { - VALUE iseqv = rb_ary_entry(load->iseq_list, iseq_index); + VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index); #if IBF_ISEQ_DEBUG fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv); #endif - if (iseqv != Qnil) { + if (iseqv) { return (rb_iseq_t *)iseqv; } else { @@ -11608,7 +11682,7 @@ ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq) https://github.com/ruby/ruby/blob/trunk/compile.c#L11682 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n", (void *)iseq, (void *)load->loader_obj, iseq_index); #endif - rb_ary_store(load->iseq_list, iseq_index, (VALUE)iseq); + pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq); #if !USE_LAZY_LOAD #if IBF_ISEQ_DEBUG @@ -11639,9 +11713,8 @@ ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, https://github.com/ruby/ruby/blob/trunk/compile.c#L11713 load->global_buffer.size = load->header->size; load->global_buffer.obj_list_offset = load->header->global_object_list_offset; load->global_buffer.obj_list_size = load->header->global_object_list_size; - RB_OBJ_WRITE(loader_obj, &load->iseq_list, rb_ary_tmp_new(0)); - RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, rb_ary_tmp_new(load->global_buffer.obj_list_size)); - rb_ary_resize(load->global_buffer.obj_list, load->global_buffer.obj_list_size); + RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(load->header->iseq_list_size)); + RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size)); load->iseq = NULL; load->current_buffer = &load->global_buffer; -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/