Skip to content

Commit 28cde78

Browse files
avm2: Replace most uses of instance_of with instance_class
This commit does not build by itself
1 parent bc85638 commit 28cde78

File tree

25 files changed

+337
-276
lines changed

25 files changed

+337
-276
lines changed

core/src/avm2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ mod vtable;
7272
pub use crate::avm2::activation::Activation;
7373
pub use crate::avm2::array::ArrayStorage;
7474
pub use crate::avm2::call_stack::{CallNode, CallStack};
75+
pub use crate::avm2::class::Class;
7576
#[allow(unused)] // For debug_ui
7677
pub use crate::avm2::domain::{Domain, DomainPtr};
7778
pub use crate::avm2::error::Error;

core/src/avm2/activation.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
16321632

16331633
fn op_get_outer_scope(&mut self, index: u32) -> Result<FrameControl<'gc>, Error<'gc>> {
16341634
// Verifier ensures that this points to a valid outer scope
1635+
16351636
let scope = self.outer.get_unchecked(index as usize);
16361637

16371638
self.push_stack(scope.values());
@@ -1730,10 +1731,9 @@ impl<'a, 'gc> Activation<'a, 'gc> {
17301731
} else {
17311732
// Even if it's an object with the "descendants" property, we won't support it.
17321733
let class_name = object
1733-
.instance_of()
1734+
.instance_class()
17341735
.map(|cls| {
1735-
cls.inner_class_definition()
1736-
.name()
1736+
cls.name()
17371737
.to_qualified_name_err_message(self.context.gc_context)
17381738
})
17391739
.unwrap_or_else(|| AvmString::from("<UNKNOWN>"));

core/src/avm2/amf.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub fn serialize_value<'gc>(
7272
Some(AmfValue::ECMAArray(dense, sparse, len))
7373
} else if let Some(vec) = o.as_vector_storage() {
7474
let val_type = vec.value_type();
75-
if val_type == Some(activation.avm2().classes().int) {
75+
if val_type == Some(activation.avm2().classes().int.inner_class_definition()) {
7676
let int_vec: Vec<_> = vec
7777
.iter()
7878
.map(|v| {
@@ -81,7 +81,9 @@ pub fn serialize_value<'gc>(
8181
})
8282
.collect();
8383
Some(AmfValue::VectorInt(int_vec, vec.is_fixed()))
84-
} else if val_type == Some(activation.avm2().classes().uint) {
84+
} else if val_type
85+
== Some(activation.avm2().classes().uint.inner_class_definition())
86+
{
8587
let uint_vec: Vec<_> = vec
8688
.iter()
8789
.map(|v| {
@@ -90,7 +92,9 @@ pub fn serialize_value<'gc>(
9092
})
9193
.collect();
9294
Some(AmfValue::VectorUInt(uint_vec, vec.is_fixed()))
93-
} else if val_type == Some(activation.avm2().classes().number) {
95+
} else if val_type
96+
== Some(activation.avm2().classes().number.inner_class_definition())
97+
{
9498
let num_vec: Vec<_> = vec
9599
.iter()
96100
.map(|v| {
@@ -108,7 +112,8 @@ pub fn serialize_value<'gc>(
108112
})
109113
.collect();
110114

111-
let val_type = val_type.unwrap_or(activation.avm2().classes().object);
115+
let val_type = val_type
116+
.unwrap_or(activation.avm2().classes().object.inner_class_definition());
112117

113118
let name = class_to_alias(activation, val_type);
114119
Some(AmfValue::VectorObject(obj_vec, name, vec.is_fixed()))
@@ -125,11 +130,11 @@ pub fn serialize_value<'gc>(
125130
} else if let Some(bytearray) = o.as_bytearray() {
126131
Some(AmfValue::ByteArray(bytearray.bytes().to_vec()))
127132
} else {
128-
let class = o.instance_of().expect("Missing ClassObject");
133+
let class = o.instance_class().expect("Missing Class");
129134
let name = class_to_alias(activation, class);
130135

131136
let mut attributes = EnumSet::empty();
132-
if !class.inner_class_definition().is_sealed() {
137+
if !class.is_sealed() {
133138
attributes.insert(Attribute::Dynamic);
134139
}
135140

@@ -359,23 +364,23 @@ pub fn deserialize_value<'gc>(
359364
let storage = VectorStorage::from_values(
360365
vec.iter().map(|v| (*v).into()).collect(),
361366
*is_fixed,
362-
Some(activation.avm2().classes().number),
367+
Some(activation.avm2().classes().number.inner_class_definition()),
363368
);
364369
VectorObject::from_vector(storage, activation)?.into()
365370
}
366371
AmfValue::VectorUInt(vec, is_fixed) => {
367372
let storage = VectorStorage::from_values(
368373
vec.iter().map(|v| (*v).into()).collect(),
369374
*is_fixed,
370-
Some(activation.avm2().classes().uint),
375+
Some(activation.avm2().classes().uint.inner_class_definition()),
371376
);
372377
VectorObject::from_vector(storage, activation)?.into()
373378
}
374379
AmfValue::VectorInt(vec, is_fixed) => {
375380
let storage = VectorStorage::from_values(
376381
vec.iter().map(|v| (*v).into()).collect(),
377382
*is_fixed,
378-
Some(activation.avm2().classes().int),
383+
Some(activation.avm2().classes().int.inner_class_definition()),
379384
);
380385
VectorObject::from_vector(storage, activation)?.into()
381386
}
@@ -397,7 +402,7 @@ pub fn deserialize_value<'gc>(
397402
})
398403
.collect::<Result<Vec<_>, _>>()?,
399404
*is_fixed,
400-
Some(class),
405+
Some(class.inner_class_definition()),
401406
);
402407
VectorObject::from_vector(storage, activation)?.into()
403408
}

core/src/avm2/class.rs

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ pub struct ClassData<'gc> {
104104
/// superinterfaces, nor interfaces implemented by the superclass.
105105
direct_interfaces: Vec<Class<'gc>>,
106106

107+
/// The list of all interfaces implemented by this class.
108+
all_interfaces: Vec<Class<'gc>>,
109+
107110
/// The instance allocator for this class.
108111
///
109112
/// If `None`, then instances of this object will be allocated the same way
@@ -163,7 +166,7 @@ pub struct ClassData<'gc> {
163166
/// Maps a type parameter to the application of this class with that parameter.
164167
///
165168
/// Only applicable if this class is generic.
166-
applications: FnvHashMap<Option<ClassKey<'gc>>, Class<'gc>>,
169+
applications: FnvHashMap<Option<Class<'gc>>, Class<'gc>>,
167170

168171
/// Whether or not this is a system-defined class.
169172
///
@@ -184,29 +187,17 @@ impl PartialEq for Class<'_> {
184187
}
185188
}
186189

187-
impl<'gc> core::fmt::Debug for Class<'gc> {
188-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
189-
f.debug_struct("Class").field("name", &self.name()).finish()
190-
}
191-
}
192-
193-
/// Allows using a `Class<'gc>` as a HashMap key,
194-
/// using the pointer address for hashing/equality.
195-
#[derive(Collect, Copy, Clone)]
196-
#[collect(no_drop)]
197-
struct ClassKey<'gc>(Class<'gc>);
190+
impl Eq for Class<'_> {}
198191

199-
impl PartialEq for ClassKey<'_> {
200-
fn eq(&self, other: &Self) -> bool {
201-
self.0 == other.0
192+
impl Hash for Class<'_> {
193+
fn hash<H: Hasher>(&self, state: &mut H) {
194+
self.0.as_ptr().hash(state);
202195
}
203196
}
204197

205-
impl Eq for ClassKey<'_> {}
206-
207-
impl Hash for ClassKey<'_> {
208-
fn hash<H: Hasher>(&self, state: &mut H) {
209-
self.0 .0.as_ptr().hash(state);
198+
impl<'gc> core::fmt::Debug for Class<'gc> {
199+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
200+
f.debug_struct("Class").field("name", &self.name()).finish()
210201
}
211202
}
212203

@@ -237,6 +228,7 @@ impl<'gc> Class<'gc> {
237228
attributes: ClassAttributes::empty(),
238229
protected_namespace: None,
239230
direct_interfaces: Vec::new(),
231+
all_interfaces: Vec::new(),
240232
instance_allocator: None,
241233
instance_init,
242234
native_instance_init,
@@ -255,8 +247,7 @@ impl<'gc> Class<'gc> {
255247
}
256248

257249
pub fn add_application(self, mc: &Mutation<'gc>, param: Option<Class<'gc>>, cls: Class<'gc>) {
258-
let key = param.map(ClassKey);
259-
self.0.write(mc).applications.insert(key, cls);
250+
self.0.write(mc).applications.insert(param, cls);
260251
}
261252

262253
/// Apply type parameters to an existing class.
@@ -271,9 +262,7 @@ impl<'gc> Class<'gc> {
271262
let mc = context.gc_context;
272263
let this_read = this.0.read();
273264

274-
let key = param.map(ClassKey);
275-
276-
if let Some(application) = this_read.applications.get(&key) {
265+
if let Some(application) = this_read.applications.get(&param) {
277266
return *application;
278267
}
279268

@@ -312,7 +301,7 @@ impl<'gc> Class<'gc> {
312301

313302
drop(this_read);
314303

315-
this.0.write(mc).applications.insert(key, new_class);
304+
this.0.write(mc).applications.insert(Some(param), new_class);
316305
new_class
317306
}
318307

@@ -464,6 +453,7 @@ impl<'gc> Class<'gc> {
464453
attributes,
465454
protected_namespace,
466455
direct_interfaces: interfaces,
456+
all_interfaces: Vec::new(),
467457
instance_allocator,
468458
instance_init,
469459
native_instance_init,
@@ -658,7 +648,7 @@ impl<'gc> Class<'gc> {
658648
// interfaces (i.e. those that were not already implemented by the superclass)
659649
// Otherwise, our behavior diverges from Flash Player in certain cases.
660650
// See the ignored test 'tests/tests/swfs/avm2/weird_superinterface_properties/'
661-
for interface in interfaces {
651+
for interface in &interfaces {
662652
for interface_trait in &*interface.instance_traits() {
663653
if !interface_trait.name().namespace().is_public() {
664654
let public_name = QName::new(
@@ -674,6 +664,8 @@ impl<'gc> Class<'gc> {
674664
}
675665
}
676666

667+
self.0.write(context.gc_context).all_interfaces = interfaces;
668+
677669
Ok(())
678670
}
679671

@@ -704,6 +696,7 @@ impl<'gc> Class<'gc> {
704696
attributes: ClassAttributes::empty(),
705697
protected_namespace: None,
706698
direct_interfaces: Vec::new(),
699+
all_interfaces: Vec::new(),
707700
instance_allocator: None,
708701
instance_init: Method::from_builtin(
709702
|_, _, _| Ok(Value::Undefined),
@@ -737,6 +730,36 @@ impl<'gc> Class<'gc> {
737730
Ok(class)
738731
}
739732

733+
/// Determine if this class has a given type in its superclass chain.
734+
///
735+
/// The given class `test_class` should be either a superclass or
736+
/// interface we are checking against this class.
737+
///
738+
/// To test if a class *instance* is of a given type, see `Object::is_of_type`.
739+
pub fn has_class_in_chain(self, test_class: Class<'gc>) -> bool {
740+
let mut my_class = Some(self);
741+
742+
while let Some(class) = my_class {
743+
if class == test_class {
744+
return true;
745+
}
746+
747+
my_class = class.super_class()
748+
}
749+
750+
// A `Class` stores all of the interfaces it implements, including
751+
// those from superinterfaces and superclasses (recursively).
752+
if test_class.is_interface() {
753+
for interface in &*self.all_interfaces() {
754+
if *interface == test_class {
755+
return true;
756+
}
757+
}
758+
}
759+
760+
false
761+
}
762+
740763
pub fn instance_vtable(self) -> VTable<'gc> {
741764
self.0.read().instance_vtable
742765
}
@@ -749,6 +772,26 @@ impl<'gc> Class<'gc> {
749772
self.0.try_read().map(|r| r.name)
750773
}
751774

775+
/// Attempts to obtain the name of this class.
776+
/// If we are unable to read from the necessary `GcCell`,
777+
/// the returned value will be some kind of error message.
778+
///
779+
/// This should only be used in a debug context, where
780+
/// we need infallible access to *something* to print
781+
/// out.
782+
pub fn debug_name(self) -> Box<dyn fmt::Debug + 'gc> {
783+
let class_name = self.try_name();
784+
785+
match class_name {
786+
Ok(class_name) => Box::new(class_name),
787+
Err(err) => Box::new(err),
788+
}
789+
}
790+
791+
pub fn param(self) -> Option<Option<Class<'gc>>> {
792+
self.0.read().param
793+
}
794+
752795
pub fn set_param(self, mc: &Mutation<'gc>, param: Option<Option<Class<'gc>>>) {
753796
self.0.write(mc).param = param;
754797
}
@@ -1079,6 +1122,10 @@ impl<'gc> Class<'gc> {
10791122
Ref::map(self.0.read(), |c| &c.direct_interfaces)
10801123
}
10811124

1125+
pub fn all_interfaces(&self) -> Ref<Vec<Class<'gc>>> {
1126+
Ref::map(self.0.read(), |c| &c.all_interfaces)
1127+
}
1128+
10821129
/// Determine if this class is sealed (no dynamic properties)
10831130
pub fn is_sealed(self) -> bool {
10841131
self.0.read().attributes.contains(ClassAttributes::SEALED)

core/src/avm2/error.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
use ruffle_wstr::WString;
22

33
use crate::avm2::object::TObject;
4-
use crate::avm2::Activation;
5-
use crate::avm2::AvmString;
6-
use crate::avm2::Multiname;
7-
use crate::avm2::Value;
4+
use crate::avm2::{Activation, AvmString, Class, Multiname, Value};
85
use std::borrow::Cow;
96
use std::fmt::Debug;
107
use std::mem::size_of;
@@ -94,13 +91,12 @@ pub fn make_reference_error<'gc>(
9491
activation: &mut Activation<'_, 'gc>,
9592
code: ReferenceErrorCode,
9693
multiname: &Multiname<'gc>,
97-
object_class: Option<ClassObject<'gc>>,
94+
object_class: Option<Class<'gc>>,
9895
) -> Error<'gc> {
9996
let qualified_name = multiname.as_uri(activation.context.gc_context);
10097
let class_name = object_class
10198
.map(|cls| {
102-
cls.inner_class_definition()
103-
.name()
99+
cls.name()
104100
.to_qualified_name_err_message(activation.context.gc_context)
105101
})
106102
.unwrap_or_else(|| AvmString::from("<UNKNOWN>"));

core/src/avm2/globals.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -419,18 +419,17 @@ fn vector_class<'gc>(
419419
let mc = activation.context.gc_context;
420420
let (_, global, mut domain) = script.init();
421421

422-
let cls = param_class.map(|c| c.inner_class_definition());
422+
let param_class = param_class.map(|c| c.inner_class_definition());
423423
let vector_cls = class(
424-
vector::create_builtin_class(activation, cls),
424+
vector::create_builtin_class(activation, param_class),
425425
script,
426426
activation,
427427
)?;
428-
vector_cls.set_param(mc, Some(param_class));
429428

430429
let generic_vector = activation.avm2().classes().generic_vector;
431430
generic_vector.add_application(mc, param_class, vector_cls);
432431
let generic_cls = generic_vector.inner_class_definition();
433-
generic_cls.add_application(mc, cls, vector_cls.inner_class_definition());
432+
generic_cls.add_application(mc, param_class, vector_cls.inner_class_definition());
434433

435434
let legacy_name = QName::new(activation.avm2().vector_internal_namespace, legacy_name);
436435
global.install_const_late(

core/src/avm2/globals/flash/display/bitmap_data.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pub fn init<'gc>(
9292
) -> Result<Value<'gc>, Error<'gc>> {
9393
// We set the underlying BitmapData instance - we start out with a dummy BitmapDataWrapper,
9494
// which makes custom classes see a disposed BitmapData before they call super()
95-
let name = this.instance_of_class_definition().map(|c| c.name());
95+
let name = this.instance_class().map(|c| c.name());
9696
let character = this
9797
.instance_of()
9898
.and_then(|t| {
@@ -374,7 +374,7 @@ pub fn get_vector<'gc>(
374374
height,
375375
);
376376

377-
let value_type = activation.avm2().classes().uint;
377+
let value_type = activation.avm2().classes().uint.inner_class_definition();
378378
let new_storage = VectorStorage::from_values(pixels, false, Some(value_type));
379379

380380
return Ok(VectorObject::from_vector(new_storage, activation)?.into());

0 commit comments

Comments
 (0)