diff options
-rw-r--r-- | test/ruby/test_yjit.rb | 2 | ||||
-rw-r--r-- | vm_core.h | 1 | ||||
-rw-r--r-- | vm_insnhelper.c | 6 | ||||
-rw-r--r-- | yjit/bindgen/src/main.rs | 1 | ||||
-rw-r--r-- | yjit/src/codegen.rs | 49 | ||||
-rw-r--r-- | yjit/src/cruby_bindings.inc.rs | 1 |
6 files changed, 50 insertions, 10 deletions
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index 190073b028..0207f4aaf1 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -661,7 +661,7 @@ class TestYJIT < Test::Unit::TestCase def test_send_block # Setlocal_wc_0 sometimes side-exits on write barrier - assert_compiles(<<~'RUBY', result: "b:n/b:y/b:y/b:n", exits: { :setlocal_WC_0 => 0..1 }) + assert_compiles(<<~'RUBY', result: "b:n/b:y/b:y/b:n") def internal_method(&b) "b:#{block_given? ? "y" : "n"}" end @@ -1758,6 +1758,7 @@ rb_thread_t * ruby_thread_from_native(void); int ruby_thread_set_native(rb_thread_t *th); int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp); void rb_vm_rewind_cfp(rb_execution_context_t *ec, rb_control_frame_t *cfp); +void rb_vm_env_write(const VALUE *ep, int index, VALUE v); VALUE rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler); void rb_vm_register_special_exception_str(enum ruby_special_exceptions sp, VALUE exception_class, VALUE mesg); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 7ee8fd2cbf..a325d070a2 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -505,6 +505,12 @@ vm_env_write(const VALUE *ep, int index, VALUE v) } } +void +rb_vm_env_write(const VALUE *ep, int index, VALUE v) +{ + vm_env_write(ep, index, v); +} + VALUE rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler) { diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index 6b6337d541..baa71fc6cf 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -283,6 +283,7 @@ fn main() { .blocklist_type("rb_control_frame_struct") .opaque_type("rb_control_frame_struct") .allowlist_function("rb_vm_bh_to_procval") + .allowlist_function("rb_vm_env_write") .allowlist_function("rb_vm_ep_local_ep") .allowlist_type("vm_special_object_type") .allowlist_var("VM_ENV_DATA_INDEX_SPECVAL") diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 919e1662b8..88c5677551 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -1546,8 +1546,7 @@ fn gen_expandarray( let array_opnd = asm.stack_opnd(0); - // num is the number of requested values. If there aren't enough in the - // array then we're going to push on nils. + // If the array operand is nil, just push on nils if asm.ctx.get_opnd_type(array_opnd.into()) == Type::Nil { asm.stack_pop(1); // pop after using the type info // special case for a, b = nil pattern @@ -1762,6 +1761,7 @@ fn gen_getlocal_wc1( fn gen_setlocal_generic( jit: &mut JITState, asm: &mut Assembler, + ocb: &mut OutlinedCb, ep_offset: u32, level: u32, ) -> Option<CodegenStatus> { @@ -1770,6 +1770,29 @@ fn gen_setlocal_generic( // Load environment pointer EP at level let ep_opnd = gen_get_ep(asm, level); + // Fallback because of write barrier + if asm.ctx.get_chain_depth() > 0 + { + // Save the PC and SP because it runs GC + jit_prepare_routine_call(jit, asm); + + // Pop the value to write from the stack + let value_opnd = asm.stack_pop(1); + + // void rb_vm_env_write(const VALUE *ep, int index, VALUE v) + let index = -(ep_offset as i64); + asm.ccall( + rb_vm_env_write as *const u8, + vec![ + ep_opnd, + index.into(), + value_opnd, + ] + ); + + return Some(KeepCompiling); + } + // Write barriers may be required when VM_ENV_FLAG_WB_REQUIRED is set, however write barriers // only affect heap objects being written. If we know an immediate value is being written we // can skip this check. @@ -1783,7 +1806,15 @@ fn gen_setlocal_generic( asm.test(flags_opnd, VM_ENV_FLAG_WB_REQUIRED.into()); // if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0 - asm.jnz(Target::side_exit(Counter::setlocal_wb_required)); + assert!(asm.ctx.get_chain_depth() == 0); + jit_chain_guard( + JCC_JNZ, + jit, + asm, + ocb, + 1, + Counter::setlocal_wb_required, + ); } if level == 0 { @@ -1804,29 +1835,29 @@ fn gen_setlocal_generic( fn gen_setlocal( jit: &mut JITState, asm: &mut Assembler, - _ocb: &mut OutlinedCb, + ocb: &mut OutlinedCb, ) -> Option<CodegenStatus> { let idx = jit.get_arg(0).as_u32(); let level = jit.get_arg(1).as_u32(); - gen_setlocal_generic(jit, asm, idx, level) + gen_setlocal_generic(jit, asm, ocb, idx, level) } fn gen_setlocal_wc0( jit: &mut JITState, asm: &mut Assembler, - _ocb: &mut OutlinedCb, + ocb: &mut OutlinedCb, ) -> Option<CodegenStatus> { let idx = jit.get_arg(0).as_u32(); - gen_setlocal_generic(jit, asm, idx, 0) + gen_setlocal_generic(jit, asm, ocb, idx, 0) } fn gen_setlocal_wc1( jit: &mut JITState, asm: &mut Assembler, - _ocb: &mut OutlinedCb, + ocb: &mut OutlinedCb, ) -> Option<CodegenStatus> { let idx = jit.get_arg(0).as_u32(); - gen_setlocal_generic(jit, asm, idx, 1) + gen_setlocal_generic(jit, asm, ocb, idx, 1) } // new hash initialized from top N values diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index 1d0704073d..ccf5b530d6 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -1166,6 +1166,7 @@ extern "C" { pub static mut rb_block_param_proxy: VALUE; pub fn rb_vm_ep_local_ep(ep: *const VALUE) -> *const VALUE; pub fn rb_iseq_path(iseq: *const rb_iseq_t) -> VALUE; + pub fn rb_vm_env_write(ep: *const VALUE, index: ::std::os::raw::c_int, v: VALUE); pub fn rb_vm_bh_to_procval(ec: *const rb_execution_context_t, block_handler: VALUE) -> VALUE; pub fn rb_vm_frame_method_entry( cfp: *const rb_control_frame_t, |