avm1: Replace run_with_stack_frame with run_in_avm

This commit is contained in:
Nathan Adams 2020-06-28 19:15:01 +02:00
parent 0dd2ece371
commit aaa082fb60
7 changed files with 188 additions and 250 deletions

View File

@ -143,41 +143,37 @@ impl<'gc> Avm1<'gc> {
return; return;
} }
let activation = GcCell::allocate( self.run_in_avm(
action_context.gc_context, action_context,
Activation::from_nothing( swf_version,
swf_version, active_clip,
self.global_object_cell(), |activation, context| {
action_context.gc_context, let clip_obj = active_clip.object().coerce_to_object(activation, context);
active_clip, 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 /// Add a stack frame that executes code in timeline scope
@ -222,7 +218,8 @@ impl<'gc> Avm1<'gc> {
None, 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 /// Add a stack frame that executes code in initializer scope
@ -238,42 +235,38 @@ impl<'gc> Avm1<'gc> {
return; return;
} }
let activation = GcCell::allocate( self.run_in_avm(
action_context.gc_context, action_context,
Activation::from_nothing( swf_version,
swf_version, active_clip,
self.globals, |activation, context| {
action_context.gc_context, let clip_obj = active_clip.object().coerce_to_object(activation, context);
active_clip, 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 /// Add a stack frame that executes code in timeline scope for an object
@ -292,10 +285,6 @@ impl<'gc> Avm1<'gc> {
return; return;
} }
let activation = GcCell::allocate(
context.gc_context,
Activation::from_nothing(swf_version, self.globals, context.gc_context, active_clip),
);
fn caller<'gc>( fn caller<'gc>(
activation: &mut StackFrame<'_, 'gc>, activation: &mut StackFrame<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
@ -310,21 +299,33 @@ impl<'gc> Avm1<'gc> {
let _ = callback.call(activation, context, obj, base_proto, args); 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) caller(activation, context, obj, name, args)
}); });
} }
/// Run a function within the scope of an activation. /// 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, &mut self,
activation: GcCell<'gc, Activation<'gc>>,
context: &mut UpdateContext<'a, 'gc, '_>, context: &mut UpdateContext<'a, 'gc, '_>,
swf_version: u8,
base_clip: DisplayObject<'gc>,
function: F, function: F,
) -> R ) -> R
where where
for<'b> F: FnOnce(&mut StackFrame<'b, 'gc>, &mut UpdateContext<'a, 'gc, '_>) -> R, 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); let mut stack_frame = StackFrame::new(self, None, activation);
function(&mut stack_frame, context) function(&mut stack_frame, context)
} }
@ -338,11 +339,7 @@ impl<'gc> Avm1<'gc> {
method: &str, method: &str,
args: &[Value<'gc>], args: &[Value<'gc>],
) { ) {
let activation = GcCell::allocate( self.run_in_avm(context, swf_version, active_clip, |activation, context| {
context.gc_context,
Activation::from_nothing(swf_version, self.globals, context.gc_context, active_clip),
);
self.run_with_stack_frame(activation, context, |activation, context| {
let listeners = activation.avm().system_listeners.get(listener); let listeners = activation.avm().system_listeners.get(listener);
let mut handlers = listeners.prepare_handlers(activation, context, method); let mut handlers = listeners.prepare_handlers(activation, context, method);

View File

@ -726,7 +726,6 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
mod tests { mod tests {
use super::*; use super::*;
use crate::avm1::activation::Activation;
use crate::avm1::globals::system::SystemProperties; use crate::avm1::globals::system::SystemProperties;
use crate::avm1::property::Attribute::*; use crate::avm1::property::Attribute::*;
use crate::avm1::Avm1; use crate::avm1::Avm1;
@ -800,15 +799,9 @@ mod tests {
let object = ScriptObject::object(gc_context, Some(avm.prototypes().object)).into(); let object = ScriptObject::object(gc_context, Some(avm.prototypes().object)).into();
let globals = avm.global_object_cell(); avm.run_in_avm(&mut context, swf_version, root, |activation, context| {
avm.run_with_stack_frame( test(activation, context, object)
GcCell::allocate( })
gc_context,
Activation::from_nothing(swf_version, globals, gc_context, root),
),
&mut context,
|activation, context| test(activation, context, object),
)
}) })
} }

View File

@ -1,4 +1,3 @@
use crate::avm1::activation::Activation;
use crate::avm1::error::Error; use crate::avm1::error::Error;
use crate::avm1::globals::system::SystemProperties; use crate::avm1::globals::system::SystemProperties;
use crate::avm1::stack_frame::StackFrame; use crate::avm1::stack_frame::StackFrame;
@ -14,7 +13,7 @@ use crate::library::Library;
use crate::loader::LoadManager; use crate::loader::LoadManager;
use crate::prelude::*; use crate::prelude::*;
use crate::tag_utils::{SwfMovie, SwfSlice}; 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 rand::{rngs::SmallRng, SeedableRng};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::sync::Arc; use std::sync::Arc;
@ -78,8 +77,6 @@ where
root.post_instantiation(&mut avm, &mut context, root, None, false); root.post_instantiation(&mut avm, &mut context, root, None, false);
root.set_name(context.gc_context, ""); root.set_name(context.gc_context, "");
let globals = avm.global_object_cell();
fn run_test<'a, 'gc: 'a, F>( fn run_test<'a, 'gc: 'a, F>(
activation: &mut StackFrame<'_, 'gc>, activation: &mut StackFrame<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
@ -99,14 +96,9 @@ where
} }
} }
avm.run_with_stack_frame( avm.run_in_avm(&mut context, swf_version, root, |activation, context| {
GcCell::allocate( run_test(activation, context, root, test)
gc_context, });
Activation::from_nothing(swf_version, globals, gc_context, root),
),
&mut context,
|activation, context| run_test(activation, context, root, test),
);
} }
rootless_arena(|gc_context| in_the_arena(swf_version, test, gc_context)) rootless_arena(|gc_context| in_the_arena(swf_version, test, gc_context))

View File

@ -1,31 +1,24 @@
use crate::avm1::activation::Activation;
use crate::avm1::error::Error; use crate::avm1::error::Error;
use crate::avm1::test_utils::with_avm; use crate::avm1::test_utils::with_avm;
use crate::avm1::TObject; use crate::avm1::TObject;
use gc_arena::GcCell;
#[test] #[test]
fn locals_into_form_values() { fn locals_into_form_values() {
with_avm(19, |activation, context, _this| -> Result<(), Error> { with_avm(19, |activation, context, _this| -> Result<(), Error> {
let my_activation = Activation::from_nothing( let my_local_values = activation.avm().run_in_avm(
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),
context, 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); assert_eq!(my_local_values.len(), 2);

View File

@ -1,5 +1,5 @@
//! `MovieClip` display object and support code. //! `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::backend::audio::AudioStreamHandle;
use crate::avm1::stack_frame::StackFrame; use crate::avm1::stack_frame::StackFrame;
@ -975,15 +975,6 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
return Some(self_node); 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>( fn finder<'gc>(
activation: &mut StackFrame<'_, 'gc>, activation: &mut StackFrame<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
@ -1000,10 +991,12 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
} }
None None
}; };
let result: Option<DisplayObject<'gc>> = let result: Option<DisplayObject<'gc>> = avm.run_in_avm(
avm.run_with_stack_frame(activation, context, |activation, context| { context,
finder(activation, context, self_node, self.object()) context.swf.version(),
}); *context.levels.get(&0).unwrap(),
|activation, context| finder(activation, context, self_node, self.object()),
);
if result.is_some() { if result.is_some() {
return result; 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 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 we are not, then this must be queued to be ran first-thing
if instantiated_from_avm && self.0.read().avm1_constructor.is_some() { 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>( fn initializer<'gc>(
activation: &mut StackFrame<'_, 'gc>, activation: &mut StackFrame<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
@ -1094,9 +1078,12 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
let _ = constructor.call(activation, context, object, None, &[]); let _ = constructor.call(activation, context, object, None, &[]);
} }
} }
avm.run_with_stack_frame(activation, context, |activation, context| { avm.run_in_avm(
initializer(activation, context, self, init_object) context,
}); context.swf.version(),
*context.levels.get(&0).unwrap(),
|activation, context| initializer(activation, context, self, init_object),
);
return; return;
} }
@ -1106,22 +1093,18 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
Some(context.system_prototypes.movie_clip), Some(context.system_prototypes.movie_clip),
); );
if let Some(init_object) = init_object { if let Some(init_object) = init_object {
let activation = GcCell::allocate( avm.run_in_avm(
context.gc_context, context,
Activation::from_nothing( context.swf.version(),
context.swf.version(), *context.levels.get(&0).unwrap(),
avm.global_object_cell(), |activation, context| {
context.gc_context, for key in init_object.get_keys(activation) {
*context.levels.get(&0).unwrap(), if let Ok(value) = init_object.get(&key, activation, context) {
), let _ = object.set(&key, value, activation, context);
); }
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);
} }
} },
}); );
} }
let mut mc = self.0.write(context.gc_context); let mut mc = self.0.write(context.gc_context);
mc.object = Some(object.into()); mc.object = Some(object.into());

View File

@ -1,13 +1,13 @@
//! Management of async loaders //! Management of async loaders
use crate::avm1::{Activation, Object, TObject, Value}; use crate::avm1::{Object, TObject, Value};
use crate::backend::navigator::OwnedFuture; use crate::backend::navigator::OwnedFuture;
use crate::context::{ActionQueue, ActionType}; use crate::context::{ActionQueue, ActionType};
use crate::display_object::{DisplayObject, MorphShape, TDisplayObject}; use crate::display_object::{DisplayObject, MorphShape, TDisplayObject};
use crate::player::{Player, NEWEST_PLAYER_VERSION}; use crate::player::{Player, NEWEST_PLAYER_VERSION};
use crate::tag_utils::SwfMovie; use crate::tag_utils::SwfMovie;
use crate::xml::XMLNode; use crate::xml::XMLNode;
use gc_arena::{Collect, CollectionContext, GcCell}; use gc_arena::{Collect, CollectionContext};
use generational_arena::{Arena, Index}; use generational_arena::{Arena, Index};
use std::string::FromUtf8Error; use std::string::FromUtf8Error;
use std::sync::{Arc, Mutex, Weak}; use std::sync::{Arc, Mutex, Weak};
@ -473,18 +473,10 @@ impl<'gc> Loader<'gc> {
_ => return Err(Error::NotMovieLoader), _ => return Err(Error::NotMovieLoader),
}; };
let activation = GcCell::allocate( avm.run_in_avm::<_, Result<(), crate::avm1::error::Error>>(
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,
uc, uc,
uc.swf.version(),
*uc.levels.get(&0).unwrap(),
|activation, context| { |activation, context| {
for (k, v) in form_urlencoded::parse(&data) { for (k, v) in form_urlencoded::parse(&data) {
that.set(&k, v.into_owned().into(), activation, context)?; that.set(&k, v.into_owned().into(), activation, context)?;

View File

@ -3,7 +3,7 @@ use crate::avm1::globals::system::SystemProperties;
use crate::avm1::listeners::SystemListener; use crate::avm1::listeners::SystemListener;
use crate::avm1::object::Object; use crate::avm1::object::Object;
use crate::avm1::stack_frame::StackFrame; 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::input::{InputBackend, MouseCursor};
use crate::backend::storage::StorageBackend; use crate::backend::storage::StorageBackend;
use crate::backend::{ use crate::backend::{
@ -272,24 +272,20 @@ impl Player {
root.set_name(context.gc_context, ""); root.set_name(context.gc_context, "");
context.levels.insert(0, root); context.levels.insert(0, root);
let activation = GcCell::allocate( avm.run_in_avm(
context.gc_context, context,
Activation::from_nothing( context.swf.version(),
context.swf.version(), *context.levels.get(&0).unwrap(),
avm.global_object_cell(), |activation, context| {
context.gc_context, let object = root.object().coerce_to_object(activation, context);
*context.levels.get(&0).unwrap(), 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(); player.build_matrices();
@ -391,37 +387,33 @@ impl Player {
if self.input.is_key_down(KeyCode::Control) && self.input.is_key_down(KeyCode::Alt) { if self.input.is_key_down(KeyCode::Control) && self.input.is_key_down(KeyCode::Alt) {
self.mutate_with_update_context(|avm, context| { self.mutate_with_update_context(|avm, context| {
let mut dumper = VariableDumper::new(" "); let mut dumper = VariableDumper::new(" ");
let activation = GcCell::allocate( avm.run_in_avm(
context.gc_context, context,
Activation::from_nothing( context.swf.version(),
context.swf.version(), *context.levels.get(&0).unwrap(),
avm.global_object_cell(), |activation, context| {
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);
dumper.print_variables( dumper.print_variables(
&format!("Level #{}:", level), "Global Variables:",
&format!("_level{}", level), "_global",
&object, &activation.avm().global_object_cell(),
activation, activation,
context, 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()); log::info!("Variable dump:\n{}", dumper.output());
}); });
} }
@ -756,15 +748,6 @@ impl Player {
constructor: Some(constructor), constructor: Some(constructor),
events, 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>( fn initializer<'gc>(
activation: &mut StackFrame<'_, 'gc>, activation: &mut StackFrame<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
@ -792,9 +775,14 @@ impl Player {
} }
} }
let clip = actions.clip; let clip = actions.clip;
avm.run_with_stack_frame(activation, context, |activation, context| { avm.run_in_avm(
initializer(activation, context, clip, constructor, events) context,
}); context.swf.version(),
actions.clip,
|activation, context| {
initializer(activation, context, clip, constructor, events)
},
);
} }
// Run constructor events without changing the prototype // Run constructor events without changing the prototype
ActionType::Construct { ActionType::Construct {
@ -1023,22 +1011,22 @@ impl Player {
pub fn flush_shared_objects(&mut self) { pub fn flush_shared_objects(&mut self) {
self.update(|avm, update_context| { self.update(|avm, update_context| {
let activation = GcCell::allocate( avm.run_in_avm(
update_context.gc_context, update_context,
Activation::from_nothing( update_context.swf.version(),
update_context.swf.version(), *update_context.levels.get(&0).unwrap(),
avm.global_object_cell(), |activation, context| {
update_context.gc_context, let shared_objects = context.shared_objects.clone();
*update_context.levels.get(&0).unwrap(), 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, &[]);
}
});
}); });
} }
} }