From 84a5fae43f30577771107b6a28266260437e4578 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Fri, 26 Jun 2020 09:12:33 +0200 Subject: [PATCH] avm1: Only perform stack-frame adjustments in one place, not scattered throughout actions --- core/src/avm1/return_value.rs | 5 +- core/src/avm1/stack_frame.rs | 267 +++++++++++++++++++--------------- 2 files changed, 149 insertions(+), 123 deletions(-) diff --git a/core/src/avm1/return_value.rs b/core/src/avm1/return_value.rs index 3e0b75faf..253946204 100644 --- a/core/src/avm1/return_value.rs +++ b/core/src/avm1/return_value.rs @@ -95,10 +95,7 @@ impl<'gc> ReturnValue<'gc> { Immediate(val) => Ok(val), ResultOf(frame) => match avm.run_current_frame(context, frame) { Ok(_) => Ok(avm.pop()), - Err(e) => { - avm.retire_stack_frame(context, Value::Undefined); - Err(e) - } + Err(e) => Err(e), }, } } diff --git a/core/src/avm1/stack_frame.rs b/core/src/avm1/stack_frame.rs index 5f951c7c6..9a9e3a869 100644 --- a/core/src/avm1/stack_frame.rs +++ b/core/src/avm1/stack_frame.rs @@ -27,9 +27,16 @@ macro_rules! avm_debug { ) } -enum FrameControl { +#[derive(Debug, Clone)] +enum ReturnType<'gc> { + Implicit, + Explicit(Value<'gc>), +} + +#[derive(Debug, Clone)] +enum FrameControl<'gc> { Continue, - Return, + Return(ReturnType<'gc>), } #[derive(Collect)] @@ -55,7 +62,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { let result = loop { let result = self.do_action(&data, context, &mut read); match result { - Ok(FrameControl::Return) => break Ok(()), + Ok(FrameControl::Return(return_type)) => break Ok(return_type), Ok(FrameControl::Continue) => {} Err(e) => break Err(e), } @@ -66,13 +73,23 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { activation.set_pc(read.pos()); drop(activation); - if let Err(error) = &result { - if error.is_halting() { - self.avm.halt(); + match result { + Ok(ReturnType::Explicit(value)) => { + self.avm.retire_stack_frame(context, value); + Ok(()) + } + Ok(ReturnType::Implicit) => { + self.avm.retire_stack_frame(context, Value::Undefined); + Ok(()) + } + Err(error) => { + if error.is_halting() { + self.avm.halt(); + } + self.avm.retire_stack_frame(context, Value::Undefined); + Err(error) } } - - result } /// Run a single action from a given action reader. @@ -81,11 +98,10 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { data: &SwfSlice, context: &mut UpdateContext<'_, 'gc, '_>, reader: &mut Reader<'_>, - ) -> Result> { + ) -> Result, Error<'gc>> { if reader.pos() >= (data.end - data.start) { //Executing beyond the end of a function constitutes an implicit return. - self.avm.retire_stack_frame(context, Value::Undefined); - Ok(FrameControl::Return) + Ok(FrameControl::Return(ReturnType::Implicit)) } else if let Some(action) = reader.read_action()? { avm_debug!("Action: {:?}", action); @@ -173,7 +189,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { Action::PushDuplicate => self.action_push_duplicate(context), Action::RandomNumber => self.action_random_number(context), Action::RemoveSprite => self.action_remove_sprite(context), - Action::Return => self.action_return(context), + Action::Return => self.action_return(), Action::SetMember => self.action_set_member(context), Action::SetProperty => self.action_set_property(context), Action::SetTarget(target) => self.action_set_target(context, &target), @@ -223,8 +239,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { result } else { //The explicit end opcode was encountered so return here - self.avm.retire_stack_frame(context, Value::Undefined); - Ok(FrameControl::Return) + Ok(FrameControl::Return(ReturnType::Implicit)) } } @@ -232,12 +247,15 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { &mut self, _context: &mut UpdateContext, action: swf::avm1::types::Action, - ) -> Result> { + ) -> Result, Error<'gc>> { log::error!("Unknown AVM1 opcode: {:?}", action); Ok(FrameControl::Continue) } - fn action_add(&mut self, _context: &mut UpdateContext) -> Result> { + fn action_add( + &mut self, + _context: &mut UpdateContext, + ) -> Result, Error<'gc>> { let a = self.avm.pop(); let b = self.avm.pop(); self.avm.push(b.into_number_v1() + a.into_number_v1()); @@ -247,7 +265,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_add_2( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // ECMA-262 s. 11.6.1 let a = self.avm.pop(); let b = self.avm.pop(); @@ -271,7 +289,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_and( &mut self, _context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // AS1 logical and let a = self.avm.pop(); let b = self.avm.pop(); @@ -285,7 +303,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_ascii_to_char( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel): Results on incorrect operands? let val = (self.avm.pop().coerce_to_f64(self.avm, context)? as u8) as char; self.avm.push(val.to_string()); @@ -295,7 +313,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_char_to_ascii( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel): Results on incorrect operands? let val = self.avm.pop(); let string = val.coerce_to_string(self.avm, context)?; @@ -307,7 +325,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_clone_sprite( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let depth = self.avm.pop(); let target = self.avm.pop(); let source = self.avm.pop(); @@ -334,7 +352,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_bit_and( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_u32(self.avm, context)?; let b = self.avm.pop().coerce_to_u32(self.avm, context)?; let result = a & b; @@ -345,7 +363,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_bit_lshift( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_i32(self.avm, context)? & 0b11111; // Only 5 bits used for shift count let b = self.avm.pop().coerce_to_i32(self.avm, context)?; let result = b << a; @@ -356,7 +374,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_bit_or( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_u32(self.avm, context)?; let b = self.avm.pop().coerce_to_u32(self.avm, context)?; let result = a | b; @@ -367,7 +385,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_bit_rshift( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_i32(self.avm, context)? & 0b11111; // Only 5 bits used for shift count let b = self.avm.pop().coerce_to_i32(self.avm, context)?; let result = b >> a; @@ -378,7 +396,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_bit_urshift( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_u32(self.avm, context)? & 0b11111; // Only 5 bits used for shift count let b = self.avm.pop().coerce_to_u32(self.avm, context)?; let result = b >> a; @@ -389,7 +407,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_bit_xor( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_u32(self.avm, context)?; let b = self.avm.pop().coerce_to_u32(self.avm, context)?; let result = b ^ a; @@ -400,7 +418,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_call( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // Runs any actions on the given frame. let frame = self.avm.pop(); let clip = self.avm.target_clip_or_root(); @@ -441,7 +459,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_call_function( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let fn_name_value = self.avm.pop(); let fn_name = fn_name_value.coerce_to_string(self.avm, context)?; let mut args = Vec::new(); @@ -469,7 +487,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_call_method( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let method_name = self.avm.pop(); let object_val = self.avm.pop(); let object = value_object::ValueObject::boxed(self.avm, context, object_val); @@ -513,7 +531,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_cast_op( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let obj = self.avm.pop().coerce_to_object(self.avm, context); let constr = self.avm.pop().coerce_to_object(self.avm, context); @@ -534,7 +552,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { &mut self, context: &mut UpdateContext<'_, 'gc, '_>, constant_pool: &[&str], - ) -> Result> { + ) -> Result, Error<'gc>> { self.avm.constant_pool = GcCell::allocate( context.gc_context, constant_pool.iter().map(|s| (*s).to_string()).collect(), @@ -549,7 +567,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_decrement( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_f64(self.avm, context)?; self.avm.push(a - 1.0); Ok(FrameControl::Continue) @@ -561,7 +579,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { name: &str, params: &[&str], actions: &[u8], - ) -> Result> { + ) -> Result, Error<'gc>> { let swf_version = self.activation.read().swf_version(); let func_data = self.activation.read().data().to_subslice(actions).unwrap(); let scope = @@ -599,7 +617,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { &mut self, context: &mut UpdateContext<'_, 'gc, '_>, action_func: &Function, - ) -> Result> { + ) -> Result, Error<'gc>> { let swf_version = self.activation.read().swf_version(); let func_data = self .activation @@ -640,7 +658,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_define_local( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // If the property does not exist on the local object's prototype chain, it is created on the local object. // Otherwise, the property is set (including calling virtual setters). let value = self.avm.pop(); @@ -655,7 +673,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_define_local_2( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // If the property does not exist on the local object's prototype chain, it is created on the local object. // Otherwise, the property is unchanged. let name_val = self.avm.pop(); @@ -673,7 +691,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_delete( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let name_val = self.avm.pop(); let name = name_val.coerce_to_string(self.avm, context)?; let object = self.avm.pop(); @@ -692,7 +710,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_delete_2( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let name_val = self.avm.pop(); let name = name_val.coerce_to_string(self.avm, context)?; @@ -712,7 +730,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_divide( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // AS1 divide let a = self.avm.pop().coerce_to_f64(self.avm, context)?; let b = self.avm.pop().coerce_to_f64(self.avm, context)?; @@ -725,7 +743,10 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { Ok(FrameControl::Continue) } - fn action_end_drag(&mut self, context: &mut UpdateContext) -> Result> { + fn action_end_drag( + &mut self, + context: &mut UpdateContext, + ) -> Result, Error<'gc>> { *context.drag_object = None; Ok(FrameControl::Continue) } @@ -733,7 +754,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_enumerate( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let name_value = self.avm.pop(); let name = name_value.coerce_to_string(self.avm, context)?; self.avm.push(Value::Null); // Sentinel that indicates end of enumeration @@ -758,7 +779,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_enumerate_2( &mut self, _context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let value = self.avm.pop(); self.avm.push(Value::Null); // Sentinel that indicates end of enumeration @@ -778,7 +799,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_equals( &mut self, _context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // AS1 equality let a = self.avm.pop(); let b = self.avm.pop(); @@ -792,7 +813,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_equals_2( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // Version >=5 equality let a = self.avm.pop(); let b = self.avm.pop(); @@ -804,7 +825,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_extends( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let superclass = self.avm.pop().coerce_to_object(self.avm, context); let subclass = self.avm.pop().coerce_to_object(self.avm, context); @@ -841,7 +862,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_get_member( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let name_val = self.avm.pop(); let name = name_val.coerce_to_string(self.avm, context)?; let object_val = self.avm.pop(); @@ -856,7 +877,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_get_property( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let prop_index = self.avm.pop().into_number_v1() as usize; let path = self.avm.pop(); let ret = if let Some(target) = self.avm.target_clip() { @@ -884,7 +905,10 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { Ok(FrameControl::Continue) } - fn action_get_time(&mut self, context: &mut UpdateContext) -> Result> { + fn action_get_time( + &mut self, + context: &mut UpdateContext, + ) -> Result, Error<'gc>> { let time = context.navigator.time_since_launch().as_millis() as u32; self.avm.push(time); Ok(FrameControl::Continue) @@ -893,7 +917,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_get_variable( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let var_path = self.avm.pop(); let path = var_path.coerce_to_string(self.avm, context)?; @@ -907,7 +931,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { context: &mut UpdateContext<'_, 'gc, '_>, url: &str, target: &str, - ) -> Result> { + ) -> Result, Error<'gc>> { if target.starts_with("_level") && target.len() > 6 { let url = url.to_string(); match target[6..].parse::() { @@ -950,7 +974,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { swf_method: swf::avm1::types::SendVarsMethod, is_target_sprite: bool, is_load_vars: bool, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO: Support `LoadVariablesFlag`, `LoadTargetFlag` // TODO: What happens if there's only one string? let target = self.avm.pop(); @@ -1036,7 +1060,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { &mut self, context: &mut UpdateContext<'_, 'gc, '_>, frame: u16, - ) -> Result> { + ) -> Result, Error<'gc>> { if let Some(clip) = self.avm.target_clip() { if let Some(clip) = clip.as_movie_clip() { // The frame on the stack is 0-based, not 1-based. @@ -1055,7 +1079,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { context: &mut UpdateContext<'_, 'gc, '_>, set_playing: bool, scene_offset: u16, - ) -> Result> { + ) -> Result, Error<'gc>> { // Version 4+ gotoAndPlay/gotoAndStop // Param can either be a frame number or a frame label. if let Some(clip) = self.avm.target_clip() { @@ -1082,7 +1106,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { &mut self, context: &mut UpdateContext<'_, 'gc, '_>, label: &str, - ) -> Result> { + ) -> Result, Error<'gc>> { if let Some(clip) = self.avm.target_clip() { if let Some(clip) = clip.as_movie_clip() { if let Some(frame) = clip.frame_label_to_number(label) { @@ -1104,7 +1128,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { _context: &mut UpdateContext, jump_offset: i16, reader: &mut Reader<'_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let val = self.avm.pop(); if val.as_bool(self.avm.current_swf_version()) { reader.seek(jump_offset.into()); @@ -1115,7 +1139,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_increment( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_f64(self.avm, context)?; self.avm.push(a + 1.0); Ok(FrameControl::Continue) @@ -1124,7 +1148,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_init_array( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let num_elements = self.avm.pop().coerce_to_f64(self.avm, context)? as i64; let array = ScriptObject::array(context.gc_context, Some(self.avm.prototypes.array)); @@ -1139,7 +1163,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_init_object( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let num_props = self.avm.pop().coerce_to_f64(self.avm, context)? as i64; let object = ScriptObject::object(context.gc_context, Some(self.avm.prototypes.object)); for _ in 0..num_props { @@ -1157,7 +1181,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_implements_op( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let constr = self.avm.pop().coerce_to_object(self.avm, context); let count = self.avm.pop().coerce_to_f64(self.avm, context)? as i64; //TODO: Is this coercion actually performed by Flash? let mut interfaces = vec![]; @@ -1180,7 +1204,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_instance_of( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let constr = self.avm.pop().coerce_to_object(self.avm, context); let obj = self.avm.pop().coerce_to_object(self.avm, context); @@ -1198,7 +1222,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { _context: &mut UpdateContext, jump_offset: i16, reader: &mut Reader<'_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel): Handle out-of-bounds. reader.seek(jump_offset.into()); Ok(FrameControl::Continue) @@ -1207,7 +1231,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_less( &mut self, _context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // AS1 less than let a = self.avm.pop(); let b = self.avm.pop(); @@ -1220,7 +1244,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_less_2( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // ECMA-262 s. 11.8.1 let a = self.avm.pop(); let b = self.avm.pop(); @@ -1234,7 +1258,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_greater( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // ECMA-262 s. 11.8.2 let a = self.avm.pop(); let b = self.avm.pop(); @@ -1248,7 +1272,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_mb_ascii_to_char( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel): Results on incorrect operands? use std::convert::TryFrom; let result = char::try_from(self.avm.pop().coerce_to_f64(self.avm, context)? as u32); @@ -1262,7 +1286,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_mb_char_to_ascii( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel): Results on incorrect operands? let val = self.avm.pop(); let s = val.coerce_to_string(self.avm, context)?; @@ -1274,7 +1298,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_mb_string_extract( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel): Result with incorrect operands? let len = self.avm.pop().coerce_to_f64(self.avm, context)? as usize; let start = self.avm.pop().coerce_to_f64(self.avm, context)? as usize; @@ -1288,7 +1312,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_mb_string_length( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel): Result with non-string operands? let val = self.avm.pop(); let len = val.coerce_to_string(self.avm, context)?.len(); @@ -1299,7 +1323,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_multiply( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_f64(self.avm, context)?; let b = self.avm.pop().coerce_to_f64(self.avm, context)?; self.avm.push(a * b); @@ -1309,7 +1333,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_modulo( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO: Wrong operands? let a = self.avm.pop().coerce_to_f64(self.avm, context)?; let b = self.avm.pop().coerce_to_f64(self.avm, context)?; @@ -1320,7 +1344,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_not( &mut self, _context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let version = self.avm.current_swf_version(); let val = !self.avm.pop().as_bool(version); self.avm.push(Value::from_bool(val, version)); @@ -1330,7 +1354,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_next_frame( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { if let Some(clip) = self.avm.target_clip() { if let Some(clip) = clip.as_movie_clip() { clip.next_frame(self.avm, context); @@ -1346,7 +1370,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_new_method( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let method_name = self.avm.pop(); let object_val = self.avm.pop(); let num_args = self.avm.pop().coerce_to_f64(self.avm, context)? as i64; @@ -1402,7 +1426,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_new_object( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let fn_name_val = self.avm.pop(); let fn_name = fn_name_val.coerce_to_string(self.avm, context)?; let num_args = self.avm.pop().coerce_to_f64(self.avm, context)? as i64; @@ -1453,7 +1477,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_or( &mut self, _context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // AS1 logical or let a = self.avm.pop(); let b = self.avm.pop(); @@ -1466,7 +1490,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_play( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { if let Some(clip) = self.avm.target_clip() { if let Some(clip) = clip.as_movie_clip() { clip.play(context) @@ -1482,7 +1506,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_prev_frame( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { if let Some(clip) = self.avm.target_clip() { if let Some(clip) = clip.as_movie_clip() { clip.prev_frame(self.avm, context); @@ -1495,7 +1519,10 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { Ok(FrameControl::Continue) } - fn action_pop(&mut self, _context: &mut UpdateContext) -> Result> { + fn action_pop( + &mut self, + _context: &mut UpdateContext, + ) -> Result, Error<'gc>> { self.avm.pop(); Ok(FrameControl::Continue) } @@ -1504,7 +1531,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { &mut self, _context: &mut UpdateContext, values: &[swf::avm1::types::Value], - ) -> Result> { + ) -> Result, Error<'gc>> { for value in values { use swf::avm1::types::Value as SwfValue; let value = match value { @@ -1543,7 +1570,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_push_duplicate( &mut self, _context: &mut UpdateContext, - ) -> Result> { + ) -> Result, Error<'gc>> { let val = self.avm.pop(); self.avm.push(val.clone()); self.avm.push(val); @@ -1553,7 +1580,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_random_number( &mut self, context: &mut UpdateContext, - ) -> Result> { + ) -> Result, Error<'gc>> { // A max value < 0 will always return 0, // and the max value gets converted into an i32, so any number > 2^31 - 1 will return 0. let max = self.avm.pop().into_number_v1() as i32; @@ -1569,7 +1596,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_remove_sprite( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let target = self.avm.pop(); let start_clip = self.avm.target_clip_or_root(); let target_clip = self @@ -1584,20 +1611,16 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { Ok(FrameControl::Continue) } - fn action_return( - &mut self, - context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + fn action_return(&mut self) -> Result, Error<'gc>> { let return_value = self.avm.pop(); - self.avm.retire_stack_frame(context, return_value); - Ok(FrameControl::Return) + Ok(FrameControl::Return(ReturnType::Explicit(return_value))) } fn action_set_member( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let value = self.avm.pop(); let name_val = self.avm.pop(); let name = name_val.coerce_to_string(self.avm, context)?; @@ -1611,7 +1634,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_set_property( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let value = self.avm.pop(); let prop_index = self.avm.pop().coerce_to_u32(self.avm, context)? as usize; let path = self.avm.pop(); @@ -1637,7 +1660,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_set_variable( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // Flash 4-style variable let value = self.avm.pop(); let var_path_val = self.avm.pop(); @@ -1650,7 +1673,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_strict_equals( &mut self, _context: &mut UpdateContext, - ) -> Result> { + ) -> Result, Error<'gc>> { // The same as normal equality but types must match let a = self.avm.pop(); let b = self.avm.pop(); @@ -1663,7 +1686,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { &mut self, context: &mut UpdateContext<'_, 'gc, '_>, target: &str, - ) -> Result> { + ) -> Result, Error<'gc>> { let base_clip = self.avm.base_clip(); let new_target_clip; let root = base_clip.root(); @@ -1704,7 +1727,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_set_target2( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let target = self.avm.pop(); match target { Value::String(target) => { @@ -1747,7 +1770,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_stack_swap( &mut self, _context: &mut UpdateContext, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop(); let b = self.avm.pop(); self.avm.push(a); @@ -1758,7 +1781,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_start_drag( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let target = self.avm.pop(); let start_clip = self.avm.target_clip_or_root(); let display_object = self @@ -1790,7 +1813,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_stop( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { if let Some(clip) = self.avm.target_clip() { if let Some(clip) = clip.as_movie_clip() { clip.stop(context); @@ -1806,7 +1829,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_stop_sounds( &mut self, context: &mut UpdateContext, - ) -> Result> { + ) -> Result, Error<'gc>> { context.audio.stop_all_sounds(); Ok(FrameControl::Continue) } @@ -1815,7 +1838,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { &mut self, context: &mut UpdateContext<'_, 'gc, '_>, register: u8, - ) -> Result> { + ) -> Result, Error<'gc>> { // The value must remain on the stack. let val = self.avm.pop(); self.avm.push(val.clone()); @@ -1827,7 +1850,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_string_add( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // SWFv4 string concatenation // TODO(Herschel): Result with non-string operands? let a = self.avm.pop(); @@ -1844,7 +1867,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_string_equals( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // AS1 strcmp let a = self.avm.pop(); let b = self.avm.pop(); @@ -1858,7 +1881,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_string_extract( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // SWFv4 substring // TODO(Herschel): Result with incorrect operands? let len = self.avm.pop().coerce_to_f64(self.avm, context)? as usize; @@ -1880,7 +1903,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_string_greater( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // AS1 strcmp let a = self.avm.pop(); let b = self.avm.pop(); @@ -1897,7 +1920,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_string_length( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // AS1 strlen // Only returns byte length. // TODO(Herschel): Result with non-string operands? @@ -1910,7 +1933,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_string_less( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // AS1 strcmp let a = self.avm.pop(); let b = self.avm.pop(); @@ -1927,7 +1950,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_subtract( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let a = self.avm.pop().coerce_to_f64(self.avm, context)?; let b = self.avm.pop().coerce_to_f64(self.avm, context)?; self.avm.push(b - a); @@ -1937,7 +1960,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_target_path( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel) let _clip = self.avm.pop().coerce_to_object(self.avm, context); self.avm.push(Value::Undefined); @@ -1945,7 +1968,10 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { Ok(FrameControl::Continue) } - fn toggle_quality(&mut self, _context: &mut UpdateContext) -> Result> { + fn toggle_quality( + &mut self, + _context: &mut UpdateContext, + ) -> Result, Error<'gc>> { // TODO(Herschel): Noop for now? Could chang anti-aliasing on render backend. Ok(FrameControl::Continue) } @@ -1953,7 +1979,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_to_integer( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let val = self.avm.pop().coerce_to_f64(self.avm, context)?; self.avm.push(val.trunc()); Ok(FrameControl::Continue) @@ -1962,7 +1988,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_to_number( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let val = self.avm.pop().coerce_to_f64(self.avm, context)?; self.avm.push(val); Ok(FrameControl::Continue) @@ -1971,7 +1997,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_to_string( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let val = self.avm.pop(); let string = val.coerce_to_string(self.avm, context)?; self.avm.push(string); @@ -1981,7 +2007,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { fn action_trace( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let val = self.avm.pop(); // trace always prints "undefined" even though SWF6 and below normally // coerce undefined to "". @@ -1994,7 +2020,10 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { Ok(FrameControl::Continue) } - fn action_type_of(&mut self, _context: &mut UpdateContext) -> Result> { + fn action_type_of( + &mut self, + _context: &mut UpdateContext, + ) -> Result, Error<'gc>> { let type_of = self.avm.pop().type_of(); self.avm.push(type_of); Ok(FrameControl::Continue) @@ -2006,7 +2035,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { _frame: u16, num_actions_to_skip: u8, r: &mut Reader<'_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel): Always true for now. let loaded = true; if !loaded { @@ -2022,7 +2051,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { context: &mut UpdateContext<'_, 'gc, '_>, num_actions_to_skip: u8, r: &mut Reader<'_>, - ) -> Result> { + ) -> Result, Error<'gc>> { // TODO(Herschel): Always true for now. let _frame_num = self.avm.pop().coerce_to_f64(self.avm, context)? as u16; let loaded = true; @@ -2034,10 +2063,11 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { Ok(FrameControl::Continue) } + #[allow(unused_variables)] fn action_throw( &mut self, context: &mut UpdateContext<'_, 'gc, '_>, - ) -> Result> { + ) -> Result, Error<'gc>> { let value = self.avm.pop(); avm_debug!( "Thrown exception: {}", @@ -2045,7 +2075,6 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { .coerce_to_string(self.avm, context) .unwrap_or_else(|_| Cow::Borrowed("undefined")) ); - self.avm.retire_stack_frame(context, Value::Undefined); Err(Error::ThrownValue(value)) } @@ -2053,7 +2082,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { &mut self, context: &mut UpdateContext<'_, 'gc, '_>, actions: &[u8], - ) -> Result> { + ) -> Result, Error<'gc>> { let object = self.avm.pop().coerce_to_object(self.avm, context); let block = self.activation.read().data().to_subslice(actions).unwrap(); let with_scope = Scope::new_with_scope(