From bac18c1a845e6b9b21a8fe511df4ae14322d937a Mon Sep 17 00:00:00 2001 From: Lord-McSweeney Date: Thu, 20 Jun 2024 09:52:10 -0700 Subject: [PATCH] avm2: Simplify `ClassObject::link_type` --- core/src/avm2/globals.rs | 32 ++++++++++++++++------------ core/src/avm2/object/class_object.rs | 15 +++++++------ 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index 039989aeb..b62697d77 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -493,45 +493,49 @@ pub fn load_player_globals<'gc>( // // Hence, this ridiculously complicated dance of classdef, type allocation, // and partial initialization. + + // Object extends nothing let object_i_class = object::create_i_class(activation); + + // Class extends Object let class_i_class = class::create_i_class(activation, object_i_class); + // Object$ extends Class let object_c_class = object::create_c_class(activation, class_i_class); object_i_class.set_c_class(mc, object_c_class); object_c_class.set_i_class(mc, object_i_class); + // Class$ extends Class let class_c_class = class::create_c_class(activation, class_i_class); class_i_class.set_c_class(mc, class_c_class); class_c_class.set_i_class(mc, class_i_class); - let object_class = ClassObject::from_class_partial(activation, object_i_class, None)?; - let object_proto = ScriptObject::custom_object(mc, Some(object_class), None); domain.export_class(object_i_class.name(), object_i_class, mc); - - let class_class = - ClassObject::from_class_partial(activation, class_i_class, Some(object_class))?; - let class_proto = ScriptObject::custom_object(mc, Some(object_class), Some(object_proto)); domain.export_class(class_i_class.name(), class_i_class, mc); // Function is more of a "normal" class than the other two, so we can create it normally. let fn_classdef = function::create_class(activation, object_i_class, class_i_class); - let fn_class = ClassObject::from_class_partial(activation, fn_classdef, Some(object_class))?; - let fn_proto = ScriptObject::custom_object(mc, Some(fn_class), Some(object_proto)); domain.export_class(fn_classdef.name(), fn_classdef, mc); - let fn_c_class = fn_classdef - .c_class() - .expect("function::create_class returns an i_class"); + let object_class = ClassObject::from_class_partial(activation, object_i_class, None)?; + let object_proto = ScriptObject::custom_object(mc, Some(object_class), None); + + let class_class = + ClassObject::from_class_partial(activation, class_i_class, Some(object_class))?; + let class_proto = ScriptObject::custom_object(mc, Some(object_class), Some(object_proto)); + + let fn_class = ClassObject::from_class_partial(activation, fn_classdef, Some(object_class))?; + let fn_proto = ScriptObject::custom_object(mc, Some(fn_class), Some(object_proto)); // Now to weave the Gordian knot... object_class.link_prototype(activation, object_proto)?; - object_class.link_type(mc, class_proto, object_c_class); + object_class.link_type(mc, class_proto); fn_class.link_prototype(activation, fn_proto)?; - fn_class.link_type(mc, class_proto, fn_c_class); + fn_class.link_type(mc, class_proto); class_class.link_prototype(activation, class_proto)?; - class_class.link_type(mc, class_proto, class_c_class); + class_class.link_type(mc, class_proto); // At this point, we need at least a partial set of system classes in // order to continue initializing the player. The rest of the classes diff --git a/core/src/avm2/object/class_object.rs b/core/src/avm2/object/class_object.rs index 5be3196bf..3a55a6abe 100644 --- a/core/src/avm2/object/class_object.rs +++ b/core/src/avm2/object/class_object.rs @@ -112,10 +112,6 @@ impl<'gc> ClassObject<'gc> { class: Class<'gc>, superclass_object: Option>, ) -> Result> { - let c_class = class - .c_class() - .expect("Can only call ClassObject::from_class on i_classes"); - let class_object = Self::from_class_partial(activation, class, superclass_object)?; let class_proto = class_object.allocate_prototype(activation, superclass_object)?; @@ -123,7 +119,7 @@ impl<'gc> ClassObject<'gc> { let class_class_proto = activation.avm2().classes().class.prototype(); - class_object.link_type(activation.context.gc_context, class_class_proto, c_class); + class_object.link_type(activation.context.gc_context, class_class_proto); class_object.init_instance_vtable(activation)?; class_object.into_finished_class(activation) } @@ -145,6 +141,10 @@ impl<'gc> ClassObject<'gc> { class: Class<'gc>, superclass_object: Option>, ) -> Result> { + let c_class = class + .c_class() + .expect("Can only call ClassObject::from_class on i_classes"); + let scope = activation.create_scopechain(); if let Some(base_class) = superclass_object.map(|b| b.inner_class_definition()) { if base_class.is_final() { @@ -190,6 +190,8 @@ impl<'gc> ClassObject<'gc> { .write(activation.context.gc_context) .instance_scope = instance_scope; + class_object.set_instance_class(activation.context.gc_context, c_class); + class.add_class_object(activation.context.gc_context, class_object); Ok(class_object) @@ -319,10 +321,9 @@ impl<'gc> ClassObject<'gc> { /// This is intended to support initialization of early types such as /// `Class` and `Object`. All other types should pull `Class`'s prototype /// and type object from the `Avm2` instance. - pub fn link_type(self, gc_context: &Mutation<'gc>, proto: Object<'gc>, c_class: Class<'gc>) { + pub fn link_type(self, gc_context: &Mutation<'gc>, proto: Object<'gc>) { let mut write = self.0.write(gc_context); - write.base.set_instance_class(c_class); write.base.set_proto(proto); }