Add support for cached/interned pool strings in the `TranslationUnit`.

This commit is contained in:
David Wendt 2020-07-13 23:42:07 -04:00
parent e1b9b823fc
commit 70e9e7e9e9
1 changed files with 56 additions and 0 deletions

View File

@ -1,5 +1,6 @@
//! Whole script representation
use crate::avm1::AvmString;
use crate::avm2::class::Class;
use crate::avm2::method::{BytecodeMethod, Method};
use crate::avm2::r#trait::Trait;
@ -45,6 +46,9 @@ pub struct TranslationUnitData<'gc> {
/// All scripts loaded from the ABC's scripts list.
scripts: HashMap<u32, GcCell<'gc, Script<'gc>>>,
/// All strings loaded from the ABC's strings list.
strings: HashMap<u32, AvmString<'gc>>,
}
impl<'gc> TranslationUnit<'gc> {
@ -56,6 +60,7 @@ impl<'gc> TranslationUnit<'gc> {
classes: HashMap::new(),
methods: HashMap::new(),
scripts: HashMap::new(),
strings: HashMap::new(),
},
))
}
@ -138,6 +143,57 @@ impl<'gc> TranslationUnit<'gc> {
Ok(script)
}
/// Load a string from the ABC's constant pool.
///
/// This function yields an error if no such string index exists.
///
/// This function yields `None` to signal string index zero, which callers
/// are free to interpret as the context demands.
pub fn pool_string_option(
self,
string_index: u32,
mc: MutationContext<'gc, '_>,
) -> Result<Option<AvmString<'gc>>, Error> {
let mut write = self.0.write(mc);
if let Some(string) = write.strings.get(&string_index) {
return Ok(Some(*string));
}
if string_index == 0 {
return Ok(None);
}
let avm_string = AvmString::new(
mc,
write
.abc
.0
.constant_pool
.strings
.get(string_index as usize - 1)
.ok_or_else(|| format!("Unknown string constant {}", string_index))?,
);
write.strings.insert(string_index, avm_string);
Ok(Some(avm_string))
}
/// Load a string from the ABC's constant pool.
///
/// This function yields an error if no such string index exists.
///
/// String index 0 is always `""`. If you need to instead treat 0 as
/// something else, then please use `pool_string_option`.
pub fn pool_string(
self,
string_index: u32,
mc: MutationContext<'gc, '_>,
) -> Result<AvmString<'gc>, Error> {
Ok(self
.pool_string_option(string_index, mc)?
.unwrap_or_else(|| "".into()))
}
}
/// A loaded Script from an ABC file.