Add a method to force resolve a `ReturnValue` on the Rust stack via recursion.

This commit is contained in:
David Wendt 2019-10-22 15:18:40 -04:00
parent bc74b2fc4a
commit e2dcf47c56
2 changed files with 43 additions and 14 deletions

View File

@ -301,23 +301,32 @@ impl<'gc> Avm1<'gc> {
pub fn run_current_frame( pub fn run_current_frame(
&mut self, &mut self,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
stop_frame: GcCell<'gc, Activation<'gc>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let stop_frame = *self.stack_frames.last().unwrap(); let mut stop_frame_id = None;
let stop_frame_id = self.stack_frames.len() - 1; for (index, frame) in self.stack_frames.iter().enumerate() {
if GcCell::ptr_eq(stop_frame, *frame) {
while self stop_frame_id = Some(index);
.stack_frames }
.get(stop_frame_id)
.map(|fr| GcCell::ptr_eq(stop_frame, *fr))
.unwrap_or(false)
{
self.with_current_reader_mut(context, |this, r, context| {
this.do_next_action(context, r)
})
.unwrap()?;
} }
Ok(()) if let Some(stop_frame_id) = stop_frame_id {
while self
.stack_frames
.get(stop_frame_id)
.map(|fr| GcCell::ptr_eq(stop_frame, *fr))
.unwrap_or(false)
{
self.with_current_reader_mut(context, |this, r, context| {
this.do_next_action(context, r)
})
.unwrap()?;
}
Ok(())
} else {
Err("Attempted to run a frame not on the current interpreter stack".into())
}
} }
/// Run a single action from a given action reader. /// Run a single action from a given action reader.

View File

@ -109,6 +109,26 @@ impl<'gc> ReturnValue<'gc> {
}; };
} }
/// Force a return value to resolve on the Rust stack by recursing back
/// into the AVM.
pub fn resolve(
self,
avm: &mut Avm1<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
use ReturnValue::*;
match self {
Immediate(val) => Ok(val),
ResultOf(frame) => {
avm.run_current_frame(context, frame)?;
avm.pop()
}
NoResult => Err("Attempted to resolve a no-result return value".into()),
}
}
/// Consumes the given return value. /// Consumes the given return value.
/// ///
/// This exists primarily so that users of return values can indicate that /// This exists primarily so that users of return values can indicate that