Skip to content

Commit

Permalink
avm2: Store Class instead of QName as superclass of Class
Browse files Browse the repository at this point in the history
  • Loading branch information
Lord-McSweeney authored and Lord-McSweeney committed Apr 20, 2024
1 parent 41bba9d commit 8a4946f
Show file tree
Hide file tree
Showing 20 changed files with 95 additions and 145 deletions.
9 changes: 0 additions & 9 deletions core/src/avm2/activation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,15 +326,6 @@ impl<'a, 'gc> Activation<'a, 'gc> {
}
}

pub fn lookup_class_in_domain(
&mut self,
name: &Multiname<'gc>,
) -> Result<GcCell<'gc, Class<'gc>>, Error<'gc>> {
self.domain()
.get_class(name, self.context.gc_context)
.ok_or_else(|| format!("Attempted to resolve nonexistent type {name:?}").into())
}

/// Resolve a single parameter value.
///
/// Given an individual parameter value and the associated parameter's
Expand Down
43 changes: 33 additions & 10 deletions core/src/avm2/class.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! AVM2 classes
use crate::avm2::activation::Activation;
use crate::avm2::error::make_error_1014;
use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::object::{ClassObject, Object};
use crate::avm2::script::TranslationUnit;
Expand All @@ -10,6 +11,7 @@ use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::Namespace;
use crate::avm2::QName;
use crate::context::UpdateContext;
use bitflags::bitflags;
use fnv::FnvHashMap;
use gc_arena::{Collect, GcCell, Mutation};
Expand Down Expand Up @@ -80,8 +82,8 @@ pub struct Class<'gc> {
/// The type parameter for this class (only supported for Vector)
param: Option<Option<GcCell<'gc, Class<'gc>>>>,

/// The name of this class's superclass.
super_class: Option<Multiname<'gc>>,
/// This class's superclass, or None if it has no superclass
super_class: Option<GcCell<'gc, Class<'gc>>>,

/// Attributes of the given class.
#[collect(require_static)]
Expand Down Expand Up @@ -203,7 +205,7 @@ impl<'gc> Class<'gc> {
/// using `load_traits`.
pub fn new(
name: QName<'gc>,
super_class: Option<Multiname<'gc>>,
super_class: Option<GcCell<'gc, Class<'gc>>>,
instance_init: Method<'gc>,
class_init: Method<'gc>,
mc: &Mutation<'gc>,
Expand Down Expand Up @@ -249,10 +251,12 @@ impl<'gc> Class<'gc> {
/// This is used to parameterize a generic type. The returned class will no
/// longer be generic.
pub fn with_type_param(
context: &mut UpdateContext<'_, 'gc>,
this: GcCell<'gc, Class<'gc>>,
param: Option<GcCell<'gc, Class<'gc>>>,
mc: &Mutation<'gc>,
) -> GcCell<'gc, Class<'gc>> {
let mc = context.gc_context;

let read = this.read();
let key = param.map(ClassKey);

Expand All @@ -275,7 +279,13 @@ impl<'gc> Class<'gc> {
// FIXME - we should store a `Multiname` instead of a `QName`, and use the
// `params` field. For now, this is good enough to get tests passing
QName::new(read.name.namespace(), AvmString::new_utf8(mc, name)),
Some(Multiname::new(read.name.namespace(), "Vector.<*>")),
Some(
context
.avm2
.classes()
.object_vector
.inner_class_definition(),
),
object_vector_cls.read().instance_init(),
object_vector_cls.read().class_init(),
mc,
Expand Down Expand Up @@ -336,10 +346,19 @@ impl<'gc> Class<'gc> {
let super_class = if abc_instance.super_name.0 == 0 {
None
} else {
let multiname =
unit.pool_multiname_static(abc_instance.super_name, &mut activation.context)?;

Some(
unit.pool_multiname_static(abc_instance.super_name, &mut activation.context)?
.deref()
.clone(),
activation
.domain()
.get_class(&mut activation.context, &multiname)
.ok_or_else(|| {
make_error_1014(
activation,
multiname.to_qualified_name(activation.context.gc_context),
)
})?,
)
};

Expand Down Expand Up @@ -616,8 +635,12 @@ impl<'gc> Class<'gc> {
self.param = param;
}

pub fn super_class_name(&self) -> &Option<Multiname<'gc>> {
&self.super_class
pub fn super_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
self.super_class
}

pub fn super_class_name(&self) -> Option<Multiname<'gc>> {
self.super_class.map(|c| c.read().name().into())
}

pub fn protected_namespace(&self) -> Option<Namespace<'gc>> {
Expand Down
9 changes: 5 additions & 4 deletions core/src/avm2/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::QName;
use crate::context::UpdateContext;
use gc_arena::{Collect, GcCell, GcWeakCell, Mutation};
use ruffle_wstr::WStr;

Expand Down Expand Up @@ -213,20 +214,20 @@ impl<'gc> Domain<'gc> {

pub fn get_class(
self,
context: &mut UpdateContext<'_, 'gc>,
multiname: &Multiname<'gc>,
mc: &Mutation<'gc>,
) -> Option<GcCell<'gc, Class<'gc>>> {
let class = self.get_class_inner(multiname);

if let Some(class) = class {
if let Some(param) = multiname.param() {
if !param.is_any_name() {
if let Some(resolved_param) = self.get_class(&param, mc) {
return Some(Class::with_type_param(class, Some(resolved_param), mc));
if let Some(resolved_param) = self.get_class(context, &param) {
return Some(Class::with_type_param(context, class, Some(resolved_param)));
}
return None;
} else {
return Some(Class::with_type_param(class, None, mc));
return Some(Class::with_type_param(context, class, None));
}
}
}
Expand Down
30 changes: 9 additions & 21 deletions core/src/avm2/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::avm2::activation::Activation;
use crate::avm2::api_version::ApiVersion;
use crate::avm2::class::Class;
use crate::avm2::domain::Domain;
use crate::avm2::object::{ClassObject, Object, ScriptObject, TObject};
use crate::avm2::object::{ClassObject, ScriptObject, TObject};
use crate::avm2::scope::{Scope, ScopeChain};
use crate::avm2::script::Script;
use crate::avm2::Avm2;
Expand Down Expand Up @@ -376,23 +376,11 @@ fn class<'gc>(
let (_, global, mut domain) = script.init();

let class_read = class_def.read();
let super_class = if let Some(sc_name) = class_read.super_class_name() {
let super_class: Result<Object<'gc>, Error<'gc>> = activation
.resolve_definition(sc_name)
.ok()
.and_then(|v| v)
.and_then(|v| v.as_object())
.ok_or_else(|| {
format!(
"Could not resolve superclass {} when defining global class {}",
sc_name.to_qualified_name(mc),
class_read.name().to_qualified_name(mc)
)
.into()
});
let super_class = super_class?
.as_class_object()
.ok_or_else(|| Error::from("Base class of a global class is not a class"))?;
let super_class = if let Some(super_class) = class_read.super_class() {
let super_class = super_class
.read()
.class_object()
.ok_or_else(|| Error::from("Base class should have been initialized"))?;

Some(super_class)
} else {
Expand Down Expand Up @@ -498,18 +486,18 @@ pub fn load_player_globals<'gc>(
let object_proto = ScriptObject::custom_object(mc, Some(object_class), None);
domain.export_class(object_classdef.read().name(), object_classdef, mc);

let fn_classdef = function::create_class(activation);
let fn_classdef = function::create_class(activation, object_classdef);
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.read().name(), fn_classdef, mc);

let class_classdef = class::create_class(activation);
let class_classdef = class::create_class(activation, object_classdef);
let class_class =
ClassObject::from_class_partial(activation, class_classdef, Some(object_class))?;
let class_proto = ScriptObject::custom_object(mc, Some(object_class), Some(object_proto));
domain.export_class(class_classdef.read().name(), class_classdef, mc);

let global_classdef = global_scope::create_class(activation);
let global_classdef = global_scope::create_class(activation, object_classdef);
let global_class =
ClassObject::from_class_partial(activation, global_classdef, Some(object_class))?;
let global_proto = ScriptObject::custom_object(mc, Some(object_class), Some(object_proto));
Expand Down
6 changes: 1 addition & 5 deletions core/src/avm2/globals/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::object::{array_allocator, ArrayObject, FunctionObject, Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::QName;
use crate::string::AvmString;
use bitflags::bitflags;
Expand Down Expand Up @@ -1247,10 +1246,7 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Cl
let mc = activation.context.gc_context;
let class = Class::new(
QName::new(activation.avm2().public_namespace_base_version, "Array"),
Some(Multiname::new(
activation.avm2().public_namespace_base_version,
"Object",
)),
Some(activation.avm2().classes().object.inner_class_definition()),
Method::from_builtin(instance_init, "<Array instance initializer>", mc),
Method::from_builtin(class_init, "<Array class initializer>", mc),
mc,
Expand Down
6 changes: 1 addition & 5 deletions core/src/avm2/globals/boolean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::object::{primitive_allocator, FunctionObject, Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::QName;
use gc_arena::GcCell;

Expand Down Expand Up @@ -136,10 +135,7 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Cl
let mc = activation.context.gc_context;
let class = Class::new(
QName::new(activation.avm2().public_namespace_base_version, "Boolean"),
Some(Multiname::new(
activation.avm2().public_namespace_base_version,
"Object",
)),
Some(activation.avm2().classes().object.inner_class_definition()),
Method::from_builtin(instance_init, "<Boolean instance initializer>", mc),
Method::from_builtin(class_init, "<Boolean class initializer>", mc),
mc,
Expand Down
11 changes: 5 additions & 6 deletions core/src/avm2/globals/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::object::{Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::QName;
use gc_arena::GcCell;

Expand Down Expand Up @@ -44,14 +43,14 @@ fn prototype<'gc>(
}

/// Construct `Class`'s class.
pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Class<'gc>> {
pub fn create_class<'gc>(
activation: &mut Activation<'_, 'gc>,
object_class: GcCell<'gc, Class<'gc>>,
) -> GcCell<'gc, Class<'gc>> {
let gc_context = activation.context.gc_context;
let class_class = Class::new(
QName::new(activation.avm2().public_namespace_base_version, "Class"),
Some(Multiname::new(
activation.avm2().public_namespace_base_version,
"Object",
)),
Some(object_class),
Method::from_builtin(instance_init, "<Class instance initializer>", gc_context),
Method::from_builtin(class_init, "<Class class initializer>", gc_context),
gc_context,
Expand Down
6 changes: 1 addition & 5 deletions core/src/avm2/globals/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::object::{date_allocator, DateObject, FunctionObject, Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::QName;
use crate::locale::{get_current_date_time, get_timezone};
use crate::string::{utils as string_utils, AvmString, WStr};
Expand Down Expand Up @@ -1327,10 +1326,7 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Cl
let mc = activation.context.gc_context;
let class = Class::new(
QName::new(activation.avm2().public_namespace_base_version, "Date"),
Some(Multiname::new(
activation.avm2().public_namespace_base_version,
"Object",
)),
Some(activation.avm2().classes().object.inner_class_definition()),
Method::from_builtin(instance_init, "<Date instance initializer>", mc),
Method::from_builtin(class_init, "<Date class initializer>", mc),
mc,
Expand Down
11 changes: 5 additions & 6 deletions core/src/avm2/globals/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::object::{function_allocator, FunctionObject, Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::QName;
use gc_arena::GcCell;

Expand Down Expand Up @@ -222,14 +221,14 @@ fn set_prototype<'gc>(
}

/// Construct `Function`'s class.
pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Class<'gc>> {
pub fn create_class<'gc>(
activation: &mut Activation<'_, 'gc>,
object_classdef: GcCell<'gc, Class<'gc>>,
) -> GcCell<'gc, Class<'gc>> {
let gc_context = activation.context.gc_context;
let function_class = Class::new(
QName::new(activation.avm2().public_namespace_base_version, "Function"),
Some(Multiname::new(
activation.avm2().public_namespace_base_version,
"Object",
)),
Some(object_classdef),
Method::from_builtin(instance_init, "<Function instance initializer>", gc_context),
Method::from_builtin(class_init, "<Function class initializer>", gc_context),
gc_context,
Expand Down
11 changes: 5 additions & 6 deletions core/src/avm2/globals/global_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::avm2::method::Method;
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::QName;
use gc_arena::GcCell;

Expand All @@ -33,14 +32,14 @@ pub fn class_init<'gc>(
}

/// Construct `global`'s class.
pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Class<'gc>> {
pub fn create_class<'gc>(
activation: &mut Activation<'_, 'gc>,
object_class: GcCell<'gc, Class<'gc>>,
) -> GcCell<'gc, Class<'gc>> {
let mc = activation.context.gc_context;
Class::new(
QName::new(activation.avm2().public_namespace_base_version, "global"),
Some(Multiname::new(
activation.avm2().public_namespace_base_version,
"Object",
)),
Some(object_class),
Method::from_builtin(instance_init, "<global instance initializer>", mc),
Method::from_builtin(class_init, "<global class initializer>", mc),
mc,
Expand Down
5 changes: 1 addition & 4 deletions core/src/avm2/globals/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,7 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Cl
let mc = activation.context.gc_context;
let class = Class::new(
QName::new(activation.avm2().public_namespace_base_version, "int"),
Some(Multiname::new(
activation.avm2().public_namespace_base_version,
"Object",
)),
Some(activation.avm2().classes().object.inner_class_definition()),
Method::from_builtin_and_params(
instance_init,
"<int instance initializer>",
Expand Down
6 changes: 1 addition & 5 deletions core/src/avm2/globals/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::object::{namespace_allocator, FunctionObject, Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::Multiname;
use crate::avm2::Namespace;
use crate::avm2::QName;
use crate::{avm2_stub_constructor, avm2_stub_getter};
Expand Down Expand Up @@ -133,10 +132,7 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Cl
let mc = activation.context.gc_context;
let class = Class::new(
QName::new(activation.avm2().public_namespace_base_version, "Namespace"),
Some(Multiname::new(
activation.avm2().public_namespace_base_version,
"Object",
)),
Some(activation.avm2().classes().object.inner_class_definition()),
Method::from_builtin(instance_init, "<Namespace instance initializer>", mc),
Method::from_builtin(class_init, "<Namespace class initializer>", mc),
mc,
Expand Down
Loading

0 comments on commit 8a4946f

Please sign in to comment.