diff --git a/gc.c b/gc.c index 3c9adf3b007384..ca018b7ae14114 100644 --- a/gc.c +++ b/gc.c @@ -9596,6 +9596,11 @@ gc_set_candidate_object_i(void *vstart, void *vend, size_t stride, void *data) case T_NONE: case T_ZOMBIE: break; + case T_STRING: + // precompute the string coderange. This both save time for when it will be + // eventually needed, and avoid mutating heap pages after a potential fork. + rb_enc_str_coderange(v); + // fall through default: if (!RVALUE_OLD_P(v) && !RVALUE_WB_UNPROTECTED(v)) { RVALUE_AGE_SET_CANDIDATE(objspace, v); diff --git a/internal/string.h b/internal/string.h index 5f59d9621b6b81..3c9dca88008c56 100644 --- a/internal/string.h +++ b/internal/string.h @@ -17,6 +17,7 @@ #define STR_NOEMBED FL_USER1 #define STR_SHARED FL_USER2 /* = ELTS_SHARED */ +#define STR_NOFREE FL_USER18 #ifdef rb_fstring_cstr # undef rb_fstring_cstr diff --git a/process.c b/process.c index 5761aea718d277..91f434f5e2e8e5 100644 --- a/process.c +++ b/process.c @@ -8555,6 +8555,7 @@ static VALUE rb_mProcID_Syscall; * * Perform a major GC. * * Compacts the heap. * * Promotes all surviving objects to the old generation. + * * Precompute the coderange of all strings. */ static VALUE @@ -8566,7 +8567,6 @@ proc_warmup(VALUE _) return Qtrue; } - /* * Document-module: Process * diff --git a/string.c b/string.c index 9cc4dfd3ce0b8d..a17bf4e35daa8d 100644 --- a/string.c +++ b/string.c @@ -102,7 +102,6 @@ VALUE rb_cSymbol; #define STR_SHARED_ROOT FL_USER5 #define STR_BORROWED FL_USER6 #define STR_TMPLOCK FL_USER7 -#define STR_NOFREE FL_USER18 #define STR_FAKESTR FL_USER19 #define STR_SET_NOEMBED(str) do {\ diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index 6ca16733bbf014..9846f5e2db9013 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -2709,4 +2709,16 @@ def test_warmup_run_major_gc_and_compact assert_equal compact_count + 1, GC.stat(:compact_count) end; end + + def test_warmup_precompute_string_coderange + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + require 'objspace' + begin; + obj = "a" * 12 + obj.force_encoding(Encoding::BINARY) + assert_include(ObjectSpace.dump(obj), '"coderange":"unknown"') + Process.warmup + assert_include(ObjectSpace.dump(obj), '"coderange":"7bit"') + end; + end end