1use std::{
10 cell::{Cell, RefCell},
11 collections::BTreeSet,
12 marker::PhantomData,
13 rc::Rc,
14};
15
16use crate::{
17 error::Exception,
18 transforms::compile::CompiledState,
19 utils::{StateSnapshot, Updatable},
20 Array,
21};
22
23use super::{Closure, Compiled, Guarded, StateLayout, VectorArray};
24
25pub fn compile_with_state<F, U, A, O, E>(
28 f: F,
29 shapeless: impl Into<Option<bool>>,
30) -> impl for<'a> FnMut(&mut U, F::Args<'a>) -> Result<O, Exception>
31where
32 F: CompileWithState<U, A, O, E> + 'static,
33 U: Updatable,
34{
35 let shapeless = shapeless.into().unwrap_or(false);
36 let mut compiled = f.compile(shapeless);
37 move |state, args| compiled.call_mut(state, args)
38}
39
40pub trait CompileWithState<U, A, O, E> {
52 type Args<'a>;
58
59 fn compile(
61 self,
62 shapeless: bool,
63 ) -> impl for<'args> CallMutWithState<U, Self::Args<'args>, O, E>;
64}
65
66impl<F, U> CompileWithState<U, &[Array], Vec<Array>, ()> for F
67where
68 F: FnMut(&mut U, &[Array]) -> Vec<Array> + 'static,
69 U: Updatable,
70{
71 type Args<'a> = &'a [Array];
72
73 fn compile(
74 self,
75 shapeless: bool,
76 ) -> impl for<'args> CallMutWithState<U, Self::Args<'args>, Vec<Array>, ()> {
77 let state = CompiledState::new(self, shapeless);
78 Compiled::<F, _> {
79 f_marker: PhantomData,
80 state,
81 }
82 }
83}
84
85impl<F, U> CompileWithState<U, &Array, Array, ()> for F
86where
87 F: FnMut(&mut U, &Array) -> Array + 'static,
88 U: Updatable,
89{
90 type Args<'a> = &'a Array;
91
92 fn compile(
93 mut self,
94 shapeless: bool,
95 ) -> impl for<'args> CallMutWithState<U, Self::Args<'args>, Array, ()> {
96 let f = move |state: &mut U, args: &[Array]| -> Vec<Array> {
97 let result = (self)(state, &args[0]);
98 vec![result]
99 };
100 let state = CompiledState::new(f, shapeless);
101 Compiled::<F, _> {
102 f_marker: PhantomData,
103 state,
104 }
105 }
106}
107
108impl<F, U> CompileWithState<U, (&Array, &Array), Array, ()> for F
109where
110 F: FnMut(&mut U, (&Array, &Array)) -> Array + 'static,
111 U: Updatable,
112{
113 type Args<'a> = (&'a Array, &'a Array);
114
115 fn compile(
116 mut self,
117 shapeless: bool,
118 ) -> impl for<'args> CallMutWithState<U, Self::Args<'args>, Array, ()> {
119 let f = move |state: &mut U, args: &[Array]| -> Vec<Array> {
120 let result = (self)(state, (&args[0], &args[1]));
121 vec![result]
122 };
123 let state = CompiledState::new(f, shapeless);
124 Compiled::<F, _> {
125 f_marker: PhantomData,
126 state,
127 }
128 }
129}
130
131impl<F, U> CompileWithState<U, (&Array, &Array, &Array), Array, ()> for F
132where
133 F: FnMut(&mut U, (&Array, &Array, &Array)) -> Array + 'static,
134 U: Updatable,
135{
136 type Args<'a> = (&'a Array, &'a Array, &'a Array);
137
138 fn compile(
139 mut self,
140 shapeless: bool,
141 ) -> impl for<'args> CallMutWithState<U, Self::Args<'args>, Array, ()> {
142 let f = move |state: &mut U, args: &[Array]| -> Vec<Array> {
143 let result = (self)(state, (&args[0], &args[1], &args[2]));
144 vec![result]
145 };
146 let state = CompiledState::new(f, shapeless);
147 Compiled::<F, _> {
148 f_marker: PhantomData,
149 state,
150 }
151 }
152}
153
154impl<F, U> CompileWithState<U, &[Array], Vec<Array>, Exception> for F
155where
156 F: FnMut(&mut U, &[Array]) -> Result<Vec<Array>, Exception> + 'static,
157 U: Updatable,
158{
159 type Args<'a> = &'a [Array];
160
161 fn compile(
162 self,
163 shapeless: bool,
164 ) -> impl for<'args> CallMutWithState<U, Self::Args<'args>, Vec<Array>, Exception> {
165 let state = CompiledState::new(self, shapeless);
166 Compiled::<F, _> {
167 f_marker: PhantomData,
168 state,
169 }
170 }
171}
172
173impl<F, U> CompileWithState<U, &Array, Array, Exception> for F
174where
175 F: FnMut(&mut U, &Array) -> Result<Array, Exception> + 'static,
176 U: Updatable,
177{
178 type Args<'a> = &'a Array;
179
180 fn compile(
181 mut self,
182 shapeless: bool,
183 ) -> impl for<'args> CallMutWithState<U, Self::Args<'args>, Array, Exception> {
184 let f = move |state: &mut U, args: &[Array]| -> Result<Vec<Array>, Exception> {
185 let result = (self)(state, &args[0])?;
186 Ok(vec![result])
187 };
188 let state = CompiledState::new(f, shapeless);
189 Compiled::<F, _> {
190 f_marker: PhantomData,
191 state,
192 }
193 }
194}
195
196impl<F, U> CompileWithState<U, (&Array, &Array), Array, Exception> for F
197where
198 F: FnMut(&mut U, (&Array, &Array)) -> Result<Array, Exception> + 'static,
199 U: Updatable,
200{
201 type Args<'a> = (&'a Array, &'a Array);
202
203 fn compile(
204 mut self,
205 shapeless: bool,
206 ) -> impl for<'args> CallMutWithState<U, Self::Args<'args>, Array, Exception> {
207 let f = move |state: &mut U, args: &[Array]| -> Result<Vec<Array>, Exception> {
208 let result = (self)(state, (&args[0], &args[1]))?;
209 Ok(vec![result])
210 };
211 let state = CompiledState::new(f, shapeless);
212 Compiled::<F, _> {
213 f_marker: PhantomData,
214 state,
215 }
216 }
217}
218
219impl<F, U> CompileWithState<U, (&Array, &Array, &Array), Array, Exception> for F
220where
221 F: FnMut(&mut U, (&Array, &Array, &Array)) -> Result<Array, Exception> + 'static,
222 U: Updatable,
223{
224 type Args<'a> = (&'a Array, &'a Array, &'a Array);
225
226 fn compile(
227 mut self,
228 shapeless: bool,
229 ) -> impl for<'args> CallMutWithState<U, Self::Args<'args>, Array, Exception> {
230 let f = move |state: &mut U, args: &[Array]| -> Result<Vec<Array>, Exception> {
231 let result = (self)(state, (&args[0], &args[1], &args[2]))?;
232 Ok(vec![result])
233 };
234 let state = CompiledState::new(f, shapeless);
235 Compiled::<F, _> {
236 f_marker: PhantomData,
237 state,
238 }
239 }
240}
241
242pub trait CallMutWithState<U, A, O, E> {
244 fn call_mut(&mut self, state: &mut U, args: A) -> Result<O, Exception>;
246}
247
248impl<U, F, G> CallMutWithState<U, &[Array], Vec<Array>, ()> for Compiled<F, G>
249where
250 F: FnMut(&mut U, &[Array]) -> Vec<Array>,
251 G: FnMut(&mut U, &[Array]) -> Vec<Array>,
252 U: Updatable,
253{
254 fn call_mut(&mut self, state: &mut U, args: &[Array]) -> Result<Vec<Array>, Exception> {
255 self.state.call_mut_with_state(state, args)
256 }
257}
258
259impl<U, F, G> CallMutWithState<U, &Array, Array, ()> for Compiled<F, G>
260where
261 F: FnMut(&mut U, &Array) -> Array,
262 G: FnMut(&mut U, &[Array]) -> Vec<Array>,
263 U: Updatable,
264{
265 fn call_mut(&mut self, state: &mut U, args: &Array) -> Result<Array, Exception> {
266 let args = std::slice::from_ref(args);
267 let result = self.state.call_mut_with_state(state, args)?;
268 Ok(result.into_iter().next().unwrap())
269 }
270}
271
272impl<U, F, G> CallMutWithState<U, (&Array, &Array), Array, ()> for Compiled<F, G>
273where
274 F: FnMut(&mut U, (&Array, &Array)) -> Array,
275 G: FnMut(&mut U, &[Array]) -> Vec<Array>,
276 U: Updatable,
277{
278 fn call_mut(&mut self, state: &mut U, args: (&Array, &Array)) -> Result<Array, Exception> {
279 let args = &[args.0, args.1];
280 let result = self.state.call_mut_with_state(state, args)?;
281 Ok(result.into_iter().next().unwrap())
282 }
283}
284
285impl<U, F, G> CallMutWithState<U, (&Array, &Array, &Array), Array, ()> for Compiled<F, G>
286where
287 F: FnMut(&mut U, (&Array, &Array, &Array)) -> Array,
288 G: FnMut(&mut U, &[Array]) -> Vec<Array>,
289 U: Updatable,
290{
291 fn call_mut(
292 &mut self,
293 state: &mut U,
294 args: (&Array, &Array, &Array),
295 ) -> Result<Array, Exception> {
296 let args = &[args.0, args.1, args.2];
297 let result = self.state.call_mut_with_state(state, args)?;
298 Ok(result.into_iter().next().unwrap())
299 }
300}
301
302impl<U, F, G> CallMutWithState<U, &[Array], Vec<Array>, Exception> for Compiled<F, G>
303where
304 F: FnMut(&mut U, &[Array]) -> Result<Vec<Array>, Exception>,
305 G: FnMut(&mut U, &[Array]) -> Result<Vec<Array>, Exception>,
306 U: Updatable,
307{
308 fn call_mut(&mut self, state: &mut U, args: &[Array]) -> Result<Vec<Array>, Exception> {
309 self.state.fallible_call_mut_with_state(state, args)
310 }
311}
312
313impl<U, F, G> CallMutWithState<U, &Array, Array, Exception> for Compiled<F, G>
314where
315 F: FnMut(&mut U, &Array) -> Result<Array, Exception>,
316 G: FnMut(&mut U, &[Array]) -> Result<Vec<Array>, Exception>,
317 U: Updatable,
318{
319 fn call_mut(&mut self, state: &mut U, args: &Array) -> Result<Array, Exception> {
320 let args = std::slice::from_ref(args);
321 let result = self.state.fallible_call_mut_with_state(state, args)?;
322 Ok(result.into_iter().next().unwrap())
323 }
324}
325
326impl<U, F, G> CallMutWithState<U, (&Array, &Array), Array, Exception> for Compiled<F, G>
327where
328 F: FnMut(&mut U, (&Array, &Array)) -> Result<Array, Exception>,
329 G: FnMut(&mut U, &[Array]) -> Result<Vec<Array>, Exception>,
330 U: Updatable,
331{
332 fn call_mut(&mut self, state: &mut U, args: (&Array, &Array)) -> Result<Array, Exception> {
333 let args = &[args.0, args.1];
334 let result = self.state.fallible_call_mut_with_state(state, args)?;
335 Ok(result.into_iter().next().unwrap())
336 }
337}
338
339impl<U, F, G> CallMutWithState<U, (&Array, &Array, &Array), Array, Exception> for Compiled<F, G>
340where
341 F: FnMut(&mut U, (&Array, &Array, &Array)) -> Result<Array, Exception>,
342 G: FnMut(&mut U, &[Array]) -> Result<Vec<Array>, Exception>,
343 U: Updatable,
344{
345 fn call_mut(
346 &mut self,
347 state: &mut U,
348 args: (&Array, &Array, &Array),
349 ) -> Result<Array, Exception> {
350 let args = &[args.0, args.1, args.2];
351 let result = self.state.fallible_call_mut_with_state(state, args)?;
352 Ok(result.into_iter().next().unwrap())
353 }
354}
355
356#[inline]
357fn call_mut_with_state_inner<U>(
358 inner_closure: Closure,
359 fun_id: usize,
360 shapeless: bool,
361 state: Rc<RefCell<&mut U>>,
362 args: &[impl AsRef<Array>],
363 num_function_outputs: Rc<Cell<Option<usize>>>,
364 state_layout: Rc<RefCell<Option<StateLayout>>>,
365) -> crate::error::Result<Vec<Array>>
366where
367 U: Updatable,
368{
369 let compiled = Closure::try_from_op(|res| unsafe {
372 let constants = &[];
373 mlx_sys::mlx_detail_compile(
374 res,
375 inner_closure.as_ptr(),
376 fun_id,
377 shapeless,
378 constants.as_ptr(),
379 0,
380 )
381 })?;
382
383 let inner_inputs_vector = {
384 let mut borrow = state.borrow_mut();
385 let state_inputs = borrow.state_projection()?.snapshot();
386 VectorArray::try_from_iter(
387 args.iter()
388 .map(AsRef::as_ref)
389 .chain(state_inputs.present_values()),
390 )?
391 };
392
393 let result_vector = VectorArray::try_from_op(|res| unsafe {
396 mlx_sys::mlx_closure_apply(res, compiled.as_ptr(), inner_inputs_vector.as_ptr())
397 })?;
398
399 let result_plus_state_output: Vec<Array> = result_vector.try_into_values()?;
400
401 let num_fn_outputs = num_function_outputs.get().ok_or_else(|| {
404 Exception::custom(
405 "compile_with_state: internal error - function output count not captured during tracing"
406 )
407 })?;
408 let expected_state_layout = state_layout.borrow().clone().ok_or_else(|| {
409 Exception::custom(
410 "compile_with_state: internal error - state layout not captured during tracing",
411 )
412 })?;
413 validate_state_layout(
414 &expected_state_layout,
415 &mut **state.borrow_mut(),
416 "apply input",
417 )?;
418
419 let expected_state_outputs = expected_state_layout
420 .iter()
421 .filter(|entry| entry.is_present())
422 .count();
423 let expected_output_count = num_fn_outputs + expected_state_outputs;
424 if result_plus_state_output.len() != expected_output_count {
425 return Err(Exception::custom(format!(
426 "compile_with_state: invalid output count - expected {num_fn_outputs} function \
427 outputs and {} state outputs, got {} total outputs",
428 expected_state_outputs,
429 result_plus_state_output.len()
430 )));
431 }
432
433 let function_results = &result_plus_state_output[..num_fn_outputs];
434 let state_outputs = &result_plus_state_output[num_fn_outputs..];
435
436 let state_output =
437 StateSnapshot::from_layout_and_values(&expected_state_layout, state_outputs)?;
438 let output_layout = state_output.layout();
439 if output_layout != expected_state_layout {
440 return Err(Exception::custom(format!(
441 "compile_with_state: state output layout changed: expected \
442 {expected_state_layout:?}, got {output_layout:?}"
443 )));
444 }
445
446 state
447 .borrow_mut()
448 .state_projection()?
449 .restore(state_output, false)?;
450
451 Ok(function_results.to_vec())
453}
454
455fn current_state_layout(state: &mut impl Updatable) -> Result<StateLayout, Exception> {
456 Ok(state.state_projection()?.layout())
457}
458
459fn validate_state_layout(
460 expected: &[crate::utils::StateLayoutEntry],
461 state: &mut impl Updatable,
462 phase: &str,
463) -> Result<(), Exception> {
464 let actual = current_state_layout(state)?;
465 if actual == expected {
466 Ok(())
467 } else {
468 Err(Exception::custom(format!(
469 "compile_with_state: state layout changed at {phase}: expected {expected:?}, got \
470 {actual:?}"
471 )))
472 }
473}
474
475fn state_snapshot(state: &mut impl Updatable) -> Result<StateSnapshot, Exception> {
476 Ok(state.state_projection()?.snapshot())
477}
478
479fn restore_state(
480 state: &mut impl Updatable,
481 snapshot: &StateSnapshot,
482 reset_new: bool,
483) -> Result<(), Exception> {
484 Ok(state
485 .state_projection()?
486 .restore(snapshot.clone(), reset_new)?)
487}
488
489fn state_grew(before: &StateSnapshot, after: &StateSnapshot) -> bool {
490 let before = before
491 .iter()
492 .map(|(key, _)| key.to_owned())
493 .collect::<BTreeSet<_>>();
494 let after = after
495 .iter()
496 .map(|(key, _)| key.to_owned())
497 .collect::<BTreeSet<_>>();
498 before.len() < after.len() && before.is_subset(&after)
499}
500
501impl<F> CompiledState<F> {
502 fn call_mut_with_state<U>(
503 &mut self,
504 state: &mut U,
505 args: &[impl AsRef<Array>],
506 ) -> Result<Vec<Array>, Exception>
507 where
508 F: FnMut(&mut U, &[Array]) -> Vec<Array>,
509 U: Updatable,
510 {
511 self.call_mut_with_state_attempt(state, args, true)
512 }
513
514 fn call_mut_with_state_attempt<U>(
515 &mut self,
516 state: &mut U,
517 args: &[impl AsRef<Array>],
518 allow_growth_recovery: bool,
519 ) -> Result<Vec<Array>, Exception>
520 where
521 F: FnMut(&mut U, &[Array]) -> Vec<Array>,
522 U: Updatable,
523 {
524 let was_untraced = self.state_layout.is_none();
525 if let Some(expected) = self.state_layout.as_deref() {
526 validate_state_layout(expected, state, "call input")?;
527 }
528 let args_len = args.len();
529 let saved_state = state_snapshot(state)?;
530 let state = Rc::new(RefCell::new(state));
531 let f = &mut self.f;
532
533 let num_function_outputs = Rc::new(Cell::new(self.num_function_outputs));
535 let num_fn_outputs_clone = Rc::clone(&num_function_outputs);
536 let state_layout = Rc::new(RefCell::new(self.state_layout.clone()));
537 let state_layout_clone = Rc::clone(&state_layout);
538
539 let state_clone = Rc::clone(&state);
540 let inner = move |tracers: &[Array]| -> Result<Vec<Array>, Exception> {
541 let tracer_args = &tracers[..args_len];
546
547 let saved_state_inputs = state_snapshot(&mut **state_clone.borrow_mut())?;
549
550 let state_input_count = saved_state_inputs.present_values().count();
552 if tracers.len() != args_len + state_input_count {
553 return Err(Exception::custom(format!(
554 "compile_with_state: invalid tracer count - expected {} arguments and {} state inputs, got {} total inputs",
555 args_len,
556 state_input_count,
557 tracers.len()
558 )));
559 }
560 let tracer_state = StateSnapshot::from_layout_and_values(
561 &saved_state_inputs.layout(),
562 &tracers[args_len..],
563 )?;
564 state_clone
565 .borrow_mut()
566 .state_projection()?
567 .restore(tracer_state, false)?;
568
569 let mut result = (f)(*state_clone.borrow_mut(), tracer_args);
571
572 num_fn_outputs_clone.set(Some(result.len()));
574
575 let state_output = state_snapshot(&mut **state_clone.borrow_mut())?;
577 let mut state_output_tracers =
578 state_output.present_values().cloned().collect::<Vec<_>>();
579
580 if state_layout_clone.borrow().is_none() {
581 *state_layout_clone.borrow_mut() = Some(state_output.layout());
582 }
583
584 restore_state(*state_clone.borrow_mut(), &saved_state_inputs, true)?;
586
587 result.append(&mut state_output_tracers);
589
590 Ok(result)
591 };
592
593 let inner_closure = Closure::new_fallible(inner);
594 let result = call_mut_with_state_inner(
595 inner_closure,
596 self.id,
597 self.shapeless,
598 Rc::clone(&state),
599 args,
600 Rc::clone(&num_function_outputs),
601 Rc::clone(&state_layout),
602 );
603 self.num_function_outputs = num_function_outputs.get();
604 self.state_layout = state_layout.borrow().clone();
605 if let Err(error) = &result {
606 let after_failure = state_snapshot(&mut **state.borrow_mut())?;
607 if allow_growth_recovery && was_untraced && state_grew(&saved_state, &after_failure) {
608 restore_state(*state.borrow_mut(), &saved_state, true)?;
609 let retry =
610 self.call_mut_with_state_attempt(&mut **state.borrow_mut(), args, false);
611 if retry.is_err() {
612 restore_state(*state.borrow_mut(), &saved_state, false)?;
613 self.cache.erase(self.id);
614 self.num_function_outputs = None;
615 self.state_layout = None;
616 }
617 return retry;
618 }
619 restore_state(*state.borrow_mut(), &saved_state, false).map_err(|restore_error| {
620 Exception::custom(format!(
621 "{}; transactional restore failed: {}",
622 error.what(),
623 restore_error.what()
624 ))
625 })?;
626 }
627 result
628 }
629
630 fn fallible_call_mut_with_state<U>(
631 &mut self,
632 state: &mut U,
633 args: &[impl AsRef<Array>],
634 ) -> Result<Vec<Array>, Exception>
635 where
636 F: FnMut(&mut U, &[Array]) -> Result<Vec<Array>, Exception>,
637 U: Updatable,
638 {
639 self.fallible_call_mut_with_state_attempt(state, args, true)
640 }
641
642 fn fallible_call_mut_with_state_attempt<U>(
643 &mut self,
644 state: &mut U,
645 args: &[impl AsRef<Array>],
646 allow_growth_recovery: bool,
647 ) -> Result<Vec<Array>, Exception>
648 where
649 F: FnMut(&mut U, &[Array]) -> Result<Vec<Array>, Exception>,
650 U: Updatable,
651 {
652 let was_untraced = self.state_layout.is_none();
653 if let Some(expected) = self.state_layout.as_deref() {
654 validate_state_layout(expected, state, "call input")?;
655 }
656 let args_len = args.len();
657 let saved_state = state_snapshot(state)?;
658 let state = Rc::new(RefCell::new(state));
659 let f = &mut self.f;
660
661 let num_function_outputs = Rc::new(Cell::new(self.num_function_outputs));
663 let num_fn_outputs_clone = Rc::clone(&num_function_outputs);
664 let state_layout = Rc::new(RefCell::new(self.state_layout.clone()));
665 let state_layout_clone = Rc::clone(&state_layout);
666
667 let state_clone = Rc::clone(&state);
668 let inner = move |tracers: &[Array]| -> Result<Vec<Array>, Exception> {
669 let tracer_args = &tracers[..args_len];
674
675 let saved_state_inputs = state_snapshot(&mut **state_clone.borrow_mut())?;
677
678 let state_input_count = saved_state_inputs.present_values().count();
680 if tracers.len() != args_len + state_input_count {
681 return Err(Exception::custom(format!(
682 "compile_with_state: invalid tracer count - expected {} arguments and {} state inputs, got {} total inputs",
683 args_len,
684 state_input_count,
685 tracers.len()
686 )));
687 }
688 let tracer_state = StateSnapshot::from_layout_and_values(
689 &saved_state_inputs.layout(),
690 &tracers[args_len..],
691 )?;
692 state_clone
693 .borrow_mut()
694 .state_projection()?
695 .restore(tracer_state, false)?;
696
697 let call_result = {
699 let mut state = state_clone.borrow_mut();
700 (f)(&mut **state, tracer_args)
701 };
702 let mut result = match call_result {
703 Ok(result) => result,
704 Err(error) => {
705 restore_state(*state_clone.borrow_mut(), &saved_state_inputs, false).map_err(
706 |restore_error| {
707 Exception::custom(format!(
708 "{}; transactional restore failed: {}",
709 error.what(),
710 restore_error.what()
711 ))
712 },
713 )?;
714 return Err(error);
715 }
716 };
717
718 num_fn_outputs_clone.set(Some(result.len()));
720
721 let state_output = state_snapshot(&mut **state_clone.borrow_mut())?;
723 let mut state_output_tracers =
724 state_output.present_values().cloned().collect::<Vec<_>>();
725
726 if state_layout_clone.borrow().is_none() {
727 *state_layout_clone.borrow_mut() = Some(state_output.layout());
728 }
729
730 restore_state(*state_clone.borrow_mut(), &saved_state_inputs, true)?;
732
733 result.append(&mut state_output_tracers);
735
736 Ok(result)
737 };
738
739 let inner_closure = Closure::new_fallible(inner);
740 let result = call_mut_with_state_inner(
741 inner_closure,
742 self.id,
743 self.shapeless,
744 Rc::clone(&state),
745 args,
746 Rc::clone(&num_function_outputs),
747 Rc::clone(&state_layout),
748 );
749 self.num_function_outputs = num_function_outputs.get();
750 self.state_layout = state_layout.borrow().clone();
751 if let Err(error) = &result {
752 let after_failure = state_snapshot(&mut **state.borrow_mut())?;
753 if allow_growth_recovery && was_untraced && state_grew(&saved_state, &after_failure) {
754 restore_state(*state.borrow_mut(), &saved_state, true)?;
755 let retry = self.fallible_call_mut_with_state_attempt(
756 &mut **state.borrow_mut(),
757 args,
758 false,
759 );
760 if retry.is_err() {
761 restore_state(*state.borrow_mut(), &saved_state, false)?;
762 self.cache.erase(self.id);
763 self.num_function_outputs = None;
764 self.state_layout = None;
765 }
766 return retry;
767 }
768 restore_state(*state.borrow_mut(), &saved_state, false).map_err(|restore_error| {
769 Exception::custom(format!(
770 "{}; transactional restore failed: {}",
771 error.what(),
772 restore_error.what()
773 ))
774 })?;
775 }
776 result
777 }
778}