|
1 | | -use cairo_lang_casm::cell_expression::{CellExpression, CellOperator}; |
2 | | -use cairo_lang_casm::operand::DerefOrImmediate; |
| 1 | +use cairo_lang_casm::cell_expression::CellExpression; |
3 | 2 | use cairo_lang_sierra::extensions::ConcreteLibfunc; |
4 | 3 | use cairo_lang_sierra::extensions::structure::{ |
5 | 4 | ConcreteStructBoxedDeconstructLibfunc, StructConcreteLibfunc, |
6 | 5 | }; |
7 | | -use cairo_lang_utils::casts::IntoOrPanic; |
| 6 | +use cairo_lang_sierra::ids::ConcreteTypeId; |
| 7 | +use cairo_lang_sierra_type_size::TypeSizeMap; |
8 | 8 |
|
9 | 9 | use super::{CompiledInvocation, CompiledInvocationBuilder, InvocationError}; |
10 | 10 | use crate::references::ReferenceExpression; |
@@ -58,28 +58,33 @@ fn build_struct_boxed_deconstruct( |
58 | 58 | libfunc: &ConcreteStructBoxedDeconstructLibfunc, |
59 | 59 | builder: CompiledInvocationBuilder<'_>, |
60 | 60 | ) -> Result<CompiledInvocation, InvocationError> { |
61 | | - let [cell] = builder.try_get_single_cells()?; |
62 | | - let Some((boxed_struct_addr, orig_offset)) = cell.to_deref_with_offset() else { |
63 | | - return Err(InvocationError::InvalidReferenceExpressionForArgument); |
64 | | - }; |
65 | | - let mut next_member_box = cell.clone(); |
66 | | - let mut outputs = vec![]; |
67 | | - let mut current_offset = orig_offset.into_or_panic::<i16>(); |
68 | | - for member_ty in &libfunc.members { |
69 | | - outputs.push(next_member_box); |
70 | | - let member_size = *builder |
71 | | - .program_info |
72 | | - .type_sizes |
73 | | - .get(member_ty) |
| 61 | + let [input_ptr] = builder.try_get_single_cells()?; |
| 62 | + let outputs = |
| 63 | + boxed_members_cell_exprs(builder.program_info.type_sizes, &libfunc.members, input_ptr) |
74 | 64 | .ok_or(InvocationError::InvalidReferenceExpressionForArgument)?; |
75 | | - current_offset += member_size; |
76 | | - next_member_box = CellExpression::BinOp { |
77 | | - op: CellOperator::Add, |
78 | | - a: boxed_struct_addr, |
79 | | - b: DerefOrImmediate::Immediate(current_offset.into()), |
80 | | - }; |
81 | | - } |
82 | | - |
83 | 65 | Ok(builder |
84 | 66 | .build_only_reference_changes(outputs.into_iter().map(ReferenceExpression::from_cell))) |
85 | 67 | } |
| 68 | + |
| 69 | +/// Returns a vector of cell expressions representing the memory addresses of the unboxed members of |
| 70 | +/// a boxed struct. |
| 71 | +/// |
| 72 | +/// Note: All failures returning `None` in this function should never actually occur assuming the |
| 73 | +/// original boxed type containing recursively all other types (through enums or structs), had an |
| 74 | +/// `orig_offset` offset of 0, as all internal offsets are bounded by the size of the struct itself, |
| 75 | +/// which is bounded by `i16::MAX`. |
| 76 | +fn boxed_members_cell_exprs( |
| 77 | + type_sizes: &TypeSizeMap, |
| 78 | + member_tys: &[ConcreteTypeId], |
| 79 | + input_ptr: &CellExpression, |
| 80 | +) -> Option<Vec<CellExpression>> { |
| 81 | + let (boxed_struct_ptr, orig_offset) = input_ptr.to_deref_with_offset()?; |
| 82 | + let mut outputs = vec![]; |
| 83 | + let mut current_offset = orig_offset.try_into().ok()?; |
| 84 | + for member_ty in member_tys { |
| 85 | + outputs.push(CellExpression::add_with_const(boxed_struct_ptr, current_offset)); |
| 86 | + let member_size = *type_sizes.get(member_ty)?; |
| 87 | + current_offset = current_offset.checked_add(member_size)?; |
| 88 | + } |
| 89 | + Some(outputs) |
| 90 | +} |
0 commit comments