diff --git a/core/src/avm2.rs b/core/src/avm2.rs index 4eb9a9d38..20e37b013 100644 --- a/core/src/avm2.rs +++ b/core/src/avm2.rs @@ -100,7 +100,7 @@ impl<'gc> Avm2<'gc> { let mut read = Reader::new(abc.as_ref()); let abc_file = Rc::new(read.read()?); - let tunit = TranslationUnit::from_abc(abc_file); + let tunit = TranslationUnit::from_abc(abc_file, context.gc_context); for i in (0..abc_file.scripts.len()).rev() { let script = tunit.load_script(i as u32, context.gc_context)?; diff --git a/core/src/avm2/class.rs b/core/src/avm2/class.rs index 6114ed53c..99ba2e958 100644 --- a/core/src/avm2/class.rs +++ b/core/src/avm2/class.rs @@ -156,7 +156,7 @@ impl<'gc> Class<'gc> { /// caller is responsible for storing the class in the `TranslationUnit` /// and calling `load_traits` to complete the trait-loading process. pub fn from_abc_index( - unit: &mut TranslationUnit<'gc>, + unit: TranslationUnit<'gc>, class_index: u32, mc: MutationContext<'gc, '_>, ) -> Result, Error> { @@ -198,8 +198,8 @@ impl<'gc> Class<'gc> { )?); } - let instance_init = unit.load_method(abc_instance.init_method.0)?; - let class_init = unit.load_method(abc_class.init_method.0)?; + let instance_init = unit.load_method(abc_instance.init_method.0, mc)?; + let class_init = unit.load_method(abc_class.init_method.0, mc)?; Ok(GcCell::allocate( mc, @@ -228,7 +228,7 @@ impl<'gc> Class<'gc> { /// instantiated into an `Object`. pub fn load_traits( &mut self, - unit: &mut TranslationUnit<'gc>, + unit: TranslationUnit<'gc>, class_index: u32, mc: MutationContext<'gc, '_>, ) -> Result<(), Error> { diff --git a/core/src/avm2/script.rs b/core/src/avm2/script.rs index 235e46cde..c4e557570 100644 --- a/core/src/avm2/script.rs +++ b/core/src/avm2/script.rs @@ -6,6 +6,7 @@ use crate::avm2::r#trait::Trait; use crate::avm2::Error; use gc_arena::{Collect, GcCell, MutationContext}; use std::collections::HashMap; +use std::mem::drop; use std::rc::Rc; use swf::avm2::types::{AbcFile, Index, Script as AbcScript}; @@ -13,6 +14,10 @@ use swf::avm2::types::{AbcFile, Index, Script as AbcScript}; #[collect(require_static)] pub struct CollectWrapper(T); +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] +pub struct TranslationUnit<'gc>(GcCell<'gc, TranslationUnitData<'gc>>); + /// A loaded ABC file, with any loaded ABC items alongside it. /// /// A `TranslationUnit` is constructed when ABC loading begins, and it stores @@ -27,7 +32,7 @@ pub struct CollectWrapper(T); /// constructing the appropriate runtime object for that item. #[derive(Clone, Debug, Collect)] #[collect(no_drop)] -pub struct TranslationUnit<'gc> { +pub struct TranslationUnitData<'gc> { /// The ABC file that all of the following loaded data comes from. abc: CollectWrapper>, @@ -42,68 +47,86 @@ pub struct TranslationUnit<'gc> { } impl<'gc> TranslationUnit<'gc> { - pub fn from_abc(abc: Rc) -> Self { - Self { - abc: CollectWrapper(abc), - classes: HashMap::new(), - methods: HashMap::new(), - scripts: HashMap::new(), - } + pub fn from_abc(abc: Rc, mc: MutationContext<'gc, '_>) -> Self { + Self(GcCell::allocate( + mc, + TranslationUnitData { + abc: CollectWrapper(abc), + classes: HashMap::new(), + methods: HashMap::new(), + scripts: HashMap::new(), + }, + )) } /// Retrieve the underlying `AbcFile` for this translation unit. - pub fn abc(&self) -> Rc { - self.abc.0 + pub fn abc(self) -> Rc { + self.0.read().abc.0 } /// Load a method from the ABC file and return it's method definition. - pub fn load_method(&mut self, method_index: u32) -> Result, Error> { - if let Some(method) = self.methods.get(&method_index) { + pub fn load_method( + self, + method_index: u32, + mc: MutationContext<'gc, '_>, + ) -> Result, Error> { + let write = self.0.write(mc); + if let Some(method) = write.methods.get(&method_index) { return Ok(method.clone()); } + let abc = write.abc.0; + + drop(write); + let method: Result = - Avm2MethodEntry::from_method_index(self.abc.0, Index::new(method_index)) + Avm2MethodEntry::from_method_index(abc, Index::new(method_index)) .ok_or_else(|| "Method index does not exist".into()); let method = method?.into(); - self.methods.insert(method_index, method); + self.0.write(mc).methods.insert(method_index, method); return Ok(method); } /// Load a class from the ABC file and return it's class definition. pub fn load_class( - &mut self, + self, class_index: u32, mc: MutationContext<'gc, '_>, ) -> Result>, Error> { - if let Some(class) = self.classes.get(&class_index) { + let write = self.0.write(mc); + if let Some(class) = write.classes.get(&class_index) { return Ok(class.clone()); } - let class = Class::from_abc_index(&mut self, class_index, mc)?; - self.classes.insert(class_index, class); + drop(write); - class.write(mc).load_traits(&mut self, class_index, mc)?; + let class = Class::from_abc_index(self, class_index, mc)?; + self.0.write(mc).classes.insert(class_index, class); + + class.write(mc).load_traits(self, class_index, mc)?; return Ok(class); } /// Load a script from the ABC file and return it's script definition. pub fn load_script( - &mut self, + self, script_index: u32, mc: MutationContext<'gc, '_>, ) -> Result>, Error> { - if let Some(scripts) = self.scripts.get(&script_index) { + let write = self.0.write(mc); + if let Some(scripts) = write.scripts.get(&script_index) { return Ok(scripts.clone()); } - let script = Script::from_abc_index(&mut self, script_index, mc)?; - self.scripts.insert(script_index, script); + drop(write); - script.write(mc).load_traits(&mut self, script_index, mc)?; + let script = Script::from_abc_index(self, script_index, mc)?; + self.0.write(mc).scripts.insert(script_index, script); + + script.write(mc).load_traits(self, script_index, mc)?; return Ok(script); } @@ -131,7 +154,7 @@ impl<'gc> Script<'gc> { /// `TranslationUnit` and calling `load_traits` to complete the /// trait-loading process. pub fn from_abc_index( - unit: &mut TranslationUnit<'gc>, + unit: TranslationUnit<'gc>, script_index: u32, mc: MutationContext<'gc, '_>, ) -> Result, Error> { @@ -142,7 +165,7 @@ impl<'gc> Script<'gc> { .ok_or_else(|| "LoadError: Script index not valid".into()); let script = script?; - let init = unit.load_method(script.init_method.0)?; + let init = unit.load_method(script.init_method.0, mc)?; Ok(GcCell::allocate( mc, @@ -162,7 +185,7 @@ impl<'gc> Script<'gc> { /// executed. pub fn load_traits( &mut self, - unit: &mut TranslationUnit<'gc>, + unit: TranslationUnit<'gc>, script_index: u32, mc: MutationContext<'gc, '_>, ) -> Result<(), Error> { diff --git a/core/src/avm2/trait.rs b/core/src/avm2/trait.rs index 0726de6c7..41a70ff63 100644 --- a/core/src/avm2/trait.rs +++ b/core/src/avm2/trait.rs @@ -83,7 +83,7 @@ pub enum TraitKind<'gc> { impl<'gc> Trait<'gc> { /// Convert an ABC trait into a loaded trait. pub fn from_abc_trait( - unit: &mut TranslationUnit<'gc>, + unit: TranslationUnit<'gc>, abc_trait: &AbcTrait, mc: MutationContext<'gc, '_>, ) -> Result { @@ -114,7 +114,7 @@ impl<'gc> Trait<'gc> { is_override: abc_trait.is_override, kind: TraitKind::Method { disp_id, - method: unit.load_method(method.0)?, + method: unit.load_method(method.0, mc)?, }, }, AbcTraitKind::Getter { disp_id, method } => Trait { @@ -123,7 +123,7 @@ impl<'gc> Trait<'gc> { is_override: abc_trait.is_override, kind: TraitKind::Getter { disp_id, - method: unit.load_method(method.0)?, + method: unit.load_method(method.0, mc)?, }, }, AbcTraitKind::Setter { disp_id, method } => Trait { @@ -132,7 +132,7 @@ impl<'gc> Trait<'gc> { is_override: abc_trait.is_override, kind: TraitKind::Setter { disp_id, - method: unit.load_method(method.0)?, + method: unit.load_method(method.0, mc)?, }, }, AbcTraitKind::Class { slot_id, class } => Trait { @@ -150,7 +150,7 @@ impl<'gc> Trait<'gc> { is_override: abc_trait.is_override, kind: TraitKind::Function { slot_id, - function: unit.load_method(function.0)?, + function: unit.load_method(function.0, mc)?, }, }, AbcTraitKind::Const {