Skip to content

Commit 9563b40

Browse files
committed
feat(native): store recorder with typed data
1 parent 1ae20c2 commit 9563b40

File tree

1 file changed

+65
-14
lines changed
  • gems/native-tracer/ext/native_tracer/src

1 file changed

+65
-14
lines changed

gems/native-tracer/ext/native_tracer/src/lib.rs

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
#![allow(clippy::missing_safety_doc)]
22

33
use std::{
4-
ffi::{CStr, CString},
4+
ffi::CStr,
55
mem::transmute,
6-
os::raw::{c_char, c_int, c_void},
7-
path::{Path, PathBuf},
6+
os::raw::{c_char, c_void},
7+
path::Path,
88
ptr,
9-
sync::{Mutex},
9+
sync::Mutex,
1010
};
1111

1212
use rb_sys::{
1313
rb_add_event_hook2, rb_remove_event_hook_with_data, rb_define_class,
14-
rb_define_alloc_func, rb_define_method, rb_obj_alloc,
15-
rb_ivar_set, rb_ivar_get, rb_intern, rb_ull2inum, rb_num2ull,
14+
rb_define_alloc_func, rb_define_method,
1615
rb_event_hook_flag_t::RUBY_EVENT_HOOK_FLAG_RAW_ARG,
1716
rb_event_flag_t, rb_trace_arg_t,
1817
rb_tracearg_event_flag, rb_tracearg_lineno, rb_tracearg_path,
@@ -21,23 +20,75 @@ use rb_sys::{
2120
};
2221
use runtime_tracing::{Tracer, Line};
2322

23+
#[repr(C)]
24+
struct RTypedData {
25+
_basic: [VALUE; 2],
26+
type_: *const rb_data_type_t,
27+
typed_flag: VALUE,
28+
data: *mut c_void,
29+
}
30+
31+
#[repr(C)]
32+
struct rb_data_type_function_struct {
33+
dmark: Option<unsafe extern "C" fn(*mut c_void)>,
34+
dfree: Option<unsafe extern "C" fn(*mut c_void)>,
35+
dsize: Option<unsafe extern "C" fn(*const c_void) -> usize>,
36+
dcompact: Option<unsafe extern "C" fn(*mut c_void)>,
37+
reserved: [*mut c_void; 1],
38+
}
39+
40+
#[repr(C)]
41+
struct rb_data_type_t {
42+
wrap_struct_name: *const c_char,
43+
function: rb_data_type_function_struct,
44+
parent: *const rb_data_type_t,
45+
data: *mut c_void,
46+
flags: VALUE,
47+
}
48+
49+
extern "C" {
50+
fn rb_data_typed_object_wrap(
51+
klass: VALUE,
52+
datap: *mut c_void,
53+
data_type: *const rb_data_type_t,
54+
) -> VALUE;
55+
fn rb_check_typeddata(obj: VALUE, data_type: *const rb_data_type_t) -> *mut c_void;
56+
}
57+
2458
struct Recorder {
2559
tracer: Mutex<Tracer>,
2660
active: bool,
2761
}
2862

29-
static mut PTR_IVAR: ID = 0;
63+
unsafe extern "C" fn recorder_free(ptr: *mut c_void) {
64+
if !ptr.is_null() {
65+
drop(Box::from_raw(ptr as *mut Recorder));
66+
}
67+
}
68+
69+
static mut RECORDER_TYPE: rb_data_type_t = rb_data_type_t {
70+
wrap_struct_name: b"Recorder\0".as_ptr() as *const c_char,
71+
function: rb_data_type_function_struct {
72+
dmark: None,
73+
dfree: Some(recorder_free),
74+
dsize: None,
75+
dcompact: None,
76+
reserved: [ptr::null_mut(); 1],
77+
},
78+
parent: ptr::null(),
79+
data: ptr::null_mut(),
80+
flags: 0 as VALUE,
81+
};
3082

3183
unsafe fn get_recorder(obj: VALUE) -> *mut Recorder {
32-
let val = rb_ivar_get(obj, PTR_IVAR);
33-
rb_num2ull(val) as *mut Recorder
84+
let ty = std::ptr::addr_of!(RECORDER_TYPE) as *const rb_data_type_t;
85+
rb_check_typeddata(obj, ty) as *mut Recorder
3486
}
3587

3688
unsafe extern "C" fn ruby_recorder_alloc(klass: VALUE) -> VALUE {
37-
let obj = rb_obj_alloc(klass);
3889
let recorder = Box::new(Recorder { tracer: Mutex::new(Tracer::new("ruby", &vec![])), active: false });
39-
rb_ivar_set(obj, PTR_IVAR, rb_ull2inum(Box::into_raw(recorder) as u64));
40-
obj
90+
let ty = std::ptr::addr_of!(RECORDER_TYPE) as *const rb_data_type_t;
91+
rb_data_typed_object_wrap(klass, Box::into_raw(recorder) as *mut c_void, ty)
4192
}
4293

4394
unsafe extern "C" fn ruby_recorder_initialize(_self: VALUE) -> VALUE {
@@ -89,7 +140,8 @@ unsafe extern "C" fn flush_trace(self_val: VALUE, out_dir: VALUE) -> VALUE {
89140
}
90141
}
91142
drop(Box::from_raw(recorder_ptr));
92-
rb_ivar_set(self_val, PTR_IVAR, rb_ull2inum(0));
143+
let rdata = self_val as *mut RTypedData;
144+
(*rdata).data = ptr::null_mut();
93145
rb_sys::Qnil.into()
94146
}
95147

@@ -130,7 +182,6 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) {
130182
#[no_mangle]
131183
pub extern "C" fn Init_codetracer_ruby_recorder() {
132184
unsafe {
133-
PTR_IVAR = rb_intern(b"@ptr\0".as_ptr() as *const c_char);
134185
let class = rb_define_class(b"RubyRecorder\0".as_ptr() as *const c_char, rb_cObject);
135186
rb_define_alloc_func(class, Some(ruby_recorder_alloc));
136187
let init_cb: unsafe extern "C" fn(VALUE) -> VALUE = ruby_recorder_initialize;

0 commit comments

Comments
 (0)