Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 36 additions & 24 deletions gems/native-tracer/ext/native_tracer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ struct Recorder {
inst_meth_id: ID,
parameters_id: ID,
class_id: ID,
struct_types: HashMap<String, runtime_tracing::TypeId>,
struct_type_versions: HashMap<String, usize>,
}

fn value_type_id(val: &ValueRecord) -> runtime_tracing::TypeId {
Expand Down Expand Up @@ -119,26 +119,26 @@ unsafe fn struct_value(
vals.push(to_value(recorder, *v, depth - 1, to_s_id));
}

let type_id = if let Some(id) = recorder.struct_types.get(class_name) {
*id
} else {
let field_types: Vec<FieldTypeRecord> = field_names
.iter()
.zip(&vals)
.map(|(n, v)| FieldTypeRecord {
name: (*n).to_string(),
type_id: value_type_id(v),
})
.collect();
let typ = TypeRecord {
kind: TypeKind::Struct,
lang_type: class_name.to_string(),
specific_info: TypeSpecificInfo::Struct { fields: field_types },
};
let id = recorder.tracer.ensure_raw_type_id(typ);
recorder.struct_types.insert(class_name.to_string(), id);
id
let version_entry = recorder
.struct_type_versions
.entry(class_name.to_string())
.or_insert(0);
let name_version = format!("{} (#{})", class_name, *version_entry);
*version_entry += 1;
let field_types: Vec<FieldTypeRecord> = field_names
.iter()
.zip(&vals)
.map(|(n, v)| FieldTypeRecord {
name: (*n).to_string(),
type_id: value_type_id(v),
})
.collect();
let typ = TypeRecord {
kind: TypeKind::Struct,
lang_type: name_version,
specific_info: TypeSpecificInfo::Struct { fields: field_types },
};
let type_id = recorder.tracer.ensure_raw_type_id(typ);

ValueRecord::Struct {
field_values: vals,
Expand Down Expand Up @@ -197,7 +197,7 @@ unsafe extern "C" fn ruby_recorder_alloc(klass: VALUE) -> VALUE {
inst_meth_id,
parameters_id,
class_id,
struct_types: HashMap::new(),
struct_type_versions: HashMap::new(),
});
let ty = std::ptr::addr_of!(RECORDER_TYPE) as *const rb_data_type_t;
rb_data_typed_object_wrap(klass, Box::into_raw(recorder) as *mut c_void, ty)
Expand Down Expand Up @@ -577,7 +577,13 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) {
String::from_utf8_lossy(std::slice::from_raw_parts(ptr as *const u8, len)).to_string()
};
let line = rb_num2long(line_val) as i64;
if path.contains("native_trace.rb") {
if path.contains("native_trace.rb")
|| path.contains("lib/ruby")
|| path.contains("recorder.rb")
|| path.contains("trace.rb")
|| path.contains("gems/")
|| path.starts_with("<internal:")
{
return;
}

Expand All @@ -594,9 +600,9 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) {
let mid_sym = rb_tracearg_callee_id(arg);
let mid = rb_sym2id(mid_sym);
let defined_class = rb_funcall(self_val, recorder.class_id, 0);
let mut args = Vec::new();
if !NIL_P(binding) {
args = record_parameters(recorder, binding, defined_class, mid, true);
// ensure parameter types are registered before self
let _ = record_parameters(recorder, binding, defined_class, mid, false);
}
let class_name = cstr_to_string(rb_obj_classname(self_val)).unwrap_or_else(|| "Object".to_string());
let text = value_to_string_safe(self_val, recorder.to_s_id).unwrap_or_default();
Expand All @@ -606,6 +612,12 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) {
.tracer
.register_variable_with_full_value("self", self_rec.clone());

let mut args = if NIL_P(binding) {
Vec::new()
} else {
record_parameters(recorder, binding, defined_class, mid, true)
};

args.insert(0, recorder.tracer.arg("self", self_rec));
recorder.tracer.register_step(Path::new(&path), Line(line));
let name_c = rb_id2name(mid);
Expand Down
6 changes: 3 additions & 3 deletions gems/pure-ruby-tracer/lib/recorder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def to_data_for_json
end


ValueRecord = Struct.new(:kind, :type_id, :i, :b, :text, :r, :msg, :elements, :is_slice, :field_values, keyword_init: true) do
ValueRecord = Struct.new(:kind, :type_id, :i, :f, :b, :text, :r, :msg, :elements, :is_slice, :field_values, keyword_init: true) do
def to_data_for_json
res = to_h.compact
if !res[:elements].nil?
Expand Down Expand Up @@ -402,7 +402,7 @@ def to_value(v, depth=10)
end
when Range
struct_value('Range', ['begin', 'end'], [v.begin, v.end], depth)
when defined?(Set) && v.is_a?(Set)
when ->(o) { defined?(Set) && o.is_a?(Set) }
if v.size > MAX_COUNT
NOT_SUPPORTED_VALUE
else
Expand All @@ -414,7 +414,7 @@ def to_value(v, depth=10)
struct_value('Regexp', ['source', 'options'], [v.source, v.options], depth)
when Struct
struct_value(v.class.name, v.members.map(&:to_s), v.values, depth)
when defined?(OpenStruct) && v.is_a?(OpenStruct)
when ->(o) { defined?(OpenStruct) && o.is_a?(OpenStruct) }
h = v.to_h
pairs = h.map do |k, val|
struct_value('Pair', ['k', 'v'], [k, val], depth)
Expand Down
Loading
Loading