@@ -8239,6 +8239,44 @@ fn test_no_ep_escape_invalidation_at_max_versions() {
82398239 assert_snapshot ! ( result, @r#""expected""# ) ;
82408240}
82418241
8242+ #[ test]
8243+ fn test_concurrent_ep_escape ( ) {
8244+ // Test to see if concurrent environment escapes
8245+ // sharing one piece of JIT code produce one consistent result.
8246+ rb_zjit_prepare_options ( ) ;
8247+ set_call_threshold ( 2 ) ;
8248+ set_inline_threshold ( 0 ) ;
8249+ let result = inspect ( r#"
8250+ def spill_escaper(gate)
8251+ a = 1
8252+ b = 2
8253+ spill_captor(gate) { } # empty block, no eager spill
8254+ end
8255+
8256+ # Returning `blk` materializes the Proc, which escapes spill_escaper's EP.
8257+ def spill_captor(gate, &blk)
8258+ gate.receive ? blk : nil
8259+ end
8260+
8261+ ready = Ractor::Port.new
8262+ results = Ractor::Port.new
8263+ ractors = 4.times.map do
8264+ Ractor.new(ready, results) do |ready, results|
8265+ port = Ractor.current.default_port
8266+ 2.times { port << false; spill_escaper(port) } # compile spill_escaper, no escape
8267+ ready << :parked # parks until the main Ractor releases
8268+ bnd = spill_escaper(port).binding
8269+ results << [bnd.local_variable_get(:a), bnd.local_variable_get(:b)]
8270+ end
8271+ end
8272+
8273+ ractors.size.times { ready.receive }
8274+ ractors.each { |r| r << true } # have all ractor do EP escapes
8275+ ractors.size.times.map { results.receive }.uniq
8276+ "# ) ;
8277+ assert_snapshot ! ( result, @r#"[[1, 2]]"# ) ;
8278+ }
8279+
82428280#[ test]
82438281fn test_float_arithmetic ( ) {
82448282 set_call_threshold ( 1 ) ;
0 commit comments