Fix re-embedding of strings during compaction
The reference updating code for strings is not re-embedding strings because the code is incorrectly wrapped inside of a `if (STR_SHARED_P(obj))` clause. Shared strings can't be re-embedded so this ends up being a no-op. This means that strings can be moved to a large size pool during compaction, but won't be re-embedded, which would waste the space.
This commit is contained in:
parent
29dc9378d9
commit
3be2acfafd
Notes:
git
2023-01-09 13:49:57 +00:00
18
gc.c
18
gc.c
@ -10609,17 +10609,19 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
|
|||||||
#if USE_RVARGC
|
#if USE_RVARGC
|
||||||
VALUE new_root = any->as.string.as.heap.aux.shared;
|
VALUE new_root = any->as.string.as.heap.aux.shared;
|
||||||
rb_str_update_shared_ary(obj, old_root, new_root);
|
rb_str_update_shared_ary(obj, old_root, new_root);
|
||||||
|
|
||||||
// if, after move the string is not embedded, and can fit in the
|
|
||||||
// slot it's been placed in, then re-embed it
|
|
||||||
if (rb_gc_obj_slot_size(obj) >= rb_str_size_as_embedded(obj)) {
|
|
||||||
if (!STR_EMBED_P(obj) && rb_str_reembeddable_p(obj)) {
|
|
||||||
rb_str_make_embedded(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_RVARGC
|
||||||
|
/* If, after move the string is not embedded, and can fit in the
|
||||||
|
* slot it's been placed in, then re-embed it. */
|
||||||
|
if (rb_gc_obj_slot_size(obj) >= rb_str_size_as_embedded(obj)) {
|
||||||
|
if (!STR_EMBED_P(obj) && rb_str_reembeddable_p(obj)) {
|
||||||
|
rb_str_make_embedded(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_DATA:
|
case T_DATA:
|
||||||
|
12
string.c
12
string.c
@ -312,14 +312,18 @@ rb_str_make_embedded(VALUE str)
|
|||||||
RUBY_ASSERT(rb_str_reembeddable_p(str));
|
RUBY_ASSERT(rb_str_reembeddable_p(str));
|
||||||
RUBY_ASSERT(!STR_EMBED_P(str));
|
RUBY_ASSERT(!STR_EMBED_P(str));
|
||||||
|
|
||||||
char *buf = RSTRING_PTR(str);
|
char *buf = RSTRING(str)->as.heap.ptr;
|
||||||
long len = RSTRING_LEN(str);
|
long len = RSTRING(str)->as.heap.len;
|
||||||
|
|
||||||
STR_SET_EMBED(str);
|
STR_SET_EMBED(str);
|
||||||
STR_SET_EMBED_LEN(str, len);
|
STR_SET_EMBED_LEN(str, len);
|
||||||
|
|
||||||
memmove(RSTRING_PTR(str), buf, len);
|
if (len > 0) {
|
||||||
ruby_xfree(buf);
|
memcpy(RSTRING_PTR(str), buf, len);
|
||||||
|
ruby_xfree(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
TERM_FILL(RSTRING(str)->as.embed.ary + len, TERM_LEN(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -382,7 +382,7 @@ class TestGCCompact < Test::Unit::TestCase
|
|||||||
def test_moving_strings_up_size_pools
|
def test_moving_strings_up_size_pools
|
||||||
omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
|
omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
|
||||||
|
|
||||||
assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV)
|
assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV)
|
||||||
begin;
|
begin;
|
||||||
STR_COUNT = 500
|
STR_COUNT = 500
|
||||||
|
|
||||||
@ -394,14 +394,14 @@ class TestGCCompact < Test::Unit::TestCase
|
|||||||
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
|
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
|
||||||
|
|
||||||
assert_operator(stats[:moved_up][:T_STRING], :>=, STR_COUNT)
|
assert_operator(stats[:moved_up][:T_STRING], :>=, STR_COUNT)
|
||||||
assert(ary) # warning: assigned but unused variable - ary
|
assert_include(ObjectSpace.dump(ary[0]), '"embedded":true')
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_moving_strings_down_size_pools
|
def test_moving_strings_down_size_pools
|
||||||
omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
|
omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1
|
||||||
|
|
||||||
assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV)
|
assert_separately(%w[-robjspace], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10, signal: :SEGV)
|
||||||
begin;
|
begin;
|
||||||
STR_COUNT = 500
|
STR_COUNT = 500
|
||||||
|
|
||||||
@ -412,7 +412,7 @@ class TestGCCompact < Test::Unit::TestCase
|
|||||||
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
|
stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
|
||||||
|
|
||||||
assert_operator(stats[:moved_down][:T_STRING], :>=, STR_COUNT)
|
assert_operator(stats[:moved_down][:T_STRING], :>=, STR_COUNT)
|
||||||
assert(ary) # warning: assigned but unused variable - ary
|
assert_include(ObjectSpace.dump(ary[0]), '"embedded":true')
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user