e41f67
commit 6d1ca6737f31b2e24664a093f1827dd74a121a9f
e41f67
Author: Jarek Prokop <jprokop@redhat.com>
e41f67
Date:   Thu May 26 11:28:13 2022 +0200
e41f67
e41f67
    Gc ppc64le fix
e41f67
e41f67
diff --git a/gc.c b/gc.c
e41f67
index ef9327df1f..1c35856c44 100644
e41f67
--- a/gc.c
e41f67
+++ b/gc.c
e41f67
@@ -9421,6 +9421,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t slot_size)
e41f67
     return (VALUE)src;
e41f67
 }
e41f67
 
e41f67
+#if GC_COMPACTION_SUPPORTED
e41f67
 static int
e41f67
 compare_free_slots(const void *left, const void *right, void *dummy)
e41f67
 {
e41f67
@@ -9468,6 +9469,7 @@ gc_sort_heap_by_empty_slots(rb_objspace_t *objspace)
e41f67
         free(page_list);
e41f67
     }
e41f67
 }
e41f67
+#endif
e41f67
 
e41f67
 static void
e41f67
 gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
e41f67
@@ -10147,8 +10149,21 @@ gc_update_references(rb_objspace_t *objspace)
e41f67
     gc_update_table_refs(objspace, finalizer_table);
e41f67
 }
e41f67
 
e41f67
+#if GC_COMPACTION_SUPPORTED
e41f67
+/*
e41f67
+ *  call-seq:
e41f67
+ *     GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}}
e41f67
+ *
e41f67
+ *  Returns information about object moved in the most recent GC compaction.
e41f67
+ *
e41f67
+ * The returned hash has two keys :considered and :moved.  The hash for
e41f67
+ * :considered lists the number of objects that were considered for movement
e41f67
+ * by the compactor, and the :moved hash lists the number of objects that
e41f67
+ * were actually moved.  Some objects can't be moved (maybe they were pinned)
e41f67
+ * so these numbers can be used to calculate compaction efficiency.
e41f67
+ */
e41f67
 static VALUE
e41f67
-gc_compact_stats(rb_execution_context_t *ec, VALUE self)
e41f67
+gc_compact_stats(VALUE self)
e41f67
 {
e41f67
     size_t i;
e41f67
     rb_objspace_t *objspace = &rb_objspace;
e41f67
@@ -10171,7 +10186,11 @@ gc_compact_stats(rb_execution_context_t *ec, VALUE self)
e41f67
 
e41f67
     return h;
e41f67
 }
e41f67
+#else
e41f67
+#  define gc_compact_stats rb_f_notimplement
e41f67
+#endif
e41f67
 
e41f67
+#if GC_COMPACTION_SUPPORTED
e41f67
 static void
e41f67
 root_obj_check_moved_i(const char *category, VALUE obj, void *data)
e41f67
 {
e41f67
@@ -10221,22 +10240,78 @@ heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data)
e41f67
     return 0;
e41f67
 }
e41f67
 
e41f67
+/*
e41f67
+ *  call-seq:
e41f67
+ *     GC.compact
e41f67
+ *
e41f67
+ * This function compacts objects together in Ruby's heap.  It eliminates
e41f67
+ * unused space (or fragmentation) in the heap by moving objects in to that
e41f67
+ * unused space.  This function returns a hash which contains statistics about
e41f67
+ * which objects were moved.  See `GC.latest_gc_info` for details about
e41f67
+ * compaction statistics.
e41f67
+ *
e41f67
+ * This method is implementation specific and not expected to be implemented
e41f67
+ * in any implementation besides MRI.
e41f67
+ *
e41f67
+ * To test whether GC compaction is supported, use the idiom:
e41f67
+ *
e41f67
+ *   GC.respond_to?(:compact)
e41f67
+ */
e41f67
 static VALUE
e41f67
-gc_compact(rb_execution_context_t *ec, VALUE self)
e41f67
+gc_compact(VALUE self)
e41f67
 {
e41f67
     /* Run GC with compaction enabled */
e41f67
-    gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qtrue);
e41f67
+    gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue);
e41f67
 
e41f67
-    return gc_compact_stats(ec, self);
e41f67
+    return gc_compact_stats(self);
e41f67
 }
e41f67
+#else
e41f67
+#  define gc_compact rb_f_notimplement
e41f67
+#endif
e41f67
 
e41f67
+#if GC_COMPACTION_SUPPORTED
e41f67
+/*
e41f67
+ * call-seq:
e41f67
+ *    GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
e41f67
+ *
e41f67
+ * Verify compaction reference consistency.
e41f67
+ *
e41f67
+ * This method is implementation specific.  During compaction, objects that
e41f67
+ * were moved are replaced with T_MOVED objects.  No object should have a
e41f67
+ * reference to a T_MOVED object after compaction.
e41f67
+ *
e41f67
+ * This function doubles the heap to ensure room to move all objects,
e41f67
+ * compacts the heap to make sure everything moves, updates all references,
e41f67
+ * then performs a full GC.  If any object contains a reference to a T_MOVED
e41f67
+ * object, that object should be pushed on the mark stack, and will
e41f67
+ * make a SEGV.
e41f67
+ */
e41f67
 static VALUE
e41f67
-gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE double_heap, VALUE toward_empty)
e41f67
+gc_verify_compaction_references(int argc, VALUE *argv, VALUE self)
e41f67
 {
e41f67
     rb_objspace_t *objspace = &rb_objspace;
e41f67
+    VALUE kwargs, double_heap = Qfalse, toward_empty = Qfalse;
e41f67
+    static ID id_toward, id_double_heap, id_empty;
e41f67
+
e41f67
+    if (!id_toward) {
e41f67
+        id_toward = rb_intern("toward");
e41f67
+        id_double_heap = rb_intern("double_heap");
e41f67
+        id_empty = rb_intern("empty");
e41f67
+    }
e41f67
+
e41f67
+    rb_scan_args(argc, argv, ":", &kwargs);
e41f67
+    if (!NIL_P(kwargs)) {
e41f67
+        if (rb_hash_has_key(kwargs, ID2SYM(id_toward))) {
e41f67
+            VALUE toward = rb_hash_aref(kwargs, ID2SYM(id_toward));
e41f67
+            toward_empty = (toward == ID2SYM(id_empty)) ? Qtrue : Qfalse;
e41f67
+        }
e41f67
+        if (rb_hash_has_key(kwargs, ID2SYM(id_double_heap))) {
e41f67
+            double_heap = rb_hash_aref(kwargs, ID2SYM(id_double_heap));
e41f67
+        }
e41f67
+    }
e41f67
 
e41f67
     /* Clear the heap. */
e41f67
-    gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qfalse);
e41f67
+    gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qfalse);
e41f67
 
e41f67
     RB_VM_LOCK_ENTER();
e41f67
     {
e41f67
@@ -10256,13 +10331,16 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do
e41f67
     }
e41f67
     RB_VM_LOCK_LEAVE();
e41f67
 
e41f67
-    gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qtrue);
e41f67
+    gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue);
e41f67
 
e41f67
     objspace_reachable_objects_from_root(objspace, root_obj_check_moved_i, NULL);
e41f67
     objspace_each_objects(objspace, heap_check_moved_i, NULL, TRUE);
e41f67
 
e41f67
-    return gc_compact_stats(ec, self);
e41f67
+    return gc_compact_stats(self);
e41f67
 }
e41f67
+#else
e41f67
+#  define gc_verify_compaction_references rb_f_notimplement
e41f67
+#endif
e41f67
 
e41f67
 VALUE
e41f67
 rb_gc_start(void)
e41f67
@@ -10722,26 +10800,45 @@ gc_disable(rb_execution_context_t *ec, VALUE _)
e41f67
     return rb_gc_disable();
e41f67
 }
e41f67
 
e41f67
+#if GC_COMPACTION_SUPPORTED
e41f67
+/*
e41f67
+ *  call-seq:
e41f67
+ *     GC.auto_compact = flag
e41f67
+ *
e41f67
+ *  Updates automatic compaction mode.
e41f67
+ *
e41f67
+ *  When enabled, the compactor will execute on every major collection.
e41f67
+ *
e41f67
+ *  Enabling compaction will degrade performance on major collections.
e41f67
+ */
e41f67
 static VALUE
e41f67
-gc_set_auto_compact(rb_execution_context_t *ec, VALUE _, VALUE v)
e41f67
+gc_set_auto_compact(VALUE _, VALUE v)
e41f67
 {
e41f67
     /* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for
e41f67
      * the read barrier, so we must disable automatic compaction. */
e41f67
-#if !defined(__MINGW32__) && !defined(_WIN32)
e41f67
-    if (!USE_MMAP_ALIGNED_ALLOC) {
e41f67
-        rb_raise(rb_eNotImpError, "Automatic compaction isn't available on this platform");
e41f67
-    }
e41f67
-#endif
e41f67
 
e41f67
     ruby_enable_autocompact = RTEST(v);
e41f67
     return v;
e41f67
 }
e41f67
+#else
e41f67
+#  define gc_set_auto_compact rb_f_notimplement
e41f67
+#endif
e41f67
 
e41f67
+#if GC_COMPACTION_SUPPORTED
e41f67
+/*
e41f67
+ *  call-seq:
e41f67
+ *     GC.auto_compact    -> true or false
e41f67
+ *
e41f67
+ *  Returns whether or not automatic compaction has been enabled.
e41f67
+ */
e41f67
 static VALUE
e41f67
-gc_get_auto_compact(rb_execution_context_t *ec, VALUE _)
e41f67
+gc_get_auto_compact(VALUE _)
e41f67
 {
e41f67
     return RBOOL(ruby_enable_autocompact);
e41f67
 }
e41f67
+#else
e41f67
+#  define gc_get_auto_compact rb_f_notimplement
e41f67
+#endif
e41f67
 
e41f67
 static int
e41f67
 get_envparam_size(const char *name, size_t *default_value, size_t lower_bound)
e41f67
@@ -13599,6 +13696,11 @@ Init_GC(void)
e41f67
     rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
e41f67
     rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
e41f67
 #endif
e41f67
+    rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0);
e41f67
+    rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0);
e41f67
+    rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1);
e41f67
+    rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0);
e41f67
+    rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1);
e41f67
 
e41f67
 #if GC_DEBUG_STRESS_TO_CLASS
e41f67
     rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1);
e41f67
diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb
e41f67
index 42ad028530..411d5eab69 100644
e41f67
--- a/test/ruby/test_gc_compact.rb
e41f67
+++ b/test/ruby/test_gc_compact.rb
e41f67
@@ -9,14 +9,7 @@
e41f67
 end
e41f67
 
e41f67
 class TestGCCompact < Test::Unit::TestCase
e41f67
-  module SupportsCompact
e41f67
-    def setup
e41f67
-      skip "autocompact not supported on this platform" unless supports_auto_compact?
e41f67
-      super
e41f67
-    end
e41f67
-
e41f67
-    private
e41f67
-
e41f67
+  module CompactionSupportInspector
e41f67
     def supports_auto_compact?
e41f67
       return true unless defined?(Etc::SC_PAGE_SIZE)
e41f67
 
e41f67
@@ -30,10 +23,19 @@ def supports_auto_compact?
e41f67
     end
e41f67
   end
e41f67
 
e41f67
-  include SupportsCompact
e41f67
+  module OmitUnlessCompactSupported
e41f67
+    include CompactionSupportInspector
e41f67
+
e41f67
+    def setup
e41f67
+      omit "autocompact not supported on this platform" unless supports_auto_compact?
e41f67
+      super
e41f67
+    end
e41f67
+  end
e41f67
+
e41f67
+  include OmitUnlessCompactSupported
e41f67
 
e41f67
   class AutoCompact < Test::Unit::TestCase
e41f67
-    include SupportsCompact
e41f67
+    include OmitUnlessCompactSupported
e41f67
 
e41f67
     def test_enable_autocompact
e41f67
       before = GC.auto_compact
e41f67
@@ -87,13 +89,39 @@ def test_implicit_compaction_does_something
e41f67
     end
e41f67
   end
e41f67
 
e41f67
-  def os_page_size
e41f67
-    return true unless defined?(Etc::SC_PAGE_SIZE)
e41f67
+  class CompactMethodsNotImplemented < Test::Unit::TestCase
e41f67
+    include CompactionSupportInspector
e41f67
+
e41f67
+    def assert_not_implemented(method, *args)
e41f67
+      omit "autocompact is supported on this platform" if supports_auto_compact?
e41f67
+
e41f67
+      assert_raise(NotImplementedError) { GC.send(method, *args) }
e41f67
+      refute(GC.respond_to?(method), "GC.#{method} should be defined as rb_f_notimplement")
e41f67
+    end
e41f67
+
e41f67
+    def test_gc_compact_not_implemented
e41f67
+      assert_not_implemented(:compact)
e41f67
+    end
e41f67
+
e41f67
+    def test_gc_auto_compact_get_not_implemented
e41f67
+      assert_not_implemented(:auto_compact)
e41f67
+    end
e41f67
+
e41f67
+    def test_gc_auto_compact_set_not_implemented
e41f67
+      assert_not_implemented(:auto_compact=, true)
e41f67
+    end
e41f67
+
e41f67
+    def test_gc_latest_compact_info_not_implemented
e41f67
+      assert_not_implemented(:latest_compact_info)
e41f67
+    end
e41f67
+
e41f67
+    def test_gc_verify_compaction_references_not_implemented
e41f67
+      assert_not_implemented(:verify_compaction_references)
e41f67
+    end
e41f67
   end
e41f67
 
e41f67
-  def setup
e41f67
-    skip "autocompact not supported on this platform" unless supports_auto_compact?
e41f67
-    super
e41f67
+  def os_page_size
e41f67
+    return true unless defined?(Etc::SC_PAGE_SIZE)
e41f67
   end
e41f67
 
e41f67
   def test_gc_compact_stats
e41f67
diff --git a/gc.rb b/gc.rb
e41f67
index 72637f3796..9265dd7b57 100644
e41f67
--- a/gc.rb
e41f67
+++ b/gc.rb
e41f67
@@ -38,27 +38,6 @@ def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
e41f67
     Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
e41f67
   end
e41f67
e41f67
-  #  call-seq:
e41f67
-  #     GC.auto_compact    -> true or false
e41f67
-  #
e41f67
-  #  Returns whether or not automatic compaction has been enabled.
e41f67
-  #
e41f67
-  def self.auto_compact
e41f67
-    Primitive.gc_get_auto_compact
e41f67
-  end
e41f67
-
e41f67
-  #  call-seq:
e41f67
-  #     GC.auto_compact = flag
e41f67
-  #
e41f67
-  #  Updates automatic compaction mode.
e41f67
-  #
e41f67
-  #  When enabled, the compactor will execute on every major collection.
e41f67
-  #
e41f67
-  #  Enabling compaction will degrade performance on major collections.
e41f67
-  def self.auto_compact=(flag)
e41f67
-    Primitive.gc_set_auto_compact(flag)
e41f67
-  end
e41f67
-
e41f67
   #  call-seq:
e41f67
   #     GC.enable    -> true or false
e41f67
   #
e41f67
@@ -210,53 +189,6 @@ def self.latest_gc_info hash_or_key = nil
e41f67
     Primitive.gc_latest_gc_info hash_or_key
e41f67
   end
e41f67
e41f67
-  #  call-seq:
e41f67
-  #     GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}}
e41f67
-  #
e41f67
-  #  Returns information about object moved in the most recent GC compaction.
e41f67
-  #
e41f67
-  # The returned hash has two keys :considered and :moved.  The hash for
e41f67
-  # :considered lists the number of objects that were considered for movement
e41f67
-  # by the compactor, and the :moved hash lists the number of objects that
e41f67
-  # were actually moved.  Some objects can't be moved (maybe they were pinned)
e41f67
-  # so these numbers can be used to calculate compaction efficiency.
e41f67
-  def self.latest_compact_info
e41f67
-    Primitive.gc_compact_stats
e41f67
-  end
e41f67
-
e41f67
-  #  call-seq:
e41f67
-  #     GC.compact
e41f67
-  #
e41f67
-  # This function compacts objects together in Ruby's heap.  It eliminates
e41f67
-  # unused space (or fragmentation) in the heap by moving objects in to that
e41f67
-  # unused space.  This function returns a hash which contains statistics about
e41f67
-  # which objects were moved.  See `GC.latest_gc_info` for details about
e41f67
-  # compaction statistics.
e41f67
-  #
e41f67
-  # This method is implementation specific and not expected to be implemented
e41f67
-  # in any implementation besides MRI.
e41f67
-  def self.compact
e41f67
-    Primitive.gc_compact
e41f67
-  end
e41f67
-
e41f67
-  # call-seq:
e41f67
-  #    GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
e41f67
-  #
e41f67
-  # Verify compaction reference consistency.
e41f67
-  #
e41f67
-  # This method is implementation specific.  During compaction, objects that
e41f67
-  # were moved are replaced with T_MOVED objects.  No object should have a
e41f67
-  # reference to a T_MOVED object after compaction.
e41f67
-  #
e41f67
-  # This function doubles the heap to ensure room to move all objects,
e41f67
-  # compacts the heap to make sure everything moves, updates all references,
e41f67
-  # then performs a full GC.  If any object contains a reference to a T_MOVED
e41f67
-  # object, that object should be pushed on the mark stack, and will
e41f67
-  # make a SEGV.
e41f67
-  def self.verify_compaction_references(toward: nil, double_heap: false)
e41f67
-    Primitive.gc_verify_compaction_references(double_heap, toward == :empty)
e41f67
-  end
e41f67
-
e41f67
   # call-seq:
e41f67
   #     GC.using_rvargc? -> true or false
e41f67
   #