From 0679fd1a9eff479282a4471b17df19d0a0da7274 Mon Sep 17 00:00:00 2001 From: Adrian Wielgosik Date: Sat, 18 Sep 2021 11:22:54 +0200 Subject: [PATCH] amv2: Move superclass_object() to ClassObject --- core/src/avm2/activation.rs | 5 +++++ core/src/avm2/globals/flash/utils.rs | 20 ++++++++++++++++++-- core/src/avm2/object.rs | 21 ++++++++++++--------- core/src/avm2/object/class_object.rs | 12 ++++++++---- core/src/avm2/object/custom_object.rs | 4 ++++ core/src/avm2/object/script_object.rs | 11 +++++++++++ core/src/avm2/object/stage_object.rs | 4 ++++ 7 files changed, 62 insertions(+), 15 deletions(-) diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index c82c3d455..2d60fd1c4 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -502,6 +502,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { ) -> Result, Error> { let superclass_object: Result, Error> = self .subclass_object() + .and_then(|c| c.as_class_object_really()) .and_then(|c| c.superclass_object()) .ok_or_else(|| { "Attempted to call super constructor without a superclass." @@ -1205,6 +1206,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let superclass_object: Result, Error> = self .subclass_object() + .and_then(|c| c.as_class_object_really()) .and_then(|bc| bc.superclass_object()) .ok_or_else(|| { "Attempted to call super method without a superclass." @@ -1237,6 +1239,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let superclass_object: Result, Error> = self .subclass_object() + .and_then(|c| c.as_class_object_really()) .and_then(|bc| bc.superclass_object()) .ok_or_else(|| { "Attempted to call super method without a superclass." @@ -1378,6 +1381,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let superclass_object: Result, Error> = self .subclass_object() + .and_then(|c| c.as_class_object_really()) .and_then(|bc| bc.superclass_object()) .ok_or_else(|| { "Attempted to call super method without a superclass." @@ -1409,6 +1413,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let superclass_object: Result, Error> = self .subclass_object() + .and_then(|c| c.as_class_object_really()) .and_then(|bc| bc.superclass_object()) .ok_or_else(|| { "Attempted to call super method without a superclass." diff --git a/core/src/avm2/globals/flash/utils.rs b/core/src/avm2/globals/flash/utils.rs index b2167fff6..7715d84d6 100644 --- a/core/src/avm2/globals/flash/utils.rs +++ b/core/src/avm2/globals/flash/utils.rs @@ -29,9 +29,17 @@ pub fn get_qualified_class_name<'gc>( .unwrap_or(&Value::Undefined) .coerce_to_object(activation)?; + let class = match obj.as_class_object_really() { + Some(class) => class, + None => match obj.instance_of() { + Some(cls) => cls.as_class_object_really().unwrap(), + None => return Ok(Value::Null), + } + }; + Ok(AvmString::new( activation.context.gc_context, - obj.as_class() + class.as_class() .ok_or("This object does not have a class")? .read() .name() @@ -51,7 +59,15 @@ pub fn get_qualified_super_class_name<'gc>( .unwrap_or(&Value::Undefined) .coerce_to_object(activation)?; - if let Some(super_class) = obj.superclass_object() { + let class = match obj.as_class_object_really() { + Some(class) => class, + None => match obj.instance_of() { + Some(cls) => cls.as_class_object_really().unwrap(), + None => return Ok(Value::Null), + } + }; + + if let Some(super_class) = class.superclass_object() { Ok(AvmString::new( activation.context.gc_context, super_class diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 7df44f110..a89f5e1f3 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -138,7 +138,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy return Ok(Some(self.into())); } - if let Some(base) = self.superclass_object() { + if let Some(base) = self.as_class_object_really().and_then(|cls| cls.superclass_object()) { return base.find_class_for_trait(name); } @@ -427,8 +427,10 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy activation: &mut Activation<'_, 'gc, '_>, from_class_object: Object<'gc>, ) -> Result<(), Error> { - if let Some(superclass_object) = from_class_object.superclass_object() { - self.install_instance_traits(activation, superclass_object)?; + if let Some(from_class_object) = from_class_object.as_class_object_really() { + if let Some(superclass_object) = from_class_object.superclass_object() { + self.install_instance_traits(activation, superclass_object)?; + } } if let Some(class) = from_class_object.as_class() { @@ -1063,7 +1065,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy } } - my_class = class.superclass_object() + if let Some(class) = class.as_class_object_really() { + my_class = class.superclass_object() + } else { + my_class = None; + } } Ok(false) @@ -1078,6 +1084,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// Get this object's class object, if it has one. fn as_class_object(&self) -> Option>; + fn instance_of(&self) -> Option>; + fn as_class_object_really(&self) -> Option> { None } @@ -1096,11 +1104,6 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// class at allocation time, such as during early runtime setup. fn set_class_object(self, mc: MutationContext<'gc, '_>, class_object: Object<'gc>); - /// Get the superclass object of this object. - fn superclass_object(self) -> Option> { - None - } - /// Get this class's instance allocator. fn instance_allocator(self) -> Option { None diff --git a/core/src/avm2/object/class_object.rs b/core/src/avm2/object/class_object.rs index dd9c103e3..e02a968d4 100644 --- a/core/src/avm2/object/class_object.rs +++ b/core/src/avm2/object/class_object.rs @@ -339,6 +339,10 @@ impl<'gc> ClassObject<'gc> { pub fn interfaces(self) -> Vec> { self.0.read().interfaces.clone() } + + pub fn superclass_object(self) -> Option> { + self.0.read().superclass_object + } } impl<'gc> TObject<'gc> for ClassObject<'gc> { @@ -443,10 +447,6 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> { .into()) } - fn superclass_object(self) -> Option> { - self.0.read().superclass_object - } - fn instance_allocator(self) -> Option { Some(self.0.read().instance_allocator.0) } @@ -490,6 +490,10 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> { Some(*self) } + fn instance_of(&self) -> Option> { + self.0.read().base.instance_of() + } + fn as_class_params(&self) -> Option>> { self.0.read().params } diff --git a/core/src/avm2/object/custom_object.rs b/core/src/avm2/object/custom_object.rs index 8650a0b4b..fb5eb1123 100644 --- a/core/src/avm2/object/custom_object.rs +++ b/core/src/avm2/object/custom_object.rs @@ -118,6 +118,10 @@ macro_rules! impl_avm2_custom_object_instance { self.0.read().$field.as_class_object() } + fn instance_of(&self) -> Option> { + self.0.read().$field.instance_of() + } + fn set_class_object(self, mc: MutationContext<'gc, '_>, class_object: Object<'gc>) { self.0.write(mc).$field.set_class_object(class_object); } diff --git a/core/src/avm2/object/script_object.rs b/core/src/avm2/object/script_object.rs index f703e640e..a65d63044 100644 --- a/core/src/avm2/object/script_object.rs +++ b/core/src/avm2/object/script_object.rs @@ -311,6 +311,10 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> { fn set_class_object(self, mc: MutationContext<'gc, '_>, class_object: Object<'gc>) { self.0.write(mc).set_class_object(class_object); } + + fn instance_of(&self) -> Option> { + self.0.read().instance_of() + } } impl<'gc> ScriptObject<'gc> { @@ -527,6 +531,7 @@ impl<'gc> ScriptObjectData<'gc> { return Ok(true); } + let class = class.as_class_object_really().unwrap(); cur_class = class.superclass_object(); } @@ -590,6 +595,7 @@ impl<'gc> ScriptObjectData<'gc> { return Ok(Some(ns)); } + let class = class.as_class_object_really().unwrap(); cur_class = class.superclass_object(); } @@ -835,6 +841,11 @@ impl<'gc> ScriptObjectData<'gc> { self.instance_of } + /// Get the class object for this object, if it has one. + pub fn instance_of(&self) -> Option> { + self.instance_of + } + /// Associate the object with a particular class object. /// /// This turns the object into an instance of that class. It should only be diff --git a/core/src/avm2/object/stage_object.rs b/core/src/avm2/object/stage_object.rs index 95760ea5d..f13f46bb8 100644 --- a/core/src/avm2/object/stage_object.rs +++ b/core/src/avm2/object/stage_object.rs @@ -298,6 +298,10 @@ impl<'gc> TObject<'gc> for StageObject<'gc> { self.0.write(mc).base.set_class_object(class_object); } + fn instance_of(&self) -> Option> { + self.0.read().base.instance_of() + } + fn as_display_object(&self) -> Option> { self.0.read().display_object }