|
1 | 1 | //! This module is responsible for marking/moving objects on GC. |
2 | 2 |
|
3 | 3 | use std::{ffi::c_void, ops::Range}; |
4 | | -use crate::codegen::IseqCallRef; |
5 | | -use crate::stats::CompileError; |
6 | | -use crate::{cruby::*, profile::IseqProfile, state::ZJITState, stats::with_time_stat, virtualmem::CodePtr}; |
| 4 | +use crate::{cruby::*, state::ZJITState, stats::with_time_stat, virtualmem::CodePtr}; |
| 5 | +use crate::payload::{IseqPayload, get_or_create_iseq_payload, payload_ptr_as_mut}; |
7 | 6 | use crate::stats::Counter::gc_time_ns; |
8 | 7 | use crate::state::gc_mark_raw_samples; |
9 | 8 |
|
10 | | -/// This is all the data ZJIT stores on an ISEQ. We mark objects in this struct on GC. |
11 | | -#[derive(Debug)] |
12 | | -pub struct IseqPayload { |
13 | | - /// Compilation status of the ISEQ. It has the JIT code address of the first block if Compiled. |
14 | | - pub status: IseqStatus, |
15 | | - |
16 | | - /// Type information of YARV instruction operands |
17 | | - pub profile: IseqProfile, |
18 | | - |
19 | | - /// GC offsets of the JIT code. These are the addresses of objects that need to be marked. |
20 | | - pub gc_offsets: Vec<CodePtr>, |
21 | | - |
22 | | - /// JIT-to-JIT calls in the ISEQ. The IseqPayload's ISEQ is the caller of it. |
23 | | - pub iseq_calls: Vec<IseqCallRef>, |
24 | | -} |
25 | | - |
26 | | -impl IseqPayload { |
27 | | - fn new(iseq_size: u32) -> Self { |
28 | | - Self { |
29 | | - status: IseqStatus::NotCompiled, |
30 | | - profile: IseqProfile::new(iseq_size), |
31 | | - gc_offsets: vec![], |
32 | | - iseq_calls: vec![], |
33 | | - } |
34 | | - } |
35 | | -} |
36 | | - |
37 | | -/// Set of CodePtrs for an ISEQ |
38 | | -#[derive(Clone, Debug, PartialEq)] |
39 | | -pub struct IseqCodePtrs { |
40 | | - /// Entry for the interpreter |
41 | | - pub start_ptr: CodePtr, |
42 | | - /// Entries for JIT-to-JIT calls |
43 | | - pub jit_entry_ptrs: Vec<CodePtr>, |
44 | | -} |
45 | | - |
46 | | -#[derive(Debug, PartialEq)] |
47 | | -pub enum IseqStatus { |
48 | | - Compiled(IseqCodePtrs), |
49 | | - CantCompile(CompileError), |
50 | | - NotCompiled, |
51 | | -} |
52 | | - |
53 | | -/// Get a pointer to the payload object associated with an ISEQ. Create one if none exists. |
54 | | -pub fn get_or_create_iseq_payload_ptr(iseq: IseqPtr) -> *mut IseqPayload { |
55 | | - type VoidPtr = *mut c_void; |
56 | | - |
57 | | - unsafe { |
58 | | - let payload = rb_iseq_get_zjit_payload(iseq); |
59 | | - if payload.is_null() { |
60 | | - // Allocate a new payload with Box and transfer ownership to the GC. |
61 | | - // We drop the payload with Box::from_raw when the GC frees the ISEQ and calls us. |
62 | | - // NOTE(alan): Sometimes we read from an ISEQ without ever writing to it. |
63 | | - // We allocate in those cases anyways. |
64 | | - let iseq_size = get_iseq_encoded_size(iseq); |
65 | | - let new_payload = IseqPayload::new(iseq_size); |
66 | | - let new_payload = Box::into_raw(Box::new(new_payload)); |
67 | | - rb_iseq_set_zjit_payload(iseq, new_payload as VoidPtr); |
68 | | - |
69 | | - new_payload |
70 | | - } else { |
71 | | - payload as *mut IseqPayload |
72 | | - } |
73 | | - } |
74 | | -} |
75 | | - |
76 | | -/// Get the payload object associated with an ISEQ. Create one if none exists. |
77 | | -pub fn get_or_create_iseq_payload(iseq: IseqPtr) -> &'static mut IseqPayload { |
78 | | - let payload_non_null = get_or_create_iseq_payload_ptr(iseq); |
79 | | - payload_ptr_as_mut(payload_non_null) |
80 | | -} |
81 | | - |
82 | | -/// Convert an IseqPayload pointer to a mutable reference. Only one reference |
83 | | -/// should be kept at a time. |
84 | | -fn payload_ptr_as_mut(payload_ptr: *mut IseqPayload) -> &'static mut IseqPayload { |
85 | | - // SAFETY: we should have the VM lock and all other Ruby threads should be asleep. So we have |
86 | | - // exclusive mutable access. |
87 | | - // Hmm, nothing seems to stop calling this on the same |
88 | | - // iseq twice, though, which violates aliasing rules. |
89 | | - unsafe { payload_ptr.as_mut() }.unwrap() |
90 | | -} |
91 | | - |
92 | 9 | /// GC callback for marking GC objects in the per-ISEQ payload. |
93 | 10 | #[unsafe(no_mangle)] |
94 | 11 | pub extern "C" fn rb_zjit_iseq_mark(payload: *mut c_void) { |
|
0 commit comments