From edc37dee5d59dd60e1d2d440f96912962da8cfe3 Mon Sep 17 00:00:00 2001 From: David Wendt Date: Mon, 16 Sep 2019 19:15:22 -0400 Subject: [PATCH] Add support for calling bare functions and returning from them. --- core/src/avm1.rs | 33 ++++++++++++++++++++------------- core/src/avm1/object.rs | 12 +++++++++++- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/core/src/avm1.rs b/core/src/avm1.rs index e31947acf..5180aaa93 100644 --- a/core/src/avm1.rs +++ b/core/src/avm1.rs @@ -563,22 +563,24 @@ impl<'gc> Avm1<'gc> { Err("Unimplemented action: Call".into()) } - fn action_call_function(&mut self, _context: &mut ActionContext) -> Result<(), Error> { - let _fn_name = self.pop()?.as_string()?; + fn action_call_function(&mut self, context: &mut ActionContext<'_, 'gc, '_>) -> Result<(), Error> { + let fn_name = self.pop()?; + let mut args = Vec::new(); let num_args = self.pop()?.as_i64()?; // TODO(Herschel): max arg count? for _ in 0..num_args { - self.pop()?; + args.push(self.pop()?); + } + + let target_fn = self.current_stack_frame_mut().unwrap().locals_mut().get(fn_name.as_string()?).unwrap_or_else(|| &Value::Undefined).clone(); + let return_value = target_fn.call(self, context, self.globals, &args)?; + if let Some(instant_return) = return_value { + self.current_stack_frame_mut().unwrap().stack_mut().push(instant_return); } - self.current_stack_frame_mut().unwrap().stack_mut().push(Value::Undefined); - // TODO(Herschel) - Err("Unimplemented action: CallFunction".into()) + Ok(()) } - fn action_call_method( - &mut self, - context: &mut ActionContext<'_, 'gc, '_>, - ) -> Result<(), Error> { + fn action_call_method(&mut self, context: &mut ActionContext<'_, 'gc, '_>) -> Result<(), Error> { let method_name = self.pop()?; let object = self.pop()?; let num_args = self.pop()?.as_i64()?; // TODO(Herschel): max arg count? @@ -1247,9 +1249,14 @@ impl<'gc> Avm1<'gc> { } fn action_return(&mut self, _context: &mut ActionContext) -> Result<(), Error> { - let _result = self.pop()?; - // TODO(Herschel) - Err("Unimplemented action: Return".into()) + let result = self.pop()?; + + if self.stack_frames.len() > 1 { + self.retire_stack_frame(); + self.current_stack_frame_mut().unwrap().stack_mut().push(result); + } + + Ok(()) } fn action_set_member(&mut self, _context: &mut ActionContext) -> Result<(), Error> { diff --git a/core/src/avm1/object.rs b/core/src/avm1/object.rs index efb54cd62..99c081baa 100644 --- a/core/src/avm1/object.rs +++ b/core/src/avm1/object.rs @@ -67,7 +67,17 @@ impl<'gc> Executable<'gc> { pub fn exec(&self, avm: &mut Avm1<'gc>, ac: &mut ActionContext<'_, 'gc, '_>, this: GcCell<'gc, Object<'gc>>, args: &[Value<'gc>]) -> Option> { match self { Executable::Native(nf) => Some(nf(avm, ac, this, args)), - Executable::Action(af) => None + Executable::Action(af) => { + avm.insert_stack_frame_from_action(af.swf_version, af.data.clone()); + + for arg in args { + avm.current_stack_frame_mut().unwrap().stack_mut().push(arg.clone()); + } + + avm.current_stack_frame_mut().unwrap().locals_mut().insert("this".to_string(), Value::Object(this)); + + None + } } } }