From b1bcceaa78e9a0fe58dde0bbd4fb86d3079f7d49 Mon Sep 17 00:00:00 2001 From: David Wendt Date: Tue, 4 Aug 2020 22:50:46 -0400 Subject: [PATCH] Allow accessing the `Class` off of a constructor or prototype that references it. --- core/src/avm2/globals.rs | 4 +- core/src/avm2/object.rs | 3 + core/src/avm2/object/custom_object.rs | 4 + core/src/avm2/object/primitive_object.rs | 263 +---------------------- core/src/avm2/object/script_object.rs | 13 ++ 5 files changed, 29 insertions(+), 258 deletions(-) diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index 266fefb3d..85ec0d9c8 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -99,7 +99,9 @@ fn class<'gc>( let class_trait = Trait::from_class(class_def); let global_scope = Scope::push_scope(global.get_scope(), global, activation.context.gc_context); - global.install_foreign_trait(activation, class_trait, Some(global_scope), global) + global.install_foreign_trait(activation, class_trait, Some(global_scope), global)?; + + Ok(()) } /// Add a builtin constant to the global scope. diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 02575ab54..a116e05e0 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -723,6 +723,9 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// Get a raw pointer value for this object. fn as_ptr(&self) -> *const ObjectPtr; + /// Get this object's `Class`, if it has one. + fn as_class(&self) -> Option>>; + /// Get this object's `Executable`, if it has one. fn as_executable(&self) -> Option> { None diff --git a/core/src/avm2/object/custom_object.rs b/core/src/avm2/object/custom_object.rs index 7ce9f3546..746e7d3a8 100644 --- a/core/src/avm2/object/custom_object.rs +++ b/core/src/avm2/object/custom_object.rs @@ -179,6 +179,10 @@ macro_rules! impl_avm2_custom_object { self.0.as_ptr() as *const ObjectPtr } + fn as_class(&self) -> Option>> { + self.0.read().base.as_class() + } + fn install_method( &mut self, mc: MutationContext<'gc, '_>, diff --git a/core/src/avm2/object/primitive_object.rs b/core/src/avm2/object/primitive_object.rs index fd93f6b1a..c0c433782 100644 --- a/core/src/avm2/object/primitive_object.rs +++ b/core/src/avm2/object/primitive_object.rs @@ -2,7 +2,6 @@ use crate::avm2::activation::Activation; use crate::avm2::class::Class; -use crate::avm2::function::Executable; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::{ScriptObjectClass, ScriptObjectData}; use crate::avm2::object::{Object, ObjectPtr, TObject}; @@ -11,6 +10,7 @@ use crate::avm2::scope::Scope; use crate::avm2::string::AvmString; use crate::avm2::value::Value; use crate::avm2::Error; +use crate::impl_avm2_custom_object; use gc_arena::{Collect, GcCell, MutationContext}; /// An Object which represents a primitive value of some other kind. @@ -50,181 +50,14 @@ impl<'gc> PrimitiveObject<'gc> { } impl<'gc> TObject<'gc> for PrimitiveObject<'gc> { - fn get_property_local( - self, - reciever: Object<'gc>, - name: &QName<'gc>, - activation: &mut Activation<'_, 'gc, '_>, - ) -> Result, Error> { - let read = self.0.read(); - let rv = read.base.get_property_local(reciever, name, activation)?; + impl_avm2_custom_object!(base); - drop(read); - - rv.resolve(activation) + fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result, Error> { + Ok(self.0.read().primitive.clone()) } - fn set_property_local( - self, - reciever: Object<'gc>, - name: &QName<'gc>, - value: Value<'gc>, - activation: &mut Activation<'_, 'gc, '_>, - ) -> Result<(), Error> { - let mut write = self.0.write(activation.context.gc_context); - let rv = write - .base - .set_property_local(reciever, name, value, activation)?; - - drop(write); - - rv.resolve(activation)?; - - Ok(()) - } - - fn init_property_local( - self, - reciever: Object<'gc>, - name: &QName<'gc>, - value: Value<'gc>, - activation: &mut Activation<'_, 'gc, '_>, - ) -> Result<(), Error> { - let mut write = self.0.write(activation.context.gc_context); - let rv = write - .base - .init_property_local(reciever, name, value, activation)?; - - drop(write); - - rv.resolve(activation)?; - - Ok(()) - } - - fn is_property_overwritable( - self, - gc_context: MutationContext<'gc, '_>, - name: &QName<'gc>, - ) -> bool { - self.0.write(gc_context).base.is_property_overwritable(name) - } - - fn delete_property( - &self, - gc_context: MutationContext<'gc, '_>, - multiname: &QName<'gc>, - ) -> bool { - self.0.write(gc_context).base.delete_property(multiname) - } - - fn get_slot(self, id: u32) -> Result, Error> { - self.0.read().base.get_slot(id) - } - - fn set_slot( - self, - id: u32, - value: Value<'gc>, - mc: MutationContext<'gc, '_>, - ) -> Result<(), Error> { - self.0.write(mc).base.set_slot(id, value, mc) - } - - fn init_slot( - self, - id: u32, - value: Value<'gc>, - mc: MutationContext<'gc, '_>, - ) -> Result<(), Error> { - self.0.write(mc).base.init_slot(id, value, mc) - } - - fn get_method(self, id: u32) -> Option> { - self.0.read().base.get_method(id) - } - - fn get_trait(self, name: &QName<'gc>) -> Result>, Error> { - self.0.read().base.get_trait(name) - } - - fn get_provided_trait( - &self, - name: &QName<'gc>, - known_traits: &mut Vec>, - ) -> Result<(), Error> { - self.0.read().base.get_provided_trait(name, known_traits) - } - - fn get_scope(self) -> Option>> { - self.0.read().base.get_scope() - } - - fn resolve_any(self, local_name: AvmString<'gc>) -> Result>, Error> { - self.0.read().base.resolve_any(local_name) - } - - fn resolve_any_trait( - self, - local_name: AvmString<'gc>, - ) -> Result>, Error> { - self.0.read().base.resolve_any_trait(local_name) - } - - fn has_own_property(self, name: &QName<'gc>) -> Result { - self.0.read().base.has_own_property(name) - } - - fn has_trait(self, name: &QName<'gc>) -> Result { - self.0.read().base.has_trait(name) - } - - fn provides_trait(self, name: &QName<'gc>) -> Result { - self.0.read().base.provides_trait(name) - } - - fn has_instantiated_property(self, name: &QName<'gc>) -> bool { - self.0.read().base.has_instantiated_property(name) - } - - fn has_own_virtual_getter(self, name: &QName<'gc>) -> bool { - self.0.read().base.has_own_virtual_getter(name) - } - - fn has_own_virtual_setter(self, name: &QName<'gc>) -> bool { - self.0.read().base.has_own_virtual_setter(name) - } - - fn proto(&self) -> Option> { - self.0.read().base.proto() - } - - fn get_enumerant_name(&self, index: u32) -> Option> { - self.0.read().base.get_enumerant_name(index) - } - - fn property_is_enumerable(&self, name: &QName<'gc>) -> bool { - self.0.read().base.property_is_enumerable(name) - } - - fn set_local_property_is_enumerable( - &self, - mc: MutationContext<'gc, '_>, - name: &QName<'gc>, - is_enumerable: bool, - ) -> Result<(), Error> { - self.0 - .write(mc) - .base - .set_local_property_is_enumerable(name, is_enumerable) - } - - fn as_ptr(&self) -> *const ObjectPtr { - self.0.as_ptr() as *const ObjectPtr - } - - fn as_executable(&self) -> Option> { - None + fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result, Error> { + Ok(self.0.read().primitive.clone()) } fn construct( @@ -266,88 +99,4 @@ impl<'gc> TObject<'gc> for PrimitiveObject<'gc> { )) .into()) } - - fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result, Error> { - Ok(self.0.read().primitive.clone()) - } - - fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result, Error> { - Ok(self.0.read().primitive.clone()) - } - - fn install_method( - &mut self, - mc: MutationContext<'gc, '_>, - name: QName<'gc>, - disp_id: u32, - function: Object<'gc>, - ) { - self.0 - .write(mc) - .base - .install_method(name, disp_id, function) - } - - fn install_getter( - &mut self, - mc: MutationContext<'gc, '_>, - name: QName<'gc>, - disp_id: u32, - function: Object<'gc>, - ) -> Result<(), Error> { - self.0 - .write(mc) - .base - .install_getter(name, disp_id, function) - } - - fn install_setter( - &mut self, - mc: MutationContext<'gc, '_>, - name: QName<'gc>, - disp_id: u32, - function: Object<'gc>, - ) -> Result<(), Error> { - self.0 - .write(mc) - .base - .install_setter(name, disp_id, function) - } - - fn install_dynamic_property( - &mut self, - mc: MutationContext<'gc, '_>, - name: QName<'gc>, - value: Value<'gc>, - ) -> Result<(), Error> { - self.0.write(mc).base.install_dynamic_property(name, value) - } - - fn install_slot( - &mut self, - mc: MutationContext<'gc, '_>, - name: QName<'gc>, - id: u32, - value: Value<'gc>, - ) { - self.0.write(mc).base.install_slot(name, id, value) - } - - fn install_const( - &mut self, - mc: MutationContext<'gc, '_>, - name: QName<'gc>, - id: u32, - value: Value<'gc>, - ) { - self.0.write(mc).base.install_const(name, id, value) - } - - fn interfaces(&self) -> Vec> { - self.0.read().base.interfaces() - } - - fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec>) { - self.0.write(context).base.set_interfaces(iface_list) - } } diff --git a/core/src/avm2/object/script_object.rs b/core/src/avm2/object/script_object.rs index 7e6b367a9..c799bf559 100644 --- a/core/src/avm2/object/script_object.rs +++ b/core/src/avm2/object/script_object.rs @@ -337,6 +337,10 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> { fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec>) { self.0.write(context).set_interfaces(iface_list) } + + fn as_class(&self) -> Option>> { + self.0.read().as_class() + } } impl<'gc> ScriptObject<'gc> { @@ -897,4 +901,13 @@ impl<'gc> ScriptObjectData<'gc> { pub fn set_interfaces(&mut self, iface_list: Vec>) { self.interfaces = iface_list; } + + /// Get the class for this object, if it has one. + pub fn as_class(&self) -> Option>> { + match self.class { + ScriptObjectClass::ClassConstructor(class, _) => Some(class), + ScriptObjectClass::InstancePrototype(class, _) => Some(class), + ScriptObjectClass::NoClass => None, + } + } }