@@ -196,6 +196,32 @@ def test
196196 } , insns : [ :setglobal ]
197197 end
198198
199+ def test_toplevel_binding
200+ # Not using assert_compiles, which doesn't use the toplevel frame for `test_script`.
201+ out , err , status = eval_with_jit ( %q{
202+ a = 1
203+ b = 2
204+ TOPLEVEL_BINDING.local_variable_set(:b, 3)
205+ c = 4
206+ print [a, b, c]
207+ } )
208+ assert_success ( out , err , status )
209+ assert_equal "[1, 3, 4]" , out
210+ end
211+
212+ def test_toplevel_local_after_eval
213+ # Not using assert_compiles, which doesn't use the toplevel frame for `test_script`.
214+ out , err , status = eval_with_jit ( %q{
215+ a = 1
216+ b = 2
217+ eval('b = 3')
218+ c = 4
219+ print [a, b, c]
220+ } )
221+ assert_success ( out , err , status )
222+ assert_equal "[1, 3, 4]" , out
223+ end
224+
199225 def test_getlocal_after_eval
200226 assert_compiles '2' , %q{
201227 def test
@@ -2428,12 +2454,8 @@ def assert_runs(expected, test_script, insns: [], assert_compiles: false, **opts
24282454 IO.open(#{ pipe_fd } ).write(Marshal.dump(result))
24292455 RUBY
24302456
2431- status , out , err , result = eval_with_jit ( script , pipe_fd :, **opts )
2432-
2433- message = "exited with status #{ status . to_i } "
2434- message << "\n stdout:\n ```\n #{ out } ```\n " unless out . empty?
2435- message << "\n stderr:\n ```\n #{ err } ```\n " unless err . empty?
2436- assert status . success? , message
2457+ out , err , status , result = eval_with_jit ( script , pipe_fd :, **opts )
2458+ assert_success ( out , err , status )
24372459
24382460 result = Marshal . load ( result )
24392461 assert_equal ( expected , result . fetch ( :ret_val ) . inspect )
@@ -2462,7 +2484,7 @@ def eval_with_jit(
24622484 debug : true ,
24632485 allowed_iseqs : nil ,
24642486 timeout : 1000 ,
2465- pipe_fd :
2487+ pipe_fd : nil
24662488 )
24672489 args = [ "--disable-gems" ]
24682490 if zjit
@@ -2478,18 +2500,25 @@ def eval_with_jit(
24782500 end
24792501 end
24802502 args << "-e" << script_shell_encode ( script )
2481- pipe_r , pipe_w = IO . pipe
2482- # Separate thread so we don't deadlock when
2483- # the child ruby blocks writing the output to pipe_fd
2484- pipe_out = nil
2485- pipe_reader = Thread . new do
2486- pipe_out = pipe_r . read
2487- pipe_r . close
2503+ ios = { }
2504+ if pipe_fd
2505+ pipe_r , pipe_w = IO . pipe
2506+ # Separate thread so we don't deadlock when
2507+ # the child ruby blocks writing the output to pipe_fd
2508+ pipe_out = nil
2509+ pipe_reader = Thread . new do
2510+ pipe_out = pipe_r . read
2511+ pipe_r . close
2512+ end
2513+ ios [ pipe_fd ] = pipe_w
24882514 end
2489- out , err , status = EnvUtil . invoke_ruby ( args , '' , true , true , rubybin : RbConfig . ruby , timeout : timeout , ios : { pipe_fd => pipe_w } )
2490- pipe_w . close
2491- pipe_reader . join ( timeout )
2492- [ status , out , err , pipe_out ]
2515+ result = EnvUtil . invoke_ruby ( args , '' , true , true , rubybin : RbConfig . ruby , timeout : timeout , ios :)
2516+ if pipe_fd
2517+ pipe_w . close
2518+ pipe_reader . join ( timeout )
2519+ result << pipe_out
2520+ end
2521+ result
24932522 ensure
24942523 pipe_reader &.kill
24952524 pipe_reader &.join ( timeout )
@@ -2498,6 +2527,13 @@ def eval_with_jit(
24982527 jitlist &.unlink
24992528 end
25002529
2530+ def assert_success ( out , err , status )
2531+ message = "exited with status #{ status . to_i } "
2532+ message << "\n stdout:\n ```\n #{ out } ```\n " unless out . empty?
2533+ message << "\n stderr:\n ```\n #{ err } ```\n " unless err . empty?
2534+ assert status . success? , message
2535+ end
2536+
25012537 def script_shell_encode ( s )
25022538 # We can't pass utf-8-encoded characters directly in a shell arg. But we can use Ruby \u constants.
25032539 s . chars . map { |c | c . ascii_only? ? c : "\\ u%x" % c . codepoints [ 0 ] } . join
0 commit comments