Skip to content

Commit

Permalink
Pin array buffer in RARRAY_PTR_USE
Browse files Browse the repository at this point in the history
This prevents the underlying buffer from being moved by the GC when the
pointer to the buffer is passed to native C code unaware of object
movement (such as `qsort_r`).
  • Loading branch information
wks committed Sep 22, 2023
1 parent c56f215 commit d82b82e
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 0 deletions.
24 changes: 24 additions & 0 deletions include/ruby/internal/core/rarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,13 +320,37 @@ rb_array_const_ptr(VALUE a)
* This is an implementation detail of #RARRAY_PTR_USE. People do not use it
* directly.
*/
#if USE_MMTK
// Defined in mmtk_support.c
bool rb_mmtk_enabled_p(void);
void rb_mmtk_pin_array_buffer(VALUE array, volatile VALUE *stack_slot);

// When using MMTk, we need to pin the underlying buffer if the array is not embedded becuase the
// buffer is in the GC heap. Otherwise, if C calls back to Ruby, and Ruby triggers GCm and GC
// moves the array buffer, the C function will be operating on the old address of the buffer.
#define RBIMPL_RARRAY_STMT(ary, var, expr) do { \
RBIMPL_ASSERT_TYPE((ary), RUBY_T_ARRAY); \
const VALUE rbimpl_ary = (ary); \
volatile VALUE rb_mmtk_impl_pinned; \
if (rb_mmtk_enabled_p()) { \
rb_mmtk_pin_array_buffer(ary, &rb_mmtk_impl_pinned); \
} else { \
rb_mmtk_impl_pinned = 0; \
} \
VALUE *var = rb_ary_ptr_use_start(rbimpl_ary); \
expr; \
rb_ary_ptr_use_end(rbimpl_ary); \
rb_mmtk_impl_pinned = 0; \
} while (0)
#else
#define RBIMPL_RARRAY_STMT(ary, var, expr) do { \
RBIMPL_ASSERT_TYPE((ary), RUBY_T_ARRAY); \
const VALUE rbimpl_ary = (ary); \
VALUE *var = rb_ary_ptr_use_start(rbimpl_ary); \
expr; \
rb_ary_ptr_use_end(rbimpl_ary); \
} while (0)
#endif

/**
* Declares a section of code where raw pointers are used. In case you need to
Expand Down
4 changes: 4 additions & 0 deletions internal/mmtk_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ void rb_mmtk_scan_offsetted_strbuf_field(char** field, bool update);
rb_mmtk_objbuf_t* rb_mmtk_new_objbuf(size_t capa);
VALUE* rb_mmtk_objbuf_to_elems(rb_mmtk_objbuf_t* objbuf);

// Object pinning

void rb_mmtk_pin_array_buffer(VALUE array, volatile VALUE *stack_slot);

// MMTk-specific Ruby module (GC::MMTk)
void rb_mmtk_define_gc_mmtk_module(void);
VALUE rb_mmtk_plan_name(VALUE _);
Expand Down
18 changes: 18 additions & 0 deletions mmtk_support.c
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,24 @@ rb_mmtk_objbuf_to_elems(rb_mmtk_objbuf_t* objbuf)
return objbuf->ary;
}

////////////////////////////////////////////////////////////////////////////////
// Object pinning
////////////////////////////////////////////////////////////////////////////////

// Temporarily pin the buffer of an array so that it can be passed to native functions which are
// not aware of object movement.
void
rb_mmtk_pin_array_buffer(VALUE array, volatile VALUE *stack_slot)
{
// We store the reference into the given stack slot so that the conservative stack scanner can
// pick it up.
if (ARY_EMBED_P(array)) {
*stack_slot = array;
} else {
*stack_slot = RARRAY_EXT(array)->objbuf;
}
}

////////////////////////////////////////////////////////////////////////////////
// MMTk-specific Ruby module (GC::MMTk)
////////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit d82b82e

Please sign in to comment.