avm2: Avoid unnecessary Gc allocation for `PropertyClass::Name`

This commit is contained in:
Lord-McSweeney 2024-09-12 23:28:36 -07:00 committed by Lord-McSweeney
parent ed9b250d0a
commit ae956eb10f
2 changed files with 11 additions and 20 deletions

View File

@ -7,7 +7,7 @@ use crate::avm2::TranslationUnit;
use crate::avm2::Value; use crate::avm2::Value;
use crate::context::GcContext; use crate::context::GcContext;
use crate::string::AvmString; use crate::string::AvmString;
use gc_arena::{Collect, Gc, Mutation}; use gc_arena::{Collect, Gc};
use super::class::Class; use super::class::Class;
@ -36,22 +36,17 @@ pub enum Property {
#[derive(Collect, Clone, Copy)] #[derive(Collect, Clone, Copy)]
#[collect(no_drop)] #[collect(no_drop)]
pub enum PropertyClass<'gc> { pub enum PropertyClass<'gc> {
/// The type `*` (Multiname::is_any()). This allows /// The type `*`. This allows `Value::Undefined`, so it needs to
/// `Value::Undefined`, so it needs to be distinguished /// be distinguished from the `Object` class
/// from the `Object` class
Any, Any,
Class(Class<'gc>), Class(Class<'gc>),
Name(Gc<'gc, (Gc<'gc, Multiname<'gc>>, Option<TranslationUnit<'gc>>)>), Name(Gc<'gc, Multiname<'gc>>, Option<TranslationUnit<'gc>>),
} }
impl<'gc> PropertyClass<'gc> { impl<'gc> PropertyClass<'gc> {
pub fn name( pub fn name(name: Option<Gc<'gc, Multiname<'gc>>>, unit: Option<TranslationUnit<'gc>>) -> Self {
mc: &Mutation<'gc>,
name: Option<Gc<'gc, Multiname<'gc>>>,
unit: Option<TranslationUnit<'gc>>,
) -> Self {
if let Some(name) = name { if let Some(name) = name {
PropertyClass::Name(Gc::new(mc, (name, unit))) PropertyClass::Name(name, unit)
} else { } else {
PropertyClass::Any PropertyClass::Any
} }
@ -67,9 +62,7 @@ impl<'gc> PropertyClass<'gc> {
) -> Result<(Value<'gc>, bool), Error<'gc>> { ) -> Result<(Value<'gc>, bool), Error<'gc>> {
let (class, changed) = match self { let (class, changed) = match self {
PropertyClass::Class(class) => (Some(*class), false), PropertyClass::Class(class) => (Some(*class), false),
PropertyClass::Name(gc) => { PropertyClass::Name(name, unit) => {
let (name, unit) = &**gc;
// Note - we look up the class in the domain by name, which allows us to look up private classes. // Note - we look up the class in the domain by name, which allows us to look up private classes.
// This also has the advantage of letting us coerce to a class while the `ClassObject` // This also has the advantage of letting us coerce to a class while the `ClassObject`
// is still being constructed (since the `Class` will already exist in the domain). // is still being constructed (since the `Class` will already exist in the domain).
@ -104,9 +97,7 @@ impl<'gc> PropertyClass<'gc> {
) -> Result<Option<Class<'gc>>, Error<'gc>> { ) -> Result<Option<Class<'gc>>, Error<'gc>> {
match self { match self {
PropertyClass::Class(class) => Ok(Some(*class)), PropertyClass::Class(class) => Ok(Some(*class)),
PropertyClass::Name(gc) => { PropertyClass::Name(name, unit) => {
let (name, unit) = &**gc;
let domain = unit.map_or(activation.avm2().playerglobals_domain, |u| u.domain()); let domain = unit.map_or(activation.avm2().playerglobals_domain, |u| u.domain());
if let Some(class) = domain.get_class(activation.context, name) { if let Some(class) = domain.get_class(activation.context, name) {
*self = PropertyClass::Class(class); *self = PropertyClass::Class(class);
@ -125,7 +116,7 @@ impl<'gc> PropertyClass<'gc> {
pub fn get_name(&self, context: &mut GcContext<'_, 'gc>) -> AvmString<'gc> { pub fn get_name(&self, context: &mut GcContext<'_, 'gc>) -> AvmString<'gc> {
match self { match self {
PropertyClass::Class(class) => class.name().to_qualified_name(context.gc_context), PropertyClass::Class(class) => class.name().to_qualified_name(context.gc_context),
PropertyClass::Name(gc) => gc.0.to_qualified_name_or_star(context), PropertyClass::Name(name, _) => name.to_qualified_name_or_star(context),
PropertyClass::Any => context.interner.get_ascii_char('*'), PropertyClass::Any => context.interner.get_ascii_char('*'),
} }
} }

View File

@ -461,13 +461,13 @@ impl<'gc> VTable<'gc> {
type_name, unit, .. type_name, unit, ..
} => ( } => (
Property::new_slot(new_slot_id), Property::new_slot(new_slot_id),
PropertyClass::name(mc, *type_name, *unit), PropertyClass::name(*type_name, *unit),
), ),
TraitKind::Const { TraitKind::Const {
type_name, unit, .. type_name, unit, ..
} => ( } => (
Property::new_const_slot(new_slot_id), Property::new_const_slot(new_slot_id),
PropertyClass::name(mc, *type_name, *unit), PropertyClass::name(*type_name, *unit),
), ),
TraitKind::Class { class, .. } => ( TraitKind::Class { class, .. } => (
Property::new_const_slot(new_slot_id), Property::new_const_slot(new_slot_id),