avm2: Simplify `ClassObject::link_type`

This commit is contained in:
Lord-McSweeney 2024-06-20 09:52:10 -07:00 committed by Lord-McSweeney
parent 9c872860e9
commit bac18c1a84
2 changed files with 26 additions and 21 deletions

View File

@ -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

View File

@ -112,10 +112,6 @@ impl<'gc> ClassObject<'gc> {
class: Class<'gc>,
superclass_object: Option<ClassObject<'gc>>,
) -> Result<Self, Error<'gc>> {
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<ClassObject<'gc>>,
) -> Result<Self, Error<'gc>> {
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);
}