Skip to content

Commit

Permalink
avm2: Make ClassObject::from_class_partial and `ClassObject::link_p…
Browse files Browse the repository at this point in the history
…rototype` infallible
  • Loading branch information
Lord-McSweeney authored and Lord-McSweeney committed Feb 20, 2025
1 parent 0e46856 commit 5ebe6d9
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 30 deletions.
1 change: 1 addition & 0 deletions core/src/avm2/activation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
abc_method,
body,
)?;

ClassObject::from_class(&mut dummy_activation, activation_class, None)
})?;

Expand Down
14 changes: 7 additions & 7 deletions core/src/avm2/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,20 +555,20 @@ pub fn load_player_globals<'gc>(
let gs = scope.chain(mc, &[Scope::new(globals.into())]);
activation.set_outer(gs);

let object_class = ClassObject::from_class_partial(activation, object_i_class, None)?;
let object_class = ClassObject::from_class_partial(activation, object_i_class, None);
let object_proto =
ScriptObject::custom_object(mc, object_i_class, None, object_class.instance_vtable());

let class_class =
ClassObject::from_class_partial(activation, class_i_class, Some(object_class))?;
ClassObject::from_class_partial(activation, class_i_class, Some(object_class));
let class_proto = ScriptObject::custom_object(
mc,
object_i_class,
Some(object_proto),
object_class.instance_vtable(),
);

let fn_class = ClassObject::from_class_partial(activation, fn_classdef, Some(object_class))?;
let fn_class = ClassObject::from_class_partial(activation, fn_classdef, Some(object_class));
let fn_proto = ScriptObject::custom_object(
mc,
fn_classdef,
Expand All @@ -577,13 +577,13 @@ pub fn load_player_globals<'gc>(
);

// Now to weave the Gordian knot...
object_class.link_prototype(activation, object_proto)?;
object_class.link_prototype(activation, object_proto);
object_class.link_type(mc, class_proto);

fn_class.link_prototype(activation, fn_proto)?;
fn_class.link_prototype(activation, fn_proto);
fn_class.link_type(mc, class_proto);

class_class.link_prototype(activation, class_proto)?;
class_class.link_prototype(activation, class_proto);
class_class.link_type(mc, class_proto);

// At this point, we need at least a partial set of system classes in
Expand All @@ -607,7 +607,7 @@ pub fn load_player_globals<'gc>(

// Function's prototype is an instance of itself
let fn_proto = fn_class.construct(activation, &[])?.as_object().unwrap();
fn_class.link_prototype(activation, fn_proto)?;
fn_class.link_prototype(activation, fn_proto);

// Object prototype is enough
globals.set_proto(mc, object_class.prototype());
Expand Down
38 changes: 15 additions & 23 deletions core/src/avm2/object/class_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,14 @@ impl<'gc> ClassObject<'gc> {
self,
activation: &mut Activation<'_, 'gc>,
superclass_object: Option<ClassObject<'gc>>,
) -> Result<Object<'gc>, Error<'gc>> {
) -> Object<'gc> {
let proto = ScriptObject::new_object(activation);

if let Some(superclass_object) = superclass_object {
let base_proto = superclass_object.prototype();
proto.set_proto(activation.gc(), base_proto);
}
Ok(proto)
proto
}

/// Construct a class.
Expand All @@ -114,10 +114,10 @@ impl<'gc> ClassObject<'gc> {
class: Class<'gc>,
superclass_object: Option<ClassObject<'gc>>,
) -> Result<Self, Error<'gc>> {
let class_object = Self::from_class_partial(activation, class, superclass_object)?;
let class_proto = class_object.allocate_prototype(activation, superclass_object)?;
let class_object = Self::from_class_partial(activation, class, superclass_object);
let class_proto = class_object.allocate_prototype(activation, superclass_object);

class_object.link_prototype(activation, class_proto)?;
class_object.link_prototype(activation, class_proto);

let class_class_proto = activation.avm2().classes().class.prototype();
class_object.link_type(activation.gc(), class_class_proto);
Expand All @@ -141,7 +141,7 @@ impl<'gc> ClassObject<'gc> {
activation: &mut Activation<'_, 'gc>,
class: Class<'gc>,
superclass_object: Option<ClassObject<'gc>>,
) -> Result<Self, Error<'gc>> {
) -> Self {
let c_class = class
.c_class()
.expect("Can only call ClassObject::from_class on i_classes");
Expand Down Expand Up @@ -176,14 +176,14 @@ impl<'gc> ClassObject<'gc> {
instance_scope
)
.set(instance_scope);
class_object.init_instance_vtable(activation)?;
class_object.init_instance_vtable(activation);

class.add_class_object(activation.gc(), class_object);

Ok(class_object)
class_object
}

fn init_instance_vtable(self, activation: &mut Activation<'_, 'gc>) -> Result<(), Error<'gc>> {
fn init_instance_vtable(self, activation: &mut Activation<'_, 'gc>) {
let class = self.inner_class_definition();

self.instance_vtable().init_vtable(
Expand All @@ -194,9 +194,7 @@ impl<'gc> ClassObject<'gc> {
activation.gc(),
);

self.link_interfaces(activation)?;

Ok(())
self.link_interfaces(activation);
}

/// Finish initialization of the class.
Expand Down Expand Up @@ -244,26 +242,22 @@ impl<'gc> ClassObject<'gc> {
}

/// Link this class to a prototype.
pub fn link_prototype(
self,
activation: &mut Activation<'_, 'gc>,
class_proto: Object<'gc>,
) -> Result<(), Error<'gc>> {
pub fn link_prototype(self, activation: &mut Activation<'_, 'gc>, class_proto: Object<'gc>) {
let mc = activation.gc();

unlock!(Gc::write(mc, self.0), ClassObjectData, prototype).set(Some(class_proto));
class_proto.set_string_property_local(istr!("constructor"), self.into(), activation)?;
class_proto
.set_string_property_local(istr!("constructor"), self.into(), activation)
.expect("Prototype is a dynamic object");
class_proto.set_local_property_is_enumerable(mc, istr!("constructor"), false);

Ok(())
}

/// Link this class to it's interfaces.
///
/// This should be done after all instance traits has been resolved, as
/// instance traits will be resolved to their corresponding methods at this
/// time.
pub fn link_interfaces(self, activation: &mut Activation<'_, 'gc>) -> Result<(), Error<'gc>> {
fn link_interfaces(self, activation: &mut Activation<'_, 'gc>) {
let class = self.inner_class_definition();

// FIXME - we should only be copying properties for newly-implemented
Expand All @@ -283,8 +277,6 @@ impl<'gc> ClassObject<'gc> {
}
}
}

Ok(())
}

/// Manually set the type of this `Class`.
Expand Down

0 comments on commit 5ebe6d9

Please sign in to comment.