Move AVM2 into the UpdateContext.

This commit is contained in:
David Wendt 2020-07-27 23:19:43 -04:00
parent bfa5f8ae35
commit 8ebf5405e2
23 changed files with 501 additions and 632 deletions

View File

@ -843,6 +843,7 @@ mod tests {
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, Timers}; use crate::avm1::{Avm1, Timers};
use crate::avm2::Avm2;
use crate::backend::audio::NullAudioBackend; use crate::backend::audio::NullAudioBackend;
use crate::backend::input::NullInputBackend; use crate::backend::input::NullInputBackend;
use crate::backend::navigator::NullNavigatorBackend; use crate::backend::navigator::NullNavigatorBackend;
@ -864,7 +865,8 @@ mod tests {
F: for<'a, 'gc> FnOnce(&mut Activation<'_, 'gc, '_>, Object<'gc>) -> R, F: for<'a, 'gc> FnOnce(&mut Activation<'_, 'gc, '_>, Object<'gc>) -> R,
{ {
rootless_arena(|gc_context| { rootless_arena(|gc_context| {
let mut avm = Avm1::new(gc_context, swf_version); let mut avm1 = Avm1::new(gc_context, swf_version);
let mut avm2 = Avm2::new(gc_context);
let swf = Arc::new(SwfMovie::empty(swf_version)); let swf = Arc::new(SwfMovie::empty(swf_version));
let mut root: DisplayObject<'_> = let mut root: DisplayObject<'_> =
MovieClip::new(SwfSlice::empty(swf.clone()), gc_context).into(); MovieClip::new(SwfSlice::empty(swf.clone()), gc_context).into();
@ -872,8 +874,8 @@ mod tests {
let mut levels = BTreeMap::new(); let mut levels = BTreeMap::new();
levels.insert(0, root); levels.insert(0, root);
let object = ScriptObject::object(gc_context, Some(avm.prototypes().object)).into(); let object = ScriptObject::object(gc_context, Some(avm1.prototypes().object)).into();
let globals = avm.global_object_cell(); let globals = avm1.global_object_cell();
let mut context = UpdateContext { let mut context = UpdateContext {
gc_context, gc_context,
@ -893,7 +895,7 @@ mod tests {
library: &mut Library::default(), library: &mut Library::default(),
navigator: &mut NullNavigatorBackend::new(), navigator: &mut NullNavigatorBackend::new(),
renderer: &mut NullRenderer::new(), renderer: &mut NullRenderer::new(),
system_prototypes: avm.prototypes().clone(), system_prototypes: avm1.prototypes().clone(),
mouse_hovered_object: None, mouse_hovered_object: None,
mouse_position: &(Twips::new(0), Twips::new(0)), mouse_position: &(Twips::new(0), Twips::new(0)),
drag_object: &mut None, drag_object: &mut None,
@ -907,7 +909,8 @@ mod tests {
unbound_text_fields: &mut Vec::new(), unbound_text_fields: &mut Vec::new(),
timers: &mut Timers::new(), timers: &mut Timers::new(),
needs_render: &mut false, needs_render: &mut false,
avm1: &mut avm, avm1: &mut avm1,
avm2: &mut avm2,
}; };
root.post_instantiation(&mut context, root, None, false); root.post_instantiation(&mut context, root, None, false);

View File

@ -2,6 +2,7 @@ use crate::avm1::activation::{Activation, ActivationIdentifier};
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::{Avm1, Object, Timers, UpdateContext}; use crate::avm1::{Avm1, Object, Timers, UpdateContext};
use crate::avm2::Avm2;
use crate::backend::audio::NullAudioBackend; use crate::backend::audio::NullAudioBackend;
use crate::backend::input::NullInputBackend; use crate::backend::input::NullInputBackend;
use crate::backend::navigator::NullNavigatorBackend; use crate::backend::navigator::NullNavigatorBackend;
@ -27,6 +28,7 @@ where
F: FnOnce(&mut Activation<'_, 'gc, '_>, Object<'gc>) -> Result<(), Error<'gc>>, F: FnOnce(&mut Activation<'_, 'gc, '_>, Object<'gc>) -> Result<(), Error<'gc>>,
{ {
let mut avm1 = Avm1::new(gc_context, swf_version); let mut avm1 = Avm1::new(gc_context, swf_version);
let mut avm2 = Avm2::new(gc_context);
let swf = Arc::new(SwfMovie::empty(swf_version)); let swf = Arc::new(SwfMovie::empty(swf_version));
let mut root: DisplayObject<'gc> = let mut root: DisplayObject<'gc> =
MovieClip::new(SwfSlice::empty(swf.clone()), gc_context).into(); MovieClip::new(SwfSlice::empty(swf.clone()), gc_context).into();
@ -69,6 +71,7 @@ where
timers: &mut Timers::new(), timers: &mut Timers::new(),
needs_render: &mut false, needs_render: &mut false,
avm1: &mut avm1, avm1: &mut avm1,
avm2: &mut avm2,
}; };
root.post_instantiation(&mut context, root, None, false); root.post_instantiation(&mut context, root, None, false);
root.set_name(context.gc_context, ""); root.set_name(context.gc_context, "");

View File

@ -85,20 +85,19 @@ impl<'gc> Avm2<'gc> {
/// Run a script's initializer method. /// Run a script's initializer method.
pub fn run_script_initializer( pub fn run_script_initializer(
&mut self,
script: GcCell<'gc, Script<'gc>>, script: GcCell<'gc, Script<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut init_activation = Activation::from_script(self, context, script, self.globals)?; let globals = context.avm2.globals;
let mut init_activation = Activation::from_script(context.reborrow(), script, globals)?;
init_activation.run_stack_frame_for_script(context, script) init_activation.run_stack_frame_for_script(script)
} }
/// Load an ABC file embedded in a `SwfSlice`. /// Load an ABC file embedded in a `SwfSlice`.
/// ///
/// The `SwfSlice` must resolve to the contents of an ABC file. /// The `SwfSlice` must resolve to the contents of an ABC file.
pub fn load_abc( pub fn load_abc(
&mut self,
abc: SwfSlice, abc: SwfSlice,
_abc_name: &str, _abc_name: &str,
_lazy_init: bool, _lazy_init: bool,
@ -111,16 +110,15 @@ impl<'gc> Avm2<'gc> {
for i in (0..abc_file.scripts.len()).rev() { for i in (0..abc_file.scripts.len()).rev() {
let script = tunit.load_script(i as u32, context.gc_context)?; let script = tunit.load_script(i as u32, context.gc_context)?;
let mut globals = self.globals(); let mut globals = context.avm2.globals();
let scope = Scope::push_scope(None, globals, context.gc_context); let scope = Scope::push_scope(None, globals, context.gc_context);
let mut null_activation = Activation::from_nothing(self, context); let mut null_activation = Activation::from_nothing(context.reborrow());
// TODO: Lazyinit means we shouldn't do this until traits are // TODO: Lazyinit means we shouldn't do this until traits are
// actually mentioned... // actually mentioned...
for trait_entry in script.read().traits()?.iter() { for trait_entry in script.read().traits()?.iter() {
globals.install_foreign_trait( globals.install_foreign_trait(
&mut null_activation, &mut null_activation,
context,
trait_entry.clone(), trait_entry.clone(),
Some(scope), Some(scope),
globals, globals,
@ -129,7 +127,7 @@ impl<'gc> Avm2<'gc> {
drop(null_activation); drop(null_activation);
self.run_script_initializer(script, context)?; Self::run_script_initializer(script, context)?;
} }
Ok(()) Ok(())

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@ use crate::avm2::script_object::{ScriptObject, ScriptObjectClass, ScriptObjectDa
use crate::avm2::string::AvmString; use crate::avm2::string::AvmString;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, CollectionContext, Gc, GcCell, MutationContext}; use gc_arena::{Collect, CollectionContext, Gc, GcCell, MutationContext};
use std::fmt; use std::fmt;
@ -87,22 +86,17 @@ impl<'gc> Executable<'gc> {
&self, &self,
unbound_reciever: Option<Object<'gc>>, unbound_reciever: Option<Object<'gc>>,
arguments: &[Value<'gc>], arguments: &[Value<'gc>],
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
base_proto: Option<Object<'gc>>, base_proto: Option<Object<'gc>>,
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
match self { match self {
Executable::Native(nf, reciever) => nf( Executable::Native(nf, reciever) => {
activation, nf(activation, reciever.or(unbound_reciever), arguments)
context, }
reciever.or(unbound_reciever),
arguments,
),
Executable::Action(bm) => { Executable::Action(bm) => {
let reciever = bm.reciever.or(unbound_reciever); let reciever = bm.reciever.or(unbound_reciever);
let mut activation = Activation::from_method( let mut activation = Activation::from_method(
activation.avm2(), activation.context.reborrow(),
context,
bm.method, bm.method,
bm.scope, bm.scope,
reciever, reciever,
@ -110,7 +104,7 @@ impl<'gc> Executable<'gc> {
base_proto, base_proto,
)?; )?;
activation.run_actions(bm.method, context) activation.run_actions(bm.method)
} }
} }
} }
@ -161,8 +155,7 @@ impl<'gc> FunctionObject<'gc> {
/// to be limited to interfaces (at least by the AS3 compiler in Animate /// to be limited to interfaces (at least by the AS3 compiler in Animate
/// CC 2020.) /// CC 2020.)
pub fn from_class( pub fn from_class(
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
class: GcCell<'gc, Class<'gc>>, class: GcCell<'gc, Class<'gc>>,
base_class: Option<Object<'gc>>, base_class: Option<Object<'gc>>,
scope: Option<GcCell<'gc, Scope<'gc>>>, scope: Option<GcCell<'gc, Scope<'gc>>>,
@ -174,7 +167,6 @@ impl<'gc> FunctionObject<'gc> {
base_class, base_class,
&QName::new(Namespace::public_namespace(), "prototype"), &QName::new(Namespace::public_namespace(), "prototype"),
activation, activation,
context,
)? )?
.as_object() .as_object()
.map_err(|_| { .map_err(|_| {
@ -189,9 +181,9 @@ impl<'gc> FunctionObject<'gc> {
.into() .into()
}); });
super_proto?.derive(activation, context, class, scope)? super_proto?.derive(activation, class, scope)?
} else { } else {
ScriptObject::bare_object(context.gc_context) ScriptObject::bare_object(activation.context.gc_context)
}; };
let mut interfaces = Vec::new(); let mut interfaces = Vec::new();
@ -199,8 +191,8 @@ impl<'gc> FunctionObject<'gc> {
for interface_name in interface_names { for interface_name in interface_names {
let interface = if let Some(scope) = scope { let interface = if let Some(scope) = scope {
scope scope
.write(context.gc_context) .write(activation.context.gc_context)
.resolve(&interface_name, activation, context)? .resolve(&interface_name, activation)?
} else { } else {
None None
}; };
@ -215,7 +207,6 @@ impl<'gc> FunctionObject<'gc> {
interface, interface,
&QName::new(Namespace::public_namespace(), "prototype"), &QName::new(Namespace::public_namespace(), "prototype"),
activation, activation,
context,
)? )?
.as_object()?; .as_object()?;
@ -223,7 +214,7 @@ impl<'gc> FunctionObject<'gc> {
} }
if !interfaces.is_empty() { if !interfaces.is_empty() {
class_proto.set_interfaces(context.gc_context, interfaces); class_proto.set_interfaces(activation.context.gc_context, interfaces);
} }
let fn_proto = activation.avm2().prototypes().function; let fn_proto = activation.avm2().prototypes().function;
@ -232,7 +223,7 @@ impl<'gc> FunctionObject<'gc> {
let initializer = class_read.instance_init(); let initializer = class_read.instance_init();
let mut constr: Object<'gc> = FunctionObject(GcCell::allocate( let mut constr: Object<'gc> = FunctionObject(GcCell::allocate(
context.gc_context, activation.context.gc_context,
FunctionObjectData { FunctionObjectData {
base: ScriptObjectData::base_new( base: ScriptObjectData::base_new(
Some(fn_proto), Some(fn_proto),
@ -242,26 +233,26 @@ impl<'gc> FunctionObject<'gc> {
initializer, initializer,
scope, scope,
None, None,
context.gc_context, activation.context.gc_context,
)), )),
}, },
)) ))
.into(); .into();
constr.install_dynamic_property( constr.install_dynamic_property(
context.gc_context, activation.context.gc_context,
QName::new(Namespace::public_namespace(), "prototype"), QName::new(Namespace::public_namespace(), "prototype"),
class_proto.into(), class_proto.into(),
)?; )?;
class_proto.install_dynamic_property( class_proto.install_dynamic_property(
context.gc_context, activation.context.gc_context,
QName::new(Namespace::public_namespace(), "constructor"), QName::new(Namespace::public_namespace(), "constructor"),
constr.into(), constr.into(),
)?; )?;
let class_initializer = class_read.class_init(); let class_initializer = class_read.class_init();
let class_constr = FunctionObject::from_method( let class_constr = FunctionObject::from_method(
context.gc_context, activation.context.gc_context,
class_initializer, class_initializer,
scope, scope,
class_constr_proto, class_constr_proto,
@ -346,15 +337,14 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
self, self,
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
let read = self.0.read(); let read = self.0.read();
let rv = read.base.get_property_local(reciever, name, activation)?; let rv = read.base.get_property_local(reciever, name, activation)?;
drop(read); drop(read);
rv.resolve(activation, context) rv.resolve(activation)
} }
fn set_property_local( fn set_property_local(
@ -362,17 +352,16 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut write = self.0.write(context.gc_context); let mut write = self.0.write(activation.context.gc_context);
let rv = write let rv = write
.base .base
.set_property_local(reciever, name, value, activation, context)?; .set_property_local(reciever, name, value, activation)?;
drop(write); drop(write);
rv.resolve(activation, context)?; rv.resolve(activation)?;
Ok(()) Ok(())
} }
@ -382,17 +371,16 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut write = self.0.write(context.gc_context); let mut write = self.0.write(activation.context.gc_context);
let rv = write let rv = write
.base .base
.init_property_local(reciever, name, value, activation, context)?; .init_property_local(reciever, name, value, activation)?;
drop(write); drop(write);
rv.resolve(activation, context)?; rv.resolve(activation)?;
Ok(()) Ok(())
} }
@ -526,12 +514,11 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
self, self,
reciever: Option<Object<'gc>>, reciever: Option<Object<'gc>>,
arguments: &[Value<'gc>], arguments: &[Value<'gc>],
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
base_proto: Option<Object<'gc>>, base_proto: Option<Object<'gc>>,
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
if let Some(exec) = &self.0.read().exec { if let Some(exec) = &self.0.read().exec {
exec.exec(reciever, arguments, activation, context, base_proto) exec.exec(reciever, arguments, activation, base_proto)
} else { } else {
Err("Not a callable function!".into()) Err("Not a callable function!".into())
} }
@ -539,15 +526,14 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
fn construct( fn construct(
&self, &self,
_activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Object<'gc>, Error> { ) -> Result<Object<'gc>, Error> {
let this: Object<'gc> = Object::FunctionObject(*self); let this: Object<'gc> = Object::FunctionObject(*self);
let base = ScriptObjectData::base_new(Some(this), ScriptObjectClass::NoClass); let base = ScriptObjectData::base_new(Some(this), ScriptObjectClass::NoClass);
Ok(FunctionObject(GcCell::allocate( Ok(FunctionObject(GcCell::allocate(
context.gc_context, activation.context.gc_context,
FunctionObjectData { base, exec: None }, FunctionObjectData { base, exec: None },
)) ))
.into()) .into())
@ -555,8 +541,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
fn derive( fn derive(
&self, &self,
_activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
class: GcCell<'gc, Class<'gc>>, class: GcCell<'gc, Class<'gc>>,
scope: Option<GcCell<'gc, Scope<'gc>>>, scope: Option<GcCell<'gc, Scope<'gc>>>,
) -> Result<Object<'gc>, Error> { ) -> Result<Object<'gc>, Error> {
@ -567,7 +552,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
); );
Ok(FunctionObject(GcCell::allocate( Ok(FunctionObject(GcCell::allocate(
context.gc_context, activation.context.gc_context,
FunctionObjectData { base, exec: None }, FunctionObjectData { base, exec: None },
)) ))
.into()) .into())

View File

@ -9,7 +9,6 @@ use crate::avm2::script_object::ScriptObject;
use crate::avm2::string::AvmString; use crate::avm2::string::AvmString;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, MutationContext}; use gc_arena::{Collect, MutationContext};
use std::f64::NAN; use std::f64::NAN;
@ -19,8 +18,7 @@ mod function;
mod object; mod object;
fn trace<'gc>( fn trace<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {

View File

@ -5,7 +5,6 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject; use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext; use gc_arena::MutationContext;
/// Implements `Class` /// Implements `Class`
@ -13,8 +12,7 @@ use gc_arena::MutationContext;
/// Notably, you cannot construct new classes this way, so this returns an /// Notably, you cannot construct new classes this way, so this returns an
/// error. /// error.
pub fn constructor<'gc>( pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject; use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext; use gc_arena::MutationContext;
/// Implements `flash.display.DisplayObject`'s constructor. /// Implements `flash.display.DisplayObject`'s constructor.
pub fn constructor<'gc>( pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject; use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext; use gc_arena::MutationContext;
/// Implements `flash.display.DisplayObjectContainer`'s constructor. /// Implements `flash.display.DisplayObjectContainer`'s constructor.
pub fn constructor<'gc>( pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject; use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext; use gc_arena::MutationContext;
/// Implements `flash.display.InteractiveObject`'s constructor. /// Implements `flash.display.InteractiveObject`'s constructor.
pub fn constructor<'gc>( pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject; use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext; use gc_arena::MutationContext;
/// Implements `flash.display.MovieClip`'s constructor. /// Implements `flash.display.MovieClip`'s constructor.
pub fn constructor<'gc>( pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject; use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext; use gc_arena::MutationContext;
/// Implements `flash.display.Sprite`'s constructor. /// Implements `flash.display.Sprite`'s constructor.
pub fn constructor<'gc>( pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject; use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext; use gc_arena::MutationContext;
/// Implements `flash.events.EventDispatcher`'s constructor. /// Implements `flash.events.EventDispatcher`'s constructor.
pub fn constructor<'gc>( pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {

View File

@ -7,13 +7,11 @@ use crate::avm2::object::{Object, TObject};
use crate::avm2::script_object::ScriptObject; use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext; use gc_arena::MutationContext;
/// Implements `Function` /// Implements `Function`
pub fn constructor<'gc>( pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
@ -22,8 +20,7 @@ pub fn constructor<'gc>(
/// Implements `Function.prototype.call` /// Implements `Function.prototype.call`
fn call<'gc>( fn call<'gc>(
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
func: Option<Object<'gc>>, func: Option<Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
@ -32,9 +29,9 @@ fn call<'gc>(
if let Some(func) = func { if let Some(func) = func {
if args.len() > 1 { if args.len() > 1 {
Ok(func.call(this, &args[1..], activation, context, base_proto)?) Ok(func.call(this, &args[1..], activation, base_proto)?)
} else { } else {
Ok(func.call(this, &[], activation, context, base_proto)?) Ok(func.call(this, &[], activation, base_proto)?)
} }
} else { } else {
Err("Not a callable function".into()) Err("Not a callable function".into())

View File

@ -6,13 +6,11 @@ use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::{Object, TObject}; use crate::avm2::object::{Object, TObject};
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext; use gc_arena::MutationContext;
/// Implements `Object` /// Implements `Object`
pub fn constructor<'gc>( pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_this: Option<Object<'gc>>, _this: Option<Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
@ -21,44 +19,40 @@ pub fn constructor<'gc>(
/// Implements `Object.prototype.toString` /// Implements `Object.prototype.toString`
fn to_string<'gc>( fn to_string<'gc>(
_: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,
_: &[Value<'gc>], _: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
Ok(this Ok(this
.map(|t| t.to_string(context.gc_context)) .map(|t| t.to_string(activation.context.gc_context))
.unwrap_or(Ok(Value::Undefined))?) .unwrap_or(Ok(Value::Undefined))?)
} }
/// Implements `Object.prototype.toLocaleString` /// Implements `Object.prototype.toLocaleString`
fn to_locale_string<'gc>( fn to_locale_string<'gc>(
_: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,
_: &[Value<'gc>], _: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
Ok(this Ok(this
.map(|t| t.to_string(context.gc_context)) .map(|t| t.to_string(activation.context.gc_context))
.unwrap_or(Ok(Value::Undefined))?) .unwrap_or(Ok(Value::Undefined))?)
} }
/// Implements `Object.prototype.valueOf` /// Implements `Object.prototype.valueOf`
fn value_of<'gc>( fn value_of<'gc>(
_: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,
_: &[Value<'gc>], _: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
Ok(this Ok(this
.map(|t| t.value_of(context.gc_context)) .map(|t| t.value_of(activation.context.gc_context))
.unwrap_or(Ok(Value::Undefined))?) .unwrap_or(Ok(Value::Undefined))?)
} }
/// `Object.prototype.hasOwnProperty` /// `Object.prototype.hasOwnProperty`
pub fn has_own_property<'gc>( pub fn has_own_property<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_context: &mut UpdateContext<'_, 'gc, '_>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
@ -79,8 +73,7 @@ pub fn has_own_property<'gc>(
/// `Object.prototype.isPrototypeOf` /// `Object.prototype.isPrototypeOf`
pub fn is_prototype_of<'gc>( pub fn is_prototype_of<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_context: &mut UpdateContext<'_, 'gc, '_>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
@ -102,8 +95,7 @@ pub fn is_prototype_of<'gc>(
/// `Object.prototype.propertyIsEnumerable` /// `Object.prototype.propertyIsEnumerable`
pub fn property_is_enumerable<'gc>( pub fn property_is_enumerable<'gc>(
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_context: &mut UpdateContext<'_, 'gc, '_>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
@ -124,8 +116,7 @@ pub fn property_is_enumerable<'gc>(
/// `Object.prototype.setPropertyIsEnumerable` /// `Object.prototype.setPropertyIsEnumerable`
pub fn set_property_is_enumerable<'gc>( pub fn set_property_is_enumerable<'gc>(
_activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
@ -142,7 +133,7 @@ pub fn set_property_is_enumerable<'gc>(
if let Some(ns) = this.resolve_any(name)? { if let Some(ns) = this.resolve_any(name)? {
if !ns.is_private() { if !ns.is_private() {
let qname = QName::new(ns, name); let qname = QName::new(ns, name);
this.set_local_property_is_enumerable(context.gc_context, &qname, is_enum)?; this.set_local_property_is_enumerable(activation.context.gc_context, &qname, is_enum)?;
} }
} }

View File

@ -5,7 +5,6 @@ use crate::avm2::object::Object;
use crate::avm2::script::TranslationUnit; use crate::avm2::script::TranslationUnit;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, CollectionContext, Gc, MutationContext}; use gc_arena::{Collect, CollectionContext, Gc, MutationContext};
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
@ -30,8 +29,7 @@ pub struct CollectWrapper<T>(T);
/// your function yields `None`, you must ensure that the top-most activation /// your function yields `None`, you must ensure that the top-most activation
/// in the AVM1 runtime will return with the value of this function. /// in the AVM1 runtime will return with the value of this function.
pub type NativeMethod<'gc> = fn( pub type NativeMethod<'gc> = fn(
&mut Activation<'_, 'gc>, &mut Activation<'_, 'gc, '_>,
&mut UpdateContext<'_, 'gc, '_>,
Option<Object<'gc>>, Option<Object<'gc>>,
&[Value<'gc>], &[Value<'gc>],
) -> Result<Value<'gc>, Error>; ) -> Result<Value<'gc>, Error>;

View File

@ -10,7 +10,6 @@ use crate::avm2::script_object::ScriptObject;
use crate::avm2::string::AvmString; use crate::avm2::string::AvmString;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use ruffle_macros::enum_trait_object; use ruffle_macros::enum_trait_object;
use std::fmt::Debug; use std::fmt::Debug;
@ -32,8 +31,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
self, self,
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error>; ) -> Result<Value<'gc>, Error>;
/// Retrieve a property by it's QName. /// Retrieve a property by it's QName.
@ -41,23 +39,22 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
&mut self, &mut self,
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
if !self.has_instantiated_property(name) { if !self.has_instantiated_property(name) {
for abc_trait in self.get_trait(name)? { for abc_trait in self.get_trait(name)? {
self.install_trait(activation, context, abc_trait, reciever)?; self.install_trait(activation, abc_trait, reciever)?;
} }
} }
let has_no_getter = self.has_own_virtual_setter(name) && !self.has_own_virtual_getter(name); let has_no_getter = self.has_own_virtual_setter(name) && !self.has_own_virtual_getter(name);
if self.has_own_property(name)? && !has_no_getter { if self.has_own_property(name)? && !has_no_getter {
return self.get_property_local(reciever, name, activation, context); return self.get_property_local(reciever, name, activation);
} }
if let Some(mut proto) = self.proto() { if let Some(mut proto) = self.proto() {
return proto.get_property(reciever, name, activation, context); return proto.get_property(reciever, name, activation);
} }
Ok(Value::Undefined) Ok(Value::Undefined)
@ -85,8 +82,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error>; ) -> Result<(), Error>;
/// Set a property by it's QName. /// Set a property by it's QName.
@ -95,17 +91,16 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if !self.has_instantiated_property(name) { if !self.has_instantiated_property(name) {
for abc_trait in self.get_trait(name)? { for abc_trait in self.get_trait(name)? {
self.install_trait(activation, context, abc_trait, reciever)?; self.install_trait(activation, abc_trait, reciever)?;
} }
} }
if self.has_own_virtual_setter(name) { if self.has_own_virtual_setter(name) {
return self.set_property_local(reciever, name, value, activation, context); return self.set_property_local(reciever, name, value, activation);
} }
let mut proto = self.proto(); let mut proto = self.proto();
@ -114,13 +109,13 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
//we're calling a virtual setter. If you call `set_property` on //we're calling a virtual setter. If you call `set_property` on
//a non-virtual you will actually alter the prototype. //a non-virtual you will actually alter the prototype.
if my_proto.has_own_virtual_setter(name) { if my_proto.has_own_virtual_setter(name) {
return my_proto.set_property(reciever, name, value, activation, context); return my_proto.set_property(reciever, name, value, activation);
} }
proto = my_proto.proto(); proto = my_proto.proto();
} }
reciever.set_property_local(reciever, name, value, activation, context) reciever.set_property_local(reciever, name, value, activation)
} }
/// Init a property on this specific object. /// Init a property on this specific object.
@ -129,8 +124,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error>; ) -> Result<(), Error>;
/// Init a property by it's QName. /// Init a property by it's QName.
@ -139,17 +133,16 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if !self.has_instantiated_property(name) { if !self.has_instantiated_property(name) {
for abc_trait in self.get_trait(name)? { for abc_trait in self.get_trait(name)? {
self.install_trait(activation, context, abc_trait, reciever)?; self.install_trait(activation, abc_trait, reciever)?;
} }
} }
if self.has_own_virtual_setter(name) { if self.has_own_virtual_setter(name) {
return self.init_property_local(reciever, name, value, activation, context); return self.init_property_local(reciever, name, value, activation);
} }
let mut proto = self.proto(); let mut proto = self.proto();
@ -158,13 +151,13 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
//we're calling a virtual setter. If you call `set_property` on //we're calling a virtual setter. If you call `set_property` on
//a non-virtual you will actually alter the prototype. //a non-virtual you will actually alter the prototype.
if my_proto.has_own_virtual_setter(name) { if my_proto.has_own_virtual_setter(name) {
return my_proto.init_property(reciever, name, value, activation, context); return my_proto.init_property(reciever, name, value, activation);
} }
proto = my_proto.proto(); proto = my_proto.proto();
} }
reciever.init_property_local(reciever, name, value, activation, context) reciever.init_property_local(reciever, name, value, activation)
} }
/// Retrieve a slot by it's index. /// Retrieve a slot by it's index.
@ -411,19 +404,17 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// object. /// object.
fn install_trait( fn install_trait(
&mut self, &mut self,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
trait_entry: Trait<'gc>, trait_entry: Trait<'gc>,
reciever: Object<'gc>, reciever: Object<'gc>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.install_foreign_trait(activation, context, trait_entry, self.get_scope(), reciever) self.install_foreign_trait(activation, trait_entry, self.get_scope(), reciever)
} }
/// Install a trait from anywyere. /// Install a trait from anywyere.
fn install_foreign_trait( fn install_foreign_trait(
&mut self, &mut self,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
trait_entry: Trait<'gc>, trait_entry: Trait<'gc>,
scope: Option<GcCell<'gc, Scope<'gc>>>, scope: Option<GcCell<'gc, Scope<'gc>>>,
reciever: Object<'gc>, reciever: Object<'gc>,
@ -444,7 +435,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
.. ..
} => { } => {
self.install_slot( self.install_slot(
context.gc_context, activation.context.gc_context,
trait_name, trait_name,
*slot_id, *slot_id,
default_value.clone().unwrap_or(Value::Undefined), default_value.clone().unwrap_or(Value::Undefined),
@ -454,37 +445,52 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
disp_id, method, .. disp_id, method, ..
} => { } => {
let function = FunctionObject::from_method( let function = FunctionObject::from_method(
context.gc_context, activation.context.gc_context,
method.clone(), method.clone(),
scope, scope,
fn_proto, fn_proto,
Some(reciever), Some(reciever),
); );
self.install_method(context.gc_context, trait_name, *disp_id, function); self.install_method(
activation.context.gc_context,
trait_name,
*disp_id,
function,
);
} }
TraitKind::Getter { TraitKind::Getter {
disp_id, method, .. disp_id, method, ..
} => { } => {
let function = FunctionObject::from_method( let function = FunctionObject::from_method(
context.gc_context, activation.context.gc_context,
method.clone(), method.clone(),
scope, scope,
fn_proto, fn_proto,
Some(reciever), Some(reciever),
); );
self.install_getter(context.gc_context, trait_name, *disp_id, function)?; self.install_getter(
activation.context.gc_context,
trait_name,
*disp_id,
function,
)?;
} }
TraitKind::Setter { TraitKind::Setter {
disp_id, method, .. disp_id, method, ..
} => { } => {
let function = FunctionObject::from_method( let function = FunctionObject::from_method(
context.gc_context, activation.context.gc_context,
method.clone(), method.clone(),
scope, scope,
fn_proto, fn_proto,
Some(reciever), Some(reciever),
); );
self.install_setter(context.gc_context, trait_name, *disp_id, function)?; self.install_setter(
activation.context.gc_context,
trait_name,
*disp_id,
function,
)?;
} }
TraitKind::Class { slot_id, class } => { TraitKind::Class { slot_id, class } => {
let class_read = class.read(); let class_read = class.read();
@ -494,7 +500,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
.unwrap_or_else(|| QName::dynamic_name("Object")); .unwrap_or_else(|| QName::dynamic_name("Object"));
let super_class: Result<Object<'gc>, Error> = self let super_class: Result<Object<'gc>, Error> = self
.get_property(reciever, &super_name, activation, context)? .get_property(reciever, &super_name, activation)?
.as_object() .as_object()
.map_err(|_e| { .map_err(|_e| {
format!("Could not resolve superclass {:?}", super_name.local_name()) format!("Could not resolve superclass {:?}", super_name.local_name())
@ -507,9 +513,9 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
}; };
let (class_object, _cinit) = let (class_object, _cinit) =
FunctionObject::from_class(activation, context, *class, super_class, scope)?; FunctionObject::from_class(activation, *class, super_class, scope)?;
self.install_const( self.install_const(
context.gc_context, activation.context.gc_context,
class_read.name().clone(), class_read.name().clone(),
*slot_id, *slot_id,
class_object.into(), class_object.into(),
@ -519,22 +525,29 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
slot_id, function, .. slot_id, function, ..
} => { } => {
let mut fobject = FunctionObject::from_method( let mut fobject = FunctionObject::from_method(
context.gc_context, activation.context.gc_context,
function.clone(), function.clone(),
scope, scope,
fn_proto, fn_proto,
None, None,
); );
let es3_proto = let es3_proto = ScriptObject::object(
ScriptObject::object(context.gc_context, activation.avm2().prototypes().object); activation.context.gc_context,
activation.avm2().prototypes().object,
);
fobject.install_slot( fobject.install_slot(
context.gc_context, activation.context.gc_context,
QName::new(Namespace::public_namespace(), "prototype"), QName::new(Namespace::public_namespace(), "prototype"),
0, 0,
es3_proto.into(), es3_proto.into(),
); );
self.install_const(context.gc_context, trait_name, *slot_id, fobject.into()); self.install_const(
activation.context.gc_context,
trait_name,
*slot_id,
fobject.into(),
);
} }
TraitKind::Const { TraitKind::Const {
slot_id, slot_id,
@ -542,7 +555,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
.. ..
} => { } => {
self.install_const( self.install_const(
context.gc_context, activation.context.gc_context,
trait_name, trait_name,
*slot_id, *slot_id,
default_value.clone().unwrap_or(Value::Undefined), default_value.clone().unwrap_or(Value::Undefined),
@ -558,8 +571,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
self, self,
_reciever: Option<Object<'gc>>, _reciever: Option<Object<'gc>>,
_arguments: &[Value<'gc>], _arguments: &[Value<'gc>],
_activation: &mut Activation<'_, 'gc>, _activation: &mut Activation<'_, 'gc, '_>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_base_proto: Option<Object<'gc>>, _base_proto: Option<Object<'gc>>,
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
Err("Object is not callable".into()) Err("Object is not callable".into())
@ -584,8 +596,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// purely so that host objects can be constructed by the VM. /// purely so that host objects can be constructed by the VM.
fn construct( fn construct(
&self, &self,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<Object<'gc>, Error>; ) -> Result<Object<'gc>, Error>;
@ -600,8 +611,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// traits. /// traits.
fn derive( fn derive(
&self, &self,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
class: GcCell<'gc, Class<'gc>>, class: GcCell<'gc, Class<'gc>>,
scope: Option<GcCell<'gc, Scope<'gc>>>, scope: Option<GcCell<'gc, Scope<'gc>>>,
) -> Result<Object<'gc>, Error>; ) -> Result<Object<'gc>, Error>;
@ -638,18 +648,12 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
#[allow(unused_mut)] //it's not unused #[allow(unused_mut)] //it's not unused
fn is_instance_of( fn is_instance_of(
&self, &self,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
mut constructor: Object<'gc>, mut constructor: Object<'gc>,
check_interfaces: bool, check_interfaces: bool,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
let type_proto = constructor let type_proto = constructor
.get_property( .get_property(constructor, &QName::dynamic_name("prototype"), activation)?
constructor,
&QName::dynamic_name("prototype"),
activation,
context,
)?
.as_object()?; .as_object()?;
let mut my_proto = self.proto(); let mut my_proto = self.proto();

View File

@ -4,7 +4,6 @@ use crate::avm2::activation::Activation;
use crate::avm2::function::Executable; use crate::avm2::function::Executable;
use crate::avm2::object::Object; use crate::avm2::object::Object;
use crate::avm2::{Error, Value}; use crate::avm2::{Error, Value};
use crate::context::UpdateContext;
use std::fmt; use std::fmt;
/// Represents the return value of a function call that has not yet executed. /// Represents the return value of a function call that has not yet executed.
@ -83,11 +82,7 @@ impl<'gc> ReturnValue<'gc> {
/// ///
/// All return values must eventually resolved - it is a compile error to /// All return values must eventually resolved - it is a compile error to
/// fail to do so. /// fail to do so.
pub fn resolve( pub fn resolve(self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Value<'gc>, Error> {
self,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
match self { match self {
Self::Immediate(v) => Ok(v), Self::Immediate(v) => Ok(v),
Self::ResultOf { Self::ResultOf {
@ -95,13 +90,7 @@ impl<'gc> ReturnValue<'gc> {
unbound_reciever, unbound_reciever,
arguments, arguments,
base_proto, base_proto,
} => executable.exec( } => executable.exec(unbound_reciever, &arguments, activation, base_proto),
unbound_reciever,
&arguments,
activation,
context,
base_proto,
),
} }
} }
} }

View File

@ -5,7 +5,6 @@ use crate::avm2::names::Multiname;
use crate::avm2::object::{Object, TObject}; use crate::avm2::object::{Object, TObject};
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::Ref; use std::cell::Ref;
@ -100,8 +99,7 @@ impl<'gc> Scope<'gc> {
pub fn find( pub fn find(
&self, &self,
name: &Multiname<'gc>, name: &Multiname<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Option<Object<'gc>>, Error> { ) -> Result<Option<Object<'gc>>, Error> {
if let Some(qname) = self.locals().resolve_multiname(name)? { if let Some(qname) = self.locals().resolve_multiname(name)? {
if self.locals().has_property(&qname)? { if self.locals().has_property(&qname)? {
@ -110,7 +108,7 @@ impl<'gc> Scope<'gc> {
} }
if let Some(scope) = self.parent() { if let Some(scope) = self.parent() {
return scope.find(name, activation, context); return scope.find(name, activation);
} }
Ok(None) Ok(None)
@ -123,8 +121,7 @@ impl<'gc> Scope<'gc> {
pub fn resolve( pub fn resolve(
&mut self, &mut self,
name: &Multiname<'gc>, name: &Multiname<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Option<Value<'gc>>, Error> { ) -> Result<Option<Value<'gc>>, Error> {
if let Some(qname) = self.locals().resolve_multiname(name)? { if let Some(qname) = self.locals().resolve_multiname(name)? {
if self.locals().has_property(&qname)? { if self.locals().has_property(&qname)? {
@ -132,15 +129,14 @@ impl<'gc> Scope<'gc> {
self.values, self.values,
&qname, &qname,
activation, activation,
context,
)?)); )?));
} }
} }
if let Some(parent) = self.parent { if let Some(parent) = self.parent {
return parent return parent
.write(context.gc_context) .write(activation.context.gc_context)
.resolve(name, activation, context); .resolve(name, activation);
} }
//TODO: Should undefined variables halt execution? //TODO: Should undefined variables halt execution?

View File

@ -14,7 +14,6 @@ use crate::avm2::slot::Slot;
use crate::avm2::string::AvmString; use crate::avm2::string::AvmString;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug; use std::fmt::Debug;
@ -80,15 +79,14 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
self, self,
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
let rv = self let rv = self
.0 .0
.read() .read()
.get_property_local(reciever, name, activation)?; .get_property_local(reciever, name, activation)?;
rv.resolve(activation, context) rv.resolve(activation)
} }
fn set_property_local( fn set_property_local(
@ -96,15 +94,14 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let rv = self let rv = self
.0 .0
.write(context.gc_context) .write(activation.context.gc_context)
.set_property_local(reciever, name, value, activation, context)?; .set_property_local(reciever, name, value, activation)?;
rv.resolve(activation, context)?; rv.resolve(activation)?;
Ok(()) Ok(())
} }
@ -114,15 +111,14 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let rv = self let rv = self
.0 .0
.write(context.gc_context) .write(activation.context.gc_context)
.init_property_local(reciever, name, value, activation, context)?; .init_property_local(reciever, name, value, activation)?;
rv.resolve(activation, context)?; rv.resolve(activation)?;
Ok(()) Ok(())
} }
@ -245,24 +241,22 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
fn construct( fn construct(
&self, &self,
_activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Object<'gc>, Error> { ) -> Result<Object<'gc>, Error> {
let this: Object<'gc> = Object::ScriptObject(*self); let this: Object<'gc> = Object::ScriptObject(*self);
Ok(ScriptObject::object(context.gc_context, this)) Ok(ScriptObject::object(activation.context.gc_context, this))
} }
fn derive( fn derive(
&self, &self,
_activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
class: GcCell<'gc, Class<'gc>>, class: GcCell<'gc, Class<'gc>>,
scope: Option<GcCell<'gc, Scope<'gc>>>, scope: Option<GcCell<'gc, Scope<'gc>>>,
) -> Result<Object<'gc>, Error> { ) -> Result<Object<'gc>, Error> {
let this: Object<'gc> = Object::ScriptObject(*self); let this: Object<'gc> = Object::ScriptObject(*self);
Ok(ScriptObject::prototype( Ok(ScriptObject::prototype(
context.gc_context, activation.context.gc_context,
this, this,
class, class,
scope, scope,
@ -419,7 +413,7 @@ impl<'gc> ScriptObjectData<'gc> {
&self, &self,
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
) -> Result<ReturnValue<'gc>, Error> { ) -> Result<ReturnValue<'gc>, Error> {
let prop = self.values.get(name); let prop = self.values.get(name);
@ -435,8 +429,7 @@ impl<'gc> ScriptObjectData<'gc> {
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<ReturnValue<'gc>, Error> { ) -> Result<ReturnValue<'gc>, Error> {
let slot_id = if let Some(prop) = self.values.get(name) { let slot_id = if let Some(prop) = self.values.get(name) {
if let Some(slot_id) = prop.slot_id() { if let Some(slot_id) = prop.slot_id() {
@ -449,7 +442,7 @@ impl<'gc> ScriptObjectData<'gc> {
}; };
if let Some(slot_id) = slot_id { if let Some(slot_id) = slot_id {
self.set_slot(slot_id, value, context.gc_context)?; self.set_slot(slot_id, value, activation.context.gc_context)?;
Ok(Value::Undefined.into()) Ok(Value::Undefined.into())
} else if self.values.contains_key(name) { } else if self.values.contains_key(name) {
let prop = self.values.get_mut(name).unwrap(); let prop = self.values.get_mut(name).unwrap();
@ -470,12 +463,11 @@ impl<'gc> ScriptObjectData<'gc> {
reciever: Object<'gc>, reciever: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<ReturnValue<'gc>, Error> { ) -> Result<ReturnValue<'gc>, Error> {
if let Some(prop) = self.values.get_mut(name) { if let Some(prop) = self.values.get_mut(name) {
if let Some(slot_id) = prop.slot_id() { if let Some(slot_id) = prop.slot_id() {
self.init_slot(slot_id, value, context.gc_context)?; self.init_slot(slot_id, value, activation.context.gc_context)?;
Ok(Value::Undefined.into()) Ok(Value::Undefined.into())
} else { } else {
let proto = self.proto; let proto = self.proto;

View File

@ -3,6 +3,7 @@ use crate::avm1;
use crate::avm1::globals::system::SystemProperties; use crate::avm1::globals::system::SystemProperties;
use crate::avm1::{Avm1, Object, Timers, Value}; use crate::avm1::{Avm1, Object, Timers, Value};
use crate::avm2::Avm2;
use crate::backend::input::InputBackend; use crate::backend::input::InputBackend;
use crate::backend::storage::StorageBackend; use crate::backend::storage::StorageBackend;
use crate::backend::{audio::AudioBackend, navigator::NavigatorBackend, render::RenderBackend}; use crate::backend::{audio::AudioBackend, navigator::NavigatorBackend, render::RenderBackend};
@ -117,6 +118,9 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> {
/// The AVM1 global state. /// The AVM1 global state.
pub avm1: &'a mut Avm1<'gc>, pub avm1: &'a mut Avm1<'gc>,
/// The AVM2 global state.
pub avm2: &'a mut Avm2<'gc>,
} }
unsafe impl<'a, 'gc, 'gc_context> Collect for UpdateContext<'a, 'gc, 'gc_context> { unsafe impl<'a, 'gc, 'gc_context> Collect for UpdateContext<'a, 'gc, 'gc_context> {
@ -145,6 +149,7 @@ unsafe impl<'a, 'gc, 'gc_context> Collect for UpdateContext<'a, 'gc, 'gc_context
self.unbound_text_fields.trace(cc); self.unbound_text_fields.trace(cc);
self.timers.trace(cc); self.timers.trace(cc);
self.avm1.trace(cc); self.avm1.trace(cc);
self.avm2.trace(cc);
} }
} }
@ -188,6 +193,7 @@ impl<'a, 'gc, 'gc_context> UpdateContext<'a, 'gc, 'gc_context> {
unbound_text_fields: self.unbound_text_fields, unbound_text_fields: self.unbound_text_fields,
timers: self.timers, timers: self.timers,
avm1: self.avm1, avm1: self.avm1,
avm2: self.avm2,
} }
} }
} }

View File

@ -370,13 +370,14 @@ impl<'gc> Loader<'gc> {
.expect("Could not upgrade weak reference to player"); .expect("Could not upgrade weak reference to player");
Box::pin(async move { Box::pin(async move {
player.lock().expect("Could not lock player!!").update( player
|_avm2, uc| -> Result<(), Error> { .lock()
.expect("Could not lock player!!")
.update(|uc| -> Result<(), Error> {
url = uc.navigator.resolve_relative_url(&url).into_owned(); url = uc.navigator.resolve_relative_url(&url).into_owned();
Ok(()) Ok(())
}, })?;
)?;
let data = (fetch.await) let data = (fetch.await)
.and_then(|data| Ok((data.len(), SwfMovie::from_data(&data, Some(url.clone()))?))); .and_then(|data| Ok((data.len(), SwfMovie::from_data(&data, Some(url.clone()))?)));
@ -414,8 +415,10 @@ impl<'gc> Loader<'gc> {
.expect("Could not upgrade weak reference to player"); .expect("Could not upgrade weak reference to player");
Box::pin(async move { Box::pin(async move {
player.lock().expect("Could not lock player!!").update( player
|_avm2, uc| -> Result<(), Error> { .lock()
.expect("Could not lock player!!")
.update(|uc| -> Result<(), Error> {
url = uc.navigator.resolve_relative_url(&url).into_owned(); url = uc.navigator.resolve_relative_url(&url).into_owned();
let (clip, broadcaster) = match uc.load_manager.get_loader(handle) { let (clip, broadcaster) = match uc.load_manager.get_loader(handle) {
@ -446,8 +449,7 @@ impl<'gc> Loader<'gc> {
} }
Ok(()) Ok(())
}, })?;
)?;
let data = (fetch.await) let data = (fetch.await)
.and_then(|data| Ok((data.len(), SwfMovie::from_data(&data, Some(url.clone()))?))); .and_then(|data| Ok((data.len(), SwfMovie::from_data(&data, Some(url.clone()))?)));
@ -457,7 +459,7 @@ impl<'gc> Loader<'gc> {
player player
.lock() .lock()
.expect("Could not lock player!!") .expect("Could not lock player!!")
.update(|_avm2, uc| { .update(|uc| {
let (clip, broadcaster) = match uc.load_manager.get_loader(handle) { let (clip, broadcaster) = match uc.load_manager.get_loader(handle) {
Some(Loader::Movie { Some(Loader::Movie {
target_clip, target_clip,
@ -530,8 +532,10 @@ impl<'gc> Loader<'gc> {
//error types we can actually inspect. //error types we can actually inspect.
//This also can get errors from decoding an invalid SWF file, //This also can get errors from decoding an invalid SWF file,
//too. We should distinguish those to player code. //too. We should distinguish those to player code.
player.lock().expect("Could not lock player!!").update( player
|_avm2, uc| -> Result<(), Error> { .lock()
.expect("Could not lock player!!")
.update(|uc| -> Result<(), Error> {
let (clip, broadcaster) = match uc.load_manager.get_loader(handle) { let (clip, broadcaster) = match uc.load_manager.get_loader(handle) {
Some(Loader::Movie { Some(Loader::Movie {
target_clip, target_clip,
@ -564,8 +568,7 @@ impl<'gc> Loader<'gc> {
}; };
Ok(()) Ok(())
}, })
)
} }
}) })
} }
@ -588,7 +591,7 @@ impl<'gc> Loader<'gc> {
let data = fetch.await?; let data = fetch.await?;
// Fire the load handler. // Fire the load handler.
player.lock().unwrap().update(|_avm2, uc| { player.lock().unwrap().update(|uc| {
let loader = uc.load_manager.get_loader(handle); let loader = uc.load_manager.get_loader(handle);
let that = match loader { let that = match loader {
Some(&Loader::Form { target_object, .. }) => target_object, Some(&Loader::Form { target_object, .. }) => target_object,
@ -635,7 +638,7 @@ impl<'gc> Loader<'gc> {
let data = fetch.await; let data = fetch.await;
// Fire the load handler. // Fire the load handler.
player.lock().unwrap().update(|_avm2, uc| { player.lock().unwrap().update(|uc| {
let loader = uc.load_manager.get_loader(handle); let loader = uc.load_manager.get_loader(handle);
let that = match loader { let that = match loader {
Some(&Loader::LoadVars { target_object, .. }) => target_object, Some(&Loader::LoadVars { target_object, .. }) => target_object,
@ -737,7 +740,7 @@ impl<'gc> Loader<'gc> {
let xmlstring = String::from_utf8(data)?; let xmlstring = String::from_utf8(data)?;
player.lock().expect("Could not lock player!!").update( player.lock().expect("Could not lock player!!").update(
|_avm2, uc| -> Result<(), Error> { |uc| -> Result<(), Error> {
let (mut node, active_clip) = match uc.load_manager.get_loader(handle) { let (mut node, active_clip) = match uc.load_manager.get_loader(handle) {
Some(Loader::XML { Some(Loader::XML {
target_node, target_node,
@ -773,7 +776,7 @@ impl<'gc> Loader<'gc> {
)?; )?;
} else { } else {
player.lock().expect("Could not lock player!!").update( player.lock().expect("Could not lock player!!").update(
|_avm2, uc| -> Result<(), Error> { |uc| -> Result<(), Error> {
let (mut node, active_clip) = match uc.load_manager.get_loader(handle) { let (mut node, active_clip) = match uc.load_manager.get_loader(handle) {
Some(Loader::XML { Some(Loader::XML {
target_node, target_node,

View File

@ -275,7 +275,7 @@ impl Player {
/// This should not be called if a root movie fetch has already been kicked /// This should not be called if a root movie fetch has already been kicked
/// off. /// off.
pub fn fetch_root_movie(&mut self, movie_url: &str) { pub fn fetch_root_movie(&mut self, movie_url: &str) {
self.mutate_with_update_context(|_avm2, context| { self.mutate_with_update_context(|context| {
let fetch = context.navigator.fetch(movie_url, RequestOptions::get()); let fetch = context.navigator.fetch(movie_url, RequestOptions::get());
let process = context.load_manager.load_root_movie( let process = context.load_manager.load_root_movie(
context.player.clone().unwrap(), context.player.clone().unwrap(),
@ -305,7 +305,7 @@ impl Player {
self.frame_rate = movie.header().frame_rate.into(); self.frame_rate = movie.header().frame_rate.into();
self.swf = movie; self.swf = movie;
self.mutate_with_update_context(|_avm2, context| { self.mutate_with_update_context(|context| {
let mut root: DisplayObject = let mut root: DisplayObject =
MovieClip::from_movie(context.gc_context, context.swf.clone()).into(); MovieClip::from_movie(context.gc_context, context.swf.clone()).into();
root.set_depth(context.gc_context, 0); root.set_depth(context.gc_context, 0);
@ -447,7 +447,7 @@ 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(|_avm2, context| { self.mutate_with_update_context(|context| {
let mut dumper = VariableDumper::new(" "); let mut dumper = VariableDumper::new(" ");
let levels = context.levels.clone(); let levels = context.levels.clone();
@ -483,19 +483,19 @@ 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(|avm2, context| { self.mutate_with_update_context(|context| {
if context.avm1.show_debug_output() { if context.avm1.show_debug_output() {
log::info!( log::info!(
"AVM Debugging turned off! Press CTRL+ALT+D to turn off again." "AVM Debugging turned off! Press CTRL+ALT+D to turn off again."
); );
context.avm1.set_show_debug_output(false); context.avm1.set_show_debug_output(false);
avm2.set_show_debug_output(false); context.avm2.set_show_debug_output(false);
} else { } else {
log::info!( log::info!(
"AVM Debugging turned on! Press CTRL+ALT+D to turn on again." "AVM Debugging turned on! Press CTRL+ALT+D to turn on again."
); );
context.avm1.set_show_debug_output(true); context.avm1.set_show_debug_output(true);
avm2.set_show_debug_output(true); context.avm2.set_show_debug_output(true);
} }
}); });
} }
@ -537,7 +537,7 @@ impl Player {
}; };
if button_event.is_some() { if button_event.is_some() {
self.mutate_with_update_context(|_avm2, context| { self.mutate_with_update_context(|context| {
let levels: Vec<DisplayObject<'_>> = context.levels.values().copied().collect(); let levels: Vec<DisplayObject<'_>> = context.levels.values().copied().collect();
for level in levels { for level in levels {
if let Some(button_event) = button_event { if let Some(button_event) = button_event {
@ -565,7 +565,7 @@ impl Player {
}; };
if clip_event.is_some() || listener.is_some() { if clip_event.is_some() || listener.is_some() {
self.mutate_with_update_context(|_avm2, context| { self.mutate_with_update_context(|context| {
let levels: Vec<DisplayObject<'_>> = context.levels.values().copied().collect(); let levels: Vec<DisplayObject<'_>> = context.levels.values().copied().collect();
for level in levels { for level in levels {
@ -589,7 +589,7 @@ impl Player {
} }
let mut is_mouse_down = self.is_mouse_down; let mut is_mouse_down = self.is_mouse_down;
self.mutate_with_update_context(|avm2, context| { self.mutate_with_update_context(|context| {
if let Some(node) = context.mouse_hovered_object { if let Some(node) = context.mouse_hovered_object {
if node.removed() { if node.removed() {
context.mouse_hovered_object = None; context.mouse_hovered_object = None;
@ -616,7 +616,7 @@ impl Player {
_ => (), _ => (),
} }
Self::run_actions(avm2, context); Self::run_actions(context);
}); });
self.is_mouse_down = is_mouse_down; self.is_mouse_down = is_mouse_down;
if needs_render { if needs_render {
@ -627,7 +627,7 @@ impl Player {
/// Update dragged object, if any. /// Update dragged object, if any.
fn update_drag(&mut self) { fn update_drag(&mut self) {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
self.mutate_with_update_context(|_avm2, context| { self.mutate_with_update_context(|context| {
if let Some(drag_object) = &mut context.drag_object { if let Some(drag_object) = &mut context.drag_object {
if drag_object.display_object.removed() { if drag_object.display_object.removed() {
// Be sure to clear the drag if the object was removed. // Be sure to clear the drag if the object was removed.
@ -662,7 +662,7 @@ impl Player {
let mouse_pos = self.mouse_pos; let mouse_pos = self.mouse_pos;
let mut new_cursor = self.mouse_cursor; let mut new_cursor = self.mouse_cursor;
let hover_changed = self.mutate_with_update_context(|avm2, context| { let hover_changed = self.mutate_with_update_context(|context| {
// Check hovered object. // Check hovered object.
let mut new_hovered = None; let mut new_hovered = None;
for (_depth, level) in context.levels.clone().iter().rev() { for (_depth, level) in context.levels.clone().iter().rev() {
@ -692,7 +692,7 @@ impl Player {
context.mouse_hovered_object = new_hovered; context.mouse_hovered_object = new_hovered;
Self::run_actions(avm2, context); Self::run_actions(context);
true true
} else { } else {
false false
@ -713,7 +713,7 @@ impl Player {
/// This should only be called once. Further movie loads should preload the /// This should only be called once. Further movie loads should preload the
/// specific `MovieClip` referenced. /// specific `MovieClip` referenced.
fn preload(&mut self) { fn preload(&mut self) {
self.mutate_with_update_context(|_avm2, context| { self.mutate_with_update_context(|context| {
let mut morph_shapes = fnv::FnvHashMap::default(); let mut morph_shapes = fnv::FnvHashMap::default();
let root = *context.levels.get(&0).expect("root level"); let root = *context.levels.get(&0).expect("root level");
root.as_movie_clip() root.as_movie_clip()
@ -732,7 +732,7 @@ impl Player {
} }
pub fn run_frame(&mut self) { pub fn run_frame(&mut self) {
self.update(|_avm2, update_context| { self.update(|update_context| {
// TODO: In what order are levels run? // TODO: In what order are levels run?
// NOTE: We have to copy all the layer pointers into a separate list // NOTE: We have to copy all the layer pointers into a separate list
// because level updates can create more levels, which we don't // because level updates can create more levels, which we don't
@ -813,7 +813,7 @@ impl Player {
self.input.deref_mut() self.input.deref_mut()
} }
fn run_actions<'gc>(avm2: &mut Avm2<'gc>, context: &mut UpdateContext<'_, 'gc, '_>) { fn run_actions<'gc>(context: &mut UpdateContext<'_, 'gc, '_>) {
// Note that actions can queue further actions, so a while loop is necessary here. // Note that actions can queue further actions, so a while loop is necessary here.
while let Some(actions) = context.action_queue.pop_action() { while let Some(actions) = context.action_queue.pop_action() {
// We don't run frame actions if the clip was removed after it queued the action. // We don't run frame actions if the clip was removed after it queued the action.
@ -917,7 +917,7 @@ impl Player {
is_lazy_initialize, is_lazy_initialize,
abc, abc,
} => { } => {
if let Err(e) = avm2.load_abc(abc, &name, is_lazy_initialize, context) { if let Err(e) = Avm2::load_abc(abc, &name, is_lazy_initialize, context) {
log::warn!("Error loading ABC file: {}", e); log::warn!("Error loading ABC file: {}", e);
} }
} }
@ -966,7 +966,7 @@ impl Player {
/// This takes cares of populating the `UpdateContext` struct, avoiding borrow issues. /// This takes cares of populating the `UpdateContext` struct, avoiding borrow issues.
fn mutate_with_update_context<F, R>(&mut self, f: F) -> R fn mutate_with_update_context<F, R>(&mut self, f: F) -> R
where where
F: for<'a, 'gc> FnOnce(&mut Avm2<'gc>, &mut UpdateContext<'a, 'gc, '_>) -> R, F: for<'a, 'gc> FnOnce(&mut UpdateContext<'a, 'gc, '_>) -> R,
{ {
// We have to do this piecewise borrowing of fields before the closure to avoid // We have to do this piecewise borrowing of fields before the closure to avoid
// completely borrowing `self`. // completely borrowing `self`.
@ -1050,9 +1050,10 @@ impl Player {
timers, timers,
needs_render, needs_render,
avm1, avm1,
avm2,
}; };
let ret = f(avm2, &mut update_context); let ret = f(&mut update_context);
// Hovered object may have been updated; copy it back to the GC root. // Hovered object may have been updated; copy it back to the GC root.
root_data.mouse_hovered_object = update_context.mouse_hovered_object; root_data.mouse_hovered_object = update_context.mouse_hovered_object;
@ -1084,15 +1085,12 @@ impl Player {
/// hover state up to date, and running garbage collection. /// hover state up to date, and running garbage collection.
pub fn update<F, R>(&mut self, func: F) -> R pub fn update<F, R>(&mut self, func: F) -> R
where where
F: for<'a, 'gc, 'gc_context> FnOnce( F: for<'a, 'gc, 'gc_context> FnOnce(&mut UpdateContext<'a, 'gc, 'gc_context>) -> R,
&mut Avm2<'gc>,
&mut UpdateContext<'a, 'gc, 'gc_context>,
) -> R,
{ {
let rval = self.mutate_with_update_context(|avm2, context| { let rval = self.mutate_with_update_context(|context| {
let rval = func(avm2, context); let rval = func(context);
Self::run_actions(avm2, context); Self::run_actions(context);
rval rval
}); });
@ -1108,7 +1106,7 @@ impl Player {
} }
pub fn flush_shared_objects(&mut self) { pub fn flush_shared_objects(&mut self) {
self.update(|_avm2, context| { self.update(|context| {
let mut activation = let mut activation =
Activation::from_stub(context.reborrow(), ActivationIdentifier::root("[Flush]")); Activation::from_stub(context.reborrow(), ActivationIdentifier::root("[Flush]"));
let shared_objects = activation.context.shared_objects.clone(); let shared_objects = activation.context.shared_objects.clone();
@ -1122,7 +1120,7 @@ impl Player {
/// Returns the approximate amount of time until the next timer tick. /// Returns the approximate amount of time until the next timer tick.
pub fn update_timers(&mut self, dt: f64) { pub fn update_timers(&mut self, dt: f64) {
self.time_til_next_timer = self.time_til_next_timer =
self.mutate_with_update_context(|_avm2, context| Timers::update_timers(context, dt)); self.mutate_with_update_context(|context| Timers::update_timers(context, dt));
} }
} }