diff --git a/core/src/avm2.rs b/core/src/avm2.rs index b31f9405f8f4..866d544f2d8e 100644 --- a/core/src/avm2.rs +++ b/core/src/avm2.rs @@ -94,7 +94,7 @@ pub use crate::avm2::multiname::Multiname; pub use crate::avm2::namespace::{CommonNamespaces, Namespace}; pub use crate::avm2::object::{ ArrayObject, BitmapDataObject, ClassObject, EventObject, LoaderInfoObject, Object, - SoundChannelObject, StageObject, TObject, + SharedObjectObject, SoundChannelObject, StageObject, TObject, }; pub use crate::avm2::qname::QName; pub use crate::avm2::value::Value; @@ -243,8 +243,7 @@ impl<'gc> Avm2<'gc> { pub fn load_player_globals(context: &mut UpdateContext<'gc>) { let globals = context.avm2.playerglobals_domain; - let mut activation = Activation::from_domain(context, globals); - globals::load_playerglobal(&mut activation, globals); + globals::load_playerglobal(context, globals); } pub fn playerglobals_domain(&self) -> Domain<'gc> { @@ -289,19 +288,16 @@ impl<'gc> Avm2<'gc> { script: Script<'gc>, context: &mut UpdateContext<'gc>, ) -> Result<(), Error<'gc>> { - // TODO can we skip creating this temporary Activation? - let mut activation = Activation::from_nothing(context); - let (method, global_object, domain) = script.init(); let scope = ScopeChain::new(domain); // Script `global` classes extend Object - let bound_superclass = Some(activation.avm2().classes().object); + let bound_superclass = Some(context.avm2.classes().object); // Provide a callee object if necessary let callee = if method.needs_arguments_object() { Some(FunctionObject::from_method( - &mut activation, + context, method, scope, Some(global_object.into()), @@ -311,6 +307,9 @@ impl<'gc> Avm2<'gc> { None }; + // TODO can we skip creating this temporary Activation? + let mut activation = Activation::from_nothing(context); + exec( method, scope, diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index 0b01a1832f17..dc5752b6efbe 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -281,7 +281,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { unreachable!(); }; - let args_object = ArrayObject::from_storage(self, args_array); + let args_object = ArrayObject::from_storage(self.context, args_array); if method .method() @@ -1124,7 +1124,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { // TODO: What scope should the function be executed with? let scope = self.create_scopechain(); - let function = FunctionObject::from_method(self, method, scope, None, None); + let function = FunctionObject::from_method(self.context, method, scope, None, None); let value = function.call(self, receiver, args)?; self.push_stack(value); @@ -1505,7 +1505,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { ScriptObject::custom_object(self.gc(), *catch_class, None, catch_class.vtable()) } else { // for `finally` scopes, FP just creates a normal object. - ScriptObject::new_object(self) + ScriptObject::new_object(self.context) }; self.push_stack(so); @@ -1754,7 +1754,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { } fn op_new_object(&mut self, num_args: u32) -> Result<(), Error<'gc>> { - let object = ScriptObject::new_object(self); + let object = ScriptObject::new_object(self.context); for _ in 0..num_args { let value = self.pop_stack(); @@ -1771,7 +1771,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { fn op_new_function(&mut self, method: Method<'gc>) -> Result<(), Error<'gc>> { let scope = self.create_scopechain(); - let new_fn = FunctionObject::from_method(self, method, scope, None, None); + let new_fn = FunctionObject::from_method(self.context, method, scope, None, None); self.push_stack(new_fn); @@ -1846,7 +1846,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { fn op_new_array(&mut self, num_args: u32) -> Result<(), Error<'gc>> { let args = self.pop_stack_args(num_args); let array = ArrayStorage::from_args(&args[..]); - let array_obj = ArrayObject::from_storage(self, array); + let array_obj = ArrayObject::from_storage(self.context, array); self.push_stack(array_obj); diff --git a/core/src/avm2/amf.rs b/core/src/avm2/amf.rs index 693586073b77..d674d9efc0dd 100644 --- a/core/src/avm2/amf.rs +++ b/core/src/avm2/amf.rs @@ -333,12 +333,12 @@ pub fn deserialize_value_impl<'gc>( AmfValue::Bool(b) => (*b).into(), AmfValue::ByteArray(bytes) => { let storage = ByteArrayStorage::from_vec(activation.context, bytes.clone()); - let bytearray = ByteArrayObject::from_storage(activation, storage); + let bytearray = ByteArrayObject::from_storage(activation.context, storage); bytearray.into() } AmfValue::ECMAArray(id, values, elements, _) => { let empty_storage = ArrayStorage::new(0); - let array = ArrayObject::from_storage(activation, empty_storage); + let array = ArrayObject::from_storage(activation.context, empty_storage); object_map.insert(*id, array.into()); // First let's create an array out of `values` (dense portion), then we add the elements onto it. @@ -371,7 +371,7 @@ pub fn deserialize_value_impl<'gc>( } AmfValue::StrictArray(id, values) => { let empty_storage = ArrayStorage::new(0); - let array = ArrayObject::from_storage(activation, empty_storage); + let array = ArrayObject::from_storage(activation.context, empty_storage); object_map.insert(*id, array.into()); let mut arr: Vec>> = Vec::with_capacity(values.len()); @@ -538,7 +538,7 @@ pub fn deserialize_lso<'gc>( activation: &mut Activation<'_, 'gc>, lso: &Lso, ) -> Result, Error<'gc>> { - let obj = ScriptObject::new_object(activation); + let obj = ScriptObject::new_object(activation.context); for child in &lso.body { obj.set_dynamic_property( diff --git a/core/src/avm2/domain.rs b/core/src/avm2/domain.rs index da9cc22a9d4f..2bc8bb8ce188 100644 --- a/core/src/avm2/domain.rs +++ b/core/src/avm2/domain.rs @@ -139,10 +139,10 @@ impl<'gc> Domain<'gc> { /// /// This function must not be called before the player globals have been /// fully allocated. - pub fn movie_domain(activation: &mut Activation<'_, 'gc>, parent: Domain<'gc>) -> Domain<'gc> { - let domain_memory = Self::create_default_domain_memory(activation); + pub fn movie_domain(context: &mut UpdateContext<'gc>, parent: Domain<'gc>) -> Domain<'gc> { + let domain_memory = Self::create_default_domain_memory(context); let this = Self(Gc::new( - activation.gc(), + context.gc(), DomainData { cell: RefLock::new(DomainDataMut { defs: PropertyMap::new(), @@ -159,7 +159,7 @@ impl<'gc> Domain<'gc> { #[cfg(feature = "egui")] { parent - .cell_mut(activation.gc()) + .cell_mut(context.gc()) .children .push(DomainWeak(Gc::downgrade(this.0))); } @@ -400,10 +400,10 @@ impl<'gc> Domain<'gc> { Ok(()) } - fn create_default_domain_memory(activation: &mut Activation<'_, 'gc>) -> ByteArrayObject<'gc> { + fn create_default_domain_memory(context: &mut UpdateContext<'gc>) -> ByteArrayObject<'gc> { let initial_data = vec![0; MIN_DOMAIN_MEMORY_LENGTH]; - let storage = ByteArrayStorage::from_vec(activation.context, initial_data); - ByteArrayObject::from_storage(activation, storage) + let storage = ByteArrayStorage::from_vec(context, initial_data); + ByteArrayObject::from_storage(context, storage) } /// Allocate the default domain memory for this domain, if it does not @@ -411,10 +411,10 @@ impl<'gc> Domain<'gc> { /// /// This function is only necessary to be called for domains created via /// `global_domain`. It will panic on already fully-initialized domains. - pub fn init_default_domain_memory(self, activation: &mut Activation<'_, 'gc>) { - let memory = Self::create_default_domain_memory(activation); + pub fn init_default_domain_memory(self, context: &mut UpdateContext<'gc>) { + let memory = Self::create_default_domain_memory(context); - let write = Gc::write(activation.gc(), self.0); + let write = Gc::write(context.gc(), self.0); match unlock!(write, DomainData, default_domain_memory).set(memory) { Ok(_) => unlock!(write, DomainData, domain_memory).set(Some(memory)), Err(_) => panic!("Already initialized domain memory!"), diff --git a/core/src/avm2/filters.rs b/core/src/avm2/filters.rs index 97b86c9b50b8..d6c3b22c427b 100644 --- a/core/src/avm2/filters.rs +++ b/core/src/avm2/filters.rs @@ -348,7 +348,7 @@ fn color_matrix_filter_to_avm2<'gc>( filter: &ColorMatrixFilter, ) -> Result, Error<'gc>> { let matrix = ArrayObject::from_storage( - activation, + activation.context, filter.matrix.iter().map(|v| Value::from(*v)).collect(), ); activation @@ -423,7 +423,7 @@ fn convolution_filter_to_avm2<'gc>( filter: &ConvolutionFilter, ) -> Result, Error<'gc>> { let matrix = ArrayObject::from_storage( - activation, + activation.context, filter .matrix .iter() @@ -755,7 +755,7 @@ fn gradient_filter_to_avm2<'gc>( class: ClassObject<'gc>, ) -> Result, Error<'gc>> { let colors = ArrayObject::from_storage( - activation, + activation.context, filter .colors .iter() @@ -763,7 +763,7 @@ fn gradient_filter_to_avm2<'gc>( .collect(), ); let alphas = ArrayObject::from_storage( - activation, + activation.context, filter .colors .iter() @@ -771,7 +771,7 @@ fn gradient_filter_to_avm2<'gc>( .collect(), ); let ratios = ArrayObject::from_storage( - activation, + activation.context, filter.colors.iter().map(|v| Value::from(v.ratio)).collect(), ); class.construct( diff --git a/core/src/avm2/flv.rs b/core/src/avm2/flv.rs index 2cddcb420cc7..d423d678c37e 100644 --- a/core/src/avm2/flv.rs +++ b/core/src/avm2/flv.rs @@ -1,24 +1,25 @@ use crate::avm2::array::ArrayStorage; use crate::avm2::object::{ArrayObject, DateObject, ScriptObject, TObject as _}; -use crate::avm2::{Activation, Value as Avm2Value}; +use crate::avm2::Value as Avm2Value; +use crate::context::UpdateContext; use crate::string::AvmString; use chrono::DateTime; use flv_rs::{Value as FlvValue, Variable as FlvVariable}; fn avm2_object_from_flv_variables<'gc>( - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, variables: Vec, ) -> Avm2Value<'gc> { - let info_object = ScriptObject::new_object(activation); + let info_object = ScriptObject::new_object(context); for value in variables { let property_name = value.name; info_object.set_dynamic_property( - AvmString::new_utf8_bytes(activation.gc(), property_name), - value.data.to_avm2_value(activation), - activation.gc(), + AvmString::new_utf8_bytes(context.gc(), property_name), + value.data.to_avm2_value(context), + context.gc(), ); } @@ -26,47 +27,47 @@ fn avm2_object_from_flv_variables<'gc>( } fn avm2_array_from_flv_values<'gc>( - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, values: Vec, ) -> Avm2Value<'gc> { let storage = ArrayStorage::from_storage( values .iter() - .map(|v| Some(v.clone().to_avm2_value(activation))) + .map(|v| Some(v.clone().to_avm2_value(context))) .collect::>>>(), ); - ArrayObject::from_storage(activation, storage).into() + ArrayObject::from_storage(context, storage).into() } fn avm2_date_from_flv_date<'gc>( - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, unix_time: f64, _local_offset: i16, ) -> Avm2Value<'gc> { let date_time = DateTime::from_timestamp(unix_time as i64, 0).expect("invalid timestamp"); - DateObject::from_date_time(activation, date_time).into() + DateObject::from_date_time(context, date_time).into() } pub trait FlvValueAvm2Ext<'gc> { - fn to_avm2_value(self, activation: &mut Activation<'_, 'gc>) -> Avm2Value<'gc>; + fn to_avm2_value(self, context: &mut UpdateContext<'gc>) -> Avm2Value<'gc>; } impl<'gc> FlvValueAvm2Ext<'gc> for FlvValue<'_> { - fn to_avm2_value(self, activation: &mut Activation<'_, 'gc>) -> Avm2Value<'gc> { + fn to_avm2_value(self, context: &mut UpdateContext<'gc>) -> Avm2Value<'gc> { match self { FlvValue::Object(variables) | FlvValue::EcmaArray(variables) => { - avm2_object_from_flv_variables(activation, variables) + avm2_object_from_flv_variables(context, variables) } - FlvValue::StrictArray(values) => avm2_array_from_flv_values(activation, values), + FlvValue::StrictArray(values) => avm2_array_from_flv_values(context, values), FlvValue::String(string_data) | FlvValue::LongString(string_data) => { - AvmString::new_utf8_bytes(activation.gc(), string_data).into() + AvmString::new_utf8_bytes(context.gc(), string_data).into() } FlvValue::Date { unix_time, local_offset, - } => avm2_date_from_flv_date(activation, unix_time, local_offset), + } => avm2_date_from_flv_date(context, unix_time, local_offset), FlvValue::Number(value) => value.into(), FlvValue::Boolean(value) => value.into(), FlvValue::Null => Avm2Value::Null, diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index 13c1be875975..ecadcded8a00 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -6,6 +6,7 @@ use crate::avm2::object::{ClassObject, ScriptObject}; use crate::avm2::scope::{Scope, ScopeChain}; use crate::avm2::script::TranslationUnit; use crate::avm2::{Avm2, Error, Multiname, Namespace, QName}; +use crate::context::UpdateContext; use crate::string::WStr; use crate::tag_utils::{self, ControlFlow, SwfMovie, SwfSlice, SwfStream}; use gc_arena::Collect; @@ -510,10 +511,10 @@ pub fn init_early_classes<'gc>( ); // Now to weave the Gordian knot... - object_class.link_prototype(activation, object_proto); + object_class.link_prototype(activation.context, object_proto); object_class.link_type(mc, class_proto); - class_class.link_prototype(activation, class_proto); + class_class.link_prototype(activation.context, class_proto); class_class.link_type(mc, class_proto); // At this point, we need both early classes to be available in `SystemClasses` @@ -815,12 +816,12 @@ pub fn init_native_system_classes(activation: &mut Activation<'_, '_>) { /// Loads classes from our custom 'playerglobal' (which are written in ActionScript) /// into the environment. See 'core/src/avm2/globals/README.md' for more information -pub fn load_playerglobal<'gc>(activation: &mut Activation<'_, 'gc>, domain: Domain<'gc>) { - activation.avm2().native_method_table = native::NATIVE_METHOD_TABLE; - activation.avm2().native_instance_allocator_table = native::NATIVE_INSTANCE_ALLOCATOR_TABLE; - activation.avm2().native_call_handler_table = native::NATIVE_CALL_HANDLER_TABLE; - activation.avm2().native_custom_constructor_table = native::NATIVE_CUSTOM_CONSTRUCTOR_TABLE; - activation.avm2().native_fast_call_list = native::NATIVE_FAST_CALL_LIST; +pub fn load_playerglobal<'gc>(context: &mut UpdateContext<'gc>, domain: Domain<'gc>) { + context.avm2.native_method_table = native::NATIVE_METHOD_TABLE; + context.avm2.native_instance_allocator_table = native::NATIVE_INSTANCE_ALLOCATOR_TABLE; + context.avm2.native_call_handler_table = native::NATIVE_CALL_HANDLER_TABLE; + context.avm2.native_custom_constructor_table = native::NATIVE_CUSTOM_CONSTRUCTOR_TABLE; + context.avm2.native_fast_call_list = native::NATIVE_FAST_CALL_LIST; let movie = Arc::new( SwfMovie::from_data(PLAYERGLOBAL, "file:///".into(), None) @@ -836,7 +837,7 @@ pub fn load_playerglobal<'gc>(activation: &mut Activation<'_, 'gc>, domain: Doma let do_abc = reader .read_do_abc_2() .expect("playerglobal.swf should be valid"); - Avm2::load_builtin_abc(activation.context, do_abc.data, domain, movie.clone()); + Avm2::load_builtin_abc(context, do_abc.data, domain, movie.clone()); } else if tag_code != TagCode::End { panic!("playerglobal should only contain `DoAbc2` tag - found tag {tag_code:?}") } @@ -846,9 +847,9 @@ pub fn load_playerglobal<'gc>(activation: &mut Activation<'_, 'gc>, domain: Doma let _ = tag_utils::decode_tags(&mut reader, tag_callback); // Domain memory must be initialized after playerglobals is loaded because it relies on ByteArray. - domain.init_default_domain_memory(activation); - activation - .avm2() + domain.init_default_domain_memory(context); + context + .avm2 .stage_domain() - .init_default_domain_memory(activation); + .init_default_domain_memory(context); } diff --git a/core/src/avm2/globals/array.rs b/core/src/avm2/globals/array.rs index 64e2150a1e16..b528d86139fc 100644 --- a/core/src/avm2/globals/array.rs +++ b/core/src/avm2/globals/array.rs @@ -87,7 +87,7 @@ pub fn build_array<'gc>( activation: &mut Activation<'_, 'gc>, array: ArrayStorage<'gc>, ) -> Value<'gc> { - ArrayObject::from_storage(activation, array).into() + ArrayObject::from_storage(activation.context, array).into() } /// Implements `Array.concat` @@ -329,7 +329,7 @@ pub fn map<'gc>( let this = this.as_object().unwrap(); let callback = match args.try_get_function(0) { - None => return Ok(ArrayObject::empty(activation).into()), + None => return Ok(ArrayObject::empty(activation.context).into()), Some(callback) => callback, }; let receiver = args.get_value(1); @@ -355,7 +355,7 @@ pub fn filter<'gc>( let this = this.as_object().unwrap(); let callback = match args.try_get_function(0) { - None => return Ok(ArrayObject::empty(activation).into()), + None => return Ok(ArrayObject::empty(activation.context).into()), Some(callback) => callback, }; let receiver = args.get_value(1); diff --git a/core/src/avm2/globals/avmplus.rs b/core/src/avm2/globals/avmplus.rs index e59edb2b4b45..1576e6026b7d 100644 --- a/core/src/avm2/globals/avmplus.rs +++ b/core/src/avm2/globals/avmplus.rs @@ -6,9 +6,10 @@ use crate::avm2::object::{ArrayObject, ScriptObject, TObject as _}; use crate::avm2::parameters::ParametersExt; use crate::avm2::property::Property; use crate::avm2::{Activation, Error, Multiname, Namespace, Object, Value}; +use crate::context::UpdateContext; use crate::string::{AvmString, StringContext}; -use crate::avm2_stub_method; +use crate::avm2_stub_method_context; use gc_arena::Gc; use ruffle_macros::istr; @@ -23,7 +24,7 @@ pub fn describe_type_json<'gc>( let value = args.get_value(0); let class_def = instance_class_describe_type(activation, value); - let object = ScriptObject::new_object(activation); + let object = ScriptObject::new_object(activation.context); let mut used_class_def = class_def; if flags.contains(DescribeTypeFlags::USE_ITRAITS) { @@ -60,7 +61,7 @@ pub fn describe_type_json<'gc>( activation.gc(), ); - let traits = describe_internal_body(activation, used_class_def, flags); + let traits = describe_internal_body(activation.context, used_class_def, flags); if flags.contains(DescribeTypeFlags::INCLUDE_TRAITS) { object.set_dynamic_property(istr!("traits"), traits.into(), activation.gc()); } else { @@ -88,48 +89,48 @@ bitflags::bitflags! { } fn describe_internal_body<'gc>( - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, class_def: Class<'gc>, flags: DescribeTypeFlags, ) -> Object<'gc> { - let mc = activation.gc(); + let mc = context.gc(); - let traits = ScriptObject::new_object(activation); + let traits = ScriptObject::new_object(context); - let bases = ArrayObject::empty(activation); - let interfaces = ArrayObject::empty(activation); - let variables = ArrayObject::empty(activation); - let accessors = ArrayObject::empty(activation); - let methods = ArrayObject::empty(activation); + let bases = ArrayObject::empty(context); + let interfaces = ArrayObject::empty(context); + let variables = ArrayObject::empty(context); + let accessors = ArrayObject::empty(context); + let methods = ArrayObject::empty(context); if flags.contains(DescribeTypeFlags::INCLUDE_BASES) { - traits.set_dynamic_property(istr!("bases"), bases.into(), activation.gc()); + traits.set_dynamic_property(istr!(context, "bases"), bases.into(), mc); } else { - traits.set_dynamic_property(istr!("bases"), Value::Null, activation.gc()); + traits.set_dynamic_property(istr!(context, "bases"), Value::Null, mc); } if flags.contains(DescribeTypeFlags::INCLUDE_INTERFACES) { - traits.set_dynamic_property(istr!("interfaces"), interfaces.into(), activation.gc()); + traits.set_dynamic_property(istr!(context, "interfaces"), interfaces.into(), mc); } else { - traits.set_dynamic_property(istr!("interfaces"), Value::Null, activation.gc()); + traits.set_dynamic_property(istr!(context, "interfaces"), Value::Null, mc); } if flags.contains(DescribeTypeFlags::INCLUDE_VARIABLES) { - traits.set_dynamic_property(istr!("variables"), variables.into(), activation.gc()); + traits.set_dynamic_property(istr!(context, "variables"), variables.into(), mc); } else { - traits.set_dynamic_property(istr!("variables"), Value::Null, activation.gc()); + traits.set_dynamic_property(istr!(context, "variables"), Value::Null, mc); } if flags.contains(DescribeTypeFlags::INCLUDE_ACCESSORS) { - traits.set_dynamic_property(istr!("accessors"), accessors.into(), activation.gc()); + traits.set_dynamic_property(istr!(context, "accessors"), accessors.into(), mc); } else { - traits.set_dynamic_property(istr!("accessors"), Value::Null, activation.gc()); + traits.set_dynamic_property(istr!(context, "accessors"), Value::Null, mc); } if flags.contains(DescribeTypeFlags::INCLUDE_METHODS) { - traits.set_dynamic_property(istr!("methods"), methods.into(), activation.gc()); + traits.set_dynamic_property(istr!(context, "methods"), methods.into(), mc); } else { - traits.set_dynamic_property(istr!("methods"), Value::Null, activation.gc()); + traits.set_dynamic_property(istr!(context, "methods"), Value::Null, mc); } let mut bases_array = bases.storage_mut(mc); @@ -164,7 +165,7 @@ fn describe_internal_body<'gc>( let mut skip_ns: Vec> = Vec::new(); if let Some(super_vtable) = super_vtable { for (_, ns, prop) in super_vtable.resolved_traits().iter() { - if !ns.as_uri(activation.strings()).is_empty() { + if !ns.as_uri(&mut context.strings).is_empty() { if let Property::Method { .. } = prop { if !skip_ns .iter() @@ -184,7 +185,7 @@ fn describe_internal_body<'gc>( continue; } - if !ns.matches_api_version(activation.avm2().root_api_version) { + if !ns.matches_api_version(context.avm2.root_api_version) { continue; } @@ -203,41 +204,37 @@ fn describe_internal_body<'gc>( if !flags.contains(DescribeTypeFlags::INCLUDE_VARIABLES) { continue; } - let prop_class_name = vtable.slot_class_name(activation.strings(), *slot_id); + let prop_class_name = vtable.slot_class_name(&mut context.strings, *slot_id); let access = match prop { - Property::ConstSlot { .. } => istr!("readonly"), - Property::Slot { .. } => istr!("readwrite"), + Property::ConstSlot { .. } => istr!(context, "readonly"), + Property::Slot { .. } => istr!(context, "readwrite"), _ => unreachable!(), }; let trait_metadata = vtable.get_metadata_for_slot(*slot_id); - let variable = ScriptObject::new_object(activation); - variable.set_dynamic_property(istr!("name"), prop_name.into(), activation.gc()); - variable.set_dynamic_property( - istr!("type"), - prop_class_name.into(), - activation.gc(), - ); - variable.set_dynamic_property(istr!("access"), access.into(), activation.gc()); + let variable = ScriptObject::new_object(context); + variable.set_dynamic_property(istr!(context, "name"), prop_name.into(), mc); + variable.set_dynamic_property(istr!(context, "type"), prop_class_name.into(), mc); + variable.set_dynamic_property(istr!(context, "access"), access.into(), mc); variable.set_dynamic_property( - istr!("uri"), + istr!(context, "uri"), uri.map_or(Value::Null, |u| u.into()), - activation.gc(), + mc, ); - variable.set_dynamic_property(istr!("metadata"), Value::Null, activation.gc()); + variable.set_dynamic_property(istr!(context, "metadata"), Value::Null, mc); if flags.contains(DescribeTypeFlags::INCLUDE_METADATA) { - let metadata_object = ArrayObject::empty(activation); + let metadata_object = ArrayObject::empty(context); if let Some(metadata) = trait_metadata { - write_metadata(metadata_object, metadata, activation); + write_metadata(metadata_object, metadata, context); } variable.set_dynamic_property( - istr!("metadata"), + istr!(context, "metadata"), metadata_object.into(), - activation.gc(), + mc, ); } @@ -264,10 +261,10 @@ fn describe_internal_body<'gc>( continue; } - let return_type_name = display_name(activation.strings(), method.return_type()); + let return_type_name = display_name(&mut context.strings, method.return_type()); if flags.contains(DescribeTypeFlags::HIDE_OBJECT) - && declared_by == activation.avm2().class_defs().object + && declared_by == context.avm2.class_defs().object { continue; } @@ -276,44 +273,40 @@ fn describe_internal_body<'gc>( let trait_metadata = vtable.get_metadata_for_disp(*disp_id); - let method_obj = ScriptObject::new_object(activation); + let method_obj = ScriptObject::new_object(context); - method_obj.set_dynamic_property(istr!("name"), prop_name.into(), activation.gc()); + method_obj.set_dynamic_property(istr!(context, "name"), prop_name.into(), mc); method_obj.set_dynamic_property( - istr!("returnType"), + istr!(context, "returnType"), return_type_name.into(), - activation.gc(), + mc, ); method_obj.set_dynamic_property( - istr!("declaredBy"), + istr!(context, "declaredBy"), declared_by_name.into(), - activation.gc(), + mc, ); method_obj.set_dynamic_property( - istr!("uri"), + istr!(context, "uri"), uri.map_or(Value::Null, |u| u.into()), - activation.gc(), + mc, ); - let params = write_params(method, activation); - method_obj.set_dynamic_property( - istr!("parameters"), - params.into(), - activation.gc(), - ); + let params = write_params(method, context); + method_obj.set_dynamic_property(istr!(context, "parameters"), params.into(), mc); - method_obj.set_dynamic_property(istr!("metadata"), Value::Null, activation.gc()); + method_obj.set_dynamic_property(istr!(context, "metadata"), Value::Null, mc); if flags.contains(DescribeTypeFlags::INCLUDE_METADATA) { - let metadata_object = ArrayObject::empty(activation); + let metadata_object = ArrayObject::empty(context); if let Some(metadata) = trait_metadata { - write_metadata(metadata_object, metadata, activation); + write_metadata(metadata_object, metadata, context); } method_obj.set_dynamic_property( - istr!("metadata"), + istr!(context, "metadata"), metadata_object.into(), - activation.gc(), + mc, ); } methods_array.push(method_obj.into()); @@ -323,9 +316,9 @@ fn describe_internal_body<'gc>( continue; } let access = match (get, set) { - (Some(_), Some(_)) => istr!("readwrite"), - (Some(_), None) => istr!("readonly"), - (None, Some(_)) => istr!("writeonly"), + (Some(_), Some(_)) => istr!(context, "readwrite"), + (Some(_), None) => istr!(context, "readonly"), + (None, Some(_)) => istr!(context, "writeonly"), (None, None) => unreachable!(), }; @@ -363,39 +356,35 @@ fn describe_internal_body<'gc>( } let uri = ns.as_uri_opt().filter(|uri| !uri.is_empty()); - let accessor_type = display_name(activation.strings(), method_type); + let accessor_type = display_name(&mut context.strings, method_type); let declared_by = defining_class.dollar_removed_name(mc).to_qualified_name(mc); - let accessor_obj = ScriptObject::new_object(activation); - accessor_obj.set_dynamic_property(istr!("name"), prop_name.into(), activation.gc()); - accessor_obj.set_dynamic_property(istr!("access"), access.into(), activation.gc()); - accessor_obj.set_dynamic_property( - istr!("type"), - accessor_type.into(), - activation.gc(), - ); + let accessor_obj = ScriptObject::new_object(context); + accessor_obj.set_dynamic_property(istr!(context, "name"), prop_name.into(), mc); + accessor_obj.set_dynamic_property(istr!(context, "access"), access.into(), mc); + accessor_obj.set_dynamic_property(istr!(context, "type"), accessor_type.into(), mc); accessor_obj.set_dynamic_property( - istr!("declaredBy"), + istr!(context, "declaredBy"), declared_by.into(), - activation.gc(), + mc, ); accessor_obj.set_dynamic_property( - istr!("uri"), + istr!(context, "uri"), uri.map_or(Value::Null, |u| u.into()), - activation.gc(), + mc, ); - let metadata_object = ArrayObject::empty(activation); + let metadata_object = ArrayObject::empty(context); if let Some(get_disp_id) = get { if let Some(metadata) = vtable.get_metadata_for_disp(*get_disp_id) { - write_metadata(metadata_object, metadata, activation); + write_metadata(metadata_object, metadata, context); } } if let Some(set_disp_id) = set { if let Some(metadata) = vtable.get_metadata_for_disp(*set_disp_id) { - write_metadata(metadata_object, metadata, activation); + write_metadata(metadata_object, metadata, context); } } @@ -403,16 +392,12 @@ fn describe_internal_body<'gc>( && metadata_object.storage().length() > 0 { accessor_obj.set_dynamic_property( - istr!("metadata"), + istr!(context, "metadata"), metadata_object.into(), - activation.gc(), + mc, ); } else { - accessor_obj.set_dynamic_property( - istr!("metadata"), - Value::Null, - activation.gc(), - ); + accessor_obj.set_dynamic_property(istr!(context, "metadata"), Value::Null, mc); } accessors_array.push(accessor_obj.into()); @@ -425,25 +410,25 @@ fn describe_internal_body<'gc>( if let Some(constructor) = constructor.filter(|c| { !c.signature().is_empty() && flags.contains(DescribeTypeFlags::INCLUDE_CONSTRUCTOR) }) { - let params = write_params(constructor, activation); - traits.set_dynamic_property(istr!("constructor"), params.into(), activation.gc()); + let params = write_params(constructor, context); + traits.set_dynamic_property(istr!(context, "constructor"), params.into(), mc); } else { // This is needed to override the normal 'constructor' property - traits.set_dynamic_property(istr!("constructor"), Value::Null, activation.gc()); + traits.set_dynamic_property(istr!(context, "constructor"), Value::Null, mc); } if flags.contains(DescribeTypeFlags::INCLUDE_METADATA) { - avm2_stub_method!( - activation, + avm2_stub_method_context!( + context, "avmplus", "describeTypeJSON", "with top-level metadata" ); - let metadata_object = ArrayObject::empty(activation); - traits.set_dynamic_property(istr!("metadata"), metadata_object.into(), activation.gc()); + let metadata_object = ArrayObject::empty(context); + traits.set_dynamic_property(istr!(context, "metadata"), metadata_object.into(), mc); } else { - traits.set_dynamic_property(istr!("metadata"), Value::Null, activation.gc()); + traits.set_dynamic_property(istr!(context, "metadata"), Value::Null, mc); } traits @@ -460,18 +445,17 @@ fn display_name<'gc>( } } -fn write_params<'gc>( - method: Method<'gc>, - activation: &mut Activation<'_, 'gc>, -) -> ArrayObject<'gc> { - let params = ArrayObject::empty(activation); - let mut params_array = params.storage_mut(activation.gc()); +fn write_params<'gc>(method: Method<'gc>, context: &mut UpdateContext<'gc>) -> ArrayObject<'gc> { + let mc = context.gc(); + + let params = ArrayObject::empty(context); + let mut params_array = params.storage_mut(mc); for param in method.signature() { - let param_type_name = display_name(activation.strings(), param.param_type_name); + let param_type_name = display_name(&mut context.strings, param.param_type_name); let optional = param.default_value.is_some(); - let param_obj = ScriptObject::new_object(activation); - param_obj.set_dynamic_property(istr!("type"), param_type_name.into(), activation.gc()); - param_obj.set_dynamic_property(istr!("optional"), optional.into(), activation.gc()); + let param_obj = ScriptObject::new_object(context); + param_obj.set_dynamic_property(istr!(context, "type"), param_type_name.into(), mc); + param_obj.set_dynamic_property(istr!(context, "optional"), optional.into(), mc); params_array.push(param_obj.into()); } params @@ -480,12 +464,12 @@ fn write_params<'gc>( fn write_metadata<'gc>( metadata_object: ArrayObject<'gc>, trait_metadata: &[Metadata<'gc>], - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, ) { - let mut metadata_array = metadata_object.storage_mut(activation.gc()); + let mut metadata_array = metadata_object.storage_mut(context.gc()); for single_trait in trait_metadata.iter() { - metadata_array.push(single_trait.as_json_object(activation).into()); + metadata_array.push(single_trait.as_json_object(context).into()); } } diff --git a/core/src/avm2/globals/date.rs b/core/src/avm2/globals/date.rs index f6f96a858aa7..586a5656fbcc 100644 --- a/core/src/avm2/globals/date.rs +++ b/core/src/avm2/globals/date.rs @@ -198,9 +198,9 @@ pub fn init_custom_prototype<'gc>( let this = this.as_object().unwrap(); let this = this.as_class_object().unwrap(); - let prototype_date_object = DateObject::for_prototype(activation, this); + let prototype_date_object = DateObject::for_prototype(activation.context, this); - this.link_prototype(activation, prototype_date_object); + this.link_prototype(activation.context, prototype_date_object); Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/display/bitmap_data.rs b/core/src/avm2/globals/flash/display/bitmap_data.rs index d4bedca6b4e0..6c8d2cc2fa8b 100644 --- a/core/src/avm2/globals/flash/display/bitmap_data.rs +++ b/core/src/avm2/globals/flash/display/bitmap_data.rs @@ -323,7 +323,7 @@ pub fn get_pixels<'gc>( &mut storage, )?; - let bytearray = ByteArrayObject::from_storage(activation, storage); + let bytearray = ByteArrayObject::from_storage(activation.context, storage); return Ok(bytearray.into()); } diff --git a/core/src/avm2/globals/flash/display/display_object.rs b/core/src/avm2/globals/flash/display/display_object.rs index 391139aba44c..ee6891e645fb 100644 --- a/core/src/avm2/globals/flash/display/display_object.rs +++ b/core/src/avm2/globals/flash/display/display_object.rs @@ -295,9 +295,9 @@ pub fn get_filters<'gc>( .iter() .map(|f| f.as_avm2_object(activation)) .collect::, Error<'gc>>>()?; - return Ok(ArrayObject::from_storage(activation, array).into()); + return Ok(ArrayObject::from_storage(activation.context, array).into()); } - Ok(ArrayObject::empty(activation).into()) + Ok(ArrayObject::empty(activation.context).into()) } fn build_argument_type_error<'gc>( diff --git a/core/src/avm2/globals/flash/display/display_object_container.rs b/core/src/avm2/globals/flash/display/display_object_container.rs index 0d76a5e632ae..5643b778e2e7 100644 --- a/core/src/avm2/globals/flash/display/display_object_container.rs +++ b/core/src/avm2/globals/flash/display/display_object_container.rs @@ -607,7 +607,10 @@ pub fn get_objects_under_point<'gc>( } } - Ok(ArrayObject::from_storage(activation, ArrayStorage::from_storage(under_point)).into()) + Ok( + ArrayObject::from_storage(activation.context, ArrayStorage::from_storage(under_point)) + .into(), + ) } pub fn are_inaccessible_objects_under_point<'gc>( diff --git a/core/src/avm2/globals/flash/display/loader_info.rs b/core/src/avm2/globals/flash/display/loader_info.rs index 12dd646f324c..6ee8cbdf4298 100644 --- a/core/src/avm2/globals/flash/display/loader_info.rs +++ b/core/src/avm2/globals/flash/display/loader_info.rs @@ -537,7 +537,7 @@ pub fn get_parameters<'gc>( LoaderStream::Swf(root, _) => root, }; - let params_obj = ScriptObject::new_object(activation); + let params_obj = ScriptObject::new_object(activation.context); let parameters = root.parameters(); for (k, v) in parameters.iter() { diff --git a/core/src/avm2/globals/flash/display/movie_clip.rs b/core/src/avm2/globals/flash/display/movie_clip.rs index 29cebd586e4b..3ad5ba7911ff 100644 --- a/core/src/avm2/globals/flash/display/movie_clip.rs +++ b/core/src/avm2/globals/flash/display/movie_clip.rs @@ -143,7 +143,7 @@ fn labels_for_scene<'gc>( Ok(( scene_name.to_string(), *scene_length, - ArrayObject::from_storage(activation, ArrayStorage::from_storage(frame_labels)), + ArrayObject::from_storage(activation.context, ArrayStorage::from_storage(frame_labels)), )) } @@ -277,7 +277,7 @@ pub fn get_scenes<'gc>( } return Ok(ArrayObject::from_storage( - activation, + activation.context, ArrayStorage::from_storage(scene_objects), ) .into()); diff --git a/core/src/avm2/globals/flash/display/shader_data.rs b/core/src/avm2/globals/flash/display/shader_data.rs index 1e0365a1e7b9..95f6bc4bcc54 100644 --- a/core/src/avm2/globals/flash/display/shader_data.rs +++ b/core/src/avm2/globals/flash/display/shader_data.rs @@ -39,7 +39,7 @@ pub fn _set_byte_code<'gc>( let name = AvmString::new_utf8(activation.gc(), &meta.key); // Top-level metadata appears to turn `TInt` into a plain integer value, // rather than a single-element array. - let value = meta.value.as_avm2_value(activation, true)?; + let value = meta.value.as_avm2_value(activation.context, true)?; this.set_dynamic_property(name, value, activation.gc()); } this.set_dynamic_property( diff --git a/core/src/avm2/globals/flash/display/shader_parameter.rs b/core/src/avm2/globals/flash/display/shader_parameter.rs index 50de6509fc8b..af57ed7c42e3 100644 --- a/core/src/avm2/globals/flash/display/shader_parameter.rs +++ b/core/src/avm2/globals/flash/display/shader_parameter.rs @@ -36,7 +36,10 @@ pub fn make_shader_parameter<'gc>( param_object.set_slot(parameter_slots::_TYPE, type_name.into(), activation)?; for meta in metadata { let name = AvmString::new_utf8(activation.gc(), &meta.key); - let value = meta.value.clone().as_avm2_value(activation, false)?; + let value = meta + .value + .clone() + .as_avm2_value(activation.context, false)?; param_value.set_public_property(name, value, activation)?; if &*name == b"defaultValue" { diff --git a/core/src/avm2/globals/flash/external/external_interface.rs b/core/src/avm2/globals/flash/external/external_interface.rs index e8e34a7b8db5..4e96893cac56 100644 --- a/core/src/avm2/globals/flash/external/external_interface.rs +++ b/core/src/avm2/globals/flash/external/external_interface.rs @@ -18,10 +18,10 @@ pub fn call<'gc>( .map(|arg| ExternalValue::from_avm2(activation, arg.to_owned())) .collect::, Error>>()?; - Ok( - ExternalInterface::call_method(activation.context, &name.to_utf8_lossy(), &external_args) - .into_avm2(activation), - ) + let result = + ExternalInterface::call_method(activation.context, &name.to_utf8_lossy(), &external_args); + + Ok(result.into_avm2(activation.context)) } fn check_available<'gc>(activation: &mut Activation<'_, 'gc>) -> Result<(), Error<'gc>> { diff --git a/core/src/avm2/globals/flash/net/file_reference.rs b/core/src/avm2/globals/flash/net/file_reference.rs index a7751b41eb9c..cab3b143e172 100644 --- a/core/src/avm2/globals/flash/net/file_reference.rs +++ b/core/src/avm2/globals/flash/net/file_reference.rs @@ -22,7 +22,7 @@ pub fn get_creation_date<'gc>( FileReference::None => return Err(make_error_2037(activation)), FileReference::FileDialogResult(ref dialog_result) => { if let Some(time) = dialog_result.creation_time() { - DateObject::from_date_time(activation, time).into() + DateObject::from_date_time(activation.context, time).into() } else { Value::Null } @@ -45,7 +45,7 @@ pub fn get_data<'gc>( FileReference::FileDialogResult(ref dialog_result) if this.loaded() => { let bytes = dialog_result.contents(); let storage = ByteArrayStorage::from_vec(activation.context, bytes.to_vec()); - ByteArrayObject::from_storage(activation, storage) + ByteArrayObject::from_storage(activation.context, storage) } // Contrary to other getters `data` will return null instead of throwing. _ => return Ok(Value::Null), @@ -67,7 +67,7 @@ pub fn get_modification_date<'gc>( FileReference::None => return Err(make_error_2037(activation)), FileReference::FileDialogResult(ref dialog_result) => { if let Some(time) = dialog_result.modification_time() { - DateObject::from_date_time(activation, time).into() + DateObject::from_date_time(activation.context, time).into() } else { Value::Null } diff --git a/core/src/avm2/globals/flash/net/shared_object.rs b/core/src/avm2/globals/flash/net/shared_object.rs index a02058ddb3c3..0b1626c20cb7 100644 --- a/core/src/avm2/globals/flash/net/shared_object.rs +++ b/core/src/avm2/globals/flash/net/shared_object.rs @@ -4,6 +4,7 @@ use crate::avm2::error::error; use crate::avm2::object::{ScriptObject, SharedObjectObject}; use crate::avm2::parameters::ParametersExt; use crate::avm2::{Activation, Error, Object, Value}; +use crate::string::AvmString; use crate::{avm2_stub_getter, avm2_stub_method, avm2_stub_setter}; use flash_lso::types::{AMFVersion, Lso}; use ruffle_macros::istr; @@ -158,7 +159,7 @@ pub fn get_local<'gc>( data } else { // No data; create a fresh data object. - ScriptObject::new_object(activation) + ScriptObject::new_object(activation.context) }; let created_shared_object = @@ -167,7 +168,7 @@ pub fn get_local<'gc>( activation .context .avm2_shared_objects - .insert(full_name, created_shared_object.into()); + .insert(full_name, created_shared_object); Ok(created_shared_object.into()) } @@ -187,23 +188,33 @@ pub fn get_data<'gc>( pub fn flush<'gc>( activation: &mut Activation<'_, 'gc>, this: Value<'gc>, - _args: &[Value<'gc>], + args: &[Value<'gc>], ) -> Result, Error<'gc>> { let this = this.as_object().unwrap(); let shared_object = this.as_shared_object().unwrap(); + let min_disk_space = args.get_i32(0); + + flush_impl(activation, shared_object, min_disk_space).map(Value::from) +} + +pub fn flush_impl<'gc>( + activation: &mut Activation<'_, 'gc>, + shared_object: SharedObjectObject<'gc>, + _min_disk_space: i32, +) -> Result, Error<'gc>> { let data = shared_object.data(); let name = shared_object.name(); let mut lso = new_lso(activation, name, data)?; // Flash does not write empty LSOs to disk if lso.body.is_empty() { - Ok(istr!("flushed").into()) + Ok(istr!("flushed")) } else { let bytes = flash_lso::write::write_to_bytes(&mut lso).unwrap_or_default(); if activation.context.storage.put(name, &bytes) { - Ok(istr!("flushed").into()) + Ok(istr!("flushed")) } else { Err(Error::avm_error(error( activation, @@ -256,7 +267,7 @@ pub fn clear<'gc>( let shared_object = this.as_shared_object().unwrap(); // Clear the local data object. - shared_object.reset_data(activation); + shared_object.reset_data(activation.context); // Delete data from storage backend. let name = shared_object.name(); diff --git a/core/src/avm2/globals/flash/system/application_domain.rs b/core/src/avm2/globals/flash/system/application_domain.rs index 36459a1c80fd..a3aaccfb0a1d 100644 --- a/core/src/avm2/globals/flash/system/application_domain.rs +++ b/core/src/avm2/globals/flash/system/application_domain.rs @@ -27,7 +27,7 @@ pub fn init<'gc>( }; let target_domain = this.as_domain_object().expect("Invalid target domain"); - let fresh_domain = Domain::movie_domain(activation, parent_domain); + let fresh_domain = Domain::movie_domain(activation.context, parent_domain); target_domain.init_domain(activation.gc(), fresh_domain); Ok(Value::Undefined) diff --git a/core/src/avm2/globals/flash/text/font.rs b/core/src/avm2/globals/flash/text/font.rs index 8abd76209c3d..ab18aae43075 100644 --- a/core/src/avm2/globals/flash/text/font.rs +++ b/core/src/avm2/globals/flash/text/font.rs @@ -138,7 +138,7 @@ pub fn enumerate_fonts<'gc>( .map(|font| FontObject::for_font(activation.gc(), font_class, font)) .collect(); - Ok(ArrayObject::from_storage(activation, storage).into()) + Ok(ArrayObject::from_storage(activation.context, storage).into()) } /// `Font.registerFont` diff --git a/core/src/avm2/globals/flash/text/style_sheet.rs b/core/src/avm2/globals/flash/text/style_sheet.rs index 413c49c78c8a..147528e00409 100644 --- a/core/src/avm2/globals/flash/text/style_sheet.rs +++ b/core/src/avm2/globals/flash/text/style_sheet.rs @@ -13,11 +13,11 @@ pub fn inner_parse_css<'gc>( args: &[Value<'gc>], ) -> Result, Error<'gc>> { let document = args.get_string(activation, 0); - let result = ScriptObject::new_object(activation); + let result = ScriptObject::new_object(activation.context); if let Ok(css) = CssStream::new(&document).parse() { for (selector, properties) in css.into_iter() { - let object = ScriptObject::new_object(activation); + let object = ScriptObject::new_object(activation.context); for (key, value) in properties.into_iter() { object.set_dynamic_property( diff --git a/core/src/avm2/globals/flash/text/text_field.rs b/core/src/avm2/globals/flash/text/text_field.rs index 58632959b4de..6ffec604029d 100644 --- a/core/src/avm2/globals/flash/text/text_field.rs +++ b/core/src/avm2/globals/flash/text/text_field.rs @@ -1555,7 +1555,7 @@ pub fn get_text_runs<'gc>( textrun_class.construct(activation, &[start.into(), end.into(), tf.into()]) }) .collect::, Error<'gc>>>()?; - Ok(ArrayObject::from_storage(activation, array).into()) + Ok(ArrayObject::from_storage(activation.context, array).into()) } pub fn get_line_index_of_char<'gc>( diff --git a/core/src/avm2/globals/flash/text/text_format.rs b/core/src/avm2/globals/flash/text/text_format.rs index 94a3d02f358e..bc4f114e4f97 100644 --- a/core/src/avm2/globals/flash/text/text_format.rs +++ b/core/src/avm2/globals/flash/text/text_format.rs @@ -601,7 +601,7 @@ pub fn get_tab_stops<'gc>( .as_ref() .map_or(Ok(Value::Null), |tab_stops| { let tab_stop_storage = tab_stops.iter().copied().collect(); - Ok(ArrayObject::from_storage(activation, tab_stop_storage).into()) + Ok(ArrayObject::from_storage(activation.context, tab_stop_storage).into()) }); } diff --git a/core/src/avm2/globals/function.rs b/core/src/avm2/globals/function.rs index 912cde5fe239..0cf4d18386a7 100644 --- a/core/src/avm2/globals/function.rs +++ b/core/src/avm2/globals/function.rs @@ -60,7 +60,7 @@ pub fn _init_function_class<'gc>( activation.avm2().system_classes.as_mut().unwrap().function = function_class_object; let function_proto = create_dummy_function(activation); - function_class_object.link_prototype(activation, function_proto.into()); + function_class_object.link_prototype(activation.context, function_proto.into()); Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/json.rs b/core/src/avm2/globals/json.rs index 0dc12c53e9f7..1ab5b91dd852 100644 --- a/core/src/avm2/globals/json.rs +++ b/core/src/avm2/globals/json.rs @@ -35,7 +35,7 @@ fn deserialize_json_inner<'gc>( } } JsonValue::Object(js_obj) => { - let obj = ScriptObject::new_object(activation); + let obj = ScriptObject::new_object(activation.context); for entry in js_obj.iter() { let key = AvmString::new_utf8(activation.gc(), entry.0); let val = deserialize_json_inner(activation, entry.1.clone(), reviver)?; @@ -72,7 +72,7 @@ fn deserialize_json_inner<'gc>( arr.push(Some(mapped_val)); } let storage = ArrayStorage::from_storage(arr); - let array = ArrayObject::from_storage(activation, storage); + let array = ArrayObject::from_storage(activation.context, storage); array.into() } }) diff --git a/core/src/avm2/globals/object.rs b/core/src/avm2/globals/object.rs index 30e7ca0163ec..1074298b4cdb 100644 --- a/core/src/avm2/globals/object.rs +++ b/core/src/avm2/globals/object.rs @@ -20,7 +20,7 @@ pub fn object_constructor<'gc>( } } - let constructed_object = ScriptObject::new_object(activation); + let constructed_object = ScriptObject::new_object(activation.context); Ok(constructed_object.into()) } diff --git a/core/src/avm2/globals/reg_exp.rs b/core/src/avm2/globals/reg_exp.rs index ac67b2c92c2a..dc92af25fd78 100644 --- a/core/src/avm2/globals/reg_exp.rs +++ b/core/src/avm2/globals/reg_exp.rs @@ -227,7 +227,7 @@ pub fn exec<'gc>( }) .collect(); - let object = ArrayObject::from_storage(activation, storage); + let object = ArrayObject::from_storage(activation.context, storage); for (name, range) in matched.named_groups() { let string = range.map_or(istr!(""), |range| { diff --git a/core/src/avm2/globals/string.rs b/core/src/avm2/globals/string.rs index 3266835d9294..0ba0b1b73a12 100644 --- a/core/src/avm2/globals/string.rs +++ b/core/src/avm2/globals/string.rs @@ -253,7 +253,7 @@ pub fn match_internal<'gc>( regexp.set_last_index(1); } - return Ok(ArrayObject::from_storage(activation, storage).into()); + return Ok(ArrayObject::from_storage(activation.context, storage).into()); } else { let old = regexp.last_index(); regexp.set_last_index(0); @@ -270,7 +270,7 @@ pub fn match_internal<'gc>( regexp.set_last_index(old); - let array = ArrayObject::from_storage(activation, storage); + let array = ArrayObject::from_storage(activation.context, storage); array.set_dynamic_property(istr!("index"), result.start().into(), activation.gc()); array.set_dynamic_property(istr!("input"), this.into(), activation.gc()); @@ -411,7 +411,7 @@ pub fn split<'gc>( }; let Some(limit) = NonZero::new(limit) else { - return Ok(ArrayObject::empty(activation).into()); + return Ok(ArrayObject::empty(activation.context).into()); }; if let Some(mut regexp) = delimiter @@ -419,7 +419,7 @@ pub fn split<'gc>( .as_ref() .and_then(|o| o.as_regexp_mut(activation.gc())) { - return Ok(regexp.split(activation, this, limit).into()); + return Ok(regexp.split(activation.context, this, limit).into()); } let delimiter = delimiter.coerce_to_string(activation)?; @@ -444,7 +444,7 @@ pub fn split<'gc>( .collect() }; - Ok(ArrayObject::from_storage(activation, storage).into()) + Ok(ArrayObject::from_storage(activation.context, storage).into()) } /// Implements `String.substr` diff --git a/core/src/avm2/globals/xml.rs b/core/src/avm2/globals/xml.rs index 5492bab3ca99..0b7a73cc3e80 100644 --- a/core/src/avm2/globals/xml.rs +++ b/core/src/avm2/globals/xml.rs @@ -590,7 +590,7 @@ pub fn in_scope_namespaces<'gc>( // 4. Let a be a new Array created as if by calling the constructor, new Array() // ... // 7. Return a - Ok(ArrayObject::from_storage(activation, ArrayStorage::from_iter(in_scope_ns)).into()) + Ok(ArrayObject::from_storage(activation.context, ArrayStorage::from_iter(in_scope_ns)).into()) } pub fn namespace_declarations<'gc>( @@ -606,7 +606,7 @@ pub fn namespace_declarations<'gc>( // 1. Let a be a new Array created as if by calling the constructor, new Array() // 2. If x.[[Class]] ∈ {"text", "comment", "processing-instruction", "attribute"}, return a if !node.is_element() { - return Ok(ArrayObject::empty(activation).into()); + return Ok(ArrayObject::empty(activation.context).into()); } // 3. Let y = x.[[Parent]] @@ -636,7 +636,11 @@ pub fn namespace_declarations<'gc>( // 9.a. Call the [[Put]] method of a with arguments ToString(i) and ns // 9.b. Let i = i + 1 // 10. Return a - Ok(ArrayObject::from_storage(activation, ArrayStorage::from_iter(declared_namespaces)).into()) + Ok(ArrayObject::from_storage( + activation.context, + ArrayStorage::from_iter(declared_namespaces), + ) + .into()) } pub fn local_name<'gc>( diff --git a/core/src/avm2/metadata.rs b/core/src/avm2/metadata.rs index dce4aefbb79e..cbf0d2e4b404 100644 --- a/core/src/avm2/metadata.rs +++ b/core/src/avm2/metadata.rs @@ -2,6 +2,7 @@ use crate::avm2::array::ArrayStorage; use crate::avm2::object::{ArrayObject, Object, ScriptObject, TObject}; use crate::avm2::script::TranslationUnit; use crate::avm2::{Activation, Error, Value}; +use crate::context::UpdateContext; use crate::string::AvmString; use gc_arena::Collect; @@ -74,28 +75,27 @@ impl<'gc> Metadata<'gc> { } // Converts the Metadata to an Object of the form used in avmplus:describeTypeJSON(). - pub fn as_json_object(&self, activation: &mut Activation<'_, 'gc>) -> Object<'gc> { - let object = ScriptObject::new_object(activation); - object.set_dynamic_property(istr!("name"), self.name.into(), activation.gc()); + pub fn as_json_object(&self, context: &mut UpdateContext<'gc>) -> Object<'gc> { + let name_str = istr!(context, "name"); + let key_str = istr!(context, "key"); + let value_str = istr!(context, "value"); + + let object = ScriptObject::new_object(context); + object.set_dynamic_property(name_str, self.name.into(), context.gc()); let values = self .items .iter() .map(|item| { - let value_object = ScriptObject::new_object(activation); - value_object.set_dynamic_property(istr!("key"), item.key.into(), activation.gc()); - value_object.set_dynamic_property( - istr!("value"), - item.value.into(), - activation.gc(), - ); + let value_object = ScriptObject::new_object(context); + value_object.set_dynamic_property(key_str, item.key.into(), context.gc()); + value_object.set_dynamic_property(value_str, item.value.into(), context.gc()); Some(value_object.into()) }) .collect::>>>(); - let values_array = - ArrayObject::from_storage(activation, ArrayStorage::from_storage(values)); - object.set_dynamic_property(istr!("value"), values_array.into(), activation.gc()); + let values_array = ArrayObject::from_storage(context, ArrayStorage::from_storage(values)); + object.set_dynamic_property(value_str, values_array.into(), context.gc()); object } } diff --git a/core/src/avm2/object/array_object.rs b/core/src/avm2/object/array_object.rs index c82c30aa9a97..5e554190cf4e 100644 --- a/core/src/avm2/object/array_object.rs +++ b/core/src/avm2/object/array_object.rs @@ -7,6 +7,7 @@ use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2::Multiname; +use crate::context::UpdateContext; use crate::string::{AvmString, WStr}; use core::fmt; use gc_arena::barrier::unlock; @@ -61,22 +62,22 @@ pub struct ArrayObjectData<'gc> { impl<'gc> ArrayObject<'gc> { /// Construct an empty array. - pub fn empty(activation: &mut Activation<'_, 'gc>) -> ArrayObject<'gc> { - Self::from_storage(activation, ArrayStorage::new(0)) + pub fn empty(context: &mut UpdateContext<'gc>) -> ArrayObject<'gc> { + Self::from_storage(context, ArrayStorage::new(0)) } /// Build an array object from storage. /// /// This will produce an instance of the system `Array` class. pub fn from_storage( - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, array: ArrayStorage<'gc>, ) -> ArrayObject<'gc> { - let class = activation.avm2().classes().array; + let class = context.avm2.classes().array; let base = ScriptObjectData::new(class); ArrayObject(Gc::new( - activation.gc(), + context.gc(), ArrayObjectData { base, array: RefLock::new(array), diff --git a/core/src/avm2/object/bytearray_object.rs b/core/src/avm2/object/bytearray_object.rs index c04450b3ad0a..5177fbaa6384 100644 --- a/core/src/avm2/object/bytearray_object.rs +++ b/core/src/avm2/object/bytearray_object.rs @@ -6,6 +6,7 @@ use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2::Multiname; use crate::character::Character; +use crate::context::UpdateContext; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; use ruffle_common::utils::HasPrefixField; @@ -81,12 +82,12 @@ pub struct ByteArrayObjectData<'gc> { } impl<'gc> ByteArrayObject<'gc> { - pub fn from_storage(activation: &mut Activation<'_, 'gc>, bytes: ByteArrayStorage) -> Self { - let class = activation.avm2().classes().bytearray; + pub fn from_storage(context: &mut UpdateContext<'gc>, bytes: ByteArrayStorage) -> Self { + let class = context.avm2.classes().bytearray; let base = ScriptObjectData::new(class); ByteArrayObject(Gc::new( - activation.gc(), + context.gc(), ByteArrayObjectData { base, storage: RefCell::new(bytes), diff --git a/core/src/avm2/object/class_object.rs b/core/src/avm2/object/class_object.rs index 376d2d62c439..7e2248e006e3 100644 --- a/core/src/avm2/object/class_object.rs +++ b/core/src/avm2/object/class_object.rs @@ -18,6 +18,7 @@ use crate::avm2::Error; use crate::avm2::Multiname; use crate::avm2::QName; use crate::avm2::TranslationUnit; +use crate::context::UpdateContext; use crate::string::AvmString; use fnv::FnvHashMap; use gc_arena::barrier::unlock; @@ -91,14 +92,14 @@ impl<'gc> ClassObject<'gc> { /// prototypes are weaved together separately. fn allocate_prototype( self, - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, superclass_object: Option>, ) -> Object<'gc> { - let proto = ScriptObject::new_object(activation); + let proto = ScriptObject::new_object(context); if let Some(superclass_object) = superclass_object { let base_proto = superclass_object.prototype(); - proto.set_proto(activation.gc(), base_proto); + proto.set_proto(context.gc(), base_proto); } proto } @@ -138,8 +139,8 @@ impl<'gc> ClassObject<'gc> { ) -> Self { let class_object = Self::from_class_minimal(activation, class, superclass_object); - let class_proto = class_object.allocate_prototype(activation, superclass_object); - class_object.link_prototype(activation, class_proto); + let class_proto = class_object.allocate_prototype(activation.context, superclass_object); + class_object.link_prototype(activation.context, class_proto); let class_class_proto = activation.avm2().classes().class.prototype(); class_object.link_type(activation.gc(), class_class_proto); @@ -259,12 +260,13 @@ impl<'gc> ClassObject<'gc> { } /// Link this class to a prototype. - pub fn link_prototype(self, activation: &mut Activation<'_, 'gc>, class_proto: Object<'gc>) { - let mc = activation.gc(); + pub fn link_prototype(self, context: &mut UpdateContext<'gc>, class_proto: Object<'gc>) { + let mc = context.gc(); + let constructor_str = istr!(context, "constructor"); unlock!(Gc::write(mc, self.0), ClassObjectData, prototype).set(Some(class_proto)); - class_proto.set_dynamic_property(istr!("constructor"), self.into(), mc); - class_proto.set_local_property_is_enumerable(mc, istr!("constructor"), false); + class_proto.set_dynamic_property(constructor_str, self.into(), mc); + class_proto.set_local_property_is_enumerable(mc, constructor_str, false); } /// Manually set the type of this `Class`. @@ -333,7 +335,7 @@ impl<'gc> ClassObject<'gc> { }; let class_init_fn = FunctionObject::from_method( - activation, + activation.context, class_initializer, scope, Some(self_value), @@ -361,7 +363,7 @@ impl<'gc> ClassObject<'gc> { // Provide a callee object if necessary let callee = if method.needs_arguments_object() { Some(FunctionObject::from_method( - activation, + activation.context, method, scope, Some(receiver), @@ -496,7 +498,7 @@ impl<'gc> ClassObject<'gc> { Some(Property::Method { disp_id }) => { let full_method = self.instance_vtable().get_full_method(disp_id).unwrap(); let callee = FunctionObject::from_method( - activation, + activation.context, full_method.method, full_method.scope(), Some(receiver.into()), @@ -614,7 +616,7 @@ impl<'gc> ClassObject<'gc> { // Only create callee if the method needs it let callee = if full_method.method.needs_arguments_object() { Some(FunctionObject::from_method( - activation, + activation.context, full_method.method, full_method.scope(), Some(receiver.into()), diff --git a/core/src/avm2/object/date_object.rs b/core/src/avm2/object/date_object.rs index beced1ebeb4a..d8605d55e5b4 100644 --- a/core/src/avm2/object/date_object.rs +++ b/core/src/avm2/object/date_object.rs @@ -3,6 +3,7 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::value::Hint; use crate::avm2::Error; +use crate::context::UpdateContext; use chrono::{DateTime, Utc}; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; @@ -41,14 +42,14 @@ impl fmt::Debug for DateObject<'_> { impl<'gc> DateObject<'gc> { pub fn from_date_time( - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, date_time: DateTime, ) -> Object<'gc> { - let class = activation.avm2().classes().date; + let class = context.avm2.classes().date; let base = ScriptObjectData::new(class); DateObject(Gc::new( - activation.gc(), + context.gc(), DateObjectData { base, date_time: Cell::new(Some(date_time)), @@ -58,10 +59,10 @@ impl<'gc> DateObject<'gc> { } pub fn for_prototype( - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, date_class: ClassObject<'gc>, ) -> Object<'gc> { - let object_class = activation.avm2().classes().object; + let object_class = context.avm2.classes().object; let base = ScriptObjectData::custom_new( date_class.inner_class_definition(), Some(object_class.prototype()), @@ -69,7 +70,7 @@ impl<'gc> DateObject<'gc> { ); let instance: Object<'gc> = DateObject(Gc::new( - activation.gc(), + context.gc(), DateObjectData { base, date_time: Cell::new(None), diff --git a/core/src/avm2/object/event_object.rs b/core/src/avm2/object/event_object.rs index 6cfdcf1c3b89..c78f2c7d1480 100644 --- a/core/src/avm2/object/event_object.rs +++ b/core/src/avm2/object/event_object.rs @@ -231,7 +231,7 @@ impl<'gc> EventObject<'gc> { activation: &mut Activation<'_, 'gc>, info: impl IntoIterator, ) -> EventObject<'gc> { - let info_object = ScriptObject::new_object(activation); + let info_object = ScriptObject::new_object(activation.context); for (key, value) in info { let key = AvmString::new_utf8(activation.gc(), key); let value = AvmString::new_utf8(activation.gc(), value); diff --git a/core/src/avm2/object/function_object.rs b/core/src/avm2/object/function_object.rs index 4b2573b0386e..70370439cf5a 100644 --- a/core/src/avm2/object/function_object.rs +++ b/core/src/avm2/object/function_object.rs @@ -8,6 +8,7 @@ use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::scope::ScopeChain; use crate::avm2::value::Value; use crate::avm2::Error; +use crate::context::UpdateContext; use crate::string::AvmString; use core::fmt; use gc_arena::barrier::unlock; @@ -57,19 +58,19 @@ impl<'gc> FunctionObject<'gc> { /// It is the caller's responsibility to ensure that the `receiver` passed /// to this method is not Value::Null or Value::Undefined. pub fn from_method( - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, method: Method<'gc>, scope: ScopeChain<'gc>, receiver: Option>, bound_superclass_object: Option>, ) -> FunctionObject<'gc> { - let fn_class = activation.avm2().classes().function; + let fn_class = context.avm2.classes().function; let exec = BoundMethod::from_method(method, scope, receiver, bound_superclass_object); - let es3_proto = ScriptObject::new_object(activation); + let es3_proto = ScriptObject::new_object(context); let function_object = FunctionObject(Gc::new( - activation.gc(), + context.gc(), FunctionObjectData { base: ScriptObjectData::new(fn_class), exec, @@ -77,11 +78,11 @@ impl<'gc> FunctionObject<'gc> { }, )); - let constructor_prop = istr!("constructor"); + let constructor_prop = istr!(context, "constructor"); // Set the constructor property on the prototype to point back to this function - es3_proto.set_dynamic_property(constructor_prop, function_object.into(), activation.gc()); - es3_proto.set_local_property_is_enumerable(activation.gc(), constructor_prop, false); + es3_proto.set_dynamic_property(constructor_prop, function_object.into(), context.gc()); + es3_proto.set_local_property_is_enumerable(context.gc(), constructor_prop, false); function_object } diff --git a/core/src/avm2/object/script_object.rs b/core/src/avm2/object/script_object.rs index af53ccf43e02..42ada1c66cb0 100644 --- a/core/src/avm2/object/script_object.rs +++ b/core/src/avm2/object/script_object.rs @@ -98,14 +98,10 @@ impl<'gc> ScriptObject<'gc> { /// Creates an instance of the Object class, exactly as if `new Object()` /// were called, but without going through any construction or call /// machinery (since it's unnecessary for the Object class). - pub fn new_object(activation: &mut Activation<'_, 'gc>) -> Object<'gc> { - let object_class = activation.avm2().classes().object; + pub fn new_object(context: &mut UpdateContext<'gc>) -> Object<'gc> { + let object_class = context.avm2.classes().object; - ScriptObject(Gc::new( - activation.gc(), - ScriptObjectData::new(object_class), - )) - .into() + ScriptObject(Gc::new(context.gc(), ScriptObjectData::new(object_class))).into() } /// Construct an instance with a possibly-none class and proto chain. @@ -115,7 +111,7 @@ impl<'gc> ScriptObject<'gc> { /// You shouldn't let scripts observe this weirdness. /// /// The proper way to create a normal empty ScriptObject (AS "Object") is to call - /// `ScriptObject::new_object(activation)`. + /// `ScriptObject::new_object(activation.context)`. /// /// Calling `custom_object(mc, object_class, object_class.prototype()` is /// technically also equivalent, but not recommended outside VM initialization code diff --git a/core/src/avm2/object/shared_object_object.rs b/core/src/avm2/object/shared_object_object.rs index 160932c83966..eeffc6ba8061 100644 --- a/core/src/avm2/object/shared_object_object.rs +++ b/core/src/avm2/object/shared_object_object.rs @@ -3,6 +3,7 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ScriptObject, TObject}; +use crate::context::UpdateContext; use gc_arena::barrier::unlock; use gc_arena::{lock::Lock, Collect, Gc, GcWeak}; use ruffle_common::utils::HasPrefixField; @@ -53,11 +54,11 @@ impl<'gc> SharedObjectObject<'gc> { self.0.data.get() } - pub fn reset_data(&self, activation: &mut Activation<'_, 'gc>) { - let empty_data = ScriptObject::new_object(activation); + pub fn reset_data(&self, context: &mut UpdateContext<'gc>) { + let empty_data = ScriptObject::new_object(context); unlock!( - Gc::write(activation.gc(), self.0), + Gc::write(context.gc(), self.0), SharedObjectObjectData, data ) diff --git a/core/src/avm2/regexp.rs b/core/src/avm2/regexp.rs index 1b5901a90b48..25f1e4c14879 100644 --- a/core/src/avm2/regexp.rs +++ b/core/src/avm2/regexp.rs @@ -8,6 +8,7 @@ use crate::avm2::function::FunctionArgs; use crate::avm2::object::FunctionObject; use crate::avm2::Error; use crate::avm2::{ArrayObject, ArrayStorage, Value}; +use crate::context::UpdateContext; use crate::string::WString; use crate::string::{AvmString, Units, WStrToUtf8}; use bitflags::bitflags; @@ -327,7 +328,7 @@ impl<'gc> RegExp<'gc> { pub fn split( &mut self, - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, text: AvmString<'gc>, limit: NonZero, ) -> ArrayObject<'gc> { @@ -339,10 +340,10 @@ impl<'gc> RegExp<'gc> { .chars() .take(limit) .map_while(|c| c.ok()) - .map(|c| AvmString::new(activation.gc(), WString::from_char(c))) + .map(|c| AvmString::new(context.gc(), WString::from_char(c))) .collect(); - return ArrayObject::from_storage(activation, storage); + return ArrayObject::from_storage(context, storage); } let mut storage = ArrayStorage::new(0); @@ -352,17 +353,12 @@ impl<'gc> RegExp<'gc> { if m.range.end == start { break; } - storage.push( - activation - .strings() - .substring(text, start..m.range.start) - .into(), - ); + storage.push(context.strings.substring(text, start..m.range.start).into()); if storage.length() >= limit { break; } for c in m.captures.iter().filter_map(Option::as_ref) { - storage.push(activation.strings().substring(text, c.clone()).into()); + storage.push(context.strings.substring(text, c.clone()).into()); if storage.length() >= limit { break; // Intentional bug to match Flash. // Causes adding parts past limit. @@ -373,10 +369,10 @@ impl<'gc> RegExp<'gc> { } if storage.length() < limit { - storage.push(AvmString::new(activation.gc(), &text[start..]).into()); + storage.push(AvmString::new(context.gc(), &text[start..]).into()); } - ArrayObject::from_storage(activation, storage) + ArrayObject::from_storage(context, storage) } pub fn find_utf16_match( diff --git a/core/src/avm2/value.rs b/core/src/avm2/value.rs index 912849ddc41e..da0350700772 100644 --- a/core/src/avm2/value.rs +++ b/core/src/avm2/value.rs @@ -962,7 +962,7 @@ impl<'gc> Value<'gc> { } let bound_method = vtable - .make_bound_method(activation, *self, disp_id) + .make_bound_method(activation.context, *self, disp_id) .expect("Method should exist"); // TODO: Bound methods should be cached on the Method in a @@ -972,7 +972,7 @@ impl<'gc> Value<'gc> { Ok(bound_method.into()) } else { let bound_method = vtable - .make_bound_method(activation, *self, disp_id) + .make_bound_method(activation.context, *self, disp_id) .expect("Method should exist"); // TODO: Bound methods should be cached on the Method in a @@ -1304,7 +1304,7 @@ impl<'gc> Value<'gc> { ); } - let bound_method = VTable::bind_method(activation, *self, full_method); + let bound_method = VTable::bind_method(activation.context, *self, full_method); // TODO: Bound methods should be cached on the Method in a // WeakKeyHashMap, not on the Object diff --git a/core/src/avm2/vtable.rs b/core/src/avm2/vtable.rs index 4e98b45cd375..176a71290a31 100644 --- a/core/src/avm2/vtable.rs +++ b/core/src/avm2/vtable.rs @@ -516,12 +516,12 @@ impl<'gc> VTable<'gc> { /// to this method is not Value::Null or Value::Undefined. pub fn make_bound_method( self, - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, receiver: Value<'gc>, disp_id: u32, ) -> Option> { self.get_full_method(disp_id) - .map(|method| Self::bind_method(activation, receiver, method)) + .map(|method| Self::bind_method(context, receiver, method)) } /// Bind an instance method to a receiver, allowing it to be used as a value. See `VTable::make_bound_method` @@ -529,12 +529,12 @@ impl<'gc> VTable<'gc> { /// It is the caller's responsibility to ensure that the `receiver` passed /// to this method is not Value::Null or Value::Undefined. pub fn bind_method( - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, receiver: Value<'gc>, method: &ClassBoundMethod<'gc>, ) -> FunctionObject<'gc> { FunctionObject::from_method( - activation, + context, method.method, method.scope(), Some(receiver), diff --git a/core/src/context.rs b/core/src/context.rs index 414e1acc167f..acb673b294a0 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -5,7 +5,7 @@ use crate::avm1::Avm1; use crate::avm1::{Object as Avm1Object, Value as Avm1Value}; use crate::avm2::api_version::ApiVersion; use crate::avm2::Activation as Avm2Activation; -use crate::avm2::{Avm2, LoaderInfoObject, Object as Avm2Object, SoundChannelObject}; +use crate::avm2::{Avm2, LoaderInfoObject, SharedObjectObject, SoundChannelObject}; use crate::avm_rng::AvmRng; use crate::backend::{ audio::{AudioBackend, AudioManager, SoundHandle, SoundInstanceHandle}, @@ -157,7 +157,7 @@ pub struct UpdateContext<'gc> { pub avm1_shared_objects: &'gc mut HashMap>, /// Shared objects cache - pub avm2_shared_objects: &'gc mut HashMap>, + pub avm2_shared_objects: &'gc mut HashMap>, /// Text fields with unbound variable bindings. pub unbound_text_fields: &'gc mut Vec>, diff --git a/core/src/external.rs b/core/src/external.rs index 9c5d9b5f4966..519351ce4d3c 100644 --- a/core/src/external.rs +++ b/core/src/external.rs @@ -235,30 +235,30 @@ impl Value { }) } - pub fn into_avm2<'gc>(self, activation: &mut Avm2Activation<'_, 'gc>) -> Avm2Value<'gc> { + pub fn into_avm2<'gc>(self, context: &mut UpdateContext<'gc>) -> Avm2Value<'gc> { match self { Value::Undefined => Avm2Value::Undefined, Value::Null => Avm2Value::Null, Value::Bool(value) => Avm2Value::Bool(value), Value::Number(value) => Avm2Value::Number(value), - Value::String(value) => Avm2Value::String(AvmString::new_utf8(activation.gc(), value)), + Value::String(value) => Avm2Value::String(AvmString::new_utf8(context.gc(), value)), Value::Object(values) => { - let obj = Avm2ScriptObject::new_object(activation); + let obj = Avm2ScriptObject::new_object(context); for (key, value) in values.into_iter() { - let key = AvmString::new_utf8(activation.gc(), key); - let value = value.into_avm2(activation); - obj.set_dynamic_property(key, value, activation.gc()); + let key = AvmString::new_utf8(context.gc(), key); + let value = value.into_avm2(context); + obj.set_dynamic_property(key, value, context.gc()); } Avm2Value::Object(obj) } Value::List(values) => { let storage = values .iter() - .map(|value| value.to_owned().into_avm2(activation)) + .map(|value| value.to_owned().into_avm2(context)) .collect(); - Avm2ArrayObject::from_storage(activation, storage).into() + Avm2ArrayObject::from_storage(context, storage).into() } } } @@ -315,7 +315,7 @@ impl<'gc> Callback<'gc> { let mut activation = Avm2Activation::from_domain(context, domain); let args: Vec = args .into_iter() - .map(|v| v.into_avm2(&mut activation)) + .map(|v| v.into_avm2(activation.context)) .collect(); let result = method.call( diff --git a/core/src/loader.rs b/core/src/loader.rs index 5302b94dc221..8b8bd227781d 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -1145,7 +1145,7 @@ pub fn load_data_into_url_loader<'gc>( let data_object = if &data_format == b"binary" { let storage = ByteArrayStorage::from_vec(activation.context, body); - let bytearray = ByteArrayObject::from_storage(activation, storage); + let bytearray = ByteArrayObject::from_storage(activation.context, storage); Some(bytearray.into()) } else if &data_format == b"variables" { @@ -1514,8 +1514,6 @@ impl<'gc> MovieLoader<'gc> { None => return Err(Error::Cancelled), }; - let mut activation = Avm2Activation::from_nothing(uc); - let domain = if let MovieLoaderVMData::Avm2 { context, default_domain, @@ -1530,13 +1528,13 @@ impl<'gc> MovieLoader<'gc> { .and_then(|o| o.as_application_domain()) .unwrap_or_else(|| { let parent_domain = default_domain; - Avm2Domain::movie_domain(&mut activation, parent_domain) + Avm2Domain::movie_domain(uc, parent_domain) }); domain } else { // This is necessary when the MovieLoaderData is AVM1, // but loaded an AVM2 SWF (mixed AVM). - activation.context.avm2.stage_domain() + uc.avm2.stage_domain() }; let movie = match sniffed_type { @@ -1549,7 +1547,7 @@ impl<'gc> MovieLoader<'gc> { ContentType::Unknown => Arc::new(SwfMovie::error_movie(url.clone())), }; - match activation.context.load_manager.get_loader_mut(handle) { + match uc.load_manager.get_loader_mut(handle) { Some(Self { movie: old, loader_status, @@ -1564,7 +1562,7 @@ impl<'gc> MovieLoader<'gc> { if let MovieLoaderVMData::Avm2 { loader_info, .. } = vm_data { loader_info.set_content_type(sniffed_type); let fake_movie = Arc::new(SwfMovie::fake_with_compressed_len( - activation.context.root_swf.version(), + uc.root_swf.version(), loader_url.clone(), data.len(), )); @@ -1574,29 +1572,26 @@ impl<'gc> MovieLoader<'gc> { // to their real values) loader_info.set_loader_stream( LoaderStream::NotYetLoaded(fake_movie, Some(clip), false), - activation.gc(), + uc.gc(), ); // Flash always fires an initial 'progress' event with // bytesLoaded=0 and bytesTotal set to the proper value. // This only seems to happen for an AVM2 event handler - MovieLoader::movie_loader_progress(handle, activation.context, 0, length)?; + MovieLoader::movie_loader_progress(handle, uc, 0, length)?; // Update the LoaderStream - we now have a real SWF movie and a real target clip // This is intentionally set *after* the first 'progress' event, to match Flash's behavior // (`LoaderInfo.parameters` is always empty during the first 'progress' event) loader_info.set_loader_stream( LoaderStream::NotYetLoaded(movie.clone(), Some(clip), false), - activation.gc(), + uc.gc(), ); } match sniffed_type { ContentType::Swf => { - let library = activation - .context - .library - .library_for_movie_mut(movie.clone()); + let library = uc.library.library_for_movie_mut(movie.clone()); library.set_avm2_domain(domain); @@ -1610,12 +1605,7 @@ impl<'gc> MovieLoader<'gc> { // Store our downloaded `SwfMovie` into our target `MovieClip`, // and initialize it. - mc.replace_with_movie( - activation.context, - Some(movie.clone()), - true, - loader_info, - ); + mc.replace_with_movie(uc, Some(movie.clone()), true, loader_info); if matches!(vm_data, MovieLoaderVMData::Avm2 { .. }) && !movie.is_action_script_3() @@ -1664,6 +1654,8 @@ impl<'gc> MovieLoader<'gc> { return Ok(()); } ContentType::Gif | ContentType::Jpeg | ContentType::Png => { + let mut activation = Avm2Activation::from_nothing(uc); + let library = activation .context .library @@ -1677,7 +1669,7 @@ impl<'gc> MovieLoader<'gc> { let transparency = true; let bitmapdata = BitmapData::new_with_pixels( - activation.context.gc_context, + activation.gc(), bitmap.width(), bitmap.height(), transparency, @@ -1762,22 +1754,16 @@ impl<'gc> MovieLoader<'gc> { MovieLoaderVMData::Avm1 { .. } => { // If the file is no valid supported file, the MovieClip enters the error state if let Some(mut mc) = clip.as_movie_clip() { - MovieLoader::load_error_swf(&mut mc, activation.context, url.clone()); + MovieLoader::load_error_swf(&mut mc, uc, url.clone()); } // AVM1 fires the event with the current and total length as 0 - MovieLoader::movie_loader_progress(handle, activation.context, 0, 0)?; - MovieLoader::movie_loader_complete( - handle, - activation.context, - None, - status, - redirected, - )?; + MovieLoader::movie_loader_progress(handle, uc, 0, 0)?; + MovieLoader::movie_loader_complete(handle, uc, None, status, redirected)?; } MovieLoaderVMData::Avm2 { loader_info, .. } => { let fake_movie = Arc::new(SwfMovie::fake_with_compressed_len( - activation.context.root_swf.version(), + uc.root_swf.version(), loader_url, data.len(), )); @@ -1786,15 +1772,10 @@ impl<'gc> MovieLoader<'gc> { loader_info.set_loader_stream( LoaderStream::NotYetLoaded(fake_movie, None, false), - activation.gc(), + uc.gc(), ); - MovieLoader::movie_loader_progress( - handle, - activation.context, - length, - length, - )?; + MovieLoader::movie_loader_progress(handle, uc, length, length)?; let mut error = "Error #2124: Loaded file is an unknown type.".to_string(); if !from_bytes { error += &format!(" URL: {url}"); @@ -2285,27 +2266,13 @@ fn select_file_dialog<'gc>( if !dialog_result.is_cancelled() { target_object.init_from_dialog_result(dialog_result); - let activation = Avm2Activation::from_nothing(uc); - let select_event = Avm2EventObject::bare_default_event( - activation.context, - "select", - ); - Avm2::dispatch_event( - activation.context, - select_event, - target_object.into(), - ); + let select_event = + Avm2EventObject::bare_default_event(uc, "select"); + Avm2::dispatch_event(uc, select_event, target_object.into()); } else { - let activation = Avm2Activation::from_nothing(uc); - let cancel_event = Avm2EventObject::bare_default_event( - activation.context, - "cancel", - ); - Avm2::dispatch_event( - activation.context, - cancel_event, - target_object.into(), - ); + let cancel_event = + Avm2EventObject::bare_default_event(uc, "cancel"); + Avm2::dispatch_event(uc, cancel_event, target_object.into()); } } Err(err) => { @@ -2380,14 +2347,8 @@ pub fn save_file_dialog<'gc>( target_object.into(), ); } else { - let activation = Avm2Activation::from_nothing(uc); - let cancel_event = - Avm2EventObject::bare_default_event(activation.context, "cancel"); - Avm2::dispatch_event( - activation.context, - cancel_event, - target_object.into(), - ); + let cancel_event = Avm2EventObject::bare_default_event(uc, "cancel"); + Avm2::dispatch_event(uc, cancel_event, target_object.into()); } } Err(err) => { diff --git a/core/src/pixel_bender.rs b/core/src/pixel_bender.rs index dcbd5eee9094..9bdad96002f8 100644 --- a/core/src/pixel_bender.rs +++ b/core/src/pixel_bender.rs @@ -1,14 +1,11 @@ use either::Either; use ruffle_render::pixel_bender::{PixelBenderType, PixelBenderTypeOpcode}; -use crate::{ - avm2::{ - error::{make_error_2004, Error2004Type}, - Activation, ArrayObject, ArrayStorage, Error, Object, Value, - }, - ecma_conversions::f64_to_wrapping_i32, - string::AvmString, -}; +use crate::avm2::error::{make_error_2004, Error2004Type}; +use crate::avm2::{Activation, ArrayObject, ArrayStorage, Error, Object, Value}; +use crate::context::UpdateContext; +use crate::ecma_conversions::f64_to_wrapping_i32; +use crate::string::AvmString; pub trait PixelBenderTypeExt { fn from_avm2_value<'gc>( @@ -21,7 +18,7 @@ pub trait PixelBenderTypeExt { fn as_avm2_value<'gc>( &self, - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, tint_as_int: bool, ) -> Result, Error<'gc>>; } @@ -151,7 +148,7 @@ impl PixelBenderTypeExt for PixelBenderType { fn as_avm2_value<'gc>( &self, - activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'gc>, tint_as_int: bool, ) -> Result, Error<'gc>> { // Flash appears to use a uint/int if the float has no fractional part @@ -164,7 +161,7 @@ impl PixelBenderTypeExt for PixelBenderType { }; let vals: Vec> = match self { PixelBenderType::TString(string) => { - return Ok(AvmString::new_utf8(activation.gc(), string).into()); + return Ok(AvmString::new_utf8(context.gc(), string).into()); } PixelBenderType::TInt(i) => { if tint_as_int { @@ -192,6 +189,6 @@ impl PixelBenderTypeExt for PixelBenderType { PixelBenderType::TBool(b) => vec![(*b).into()], }; let storage = ArrayStorage::from_args(&vals); - Ok(ArrayObject::from_storage(activation, storage).into()) + Ok(ArrayObject::from_storage(context, storage).into()) } } diff --git a/core/src/player.rs b/core/src/player.rs index 66bffb5f371a..237349d493d8 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -4,8 +4,8 @@ use crate::avm1::Object; use crate::avm1::Value; use crate::avm1::VariableDumper; use crate::avm1::{Activation, ActivationIdentifier}; -use crate::avm2::object::{EventObject as Avm2EventObject, Object as Avm2Object}; -use crate::avm2::{Activation as Avm2Activation, Avm2, CallStack}; +use crate::avm2::object::EventObject as Avm2EventObject; +use crate::avm2::{Activation as Avm2Activation, Avm2, CallStack, SharedObjectObject}; use crate::avm_rng::AvmRng; use crate::backend::ui::FontDefinition; use crate::backend::{ @@ -164,7 +164,7 @@ struct GcRootData<'gc> { avm1_shared_objects: HashMap>, - avm2_shared_objects: HashMap>, + avm2_shared_objects: HashMap>, /// Text fields with unbound variable bindings. unbound_text_fields: Vec>, @@ -223,7 +223,7 @@ impl<'gc> GcRootData<'gc> { &mut Option>, &mut LoadManager<'gc>, &mut HashMap>, - &mut HashMap>, + &mut HashMap>, &mut Vec>, &mut Timers<'gc>, &mut Option>, @@ -2403,12 +2403,14 @@ impl Player { let mut avm2_activation = Avm2Activation::from_nothing(context); for so in avm2_activation.context.avm2_shared_objects.clone().values() { - if let Err(e) = crate::avm2::globals::flash::net::shared_object::flush( + if crate::avm2::globals::flash::net::shared_object::flush_impl( &mut avm2_activation, - Avm2Value::Object(*so), - &[], - ) { - tracing::error!("Error flushing AVM2 shared object `{:?}`: {:?}", so, e); + *so, + 0, + ) + .is_err() + { + tracing::error!("Error flushing AVM2 shared object"); } } }); diff --git a/core/src/prelude.rs b/core/src/prelude.rs index a391737e9892..5c50f64ddcd7 100644 --- a/core/src/prelude.rs +++ b/core/src/prelude.rs @@ -1,4 +1,3 @@ -pub use crate::avm2::Value as Avm2Value; pub use crate::display_object::{ DisplayObject, HitTestOptions, TDisplayObject, TDisplayObjectContainer, }; diff --git a/core/src/socket.rs b/core/src/socket.rs index ffc86f726c33..1cf130f47722 100644 --- a/core/src/socket.rs +++ b/core/src/socket.rs @@ -379,15 +379,12 @@ impl<'gc> Sockets<'gc> { match target { SocketKind::Avm2(target) => { - let activation = Avm2Activation::from_nothing(context); - // Clear the buffers if the connection was closed. target.read_buffer().clear(); target.write_buffer().clear(); - let close_evt = - EventObject::bare_default_event(activation.context, "close"); - Avm2::dispatch_event(activation.context, close_evt, target.into()); + let close_evt = EventObject::bare_default_event(context, "close"); + Avm2::dispatch_event(context, close_evt, target.into()); } SocketKind::Avm1(target) => { let mut activation = Avm1Activation::from_stub( diff --git a/core/src/streams.rs b/core/src/streams.rs index c762e292d6f1..729415e51288 100644 --- a/core/src/streams.rs +++ b/core/src/streams.rs @@ -1399,7 +1399,7 @@ impl<'gc> NetStream<'gc> { .client() .expect("Client should be initialized if script data is being accessed"); - let data_object = variable_data.to_avm2_value(&mut activation); + let data_object = variable_data.to_avm2_value(activation.context); let args = &[data_object]; Avm2Value::from(client_object).call_public_property(