From 09cd13114a7c30a7fecae1bda726a419cd1b4bf2 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Mon, 12 Jan 2026 16:55:40 -0800 Subject: [PATCH 1/6] redmine-backporter.rb: Check remote-tracking branch on `has_commit` check for the `backport` command. I don't maintain local "master" branch on my ruby repository for stable branch maintenance. I want just running `git fetch origin` to make it work. It should work for those who pull origin/master into their local master too. --- tool/redmine-backporter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/redmine-backporter.rb b/tool/redmine-backporter.rb index 7f08eb8d1a956b..95a9688cb2cef9 100755 --- a/tool/redmine-backporter.rb +++ b/tool/redmine-backporter.rb @@ -190,7 +190,7 @@ def backport_command_string next false if c.match(/\A\d{1,6}\z/) # skip SVN revision # check if the Git revision is included in master - has_commit(c, "master") + has_commit(c, "origin/master") end.sort_by do |changeset| Integer(IO.popen(%W[git show -s --format=%ct #{changeset}], &:read)) end From 5de4cc56086493689701e86aa0ccf6a4a4a87d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Hasi=C5=84ski?= Date: Sun, 11 Jan 2026 14:12:07 +0100 Subject: [PATCH 2/6] Fix regexp performance regression for patterns starting with s/k Commit 981ee02c7c ("Fix performance problem with /k/i and /s/i") was merged for Ruby 4.0 to enable partial Boyer-Moore optimization for patterns containing 's' or 'k' by using the prefix before those characters. However, when 's' or 'k' appears at the start of a pattern (no usable prefix), set_bm_skip() returns 0 and the code returned early without setting any optimization mode, leaving reg->optimize at ONIG_OPTIMIZE_NONE. This caused up to 30x slowdown for patterns like /slackware/i when matched against strings with non-ASCII characters. This patch keeps the improvement from 981ee02c7c for patterns with 3+ char prefix, while fixing the regression by falling back to ONIG_OPTIMIZE_EXACT_IC with the full pattern when the usable prefix is less than 3 characters. Before: /\bslackware\b/i with non-ASCII string: 2.24 us/op After: /\bslackware\b/i with non-ASCII string: 0.70 us/op (3.2x faster) [Bug #21824] --- regcomp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/regcomp.c b/regcomp.c index 18b2c97eb6381c..320cf520e90c69 100644 --- a/regcomp.c +++ b/regcomp.c @@ -5264,18 +5264,24 @@ set_optimize_exact_info(regex_t* reg, OptExactInfo* e) if (e->ignore_case > 0) { if (e->len >= 3 || (e->len >= 2 && allow_reverse)) { + int orig_len = e->len; e->len = set_bm_skip(reg->exact, reg->exact_end, reg, reg->map, 1); - reg->exact_end = reg->exact + e->len; if (e->len >= 3) { + reg->exact_end = reg->exact + e->len; reg->optimize = (allow_reverse != 0 ? ONIG_OPTIMIZE_EXACT_BM_IC : ONIG_OPTIMIZE_EXACT_BM_NOT_REV_IC); } - else if (e->len > 0) { + else { + /* Even if BM skip table can't be built (e.g., pattern starts with + 's' or 'k' which have multi-byte case fold variants), we should + still use EXACT_IC optimization with the original pattern. + Without this fallback, patterns like /slackware/i have no + optimization at all, causing severe performance regression + especially with non-ASCII strings. See [Bug #21824] */ + e->len = orig_len; /* Restore original length for EXACT_IC */ reg->optimize = ONIG_OPTIMIZE_EXACT_IC; } - else - return 0; } else { reg->optimize = ONIG_OPTIMIZE_EXACT_IC; From 910fcfad14e3e7464815afc14a5f2b7b87502ab9 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 13 Jan 2026 10:34:38 +0900 Subject: [PATCH 3/6] mk_builtin_loader: Count local variable definition lines --- tool/mk_builtin_loader.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/mk_builtin_loader.rb b/tool/mk_builtin_loader.rb index a63e1827d5e1db..5aa07962f93b4b 100644 --- a/tool/mk_builtin_loader.rb +++ b/tool/mk_builtin_loader.rb @@ -297,7 +297,7 @@ def generate_cexpr(ofile, lineno, line_file, body_lineno, text, locals, func_nam next unless lvar or local_ptrs.include?(param) f.puts "VALUE *const #{param}__ptr = (VALUE *)&ec->cfp->ep[#{-3 - i}];" f.puts "MAYBE_UNUSED(const VALUE) #{param} = *#{param}__ptr;" if lvar - lineno += 1 + lineno += lvar ? 2 : 1 } f.puts "#line #{body_lineno} \"#{line_file}\"" lineno += 1 From ead107f0d7bd3cf1f30428b7907b9871a9a4542b Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Mon, 12 Jan 2026 17:29:29 -0800 Subject: [PATCH 4/6] [ruby/prism] Bump to v1.8.0 https://github.com/ruby/prism/commit/9c12be6e6a --- lib/prism/prism.gemspec | 2 +- prism/extension.h | 2 +- prism/templates/lib/prism/serialize.rb.erb | 2 +- prism/version.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec index 9f5d458d6c8efe..463387e55c814b 100644 --- a/lib/prism/prism.gemspec +++ b/lib/prism/prism.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "prism" - spec.version = "1.7.0" + spec.version = "1.8.0" spec.authors = ["Shopify"] spec.email = ["ruby@shopify.com"] diff --git a/prism/extension.h b/prism/extension.h index 6c3de31adb94d6..510faa48e8dfed 100644 --- a/prism/extension.h +++ b/prism/extension.h @@ -1,7 +1,7 @@ #ifndef PRISM_EXT_NODE_H #define PRISM_EXT_NODE_H -#define EXPECTED_PRISM_VERSION "1.7.0" +#define EXPECTED_PRISM_VERSION "1.8.0" #include #include diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb index 63f97dddd790b1..6902df5c0159d2 100644 --- a/prism/templates/lib/prism/serialize.rb.erb +++ b/prism/templates/lib/prism/serialize.rb.erb @@ -10,7 +10,7 @@ module Prism # The minor version of prism that we are expecting to find in the serialized # strings. - MINOR_VERSION = 7 + MINOR_VERSION = 8 # The patch version of prism that we are expecting to find in the serialized # strings. diff --git a/prism/version.h b/prism/version.h index 0b64a70dfff5c0..0ef7435c1741e7 100644 --- a/prism/version.h +++ b/prism/version.h @@ -14,7 +14,7 @@ /** * The minor version of the Prism library as an int. */ -#define PRISM_VERSION_MINOR 7 +#define PRISM_VERSION_MINOR 8 /** * The patch version of the Prism library as an int. @@ -24,6 +24,6 @@ /** * The version of the Prism library as a constant string. */ -#define PRISM_VERSION "1.7.0" +#define PRISM_VERSION "1.8.0" #endif From 9fb9bfab605a6d1edb453f64f4f3d23926e191d0 Mon Sep 17 00:00:00 2001 From: git Date: Tue, 13 Jan 2026 01:53:37 +0000 Subject: [PATCH 5/6] Update default gems list at ead107f0d7bd3cf1f30428b7907b98 [ci skip] --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index 7ec521481d4f54..6492b00276d2fb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -46,6 +46,7 @@ releases. * RubyGems 4.1.0.dev * bundler 4.1.0.dev +* prism 1.8.0 * stringio 3.2.1.dev * strscan 3.1.7.dev From 60cf8598b2f0e9548fd30761276f655569d3daf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= Date: Tue, 13 Jan 2026 11:50:01 +0900 Subject: [PATCH 6/6] [nit] refactor rename inline functions Pretty sure commit 0f64da9672d88921439f6fdb306d16fece9b9c90 didn't intend to welcome extension libraries to use these functions. --- error.c | 4 ++-- include/ruby/internal/core/rtypeddata.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/error.c b/error.c index 69dc559c5d03ed..d6518feb347db2 100644 --- a/error.c +++ b/error.c @@ -1383,14 +1383,14 @@ rb_unexpected_type(VALUE x, int t) int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent) { - return rb_typeddata_inherited_p_inline(child, parent); + return rbimpl_typeddata_inherited_p_inline(child, parent); } #undef rb_typeddata_is_kind_of int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type) { - return rb_typeddata_is_kind_of_inline(obj, data_type); + return rbimpl_typeddata_is_kind_of_inline(obj, data_type); } #undef rb_typeddata_is_instance_of diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h index bf6423f8d230f0..8c0397d80be56e 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -673,24 +673,24 @@ RTYPEDDATA_TYPE(VALUE obj) RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NONNULL(()) static inline bool -rb_typeddata_inherited_p_inline(const rb_data_type_t *child, const rb_data_type_t *parent) +rbimpl_typeddata_inherited_p_inline(const rb_data_type_t *child, const rb_data_type_t *parent) { do { if (RB_LIKELY(child == parent)) return true; } while ((child = child->parent) != NULL); return false; } -#define rb_typeddata_inherited_p rb_typeddata_inherited_p_inline +#define rb_typeddata_inherited_p rbimpl_typeddata_inherited_p_inline RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NONNULL((2)) static inline bool -rb_typeddata_is_kind_of_inline(VALUE obj, const rb_data_type_t *data_type) +rbimpl_typeddata_is_kind_of_inline(VALUE obj, const rb_data_type_t *data_type) { if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) return false; return rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type); } -#define rb_typeddata_is_kind_of rb_typeddata_is_kind_of_inline +#define rb_typeddata_is_kind_of rbimpl_typeddata_is_kind_of_inline RBIMPL_ATTR_ARTIFICIAL() RBIMPL_ATTR_NONNULL((2))