Skip to content

Commit

Permalink
Mark iseq structs with rb_gc_mark_movable
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
gmcgibbon and peterzhu2118 committed Mar 25, 2024
1 parent 5526471 commit a31ca35
Showing 1 changed file with 21 additions and 9 deletions.
30 changes: 21 additions & 9 deletions iseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit a31ca35

Please sign in to comment.