avm2: All prototypes are instances of `Object`, not their own class.
This commit is contained in:
parent
c1850d0d54
commit
469f8cb9db
|
@ -76,6 +76,39 @@ pub struct ClassObjectData<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> ClassObject<'gc> {
|
impl<'gc> ClassObject<'gc> {
|
||||||
|
/// Allocate the prototype for this class.
|
||||||
|
///
|
||||||
|
/// This function is not used during the initialization of "early classes",
|
||||||
|
/// i.e. `Object`, `Function`, and `Class`. Those classes and their
|
||||||
|
/// prototypes are weaved together separately.
|
||||||
|
///
|
||||||
|
/// The returned prototype will be an instance of `Object` (and thus not
|
||||||
|
/// have this class's instance traits), but will be allocated by this
|
||||||
|
/// class's instance allocator.
|
||||||
|
fn allocate_prototype(
|
||||||
|
self,
|
||||||
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
superclass_object: Option<ClassObject<'gc>>,
|
||||||
|
) -> Result<Object<'gc>, Error> {
|
||||||
|
let instance_allocator = self.0.read().instance_allocator.clone();
|
||||||
|
|
||||||
|
if let Some(superclass_object) = superclass_object {
|
||||||
|
let base_proto = superclass_object
|
||||||
|
.get_property(
|
||||||
|
superclass_object.into(),
|
||||||
|
&QName::new(Namespace::public(), "prototype").into(),
|
||||||
|
activation,
|
||||||
|
)?
|
||||||
|
.coerce_to_object(activation)?;
|
||||||
|
|
||||||
|
//NOTE: If we do not use `instance_allocator` here, then Vector
|
||||||
|
//enumeration will break.
|
||||||
|
(instance_allocator.0)(activation.avm2().classes().object, base_proto, activation)
|
||||||
|
} else {
|
||||||
|
Ok(ScriptObject::bare_object(activation.context.gc_context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a class.
|
/// Construct a class.
|
||||||
///
|
///
|
||||||
/// This function returns the class constructor object, which should be
|
/// This function returns the class constructor object, which should be
|
||||||
|
@ -91,22 +124,7 @@ impl<'gc> ClassObject<'gc> {
|
||||||
superclass_object: Option<ClassObject<'gc>>,
|
superclass_object: Option<ClassObject<'gc>>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let class_object = Self::from_class_partial(activation, class, superclass_object)?;
|
let class_object = Self::from_class_partial(activation, class, superclass_object)?;
|
||||||
|
let class_proto = class_object.allocate_prototype(activation, superclass_object)?;
|
||||||
//TODO: Class prototypes are *not* instances of their class and should
|
|
||||||
//not be allocated by the class allocator, but instead should be
|
|
||||||
//regular objects
|
|
||||||
let class_proto = if let Some(superclass_object) = superclass_object {
|
|
||||||
let base_proto = superclass_object
|
|
||||||
.get_property(
|
|
||||||
superclass_object.into(),
|
|
||||||
&QName::new(Namespace::public(), "prototype").into(),
|
|
||||||
activation,
|
|
||||||
)?
|
|
||||||
.coerce_to_object(activation)?;
|
|
||||||
ScriptObject::object(activation.context.gc_context, base_proto)
|
|
||||||
} else {
|
|
||||||
ScriptObject::bare_object(activation.context.gc_context)
|
|
||||||
};
|
|
||||||
|
|
||||||
class_object.link_prototype(activation, class_proto)?;
|
class_object.link_prototype(activation, class_proto)?;
|
||||||
|
|
||||||
|
@ -873,21 +891,7 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
|
||||||
let instance_allocator = self.0.read().instance_allocator.clone();
|
let instance_allocator = self.0.read().instance_allocator.clone();
|
||||||
let superclass_object = self.0.read().superclass_object;
|
let superclass_object = self.0.read().superclass_object;
|
||||||
|
|
||||||
//TODO: Class prototypes are *not* instances of their class and should
|
let class_proto = self.allocate_prototype(activation, superclass_object)?;
|
||||||
//not be allocated by the class allocator, but instead should be
|
|
||||||
//regular objects
|
|
||||||
let class_proto = if let Some(superclass_object) = superclass_object {
|
|
||||||
let base_proto = superclass_object
|
|
||||||
.get_property(
|
|
||||||
superclass_object.into(),
|
|
||||||
&QName::new(Namespace::public(), "prototype").into(),
|
|
||||||
activation,
|
|
||||||
)?
|
|
||||||
.coerce_to_object(activation)?;
|
|
||||||
(instance_allocator.0)(superclass_object, base_proto, activation)?
|
|
||||||
} else {
|
|
||||||
ScriptObject::bare_object(activation.context.gc_context)
|
|
||||||
};
|
|
||||||
|
|
||||||
let class_class = activation.avm2().classes().class;
|
let class_class = activation.avm2().classes().class;
|
||||||
let class_class_proto = activation.avm2().prototypes().class;
|
let class_class_proto = activation.avm2().prototypes().class;
|
||||||
|
|
|
@ -98,3 +98,39 @@ trace(y instanceof ITest3);
|
||||||
|
|
||||||
trace("//y instanceof Test4");
|
trace("//y instanceof Test4");
|
||||||
trace(y instanceof Test4);
|
trace(y instanceof Test4);
|
||||||
|
|
||||||
|
trace("//Test3.prototype instanceof Object");
|
||||||
|
trace(Test3.prototype instanceof Object);
|
||||||
|
|
||||||
|
trace("//Test3.prototype instanceof Test2");
|
||||||
|
trace(Test3.prototype instanceof Test2);
|
||||||
|
|
||||||
|
trace("//Test3.prototype instanceof ITest2");
|
||||||
|
trace(Test3.prototype instanceof ITest2);
|
||||||
|
|
||||||
|
trace("//Test3.prototype instanceof Test3");
|
||||||
|
trace(Test3.prototype instanceof Test3);
|
||||||
|
|
||||||
|
trace("//Test3.prototype instanceof ITest3");
|
||||||
|
trace(Test3.prototype instanceof ITest3);
|
||||||
|
|
||||||
|
trace("//Test3.prototype instanceof Test4");
|
||||||
|
trace(Test3.prototype instanceof Test4);
|
||||||
|
|
||||||
|
trace("//Test4.prototype instanceof Object");
|
||||||
|
trace(Test4.prototype instanceof Object);
|
||||||
|
|
||||||
|
trace("//Test4.prototype instanceof Test2");
|
||||||
|
trace(Test4.prototype instanceof Test2);
|
||||||
|
|
||||||
|
trace("//Test4.prototype instanceof ITest2");
|
||||||
|
trace(Test4.prototype instanceof ITest2);
|
||||||
|
|
||||||
|
trace("//Test4.prototype instanceof Test3");
|
||||||
|
trace(Test4.prototype instanceof Test3);
|
||||||
|
|
||||||
|
trace("//Test4.prototype instanceof ITest3");
|
||||||
|
trace(Test4.prototype instanceof ITest3);
|
||||||
|
|
||||||
|
trace("//Test4.prototype instanceof Test4");
|
||||||
|
trace(Test4.prototype instanceof Test4);
|
|
@ -22,3 +22,27 @@ true
|
||||||
false
|
false
|
||||||
//y instanceof Test4
|
//y instanceof Test4
|
||||||
true
|
true
|
||||||
|
//Test3.prototype instanceof Object
|
||||||
|
true
|
||||||
|
//Test3.prototype instanceof Test2
|
||||||
|
true
|
||||||
|
//Test3.prototype instanceof ITest2
|
||||||
|
false
|
||||||
|
//Test3.prototype instanceof Test3
|
||||||
|
false
|
||||||
|
//Test3.prototype instanceof ITest3
|
||||||
|
false
|
||||||
|
//Test3.prototype instanceof Test4
|
||||||
|
false
|
||||||
|
//Test4.prototype instanceof Object
|
||||||
|
true
|
||||||
|
//Test4.prototype instanceof Test2
|
||||||
|
true
|
||||||
|
//Test4.prototype instanceof ITest2
|
||||||
|
false
|
||||||
|
//Test4.prototype instanceof Test3
|
||||||
|
true
|
||||||
|
//Test4.prototype instanceof ITest3
|
||||||
|
false
|
||||||
|
//Test4.prototype instanceof Test4
|
||||||
|
false
|
||||||
|
|
Binary file not shown.
|
@ -98,3 +98,39 @@ trace(y is ITest3);
|
||||||
|
|
||||||
trace("//y is Test4");
|
trace("//y is Test4");
|
||||||
trace(y is Test4);
|
trace(y is Test4);
|
||||||
|
|
||||||
|
trace("//Test3.prototype is Object");
|
||||||
|
trace(Test3.prototype is Object);
|
||||||
|
|
||||||
|
trace("//Test3.prototype is Test2");
|
||||||
|
trace(Test3.prototype is Test2);
|
||||||
|
|
||||||
|
trace("//Test3.prototype is ITest2");
|
||||||
|
trace(Test3.prototype is ITest2);
|
||||||
|
|
||||||
|
trace("//Test3.prototype is Test3");
|
||||||
|
trace(Test3.prototype is Test3);
|
||||||
|
|
||||||
|
trace("//Test3.prototype is ITest3");
|
||||||
|
trace(Test3.prototype is ITest3);
|
||||||
|
|
||||||
|
trace("//Test3.prototype is Test4");
|
||||||
|
trace(Test3.prototype is Test4);
|
||||||
|
|
||||||
|
trace("//Test4.prototype is Object");
|
||||||
|
trace(Test4.prototype is Object);
|
||||||
|
|
||||||
|
trace("//Test4.prototype is Test2");
|
||||||
|
trace(Test4.prototype is Test2);
|
||||||
|
|
||||||
|
trace("//Test4.prototype is ITest2");
|
||||||
|
trace(Test4.prototype is ITest2);
|
||||||
|
|
||||||
|
trace("//Test4.prototype is Test3");
|
||||||
|
trace(Test4.prototype is Test3);
|
||||||
|
|
||||||
|
trace("//Test4.prototype is ITest3");
|
||||||
|
trace(Test4.prototype is ITest3);
|
||||||
|
|
||||||
|
trace("//Test4.prototype is Test4");
|
||||||
|
trace(Test4.prototype is Test4);
|
|
@ -22,3 +22,27 @@ true
|
||||||
true
|
true
|
||||||
//y is Test4
|
//y is Test4
|
||||||
true
|
true
|
||||||
|
//Test3.prototype is Object
|
||||||
|
true
|
||||||
|
//Test3.prototype is Test2
|
||||||
|
false
|
||||||
|
//Test3.prototype is ITest2
|
||||||
|
false
|
||||||
|
//Test3.prototype is Test3
|
||||||
|
false
|
||||||
|
//Test3.prototype is ITest3
|
||||||
|
false
|
||||||
|
//Test3.prototype is Test4
|
||||||
|
false
|
||||||
|
//Test4.prototype is Object
|
||||||
|
true
|
||||||
|
//Test4.prototype is Test2
|
||||||
|
false
|
||||||
|
//Test4.prototype is ITest2
|
||||||
|
false
|
||||||
|
//Test4.prototype is Test3
|
||||||
|
false
|
||||||
|
//Test4.prototype is ITest3
|
||||||
|
false
|
||||||
|
//Test4.prototype is Test4
|
||||||
|
false
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue