diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 6edb32657..f1d18ed09 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -1389,7 +1389,7 @@ impl<'gc> Object<'gc> { Self::XmlListObject(o) => WeakObject::XmlListObject(XmlListObjectWeak(GcCell::downgrade(o.0))), Self::RegExpObject(o) => WeakObject::RegExpObject(RegExpObjectWeak(Gc::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(Gc::downgrade(o.0))), Self::ClassObject(o) => WeakObject::ClassObject(ClassObjectWeak(Gc::downgrade(o.0))), Self::VectorObject(o) => WeakObject::VectorObject(VectorObjectWeak(Gc::downgrade(o.0))), Self::SoundObject(o) => WeakObject::SoundObject(SoundObjectWeak(Gc::downgrade(o.0))), diff --git a/core/src/avm2/object/loaderinfo_object.rs b/core/src/avm2/object/loaderinfo_object.rs index ef10e80bb..2559ec11f 100644 --- a/core/src/avm2/object/loaderinfo_object.rs +++ b/core/src/avm2/object/loaderinfo_object.rs @@ -13,8 +13,12 @@ use crate::display_object::{DisplayObject, TDisplayObject}; use crate::loader::ContentType; use crate::tag_utils::SwfMovie; use core::fmt; -use gc_arena::{Collect, GcCell, GcWeakCell, Mutation}; -use std::cell::{Ref, RefMut}; +use gc_arena::barrier::unlock; +use gc_arena::{ + lock::{Lock, RefLock}, + Collect, Gc, GcWeak, Mutation, +}; +use std::cell::{Cell, Ref, RefMut}; use std::sync::Arc; /// ActionScript cannot construct a LoaderInfo. Note that LoaderInfo isn't a final class. @@ -70,16 +74,16 @@ impl<'gc> LoaderStream<'gc> { /// resource. #[derive(Collect, Clone, Copy)] #[collect(no_drop)] -pub struct LoaderInfoObject<'gc>(pub GcCell<'gc, LoaderInfoObjectData<'gc>>); +pub struct LoaderInfoObject<'gc>(pub Gc<'gc, LoaderInfoObjectData<'gc>>); #[derive(Collect, Clone, Copy, Debug)] #[collect(no_drop)] -pub struct LoaderInfoObjectWeak<'gc>(pub GcWeakCell<'gc, LoaderInfoObjectData<'gc>>); +pub struct LoaderInfoObjectWeak<'gc>(pub GcWeak<'gc, LoaderInfoObjectData<'gc>>); impl fmt::Debug for LoaderInfoObject<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("LoaderInfoObject") - .field("ptr", &self.0.as_ptr()) + .field("ptr", &Gc::as_ptr(self.0)) .finish() } } @@ -88,18 +92,18 @@ impl fmt::Debug for LoaderInfoObject<'_> { #[collect(no_drop)] pub struct LoaderInfoObjectData<'gc> { /// All normal script data. - base: ScriptObjectData<'gc>, + base: RefLock>, /// The loaded stream that this gets its info from. - loaded_stream: Option>, + loaded_stream: RefLock>, loader: Option>, /// Whether or not we've fired our 'init' event - init_event_fired: bool, + init_event_fired: Cell, /// Whether or not we've fired our 'complete' event - complete_event_fired: bool, + complete_event_fired: Cell, /// The `EventDispatcher` used for `LoaderInfo.sharedEvents`. // FIXME: If we ever implement sandboxing, then ensure that we allow @@ -108,14 +112,13 @@ pub struct LoaderInfoObjectData<'gc> { uncaught_error_events: Object<'gc>, - cached_avm1movie: Option>, + cached_avm1movie: Lock>>, - #[collect(require_static)] - content_type: ContentType, + content_type: Cell, - expose_content: bool, + expose_content: Cell, - errored: bool, + errored: Cell, } impl<'gc> LoaderInfoObject<'gc> { @@ -127,17 +130,17 @@ impl<'gc> LoaderInfoObject<'gc> { loader: Option>, ) -> Result, Error<'gc>> { let class = activation.avm2().classes().loaderinfo; - let base = ScriptObjectData::new(class); - let loaded_stream = Some(LoaderStream::Swf(movie, root)); + let base = ScriptObjectData::new(class).into(); + let loaded_stream = LoaderStream::Swf(movie, root); - let this: Object<'gc> = LoaderInfoObject(GcCell::new( + let this: Object<'gc> = LoaderInfoObject(Gc::new( activation.context.gc_context, LoaderInfoObjectData { base, - loaded_stream, + loaded_stream: RefLock::new(loaded_stream), loader, - init_event_fired: false, - complete_event_fired: false, + init_event_fired: Cell::new(false), + complete_event_fired: Cell::new(false), shared_events: activation .context .avm2 @@ -150,10 +153,10 @@ impl<'gc> LoaderInfoObject<'gc> { .classes() .uncaughterrorevents .construct(activation, &[])?, - cached_avm1movie: None, - content_type: ContentType::Swf, - expose_content: false, - errored: false, + cached_avm1movie: Lock::new(None), + content_type: Cell::new(ContentType::Swf), + expose_content: Cell::new(false), + errored: Cell::new(false), }, )) .into(); @@ -176,16 +179,16 @@ impl<'gc> LoaderInfoObject<'gc> { is_stage: bool, ) -> Result, Error<'gc>> { let class = activation.avm2().classes().loaderinfo; - let base = ScriptObjectData::new(class); + let base = ScriptObjectData::new(class).into(); - let this: Object<'gc> = LoaderInfoObject(GcCell::new( + let this: Object<'gc> = LoaderInfoObject(Gc::new( activation.context.gc_context, LoaderInfoObjectData { base, - loaded_stream: Some(LoaderStream::NotYetLoaded(movie, root_clip, is_stage)), + loaded_stream: RefLock::new(LoaderStream::NotYetLoaded(movie, root_clip, is_stage)), loader, - init_event_fired: false, - complete_event_fired: false, + init_event_fired: Cell::new(false), + complete_event_fired: Cell::new(false), shared_events: activation .context .avm2 @@ -198,10 +201,10 @@ impl<'gc> LoaderInfoObject<'gc> { .classes() .uncaughterrorevents .construct(activation, &[])?, - cached_avm1movie: None, - content_type: ContentType::Unknown, - expose_content: false, - errored: false, + cached_avm1movie: Lock::new(None), + content_type: Cell::new(ContentType::Unknown), + expose_content: Cell::new(false), + errored: Cell::new(false), }, )) .into(); @@ -213,45 +216,43 @@ impl<'gc> LoaderInfoObject<'gc> { } pub fn loader(&self) -> Option> { - return self.0.read().loader; + self.0.loader } pub fn shared_events(&self) -> Object<'gc> { - return self.0.read().shared_events; + self.0.shared_events } pub fn uncaught_error_events(&self) -> Object<'gc> { - return self.0.read().uncaught_error_events; + self.0.uncaught_error_events } /// Gets the `ContentType`, 'hiding' it by returning `ContentType::Unknown` /// if we haven't yet fired the 'init' event. The real ContentType first becomes /// visible to ActionScript in the 'init' event. pub fn content_type_hide_before_init(&self) -> ContentType { - if self.0.read().init_event_fired { - self.0.read().content_type + if self.0.init_event_fired.get() { + self.0.content_type.get() } else { ContentType::Unknown } } - pub fn set_errored(&self, val: bool, mc: &Mutation<'gc>) { - self.0.write(mc).errored = val; + pub fn set_errored(&self, val: bool, _mc: &Mutation<'gc>) { + self.0.errored.set(val); } pub fn errored(&self) -> bool { - self.0.read().errored + self.0.errored.get() } pub fn init_event_fired(&self) -> bool { - self.0.read().init_event_fired + self.0.init_event_fired.get() } - pub fn reset_init_and_complete_events(&self, mc: &Mutation<'gc>) { - let mut write = self.0.write(mc); - - write.init_event_fired = false; - write.complete_event_fired = false; + pub fn reset_init_and_complete_events(&self, _mc: &Mutation<'gc>) { + self.0.init_event_fired.set(false); + self.0.complete_event_fired.set(false); } pub fn fire_init_and_complete_events( @@ -260,9 +261,9 @@ impl<'gc> LoaderInfoObject<'gc> { status: u16, redirected: bool, ) { - self.0.write(context.gc_context).expose_content = true; - if !self.0.read().init_event_fired { - self.0.write(context.gc_context).init_event_fired = true; + self.0.expose_content.set(true); + if !self.0.init_event_fired.get() { + self.0.init_event_fired.set(true); // TODO - 'init' should be fired earlier during the download. // Right now, we fire it when downloading is fully completed. @@ -270,11 +271,11 @@ impl<'gc> LoaderInfoObject<'gc> { Avm2::dispatch_event(context, init_evt, (*self).into()); } - if !self.0.read().complete_event_fired { + if !self.0.complete_event_fired.get() { // NOTE: We have to check load progress here because this function // is called unconditionally at the end of every frame. - let (should_complete, from_url) = match self.0.read().loaded_stream { - Some(LoaderStream::Swf(ref movie, root)) => ( + let (should_complete, from_url) = match &*self.0.loaded_stream.borrow() { + LoaderStream::Swf(ref movie, root) => ( root.as_movie_clip() .map(|mc| mc.loaded_bytes() as i32 >= mc.total_bytes()) .unwrap_or(true), @@ -305,7 +306,7 @@ impl<'gc> LoaderInfoObject<'gc> { Avm2::dispatch_event(context, http_status_evt, (*self).into()); } - self.0.write(context.gc_context).complete_event_fired = true; + self.0.complete_event_fired.set(true); let complete_evt = EventObject::bare_default_event(context, "complete"); Avm2::dispatch_event(context, complete_evt, (*self).into()); } @@ -314,32 +315,26 @@ impl<'gc> LoaderInfoObject<'gc> { /// Unwrap this object's loader stream pub fn as_loader_stream(&self) -> Option>> { - if self.0.read().loaded_stream.is_some() { - Some(Ref::map(self.0.read(), |v: &LoaderInfoObjectData<'gc>| { - v.loaded_stream.as_ref().unwrap() - })) - } else { - None - } + Some(self.0.loaded_stream.borrow()) } pub fn expose_content(&self) -> bool { - self.0.read().expose_content + self.0.expose_content.get() } /// Makes the 'content' visible to ActionScript. /// This is used by certain special loaders (the stage and root movie), /// which expose the loaded content before the 'init' event is fired. - pub fn set_expose_content(&self, mc: &Mutation<'gc>) { - self.0.write(mc).expose_content = true; + pub fn set_expose_content(&self, _mc: &Mutation<'gc>) { + self.0.expose_content.set(true); } pub fn set_loader_stream(&self, stream: LoaderStream<'gc>, mc: &Mutation<'gc>) { - self.0.write(mc).loaded_stream = Some(stream); + *unlock!(Gc::write(mc, self.0), LoaderInfoObjectData, loaded_stream).borrow_mut() = stream; } - pub fn set_content_type(&self, content_type: ContentType, mc: &Mutation<'gc>) { - self.0.write(mc).content_type = content_type; + pub fn set_content_type(&self, content_type: ContentType, _mc: &Mutation<'gc>) { + self.0.content_type.set(content_type); } /// Returns the AVM1Movie corresponding to the loaded movie- if @@ -349,7 +344,7 @@ impl<'gc> LoaderInfoObject<'gc> { activation: &mut Activation<'_, 'gc>, obj: DisplayObject<'gc>, ) -> Object<'gc> { - let cached_avm1movie = self.0.read().cached_avm1movie; + let cached_avm1movie = self.0.cached_avm1movie.get(); if cached_avm1movie.is_none() { let class_object = activation.avm2().classes().avm1movie; let object = StageObject::for_display_object(activation, obj, class_object) @@ -359,10 +354,15 @@ impl<'gc> LoaderInfoObject<'gc> { .call_native_init(object.into(), &[], activation) .expect("Native init should succeed"); - self.0.write(activation.context.gc_context).cached_avm1movie = Some(object.into()); + unlock!( + Gc::write(activation.context.gc_context, self.0), + LoaderInfoObjectData, + cached_avm1movie + ) + .set(Some(object.into())); } - return self.0.read().cached_avm1movie.unwrap(); + self.0.cached_avm1movie.get().unwrap() } pub fn unload(&self, activation: &mut Activation<'_, 'gc>) { @@ -375,7 +375,6 @@ impl<'gc> LoaderInfoObject<'gc> { let loader = self .0 - .read() .loader .expect("LoaderInfo must have been created by Loader"); @@ -391,15 +390,15 @@ impl<'gc> LoaderInfoObject<'gc> { impl<'gc> TObject<'gc> for LoaderInfoObject<'gc> { fn base(&self) -> Ref> { - Ref::map(self.0.read(), |read| &read.base) + self.0.base.borrow() } fn base_mut(&self, mc: &Mutation<'gc>) -> RefMut> { - RefMut::map(self.0.write(mc), |write| &mut write.base) + unlock!(Gc::write(mc, self.0), LoaderInfoObjectData, base).borrow_mut() } fn as_ptr(&self) -> *const ObjectPtr { - self.0.as_ptr() as *const ObjectPtr + Gc::as_ptr(self.0) as *const ObjectPtr } fn value_of(&self, _mc: &Mutation<'gc>) -> Result, Error<'gc>> {