summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <tenderlove@ruby-lang.org>2020-08-18 17:34:03 -0700
committerAaron Patterson <aaron.patterson@gmail.com>2020-08-18 19:10:51 -0700
commit7a58ee9b962ad0072e5213d3512c809048e4eba1 (patch)
treef74ee3e8e7b2fd2a1a3d3251a073fad008beae4f
parent371c051ca885274a9991e216b6ff6b75fb5c7ff9 (diff)
Update references when tracing allocations
The allocation tracing code keeps essentially a weak reference to objects that have been allocated (storing the allocation information along with the weak ref). Compacting the heap would break references in this weak map, so the wrong values could be returned. This commit just updates the values in the weak ref in order to fix the allocation tracing book keeping
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3429
-rw-r--r--ext/objspace/object_tracing.c80
-rw-r--r--test/objspace/test_objspace.rb2
2 files changed, 78 insertions, 4 deletions
diff --git a/ext/objspace/object_tracing.c b/ext/objspace/object_tracing.c
index a057ac2..b6ffca8 100644
--- a/ext/objspace/object_tracing.c
+++ b/ext/objspace/object_tracing.c
@@ -151,6 +151,80 @@ free_values_i(st_data_t key, st_data_t value, st_data_t data)
return ST_CONTINUE;
}
+static void
+allocation_info_tracer_mark(void *ptr)
+{
+ struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr;
+ rb_gc_mark(trace_arg->newobj_trace);
+ rb_gc_mark(trace_arg->freeobj_trace);
+}
+
+static void
+allocation_info_tracer_free(void *ptr)
+{
+ struct traceobj_arg *arg = (struct traceobj_arg *)ptr;
+ /* clear tables */
+ st_foreach(arg->object_table, free_values_i, 0);
+ st_free_table(arg->object_table);
+ st_foreach(arg->str_table, free_keys_i, 0);
+ st_free_table(arg->str_table);
+ xfree(arg);
+}
+
+static size_t
+allocation_info_tracer_memsize(const void *ptr)
+{
+ size_t size;
+ struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr;
+ size = sizeof(*trace_arg);
+ size += st_memsize(trace_arg->object_table);
+ size += st_memsize(trace_arg->str_table);
+ return size;
+}
+
+static int
+hash_foreach_should_replace_key(st_data_t key, st_data_t value, st_data_t argp, int error)
+{
+ VALUE allocated_object;
+
+ allocated_object = (VALUE)value;
+ if (allocated_object != rb_gc_location(allocated_object)) {
+ return ST_REPLACE;
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+hash_replace_key(st_data_t *key, st_data_t *value, st_data_t argp, int existing)
+{
+ *key = rb_gc_location((VALUE)*key);
+
+ return ST_CONTINUE;
+}
+
+static void
+allocation_info_tracer_compact(void *ptr)
+{
+ struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr;
+
+ if (st_foreach_with_replace(trace_arg->object_table, hash_foreach_should_replace_key, hash_replace_key, 0)) {
+ rb_raise(rb_eRuntimeError, "hash modified during iteration");
+ }
+}
+
+static const rb_data_type_t allocation_info_tracer_type = {
+ "ObjectTracing/allocation_info_tracer",
+ {
+ allocation_info_tracer_mark,
+ allocation_info_tracer_free, /* Never called because global */
+ allocation_info_tracer_memsize,
+ allocation_info_tracer_compact,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+};
+
+static VALUE traceobj_arg;
static struct traceobj_arg *tmp_trace_arg; /* TODO: Do not use global variables */
static int tmp_keep_remains; /* TODO: Do not use global variables */
@@ -158,7 +232,9 @@ static struct traceobj_arg *
get_traceobj_arg(void)
{
if (tmp_trace_arg == 0) {
- tmp_trace_arg = ALLOC_N(struct traceobj_arg, 1);
+ VALUE obj = TypedData_Make_Struct(rb_cObject, struct traceobj_arg, &allocation_info_tracer_type, tmp_trace_arg);
+ traceobj_arg = obj;
+ rb_gc_register_mark_object(traceobj_arg);
tmp_trace_arg->running = 0;
tmp_trace_arg->keep_remains = tmp_keep_remains;
tmp_trace_arg->newobj_trace = 0;
@@ -186,9 +262,7 @@ trace_object_allocations_start(VALUE self)
else {
if (arg->newobj_trace == 0) {
arg->newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, arg);
- rb_gc_register_mark_object(arg->newobj_trace);
arg->freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, arg);
- rb_gc_register_mark_object(arg->freeobj_trace);
}
rb_tracepoint_enable(arg->newobj_trace);
rb_tracepoint_enable(arg->freeobj_trace);
diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb
index 28c0431..42fbc3e 100644
--- a/test/objspace/test_objspace.rb
+++ b/test/objspace/test_objspace.rb
@@ -194,7 +194,7 @@ class TestObjSpace < Test::Unit::TestCase
assert_equal(self.class.name, ObjectSpace.allocation_class_path(o3))
assert_equal(__method__, ObjectSpace.allocation_method_id(o3))
}
- end if false # TODO: tenderlove is debugging it [Tue Aug 18 11:00:49 2020 JST]
+ end
def test_trace_object_allocations_start_stop_clear
ObjectSpace.trace_object_allocations_clear # clear object_table to get rid of erroneous detection for obj3