|
7 | 7 | #![allow(clippy::match_like_matches_macro)] |
8 | 8 | use crate::{ |
9 | 9 | backend::lir::C_ARG_OPNDS, |
10 | | - cast::IntoUsize, codegen::local_idx_to_ep_offset, cruby::*, invariants::{self, has_singleton_class_of}, payload::{get_or_create_iseq_payload, IseqPayload}, options::{debug, get_option, DumpHIR}, state::ZJITState, json::Json |
| 10 | + cast::IntoUsize, codegen::local_idx_to_ep_offset, cruby::*, invariants::{self, has_singleton_class_of}, payload::{get_or_create_iseq_payload, IseqPayload}, options::{debug, get_option, DumpHIR}, state::ZJITState, json::Json, |
| 11 | + state, |
11 | 12 | }; |
12 | 13 | use std::{ |
13 | | - cell::RefCell, collections::{BTreeSet, HashMap, HashSet, VecDeque}, ffi::{c_void, c_uint, c_int, CStr}, fmt::Display, mem::{align_of, size_of}, ptr, slice::Iter |
| 14 | + cell::RefCell, collections::{BTreeSet, HashMap, HashSet, VecDeque}, ffi::{c_void, c_uint, c_int, CStr}, fmt::Display, mem::{align_of, size_of}, ptr, slice::Iter, |
| 15 | + sync::atomic::Ordering, |
14 | 16 | }; |
15 | 17 | use crate::hir_type::{Type, types}; |
16 | 18 | use crate::hir_effect::{Effect, abstract_heaps, effects}; |
@@ -529,6 +531,7 @@ pub enum SideExitReason { |
529 | 531 | SplatKwNotNilOrHash, |
530 | 532 | SplatKwPolymorphic, |
531 | 533 | SplatKwNotProfiled, |
| 534 | + DirectiveInduced, |
532 | 535 | } |
533 | 536 |
|
534 | 537 | #[derive(Debug, Clone, Copy)] |
@@ -6547,6 +6550,7 @@ pub enum ParseError { |
6547 | 6550 | MalformedIseq(u32), // insn_idx into iseq_encoded |
6548 | 6551 | Validation(ValidationError), |
6549 | 6552 | NotAllowed, |
| 6553 | + DirectiveInduced, |
6550 | 6554 | } |
6551 | 6555 |
|
6552 | 6556 | /// Return the number of locals in the current ISEQ (includes parameters) |
@@ -7077,7 +7081,32 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { |
7077 | 7081 | } |
7078 | 7082 | YARVINSN_opt_getconstant_path => { |
7079 | 7083 | let ic = get_arg(pc, 0).as_ptr(); |
7080 | | - state.stack_push(fun.push_insn(block, Insn::GetConstantPath { ic, state: exit_id })); |
| 7084 | + let get_const_path = fun.push_insn(block, Insn::GetConstantPath { ic, state: exit_id }); |
| 7085 | + state.stack_push(get_const_path); |
| 7086 | + |
| 7087 | + // Check for `::RubyVM::ZJIT` for directives |
| 7088 | + unsafe { |
| 7089 | + let mut current_segment = (*ic).segments; |
| 7090 | + let mut segments = [ID(0); 4]; |
| 7091 | + for segment in segments.iter_mut() { |
| 7092 | + *segment = current_segment.read(); |
| 7093 | + if *segment == ID(0) { |
| 7094 | + break; |
| 7095 | + } |
| 7096 | + current_segment = current_segment.add(1); |
| 7097 | + } |
| 7098 | + if [ID!(NULL), ID!(RubyVM), ID!(ZJIT), ID(0)] == segments { |
| 7099 | + debug_assert_ne!(ID!(NULL), ID(0)); |
| 7100 | + let ruby_vm_mod = rb_const_lookup(rb_cObject, ID!(RubyVM)); |
| 7101 | + if !ruby_vm_mod.is_null() && (*ruby_vm_mod).value == rb_cRubyVM { |
| 7102 | + let zjit_module = VALUE(state::ZJIT_MODULE.load(Ordering::Relaxed)); |
| 7103 | + let lookedup_module = rb_const_lookup(rb_cRubyVM, ID!(ZJIT)); |
| 7104 | + if !lookedup_module.is_null() && (*lookedup_module).value == zjit_module { |
| 7105 | + fun.insn_types[get_const_path.0] = Type::from_value(zjit_module); |
| 7106 | + } |
| 7107 | + } |
| 7108 | + } |
| 7109 | + } |
7081 | 7110 | } |
7082 | 7111 | YARVINSN_branchunless | YARVINSN_branchunless_without_ints => { |
7083 | 7112 | if opcode == YARVINSN_branchunless { |
@@ -7538,6 +7567,28 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { |
7538 | 7567 | break; // End the block |
7539 | 7568 | } |
7540 | 7569 | let argc = unsafe { vm_ci_argc((*cd).ci) }; |
| 7570 | + let mid = unsafe { rb_vm_ci_mid(call_info) }; |
| 7571 | + |
| 7572 | + // Check for calls to directives |
| 7573 | + if argc == 0 |
| 7574 | + && (mid == ID!(induce_side_exit_bang) || mid == ID!(induce_compile_failure_bang)) |
| 7575 | + && fun.type_of(state.stack_top()?) |
| 7576 | + .ruby_object() |
| 7577 | + .is_some_and(|obj| obj == VALUE(state::ZJIT_MODULE.load(Ordering::Relaxed))) |
| 7578 | + { |
| 7579 | + |
| 7580 | + if mid == ID!(induce_side_exit_bang) |
| 7581 | + && state::zjit_module_method_match_serial(ID!(induce_side_exit_bang), &state::INDUCE_SIDE_EXIT_SERIAL) |
| 7582 | + { |
| 7583 | + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::DirectiveInduced }); |
| 7584 | + break; // End the block |
| 7585 | + } |
| 7586 | + if mid == ID!(induce_compile_failure_bang) |
| 7587 | + && state::zjit_module_method_match_serial(ID!(induce_compile_failure_bang), &state::INDUCE_COMPILE_FAILURE_SERIAL) |
| 7588 | + { |
| 7589 | + return Err(ParseError::DirectiveInduced); |
| 7590 | + } |
| 7591 | + } |
7541 | 7592 |
|
7542 | 7593 | { |
7543 | 7594 | fn new_branch_block( |
|
0 commit comments