From abbb1b25391f971625ec2fcbfa8555a02bf1cb77 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 19 Mar 2026 12:14:34 -0500 Subject: [PATCH 1/3] [ruby/prism] Swich identifiers to byte[] * JAVA_STRING_TYPE and related change to IDENTIFIER * TruffleRuby still uses java.lang.String Fixes https://github.com/ruby/prism/pull/4009 https://github.com/ruby/prism/commit/32028c52c5 --- prism/templates/template.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prism/templates/template.rb b/prism/templates/template.rb index 8f7734dd43f001..be39c2f68255e1 100755 --- a/prism/templates/template.rb +++ b/prism/templates/template.rb @@ -12,7 +12,7 @@ module Template # :nodoc: all CHECK_FIELD_KIND = ENV.fetch("CHECK_FIELD_KIND", false) JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "truffleruby" - JAVA_STRING_TYPE = JAVA_BACKEND == "jruby" ? "org.jruby.RubySymbol" : "String" + JAVA_IDENTIFIER_TYPE = JAVA_BACKEND == "truffleruby" ? "String" : "byte[]" INCLUDE_NODE_ID = !SERIALIZE_ONLY_SEMANTICS_FIELDS || JAVA_BACKEND == "jruby" COMMON_FLAGS_COUNT = 2 @@ -272,7 +272,7 @@ def call_seq_type end def java_type - JAVA_STRING_TYPE + JAVA_IDENTIFIER_TYPE end end @@ -292,7 +292,7 @@ def call_seq_type end def java_type - JAVA_STRING_TYPE + JAVA_IDENTIFIER_TYPE end end @@ -312,7 +312,7 @@ def call_seq_type end def java_type - "#{JAVA_STRING_TYPE}[]" + "#{JAVA_IDENTIFIER_TYPE}[]" end end From 7d315536670357332863615a5762f0707a437543 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 20 Mar 2026 09:59:53 -0500 Subject: [PATCH 2/3] [ruby/prism] Tweaks for byte[] identifiers * Allocate array of byte[] as byte[length][]. * Default JAVA_BACKEND to "default" with "truffleruby" the custom option. https://github.com/ruby/prism/commit/5f29860bb7 --- prism/templates/template.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prism/templates/template.rb b/prism/templates/template.rb index be39c2f68255e1..5d1afc95065219 100755 --- a/prism/templates/template.rb +++ b/prism/templates/template.rb @@ -11,7 +11,7 @@ module Template # :nodoc: all REMOVE_ON_ERROR_TYPES = SERIALIZE_ONLY_SEMANTICS_FIELDS CHECK_FIELD_KIND = ENV.fetch("CHECK_FIELD_KIND", false) - JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "truffleruby" + JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "default" JAVA_IDENTIFIER_TYPE = JAVA_BACKEND == "truffleruby" ? "String" : "byte[]" INCLUDE_NODE_ID = !SERIALIZE_ONLY_SEMANTICS_FIELDS || JAVA_BACKEND == "jruby" From 251fd7a11e442c34c1b60908409e5611f69ef858 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 21 Mar 2026 08:49:57 -0700 Subject: [PATCH 3/3] ZJIT: Fold statically known GuardGreaterEq (#16487) Array access has guards that the array index is greater than or equal to zero. In the case of code like `array[123]`, we know at compile time that 123 is greater than 0. Since we're now eagerly unboxing integers, we can fold this guard away on array access. Additionally, if we're able to tell statically that a GuardGreaterEq would fail, we can just emit a side exit at that moment. For example if we have array access like `foo[-1]`, we know that -1 will be less than 0 statically, so we can just emit the side exit at that time --- zjit/src/hir.rs | 12 +++++ zjit/src/hir/opt_tests.rs | 97 +++++++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 29 deletions(-) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index ebdf044a920daf..9c409e36fb955e 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -5071,6 +5071,18 @@ impl Function { _ => insn_id, } }, + Insn::GuardGreaterEq { left, right, state, reason } => { + let left_num = self.type_of(left).cint64_value(); + let right_num = self.type_of(right).cint64_value(); + match (left_num, right_num) { + (Some(l), Some(r)) if l >= r => { + self.make_equal_to(insn_id, left); + continue + }, + (Some(_), Some(_)) => self.new_insn(Insn::SideExit { state, reason }), + _ => insn_id, + } + }, Insn::GuardBitEquals { val, expected, .. } => { let recv_type = self.type_of(val); if recv_type.has_value(expected) { diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs index bc3f92b83ab923..c0c89e35d46eb0 100644 --- a/zjit/src/hir/opt_tests.rs +++ b/zjit/src/hir/opt_tests.rs @@ -1017,14 +1017,73 @@ mod hir_opt_tests { v34:CInt64[0] = Const CInt64(0) v29:CInt64 = ArrayLength v27 v30:CInt64[0] = GuardLess v34, v29 - v31:CInt64[0] = Const CInt64(0) - v32:CInt64[0] = GuardGreaterEq v30, v31 - v33:BasicObject = ArrayAref v27, v32 + v33:BasicObject = ArrayAref v27, v30 CheckInterrupts Return v33 "); } + #[test] + fn test_fold_guard_greater_eq() { + eval(" + def test(arr) = arr[0] + test([1,2,3]) + "); + assert_snapshot!(hir_string("test"), @" + fn test@:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :arr@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :arr@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + v15:Fixnum[0] = Const Value(0) + PatchPoint NoSingletonClass(Array@0x1008) + PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018) + v27:ArrayExact = GuardType v10, ArrayExact + v34:CInt64[0] = Const CInt64(0) + v29:CInt64 = ArrayLength v27 + v30:CInt64[0] = GuardLess v34, v29 + v33:BasicObject = ArrayAref v27, v30 + CheckInterrupts + Return v33 + "); + } + + #[test] + fn test_fold_guard_greater_eq_side_exit() { + eval(r##" + def test = [4,5,6].freeze[-10] + "##); + assert_snapshot!(hir_string("test"), @" + fn test@:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + Jump bb3(v1) + bb2(): + EntryPoint JIT(0) + v4:BasicObject = LoadArg :self@0 + Jump bb3(v4) + bb3(v6:BasicObject): + PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) + v11:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + v13:Fixnum[-10] = Const Value(-10) + PatchPoint NoSingletonClass(Array@0x1008) + PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018) + v31:CInt64[-10] = Const CInt64(-10) + v26:CInt64 = ArrayLength v11 + v27:CInt64[-10] = GuardLess v31, v26 + SideExit GuardGreaterEq + "); + } + #[test] fn neq_with_side_effect_not_elided () { let result = eval(" @@ -2287,9 +2346,7 @@ mod hir_opt_tests { v34:CInt64[0] = Const CInt64(0) v29:CInt64 = ArrayLength v27 v30:CInt64[0] = GuardLess v34, v29 - v31:CInt64[0] = Const CInt64(0) - v32:CInt64[0] = GuardGreaterEq v30, v31 - v33:BasicObject = ArrayAref v27, v32 + v33:BasicObject = ArrayAref v27, v30 CheckInterrupts Return v33 "); @@ -5998,9 +6055,7 @@ mod hir_opt_tests { v33:CInt64[0] = Const CInt64(0) v28:CInt64 = ArrayLength v23 v29:CInt64[0] = GuardLess v33, v28 - v30:CInt64[0] = Const CInt64(0) - v31:CInt64[0] = GuardGreaterEq v29, v30 - v32:BasicObject = ArrayAref v23, v31 + v32:BasicObject = ArrayAref v23, v29 CheckInterrupts Return v32 "); @@ -6032,8 +6087,6 @@ mod hir_opt_tests { v31:CInt64[1] = Const CInt64(1) v26:CInt64 = ArrayLength v11 v27:CInt64[1] = GuardLess v31, v26 - v28:CInt64[0] = Const CInt64(0) - v29:CInt64[1] = GuardGreaterEq v27, v28 v32:Fixnum[5] = Const Value(5) CheckInterrupts Return v32 @@ -6064,11 +6117,7 @@ mod hir_opt_tests { v31:CInt64[-3] = Const CInt64(-3) v26:CInt64 = ArrayLength v11 v27:CInt64[-3] = GuardLess v31, v26 - v28:CInt64[0] = Const CInt64(0) - v29:CInt64[-3] = GuardGreaterEq v27, v28 - v32:Fixnum[4] = Const Value(4) - CheckInterrupts - Return v32 + SideExit GuardGreaterEq "); } @@ -6096,11 +6145,7 @@ mod hir_opt_tests { v31:CInt64[-10] = Const CInt64(-10) v26:CInt64 = ArrayLength v11 v27:CInt64[-10] = GuardLess v31, v26 - v28:CInt64[0] = Const CInt64(0) - v29:CInt64[-10] = GuardGreaterEq v27, v28 - v32:NilClass = Const Value(nil) - CheckInterrupts - Return v32 + SideExit GuardGreaterEq "); } @@ -6128,8 +6173,6 @@ mod hir_opt_tests { v31:CInt64[10] = Const CInt64(10) v26:CInt64 = ArrayLength v11 v27:CInt64[10] = GuardLess v31, v26 - v28:CInt64[0] = Const CInt64(0) - v29:CInt64[10] = GuardGreaterEq v27, v28 v32:NilClass = Const Value(nil) CheckInterrupts Return v32 @@ -8362,9 +8405,7 @@ mod hir_opt_tests { v37:CInt64[0] = Const CInt64(0) v32:CInt64 = ArrayLength v14 v33:CInt64[0] = GuardLess v37, v32 - v34:CInt64[0] = Const CInt64(0) - v35:CInt64[0] = GuardGreaterEq v33, v34 - v36:BasicObject = ArrayAref v14, v35 + v36:BasicObject = ArrayAref v14, v33 CheckInterrupts Return v36 "); @@ -8744,9 +8785,7 @@ mod hir_opt_tests { v45:CInt64[1] = Const CInt64(1) v39:CInt64 = ArrayLength v33 v40:CInt64[1] = GuardLess v45, v39 - v41:CInt64[0] = Const CInt64(0) - v42:CInt64[1] = GuardGreaterEq v40, v41 - ArrayAset v33, v42, v19 + ArrayAset v33, v40, v19 WriteBarrier v33, v19 CheckInterrupts Return v19