diff --git a/core/src/avm2/class.rs b/core/src/avm2/class.rs index a22bd8d73b6f..32629a6fc4a2 100644 --- a/core/src/avm2/class.rs +++ b/core/src/avm2/class.rs @@ -524,7 +524,7 @@ impl<'gc> Class<'gc> { // A 'callable' class doesn't have a signature - let the // method do any needed coercions vec![], - Multiname::any(activation.context.gc_context), + Multiname::any(), true, activation.context.gc_context, ); diff --git a/core/src/avm2/e4x.rs b/core/src/avm2/e4x.rs index 99b970071139..320a744e2af0 100644 --- a/core/src/avm2/e4x.rs +++ b/core/src/avm2/e4x.rs @@ -1706,13 +1706,13 @@ pub fn string_to_multiname<'gc>( ) -> Multiname<'gc> { if let Some(name) = name.strip_prefix(b'@') { if name == b"*" { - return Multiname::any_attribute(activation.gc()); + return Multiname::any_attribute(); } let name = AvmString::new(activation.context.gc_context, name); Multiname::attribute(activation.avm2().public_namespace_base_version, name) } else if &*name == b"*" { - Multiname::any(activation.context.gc_context) + Multiname::any() } else { Multiname::new(activation.avm2().public_namespace_base_version, name) } diff --git a/core/src/avm2/globals/avmplus.rs b/core/src/avm2/globals/avmplus.rs index 930ab2a8a734..8b12a92cf999 100644 --- a/core/src/avm2/globals/avmplus.rs +++ b/core/src/avm2/globals/avmplus.rs @@ -315,7 +315,7 @@ fn describe_internal_body<'gc>( continue; } let prop_class_name = vtable - .slot_class_name(*slot_id, activation.context.gc_context)? + .slot_class_name(*slot_id)? .to_qualified_name_or_star(activation.context.gc_context); let access = match prop { diff --git a/core/src/avm2/globals/int.rs b/core/src/avm2/globals/int.rs index 9ff6025a67cd..bf14c1c1c67a 100644 --- a/core/src/avm2/globals/int.rs +++ b/core/src/avm2/globals/int.rs @@ -227,10 +227,10 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> { "", vec![ParamConfig { param_name: AvmString::new_utf8(activation.context.gc_context, "value"), - param_type_name: Multiname::any(activation.context.gc_context), + param_type_name: Multiname::any(), default_value: Some(Value::Integer(0)), }], - Multiname::any(activation.context.gc_context), + Multiname::any(), true, mc, ), diff --git a/core/src/avm2/globals/namespace.rs b/core/src/avm2/globals/namespace.rs index 9c3645154c93..a2884fb48e72 100644 --- a/core/src/avm2/globals/namespace.rs +++ b/core/src/avm2/globals/namespace.rs @@ -55,7 +55,7 @@ pub fn instance_init<'gc>( let ns = qname .uri() .map(|uri| Namespace::package(uri, api_version, &mut activation.borrow_gc())) - .unwrap_or_else(|| Namespace::any(activation.context.gc_context)); + .unwrap_or_else(Namespace::any); if ns.as_uri().is_empty() { (Some("".into()), ns) } else { diff --git a/core/src/avm2/globals/object.rs b/core/src/avm2/globals/object.rs index 20c7b2ee3bc0..1c9be8b7ddf7 100644 --- a/core/src/avm2/globals/object.rs +++ b/core/src/avm2/globals/object.rs @@ -279,7 +279,7 @@ pub fn create_i_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> { has_own_property, vec![ParamConfig::optional( "name", - Multiname::any(activation.context.gc_context), + Multiname::any(), Value::Undefined, )], Multiname::new(activation.avm2().public_namespace_base_version, "Boolean"), @@ -289,7 +289,7 @@ pub fn create_i_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> { is_prototype_of, vec![ParamConfig::optional( "theClass", - Multiname::any(activation.context.gc_context), + Multiname::any(), Value::Undefined, )], Multiname::new(activation.avm2().public_namespace_base_version, "Boolean"), @@ -299,7 +299,7 @@ pub fn create_i_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> { property_is_enumerable, vec![ParamConfig::optional( "name", - Multiname::any(activation.context.gc_context), + Multiname::any(), Value::Undefined, )], Multiname::new(activation.avm2().public_namespace_base_version, "Boolean"), diff --git a/core/src/avm2/globals/uint.rs b/core/src/avm2/globals/uint.rs index a572351474d6..d3df106dede4 100644 --- a/core/src/avm2/globals/uint.rs +++ b/core/src/avm2/globals/uint.rs @@ -228,10 +228,10 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> { "", vec![ParamConfig { param_name: AvmString::new_utf8(activation.context.gc_context, "value"), - param_type_name: Multiname::any(activation.context.gc_context), + param_type_name: Multiname::any(), default_value: Some(Value::Integer(0)), }], - Multiname::any(activation.context.gc_context), + Multiname::any(), true, mc, ), diff --git a/core/src/avm2/globals/xml.rs b/core/src/avm2/globals/xml.rs index 7c6d9572989f..649d96062ba6 100644 --- a/core/src/avm2/globals/xml.rs +++ b/core/src/avm2/globals/xml.rs @@ -576,7 +576,7 @@ pub fn children<'gc>( activation, children, Some(xml.into()), - Some(Multiname::any(activation.gc())), + Some(Multiname::any()), ) .into()) } @@ -646,7 +646,7 @@ pub fn attributes<'gc>( activation, attributes, Some(xml.into()), - Some(Multiname::any_attribute(activation.gc())), + Some(Multiname::any_attribute()), ) .into()) } @@ -733,7 +733,7 @@ pub fn append_child<'gc>( let child = crate::avm2::e4x::maybe_escape_child(activation, child)?; // 1. Let children be the result of calling the [[Get]] method of x with argument "*" - let name = Multiname::any(activation.gc()); + let name = Multiname::any(); let children = xml.get_property_local(&name, activation)?; // 2. Call the [[Put]] method of children with arguments children.[[Length]] and child @@ -1102,7 +1102,7 @@ pub fn set_children<'gc>( let value = args.get_value(0); // 1. Call the [[Put]] method of x with arguments "*" and value - xml.set_property_local(&Multiname::any(activation.gc()), value, activation)?; + xml.set_property_local(&Multiname::any(), value, activation)?; // 2. Return x Ok(xml.into()) diff --git a/core/src/avm2/globals/xml_list.rs b/core/src/avm2/globals/xml_list.rs index 517fbb55ef46..aa2080347020 100644 --- a/core/src/avm2/globals/xml_list.rs +++ b/core/src/avm2/globals/xml_list.rs @@ -226,7 +226,7 @@ pub fn children<'gc>( activation, sub_children, Some(list.into()), - Some(Multiname::any(activation.gc())), + Some(Multiname::any()), ) .into()) } @@ -320,7 +320,7 @@ pub fn attributes<'gc>( activation, child_attrs, Some(list.into()), - Some(Multiname::any_attribute(activation.gc())), + Some(Multiname::any_attribute()), ) .into()) } diff --git a/core/src/avm2/method.rs b/core/src/avm2/method.rs index 94d534ebdc20..0eaa3e7bb588 100644 --- a/core/src/avm2/method.rs +++ b/core/src/avm2/method.rs @@ -165,7 +165,7 @@ impl<'gc> BytecodeMethod<'gc> { ) -> Result> { let abc = txunit.abc(); let mut signature = Vec::new(); - let mut return_type = Multiname::any(activation.gc()); + let mut return_type = Multiname::any(); if abc.methods.get(abc_method.0 as usize).is_some() { let method = &abc.methods[abc_method.0 as usize]; @@ -429,7 +429,7 @@ impl<'gc> Method<'gc> { signature: Vec::new(), resolved_signature: GcCell::new(mc, None), // FIXME - take in the real return type. This is needed for 'describeType' - return_type: Multiname::any(mc), + return_type: Multiname::any(), is_variadic: true, }, )) diff --git a/core/src/avm2/multiname.rs b/core/src/avm2/multiname.rs index ea86424a3012..541b6b55d9b5 100644 --- a/core/src/avm2/multiname.rs +++ b/core/src/avm2/multiname.rs @@ -328,9 +328,9 @@ impl<'gc> Multiname<'gc> { } /// Indicates the any type (any name in any namespace). - pub fn any(mc: &Mutation<'gc>) -> Self { + pub fn any() -> Self { Self { - ns: NamespaceSet::single(Namespace::any(mc)), + ns: NamespaceSet::single(Namespace::any()), name: None, param: None, flags: Default::default(), @@ -338,9 +338,9 @@ impl<'gc> Multiname<'gc> { } /// Indicates the any attribute type (any attribute in any namespace). - pub fn any_attribute(mc: &Mutation<'gc>) -> Self { + pub fn any_attribute() -> Self { Self { - ns: NamespaceSet::single(Namespace::any(mc)), + ns: NamespaceSet::single(Namespace::any()), name: None, param: None, flags: MultinameFlags::ATTRIBUTE, diff --git a/core/src/avm2/namespace.rs b/core/src/avm2/namespace.rs index 110da5363167..94a0b307de33 100644 --- a/core/src/avm2/namespace.rs +++ b/core/src/avm2/namespace.rs @@ -2,7 +2,7 @@ use crate::avm2::Error; use crate::context::UpdateContext; use crate::string::{AvmAtom, AvmString}; use crate::{avm2::script::TranslationUnit, context::GcContext}; -use gc_arena::{Collect, Gc, Mutation}; +use gc_arena::{Collect, Gc}; use num_traits::FromPrimitive; use ruffle_wstr::WStr; use std::fmt::Debug; @@ -12,7 +12,10 @@ use super::api_version::ApiVersion; #[derive(Clone, Copy, Collect, Debug, PartialEq)] #[collect(no_drop)] -pub struct Namespace<'gc>(Gc<'gc, NamespaceData<'gc>>); +pub struct Namespace<'gc>( + // `None` represents the wildcard namespace `Namespace::any()`. + Option>>, +); /// Represents the name of a namespace. #[allow(clippy::enum_variant_names)] @@ -29,7 +32,6 @@ enum NamespaceData<'gc> { // note: private namespaces are always compared by pointer identity // of the enclosing `Gc`. Private(AvmAtom<'gc>), - Any, } fn strip_version_mark(url: &WStr, is_playerglobals: bool) -> Option<(&WStr, ApiVersion)> { @@ -85,7 +87,7 @@ impl<'gc> Namespace<'gc> { context: &mut UpdateContext<'gc>, ) -> Result> { if namespace_index.0 == 0 { - return Ok(Self::any(context.gc_context)); + return Ok(Self::any()); } let actual_index = namespace_index.0 as usize - 1; @@ -111,10 +113,10 @@ impl<'gc> Namespace<'gc> { // Private namespaces don't get any of the namespace version checks if let AbcNamespace::Private(_) = abc_namespace { - return Ok(Self(Gc::new( + return Ok(Self(Some(Gc::new( context.gc_context, NamespaceData::Private(namespace_name), - ))); + )))); } // FIXME - AvmCore gets this from an external source. I'm not exactly sure @@ -212,11 +214,11 @@ impl<'gc> Namespace<'gc> { AbcNamespace::StaticProtected(_) => NamespaceData::StaticProtected(namespace_name), AbcNamespace::Private(_) => unreachable!(), }; - Ok(Self(Gc::new(context.gc_context, ns))) + Ok(Self(Some(Gc::new(context.gc_context, ns)))) } - pub fn any(mc: &Mutation<'gc>) -> Self { - Self(Gc::new(mc, NamespaceData::Any)) + pub fn any() -> Self { + Self(None) } // TODO(moulins): allow passing an AvmAtom or a non-static `&WStr` directly @@ -228,10 +230,10 @@ impl<'gc> Namespace<'gc> { let atom = context .interner .intern(context.gc_context, package_name.into()); - Self(Gc::new( + Self(Some(Gc::new( context.gc_context, NamespaceData::Namespace(atom, api_version), - )) + ))) } // TODO(moulins): allow passing an AvmAtom or a non-static `&WStr` directly @@ -242,42 +244,41 @@ impl<'gc> Namespace<'gc> { let atom = context .interner .intern(context.gc_context, package_name.into()); - Self(Gc::new( + Self(Some(Gc::new( context.gc_context, NamespaceData::PackageInternal(atom), - )) + ))) } pub fn is_public(&self) -> bool { - matches!(*self.0, NamespaceData::Namespace(name, _) if name.as_wstr().is_empty()) + matches!(self.0.as_deref(), Some(NamespaceData::Namespace(name, _)) if name.as_wstr().is_empty()) } pub fn is_public_ignoring_ns(&self) -> bool { - matches!(*self.0, NamespaceData::Namespace(_, _)) + matches!(self.0.as_deref(), Some(NamespaceData::Namespace(_, _))) } pub fn is_any(&self) -> bool { - matches!(*self.0, NamespaceData::Any) + self.0.is_none() } pub fn is_private(&self) -> bool { - matches!(*self.0, NamespaceData::Private(_)) + matches!(self.0.as_deref(), Some(NamespaceData::Private(_))) } pub fn is_namespace(&self) -> bool { - matches!(*self.0, NamespaceData::Namespace(_, _)) + matches!(self.0.as_deref(), Some(NamespaceData::Namespace(_, _))) } pub fn as_uri_opt(&self) -> Option> { - match *self.0 { - NamespaceData::Namespace(a, _) => Some(a.into()), - NamespaceData::PackageInternal(a) => Some(a.into()), - NamespaceData::Protected(a) => Some(a.into()), - NamespaceData::Explicit(a) => Some(a.into()), - NamespaceData::StaticProtected(a) => Some(a.into()), - NamespaceData::Private(a) => Some(a.into()), - NamespaceData::Any => None, - } + self.0.map(|data| match *data { + NamespaceData::Namespace(a, _) => a.into(), + NamespaceData::PackageInternal(a) => a.into(), + NamespaceData::Protected(a) => a.into(), + NamespaceData::Explicit(a) => a.into(), + NamespaceData::StaticProtected(a) => a.into(), + NamespaceData::Private(a) => a.into(), + }) } /// Get the string value of this namespace, ignoring its type. @@ -294,12 +295,12 @@ impl<'gc> Namespace<'gc> { /// Namespace does not implement `PartialEq`, so that each caller is required /// to explicitly choose either `exact_version_match` or `matches_ns`. pub fn exact_version_match(&self, other: Self) -> bool { - if Gc::as_ptr(self.0) == Gc::as_ptr(other.0) { + if self.0.map(Gc::as_ptr) == other.0.map(Gc::as_ptr) { true } else if self.is_private() || other.is_private() { false } else { - *self.0 == *other.0 + self.0 == other.0 } } @@ -312,10 +313,10 @@ impl<'gc> Namespace<'gc> { if self.exact_version_match(other) { return true; } - match (&*self.0, &*other.0) { + match (self.0.as_deref(), other.0.as_deref()) { ( - NamespaceData::Namespace(name1, version1), - NamespaceData::Namespace(name2, version2), + Some(NamespaceData::Namespace(name1, version1)), + Some(NamespaceData::Namespace(name2, version2)), ) => { let name_matches = name1 == name2; let version_matches = version1 <= version2; @@ -326,8 +327,8 @@ impl<'gc> Namespace<'gc> { } } pub fn matches_api_version(&self, match_version: ApiVersion) -> bool { - match &*self.0 { - NamespaceData::Namespace(_, namespace_version) => namespace_version <= &match_version, + match self.0.as_deref() { + Some(NamespaceData::Namespace(_, version)) => version <= &match_version, _ => true, } } diff --git a/core/src/avm2/object/function_object.rs b/core/src/avm2/object/function_object.rs index b5355a738be6..676eb5748b29 100644 --- a/core/src/avm2/object/function_object.rs +++ b/core/src/avm2/object/function_object.rs @@ -37,7 +37,7 @@ pub fn function_allocator<'gc>( name: "", signature: vec![], resolved_signature: GcCell::new(activation.context.gc_context, None), - return_type: Multiname::any(activation.context.gc_context), + return_type: Multiname::any(), is_variadic: true, }, ); diff --git a/core/src/avm2/object/qname_object.rs b/core/src/avm2/object/qname_object.rs index a797277de104..1d56c21976c8 100644 --- a/core/src/avm2/object/qname_object.rs +++ b/core/src/avm2/object/qname_object.rs @@ -24,7 +24,7 @@ pub fn q_name_allocator<'gc>( activation.context.gc_context, QNameObjectData { base, - name: RefLock::new(Multiname::any(activation.context.gc_context)), + name: RefLock::new(Multiname::any()), }, )) .into()) diff --git a/core/src/avm2/object/xml_list_object.rs b/core/src/avm2/object/xml_list_object.rs index 02abc7e2b68d..8146892ce6b0 100644 --- a/core/src/avm2/object/xml_list_object.rs +++ b/core/src/avm2/object/xml_list_object.rs @@ -991,11 +991,7 @@ impl<'gc> TObject<'gc> for XmlListObject<'gc> { // 2.h.i. Call the [[Put]] method of x[i] with arguments "*" and V self.xml_object_child(index, activation) .unwrap() - .set_property_local( - &Multiname::any(activation.gc()), - value, - activation, - )?; + .set_property_local(&Multiname::any(), value, activation)?; } // NOTE: Not specified in the spec, but avmplus returns here, so we do the same. diff --git a/core/src/avm2/property.rs b/core/src/avm2/property.rs index bc8236efd035..6d2caaf3a629 100644 --- a/core/src/avm2/property.rs +++ b/core/src/avm2/property.rs @@ -127,11 +127,11 @@ impl<'gc> PropertyClass<'gc> { } } - pub fn get_name(&self, mc: &Mutation<'gc>) -> Multiname<'gc> { + pub fn get_name(&self) -> Multiname<'gc> { match self { PropertyClass::Class(class) => class.name().into(), PropertyClass::Name(gc) => gc.0.clone(), - PropertyClass::Any => Multiname::any(mc), + PropertyClass::Any => Multiname::any(), } } } diff --git a/core/src/avm2/script.rs b/core/src/avm2/script.rs index ae4024289911..c10999f0bf96 100644 --- a/core/src/avm2/script.rs +++ b/core/src/avm2/script.rs @@ -393,7 +393,7 @@ impl<'gc> TranslationUnit<'gc> { ) -> Result>, Error<'gc>> { if multiname_index.0 == 0 { let mc = context.gc_context; - Ok(Gc::new(mc, Multiname::any(mc))) + Ok(Gc::new(mc, Multiname::any())) } else { self.pool_multiname_static(multiname_index, context) } diff --git a/core/src/avm2/specification.rs b/core/src/avm2/specification.rs index 8b90c53462f8..3b21a70ef41f 100644 --- a/core/src/avm2/specification.rs +++ b/core/src/avm2/specification.rs @@ -370,7 +370,10 @@ impl Definition { ) { for class_trait in traits { if !class_trait.name().namespace().is_public() - && class_trait.name().namespace() != avm2.as3_namespace + && class_trait + .name() + .namespace() + .exact_version_match(avm2.as3_namespace) { continue; } diff --git a/core/src/avm2/vtable.rs b/core/src/avm2/vtable.rs index e6712395384e..e8ebf5fd35e6 100644 --- a/core/src/avm2/vtable.rs +++ b/core/src/avm2/vtable.rs @@ -112,17 +112,13 @@ impl<'gc> VTable<'gc> { self.0.read().disp_metadata_table.get(disp_id).cloned() } - pub fn slot_class_name( - &self, - slot_id: u32, - mc: &Mutation<'gc>, - ) -> Result, Error<'gc>> { + pub fn slot_class_name(&self, slot_id: u32) -> Result, Error<'gc>> { self.0 .read() .slot_classes .get(slot_id as usize) .ok_or_else(|| "Invalid slot ID".into()) - .map(|c| c.get_name(mc)) + .map(|c| c.get_name()) } pub fn get_trait(self, name: &Multiname<'gc>) -> Option {