diff --git a/gc.c b/gc.c
index d2d7b06ab28d5f..d0016c8332208c 100644
--- a/gc.c
+++ b/gc.c
@@ -3144,6 +3144,8 @@ rb_objspace_each_objects_without_setup(each_obj_callback *callback, void *data)
struct os_each_struct {
size_t num;
VALUE of;
+ uint single_generation;
+ size_t generation;
};
static int
@@ -3195,73 +3197,44 @@ os_obj_of_i(void *vstart, void *vend, size_t stride, void *data)
RVALUE *p = (RVALUE *)vstart, *pend = (RVALUE *)vend;
for (; p != pend; p++) {
- volatile VALUE v = (VALUE)p;
- if (!internal_object_p(v)) {
- if (!oes->of || rb_obj_is_kind_of(v, oes->of)) {
- rb_yield(v);
- oes->num++;
- }
- }
+ volatile VALUE v = (VALUE)p;
+ if (internal_object_p(v)) continue;
+ if (oes->of && !rb_obj_is_kind_of(v, oes->of)) continue;
+ if (oes->single_generation) {
+ struct allocation_info *ainfo = objspace_lookup_allocation_info(v);
+ if (!ainfo || ainfo->generation != oes->generation) continue;
+ }
+
+ rb_yield(v);
+ oes->num++;
}
return 0;
}
static VALUE
-os_obj_of(VALUE of)
+os_obj_of(VALUE of, VALUE generation)
{
struct os_each_struct oes;
oes.num = 0;
- oes.of = of;
+ oes.of = NIL_P(of) ? 0 : of;
+ if (NIL_P(generation)) {
+ oes.single_generation = FALSE;
+ } else {
+ oes.single_generation = TRUE;
+ oes.generation = NUM2SIZET(generation);
+ }
+
rb_objspace_each_objects(os_obj_of_i, &oes);
return SIZET2NUM(oes.num);
}
-/*
- * call-seq:
- * ObjectSpace.each_object([module]) {|obj| ... } -> integer
- * ObjectSpace.each_object([module]) -> an_enumerator
- *
- * Calls the block once for each living, nonimmediate object in this
- * Ruby process. If module is specified, calls the block
- * for only those classes or modules that match (or are a subclass of)
- * module. Returns the number of objects found. Immediate
- * objects (Fixnum
s, Symbol
s
- * true
, false
, and nil
) are
- * never returned. In the example below, #each_object returns both
- * the numbers we defined and several constants defined in the Math
- * module.
- *
- * If no block is given, an enumerator is returned instead.
- *
- * a = 102.7
- * b = 95 # Won't be returned
- * c = 12345678987654321
- * count = ObjectSpace.each_object(Numeric) {|x| p x }
- * puts "Total count: #{count}"
- *
- * produces:
- *
- * 12345678987654321
- * 102.7
- * 2.71828182845905
- * 3.14159265358979
- * 2.22044604925031e-16
- * 1.7976931348623157e+308
- * 2.2250738585072e-308
- * Total count: 7
- *
- */
-
static VALUE
-os_each_obj(int argc, VALUE *argv, VALUE os)
+os_each_obj(rb_execution_context_t *ec, VALUE os, VALUE of, VALUE generation)
{
- VALUE of;
-
- of = (!rb_check_arity(argc, 0, 1) ? 0 : argv[0]);
- RETURN_ENUMERATOR(os, 1, &of);
- return os_obj_of(of);
+ RETURN_ENUMERATOR(os, 2, ((VALUE[]){of, generation}));
+ return os_obj_of(of, generation);
}
/*
@@ -12017,8 +11990,6 @@ Init_GC(void)
rb_mObjSpace = rb_define_module("ObjectSpace");
- rb_define_module_function(rb_mObjSpace, "each_object", os_each_obj, -1);
-
rb_define_module_function(rb_mObjSpace, "define_finalizer", define_final, -1);
rb_define_module_function(rb_mObjSpace, "undefine_finalizer", undefine_final, 1);
diff --git a/gc.rb b/gc.rb
index 8bba0dfbc9a41d..5664c3413fb767 100644
--- a/gc.rb
+++ b/gc.rb
@@ -192,4 +192,40 @@ def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
end
module_function :garbage_collect
+
+ # call-seq:
+ # ObjectSpace.each_object([module]) {|obj| ... } -> integer
+ # ObjectSpace.each_object([module]) -> an_enumerator
+ #
+ # Calls the block once for each living, nonimmediate object in this
+ # Ruby process. If module is specified, calls the block
+ # for only those classes or modules that match (or are a subclass of)
+ # module. Returns the number of objects found. Immediate
+ # objects (Fixnum
s, Symbol
s
+ # true
, false
, and nil
) are
+ # never returned. In the example below, #each_object returns both
+ # the numbers we defined and several constants defined in the Math
+ # module.
+ #
+ # If no block is given, an enumerator is returned instead.
+ #
+ # a = 102.7
+ # b = 95 # Won't be returned
+ # c = 12345678987654321
+ # count = ObjectSpace.each_object(Numeric) {|x| p x }
+ # puts "Total count: #{count}"
+ #
+ # produces:
+ #
+ # 12345678987654321
+ # 102.7
+ # 2.71828182845905
+ # 3.14159265358979
+ # 2.22044604925031e-16
+ # 1.7976931348623157e+308
+ # 2.2250738585072e-308
+ # Total count: 7
+ def self.each_object(of = nil, generation: nil)
+ Primitive.os_each_obj(of, generation)
+ end
end