Make `Avm2MethodEntry` hold it's `TranslationUnit` rather than an `AbcFile`.

This commit is contained in:
David Wendt 2020-07-02 19:02:54 -04:00
parent 4467bc3193
commit eaebd3c63c
4 changed files with 43 additions and 23 deletions

View File

@ -233,7 +233,7 @@ impl<'gc> Avm2<'gc> {
frame_ref.lock()?;
let method = frame_ref.method();
let abc = method.abc.as_ref().clone();
let abc = method.abc();
let _method_index = method.abc_method;
let method_body_index = method.abc_method_body as usize;
@ -367,7 +367,11 @@ impl<'gc> Avm2<'gc> {
/// Retrieve the current constant pool for the currently executing function.
fn current_abc(&self) -> Option<Rc<AbcFile>> {
self.current_stack_frame()
.map(|sf| sf.read().method().abc.clone())
.map(|sf| sf.read().method().abc())
}
fn current_translation_unit(&self) -> Option<TranslationUnit<'gc>> {
self.current_stack_frame().map(|sf| sf.read().method().translation_unit())
}
/// Retrieve a int from the current constant pool.
@ -407,8 +411,8 @@ impl<'gc> Avm2<'gc> {
}
/// Retrieve a method entry from the current ABC file's method table.
fn table_method(&mut self, index: Index<AbcMethod>) -> Result<Avm2MethodEntry, Error> {
Avm2MethodEntry::from_method_index(self.current_abc().unwrap(), index.clone())
fn table_method(&mut self, index: Index<AbcMethod>) -> Result<Avm2MethodEntry<'gc>, Error> {
Avm2MethodEntry::from_method_index(self.current_translation_unit().unwrap(), index.clone())
.ok_or_else(|| format!("Method index {} does not exist", index.0).into())
}

View File

@ -50,7 +50,7 @@ impl<'gc> RegisterSet<'gc> {
#[collect(no_drop)]
pub struct Activation<'gc> {
/// The AVM method entry we're executing code out of.
method: Avm2MethodEntry,
method: Avm2MethodEntry<'gc>,
/// The current location of the instruction stream being executed.
pc: usize,
@ -125,7 +125,7 @@ impl<'gc> Activation<'gc> {
pub fn from_action(
context: &mut UpdateContext<'_, 'gc, '_>,
method: Avm2MethodEntry,
method: Avm2MethodEntry<'gc>,
scope: Option<GcCell<'gc, Scope<'gc>>>,
this: Option<Object<'gc>>,
arguments: &[Value<'gc>],
@ -184,7 +184,7 @@ impl<'gc> Activation<'gc> {
}
/// Obtain a reference to the method being executed.
pub fn method(&self) -> &Avm2MethodEntry {
pub fn method(&self) -> &Avm2MethodEntry<'gc> {
&self.method
}

View File

@ -7,6 +7,7 @@ use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::r#trait::Trait;
use crate::avm2::return_value::ReturnValue;
use crate::avm2::scope::Scope;
use crate::avm2::script::TranslationUnit;
use crate::avm2::script_object::{ScriptObjectClass, ScriptObjectData};
use crate::avm2::value::Value;
use crate::avm2::{Avm2, Error};
@ -39,10 +40,10 @@ pub type NativeFunction<'gc> = fn(
/// Represents a reference to an AVM2 method and body.
#[derive(Collect, Clone, Debug)]
#[collect(require_static)]
pub struct Avm2MethodEntry {
#[collect(no_drop)]
pub struct Avm2MethodEntry<'gc> {
/// The ABC file this function was defined in.
pub abc: Rc<AbcFile>,
pub txunit: TranslationUnit<'gc>,
/// The ABC method this function uses.
pub abc_method: u32,
@ -51,17 +52,22 @@ pub struct Avm2MethodEntry {
pub abc_method_body: u32,
}
impl Avm2MethodEntry {
impl<'gc> Avm2MethodEntry<'gc> {
/// Construct an `Avm2MethodEntry` from an `AbcFile` and method index.
///
/// The method body index will be determined by searching through the ABC
/// for a matching method. If none exists, this function returns `None`.
pub fn from_method_index(abc: Rc<AbcFile>, abc_method: Index<AbcMethod>) -> Option<Self> {
pub fn from_method_index(
txunit: TranslationUnit<'gc>,
abc_method: Index<AbcMethod>,
) -> Option<Self> {
let abc = txunit.abc();
if abc.methods.get(abc_method.0 as usize).is_some() {
for (index, method_body) in abc.method_bodies.iter().enumerate() {
if method_body.method.0 == abc_method.0 {
return Some(Self {
abc,
txunit,
abc_method: abc_method.0,
abc_method_body: index as u32,
});
@ -75,17 +81,27 @@ impl Avm2MethodEntry {
/// Get the underlying ABC file.
#[allow(dead_code)]
pub fn abc(&self) -> Rc<AbcFile> {
self.abc.clone()
self.txunit.abc().clone()
}
/// Get the underlying translation unit this method was defined in.
pub fn translation_unit(&self) -> TranslationUnit<'gc> {
self.txunit
}
/// Get a reference to the ABC method entry this refers to.
pub fn method(&self) -> &AbcMethod {
self.abc.methods.get(self.abc_method as usize).unwrap()
self.txunit
.abc()
.methods
.get(self.abc_method as usize)
.unwrap()
}
/// Get a reference to the ABC method body entry this refers to.
pub fn body(&self) -> &AbcMethodBody {
self.abc
self.txunit
.abc()
.method_bodies
.get(self.abc_method_body as usize)
.unwrap()
@ -100,7 +116,7 @@ pub enum Method<'gc> {
Native(NativeFunction<'gc>),
/// An ABC-provided method entry.
Entry(Avm2MethodEntry),
Entry(Avm2MethodEntry<'gc>),
}
unsafe impl<'gc> Collect for Method<'gc> {
@ -130,14 +146,14 @@ impl<'gc> From<NativeFunction<'gc>> for Method<'gc> {
}
}
impl<'gc> From<Avm2MethodEntry> for Method<'gc> {
fn from(a2me: Avm2MethodEntry) -> Self {
impl<'gc> From<Avm2MethodEntry<'gc>> for Method<'gc> {
fn from(a2me: Avm2MethodEntry<'gc>) -> Self {
Self::Entry(a2me)
}
}
impl<'gc> Method<'gc> {
pub fn as_entry(self) -> Result<Avm2MethodEntry, Error> {
pub fn as_entry(self) -> Result<Avm2MethodEntry<'gc>, Error> {
match self {
Method::Native(_) => {
Err("Attempted to unwrap a native method as a user-defined one".into())
@ -152,7 +168,7 @@ impl<'gc> Method<'gc> {
#[collect(no_drop)]
pub struct Avm2Function<'gc> {
/// The AVM method entry used to create this function.
pub method: Avm2MethodEntry,
pub method: Avm2MethodEntry<'gc>,
/// Closure scope stack at time of creation
pub scope: Option<GcCell<'gc, Scope<'gc>>>,
@ -175,7 +191,7 @@ pub enum Executable<'gc> {
/// Code defined in a loaded ABC file.
Action {
/// The method code to execute from a given ABC file.
method: Avm2MethodEntry,
method: Avm2MethodEntry<'gc>,
/// The scope stack to pull variables from.
scope: Option<GcCell<'gc, Scope<'gc>>>,

View File

@ -80,7 +80,7 @@ impl<'gc> TranslationUnit<'gc> {
drop(write);
let method: Result<Avm2MethodEntry, Error> =
Avm2MethodEntry::from_method_index(abc, Index::new(method_index))
Avm2MethodEntry::from_method_index(self, Index::new(method_index))
.ok_or_else(|| "Method index does not exist".into());
let method = method?.into();