Allow accessing the `Class` off of a constructor or prototype that references it.

This commit is contained in:
David Wendt 2020-08-04 22:50:46 -04:00
parent 22ec96b85e
commit b1bcceaa78
5 changed files with 29 additions and 258 deletions

View File

@ -99,7 +99,9 @@ fn class<'gc>(
let class_trait = Trait::from_class(class_def); let class_trait = Trait::from_class(class_def);
let global_scope = Scope::push_scope(global.get_scope(), global, activation.context.gc_context); 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. /// Add a builtin constant to the global scope.

View File

@ -723,6 +723,9 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// Get a raw pointer value for this object. /// Get a raw pointer value for this object.
fn as_ptr(&self) -> *const ObjectPtr; fn as_ptr(&self) -> *const ObjectPtr;
/// Get this object's `Class`, if it has one.
fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>>;
/// Get this object's `Executable`, if it has one. /// Get this object's `Executable`, if it has one.
fn as_executable(&self) -> Option<Executable<'gc>> { fn as_executable(&self) -> Option<Executable<'gc>> {
None None

View File

@ -179,6 +179,10 @@ macro_rules! impl_avm2_custom_object {
self.0.as_ptr() as *const ObjectPtr self.0.as_ptr() as *const ObjectPtr
} }
fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
self.0.read().base.as_class()
}
fn install_method( fn install_method(
&mut self, &mut self,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,

View File

@ -2,7 +2,6 @@
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::class::Class; use crate::avm2::class::Class;
use crate::avm2::function::Executable;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::{ScriptObjectClass, ScriptObjectData}; use crate::avm2::object::script_object::{ScriptObjectClass, ScriptObjectData};
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
@ -11,6 +10,7 @@ use crate::avm2::scope::Scope;
use crate::avm2::string::AvmString; use crate::avm2::string::AvmString;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::impl_avm2_custom_object;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
/// An Object which represents a primitive value of some other kind. /// 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> { impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
fn get_property_local( impl_avm2_custom_object!(base);
self,
reciever: Object<'gc>,
name: &QName<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
let read = self.0.read();
let rv = read.base.get_property_local(reciever, name, activation)?;
drop(read); fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok(self.0.read().primitive.clone())
rv.resolve(activation)
} }
fn set_property_local( fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
self, Ok(self.0.read().primitive.clone())
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<Value<'gc>, 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<Object<'gc>> {
self.0.read().base.get_method(id)
}
fn get_trait(self, name: &QName<'gc>) -> Result<Vec<Trait<'gc>>, Error> {
self.0.read().base.get_trait(name)
}
fn get_provided_trait(
&self,
name: &QName<'gc>,
known_traits: &mut Vec<Trait<'gc>>,
) -> Result<(), Error> {
self.0.read().base.get_provided_trait(name, known_traits)
}
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
self.0.read().base.get_scope()
}
fn resolve_any(self, local_name: AvmString<'gc>) -> Result<Option<Namespace<'gc>>, Error> {
self.0.read().base.resolve_any(local_name)
}
fn resolve_any_trait(
self,
local_name: AvmString<'gc>,
) -> Result<Option<Namespace<'gc>>, Error> {
self.0.read().base.resolve_any_trait(local_name)
}
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {
self.0.read().base.has_own_property(name)
}
fn has_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
self.0.read().base.has_trait(name)
}
fn provides_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
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<Object<'gc>> {
self.0.read().base.proto()
}
fn get_enumerant_name(&self, index: u32) -> Option<QName<'gc>> {
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<Executable<'gc>> {
None
} }
fn construct( fn construct(
@ -266,88 +99,4 @@ impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
)) ))
.into()) .into())
} }
fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok(self.0.read().primitive.clone())
}
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, 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<Object<'gc>> {
self.0.read().base.interfaces()
}
fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) {
self.0.write(context).base.set_interfaces(iface_list)
}
} }

View File

@ -337,6 +337,10 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) { fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) {
self.0.write(context).set_interfaces(iface_list) self.0.write(context).set_interfaces(iface_list)
} }
fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
self.0.read().as_class()
}
} }
impl<'gc> ScriptObject<'gc> { impl<'gc> ScriptObject<'gc> {
@ -897,4 +901,13 @@ impl<'gc> ScriptObjectData<'gc> {
pub fn set_interfaces(&mut self, iface_list: Vec<Object<'gc>>) { pub fn set_interfaces(&mut self, iface_list: Vec<Object<'gc>>) {
self.interfaces = iface_list; self.interfaces = iface_list;
} }
/// Get the class for this object, if it has one.
pub fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
match self.class {
ScriptObjectClass::ClassConstructor(class, _) => Some(class),
ScriptObjectClass::InstancePrototype(class, _) => Some(class),
ScriptObjectClass::NoClass => None,
}
}
} }