From aaa082fb60b2f65c69250822a26ee88cde8460b8 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sun, 28 Jun 2020 19:15:01 +0200 Subject: [PATCH] avm1: Replace run_with_stack_frame with run_in_avm --- core/src/avm1.rs | 161 +++++++++++++------------- core/src/avm1/script_object.rs | 13 +-- core/src/avm1/test_utils.rs | 16 +-- core/src/avm1/tests.rs | 33 +++--- core/src/display_object/movie_clip.rs | 65 ++++------- core/src/loader.rs | 18 +-- core/src/player.rs | 132 ++++++++++----------- 7 files changed, 188 insertions(+), 250 deletions(-) diff --git a/core/src/avm1.rs b/core/src/avm1.rs index c9f3a314b..f37f24974 100644 --- a/core/src/avm1.rs +++ b/core/src/avm1.rs @@ -143,41 +143,37 @@ impl<'gc> Avm1<'gc> { return; } - let activation = GcCell::allocate( - action_context.gc_context, - Activation::from_nothing( - swf_version, - self.global_object_cell(), - action_context.gc_context, - active_clip, - ), + self.run_in_avm( + action_context, + swf_version, + active_clip, + |activation, context| { + let clip_obj = active_clip.object().coerce_to_object(activation, context); + let child_scope = GcCell::allocate( + context.gc_context, + Scope::new( + activation.activation().read().scope_cell(), + scope::ScopeClass::Target, + clip_obj, + ), + ); + let child_activation = GcCell::allocate( + context.gc_context, + Activation::from_action( + swf_version, + code, + child_scope, + activation.avm().constant_pool, + active_clip, + clip_obj, + None, + ), + ); + if let Err(e) = activation.run_child_activation(child_activation, context) { + root_error_handler(activation, context, e); + } + }, ); - self.run_with_stack_frame(activation, action_context, |activation, context| { - let clip_obj = active_clip.object().coerce_to_object(activation, context); - let child_scope = GcCell::allocate( - context.gc_context, - Scope::new( - activation.activation().read().scope_cell(), - scope::ScopeClass::Target, - clip_obj, - ), - ); - let child_activation = GcCell::allocate( - context.gc_context, - Activation::from_action( - swf_version, - code, - child_scope, - activation.avm().constant_pool, - active_clip, - clip_obj, - None, - ), - ); - if let Err(e) = activation.run_child_activation(child_activation, context) { - root_error_handler(activation, context, e); - } - }); } /// Add a stack frame that executes code in timeline scope @@ -222,7 +218,8 @@ impl<'gc> Avm1<'gc> { None, ), ); - self.run_with_stack_frame(activation, action_context, function) + let mut stack_frame = StackFrame::new(self, None, activation); + function(&mut stack_frame, action_context) } /// Add a stack frame that executes code in initializer scope @@ -238,42 +235,38 @@ impl<'gc> Avm1<'gc> { return; } - let activation = GcCell::allocate( - action_context.gc_context, - Activation::from_nothing( - swf_version, - self.globals, - action_context.gc_context, - active_clip, - ), + self.run_in_avm( + action_context, + swf_version, + active_clip, + |activation, context| { + let clip_obj = active_clip.object().coerce_to_object(activation, context); + let child_scope = GcCell::allocate( + context.gc_context, + Scope::new( + activation.activation().read().scope_cell(), + scope::ScopeClass::Target, + clip_obj, + ), + ); + activation.avm().push(Value::Undefined); + let child_activation = GcCell::allocate( + context.gc_context, + Activation::from_action( + swf_version, + code, + child_scope, + activation.avm().constant_pool, + active_clip, + clip_obj, + None, + ), + ); + if let Err(e) = activation.run_child_activation(child_activation, context) { + root_error_handler(activation, context, e); + } + }, ); - self.run_with_stack_frame(activation, action_context, |activation, context| { - let clip_obj = active_clip.object().coerce_to_object(activation, context); - let child_scope = GcCell::allocate( - context.gc_context, - Scope::new( - activation.activation().read().scope_cell(), - scope::ScopeClass::Target, - clip_obj, - ), - ); - activation.avm().push(Value::Undefined); - let child_activation = GcCell::allocate( - context.gc_context, - Activation::from_action( - swf_version, - code, - child_scope, - activation.avm().constant_pool, - active_clip, - clip_obj, - None, - ), - ); - if let Err(e) = activation.run_child_activation(child_activation, context) { - root_error_handler(activation, context, e); - } - }); } /// Add a stack frame that executes code in timeline scope for an object @@ -292,10 +285,6 @@ impl<'gc> Avm1<'gc> { return; } - let activation = GcCell::allocate( - context.gc_context, - Activation::from_nothing(swf_version, self.globals, context.gc_context, active_clip), - ); fn caller<'gc>( activation: &mut StackFrame<'_, 'gc>, context: &mut UpdateContext<'_, 'gc, '_>, @@ -310,21 +299,33 @@ impl<'gc> Avm1<'gc> { let _ = callback.call(activation, context, obj, base_proto, args); } } - self.run_with_stack_frame(activation, context, |activation, context| { + self.run_in_avm(context, swf_version, active_clip, |activation, context| { caller(activation, context, obj, name, args) }); } /// Run a function within the scope of an activation. - pub fn run_with_stack_frame<'a, F, R>( + /// + /// This is intended to be used to create a new frame stack from nothing. + pub fn run_in_avm<'a, F, R>( &mut self, - activation: GcCell<'gc, Activation<'gc>>, context: &mut UpdateContext<'a, 'gc, '_>, + swf_version: u8, + base_clip: DisplayObject<'gc>, function: F, ) -> R where for<'b> F: FnOnce(&mut StackFrame<'b, 'gc>, &mut UpdateContext<'a, 'gc, '_>) -> R, { + let activation = GcCell::allocate( + context.gc_context, + Activation::from_nothing( + swf_version, + self.global_object_cell(), + context.gc_context, + base_clip, + ), + ); let mut stack_frame = StackFrame::new(self, None, activation); function(&mut stack_frame, context) } @@ -338,11 +339,7 @@ impl<'gc> Avm1<'gc> { method: &str, args: &[Value<'gc>], ) { - let activation = GcCell::allocate( - context.gc_context, - Activation::from_nothing(swf_version, self.globals, context.gc_context, active_clip), - ); - self.run_with_stack_frame(activation, context, |activation, context| { + self.run_in_avm(context, swf_version, active_clip, |activation, context| { let listeners = activation.avm().system_listeners.get(listener); let mut handlers = listeners.prepare_handlers(activation, context, method); diff --git a/core/src/avm1/script_object.rs b/core/src/avm1/script_object.rs index 4c2eee2ab..a686b26dc 100644 --- a/core/src/avm1/script_object.rs +++ b/core/src/avm1/script_object.rs @@ -726,7 +726,6 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> { mod tests { use super::*; - use crate::avm1::activation::Activation; use crate::avm1::globals::system::SystemProperties; use crate::avm1::property::Attribute::*; use crate::avm1::Avm1; @@ -800,15 +799,9 @@ mod tests { let object = ScriptObject::object(gc_context, Some(avm.prototypes().object)).into(); - let globals = avm.global_object_cell(); - avm.run_with_stack_frame( - GcCell::allocate( - gc_context, - Activation::from_nothing(swf_version, globals, gc_context, root), - ), - &mut context, - |activation, context| test(activation, context, object), - ) + avm.run_in_avm(&mut context, swf_version, root, |activation, context| { + test(activation, context, object) + }) }) } diff --git a/core/src/avm1/test_utils.rs b/core/src/avm1/test_utils.rs index c028eaf69..ad8080ebc 100644 --- a/core/src/avm1/test_utils.rs +++ b/core/src/avm1/test_utils.rs @@ -1,4 +1,3 @@ -use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::globals::system::SystemProperties; use crate::avm1::stack_frame::StackFrame; @@ -14,7 +13,7 @@ use crate::library::Library; use crate::loader::LoadManager; use crate::prelude::*; use crate::tag_utils::{SwfMovie, SwfSlice}; -use gc_arena::{rootless_arena, GcCell, MutationContext}; +use gc_arena::{rootless_arena, MutationContext}; use rand::{rngs::SmallRng, SeedableRng}; use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -78,8 +77,6 @@ where root.post_instantiation(&mut avm, &mut context, root, None, false); root.set_name(context.gc_context, ""); - let globals = avm.global_object_cell(); - fn run_test<'a, 'gc: 'a, F>( activation: &mut StackFrame<'_, 'gc>, context: &mut UpdateContext<'_, 'gc, '_>, @@ -99,14 +96,9 @@ where } } - avm.run_with_stack_frame( - GcCell::allocate( - gc_context, - Activation::from_nothing(swf_version, globals, gc_context, root), - ), - &mut context, - |activation, context| run_test(activation, context, root, test), - ); + avm.run_in_avm(&mut context, swf_version, root, |activation, context| { + run_test(activation, context, root, test) + }); } rootless_arena(|gc_context| in_the_arena(swf_version, test, gc_context)) diff --git a/core/src/avm1/tests.rs b/core/src/avm1/tests.rs index aebdbb453..3b602a352 100644 --- a/core/src/avm1/tests.rs +++ b/core/src/avm1/tests.rs @@ -1,31 +1,24 @@ -use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::test_utils::with_avm; use crate::avm1::TObject; -use gc_arena::GcCell; #[test] fn locals_into_form_values() { with_avm(19, |activation, context, _this| -> Result<(), Error> { - let my_activation = Activation::from_nothing( - 19, - activation.avm().global_object_cell(), - context.gc_context, - *context.levels.get(&0).expect("_level0 in test"), - ); - let my_locals = my_activation.scope().locals().to_owned(); - - my_locals - .set("value1", "string".into(), activation, context) - .unwrap(); - my_locals - .set("value2", 2.0.into(), activation, context) - .unwrap(); - - let my_local_values = activation.avm().run_with_stack_frame( - GcCell::allocate(context.gc_context, my_activation), + let my_local_values = activation.avm().run_in_avm( context, - |activation, context| activation.locals_into_form_values(context), + 19, + *context.levels.get(&0).expect("_level0 in test"), + |activation, context| { + let my_locals = activation.activation().read().scope().locals().to_owned(); + my_locals + .set("value1", "string".into(), activation, context) + .unwrap(); + my_locals + .set("value2", 2.0.into(), activation, context) + .unwrap(); + activation.locals_into_form_values(context) + }, ); assert_eq!(my_local_values.len(), 2); diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 623de1847..6e13ab925 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -1,5 +1,5 @@ //! `MovieClip` display object and support code. -use crate::avm1::{Activation, Avm1, Object, StageObject, TObject, Value}; +use crate::avm1::{Avm1, Object, StageObject, TObject, Value}; use crate::backend::audio::AudioStreamHandle; use crate::avm1::stack_frame::StackFrame; @@ -975,15 +975,6 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> { return Some(self_node); } - let activation = GcCell::allocate( - context.gc_context, - Activation::from_nothing( - context.swf.version(), - avm.global_object_cell(), - context.gc_context, - *context.levels.get(&0).unwrap(), - ), - ); fn finder<'gc>( activation: &mut StackFrame<'_, 'gc>, context: &mut UpdateContext<'_, 'gc, '_>, @@ -1000,10 +991,12 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> { } None }; - let result: Option> = - avm.run_with_stack_frame(activation, context, |activation, context| { - finder(activation, context, self_node, self.object()) - }); + let result: Option> = avm.run_in_avm( + context, + context.swf.version(), + *context.levels.get(&0).unwrap(), + |activation, context| finder(activation, context, self_node, self.object()), + ); if result.is_some() { return result; } @@ -1057,15 +1050,6 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> { // If we are running within the AVM, this must be an immediate action. // If we are not, then this must be queued to be ran first-thing if instantiated_from_avm && self.0.read().avm1_constructor.is_some() { - let activation = GcCell::allocate( - context.gc_context, - Activation::from_nothing( - context.swf.version(), - avm.global_object_cell(), - context.gc_context, - *context.levels.get(&0).unwrap(), - ), - ); fn initializer<'gc>( activation: &mut StackFrame<'_, 'gc>, context: &mut UpdateContext<'_, 'gc, '_>, @@ -1094,9 +1078,12 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> { let _ = constructor.call(activation, context, object, None, &[]); } } - avm.run_with_stack_frame(activation, context, |activation, context| { - initializer(activation, context, self, init_object) - }); + avm.run_in_avm( + context, + context.swf.version(), + *context.levels.get(&0).unwrap(), + |activation, context| initializer(activation, context, self, init_object), + ); return; } @@ -1106,22 +1093,18 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> { Some(context.system_prototypes.movie_clip), ); if let Some(init_object) = init_object { - let activation = GcCell::allocate( - context.gc_context, - Activation::from_nothing( - context.swf.version(), - avm.global_object_cell(), - context.gc_context, - *context.levels.get(&0).unwrap(), - ), - ); - avm.run_with_stack_frame(activation, context, |activation, context| { - for key in init_object.get_keys(activation) { - if let Ok(value) = init_object.get(&key, activation, context) { - let _ = object.set(&key, value, activation, context); + avm.run_in_avm( + context, + context.swf.version(), + *context.levels.get(&0).unwrap(), + |activation, context| { + for key in init_object.get_keys(activation) { + if let Ok(value) = init_object.get(&key, activation, context) { + let _ = object.set(&key, value, activation, context); + } } - } - }); + }, + ); } let mut mc = self.0.write(context.gc_context); mc.object = Some(object.into()); diff --git a/core/src/loader.rs b/core/src/loader.rs index 2a6a1bfdd..d66353d99 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -1,13 +1,13 @@ //! Management of async loaders -use crate::avm1::{Activation, Object, TObject, Value}; +use crate::avm1::{Object, TObject, Value}; use crate::backend::navigator::OwnedFuture; use crate::context::{ActionQueue, ActionType}; use crate::display_object::{DisplayObject, MorphShape, TDisplayObject}; use crate::player::{Player, NEWEST_PLAYER_VERSION}; use crate::tag_utils::SwfMovie; use crate::xml::XMLNode; -use gc_arena::{Collect, CollectionContext, GcCell}; +use gc_arena::{Collect, CollectionContext}; use generational_arena::{Arena, Index}; use std::string::FromUtf8Error; use std::sync::{Arc, Mutex, Weak}; @@ -473,18 +473,10 @@ impl<'gc> Loader<'gc> { _ => return Err(Error::NotMovieLoader), }; - let activation = GcCell::allocate( - uc.gc_context, - Activation::from_nothing( - uc.swf.version(), - avm.global_object_cell(), - uc.gc_context, - *uc.levels.get(&0).unwrap(), - ), - ); - avm.run_with_stack_frame::<_, Result<(), crate::avm1::error::Error>>( - activation, + avm.run_in_avm::<_, Result<(), crate::avm1::error::Error>>( uc, + uc.swf.version(), + *uc.levels.get(&0).unwrap(), |activation, context| { for (k, v) in form_urlencoded::parse(&data) { that.set(&k, v.into_owned().into(), activation, context)?; diff --git a/core/src/player.rs b/core/src/player.rs index 334b6de93..8e601be98 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -3,7 +3,7 @@ use crate::avm1::globals::system::SystemProperties; use crate::avm1::listeners::SystemListener; use crate::avm1::object::Object; use crate::avm1::stack_frame::StackFrame; -use crate::avm1::{Activation, Avm1, TObject, Value}; +use crate::avm1::{Avm1, TObject, Value}; use crate::backend::input::{InputBackend, MouseCursor}; use crate::backend::storage::StorageBackend; use crate::backend::{ @@ -272,24 +272,20 @@ impl Player { root.set_name(context.gc_context, ""); context.levels.insert(0, root); - let activation = GcCell::allocate( - context.gc_context, - Activation::from_nothing( - context.swf.version(), - avm.global_object_cell(), - context.gc_context, - *context.levels.get(&0).unwrap(), - ), + avm.run_in_avm( + context, + context.swf.version(), + *context.levels.get(&0).unwrap(), + |activation, context| { + let object = root.object().coerce_to_object(activation, context); + object.define_value( + context.gc_context, + "$version", + context.system.get_version_string(activation).into(), + EnumSet::empty(), + ); + }, ); - avm.run_with_stack_frame(activation, context, |activation, context| { - let object = root.object().coerce_to_object(activation, context); - object.define_value( - context.gc_context, - "$version", - context.system.get_version_string(activation).into(), - EnumSet::empty(), - ); - }); }); player.build_matrices(); @@ -391,37 +387,33 @@ impl Player { if self.input.is_key_down(KeyCode::Control) && self.input.is_key_down(KeyCode::Alt) { self.mutate_with_update_context(|avm, context| { let mut dumper = VariableDumper::new(" "); - let activation = GcCell::allocate( - context.gc_context, - Activation::from_nothing( - context.swf.version(), - avm.global_object_cell(), - context.gc_context, - *context.levels.get(&0).unwrap(), - ), - ); - avm.run_with_stack_frame(activation, context, |activation, context| { - dumper.print_variables( - "Global Variables:", - "_global", - &activation.avm().global_object_cell(), - activation, - context, - ); - let levels = context.levels.clone(); - for (level, display_object) in levels { - let object = display_object - .object() - .coerce_to_object(activation, context); + avm.run_in_avm( + context, + context.swf.version(), + *context.levels.get(&0).unwrap(), + |activation, context| { dumper.print_variables( - &format!("Level #{}:", level), - &format!("_level{}", level), - &object, + "Global Variables:", + "_global", + &activation.avm().global_object_cell(), activation, context, ); - } - }); + let levels = context.levels.clone(); + for (level, display_object) in levels { + let object = display_object + .object() + .coerce_to_object(activation, context); + dumper.print_variables( + &format!("Level #{}:", level), + &format!("_level{}", level), + &object, + activation, + context, + ); + } + }, + ); log::info!("Variable dump:\n{}", dumper.output()); }); } @@ -756,15 +748,6 @@ impl Player { constructor: Some(constructor), events, } => { - let activation = GcCell::allocate( - context.gc_context, - Activation::from_nothing( - context.swf.version(), - avm.global_object_cell(), - context.gc_context, - actions.clip, - ), - ); fn initializer<'gc>( activation: &mut StackFrame<'_, 'gc>, context: &mut UpdateContext<'_, 'gc, '_>, @@ -792,9 +775,14 @@ impl Player { } } let clip = actions.clip; - avm.run_with_stack_frame(activation, context, |activation, context| { - initializer(activation, context, clip, constructor, events) - }); + avm.run_in_avm( + context, + context.swf.version(), + actions.clip, + |activation, context| { + initializer(activation, context, clip, constructor, events) + }, + ); } // Run constructor events without changing the prototype ActionType::Construct { @@ -1023,22 +1011,22 @@ impl Player { pub fn flush_shared_objects(&mut self) { self.update(|avm, update_context| { - let activation = GcCell::allocate( - update_context.gc_context, - Activation::from_nothing( - update_context.swf.version(), - avm.global_object_cell(), - update_context.gc_context, - *update_context.levels.get(&0).unwrap(), - ), + avm.run_in_avm( + update_context, + update_context.swf.version(), + *update_context.levels.get(&0).unwrap(), + |activation, context| { + let shared_objects = context.shared_objects.clone(); + for so in shared_objects.values() { + let _ = crate::avm1::globals::shared_object::flush( + activation, + context, + *so, + &[], + ); + } + }, ); - avm.run_with_stack_frame(activation, update_context, |activation, context| { - let shared_objects = context.shared_objects.clone(); - for so in shared_objects.values() { - let _ = - crate::avm1::globals::shared_object::flush(activation, context, *so, &[]); - } - }); }); } }