diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h index aa013fdd81b730..0d7ada191d5dff 100644 --- a/include/ruby/internal/core/rarray.h +++ b/include/ruby/internal/core/rarray.h @@ -320,6 +320,29 @@ 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); \ @@ -327,6 +350,7 @@ rb_array_const_ptr(VALUE a) 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 diff --git a/internal/mmtk_support.h b/internal/mmtk_support.h index 2a30c2cabc8189..4a4dee8a3398e1 100644 --- a/internal/mmtk_support.h +++ b/internal/mmtk_support.h @@ -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 _); diff --git a/mmtk_support.c b/mmtk_support.c index ab96e37776bef3..8df0e66531de44 100644 --- a/mmtk_support.c +++ b/mmtk_support.c @@ -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) ////////////////////////////////////////////////////////////////////////////////