Add a notion of "and_then" to activation objects.
This effectively constitutes the ability to assign arbitrary native contiuations to the AVM stack.
This commit is contained in:
parent
24009d4f4a
commit
8485e919db
|
@ -244,7 +244,19 @@ impl<'gc> Avm1<'gc> {
|
|||
}
|
||||
|
||||
/// Destroy the current stack frame (if there is one).
|
||||
fn retire_stack_frame(&mut self) {
|
||||
///
|
||||
/// This function will run functions scheduled on the current stack frame's
|
||||
/// `and_then` field. This is intended to allow the runtime to act on the
|
||||
/// results of AVM code to implement things like custom getters/setters.
|
||||
fn retire_stack_frame(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) {
|
||||
if let Some(frame) = self.current_stack_frame() {
|
||||
let this = frame.read().this_cell();
|
||||
if let Some(func) = frame.read().get_then_func() {
|
||||
let ret_args = vec![self.stack.last().unwrap().to_owned()];
|
||||
func(self, context, this, &ret_args);
|
||||
}
|
||||
}
|
||||
|
||||
self.stack_frames.pop();
|
||||
}
|
||||
|
||||
|
@ -282,7 +294,7 @@ impl<'gc> Avm1<'gc> {
|
|||
self.push(Value::Undefined);
|
||||
}
|
||||
|
||||
self.retire_stack_frame();
|
||||
self.retire_stack_frame(context);
|
||||
} else if let Some(action) = reader.read_action()? {
|
||||
let result = match action {
|
||||
Action::Add => self.action_add(context),
|
||||
|
@ -415,7 +427,7 @@ impl<'gc> Avm1<'gc> {
|
|||
self.push(Value::Undefined);
|
||||
}
|
||||
|
||||
self.retire_stack_frame();
|
||||
self.retire_stack_frame(context);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1486,12 +1498,12 @@ impl<'gc> Avm1<'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn action_return(&mut self, _context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> {
|
||||
fn action_return(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> {
|
||||
let result = self.pop()?;
|
||||
|
||||
if self.stack_frames.len() > 1 {
|
||||
self.retire_stack_frame();
|
||||
self.push(result);
|
||||
self.retire_stack_frame(context);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
//! Activation records
|
||||
|
||||
use crate::avm1::function::NativeFunction;
|
||||
use crate::avm1::object::Object;
|
||||
use crate::avm1::scope::Scope;
|
||||
use crate::avm1::{Avm1, UpdateContext, Value};
|
||||
use crate::avm1::{Avm1, Value};
|
||||
use crate::context::UpdateContext;
|
||||
use crate::tag_utils::SwfSlice;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
use smallvec::SmallVec;
|
||||
|
@ -88,6 +90,12 @@ pub struct Activation<'gc> {
|
|||
/// Registers are stored in a `GcCell` so that rescopes (e.g. with) use the
|
||||
/// same register set.
|
||||
local_registers: Option<GcCell<'gc, RegisterSet<'gc>>>,
|
||||
|
||||
/// Native code to execute when the given activation frame returns.
|
||||
///
|
||||
/// This facility exists primarily to allow native code to handle the result
|
||||
/// of an AVM function call.
|
||||
then_func: Option<NativeFunction<'gc>>,
|
||||
}
|
||||
|
||||
unsafe impl<'gc> gc_arena::Collect for Activation<'gc> {
|
||||
|
@ -117,6 +125,7 @@ impl<'gc> Activation<'gc> {
|
|||
arguments,
|
||||
is_function: false,
|
||||
local_registers: None,
|
||||
then_func: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +145,7 @@ impl<'gc> Activation<'gc> {
|
|||
arguments,
|
||||
is_function: true,
|
||||
local_registers: None,
|
||||
then_func: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,6 +176,7 @@ impl<'gc> Activation<'gc> {
|
|||
arguments: None,
|
||||
is_function: false,
|
||||
local_registers: None,
|
||||
then_func: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +191,7 @@ impl<'gc> Activation<'gc> {
|
|||
arguments: self.arguments,
|
||||
is_function: false,
|
||||
local_registers: self.local_registers,
|
||||
then_func: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,4 +328,16 @@ impl<'gc> Activation<'gc> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the function scheduled to be executed, if any.
|
||||
pub fn get_then_func(&self) -> Option<NativeFunction<'gc>> {
|
||||
self.then_func
|
||||
}
|
||||
|
||||
/// Schedule a native function to execute when this stack frame returns.
|
||||
///
|
||||
/// Only one native function may be scheduled per activation.
|
||||
pub fn and_then(&mut self, func: NativeFunction<'gc>) {
|
||||
self.then_func = Some(func);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue