Make `TranslationUnit` a GC-mandatory type (only referred to by `GcCell`).

This commit is contained in:
David Wendt 2020-07-02 18:48:37 -04:00
parent 60f3ae3ba7
commit 4467bc3193
4 changed files with 60 additions and 37 deletions

View File

@ -100,7 +100,7 @@ impl<'gc> Avm2<'gc> {
let mut read = Reader::new(abc.as_ref()); let mut read = Reader::new(abc.as_ref());
let abc_file = Rc::new(read.read()?); 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() { for i in (0..abc_file.scripts.len()).rev() {
let script = tunit.load_script(i as u32, context.gc_context)?; let script = tunit.load_script(i as u32, context.gc_context)?;

View File

@ -156,7 +156,7 @@ impl<'gc> Class<'gc> {
/// caller is responsible for storing the class in the `TranslationUnit` /// caller is responsible for storing the class in the `TranslationUnit`
/// and calling `load_traits` to complete the trait-loading process. /// and calling `load_traits` to complete the trait-loading process.
pub fn from_abc_index( pub fn from_abc_index(
unit: &mut TranslationUnit<'gc>, unit: TranslationUnit<'gc>,
class_index: u32, class_index: u32,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
) -> Result<GcCell<'gc, Self>, Error> { ) -> Result<GcCell<'gc, Self>, Error> {
@ -198,8 +198,8 @@ impl<'gc> Class<'gc> {
)?); )?);
} }
let instance_init = unit.load_method(abc_instance.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)?; let class_init = unit.load_method(abc_class.init_method.0, mc)?;
Ok(GcCell::allocate( Ok(GcCell::allocate(
mc, mc,
@ -228,7 +228,7 @@ impl<'gc> Class<'gc> {
/// instantiated into an `Object`. /// instantiated into an `Object`.
pub fn load_traits( pub fn load_traits(
&mut self, &mut self,
unit: &mut TranslationUnit<'gc>, unit: TranslationUnit<'gc>,
class_index: u32, class_index: u32,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {

View File

@ -6,6 +6,7 @@ use crate::avm2::r#trait::Trait;
use crate::avm2::Error; use crate::avm2::Error;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::collections::HashMap; use std::collections::HashMap;
use std::mem::drop;
use std::rc::Rc; use std::rc::Rc;
use swf::avm2::types::{AbcFile, Index, Script as AbcScript}; 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)] #[collect(require_static)]
pub struct CollectWrapper<T>(T); pub struct CollectWrapper<T>(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 loaded ABC file, with any loaded ABC items alongside it.
/// ///
/// A `TranslationUnit` is constructed when ABC loading begins, and it stores /// A `TranslationUnit` is constructed when ABC loading begins, and it stores
@ -27,7 +32,7 @@ pub struct CollectWrapper<T>(T);
/// constructing the appropriate runtime object for that item. /// constructing the appropriate runtime object for that item.
#[derive(Clone, Debug, Collect)] #[derive(Clone, Debug, Collect)]
#[collect(no_drop)] #[collect(no_drop)]
pub struct TranslationUnit<'gc> { pub struct TranslationUnitData<'gc> {
/// The ABC file that all of the following loaded data comes from. /// The ABC file that all of the following loaded data comes from.
abc: CollectWrapper<Rc<AbcFile>>, abc: CollectWrapper<Rc<AbcFile>>,
@ -42,68 +47,86 @@ pub struct TranslationUnit<'gc> {
} }
impl<'gc> TranslationUnit<'gc> { impl<'gc> TranslationUnit<'gc> {
pub fn from_abc(abc: Rc<AbcFile>) -> Self { pub fn from_abc(abc: Rc<AbcFile>, mc: MutationContext<'gc, '_>) -> Self {
Self { Self(GcCell::allocate(
abc: CollectWrapper(abc), mc,
classes: HashMap::new(), TranslationUnitData {
methods: HashMap::new(), abc: CollectWrapper(abc),
scripts: HashMap::new(), classes: HashMap::new(),
} methods: HashMap::new(),
scripts: HashMap::new(),
},
))
} }
/// Retrieve the underlying `AbcFile` for this translation unit. /// Retrieve the underlying `AbcFile` for this translation unit.
pub fn abc(&self) -> Rc<AbcFile> { pub fn abc(self) -> Rc<AbcFile> {
self.abc.0 self.0.read().abc.0
} }
/// Load a method from the ABC file and return it's method definition. /// Load a method from the ABC file and return it's method definition.
pub fn load_method(&mut self, method_index: u32) -> Result<Method<'gc>, Error> { pub fn load_method(
if let Some(method) = self.methods.get(&method_index) { self,
method_index: u32,
mc: MutationContext<'gc, '_>,
) -> Result<Method<'gc>, Error> {
let write = self.0.write(mc);
if let Some(method) = write.methods.get(&method_index) {
return Ok(method.clone()); return Ok(method.clone());
} }
let abc = write.abc.0;
drop(write);
let method: Result<Avm2MethodEntry, Error> = let method: Result<Avm2MethodEntry, Error> =
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()); .ok_or_else(|| "Method index does not exist".into());
let method = method?.into(); let method = method?.into();
self.methods.insert(method_index, method); self.0.write(mc).methods.insert(method_index, method);
return Ok(method); return Ok(method);
} }
/// Load a class from the ABC file and return it's class definition. /// Load a class from the ABC file and return it's class definition.
pub fn load_class( pub fn load_class(
&mut self, self,
class_index: u32, class_index: u32,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
) -> Result<GcCell<'gc, Class<'gc>>, Error> { ) -> Result<GcCell<'gc, Class<'gc>>, 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()); return Ok(class.clone());
} }
let class = Class::from_abc_index(&mut self, class_index, mc)?; drop(write);
self.classes.insert(class_index, class);
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); return Ok(class);
} }
/// Load a script from the ABC file and return it's script definition. /// Load a script from the ABC file and return it's script definition.
pub fn load_script( pub fn load_script(
&mut self, self,
script_index: u32, script_index: u32,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
) -> Result<GcCell<'gc, Script<'gc>>, Error> { ) -> Result<GcCell<'gc, Script<'gc>>, 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()); return Ok(scripts.clone());
} }
let script = Script::from_abc_index(&mut self, script_index, mc)?; drop(write);
self.scripts.insert(script_index, script);
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); return Ok(script);
} }
@ -131,7 +154,7 @@ impl<'gc> Script<'gc> {
/// `TranslationUnit` and calling `load_traits` to complete the /// `TranslationUnit` and calling `load_traits` to complete the
/// trait-loading process. /// trait-loading process.
pub fn from_abc_index( pub fn from_abc_index(
unit: &mut TranslationUnit<'gc>, unit: TranslationUnit<'gc>,
script_index: u32, script_index: u32,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
) -> Result<GcCell<'gc, Self>, Error> { ) -> Result<GcCell<'gc, Self>, Error> {
@ -142,7 +165,7 @@ impl<'gc> Script<'gc> {
.ok_or_else(|| "LoadError: Script index not valid".into()); .ok_or_else(|| "LoadError: Script index not valid".into());
let script = script?; 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( Ok(GcCell::allocate(
mc, mc,
@ -162,7 +185,7 @@ impl<'gc> Script<'gc> {
/// executed. /// executed.
pub fn load_traits( pub fn load_traits(
&mut self, &mut self,
unit: &mut TranslationUnit<'gc>, unit: TranslationUnit<'gc>,
script_index: u32, script_index: u32,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {

View File

@ -83,7 +83,7 @@ pub enum TraitKind<'gc> {
impl<'gc> Trait<'gc> { impl<'gc> Trait<'gc> {
/// Convert an ABC trait into a loaded trait. /// Convert an ABC trait into a loaded trait.
pub fn from_abc_trait( pub fn from_abc_trait(
unit: &mut TranslationUnit<'gc>, unit: TranslationUnit<'gc>,
abc_trait: &AbcTrait, abc_trait: &AbcTrait,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
@ -114,7 +114,7 @@ impl<'gc> Trait<'gc> {
is_override: abc_trait.is_override, is_override: abc_trait.is_override,
kind: TraitKind::Method { kind: TraitKind::Method {
disp_id, disp_id,
method: unit.load_method(method.0)?, method: unit.load_method(method.0, mc)?,
}, },
}, },
AbcTraitKind::Getter { disp_id, method } => Trait { AbcTraitKind::Getter { disp_id, method } => Trait {
@ -123,7 +123,7 @@ impl<'gc> Trait<'gc> {
is_override: abc_trait.is_override, is_override: abc_trait.is_override,
kind: TraitKind::Getter { kind: TraitKind::Getter {
disp_id, disp_id,
method: unit.load_method(method.0)?, method: unit.load_method(method.0, mc)?,
}, },
}, },
AbcTraitKind::Setter { disp_id, method } => Trait { AbcTraitKind::Setter { disp_id, method } => Trait {
@ -132,7 +132,7 @@ impl<'gc> Trait<'gc> {
is_override: abc_trait.is_override, is_override: abc_trait.is_override,
kind: TraitKind::Setter { kind: TraitKind::Setter {
disp_id, disp_id,
method: unit.load_method(method.0)?, method: unit.load_method(method.0, mc)?,
}, },
}, },
AbcTraitKind::Class { slot_id, class } => Trait { AbcTraitKind::Class { slot_id, class } => Trait {
@ -150,7 +150,7 @@ impl<'gc> Trait<'gc> {
is_override: abc_trait.is_override, is_override: abc_trait.is_override,
kind: TraitKind::Function { kind: TraitKind::Function {
slot_id, slot_id,
function: unit.load_method(function.0)?, function: unit.load_method(function.0, mc)?,
}, },
}, },
AbcTraitKind::Const { AbcTraitKind::Const {