avm2: Use `Gc` instead of `GcCell` in `ByteArrayObject`

This commit is contained in:
Lord-McSweeney 2024-07-04 09:33:31 +03:00 committed by Lord-McSweeney
parent a5d2b613ac
commit 313c384d41
3 changed files with 58 additions and 48 deletions

View File

@ -83,8 +83,7 @@ pub enum ObjectEncoding {
Amf3 = 3, Amf3 = 3,
} }
#[derive(Clone, Collect, Debug)] #[derive(Clone, Debug)]
#[collect(no_drop)]
pub struct ByteArrayStorage { pub struct ByteArrayStorage {
/// Underlying ByteArray /// Underlying ByteArray
bytes: Vec<u8>, bytes: Vec<u8>,

View File

@ -1388,7 +1388,7 @@ impl<'gc> Object<'gc> {
Self::XmlObject(o) => WeakObject::XmlObject(XmlObjectWeak(GcCell::downgrade(o.0))), Self::XmlObject(o) => WeakObject::XmlObject(XmlObjectWeak(GcCell::downgrade(o.0))),
Self::XmlListObject(o) => WeakObject::XmlListObject(XmlListObjectWeak(GcCell::downgrade(o.0))), Self::XmlListObject(o) => WeakObject::XmlListObject(XmlListObjectWeak(GcCell::downgrade(o.0))),
Self::RegExpObject(o) => WeakObject::RegExpObject(RegExpObjectWeak(GcCell::downgrade(o.0))), Self::RegExpObject(o) => WeakObject::RegExpObject(RegExpObjectWeak(GcCell::downgrade(o.0))),
Self::ByteArrayObject(o) => WeakObject::ByteArrayObject(ByteArrayObjectWeak(GcCell::downgrade(o.0))), Self::ByteArrayObject(o) => WeakObject::ByteArrayObject(ByteArrayObjectWeak(Gc::downgrade(o.0))),
Self::LoaderInfoObject(o) => WeakObject::LoaderInfoObject(LoaderInfoObjectWeak(GcCell::downgrade(o.0))), Self::LoaderInfoObject(o) => WeakObject::LoaderInfoObject(LoaderInfoObjectWeak(GcCell::downgrade(o.0))),
Self::ClassObject(o) => WeakObject::ClassObject(ClassObjectWeak(GcCell::downgrade(o.0))), Self::ClassObject(o) => WeakObject::ClassObject(ClassObjectWeak(GcCell::downgrade(o.0))),
Self::VectorObject(o) => WeakObject::VectorObject(VectorObjectWeak(GcCell::downgrade(o.0))), Self::VectorObject(o) => WeakObject::VectorObject(VectorObjectWeak(GcCell::downgrade(o.0))),

View File

@ -7,8 +7,9 @@ use crate::avm2::Error;
use crate::avm2::Multiname; use crate::avm2::Multiname;
use crate::character::Character; use crate::character::Character;
use core::fmt; use core::fmt;
use gc_arena::{Collect, GcCell, GcWeakCell, Mutation}; use gc_arena::barrier::unlock;
use std::cell::{Ref, RefMut}; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation};
use std::cell::{Ref, RefCell, RefMut};
/// A class instance allocator that allocates ByteArray objects. /// A class instance allocator that allocates ByteArray objects.
pub fn byte_array_allocator<'gc>( pub fn byte_array_allocator<'gc>(
@ -38,27 +39,30 @@ pub fn byte_array_allocator<'gc>(
unreachable!("A ByteArray subclass should have ByteArray in superclass chain") unreachable!("A ByteArray subclass should have ByteArray in superclass chain")
}); });
let base = ScriptObjectData::new(class); let base = ScriptObjectData::new(class).into();
Ok(ByteArrayObject(GcCell::new( Ok(ByteArrayObject(Gc::new(
activation.context.gc_context, activation.context.gc_context,
ByteArrayObjectData { base, storage }, ByteArrayObjectData {
base,
storage: RefCell::new(storage),
},
)) ))
.into()) .into())
} }
#[derive(Clone, Collect, Copy)] #[derive(Clone, Collect, Copy)]
#[collect(no_drop)] #[collect(no_drop)]
pub struct ByteArrayObject<'gc>(pub GcCell<'gc, ByteArrayObjectData<'gc>>); pub struct ByteArrayObject<'gc>(pub Gc<'gc, ByteArrayObjectData<'gc>>);
#[derive(Clone, Collect, Copy, Debug)] #[derive(Clone, Collect, Copy, Debug)]
#[collect(no_drop)] #[collect(no_drop)]
pub struct ByteArrayObjectWeak<'gc>(pub GcWeakCell<'gc, ByteArrayObjectData<'gc>>); pub struct ByteArrayObjectWeak<'gc>(pub GcWeak<'gc, ByteArrayObjectData<'gc>>);
impl fmt::Debug for ByteArrayObject<'_> { impl fmt::Debug for ByteArrayObject<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ByteArrayObject") f.debug_struct("ByteArrayObject")
.field("ptr", &self.0.as_ptr()) .field("ptr", &Gc::as_ptr(self.0))
.finish() .finish()
} }
} }
@ -67,9 +71,9 @@ impl fmt::Debug for ByteArrayObject<'_> {
#[collect(no_drop)] #[collect(no_drop)]
pub struct ByteArrayObjectData<'gc> { pub struct ByteArrayObjectData<'gc> {
/// Base script object /// Base script object
base: ScriptObjectData<'gc>, base: RefLock<ScriptObjectData<'gc>>,
storage: ByteArrayStorage, storage: RefCell<ByteArrayStorage>,
} }
impl<'gc> ByteArrayObject<'gc> { impl<'gc> ByteArrayObject<'gc> {
@ -78,13 +82,13 @@ impl<'gc> ByteArrayObject<'gc> {
bytes: ByteArrayStorage, bytes: ByteArrayStorage,
) -> Result<Object<'gc>, Error<'gc>> { ) -> Result<Object<'gc>, Error<'gc>> {
let class = activation.avm2().classes().bytearray; let class = activation.avm2().classes().bytearray;
let base = ScriptObjectData::new(class); let base = ScriptObjectData::new(class).into();
let instance: Object<'gc> = ByteArrayObject(GcCell::new( let instance: Object<'gc> = ByteArrayObject(Gc::new(
activation.context.gc_context, activation.context.gc_context,
ByteArrayObjectData { ByteArrayObjectData {
base, base,
storage: bytes, storage: RefCell::new(bytes),
}, },
)) ))
.into(); .into();
@ -96,21 +100,21 @@ impl<'gc> ByteArrayObject<'gc> {
} }
pub fn storage(&self) -> Ref<ByteArrayStorage> { pub fn storage(&self) -> Ref<ByteArrayStorage> {
Ref::map(self.0.read(), |d| &d.storage) self.0.storage.borrow()
} }
} }
impl<'gc> TObject<'gc> for ByteArrayObject<'gc> { impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
fn base(&self) -> Ref<ScriptObjectData<'gc>> { fn base(&self) -> Ref<ScriptObjectData<'gc>> {
Ref::map(self.0.read(), |read| &read.base) self.0.base.borrow()
} }
fn base_mut(&self, mc: &Mutation<'gc>) -> RefMut<ScriptObjectData<'gc>> { fn base_mut(&self, mc: &Mutation<'gc>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base) unlock!(Gc::write(mc, self.0), ByteArrayObjectData, base).borrow_mut()
} }
fn as_ptr(&self) -> *const ObjectPtr { fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr Gc::as_ptr(self.0) as *const ObjectPtr
} }
fn get_property_local( fn get_property_local(
@ -118,8 +122,6 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
name: &Multiname<'gc>, name: &Multiname<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc>,
) -> Result<Value<'gc>, Error<'gc>> { ) -> Result<Value<'gc>, Error<'gc>> {
let read = self.0.read();
if name.contains_public_namespace() { if name.contains_public_namespace() {
if let Some(name) = name.local_name() { if let Some(name) = name.local_name() {
if let Ok(index) = name.parse::<usize>() { if let Ok(index) = name.parse::<usize>() {
@ -128,15 +130,15 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
} }
} }
read.base.get_property_local(name, activation) self.0.base.borrow().get_property_local(name, activation)
} }
fn get_index_property(self, index: usize) -> Option<Value<'gc>> { fn get_index_property(self, index: usize) -> Option<Value<'gc>> {
let read = self.0.read();
// ByteArrays never forward to base even for out-of-bounds access. // ByteArrays never forward to base even for out-of-bounds access.
Some( Some(
read.storage self.0
.storage
.borrow()
.get(index) .get(index)
.map_or(Value::Undefined, |val| Value::Integer(val as i32)), .map_or(Value::Undefined, |val| Value::Integer(val as i32)),
) )
@ -148,13 +150,12 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc>,
) -> Result<(), Error<'gc>> { ) -> Result<(), Error<'gc>> {
let mut write = self.0.write(activation.context.gc_context);
if name.contains_public_namespace() { if name.contains_public_namespace() {
if let Some(name) = name.local_name() { if let Some(name) = name.local_name() {
if let Ok(index) = name.parse::<usize>() { if let Ok(index) = name.parse::<usize>() {
write self.0
.storage .storage
.borrow_mut()
.set(index, value.coerce_to_u32(activation)? as u8); .set(index, value.coerce_to_u32(activation)? as u8);
return Ok(()); return Ok(());
@ -162,7 +163,13 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
} }
} }
write.base.set_property_local(name, value, activation) unlock!(
Gc::write(activation.context.gc_context, self.0),
ByteArrayObjectData,
base
)
.borrow_mut()
.set_property_local(name, value, activation)
} }
fn init_property_local( fn init_property_local(
@ -171,13 +178,12 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc>,
) -> Result<(), Error<'gc>> { ) -> Result<(), Error<'gc>> {
let mut write = self.0.write(activation.context.gc_context);
if name.contains_public_namespace() { if name.contains_public_namespace() {
if let Some(name) = name.local_name() { if let Some(name) = name.local_name() {
if let Ok(index) = name.parse::<usize>() { if let Ok(index) = name.parse::<usize>() {
write self.0
.storage .storage
.borrow_mut()
.set(index, value.coerce_to_u32(activation)? as u8); .set(index, value.coerce_to_u32(activation)? as u8);
return Ok(()); return Ok(());
@ -185,7 +191,13 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
} }
} }
write.base.init_property_local(name, value, activation) unlock!(
Gc::write(activation.context.gc_context, self.0),
ByteArrayObjectData,
base
)
.borrow_mut()
.init_property_local(name, value, activation)
} }
fn delete_property_local( fn delete_property_local(
@ -196,19 +208,18 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
if name.contains_public_namespace() { if name.contains_public_namespace() {
if let Some(name) = name.local_name() { if let Some(name) = name.local_name() {
if let Ok(index) = name.parse::<usize>() { if let Ok(index) = name.parse::<usize>() {
self.0 self.0.storage.borrow_mut().delete(index);
.write(activation.context.gc_context)
.storage
.delete(index);
return Ok(true); return Ok(true);
} }
} }
} }
Ok(self Ok(unlock!(
.0 Gc::write(activation.context.gc_context, self.0),
.write(activation.context.gc_context) ByteArrayObjectData,
.base base
)
.borrow_mut()
.delete_property_local(name)) .delete_property_local(name))
} }
@ -216,12 +227,12 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
if name.contains_public_namespace() { if name.contains_public_namespace() {
if let Some(name) = name.local_name() { if let Some(name) = name.local_name() {
if let Ok(index) = name.parse::<usize>() { if let Ok(index) = name.parse::<usize>() {
return self.0.read().storage.get(index).is_some(); return self.0.storage.borrow().get(index).is_some();
} }
} }
} }
self.0.read().base.has_own_property(name) self.0.base.borrow().has_own_property(name)
} }
fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> { fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
@ -229,11 +240,11 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
} }
fn as_bytearray(&self) -> Option<Ref<ByteArrayStorage>> { fn as_bytearray(&self) -> Option<Ref<ByteArrayStorage>> {
Some(Ref::map(self.0.read(), |d| &d.storage)) Some(self.0.storage.borrow())
} }
fn as_bytearray_mut(&self, mc: &Mutation<'gc>) -> Option<RefMut<ByteArrayStorage>> { fn as_bytearray_mut(&self, _mc: &Mutation<'gc>) -> Option<RefMut<ByteArrayStorage>> {
Some(RefMut::map(self.0.write(mc), |d| &mut d.storage)) Some(self.0.storage.borrow_mut())
} }
fn as_bytearray_object(&self) -> Option<ByteArrayObject<'gc>> { fn as_bytearray_object(&self) -> Option<ByteArrayObject<'gc>> {