diff --git a/core/src/avm2/optimize.rs b/core/src/avm2/optimize.rs index 6a840acf061f0..271eae0a6d1bd 100644 --- a/core/src/avm2/optimize.rs +++ b/core/src/avm2/optimize.rs @@ -12,7 +12,7 @@ use gc_arena::Gc; use std::collections::HashMap; #[allow(clippy::enum_variant_names)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] enum NullState { NotNull, MaybeNull, @@ -101,6 +101,33 @@ impl<'gc> OptValue<'gc> { || self.class == Some(classes.boolean.inner_class_definition()) || self.class == Some(classes.void.inner_class_definition()) } + + pub fn merged_with(self, other: OptValue<'gc>) -> OptValue<'gc> { + let mut created_value = OptValue::any(); + + // TODO: Also check common superclasses. + if self.class == other.class { + created_value.class = self.class; + } + + if self.vtable == other.vtable { + created_value.vtable = self.vtable; + } + + if self.null_state == other.null_state { + created_value.null_state = self.null_state; + } + + if self.contains_valid_integer && other.contains_valid_integer { + created_value.contains_valid_integer = true; + } + + if self.contains_valid_unsigned && other.contains_valid_unsigned { + created_value.contains_valid_unsigned = true; + } + + return created_value; + } } impl<'gc> std::fmt::Debug for OptValue<'gc> { @@ -374,14 +401,8 @@ pub fn optimize<'gc>( } else { for (i, target_local) in local_types.0.iter().enumerate() { let source_local = source_local_types.at(i); - // TODO: Check superclasses, too - if let (Some(source_local_class), Some(target_local_class)) = - (source_local.class, target_local.class) - { - if source_local_class == target_local_class { - merged_types.set(i, OptValue::of_type(source_local_class)); - } - } + + merged_types.set(i, source_local.merged_with(*target_local)); } } diff --git a/core/src/avm2/vtable.rs b/core/src/avm2/vtable.rs index 1de765245b795..bc4563eabef28 100644 --- a/core/src/avm2/vtable.rs +++ b/core/src/avm2/vtable.rs @@ -43,6 +43,12 @@ pub struct VTableData<'gc> { default_slots: Vec>>, } +impl PartialEq for VTable<'_> { + fn eq(&self, other: &Self) -> bool { + GcCell::ptr_eq(self.0, other.0) + } +} + // TODO: it might make more sense to just bind the Method to the VTable (and this its class and scope) directly // would also be nice to somehow remove the Option-ness from `defining_class` and `scope` fields for this // to be more intuitive and cheaper