Skip to content

Commit f1e34b6

Browse files
committed
local reasoning fix
1 parent 3f0e61f commit f1e34b6

2 files changed

Lines changed: 27 additions & 22 deletions

File tree

yjit/src/codegen.rs

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -234,20 +234,21 @@ impl<'a> JITState<'a> {
234234
result
235235
}
236236

237-
/// Return true if the current ISEQ could escape an environment.
238-
///
239-
/// As of vm_push_frame(), EP is always equal to BP. However, after pushing
240-
/// a frame, some ISEQ setups call vm_bind_update_env(), which redirects EP.
241-
/// Also, some method calls escape the environment to the heap.
242-
fn escapes_ep(&self) -> bool {
243-
match unsafe { get_iseq_body_type(self.iseq) } {
244-
// <main> frame is always associated to TOPLEVEL_BINDING.
245-
ISEQ_TYPE_MAIN |
246-
// Kernel#eval uses a heap EP when a Binding argument is not nil.
247-
ISEQ_TYPE_EVAL => true,
248-
// If this ISEQ has previously escaped EP, give up the optimization.
249-
_ if iseq_escapes_ep(self.iseq) => true,
250-
_ => false,
237+
// TODO
238+
fn can_assume_on_stack_env(&self) -> bool {
239+
// In principle, all ISEQs can run with an escaped environment. But,
240+
// if we're compiling the currently running iseq, and the environment
241+
// is currently on-stack, we can say our code will run as such. The
242+
// compiler never causes an environment escape and maintains the
243+
// current state.
244+
if unsafe { self.iseq == get_cfp_iseq(self.get_cfp()) && !cfp_env_has_escaped(self.get_cfp()) } {
245+
//
246+
if iseq_escapes_ep(self.iseq) {
247+
return false;
248+
}
249+
true
250+
} else {
251+
false
251252
}
252253
}
253254

@@ -370,15 +371,13 @@ impl<'a> JITState<'a> {
370371
true
371372
}
372373

373-
/// Assume that base pointer is equal to environment pointer in the current ISEQ.
374-
/// Return true if it's safe to assume so.
375374
fn assume_no_ep_escape(&mut self, asm: &mut Assembler) -> bool {
375+
if !self.can_assume_on_stack_env() {
376+
return false; // Unsound to rely on TODO
377+
}
376378
if jit_ensure_block_entry_exit(self, asm).is_none() {
377379
return false; // out of space, give up
378380
}
379-
if self.escapes_ep() {
380-
return false; // EP has been escaped in this ISEQ. disable the optimization to avoid an invalidation loop.
381-
}
382381
self.no_ep_escape = true;
383382
true
384383
}
@@ -2509,7 +2508,7 @@ fn gen_getlocal_generic(
25092508
level: u32,
25102509
) -> Option<CodegenStatus> {
25112510
// Split the block if we need to invalidate this instruction when EP escapes
2512-
if level == 0 && !jit.escapes_ep() && !jit.at_compile_target() {
2511+
if level == 0 && jit.can_assume_on_stack_env() && !jit.at_compile_target() {
25132512
return jit.defer_compilation(asm);
25142513
}
25152514

@@ -2610,7 +2609,7 @@ fn gen_setlocal_generic(
26102609
}
26112610

26122611
// Split the block if we need to invalidate this instruction when EP escapes
2613-
if level == 0 && !jit.escapes_ep() && !jit.at_compile_target() {
2612+
if level == 0 && jit.can_assume_on_stack_env() && !jit.at_compile_target() {
26142613
return jit.defer_compilation(asm);
26152614
}
26162615

yjit/src/cruby.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pub use rb_iseq_encoded_size as get_iseq_encoded_size;
176176
pub use rb_get_iseq_body_local_iseq as get_iseq_body_local_iseq;
177177
pub use rb_get_iseq_body_iseq_encoded as get_iseq_body_iseq_encoded;
178178
pub use rb_get_iseq_body_stack_max as get_iseq_body_stack_max;
179-
pub use rb_get_iseq_body_type as get_iseq_body_type;
179+
//pub use rb_get_iseq_body_type as get_iseq_body_type;
180180
pub use rb_get_iseq_flags_has_lead as get_iseq_flags_has_lead;
181181
pub use rb_get_iseq_flags_has_opt as get_iseq_flags_has_opt;
182182
pub use rb_get_iseq_flags_has_kw as get_iseq_flags_has_kw;
@@ -598,6 +598,12 @@ impl From<VALUE> for u16 {
598598
}
599599
}
600600

601+
pub unsafe fn cfp_env_has_escaped(cfp: *mut rb_control_frame_struct) -> bool {
602+
use crate::utils::IntoUsize;
603+
let ep = get_cfp_ep(cfp);
604+
0 != ep.offset(VM_ENV_DATA_INDEX_FLAGS as isize).read().0 & VM_ENV_FLAG_ESCAPED.as_usize()
605+
}
606+
601607
/// Produce a Ruby string from a Rust string slice
602608
pub fn rust_str_to_ruby(str: &str) -> VALUE {
603609
unsafe { rb_utf8_str_new(str.as_ptr() as *const _, str.len() as i64) }

0 commit comments

Comments
 (0)