diff --git a/Cargo.lock b/Cargo.lock index a6ad8673a..c546aa987 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1395,8 +1395,7 @@ dependencies = [ [[package]] name = "gc-arena" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7262a3f0bd866ed41d13f7a5147d5fe2278f6860aeab66bd72e9f2f770fc3e8" +source = "git+https://github.com/ruffle-rs/gc-arena#4931b3bc25b2b74174ff5eb9c34ae0dda732778b" dependencies = [ "gc-arena-derive", ] @@ -1404,8 +1403,7 @@ dependencies = [ [[package]] name = "gc-arena-derive" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a1fd9d509709237f7673fe8fa4a2fcf8136bf5bd43b67bab6af267a9850524" +source = "git+https://github.com/ruffle-rs/gc-arena#4931b3bc25b2b74174ff5eb9c34ae0dda732778b" dependencies = [ "proc-macro2", "quote", diff --git a/core/Cargo.toml b/core/Cargo.toml index 4feb5343f..97cbba947 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0" bitstream-io = "1.0.0" flate2 = "1.0.20" fnv = "1.0.7" -gc-arena = "0.2.0" -gc-arena-derive = "0.2.0" +gc-arena = { git = "https://github.com/ruffle-rs/gc-arena" } +gc-arena-derive = { git = "https://github.com/ruffle-rs/gc-arena" } generational-arena = "0.2.8" gif = "0.11.1" indexmap = "1.6.1" diff --git a/core/src/avm1.rs b/core/src/avm1.rs index 6ebd1c503..ff0873597 100644 --- a/core/src/avm1.rs +++ b/core/src/avm1.rs @@ -2,7 +2,7 @@ use crate::avm1::globals::create_globals; use crate::avm1::object::{search_prototype, stage_object}; use crate::context::UpdateContext; use crate::prelude::*; -use gc_arena::{GcCell, MutationContext}; +use gc_arena::{Collect, GcCell, MutationContext}; use swf::avm1::read::Reader; @@ -76,6 +76,8 @@ macro_rules! avm_error { ) } +#[derive(Collect)] +#[collect(no_drop)] pub struct Avm1<'gc> { /// The Flash Player version we're emulating. player_version: u8, @@ -119,22 +121,6 @@ pub struct Avm1<'gc> { pub debug_output: bool, } -unsafe impl<'gc> gc_arena::Collect for Avm1<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - self.globals.trace(cc); - self.constant_pool.trace(cc); - //self.system_listeners.trace(cc); - self.prototypes.trace(cc); - self.display_properties.trace(cc); - self.stack.trace(cc); - - for register in &self.registers { - register.trace(cc); - } - } -} - impl<'gc> Avm1<'gc> { pub fn new(gc_context: MutationContext<'gc, '_>, player_version: u8) -> Self { let (prototypes, globals, broadcaster_functions) = create_globals(gc_context); diff --git a/core/src/avm1/globals/date.rs b/core/src/avm1/globals/date.rs index a97e68248..a16ccd105 100644 --- a/core/src/avm1/globals/date.rs +++ b/core/src/avm1/globals/date.rs @@ -77,18 +77,13 @@ macro_rules! implement_utc_getters { }; } +#[derive(Collect)] +#[collect(require_static)] enum YearType { Full, Adjust(Box i64>), } -unsafe impl Collect for YearType { - #[inline] - fn needs_trace() -> bool { - false - } -} - impl YearType { fn adjust(&self, year: i64) -> i64 { match self { diff --git a/core/src/avm1/object/date_object.rs b/core/src/avm1/object/date_object.rs index 497d110bd..0f29b4c11 100644 --- a/core/src/avm1/object/date_object.rs +++ b/core/src/avm1/object/date_object.rs @@ -10,20 +10,17 @@ use std::fmt; #[collect(no_drop)] pub struct DateObject<'gc>(GcCell<'gc, DateObjectData<'gc>>); +#[derive(Collect)] +#[collect(no_drop)] pub struct DateObjectData<'gc> { /// The underlying script object. base: ScriptObject<'gc>, /// The DateTime represented by this object + #[collect(require_static)] date_time: Option>, } -unsafe impl<'gc> Collect for DateObjectData<'gc> { - fn trace(&self, cc: gc_arena::CollectionContext) { - self.base.trace(cc); - } -} - impl fmt::Debug for DateObject<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let this = self.0.read(); diff --git a/core/src/avm1/object/script_object.rs b/core/src/avm1/object/script_object.rs index 1ebc0109a..ee8fcf344 100644 --- a/core/src/avm1/object/script_object.rs +++ b/core/src/avm1/object/script_object.rs @@ -72,6 +72,8 @@ impl<'gc> Watcher<'gc> { #[collect(no_drop)] pub struct ScriptObject<'gc>(GcCell<'gc, ScriptObjectData<'gc>>); +#[derive(Collect)] +#[collect(no_drop)] pub struct ScriptObjectData<'gc> { prototype: Option>, values: PropertyMap>, @@ -81,16 +83,6 @@ pub struct ScriptObjectData<'gc> { watchers: PropertyMap>, } -unsafe impl<'gc> Collect for ScriptObjectData<'gc> { - fn trace(&self, cc: gc_arena::CollectionContext) { - self.prototype.trace(cc); - self.values.trace(cc); - self.array.trace(cc); - self.interfaces.trace(cc); - self.watchers.trace(cc); - } -} - impl fmt::Debug for ScriptObjectData<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Object") diff --git a/core/src/avm1/object/sound_object.rs b/core/src/avm1/object/sound_object.rs index 71bf4be03..a9b441a67 100644 --- a/core/src/avm1/object/sound_object.rs +++ b/core/src/avm1/object/sound_object.rs @@ -14,6 +14,8 @@ use std::fmt; #[collect(no_drop)] pub struct SoundObject<'gc>(GcCell<'gc, SoundObjectData<'gc>>); +#[derive(Collect)] +#[collect(no_drop)] pub struct SoundObjectData<'gc> { /// The underlying script object. /// @@ -22,9 +24,11 @@ pub struct SoundObjectData<'gc> { base: ScriptObject<'gc>, /// The sound that is attached to this object. + #[collect(require_static)] sound: Option, /// The instance of the last played sound on this object. + #[collect(require_static)] sound_instance: Option, /// Sounds in AVM1 are tied to a specific movie clip. @@ -37,13 +41,6 @@ pub struct SoundObjectData<'gc> { duration: u32, } -unsafe impl<'gc> Collect for SoundObjectData<'gc> { - fn trace(&self, cc: gc_arena::CollectionContext) { - self.base.trace(cc); - self.owner.trace(cc); - } -} - impl fmt::Debug for SoundObject<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let this = self.0.read(); diff --git a/core/src/avm1/property.rs b/core/src/avm1/property.rs index eea711b66..9e1983aa3 100644 --- a/core/src/avm1/property.rs +++ b/core/src/avm1/property.rs @@ -4,10 +4,13 @@ use crate::avm1::object::Object; use crate::avm1::Value; use bitflags::bitflags; use core::fmt; +use gc_arena::Collect; bitflags! { /// Attributes of properties in the AVM runtime. /// The values are significant and should match the order used by `object::as_set_prop_flags`. + #[derive(Collect)] + #[collect(require_static)] pub struct Attribute: u8 { const DONT_ENUM = 1 << 0; const DONT_DELETE = 1 << 1; @@ -16,7 +19,8 @@ bitflags! { } #[allow(clippy::large_enum_variant)] -#[derive(Clone)] +#[derive(Clone, Collect)] +#[collect(no_drop)] pub enum Property<'gc> { Virtual { get: Object<'gc>, @@ -108,18 +112,6 @@ impl<'gc> Property<'gc> { } } -unsafe impl<'gc> gc_arena::Collect for Property<'gc> { - fn trace(&self, cc: gc_arena::CollectionContext) { - match self { - Property::Virtual { get, set, .. } => { - get.trace(cc); - set.trace(cc); - } - Property::Stored { value, .. } => value.trace(cc), - } - } -} - impl fmt::Debug for Property<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { diff --git a/core/src/avm1/scope.rs b/core/src/avm1/scope.rs index 518601b87..43dd2750f 100644 --- a/core/src/avm1/scope.rs +++ b/core/src/avm1/scope.rs @@ -5,11 +5,12 @@ use crate::avm1::callable_value::CallableValue; use crate::avm1::error::Error; use crate::avm1::property::Attribute; use crate::avm1::{Object, ScriptObject, TObject, Value}; -use gc_arena::{GcCell, MutationContext}; +use gc_arena::{Collect, GcCell, MutationContext}; use std::cell::Ref; /// Indicates what kind of scope a scope is. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Collect)] +#[collect(require_static)] pub enum ScopeClass { /// Scope represents global scope. Global, @@ -28,21 +29,14 @@ pub enum ScopeClass { } /// Represents a scope chain for an AVM1 activation. -#[derive(Debug)] +#[derive(Debug, Collect)] +#[collect(no_drop)] pub struct Scope<'gc> { parent: Option>>, class: ScopeClass, values: Object<'gc>, } -unsafe impl<'gc> gc_arena::Collect for Scope<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - self.parent.trace(cc); - self.values.trace(cc); - } -} - impl<'gc> Scope<'gc> { /// Construct a global scope (one without a parent). pub fn from_global_object(globals: Object<'gc>) -> Scope<'gc> { diff --git a/core/src/avm1/value.rs b/core/src/avm1/value.rs index 30cf8f554..630948041 100644 --- a/core/src/avm1/value.rs +++ b/core/src/avm1/value.rs @@ -6,9 +6,11 @@ use crate::ecma_conversions::{ f64_to_string, f64_to_wrapping_i16, f64_to_wrapping_i32, f64_to_wrapping_u16, f64_to_wrapping_u32, }; +use gc_arena::Collect; use std::borrow::Cow; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Collect)] +#[collect(no_drop)] #[allow(dead_code)] pub enum Value<'gc> { Undefined, @@ -94,16 +96,6 @@ impl<'gc> From for Value<'gc> { } } -unsafe impl<'gc> gc_arena::Collect for Value<'gc> { - fn trace(&self, cc: gc_arena::CollectionContext) { - match self { - Value::String(string) => string.trace(cc), - Value::Object(object) => object.trace(cc), - _ => {} - } - } -} - impl PartialEq for Value<'_> { fn eq(&self, other: &Self) -> bool { match (self, other) { diff --git a/core/src/avm2/property.rs b/core/src/avm2/property.rs index bdb44c0d0..de6b061be 100644 --- a/core/src/avm2/property.rs +++ b/core/src/avm2/property.rs @@ -5,12 +5,14 @@ use crate::avm2::return_value::ReturnValue; use crate::avm2::value::Value; use crate::avm2::Error; use bitflags::bitflags; -use gc_arena::{Collect, CollectionContext}; +use gc_arena::Collect; bitflags! { /// Attributes of properties in the AVM runtime. /// /// TODO: Replace with AVM2 properties for traits + #[derive(Collect)] + #[collect(require_static)] pub struct Attribute: u8 { const DONT_DELETE = 1 << 0; const READ_ONLY = 1 << 1; @@ -18,7 +20,8 @@ bitflags! { } #[allow(clippy::large_enum_variant)] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] pub enum Property<'gc> { Virtual { get: Option>, @@ -35,19 +38,6 @@ pub enum Property<'gc> { }, } -unsafe impl<'gc> Collect for Property<'gc> { - fn trace(&self, cc: CollectionContext) { - match self { - Property::Virtual { get, set, .. } => { - get.trace(cc); - set.trace(cc); - } - Property::Stored { value, .. } => value.trace(cc), - Property::Slot { .. } => {} - } - } -} - impl<'gc> Property<'gc> { /// Create a new stored property. pub fn new_stored(value: impl Into>) -> Self { diff --git a/core/src/avm2/slot.rs b/core/src/avm2/slot.rs index 6d61a1ff1..3007bdaea 100644 --- a/core/src/avm2/slot.rs +++ b/core/src/avm2/slot.rs @@ -3,10 +3,11 @@ use crate::avm2::property::Attribute; use crate::avm2::value::Value; use crate::avm2::Error; -use gc_arena::{Collect, CollectionContext}; +use gc_arena::Collect; /// Represents a single slot on an object. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] pub enum Slot<'gc> { /// An unoccupied slot. /// @@ -23,15 +24,6 @@ pub enum Slot<'gc> { }, } -unsafe impl<'gc> Collect for Slot<'gc> { - fn trace(&self, cc: CollectionContext) { - match self { - Self::Unoccupied => {} - Self::Occupied { value, .. } => value.trace(cc), - } - } -} - impl<'gc> Default for Slot<'gc> { fn default() -> Self { Self::Unoccupied diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 015e5a9fa..fd5c295a2 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -6,7 +6,7 @@ use crate::{ }, }; use downcast_rs::Downcast; -use gc_arena::{Collect, CollectionContext}; +use gc_arena::Collect; use generational_arena::{Arena, Index}; pub mod decoders; @@ -165,6 +165,8 @@ impl Default for NullAudioBackend { } } +#[derive(Collect)] +#[collect(no_drop)] pub struct AudioManager<'gc> { /// The list of actively playing sounds. sounds: Vec>, @@ -370,20 +372,16 @@ impl<'gc> Default for AudioManager<'gc> { } } -unsafe impl<'gc> Collect for AudioManager<'gc> { - fn trace(&self, cc: CollectionContext) { - for sound in &self.sounds { - sound.trace(cc); - } - } -} -#[derive(Clone)] +#[derive(Clone, Collect)] +#[collect(no_drop)] pub struct SoundInstance<'gc> { /// The handle to the sound instance in the audio backend. + #[collect(require_static)] instance: SoundInstanceHandle, /// The handle to the sound definition in the audio backend. /// This will be `None` for stream sounds. + #[collect(require_static)] sound: Option, /// The display object that this sound is playing in, if any. @@ -394,13 +392,6 @@ pub struct SoundInstance<'gc> { pub avm1_object: Option>, } -unsafe impl<'gc> Collect for SoundInstance<'gc> { - fn trace(&self, cc: CollectionContext) { - self.display_object.trace(cc); - self.avm1_object.trace(cc); - } -} - /// A sound transform for a playing sound, for use by audio backends. /// This differs from `display_object::SoundTranform` by being /// already converted to `f32` and having `volume` baked in. diff --git a/core/src/character.rs b/core/src/character.rs index 3363a18d0..e968281f6 100644 --- a/core/src/character.rs +++ b/core/src/character.rs @@ -3,8 +3,10 @@ use crate::display_object::{ Bitmap, Button, EditText, Graphic, MorphShape, MovieClip, Text, Video, }; use crate::font::Font; +use gc_arena::Collect; -#[derive(Clone)] +#[derive(Clone, Collect)] +#[collect(no_drop)] pub enum Character<'gc> { EditText(EditText<'gc>), Graphic(Graphic<'gc>), @@ -14,24 +16,6 @@ pub enum Character<'gc> { Font(Font<'gc>), MorphShape(MorphShape<'gc>), Text(Text<'gc>), - Sound(SoundHandle), + Sound(#[collect(require_static)] SoundHandle), Video(Video<'gc>), } - -unsafe impl<'gc> gc_arena::Collect for Character<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - match self { - Character::EditText(c) => c.trace(cc), - Character::Graphic(c) => c.trace(cc), - Character::MovieClip(c) => c.trace(cc), - Character::Bitmap(c) => c.trace(cc), - Character::Button(c) => c.trace(cc), - Character::Font(c) => c.trace(cc), - Character::MorphShape(c) => c.trace(cc), - Character::Text(c) => c.trace(cc), - Character::Sound(c) => c.trace(cc), - Character::Video(c) => c.trace(cc), - } - } -} diff --git a/core/src/context.rs b/core/src/context.rs index 2a83cfbed..572819135 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -291,6 +291,8 @@ impl<'a, 'gc, 'gc_context> UpdateContext<'a, 'gc, 'gc_context> { } /// A queued ActionScript call. +#[derive(Collect)] +#[collect(no_drop)] pub struct QueuedActions<'gc> { /// The movie clip this ActionScript is running on. pub clip: DisplayObject<'gc>, @@ -302,14 +304,6 @@ pub struct QueuedActions<'gc> { pub is_unload: bool, } -unsafe impl<'gc> Collect for QueuedActions<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - self.clip.trace(cc); - self.action_type.trace(cc); - } -} - /// Action and gotos need to be queued up to execute at the end of the frame. pub struct ActionQueue<'gc> { /// Each priority is kept in a separate bucket. @@ -400,7 +394,8 @@ pub struct RenderContext<'a, 'gc> { } /// The type of action being run. -#[derive(Clone)] +#[derive(Clone, Collect)] +#[collect(no_drop)] pub enum ActionType<'gc> { /// Normal frame or event actions. Normal { bytecode: SwfSlice }, @@ -494,22 +489,3 @@ impl fmt::Debug for ActionType<'_> { } } } - -unsafe impl<'gc> Collect for ActionType<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - match self { - ActionType::Construct { constructor, .. } => { - constructor.trace(cc); - } - ActionType::Method { object, args, .. } => { - object.trace(cc); - args.trace(cc); - } - ActionType::NotifyListeners { args, .. } => { - args.trace(cc); - } - _ => {} - } - } -} diff --git a/core/src/display_object.rs b/core/src/display_object.rs index 857d4537a..15228b607 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -42,7 +42,8 @@ pub use movie_clip::{MovieClip, Scene}; pub use text::Text; pub use video::Video; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] pub struct DisplayObjectBase<'gc> { parent: Option>, place_frame: u16, @@ -105,17 +106,6 @@ impl<'gc> Default for DisplayObjectBase<'gc> { } } -unsafe impl<'gc> Collect for DisplayObjectBase<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - self.parent.trace(cc); - self.prev_sibling.trace(cc); - self.next_sibling.trace(cc); - self.masker.trace(cc); - self.maskee.trace(cc); - } -} - #[allow(dead_code)] impl<'gc> DisplayObjectBase<'gc> { /// Reset all properties that would be adjusted by a movie load. @@ -1491,7 +1481,8 @@ bitflags! { /// Every value is a percentage (0-100), but out of range values are allowed. /// In AVM1, this is returned by `Sound.getTransform`. /// In AVM2, this is returned by `Sprite.soundTransform`. -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Collect)] +#[collect(require_static)] pub struct SoundTransform { pub volume: i32, pub left_to_left: i32, diff --git a/core/src/display_object/button.rs b/core/src/display_object/button.rs index 899dac940..a16a27b0d 100644 --- a/core/src/display_object/button.rs +++ b/core/src/display_object/button.rs @@ -18,7 +18,8 @@ use swf::ButtonActionCondition; #[collect(no_drop)] pub struct Button<'gc>(GcCell<'gc, ButtonData<'gc>>); -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] pub struct ButtonData<'gc> { base: DisplayObjectBase<'gc>, static_data: GcCell<'gc, ButtonStatic>, @@ -567,20 +568,8 @@ impl<'gc> ButtonData<'gc> { } } -unsafe impl<'gc> gc_arena::Collect for ButtonData<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - self.container.trace(cc); - for child in self.hit_area.values() { - child.trace(cc); - } - self.base.trace(cc); - self.static_data.trace(cc); - self.object.trace(cc); - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Collect)] +#[collect(require_static)] #[allow(dead_code)] enum ButtonState { Up, @@ -595,7 +584,8 @@ struct ButtonAction { key_code: Option, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Collect)] +#[collect(require_static)] enum ButtonTracking { Push, Menu, @@ -603,7 +593,8 @@ enum ButtonTracking { /// Static data shared between all instances of a button. #[allow(dead_code)] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(require_static)] struct ButtonStatic { swf: Arc, id: CharacterId, @@ -616,10 +607,3 @@ struct ButtonStatic { down_to_over_sound: Option, over_to_up_sound: Option, } - -unsafe impl gc_arena::Collect for ButtonStatic { - #[inline] - fn needs_trace() -> bool { - false - } -} diff --git a/core/src/display_object/edit_text.rs b/core/src/display_object/edit_text.rs index f7adbef75..c162f952a 100644 --- a/core/src/display_object/edit_text.rs +++ b/core/src/display_object/edit_text.rs @@ -1625,7 +1625,8 @@ struct EditTextStatic { swf: Arc, text: EditTextStaticData, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Collect)] +#[collect(require_static)] struct EditTextStaticData { id: CharacterId, bounds: swf::Rectangle, @@ -1649,25 +1650,13 @@ struct EditTextStaticData { is_device_font: bool, } -unsafe impl<'gc> Collect for EditTextStaticData { - fn needs_trace() -> bool { - false - } -} - -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Collect)] +#[collect(require_static)] pub struct TextSelection { from: usize, to: usize, } -unsafe impl Collect for TextSelection { - #[inline] - fn needs_trace() -> bool { - false - } -} - impl TextSelection { pub fn for_position(position: usize) -> Self { Self { diff --git a/core/src/display_object/graphic.rs b/core/src/display_object/graphic.rs index bdbe1e1fc..80eda1789 100644 --- a/core/src/display_object/graphic.rs +++ b/core/src/display_object/graphic.rs @@ -11,7 +11,8 @@ use std::sync::Arc; #[collect(no_drop)] pub struct Graphic<'gc>(GcCell<'gc, GraphicData<'gc>>); -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] pub struct GraphicData<'gc> { base: DisplayObjectBase<'gc>, static_data: gc_arena::Gc<'gc, GraphicStatic>, @@ -97,25 +98,13 @@ impl<'gc> TDisplayObject<'gc> for Graphic<'gc> { } } -unsafe impl<'gc> gc_arena::Collect for GraphicData<'gc> { - fn trace(&self, cc: gc_arena::CollectionContext) { - self.base.trace(cc); - self.static_data.trace(cc); - } -} - /// Static data shared between all instances of a graphic. #[allow(dead_code)] +#[derive(Collect)] +#[collect(require_static)] struct GraphicStatic { id: CharacterId, shape: swf::Shape, render_handle: ShapeHandle, bounds: BoundingBox, } - -unsafe impl<'gc> gc_arena::Collect for GraphicStatic { - #[inline] - fn needs_trace() -> bool { - false - } -} diff --git a/core/src/display_object/morph_shape.rs b/core/src/display_object/morph_shape.rs index 7df7dd76c..1e3848a3d 100644 --- a/core/src/display_object/morph_shape.rs +++ b/core/src/display_object/morph_shape.rs @@ -12,7 +12,8 @@ use swf::Twips; #[collect(no_drop)] pub struct MorphShape<'gc>(GcCell<'gc, MorphShapeData<'gc>>); -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] pub struct MorphShapeData<'gc> { base: DisplayObjectBase<'gc>, static_data: Gc<'gc, MorphShapeStatic>, @@ -96,14 +97,6 @@ impl<'gc> TDisplayObject<'gc> for MorphShape<'gc> { } } -unsafe impl<'gc> gc_arena::Collect for MorphShapeData<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - self.base.trace(cc); - self.static_data.trace(cc); - } -} - /// A precalculated intermediate frame for a morph shape. struct Frame { shape_handle: ShapeHandle, @@ -113,6 +106,8 @@ struct Frame { /// Static data shared between all instances of a morph shape. #[allow(dead_code)] +#[derive(Collect)] +#[collect(require_static)] pub struct MorphShapeStatic { id: CharacterId, start: swf::MorphShape, @@ -307,13 +302,6 @@ impl MorphShapeStatic { } } -unsafe impl<'gc> gc_arena::Collect for MorphShapeStatic { - #[inline] - fn needs_trace() -> bool { - false - } -} - // Interpolation functions // These interpolate between two SWF shape structures. // a + b should = 1.0 diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 987143c3a..d153c8c93 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -47,12 +47,14 @@ type FrameNumber = u16; #[collect(no_drop)] pub struct MovieClip<'gc>(GcCell<'gc, MovieClipData<'gc>>); -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] pub struct MovieClipData<'gc> { base: DisplayObjectBase<'gc>, static_data: Gc<'gc, MovieClipStatic>, tag_stream_pos: u64, current_frame: FrameNumber, + #[collect(require_static)] audio_stream: Option, container: ChildContainer<'gc>, object: Option>, @@ -68,18 +70,6 @@ pub struct MovieClipData<'gc> { use_hand_cursor: bool, } -unsafe impl<'gc> Collect for MovieClipData<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - self.container.trace(cc); - self.base.trace(cc); - self.static_data.trace(cc); - self.object.trace(cc); - self.avm2_constructor.trace(cc); - self.frame_scripts.trace(cc); - } -} - impl<'gc> MovieClip<'gc> { #[allow(dead_code)] pub fn new(swf: SwfSlice, gc_context: MutationContext<'gc, '_>) -> Self { @@ -3204,6 +3194,8 @@ impl<'a> GotoPlaceObject<'a> { bitflags! { /// Boolean state flags used by `MovieClip`. + #[derive(Collect)] + #[collect(require_static)] struct MovieClipFlags: u8 { /// Whether this `MovieClip` has run its initial frame. const INITIALIZED = 1 << 0; @@ -3221,7 +3213,8 @@ bitflags! { /// Actions that are attached to a `MovieClip` event in /// an `onClipEvent`/`on` handler. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Collect)] +#[collect(require_static)] pub struct ClipAction { /// The event that triggers this handler. event: ClipEvent, diff --git a/core/src/display_object/text.rs b/core/src/display_object/text.rs index b9aa8c868..520123b09 100644 --- a/core/src/display_object/text.rs +++ b/core/src/display_object/text.rs @@ -12,7 +12,8 @@ use std::sync::Arc; #[collect(no_drop)] pub struct Text<'gc>(GcCell<'gc, TextData<'gc>>); -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] pub struct TextData<'gc> { base: DisplayObjectBase<'gc>, static_data: gc_arena::Gc<'gc, TextStatic>, @@ -194,17 +195,10 @@ impl<'gc> TDisplayObject<'gc> for Text<'gc> { } } -unsafe impl<'gc> gc_arena::Collect for TextData<'gc> { - #[inline] - fn trace(&self, cc: gc_arena::CollectionContext) { - self.base.trace(cc); - self.static_data.trace(cc); - } -} - /// Static data shared between all instances of a text object. #[allow(dead_code)] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Collect)] +#[collect(require_static)] struct TextStatic { swf: Arc, id: CharacterId, @@ -212,10 +206,3 @@ struct TextStatic { text_transform: Matrix, text_blocks: Vec, } - -unsafe impl<'gc> gc_arena::Collect for TextStatic { - #[inline] - fn needs_trace() -> bool { - false - } -} diff --git a/core/src/external.rs b/core/src/external.rs index c9f4ba87c..d2c3ef2d5 100644 --- a/core/src/external.rs +++ b/core/src/external.rs @@ -7,7 +7,7 @@ use crate::avm1::{ AvmString as Avm1String, Object as Avm1Object, ScriptObject as Avm1ScriptObject, }; use crate::context::UpdateContext; -use gc_arena::{Collect, CollectionContext}; +use gc_arena::Collect; use std::collections::BTreeMap; /// An intermediate format of representing shared data between ActionScript and elsewhere. @@ -252,19 +252,14 @@ where } } -#[derive(Default)] +#[derive(Default, Collect)] +#[collect(no_drop)] pub struct ExternalInterface<'gc> { + #[collect(require_static)] providers: Vec>, callbacks: BTreeMap>, } -unsafe impl Collect for ExternalInterface<'_> { - #[inline] - fn trace(&self, cc: CollectionContext) { - self.callbacks.trace(cc); - } -} - impl<'gc> ExternalInterface<'gc> { pub fn new() -> Self { Self::default() diff --git a/core/src/loader.rs b/core/src/loader.rs index adf502f45..12859d02b 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -259,7 +259,8 @@ impl<'gc> Default for LoadManager<'gc> { } /// The completion status of a `Loader` loading a movie. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Collect)] +#[collect(require_static)] pub enum LoaderStatus { /// The movie hasn't been loaded yet. Pending, @@ -270,16 +271,20 @@ pub enum LoaderStatus { } /// A struct that holds garbage-collected pointers for asynchronous code. +#[derive(Collect)] +#[collect(no_drop)] pub enum Loader<'gc> { /// Loader that is loading the root movie of a player. RootMovie { /// The handle to refer to this loader instance. + #[collect(require_static)] self_handle: Option, }, /// Loader that is loading a new movie into a movieclip. Movie { /// The handle to refer to this loader instance. + #[collect(require_static)] self_handle: Option, /// The target movie clip to load the movie into. @@ -303,6 +308,7 @@ pub enum Loader<'gc> { /// Loader that is loading form data into an AVM1 object scope. Form { /// The handle to refer to this loader instance. + #[collect(require_static)] self_handle: Option, /// The target AVM1 object to load form data into. @@ -312,6 +318,7 @@ pub enum Loader<'gc> { /// Loader that is loading form data into an AVM1 LoadVars object. LoadVars { /// The handle to refer to this loader instance. + #[collect(require_static)] self_handle: Option, /// The target AVM1 object to load form data into. @@ -321,6 +328,7 @@ pub enum Loader<'gc> { /// Loader that is loading XML data into an XML tree. Xml { /// The handle to refer to this loader instance. + #[collect(require_static)] self_handle: Option, /// The active movie clip at the time of load invocation. @@ -336,25 +344,6 @@ pub enum Loader<'gc> { }, } -unsafe impl<'gc> Collect for Loader<'gc> { - fn trace(&self, cc: CollectionContext) { - match self { - Loader::RootMovie { .. } => {} - Loader::Movie { - target_clip, - target_broadcaster, - .. - } => { - target_clip.trace(cc); - target_broadcaster.trace(cc); - } - Loader::Form { target_object, .. } => target_object.trace(cc), - Loader::LoadVars { target_object, .. } => target_object.trace(cc), - Loader::Xml { target_node, .. } => target_node.trace(cc), - } - } -} - impl<'gc> Loader<'gc> { /// Set the loader handle for this loader. /// diff --git a/core/src/player.rs b/core/src/player.rs index c07aafadd..b868c2443 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -1491,19 +1491,17 @@ impl Player { } } +#[derive(Collect)] +#[collect(no_drop)] pub struct DragObject<'gc> { /// The display object being dragged. pub display_object: DisplayObject<'gc>, /// The offset from the mouse position to the center of the clip. + #[collect(require_static)] pub offset: (Twips, Twips), /// The bounding rectangle where the clip will be maintained. + #[collect(require_static)] pub constraint: BoundingBox, } - -unsafe impl<'gc> gc_arena::Collect for DragObject<'gc> { - fn trace(&self, cc: gc_arena::CollectionContext) { - self.display_object.trace(cc); - } -} diff --git a/core/src/xml/error.rs b/core/src/xml/error.rs index b268758e1..79df2ee61 100644 --- a/core/src/xml/error.rs +++ b/core/src/xml/error.rs @@ -1,6 +1,6 @@ //! Error types used in XML handling -use gc_arena::{Collect, CollectionContext}; +use gc_arena::Collect; use quick_xml::Error as QXError; use std::error::Error as StdError; use std::fmt::Error as FmtError; @@ -77,14 +77,10 @@ impl From for Error { /// We can't clone `quick_xml` errors, nor can we clone several of the error /// types it wraps over, so this creates an RC boxed version of the error that /// can then be used elsewhere. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(require_static)] pub struct ParseError(Rc); -unsafe impl Collect for ParseError { - /// ParseError does not contain GC pointers. - fn trace(&self, _cc: CollectionContext<'_>) {} -} - impl ParseError { ///Convert a quick_xml error into a `ParseError`. pub fn from_quickxml_error(err: QXError) -> Self {