Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions ext/rbs_extension/legacy_location.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,11 @@ static VALUE location_end_pos(VALUE self) {
static rbs_constant_id_t rbs_constant_pool_insert_ruby_symbol(VALUE symbol) {
VALUE name = rb_sym2str(symbol);

// Constants inserted here will never be freed, but that's acceptable because:
// 1. Most symbols passed into here will be the ones already inserted into the constant pool by `parser.c`.
// 2. Methods like `add_required_child` and `add_optional_child` will usually only get called with a few different symbols.
return rbs_constant_pool_insert_constant(RBS_GLOBAL_CONSTANT_POOL, (const uint8_t *) RSTRING_PTR(name), RSTRING_LEN(name));
// To prevent memory compaction from breaking references to strings,
// strings are copied and memory managed with an owned type.
uint8_t *copied_name = malloc(RSTRING_LEN(name));
memcpy((void *) copied_name, RSTRING_PTR(name), RSTRING_LEN(name));
return rbs_constant_pool_insert_owned(RBS_GLOBAL_CONSTANT_POOL, copied_name, RSTRING_LEN(name));
}

static VALUE location_add_required_child(VALUE self, VALUE name, VALUE start, VALUE end) {
Expand Down
28 changes: 28 additions & 0 deletions test/rbs/location_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,34 @@ def test_sub_buffer_local_location
end
end

def test_gc_compaction
GC.disable
buffer = buffer()
locations = 10.times.map do |i|
Location.new(buffer, 0, 10).tap do |loc|
loc.add_required_child(:static_0, 0...1)
loc.add_required_child(:static_1, 1...2)
loc.add_required_child(:static_2, 2...3)
3.times do |j|
loc.add_required_child(:"dynamic_#{i}_#{j}", j...j+1)
end
end
end
GC.start
GC.start
GC.compact
locations.each_with_index do |loc, i|
assert_instance_of Location, loc[:static_0]
assert_instance_of Location, loc[:static_1]
assert_instance_of Location, loc[:static_2]
3.times do |j|
assert_instance_of Location, loc[:"dynamic_#{i}_#{j}"]
end
end
ensure
GC.enable
end

private

def buffer(content: nil)
Expand Down