chore: cargo fmt
This commit is contained in:
parent
3d8f611651
commit
0fb075a309
|
@ -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
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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: &[(
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Reference in New Issue