summaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
authorAaron Patterson <tenderlove@ruby-lang.org>2020-01-28 16:33:04 -0800
committerAaron Patterson <tenderlove@ruby-lang.org>2020-05-20 11:16:21 -0700
commit891e253ee71fc5196ef4b4ba4718a16bbe858499 (patch)
treed7f96a43446910d921632b144a38e454208bcb4d /compile.c
parentff58cbce94aaa001a262e6a4abc57f85113331be (diff)
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.
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c101
1 files changed, 87 insertions, 14 deletions
diff --git a/compile.c b/compile.c
index 574354f893..1159a9d21e 100644
--- a/compile.c
+++ b/compile.c
@@ -9651,6 +9651,84 @@ struct ibf_load {
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)
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)
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)
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)
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)
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,
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;