avm1: Only perform stack-frame adjustments in one place, not scattered throughout actions

This commit is contained in:
Nathan Adams 2020-06-26 09:12:33 +02:00
parent 9109d89daa
commit 84a5fae43f
2 changed files with 149 additions and 123 deletions

View File

@ -95,10 +95,7 @@ impl<'gc> ReturnValue<'gc> {
Immediate(val) => Ok(val), Immediate(val) => Ok(val),
ResultOf(frame) => match avm.run_current_frame(context, frame) { ResultOf(frame) => match avm.run_current_frame(context, frame) {
Ok(_) => Ok(avm.pop()), Ok(_) => Ok(avm.pop()),
Err(e) => { Err(e) => Err(e),
avm.retire_stack_frame(context, Value::Undefined);
Err(e)
}
}, },
} }
} }

View File

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