avm1: Add Activation to StackFrame, removing lots of get-and-unwraps

This commit is contained in:
Nathan Adams 2020-06-26 00:08:15 +02:00
parent 4d76e8b24d
commit c6b9de883f
2 changed files with 41 additions and 101 deletions

View File

@ -539,7 +539,8 @@ impl<'gc> Avm1<'gc> {
while !self.stack_frames.is_empty() { while !self.stack_frames.is_empty() {
if let Err(e) = self.with_current_reader_mut(context, |this, r, context| { if let Err(e) = self.with_current_reader_mut(context, |this, r, context| {
if !this.halted { if !this.halted {
StackFrame::new(this).do_next_action(context, r) let activation = this.current_stack_frame().unwrap();
StackFrame::new(this, activation).do_next_action(context, r)
} else { } else {
Ok(()) Ok(())
} }
@ -592,7 +593,8 @@ impl<'gc> Avm1<'gc> {
{ {
self.with_current_reader_mut(context, |this, r, context| { self.with_current_reader_mut(context, |this, r, context| {
if !this.halted { if !this.halted {
StackFrame::new(this).do_next_action(context, r) let activation = this.current_stack_frame().unwrap();
StackFrame::new(this, activation).do_next_action(context, r)
} else { } else {
Ok(()) Ok(())
} }

View File

@ -5,7 +5,8 @@ use crate::avm1::property::Attribute;
use crate::avm1::scope::Scope; use crate::avm1::scope::Scope;
use crate::avm1::value::f64_to_wrapping_u32; use crate::avm1::value::f64_to_wrapping_u32;
use crate::avm1::{ use crate::avm1::{
fscommand, globals, skip_actions, start_drag, value_object, Avm1, ScriptObject, Value, fscommand, globals, skip_actions, start_drag, value_object, Activation, Avm1, ScriptObject,
Value,
}; };
use crate::backend::navigator::{NavigationMethod, RequestOptions}; use crate::backend::navigator::{NavigationMethod, RequestOptions};
use crate::context::UpdateContext; use crate::context::UpdateContext;
@ -28,11 +29,12 @@ macro_rules! avm_debug {
#[collect(no_drop)] #[collect(no_drop)]
pub struct StackFrame<'a, 'gc: 'a> { pub struct StackFrame<'a, 'gc: 'a> {
avm: &'a mut Avm1<'gc>, avm: &'a mut Avm1<'gc>,
activation: GcCell<'gc, Activation<'gc>>,
} }
impl<'a, 'gc: 'a> StackFrame<'a, 'gc> { impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
pub fn new(avm: &'a mut Avm1<'gc>) -> Self { pub fn new(avm: &'a mut Avm1<'gc>, activation: GcCell<'gc, Activation<'gc>>) -> Self {
Self { avm } Self { avm, activation }
} }
/// Run a single action from a given action reader. /// Run a single action from a given action reader.
@ -41,7 +43,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut Reader<'_>, reader: &mut Reader<'_>,
) -> Result<(), Error<'gc>> { ) -> Result<(), Error<'gc>> {
let data = self.avm.current_stack_frame().unwrap().read().data(); let data = self.activation.read().data();
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.
@ -490,9 +492,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
context.gc_context, context.gc_context,
constant_pool.iter().map(|s| (*s).to_string()).collect(), constant_pool.iter().map(|s| (*s).to_string()).collect(),
); );
self.avm self.activation
.current_stack_frame()
.unwrap()
.write(context.gc_context) .write(context.gc_context)
.set_constant_pool(self.avm.constant_pool); .set_constant_pool(self.avm.constant_pool);
@ -515,25 +515,11 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
params: &[&str], params: &[&str],
actions: &[u8], actions: &[u8],
) -> Result<(), Error<'gc>> { ) -> Result<(), Error<'gc>> {
let swf_version = self.avm.current_stack_frame().unwrap().read().swf_version(); let swf_version = self.activation.read().swf_version();
let func_data = self let func_data = self.activation.read().data().to_subslice(actions).unwrap();
.avm let scope =
.current_stack_frame() Scope::new_closure_scope(self.activation.read().scope_cell(), context.gc_context);
.unwrap() let constant_pool = self.activation.read().constant_pool();
.read()
.data()
.to_subslice(actions)
.unwrap();
let scope = Scope::new_closure_scope(
self.avm.current_stack_frame().unwrap().read().scope_cell(),
context.gc_context,
);
let constant_pool = self
.avm
.current_stack_frame()
.unwrap()
.read()
.constant_pool();
let func = Avm1Function::from_df1( let func = Avm1Function::from_df1(
swf_version, swf_version,
func_data, func_data,
@ -554,11 +540,9 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
if name == "" { if name == "" {
self.avm.push(func_obj); self.avm.push(func_obj);
} else { } else {
self.avm.current_stack_frame().unwrap().read().define( self.activation
name, .read()
func_obj, .define(name, func_obj, context.gc_context);
context.gc_context,
);
} }
Ok(()) Ok(())
@ -569,25 +553,16 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
action_func: &Function, action_func: &Function,
) -> Result<(), Error<'gc>> { ) -> Result<(), Error<'gc>> {
let swf_version = self.avm.current_stack_frame().unwrap().read().swf_version(); let swf_version = self.activation.read().swf_version();
let func_data = self let func_data = self
.avm .activation
.current_stack_frame()
.unwrap()
.read() .read()
.data() .data()
.to_subslice(action_func.actions) .to_subslice(action_func.actions)
.unwrap(); .unwrap();
let scope = Scope::new_closure_scope( let scope =
self.avm.current_stack_frame().unwrap().read().scope_cell(), Scope::new_closure_scope(self.activation.read().scope_cell(), context.gc_context);
context.gc_context, let constant_pool = self.activation.read().constant_pool();
);
let constant_pool = self
.avm
.current_stack_frame()
.unwrap()
.read()
.constant_pool();
let func = Avm1Function::from_df2( let func = Avm1Function::from_df2(
swf_version, swf_version,
func_data, func_data,
@ -607,11 +582,9 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
if action_func.name == "" { if action_func.name == "" {
self.avm.push(func_obj); self.avm.push(func_obj);
} else { } else {
self.avm.current_stack_frame().unwrap().read().define( self.activation
action_func.name, .read()
func_obj, .define(action_func.name, func_obj, context.gc_context);
context.gc_context,
);
} }
Ok(()) Ok(())
@ -626,8 +599,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, '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)?;
let stack_frame = self.avm.current_stack_frame().unwrap(); let stack_frame = self.activation.read();
let stack_frame = stack_frame.read();
let scope = stack_frame.scope(); let scope = stack_frame.scope();
scope.locals().set(&name, value, self.avm, context) scope.locals().set(&name, value, self.avm, context)
} }
@ -640,8 +612,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
// Otherwise, the property is unchanged. // Otherwise, the property is unchanged.
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 stack_frame = self.avm.current_stack_frame().unwrap(); let stack_frame = self.activation.read();
let stack_frame = stack_frame.read();
let scope = stack_frame.scope(); let scope = stack_frame.scope();
if !scope.locals().has_property(self.avm, context, &name) { if !scope.locals().has_property(self.avm, context, &name) {
scope scope
@ -679,16 +650,9 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
//Fun fact: This isn't in the Adobe SWF19 spec, but this opcode returns //Fun fact: This isn't in the Adobe SWF19 spec, but this opcode returns
//a boolean based on if the delete actually deleted something. //a boolean based on if the delete actually deleted something.
let did_exist = self let did_exist = self.activation.read().is_defined(self.avm, context, &name);
.avm
.current_stack_frame()
.unwrap()
.read()
.is_defined(self.avm, context, &name);
self.avm self.activation
.current_stack_frame()
.unwrap()
.read() .read()
.scope() .scope()
.delete(self.avm, context, &name, context.gc_context); .delete(self.avm, context, &name, context.gc_context);
@ -726,9 +690,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
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
let object = self let object = self
.avm .activation
.current_stack_frame()
.unwrap()
.read() .read()
.resolve(&name, self.avm, context)? .resolve(&name, self.avm, context)?
.resolve(self.avm, context)?; .resolve(self.avm, context)?;
@ -1495,9 +1457,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
SwfValue::Register(v) => self.avm.current_register(*v), SwfValue::Register(v) => self.avm.current_register(*v),
SwfValue::ConstantPool(i) => { SwfValue::ConstantPool(i) => {
if let Some(value) = self if let Some(value) = self
.avm .activation
.current_stack_frame()
.unwrap()
.read() .read()
.constant_pool() .constant_pool()
.read() .read()
@ -1508,13 +1468,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
log::warn!( log::warn!(
"ActionPush: Constant pool index {} out of range (len = {})", "ActionPush: Constant pool index {} out of range (len = {})",
i, i,
self.avm self.activation.read().constant_pool().read().len()
.current_stack_frame()
.unwrap()
.read()
.constant_pool()
.read()
.len()
); );
Value::Undefined Value::Undefined
} }
@ -1662,8 +1616,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
new_target_clip = None; new_target_clip = None;
} }
let stack_frame = self.avm.current_stack_frame().unwrap(); let mut sf = self.activation.write(context.gc_context);
let mut sf = stack_frame.write(context.gc_context);
sf.set_target_clip(new_target_clip); sf.set_target_clip(new_target_clip);
let scope = sf.scope_cell(); let scope = sf.scope_cell();
@ -1688,15 +1641,13 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
} }
Value::Undefined => { Value::Undefined => {
// Reset // Reset
let stack_frame = self.avm.current_stack_frame().unwrap(); let mut sf = self.activation.write(context.gc_context);
let mut sf = stack_frame.write(context.gc_context);
let base_clip = sf.base_clip(); let base_clip = sf.base_clip();
sf.set_target_clip(Some(base_clip)); sf.set_target_clip(Some(base_clip));
} }
Value::Object(o) => { Value::Object(o) => {
if let Some(clip) = o.as_display_object() { if let Some(clip) = o.as_display_object() {
let stack_frame = self.avm.current_stack_frame().unwrap(); let mut sf = self.activation.write(context.gc_context);
let mut sf = stack_frame.write(context.gc_context);
// Movieclips can be targetted directly // Movieclips can be targetted directly
sf.set_target_clip(Some(clip)); sf.set_target_clip(Some(clip));
} else { } else {
@ -1711,8 +1662,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
} }
}; };
let stack_frame = self.avm.current_stack_frame().unwrap(); let mut sf = self.activation.write(context.gc_context);
let mut sf = stack_frame.write(context.gc_context);
let scope = sf.scope_cell(); let scope = sf.scope_cell();
let clip_obj = sf let clip_obj = sf
.target_clip() .target_clip()
@ -2019,25 +1969,13 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
actions: &[u8], actions: &[u8],
) -> Result<(), Error<'gc>> { ) -> Result<(), 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 let block = self.activation.read().data().to_subslice(actions).unwrap();
.avm
.current_stack_frame()
.unwrap()
.read()
.data()
.to_subslice(actions)
.unwrap();
let with_scope = Scope::new_with_scope( let with_scope = Scope::new_with_scope(
self.avm.current_stack_frame().unwrap().read().scope_cell(), self.activation.read().scope_cell(),
object, object,
context.gc_context, context.gc_context,
); );
let new_activation = self let new_activation = self.activation.read().to_rescope(block, with_scope);
.avm
.current_stack_frame()
.unwrap()
.read()
.to_rescope(block, with_scope);
self.avm self.avm
.stack_frames .stack_frames
.push(GcCell::allocate(context.gc_context, new_activation)); .push(GcCell::allocate(context.gc_context, new_activation));