Mark iseq structs with rb_gc_mark_movable

Using rb_gc_mark_movable and a reference update function, we can make
instruction sequences movable in memory, and avoid pinning compiled iseqs.

```
require "objspace"
iseqs = []
GC.disable
50_000.times do
  iseqs << RubyVM::InstructionSequence.compile("")
end
GC.enable
GC.compact
p ObjectSpace.dump_all(output: :string).lines.grep(/"pinned":true/).count
```

Co-authored-by: Peter Zhu <peter@peterzhu.ca>
This commit is contained in:
Gannon McGibbon 2024-03-22 15:38:28 -05:00 коммит произвёл Peter Zhu
Родитель 552647175e
Коммит a31ca3500d
1 изменённых файлов: 21 добавлений и 9 удалений

30
iseq.c
Просмотреть файл

@ -1386,18 +1386,30 @@ rb_iseq_remove_coverage_all(void)
static void
iseqw_mark(void *ptr)
{
rb_gc_mark((VALUE)ptr);
rb_gc_mark_movable(*(VALUE *)ptr);
}
static size_t
iseqw_memsize(const void *ptr)
{
return rb_iseq_memsize((const rb_iseq_t *)ptr);
return rb_iseq_memsize(*(const rb_iseq_t **)ptr);
}
static void
iseqw_ref_update(void *ptr)
{
VALUE *vptr = ptr;
*vptr = rb_gc_location(*vptr);
}
static const rb_data_type_t iseqw_data_type = {
"T_IMEMO/iseq",
{iseqw_mark, NULL, iseqw_memsize,},
{
iseqw_mark,
RUBY_TYPED_DEFAULT_FREE,
iseqw_memsize,
iseqw_ref_update,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};
@ -1408,11 +1420,9 @@ iseqw_new(const rb_iseq_t *iseq)
return iseq->wrapper;
}
else {
union { const rb_iseq_t *in; void *out; } deconst;
VALUE obj;
deconst.in = iseq;
obj = TypedData_Wrap_Struct(rb_cISeq, &iseqw_data_type, deconst.out);
RB_OBJ_WRITTEN(obj, Qundef, iseq);
rb_iseq_t **ptr;
VALUE obj = TypedData_Make_Struct(rb_cISeq, rb_iseq_t *, &iseqw_data_type, ptr);
RB_OBJ_WRITE(obj, ptr, iseq);
/* cache a wrapper object */
RB_OBJ_WRITE((VALUE)iseq, &iseq->wrapper, obj);
@ -1736,7 +1746,9 @@ iseqw_s_compile_option_get(VALUE self)
static const rb_iseq_t *
iseqw_check(VALUE iseqw)
{
rb_iseq_t *iseq = DATA_PTR(iseqw);
rb_iseq_t **iseq_ptr;
TypedData_Get_Struct(iseqw, rb_iseq_t *, &iseqw_data_type, iseq_ptr);
rb_iseq_t *iseq = *iseq_ptr;
if (!ISEQ_BODY(iseq)) {
rb_ibf_load_iseq_complete(iseq);