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;
}
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);

View File

@ -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)
})
})
}

View File

@ -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))

View File

@ -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);

View File

@ -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<DisplayObject<'gc>> =
avm.run_with_stack_frame(activation, context, |activation, context| {
finder(activation, context, self_node, self.object())
});
let result: Option<DisplayObject<'gc>> = 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());

View File

@ -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)?;

View File

@ -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, &[]);
}
});
});
}
}