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
301 changes: 49 additions & 252 deletions ghostscope-dwarf/src/analyzer/type_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ use super::DwarfAnalyzer;
use crate::{
indexable_element_layout, member_layout, semantics::PlanError, strip_type_aliases,
CompilationUnitMetadata, CuId, MemberLayout, ModuleId, PcContext, ProjectedValueRead,
ProjectedValueStep, ResolvedType, Result, SemanticType, SourceLanguage, TypeId, TypeIdentity,
TypeInfo, TypeLayoutError, TypeOrigin, TypeProjection, TypeProjectionLayout,
ValueAdapterOutcome, ValueAdapterReport, ValueAdapterStage, ValueCapturePlan,
ValueNestedFieldPlan, ValueNestedPlan, ValueNestedVariantCondition,
ValueNestedVariantFieldPlan, ValuePresentation, ValueReadPlan, ValueReadPlanOptions,
VariableAccessSegment, VariableReadPlan, VariantSelector,
ProjectedValueStep, ResolvedType, Result, SemanticType, TypeId, TypeIdentity, TypeInfo,
TypeLayoutError, TypeOrigin, TypeProjection, TypeProjectionLayout, ValueAdapterOutcome,
ValueAdapterReport, ValueAdapterStage, ValueCapturePlan, ValueNestedFieldPlan, ValueNestedPlan,
ValueReadPlan, ValueReadPlanOptions, VariableAccessSegment, VariableReadPlan,
};
use std::path::Path;

Expand Down Expand Up @@ -340,7 +338,7 @@ impl DwarfAnalyzer {
let report =
self.explain_value_read_plan_with_options(current, type_module_path, options)?;
match report.outcome {
ValueAdapterOutcome::NotApplicable => Ok(self.rust_aggregate_value_read_plan(
ValueAdapterOutcome::NotApplicable => Ok(self.aggregate_value_read_plan(
current,
type_module_path,
0,
Expand Down Expand Up @@ -503,7 +501,7 @@ impl DwarfAnalyzer {
let plan = match self.value_read_plan_shallow(current, type_module_path) {
Ok(ShallowValueReadPlan::Applied(plan)) => *plan,
Ok(ShallowValueReadPlan::NotApplicable) => {
return self.rust_aggregate_value_read_plan(
return self.aggregate_value_read_plan(
current,
type_module_path,
depth,
Expand Down Expand Up @@ -532,15 +530,16 @@ impl DwarfAnalyzer {
))
}

fn rust_aggregate_value_read_plan(
fn aggregate_value_read_plan(
&self,
current: &ResolvedType,
type_module_path: Option<&Path>,
depth: usize,
max_nesting_depth: usize,
ancestors: &mut Vec<TypeId>,
) -> Option<ValueReadPlan> {
let plan = self.rust_aggregate_value_read_plan_shallow(current, type_module_path)?;
let plan =
crate::language::build_aggregate_value_read_plan(self, current, type_module_path)?;
let plan = self.enrich_nested_value_read_plan(
current,
plan,
Expand All @@ -552,231 +551,6 @@ impl DwarfAnalyzer {
plan.nested.is_some().then_some(plan)
}

fn rust_aggregate_value_read_plan_shallow(
&self,
current: &ResolvedType,
type_module_path: Option<&Path>,
) -> Option<ValueReadPlan> {
if current.origin.as_ref().map(|origin| origin.language) != Some(SourceLanguage::Rust) {
return None;
}
let fields = match strip_type_aliases(&current.summary) {
TypeInfo::StructType { members, .. } => {
let mut fields = Vec::with_capacity(members.len());
for member in members {
let projection = match self.project_resolved_type(
current,
&VariableAccessSegment::Field(member.name.clone()),
type_module_path,
) {
Ok(projection) => projection,
Err(error) => {
tracing::debug!(
target: "ghostscope_dwarf::value_adapter",
type_name = current.summary.type_name(),
field = member.name,
%error,
"Rust aggregate could not form a nested field projection; using DWARF presentation"
);
return None;
}
};
let TypeProjectionLayout::Member { offset } = projection.layout else {
return None;
};
if offset != member.offset {
return None;
}
fields.push(ProjectedValueRead {
steps: vec![ProjectedValueStep::Member { offset }],
resolved_type: projection.resolved_type,
});
}
fields
}
TypeInfo::VariantType { .. } => Vec::new(),
_ => return None,
};

Some(ValueReadPlan::new(
current.clone(),
ValuePresentation::Dwarf,
ValueCapturePlan::InlineView {
output_type: strip_type_aliases(&current.summary).clone(),
fields,
},
))
}

fn rust_variant_nested_plan(
&self,
current: &ResolvedType,
type_module_path: Option<&Path>,
depth: usize,
max_nesting_depth: usize,
ancestors: &mut Vec<TypeId>,
) -> Option<ValueNestedPlan> {
let current_id = current.identity.layout_dwarf_id()?;
let TypeInfo::VariantType { variant_parts, .. } = strip_type_aliases(&current.summary)
else {
return None;
};
let mut fields = Vec::new();

for (part_index, part) in variant_parts.iter().enumerate() {
for (variant_index, variant) in part.variants.iter().enumerate() {
let Some(condition) = Self::nested_variant_condition(part, variant_index) else {
continue;
};
for (member_index, member) in variant.members.iter().enumerate() {
let wrapper = match self.variant_member_resolved_type(
current_id,
part_index,
variant_index,
member_index,
) {
Ok(Some(wrapper)) => wrapper,
Ok(None) => continue,
Err(error) => {
tracing::debug!(
target: "ghostscope_dwarf::value_adapter",
type_name = current.summary.type_name(),
part_index,
variant_index,
member_index,
%error,
"Rust enum payload identity could not be resolved; using DWARF presentation"
);
continue;
}
};
if wrapper.summary != member.member_type {
tracing::debug!(
target: "ghostscope_dwarf::value_adapter",
type_name = current.summary.type_name(),
variant = member.name,
"Rust enum payload identity did not match its parsed member type; using DWARF presentation"
);
continue;
}
let TypeInfo::StructType {
members: payload_fields,
..
} = strip_type_aliases(&wrapper.summary)
else {
continue;
};

for (payload_field_index, payload_field) in payload_fields.iter().enumerate() {
let projection = match self.project_resolved_type(
&wrapper,
&VariableAccessSegment::Field(payload_field.name.clone()),
type_module_path,
) {
Ok(projection) => projection,
Err(error) => {
tracing::debug!(
target: "ghostscope_dwarf::value_adapter",
type_name = current.summary.type_name(),
variant = member.name,
field = payload_field.name,
%error,
"Rust enum payload field could not be projected; using DWARF presentation"
);
continue;
}
};
let TypeProjectionLayout::Member { offset } = projection.layout else {
continue;
};
if offset != payload_field.offset {
continue;
}
let Some(value) = self.try_nested_value_read_plan(
&projection.resolved_type,
type_module_path,
depth + 1,
max_nesting_depth,
ancestors,
) else {
continue;
};
fields.push(ValueNestedVariantFieldPlan {
part_index,
variant_index,
member_index,
payload_field_index,
steps: vec![
ProjectedValueStep::Member {
offset: member.offset,
},
ProjectedValueStep::Member { offset },
],
condition: condition.clone(),
value: Box::new(value),
});
}
}
}
}

(!fields.is_empty()).then_some(ValueNestedPlan::Variant { fields })
}

fn nested_variant_condition(
part: &crate::VariantPart,
variant_index: usize,
) -> Option<ValueNestedVariantCondition> {
let variant = part.variants.get(variant_index)?;
let Some(discriminant) = &part.discriminant else {
let selected = part
.variants
.iter()
.position(|variant| matches!(variant.selector, VariantSelector::Default))
.unwrap_or(0);
return (selected == variant_index).then_some(ValueNestedVariantCondition::Always);
};

match &variant.selector {
VariantSelector::Ranges(ranges) if !ranges.is_empty() => {
Some(ValueNestedVariantCondition::Discriminant {
member: discriminant.clone(),
ranges: ranges.clone(),
inverted: false,
})
}
VariantSelector::Ranges(_) => None,
VariantSelector::Default => {
let first_default = part
.variants
.iter()
.position(|variant| matches!(variant.selector, VariantSelector::Default))?;
if first_default != variant_index {
return None;
}
let ranges = part
.variants
.iter()
.filter_map(|variant| match &variant.selector {
VariantSelector::Ranges(ranges) => Some(ranges.as_slice()),
VariantSelector::Default => None,
})
.flatten()
.cloned()
.collect::<Vec<_>>();
if ranges.is_empty() {
Some(ValueNestedVariantCondition::Always)
} else {
Some(ValueNestedVariantCondition::Discriminant {
member: discriminant.clone(),
ranges,
inverted: true,
})
}
}
}
}

fn enrich_nested_value_read_plan(
&self,
current: &ResolvedType,
Expand All @@ -797,7 +571,26 @@ impl DwarfAnalyzer {
ancestors.push(type_id);
}

let nested = match &plan.capture {
let language_nested = {
let mut resolve_nested = |child: &ResolvedType| {
self.try_nested_value_read_plan(
child,
type_module_path,
depth + 1,
max_nesting_depth,
ancestors,
)
};
crate::language::build_nested_value_read_plan(
self,
current,
&plan.capture,
type_module_path,
&mut resolve_nested,
)
};

let mut build_generic_nested = || match &plan.capture {
ValueCapturePlan::ProjectedValue { value } => self
.try_nested_value_read_plan(
&value.resolved_type,
Expand All @@ -809,22 +602,6 @@ impl DwarfAnalyzer {
.map(|value| ValueNestedPlan::ProjectedValue {
value: Box::new(value),
}),
ValueCapturePlan::InlineView {
output_type,
fields: _,
} if matches!(
strip_type_aliases(output_type),
TypeInfo::VariantType { .. }
) =>
{
self.rust_variant_nested_plan(
current,
type_module_path,
depth,
max_nesting_depth,
ancestors,
)
}
ValueCapturePlan::InlineView { fields, .. } => {
let nested_fields = fields
.iter()
Expand Down Expand Up @@ -890,6 +667,10 @@ impl DwarfAnalyzer {
| ValueCapturePlan::IndirectHashTable { .. }
| ValueCapturePlan::IndirectBTree { .. } => None,
};
let nested = match language_nested {
crate::language::NestedValuePlanResolution::Handled(nested) => nested,
crate::language::NestedValuePlanResolution::NotApplicable => build_generic_nested(),
};

if current_id.is_some() {
ancestors.pop();
Expand Down Expand Up @@ -1241,6 +1022,22 @@ impl crate::language::ValueAdapterContext for DwarfAnalyzer {
DwarfAnalyzer::template_type_parameter(self, type_id, index)
}

fn variant_member_resolved_type(
&self,
current: TypeId,
part_index: usize,
variant_index: usize,
member_index: usize,
) -> Result<Option<ResolvedType>> {
DwarfAnalyzer::variant_member_resolved_type(
self,
current,
part_index,
variant_index,
member_index,
)
}

fn type_alignment(&self, type_id: TypeId) -> Result<Option<u64>> {
DwarfAnalyzer::type_alignment(self, type_id)
}
Expand Down
8 changes: 8 additions & 0 deletions ghostscope-dwarf/src/language/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ pub(crate) trait ValueAdapterContext {
index: usize,
) -> Result<Option<ResolvedType>>;

fn variant_member_resolved_type(
&self,
current: TypeId,
part_index: usize,
variant_index: usize,
member_index: usize,
) -> Result<Option<ResolvedType>>;

fn type_alignment(&self, type_id: TypeId) -> Result<Option<u64>>;

fn tuple_member_layout(
Expand Down
Loading
Loading