chore: cargo fmt

This commit is contained in:
Adrian Wielgosik 2021-12-04 22:32:39 +01:00 committed by Adrian Wielgosik
parent 3d8f611651
commit 0fb075a309
25 changed files with 329 additions and 282 deletions

View File

@ -251,7 +251,12 @@ impl<'gc> SystemClasses<'gc> {
/// the empty object also handed to this function. It is the caller's
/// responsibility to instantiate each class and replace the empty object
/// with that.
fn new(object: ClassObject<'gc>, function: ClassObject<'gc>, class: ClassObject<'gc>, global: ClassObject<'gc>) -> Self {
fn new(
object: ClassObject<'gc>,
function: ClassObject<'gc>,
class: ClassObject<'gc>,
global: ClassObject<'gc>,
) -> Self {
SystemClasses {
object,
function,
@ -505,8 +510,12 @@ pub fn load_player_globals<'gc>(
ScriptObject::bare_object(mc),
));
activation.context.avm2.system_classes =
Some(SystemClasses::new(object_class, fn_class, class_class, global_class));
activation.context.avm2.system_classes = Some(SystemClasses::new(
object_class,
fn_class,
class_class,
global_class,
));
// Our activation environment is now functional enough to finish
// initializing the core class weave. The order of initialization shouldn't

View File

@ -64,8 +64,9 @@ fn class_init<'gc>(
scope,
None,
Some(this_class),
).into(),
activation
)
.into(),
activation,
)?;
boolean_proto.set_property_local(
&Multiname::public("valueOf"),
@ -75,8 +76,9 @@ fn class_init<'gc>(
scope,
None,
Some(this_class),
).into(),
activation
)
.into(),
activation,
)?;
boolean_proto.set_local_property_is_enumerable(gc_context, "toString".into(), false)?;
boolean_proto.set_local_property_is_enumerable(gc_context, "valueOf".into(), false)?;

View File

@ -4,7 +4,7 @@ use crate::avm2::activation::Activation;
use crate::avm2::class::Class;
use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::{TObject, Object};
use crate::avm2::object::{Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::{GcCell, MutationContext};
@ -59,9 +59,7 @@ pub fn create_class<'gc>(gc_context: MutationContext<'gc, '_>) -> GcCell<'gc, Cl
&str,
Option<NativeMethodImpl>,
Option<NativeMethodImpl>,
)] = &[
("prototype", Some(prototype), None),
];
)] = &[("prototype", Some(prototype), None)];
write.define_public_builtin_instance_properties(gc_context, PUBLIC_INSTANCE_PROPERTIES);
class_class

View File

@ -241,10 +241,7 @@ pub fn to_string<'gc>(
) -> Result<Value<'gc>, Error> {
let object_proto = activation.avm2().prototypes().object;
object_proto
.get_property(
&QName::dynamic_name("toString").into(),
activation,
)?
.get_property(&QName::dynamic_name("toString").into(), activation)?
.coerce_to_object(activation)?
.call(this, args, activation)
}

View File

@ -33,16 +33,10 @@ fn coords<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(f64, f64), Error> {
let x = this
.get_property(
&QName::new(Namespace::public(), "x").into(),
activation,
)?
.get_property(&QName::new(Namespace::public(), "x").into(), activation)?
.coerce_to_number(activation)?;
let y = this
.get_property(
&QName::new(Namespace::public(), "y").into(),
activation,
)?
.get_property(&QName::new(Namespace::public(), "y").into(), activation)?
.coerce_to_number(activation)?;
Ok((x, y))
}
@ -324,16 +318,10 @@ pub fn to_string<'gc>(
) -> Result<Value<'gc>, Error> {
if let Some(this) = this {
let x = this
.get_property(
&QName::new(Namespace::public(), "x").into(),
activation,
)?
.get_property(&QName::new(Namespace::public(), "x").into(), activation)?
.coerce_to_string(activation)?;
let y = this
.get_property(
&QName::new(Namespace::public(), "y").into(),
activation,
)?
.get_property(&QName::new(Namespace::public(), "y").into(), activation)?
.coerce_to_string(activation)?;
return Ok(AvmString::new_utf8(
activation.context.gc_context,

View File

@ -27,10 +27,7 @@ pub fn create_rectangle<'gc>(
macro_rules! get_prop {
($this:expr, $activation:expr, $name: expr) => {
$this
.get_property(
&QName::new(Namespace::public(), $name).into(),
$activation,
)?
.get_property(&QName::new(Namespace::public(), $name).into(), $activation)?
.coerce_to_number($activation)
};
}
@ -454,18 +451,10 @@ pub fn copy_from<'gc>(
) -> Result<Value<'gc>, Error> {
if let Some(rect) = args.get(0) {
let rect = rect.coerce_to_object(activation)?;
let x = rect.get_property(
&QName::new(Namespace::public(), "x").into(),
activation,
)?;
let y = rect.get_property(
&QName::new(Namespace::public(), "y").into(),
activation,
)?;
let width = rect.get_property(
&QName::new(Namespace::public(), "width").into(),
activation,
)?;
let x = rect.get_property(&QName::new(Namespace::public(), "x").into(), activation)?;
let y = rect.get_property(&QName::new(Namespace::public(), "y").into(), activation)?;
let width =
rect.get_property(&QName::new(Namespace::public(), "width").into(), activation)?;
let height = rect.get_property(
&QName::new(Namespace::public(), "height").into(),
activation,
@ -752,22 +741,13 @@ pub fn to_string<'gc>(
) -> Result<Value<'gc>, Error> {
if let Some(this) = this {
let x = this
.get_property(
&QName::new(Namespace::public(), "x").into(),
activation,
)?
.get_property(&QName::new(Namespace::public(), "x").into(), activation)?
.coerce_to_string(activation)?;
let y = this
.get_property(
&QName::new(Namespace::public(), "y").into(),
activation,
)?
.get_property(&QName::new(Namespace::public(), "y").into(), activation)?
.coerce_to_string(activation)?;
let width = this
.get_property(
&QName::new(Namespace::public(), "width").into(),
activation,
)?
.get_property(&QName::new(Namespace::public(), "width").into(), activation)?
.coerce_to_string(activation)?;
let height = this
.get_property(

View File

@ -44,7 +44,7 @@ pub fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
function_proto.set_property_local(
&Multiname::public("apply"),
@ -56,10 +56,18 @@ pub fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
function_proto.set_local_property_is_enumerable(
activation.context.gc_context,
"call".into(),
false,
)?;
function_proto.set_local_property_is_enumerable(
activation.context.gc_context,
"apply".into(),
false,
)?;
function_proto.set_local_property_is_enumerable(activation.context.gc_context, "call".into(), false)?;
function_proto.set_local_property_is_enumerable(activation.context.gc_context, "apply".into(), false)?;
}
Ok(Value::Undefined)
}
@ -135,9 +143,9 @@ fn prototype<'gc>(
if let Some(this) = this {
if let Some(function) = this.as_function_object() {
if let Some(proto) = function.prototype() {
return Ok(proto.into())
return Ok(proto.into());
} else {
return Ok(Value::Undefined)
return Ok(Value::Undefined);
}
}
}
@ -174,10 +182,7 @@ pub fn create_class<'gc>(gc_context: MutationContext<'gc, '_>) -> GcCell<'gc, Cl
let mut write = function_class.write(gc_context);
// Fixed traits (in AS3 namespace)
const AS3_INSTANCE_METHODS: &[(&str, NativeMethodImpl)] = &[
("call", call),
("apply", apply),
];
const AS3_INSTANCE_METHODS: &[(&str, NativeMethodImpl)] = &[("call", call), ("apply", apply)];
write.define_as3_builtin_instance_methods(gc_context, AS3_INSTANCE_METHODS);
const PUBLIC_INSTANCE_PROPERTIES: &[(

View File

@ -67,7 +67,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
int_proto.set_property_local(
&Multiname::public("toFixed"),
@ -79,7 +79,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
int_proto.set_property_local(
&Multiname::public("toPrecision"),
@ -91,7 +91,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
int_proto.set_property_local(
&Multiname::public("toString"),
@ -103,7 +103,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
int_proto.set_property_local(
&Multiname::public("valueOf"),
@ -115,7 +115,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
int_proto.set_local_property_is_enumerable(gc_context, "toExponential".into(), false)?;

View File

@ -66,7 +66,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
number_proto.set_property_local(
&Multiname::public("toFixed"),
@ -78,7 +78,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
number_proto.set_property_local(
&Multiname::public("toPrecision"),
@ -90,7 +90,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
number_proto.set_property_local(
&Multiname::public("toString"),
@ -102,7 +102,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
number_proto.set_property_local(
&Multiname::public("valueOf"),
@ -114,7 +114,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
number_proto.set_local_property_is_enumerable(gc_context, "toExponential".into(), false)?;
number_proto.set_local_property_is_enumerable(gc_context, "toFixed".into(), false)?;

View File

@ -120,12 +120,28 @@ pub fn class_init<'gc>(
activation,
)?;
object_proto.set_local_property_is_enumerable(gc_context, "hasOwnProperty".into(), false)?;
object_proto.set_local_property_is_enumerable(gc_context, "propertyIsEnumerable".into(), false)?;
object_proto.set_local_property_is_enumerable(gc_context, "setPropertyIsEnumerable".into(), false)?;
object_proto.set_local_property_is_enumerable(
gc_context,
"hasOwnProperty".into(),
false,
)?;
object_proto.set_local_property_is_enumerable(
gc_context,
"propertyIsEnumerable".into(),
false,
)?;
object_proto.set_local_property_is_enumerable(
gc_context,
"setPropertyIsEnumerable".into(),
false,
)?;
object_proto.set_local_property_is_enumerable(gc_context, "isPrototypeOf".into(), false)?;
object_proto.set_local_property_is_enumerable(gc_context, "toString".into(), false)?;
object_proto.set_local_property_is_enumerable(gc_context, "toLocaleString".into(), false)?;
object_proto.set_local_property_is_enumerable(
gc_context,
"toLocaleString".into(),
false,
)?;
object_proto.set_local_property_is_enumerable(gc_context, "valueOf".into(), false)?;
}

View File

@ -94,8 +94,16 @@ pub fn class_init<'gc>(
activation,
)?;
qname_proto.set_local_property_is_enumerable(activation.context.gc_context, "toString".into(), false)?;
qname_proto.set_local_property_is_enumerable(activation.context.gc_context, "valueOf".into(), false)?;
qname_proto.set_local_property_is_enumerable(
activation.context.gc_context,
"toString".into(),
false,
)?;
qname_proto.set_local_property_is_enumerable(
activation.context.gc_context,
"valueOf".into(),
false,
)?;
Ok(Value::Undefined)
}

View File

@ -67,7 +67,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
uint_proto.set_property_local(
&Multiname::public("toFixed"),
@ -79,7 +79,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
uint_proto.set_property_local(
&Multiname::public("toPrecision"),
@ -91,7 +91,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
uint_proto.set_property_local(
&Multiname::public("toString"),
@ -103,7 +103,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
uint_proto.set_property_local(
&Multiname::public("valueOf"),
@ -115,7 +115,7 @@ fn class_init<'gc>(
Some(this_class),
)
.into(),
activation
activation,
)?;
uint_proto.set_local_property_is_enumerable(gc_context, "toExponential".into(), false)?;
uint_proto.set_local_property_is_enumerable(gc_context, "toFixed".into(), false)?;

View File

@ -170,7 +170,11 @@ pub fn specialized_class_init<'gc>(
.into(),
activation,
)?;
proto.set_local_property_is_enumerable(activation.context.gc_context, (*pubname).into(), false)?;
proto.set_local_property_is_enumerable(
activation.context.gc_context,
(*pubname).into(),
false,
)?;
}
}

View File

@ -8,12 +8,12 @@ use crate::avm2::domain::Domain;
use crate::avm2::events::{DispatchList, Event};
use crate::avm2::function::Executable;
use crate::avm2::names::{Multiname, Namespace, QName};
use crate::avm2::property::Property;
use crate::avm2::regexp::RegExp;
use crate::avm2::value::{Hint, Value};
use crate::avm2::vector::VectorStorage;
use crate::avm2::property::Property;
use crate::avm2::Error;
use crate::avm2::vtable::VTable;
use crate::avm2::Error;
use crate::backend::audio::{SoundHandle, SoundInstanceHandle};
use crate::bitmap::bitmap_data::BitmapData;
use crate::display_object::DisplayObject;
@ -141,14 +141,16 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
match self.vtable().and_then(|vtable| vtable.get_trait(multiname)) {
Some(Property::Slot{slot_id}) | Some(Property::ConstSlot{slot_id})
=> self.base().get_slot(slot_id),
Some(Property::Method{disp_id}) => {
Some(Property::Slot { slot_id }) | Some(Property::ConstSlot { slot_id }) => {
self.base().get_slot(slot_id)
}
Some(Property::Method { disp_id }) => {
if let Some(bound_method) = self.base().get_bound_method(disp_id) {
return Ok(bound_method.into());
}
let vtable = self.vtable().unwrap();
if let Some(bound_method) = vtable.make_bound_method(activation, self.into(), disp_id)
if let Some(bound_method) =
vtable.make_bound_method(activation, self.into(), disp_id)
{
self.install_bound_method(activation.context.gc_context, disp_id, bound_method);
Ok(bound_method.into())
@ -156,15 +158,13 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
Err("Method not found".into())
}
}
Some(Property::Virtual{get: Some(get), ..}) => {
Some(Property::Virtual { get: Some(get), .. }) => {
self.call_method(get, &[], activation)
}
Some(Property::Virtual{get: None, ..}) => {
Some(Property::Virtual { get: None, .. }) => {
Err("Illegal read of write-only property".into())
}
None => {
self.get_property_local(multiname, activation)
}
None => self.get_property_local(multiname, activation),
}
}
@ -197,22 +197,18 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
match self.vtable().and_then(|vtable| vtable.get_trait(multiname)) {
Some(Property::Slot{slot_id}) => self.base_mut(activation.context.gc_context).set_slot(slot_id, value, activation.context.gc_context),
Some(Property::ConstSlot{..}) => {
Err("Illegal write to read-only property".into())
}
Some(Property::Method{..}) => {
Err("Cannot assign to a method".into())
}
Some(Property::Virtual{set: Some(set), ..}) => {
Some(Property::Slot { slot_id }) => self
.base_mut(activation.context.gc_context)
.set_slot(slot_id, value, activation.context.gc_context),
Some(Property::ConstSlot { .. }) => Err("Illegal write to read-only property".into()),
Some(Property::Method { .. }) => Err("Cannot assign to a method".into()),
Some(Property::Virtual { set: Some(set), .. }) => {
self.call_method(set, &[value], activation).map(|_| ())
}
Some(Property::Virtual{set: None, ..}) => {
Some(Property::Virtual { set: None, .. }) => {
Err("Illegal write to read-only property".into())
}
None => {
self.set_property_local(multiname, value, activation)
}
None => self.set_property_local(multiname, value, activation),
}
}
@ -246,24 +242,20 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
match self.vtable().and_then(|vtable| vtable.get_trait(multiname)) {
Some(Property::Slot{slot_id}) | Some(Property::ConstSlot{slot_id})
=> self.base_mut(activation.context.gc_context).set_slot(slot_id, value, activation.context.gc_context),
Some(Property::Method{..}) => {
Err("Cannot assign to a method".into())
}
Some(Property::Virtual{set: Some(set), ..}) => {
Some(Property::Slot { slot_id }) | Some(Property::ConstSlot { slot_id }) => self
.base_mut(activation.context.gc_context)
.set_slot(slot_id, value, activation.context.gc_context),
Some(Property::Method { .. }) => Err("Cannot assign to a method".into()),
Some(Property::Virtual { set: Some(set), .. }) => {
self.call_method(set, &[value], activation).map(|_| ())
}
Some(Property::Virtual{set: None, ..}) => {
Some(Property::Virtual { set: None, .. }) => {
Err("Illegal write to read-only property".into())
}
None => {
self.init_property_local(multiname, value, activation)
}
None => self.init_property_local(multiname, value, activation),
}
}
/// Call a local property of the object. The Multiname should always be public.
///
/// This skips class field lookups and looks at:
@ -279,7 +271,9 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
// Note: normally this would just call into ScriptObjectData::call_property_local
// but because calling into ScriptObjectData borrows it for entire duration,
// we run a risk of a double borrow if the inner call borrows again.
let result = self.base().get_property_local(multiname, activation)?
let result = self
.base()
.get_property_local(multiname, activation)?
.coerce_to_object(activation)?;
result.call(Some(self.into()), arguments, activation)
}
@ -297,15 +291,16 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
match self.vtable().and_then(|vtable| vtable.get_trait(multiname)) {
Some(Property::Slot{slot_id}) | Some(Property::ConstSlot{slot_id}) => {
let obj = self.base().get_slot(slot_id)?
Some(Property::Slot { slot_id }) | Some(Property::ConstSlot { slot_id }) => {
let obj = self
.base()
.get_slot(slot_id)?
.coerce_to_object(activation)?;
obj.call(Some(self.into()), arguments, activation)
}
Some(Property::Method{disp_id}) => {
Some(Property::Method { disp_id }) => {
let vtable = self.vtable().unwrap();
if let Some((superclass, method)) = vtable.get_full_method(disp_id)
{
if let Some((superclass, method)) = vtable.get_full_method(disp_id) {
if !method.needs_arguments_object() {
let scope = superclass.unwrap().instance_scope();
Executable::from_method(method, scope, None, superclass).exec(
@ -318,25 +313,30 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
if let Some(bound_method) = self.base().get_bound_method(disp_id) {
return bound_method.call(Some(self.into()), arguments, activation);
}
let bound_method = vtable.make_bound_method(activation, self.into(), disp_id).unwrap();
self.install_bound_method(activation.context.gc_context, disp_id, bound_method);
let bound_method = vtable
.make_bound_method(activation, self.into(), disp_id)
.unwrap();
self.install_bound_method(
activation.context.gc_context,
disp_id,
bound_method,
);
bound_method.call(Some(self.into()), arguments, activation)
}
} else {
Err("Method not found".into())
}
},
Some(Property::Virtual{get: Some(get), ..}) => {
let obj = self.call_method(get, &[], activation)?
}
Some(Property::Virtual { get: Some(get), .. }) => {
let obj = self
.call_method(get, &[], activation)?
.coerce_to_object(activation)?;
obj.call(Some(self.into()), arguments, activation)
}
Some(Property::Virtual{get: None, ..}) => {
Some(Property::Virtual { get: None, .. }) => {
Err("Illegal read of write-only property".into())
}
None => {
self.call_property_local(multiname, arguments, activation)
}
None => self.call_property_local(multiname, arguments, activation),
}
}
@ -383,9 +383,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
) -> Result<Value<'gc>, Error> {
if self.base().get_bound_method(id).is_none() {
if let Some(vtable) = self.vtable() {
if let Some(bound_method) =
vtable.make_bound_method(activation, self.into(), id)
{
if let Some(bound_method) = vtable.make_bound_method(activation, self.into(), id) {
self.install_bound_method(activation.context.gc_context, id, bound_method);
}
}
@ -459,15 +457,17 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
) -> Result<bool, Error> {
match self.vtable().and_then(|vtable| vtable.get_trait(multiname)) {
None => {
if self.instance_of_class_definition()
if self
.instance_of_class_definition()
.map(|c| c.read().is_sealed())
.unwrap_or(false) {
.unwrap_or(false)
{
Ok(false)
} else {
self.delete_property_local(activation, multiname)
}
},
_ => Ok(false)
}
_ => Ok(false),
}
}
@ -578,7 +578,6 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
base.install_bound_method(disp_id, function)
}
/// Install a const trait on the global object.
/// This should only ever be called on the `global` object, during initialization.
fn install_const_late(
@ -587,16 +586,17 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
name: QName<'gc>,
value: Value<'gc>,
) {
let new_slot_id = self.vtable().unwrap().install_const_trait_late(mc, name, value.clone());
self.base_mut(mc).install_const_slot_late(new_slot_id, value);
let new_slot_id = self
.vtable()
.unwrap()
.install_const_trait_late(mc, name, value.clone());
self.base_mut(mc)
.install_const_slot_late(new_slot_id, value);
}
fn install_instance_slots(
&mut self,
activation: &mut Activation<'_, 'gc, '_>,
) {
self.base_mut(activation.context.gc_context).install_instance_slots();
fn install_instance_slots(&mut self, activation: &mut Activation<'_, 'gc, '_>) {
self.base_mut(activation.context.gc_context)
.install_instance_slots();
}
/// Call the object.

View File

@ -2,7 +2,7 @@
use crate::avm2::activation::Activation;
use crate::avm2::array::ArrayStorage;
use crate::avm2::names::{Multiname};
use crate::avm2::names::Multiname;
use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
use crate::avm2::value::Value;
@ -155,13 +155,20 @@ impl<'gc> TObject<'gc> for ArrayObject<'gc> {
if name.contains_public_namespace() {
if let Some(name) = name.local_name() {
if let Ok(index) = name.parse::<usize>() {
self.0.write(activation.context.gc_context).array.delete(index);
self.0
.write(activation.context.gc_context)
.array
.delete(index);
return Ok(true);
}
}
}
Ok(self.0.write(activation.context.gc_context).base.delete_property_local(name))
Ok(self
.0
.write(activation.context.gc_context)
.base
.delete_property_local(name))
}
fn has_own_property(self, name: &Multiname<'gc>) -> bool {

View File

@ -1,6 +1,6 @@
use crate::avm2::activation::Activation;
use crate::avm2::bytearray::ByteArrayStorage;
use crate::avm2::names::{Multiname};
use crate::avm2::names::Multiname;
use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
use crate::avm2::value::Value;
@ -153,13 +153,20 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
if name.contains_public_namespace() {
if let Some(name) = name.local_name() {
if let Ok(index) = name.parse::<usize>() {
self.0.write(activation.context.gc_context).storage.delete(index);
self.0
.write(activation.context.gc_context)
.storage
.delete(index);
return Ok(true);
}
}
}
Ok(self.0.write(activation.context.gc_context).base.delete_property_local(name))
Ok(self
.0
.write(activation.context.gc_context)
.base
.delete_property_local(name))
}
fn has_own_property(self, name: &Multiname<'gc>) -> bool {

View File

@ -4,7 +4,7 @@ use crate::avm2::activation::Activation;
use crate::avm2::class::{Allocator, AllocatorFn, Class};
use crate::avm2::function::Executable;
use crate::avm2::method::Method;
use crate::avm2::names::{QName};
use crate::avm2::names::QName;
use crate::avm2::object::function_object::FunctionObject;
use crate::avm2::object::script_object::{scriptobject_allocator, ScriptObjectData};
use crate::avm2::object::{Multiname, Object, ObjectPtr, TObject};
@ -101,7 +101,11 @@ impl<'gc> ClassObject<'gc> {
activation: &mut Activation<'_, 'gc, '_>,
superclass_object: Option<ClassObject<'gc>>,
) -> Result<Object<'gc>, Error> {
let proto = activation.avm2().classes().object.construct(activation, &[])?;
let proto = activation
.avm2()
.classes()
.object
.construct(activation, &[])?;
if let Some(superclass_object) = superclass_object {
let base_proto = superclass_object.prototype();
@ -244,7 +248,7 @@ impl<'gc> ClassObject<'gc> {
class.read().instance_traits(),
self.instance_scope(),
self.superclass_object().map(|cls| cls.instance_vtable()),
activation
activation,
)?;
// class vtable == class traits + Class instance traits
@ -253,7 +257,7 @@ impl<'gc> ClassObject<'gc> {
class.read().class_traits(),
self.class_scope(),
Some(self.instance_of().unwrap().instance_vtable()),
activation
activation,
)?;
self.link_interfaces(activation)?;
@ -265,7 +269,8 @@ impl<'gc> ClassObject<'gc> {
fn install_class_vtable_and_slots(&mut self, activation: &mut Activation<'_, 'gc, '_>) {
self.set_vtable(activation.context.gc_context, self.class_vtable());
self.base_mut(activation.context.gc_context).install_instance_slots();
self.base_mut(activation.context.gc_context)
.install_instance_slots();
}
/// Link this class to a prototype.
@ -278,12 +283,12 @@ impl<'gc> ClassObject<'gc> {
class_proto.set_property_local(
&Multiname::public("constructor"),
self.into(),
activation
activation,
)?;
class_proto.set_local_property_is_enumerable(
activation.context.gc_context,
"constructor".into(),
false
false,
)?;
Ok(())
@ -347,7 +352,7 @@ impl<'gc> ClassObject<'gc> {
self.instance_vtable().copy_property_for_interface(
activation.context.gc_context,
public_name,
interface_trait.name()
interface_trait.name(),
);
}
}
@ -533,9 +538,10 @@ impl<'gc> ClassObject<'gc> {
)
.into());
}
if let Some(Property::Method{disp_id, ..}) = property {
if let Some(Property::Method { disp_id, .. }) = property {
// todo: handle errors
let (superclass_object, method) = self.instance_vtable().get_full_method(disp_id).unwrap();
let (superclass_object, method) =
self.instance_vtable().get_full_method(disp_id).unwrap();
let scope = superclass_object.unwrap().class_scope();
let callee = FunctionObject::from_method(
activation,
@ -589,9 +595,13 @@ impl<'gc> ClassObject<'gc> {
)
.into());
}
if let Some(Property::Virtual{get: Some(disp_id), ..}) = property {
if let Some(Property::Virtual {
get: Some(disp_id), ..
}) = property
{
// todo: handle errors
let (superclass_object, method) = self.instance_vtable().get_full_method(disp_id).unwrap();
let (superclass_object, method) =
self.instance_vtable().get_full_method(disp_id).unwrap();
let scope = superclass_object.unwrap().class_scope();
let callee = FunctionObject::from_method(
activation,
@ -647,9 +657,13 @@ impl<'gc> ClassObject<'gc> {
)
.into());
}
if let Some(Property::Virtual{set: Some(disp_id), ..}) = property {
if let Some(Property::Virtual {
set: Some(disp_id), ..
}) = property
{
// todo: handle errors
let (superclass_object, method) = self.instance_vtable().get_full_method(disp_id).unwrap();
let (superclass_object, method) =
self.instance_vtable().get_full_method(disp_id).unwrap();
let scope = superclass_object.unwrap().class_scope();
let callee = FunctionObject::from_method(
activation,
@ -778,8 +792,7 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
fn has_own_property(self, name: &Multiname<'gc>) -> bool {
let read = self.0.read();
read.base.has_own_dynamic_property(name)
|| self.class_vtable().has_trait(name)
read.base.has_own_dynamic_property(name) || self.class_vtable().has_trait(name)
}
fn as_class_object(&self) -> Option<ClassObject<'gc>> {
@ -891,8 +904,10 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
Some(class_object),
parameterized_class.read().instance_traits(),
class_object.instance_scope(),
class_object.superclass_object().map(|cls| cls.instance_vtable()),
activation
class_object
.superclass_object()
.map(|cls| cls.instance_vtable()),
activation,
)?;
// class vtable == class traits + Class instance traits
@ -901,7 +916,7 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
parameterized_class.read().class_traits(),
class_object.class_scope(),
Some(class_object.instance_of().unwrap().instance_vtable()),
activation
activation,
)?;
class_object.link_prototype(activation, class_proto)?;

View File

@ -151,7 +151,11 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
Ok(FunctionObject(GcCell::allocate(
activation.context.gc_context,
// todo: should this be None?
FunctionObjectData { base, exec, prototype: None },
FunctionObjectData {
base,
exec,
prototype: None,
},
))
.into())
}

View File

@ -1,16 +1,16 @@
//! Default AVM2 object impl
use crate::avm2::activation::Activation;
use crate::avm2::names::{Multiname};
use crate::avm2::object::{FunctionObject, ClassObject, Object, ObjectPtr, TObject};
use crate::avm2::names::Multiname;
use crate::avm2::object::{ClassObject, FunctionObject, Object, ObjectPtr, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::vtable::VTable;
use crate::avm2::Error;
use crate::string::AvmString;
use fnv::FnvHashMap;
use std::collections::hash_map::Entry;
use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
use std::collections::hash_map::Entry;
use std::fmt::Debug;
/// A class instance allocator that allocates `ScriptObject`s.
@ -153,19 +153,19 @@ impl<'gc> ScriptObjectData<'gc> {
let value = self.values.get(&local_name);
if let Some(value) = value {
return Ok(value.clone());
} else {
if let Some(proto) = self.proto() {
return proto.get_property_local(multiname, activation);
}
}
}
// Special case: Unresolvable properties on dynamic classes are treated
// as dynamic properties that have not yet been set, and yield
// `undefined`
if self.instance_of()
if self
.instance_of()
.map(|cls| cls.inner_class_definition().read().is_sealed())
.unwrap_or(false)
{
@ -181,11 +181,14 @@ impl<'gc> ScriptObjectData<'gc> {
value: Value<'gc>,
_activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
if self.instance_of()
if self
.instance_of()
.map(|cls| cls.inner_class_definition().read().is_sealed())
.unwrap_or(false)
{
return Err(format!("Cannot set undefined property {:?}", multiname.local_name()).into());
return Err(
format!("Cannot set undefined property {:?}", multiname.local_name()).into(),
);
}
if !multiname.contains_public_namespace() {
@ -198,7 +201,9 @@ impl<'gc> ScriptObjectData<'gc> {
};
match self.values.entry(local_name) {
Entry::Occupied(mut o) => { o.insert(value); },
Entry::Occupied(mut o) => {
o.insert(value);
}
Entry::Vacant(v) => {
//TODO: Not all classes are dynamic like this
self.enumerants.push(local_name);
@ -281,11 +286,7 @@ impl<'gc> ScriptObjectData<'gc> {
/// Set a slot by its index. This does extend the array if needed.
/// This should only be used during AVM initialization, not at runtime.
pub fn install_const_slot_late(
&mut self,
id: u32,
value: Value<'gc>,
) {
pub fn install_const_slot_late(&mut self, id: u32, value: Value<'gc>) {
if self.slots.len() < id as usize + 1 {
self.slots.resize(id as usize + 1, Value::Undefined);
}
@ -348,10 +349,7 @@ impl<'gc> ScriptObjectData<'gc> {
// sentinel.
let true_index = (index as usize).checked_sub(1)?;
self.enumerants
.get(true_index)
.cloned()
.map(|q| q.into())
self.enumerants.get(true_index).cloned().map(|q| q.into())
}
pub fn property_is_enumerable(&self, name: AvmString<'gc>) -> bool {
@ -399,8 +397,6 @@ impl<'gc> ScriptObjectData<'gc> {
*self.bound_methods.get_mut(disp_id as usize).unwrap() = Some(function);
}
/// Get the class object for this object, if it has one.
pub fn instance_of(&self) -> Option<ClassObject<'gc>> {
self.instance_of

View File

@ -1,13 +1,13 @@
//! Vector storage object
use crate::avm2::activation::Activation;
use crate::avm2::names::{Multiname};
use crate::avm2::names::Multiname;
use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
use crate::avm2::value::Value;
use crate::string::AvmString;
use crate::avm2::vector::VectorStorage;
use crate::avm2::Error;
use crate::string::AvmString;
use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
@ -179,11 +179,16 @@ impl<'gc> TObject<'gc> for VectorObject<'gc> {
) -> Result<bool, Error> {
if name.contains_public_namespace()
&& name.local_name().is_some()
&& name.local_name().unwrap().parse::<usize>().is_ok() {
&& name.local_name().unwrap().parse::<usize>().is_ok()
{
return Ok(true);
}
Ok(self.0.write(activation.context.gc_context).base.delete_property_local(name))
Ok(self
.0
.write(activation.context.gc_context)
.base
.delete_property_local(name))
}
fn has_own_property(self, name: &Multiname<'gc>) -> bool {

View File

@ -5,19 +5,10 @@ use gc_arena::Collect;
#[derive(Debug, Collect, Clone, Copy)]
#[collect(require_static)]
pub enum Property {
Virtual {
get: Option<u32>,
set: Option<u32>,
},
Method {
disp_id: u32,
},
Slot {
slot_id: u32,
},
ConstSlot {
slot_id: u32,
},
Virtual { get: Option<u32>, set: Option<u32> },
Method { disp_id: u32 },
Slot { slot_id: u32 },
ConstSlot { slot_id: u32 },
}
impl Property {
@ -26,11 +17,17 @@ impl Property {
}
pub fn new_getter(disp_id: u32) -> Self {
Property::Virtual { get: Some(disp_id), set: None, }
Property::Virtual {
get: Some(disp_id),
set: None,
}
}
pub fn new_setter(disp_id: u32) -> Self {
Property::Virtual { get: None, set: Some(disp_id) }
Property::Virtual {
get: None,
set: Some(disp_id),
}
}
pub fn new_slot(slot_id: u32) -> Self {

View File

@ -2,7 +2,7 @@
use crate::avm2::activation::Activation;
use crate::avm2::domain::Domain;
use crate::avm2::names::{Multiname};
use crate::avm2::names::Multiname;
use crate::avm2::object::{Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
@ -198,7 +198,11 @@ impl<'gc> ScopeStack<'gc> {
/// The `global` parameter indicates whether we are on global$init (script initializer).
/// When the `global` parameter is true, the scope at depth 0 is considered the global scope, and is
/// searched for dynamic properties.
pub fn find(&self, multiname: &Multiname<'gc>, global: bool) -> Result<Option<Object<'gc>>, Error> {
pub fn find(
&self,
multiname: &Multiname<'gc>,
global: bool,
) -> Result<Option<Object<'gc>>, Error> {
for (depth, scope) in self.scopes.iter().enumerate().rev() {
let values = scope.values();

View File

@ -5,9 +5,9 @@ use crate::avm2::class::Class;
use crate::avm2::domain::Domain;
use crate::avm2::method::{BytecodeMethod, Method};
use crate::avm2::object::{Object, TObject};
use crate::avm2::scope::ScopeChain;
use crate::avm2::traits::Trait;
use crate::avm2::value::Value;
use crate::avm2::scope::ScopeChain;
use crate::avm2::{Avm2, Error};
use crate::context::UpdateContext;
use crate::string::AvmString;
@ -371,7 +371,6 @@ impl<'gc> Script<'gc> {
) -> Result<Object<'gc>, Error> {
let mut write = self.0.write(context.gc_context);
if !write.initialized {
write.initialized = true;

View File

@ -1,17 +1,16 @@
use crate::avm2::activation::Activation;
use crate::avm2::property_map::PropertyMap;
use crate::avm2::method::Method;
use crate::avm2::names::{Multiname, QName};
use crate::avm2::object::{ClassObject, FunctionObject, Object};
use crate::avm2::property::Property;
use crate::avm2::value::Value;
use crate::avm2::property_map::PropertyMap;
use crate::avm2::scope::ScopeChain;
use crate::avm2::traits::{Trait, TraitKind};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::avm2::method::Method;
use crate::avm2::names::{QName, Multiname};
use crate::avm2::object::{FunctionObject, ClassObject, Object};
use gc_arena::{Collect, GcCell, MutationContext};
use std::ops::DerefMut;
use std::cell::Ref;
use std::ops::DerefMut;
#[derive(Collect, Debug, Clone, Copy)]
#[collect(no_drop)]
@ -58,7 +57,12 @@ impl<'gc> VTable<'gc> {
}
pub fn get_method(self, disp_id: u32) -> Option<Method<'gc>> {
self.0.read().method_table.get(disp_id as usize).cloned().map(|x| x.1)
self.0
.read()
.method_table
.get(disp_id as usize)
.cloned()
.map(|x| x.1)
}
pub fn get_full_method(self, disp_id: u32) -> Option<(Option<ClassObject<'gc>>, Method<'gc>)> {
@ -82,7 +86,6 @@ impl<'gc> VTable<'gc> {
superclass_vtable: Option<Self>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
// Let's talk about slot_ids and disp_ids.
// Specification is one thing, but reality is another.
@ -106,7 +109,7 @@ impl<'gc> VTable<'gc> {
// You are only allowed to call `getslot` on the object if calling method,
// callee's class and all subclasses come from the same ABC (constant pool).
// (or class has no slots, but then `getslot` fails verification anyway as it's out-of-range)
//
//
// If class and superclass come from different ABC (constant pool) and superclass has slots,
// then subclass's slot_ids are ignored and assigned automatically.
// ignored, as in: even if trait's slot_id conflicts, it's not verified at all.
@ -134,11 +137,9 @@ impl<'gc> VTable<'gc> {
// so long-term it's still something we should verify.
// (and it's far from the only verification check we lack anyway)
let mut write = self.0.write(activation.context.gc_context);
let write = write.deref_mut();
write.defining_class = defining_class;
write.scope = Some(scope);
@ -148,64 +149,74 @@ impl<'gc> VTable<'gc> {
write.default_slots = superclass_vtable.0.read().default_slots.clone();
}
let (resolved_traits, method_table, default_slots) =
(&mut write.resolved_traits, &mut write.method_table, &mut write.default_slots);
let (resolved_traits, method_table, default_slots) = (
&mut write.resolved_traits,
&mut write.method_table,
&mut write.default_slots,
);
for trait_data in traits {
match trait_data.kind() {
TraitKind::Method { method, .. } => {
let entry = (defining_class, method.clone());
match resolved_traits.get(trait_data.name()) {
Some(Property::Method{disp_id, ..}) => {
Some(Property::Method { disp_id, .. }) => {
let disp_id = *disp_id as usize;
method_table[disp_id] = entry;
},
}
// note: ideally overwriting other property types
// should be a VerifyError
_ => {
let disp_id = method_table.len() as u32;
method_table.push(entry);
resolved_traits.insert(trait_data.name(), Property::new_method(disp_id));
resolved_traits
.insert(trait_data.name(), Property::new_method(disp_id));
}
}
}
TraitKind::Getter { method, .. } => {
let entry = (defining_class, method.clone());
match resolved_traits.get_mut(trait_data.name()) {
Some(Property::Virtual{get: Some(disp_id), ..}) => {
Some(Property::Virtual {
get: Some(disp_id), ..
}) => {
let disp_id = *disp_id as usize;
method_table[disp_id] = entry;
},
Some(Property::Virtual{get, ..}) => {
}
Some(Property::Virtual { get, .. }) => {
let disp_id = method_table.len() as u32;
*get = Some(disp_id);
method_table.push(entry);
},
}
_ => {
let disp_id = method_table.len() as u32;
method_table.push(entry);
resolved_traits.insert(trait_data.name(), Property::new_getter(disp_id));
resolved_traits
.insert(trait_data.name(), Property::new_getter(disp_id));
}
}
},
}
TraitKind::Setter { method, .. } => {
let entry = (defining_class, method.clone());
match resolved_traits.get_mut(trait_data.name()) {
Some(Property::Virtual{set: Some(disp_id), ..}) => {
Some(Property::Virtual {
set: Some(disp_id), ..
}) => {
method_table[*disp_id as usize] = entry;
},
Some(Property::Virtual{set, ..}) => {
}
Some(Property::Virtual { set, .. }) => {
let disp_id = method_table.len() as u32;
method_table.push(entry);
*set = Some(disp_id);
},
}
_ => {
let disp_id = method_table.len() as u32;
method_table.push(entry);
resolved_traits.insert(trait_data.name(), Property::new_setter(disp_id));
resolved_traits
.insert(trait_data.name(), Property::new_setter(disp_id));
}
}
},
}
TraitKind::Slot { slot_id, .. }
| TraitKind::Const { slot_id, .. }
| TraitKind::Function { slot_id, .. }
@ -217,7 +228,7 @@ impl<'gc> VTable<'gc> {
let new_slot_id = if slot_id == 0 {
default_slots.push(value);
default_slots.len()as u32 - 1
default_slots.len() as u32 - 1
} else {
if let Some(Some(_)) = default_slots.get(slot_id as usize) {
// slot_id conflict
@ -233,10 +244,12 @@ impl<'gc> VTable<'gc> {
} as u32;
let new_prop = match trait_data.kind() {
TraitKind::Slot{..} | TraitKind::Function{..}
=> Property::new_slot(new_slot_id),
TraitKind::Const{..} | TraitKind::Class {..}
=> Property::new_const_slot(new_slot_id),
TraitKind::Slot { .. } | TraitKind::Function { .. } => {
Property::new_slot(new_slot_id)
}
TraitKind::Const { .. } | TraitKind::Class { .. } => {
Property::new_const_slot(new_slot_id)
}
_ => unreachable!(),
};
@ -245,11 +258,9 @@ impl<'gc> VTable<'gc> {
}
}
Ok(())
}
/// Retrieve a bound instance method suitable for use as a value.
///
/// This returns the bound method object itself, as well as it's dispatch
@ -268,15 +279,13 @@ impl<'gc> VTable<'gc> {
) -> Option<FunctionObject<'gc>> {
if let Some((superclass, method)) = self.get_full_method(disp_id) {
let scope = self.0.read().scope.unwrap();
Some(
FunctionObject::from_method(
activation,
method,
scope,
Some(receiver),
superclass,
),
)
Some(FunctionObject::from_method(
activation,
method,
scope,
Some(receiver),
superclass,
))
} else {
None
}
@ -295,7 +304,9 @@ impl<'gc> VTable<'gc> {
write.default_slots.push(Some(value));
let new_slot_id = write.default_slots.len() as u32 - 1;
write.resolved_traits.insert(name, Property::new_slot(new_slot_id));
write
.resolved_traits
.insert(name, Property::new_slot(new_slot_id));
new_slot_id
}
@ -316,7 +327,6 @@ impl<'gc> VTable<'gc> {
write.resolved_traits.insert(interface_name, prop);
}
}
}
fn trait_to_default_value<'gc>(
@ -328,14 +338,11 @@ fn trait_to_default_value<'gc>(
TraitKind::Slot { default_value, .. } => default_value.clone(),
TraitKind::Const { default_value, .. } => default_value.clone(),
TraitKind::Function { function, .. } => {
FunctionObject::from_function(
activation,
function.clone(),
scope,
).unwrap().into()
FunctionObject::from_function(activation, function.clone(), scope)
.unwrap()
.into()
}
TraitKind::Class { .. } => Value::Undefined,
_ => unreachable!()
_ => unreachable!(),
}
}

View File

@ -1189,8 +1189,7 @@ impl<'gc> MovieClip<'gc> {
if let Avm2Value::Object(c) = child.object2() {
let name = Avm2QName::new(Avm2Namespace::public(), child.name());
let mut activation = Avm2Activation::from_nothing(context.reborrow());
if let Err(e) = p.init_property(&name.into(), c.into(), &mut activation)
{
if let Err(e) = p.init_property(&name.into(), c.into(), &mut activation) {
log::error!(
"Got error when setting AVM2 child named \"{}\": {}",
&child.name(),