diff --git a/core/src/avm2/object/class_object.rs b/core/src/avm2/object/class_object.rs index 6730f3e80..d530f04ab 100644 --- a/core/src/avm2/object/class_object.rs +++ b/core/src/avm2/object/class_object.rs @@ -76,6 +76,39 @@ pub struct ClassObjectData<'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>, + ) -> Result, 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. /// /// This function returns the class constructor object, which should be @@ -91,22 +124,7 @@ impl<'gc> ClassObject<'gc> { superclass_object: Option>, ) -> Result { let class_object = Self::from_class_partial(activation, class, 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) - }; + let class_proto = class_object.allocate_prototype(activation, superclass_object)?; 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 superclass_object = self.0.read().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)?; - (instance_allocator.0)(superclass_object, base_proto, activation)? - } else { - ScriptObject::bare_object(activation.context.gc_context) - }; + let class_proto = self.allocate_prototype(activation, superclass_object)?; let class_class = activation.avm2().classes().class; let class_class_proto = activation.avm2().prototypes().class; diff --git a/tests/tests/swfs/avm2/instanceof/Test.as b/tests/tests/swfs/avm2/instanceof/Test.as index cc0881d7a..6af6057a9 100644 --- a/tests/tests/swfs/avm2/instanceof/Test.as +++ b/tests/tests/swfs/avm2/instanceof/Test.as @@ -97,4 +97,40 @@ trace("//y instanceof ITest3"); trace(y instanceof ITest3); trace("//y instanceof Test4"); -trace(y instanceof Test4); \ No newline at end of file +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); \ No newline at end of file diff --git a/tests/tests/swfs/avm2/instanceof/output.txt b/tests/tests/swfs/avm2/instanceof/output.txt index ce3c28823..8fef1006f 100644 --- a/tests/tests/swfs/avm2/instanceof/output.txt +++ b/tests/tests/swfs/avm2/instanceof/output.txt @@ -22,3 +22,27 @@ true false //y instanceof Test4 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 diff --git a/tests/tests/swfs/avm2/instanceof/test.swf b/tests/tests/swfs/avm2/instanceof/test.swf index c3074ac4c..4f5bd6029 100644 Binary files a/tests/tests/swfs/avm2/instanceof/test.swf and b/tests/tests/swfs/avm2/instanceof/test.swf differ diff --git a/tests/tests/swfs/avm2/istypelate/Test.as b/tests/tests/swfs/avm2/istypelate/Test.as index 57c8a5f45..e5018d193 100644 --- a/tests/tests/swfs/avm2/istypelate/Test.as +++ b/tests/tests/swfs/avm2/istypelate/Test.as @@ -97,4 +97,40 @@ trace("//y is ITest3"); trace(y is ITest3); trace("//y is Test4"); -trace(y is Test4); \ No newline at end of file +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); \ No newline at end of file diff --git a/tests/tests/swfs/avm2/istypelate/output.txt b/tests/tests/swfs/avm2/istypelate/output.txt index dc5e09a53..f0907bb68 100644 --- a/tests/tests/swfs/avm2/istypelate/output.txt +++ b/tests/tests/swfs/avm2/istypelate/output.txt @@ -22,3 +22,27 @@ true true //y is Test4 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 diff --git a/tests/tests/swfs/avm2/istypelate/test.swf b/tests/tests/swfs/avm2/istypelate/test.swf index 2e62a627a..646825918 100644 Binary files a/tests/tests/swfs/avm2/istypelate/test.swf and b/tests/tests/swfs/avm2/istypelate/test.swf differ