Wrap `BytecodeMethod` (and the bytecode half of `Executable`) in a `Gc`.

This is inspired by Dinnerbone's similar PR on the AVM1 side, where the Action half of that VM's `Executable` was reduced from 128 bytes to 16 by shoving it in a `Gc`. This won't be as dramatic but should still save some memory.

In fact, it should save a *lot* of memory in bytecode execution, where thanks to the previous commit's rebase, we now need to clone the current method once *for each instruction executed*. That is terrible, but should stop now.
This commit is contained in:
David Wendt 2020-07-04 17:56:27 -04:00
parent 97e005622b
commit 090fe56bd3
5 changed files with 136 additions and 118 deletions

View File

@ -11,7 +11,7 @@ use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::avm2::{value, Avm2, Error};
use crate::context::UpdateContext;
use gc_arena::{Collect, GcCell, MutationContext};
use gc_arena::{Collect, Gc, GcCell, MutationContext};
use smallvec::SmallVec;
use std::io::Cursor;
use swf::avm2::read::Reader;
@ -137,7 +137,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
script: GcCell<'gc, Script<'gc>>,
global: Object<'gc>,
) -> Result<Self, Error> {
let method = script.read().init().into_entry()?;
let method = script.read().init().into_bytecode()?;
let scope = Some(Scope::push_scope(None, global, context.gc_context));
let num_locals = method.body().num_locals;
let local_registers =
@ -166,7 +166,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
pub fn from_method(
avm2: &'a mut Avm2<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
scope: Option<GcCell<'gc, Scope<'gc>>>,
this: Option<Object<'gc>>,
arguments: &[Value<'gc>],
@ -210,7 +210,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
script: GcCell<'gc, Script<'gc>>,
) -> Result<(), Error> {
let init = script.read().init().into_entry()?;
let init = script.read().init().into_bytecode()?;
self.run_actions(init, context)?;
@ -289,24 +289,36 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
}
/// Retrieve a int from the current constant pool.
fn pool_int(&self, method: BytecodeMethod<'gc>, index: Index<i32>) -> Result<i32, Error> {
fn pool_int(
&self,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<i32>,
) -> Result<i32, Error> {
value::abc_int(&method.abc(), index)
}
/// Retrieve a int from the current constant pool.
fn pool_uint(&self, method: BytecodeMethod<'gc>, index: Index<u32>) -> Result<u32, Error> {
fn pool_uint(
&self,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<u32>,
) -> Result<u32, Error> {
value::abc_uint(&method.abc(), index)
}
/// Retrieve a double from the current constant pool.
fn pool_double(&self, method: BytecodeMethod<'gc>, index: Index<f64>) -> Result<f64, Error> {
fn pool_double(
&self,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<f64>,
) -> Result<f64, Error> {
value::abc_double(&method.abc(), index)
}
/// Retrieve a string from the current constant pool.
fn pool_string(
&self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<String>,
) -> Result<String, Error> {
value::abc_string(&method.abc(), index)
@ -315,7 +327,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
/// Retrieve a namespace from the current constant pool.
fn pool_namespace(
&self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcNamespace>,
) -> Result<Namespace, Error> {
Namespace::from_abc_namespace(&method.abc(), index)
@ -324,7 +336,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
/// Retrieve a multiname from the current constant pool.
fn pool_multiname(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcMultiname>,
) -> Result<Multiname, Error> {
Multiname::from_abc_multiname(&method.abc(), index, self.avm2)
@ -334,7 +346,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
/// pool.
fn pool_multiname_static(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcMultiname>,
) -> Result<Multiname, Error> {
Multiname::from_abc_multiname_static(&method.abc(), index)
@ -343,17 +355,18 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
/// Retrieve a method entry from the current ABC file's method table.
fn table_method(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcMethod>,
) -> Result<BytecodeMethod<'gc>, Error> {
BytecodeMethod::from_method_index(method.translation_unit(), index.clone())
mc: MutationContext<'gc, '_>,
) -> Result<Gc<'gc, BytecodeMethod<'gc>>, Error> {
BytecodeMethod::from_method_index(method.translation_unit(), index.clone(), mc)
.ok_or_else(|| format!("Method index {} does not exist", index.0).into())
}
/// Retrieve a class entry from the current ABC file's method table.
fn table_class(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
index: Index<AbcClass>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<GcCell<'gc, Class<'gc>>, Error> {
@ -364,14 +377,13 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
pub fn run_actions(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
let clone_method = method.clone();
let mut read = Reader::new(Cursor::new(clone_method.body().code.as_ref()));
let mut read = Reader::new(Cursor::new(method.body().code.as_ref()));
loop {
let result = self.do_next_opcode(method.clone(), context, &mut read);
let result = self.do_next_opcode(method, context, &mut read);
match result {
Ok(FrameControl::Return(value)) => break Ok(value),
Ok(FrameControl::Continue) => {}
@ -383,7 +395,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
/// Run a single action from a given action reader.
fn do_next_opcode(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut Reader<Cursor<&[u8]>>,
) -> Result<FrameControl<'gc>, Error> {
@ -511,7 +523,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_push_double(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
value: Index<f64>,
) -> Result<FrameControl<'gc>, Error> {
self.avm2.push(self.pool_double(method, value)?);
@ -525,7 +537,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_push_int(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
value: Index<i32>,
) -> Result<FrameControl<'gc>, Error> {
self.avm2.push(self.pool_int(method, value)?);
@ -534,7 +546,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_push_namespace(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
value: Index<AbcNamespace>,
) -> Result<FrameControl<'gc>, Error> {
self.avm2.push(self.pool_namespace(method, value)?);
@ -558,7 +570,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_push_string(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
value: Index<String>,
) -> Result<FrameControl<'gc>, Error> {
self.avm2.push(self.pool_string(method, value)?);
@ -572,7 +584,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_push_uint(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
value: Index<u32>,
) -> Result<FrameControl<'gc>, Error> {
self.avm2.push(self.pool_uint(method, value)?);
@ -661,7 +673,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_call_property(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
arg_count: u32,
@ -686,7 +698,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_call_prop_lex(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
arg_count: u32,
@ -709,7 +721,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_call_prop_void(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
arg_count: u32,
@ -733,14 +745,14 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_call_static(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMethod>,
arg_count: u32,
) -> Result<FrameControl<'gc>, Error> {
let args = self.avm2.pop_args(arg_count);
let receiver = self.avm2.pop().as_object()?;
let method = self.table_method(method, index)?;
let method = self.table_method(method, index, context.gc_context)?;
let scope = self.scope(); //TODO: Is this correct?
let function = FunctionObject::from_method(
context.gc_context,
@ -758,7 +770,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_call_super(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
arg_count: u32,
@ -791,7 +803,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_call_super_void(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
arg_count: u32,
@ -832,7 +844,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_get_property(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> {
@ -851,7 +863,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_set_property(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> {
@ -876,7 +888,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_init_property(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> {
@ -901,7 +913,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_delete_property(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> {
@ -920,7 +932,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_get_super(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> {
@ -950,7 +962,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_set_super(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> {
@ -1055,7 +1067,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_find_property(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> {
@ -1075,7 +1087,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_find_prop_strict(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> {
@ -1096,7 +1108,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_get_lex(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> {
@ -1188,7 +1200,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_construct_prop(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMultiname>,
arg_count: u32,
@ -1283,11 +1295,11 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_new_function(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcMethod>,
) -> Result<FrameControl<'gc>, Error> {
let method_entry = self.table_method(method, index)?;
let method_entry = self.table_method(method, index, context.gc_context)?;
let scope = self.scope();
let mut new_fn = FunctionObject::from_method(
@ -1313,7 +1325,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
fn op_new_class(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
index: Index<AbcClass>,
) -> Result<FrameControl<'gc>, Error> {
@ -1501,7 +1513,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
#[allow(unused_variables)]
fn op_debug(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
is_local_register: bool,
register_name: Index<String>,
register: u8,
@ -1521,7 +1533,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
#[allow(unused_variables)]
fn op_debug_file(
&mut self,
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
file_name: Index<String>,
) -> Result<FrameControl<'gc>, Error> {
let file_name = self.pool_string(method, file_name)?;

View File

@ -11,21 +11,16 @@ use crate::avm2::script_object::{ScriptObjectClass, ScriptObjectData};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, CollectionContext, GcCell, MutationContext};
use gc_arena::{Collect, CollectionContext, Gc, GcCell, MutationContext};
use std::fmt;
/// Represents code that can be executed by some means.
#[derive(Clone)]
pub enum Executable<'gc> {
/// Code defined in Ruffle's binary.
///
/// The second parameter stores the bound reciever for this function.
Native(NativeMethod<'gc>, Option<Object<'gc>>),
/// Code defined in a loaded ABC file.
Action {
/// Represents code written in AVM2 bytecode that can be executed by some
/// means.
#[derive(Clone, Collect)]
#[collect(no_drop)]
pub struct BytecodeExecutable<'gc> {
/// The method code to execute from a given ABC file.
method: BytecodeMethod<'gc>,
method: Gc<'gc, BytecodeMethod<'gc>>,
/// The scope stack to pull variables from.
scope: Option<GcCell<'gc, Scope<'gc>>>,
@ -35,21 +30,24 @@ pub enum Executable<'gc> {
/// If `None`, then the reciever provided by the caller is used. A
/// `Some` value indicates a bound executable.
reciever: Option<Object<'gc>>,
},
}
/// Represents code that can be executed by some means.
#[derive(Copy, Clone)]
pub enum Executable<'gc> {
/// Code defined in Ruffle's binary.
///
/// The second parameter stores the bound reciever for this function.
Native(NativeMethod<'gc>, Option<Object<'gc>>),
/// Code defined in a loaded ABC file.
Action(Gc<'gc, BytecodeExecutable<'gc>>),
}
unsafe impl<'gc> Collect for Executable<'gc> {
fn trace(&self, cc: CollectionContext) {
match self {
Self::Action {
method,
scope,
reciever,
} => {
method.trace(cc);
scope.trace(cc);
reciever.trace(cc);
}
Self::Action(be) => be.trace(cc),
Self::Native(_nf, reciever) => reciever.trace(cc),
}
}
@ -61,14 +59,18 @@ impl<'gc> Executable<'gc> {
method: Method<'gc>,
scope: Option<GcCell<'gc, Scope<'gc>>>,
reciever: Option<Object<'gc>>,
mc: MutationContext<'gc, '_>,
) -> Self {
match method {
Method::Native(nf) => Self::Native(nf, reciever),
Method::Entry(a2me) => Self::Action {
Method::Entry(a2me) => Self::Action(Gc::allocate(
mc,
BytecodeExecutable {
method: a2me,
scope,
reciever,
},
)),
}
}
@ -95,23 +97,19 @@ impl<'gc> Executable<'gc> {
reciever.or(unbound_reciever),
arguments,
),
Executable::Action {
method,
scope,
reciever,
} => {
let reciever = reciever.or(unbound_reciever);
Executable::Action(bm) => {
let reciever = bm.reciever.or(unbound_reciever);
let mut activation = Activation::from_method(
activation.avm2(),
context,
method.clone(),
*scope,
bm.method,
bm.scope,
reciever,
arguments,
base_proto,
);
activation.run_actions(method.clone(), context)
activation.run_actions(bm.method, context)
}
}
}
@ -120,15 +118,11 @@ impl<'gc> Executable<'gc> {
impl<'gc> fmt::Debug for Executable<'gc> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Action {
method,
scope,
reciever,
} => fmt
Self::Action(be) => fmt
.debug_struct("Executable::Action")
.field("method", method)
.field("scope", scope)
.field("reciever", reciever)
.field("method", &be.method)
.field("scope", &be.scope)
.field("reciever", &be.reciever)
.finish(),
Self::Native(nf, reciever) => fmt
.debug_tuple("Executable::Native")
@ -200,7 +194,12 @@ impl<'gc> FunctionObject<'gc> {
Some(fn_proto),
ScriptObjectClass::ClassConstructor(class, scope),
),
exec: Some(Executable::from_method(initializer, scope, None)),
exec: Some(Executable::from_method(
initializer,
scope,
None,
context.gc_context,
)),
},
))
.into();
@ -239,7 +238,7 @@ impl<'gc> FunctionObject<'gc> {
fn_proto: Object<'gc>,
reciever: Option<Object<'gc>>,
) -> Object<'gc> {
let exec = Some(Executable::from_method(method, scope, reciever));
let exec = Some(Executable::from_method(method, scope, reciever, mc));
FunctionObject(GcCell::allocate(
mc,
@ -261,7 +260,7 @@ impl<'gc> FunctionObject<'gc> {
mc,
FunctionObjectData {
base: ScriptObjectData::base_new(Some(fn_proto), ScriptObjectClass::NoClass),
exec: Some(Executable::from_method(nf.into(), None, None)),
exec: Some(Executable::from_method(nf.into(), None, None, mc)),
},
))
.into()
@ -278,7 +277,7 @@ impl<'gc> FunctionObject<'gc> {
mc,
FunctionObjectData {
base: ScriptObjectData::base_new(Some(fn_proto), ScriptObjectClass::NoClass),
exec: Some(Executable::from_method(constr.into(), None, None)),
exec: Some(Executable::from_method(constr.into(), None, None, mc)),
},
))
.into();
@ -465,7 +464,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
}
fn as_executable(&self) -> Option<Executable<'gc>> {
self.0.read().exec.clone()
self.0.read().exec
}
fn call(

View File

@ -6,7 +6,7 @@ use crate::avm2::script::TranslationUnit;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, CollectionContext};
use gc_arena::{Collect, CollectionContext, Gc, MutationContext};
use std::fmt;
use std::rc::Rc;
use swf::avm2::types::{AbcFile, Index, Method as AbcMethod, MethodBody as AbcMethodBody};
@ -61,18 +61,22 @@ impl<'gc> BytecodeMethod<'gc> {
pub fn from_method_index(
txunit: TranslationUnit<'gc>,
abc_method: Index<AbcMethod>,
) -> Option<Self> {
mc: MutationContext<'gc, '_>,
) -> Option<Gc<'gc, 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 {
return Some(Gc::allocate(
mc,
Self {
txunit,
abc: CollectWrapper(txunit.abc()),
abc_method: abc_method.0,
abc_method_body: index as u32,
});
},
));
}
}
}
@ -115,7 +119,7 @@ pub enum Method<'gc> {
Native(NativeMethod<'gc>),
/// An ABC-provided method entry.
Entry(BytecodeMethod<'gc>),
Entry(Gc<'gc, BytecodeMethod<'gc>>),
}
unsafe impl<'gc> Collect for Method<'gc> {
@ -145,19 +149,22 @@ impl<'gc> From<NativeMethod<'gc>> for Method<'gc> {
}
}
impl<'gc> From<BytecodeMethod<'gc>> for Method<'gc> {
fn from(a2me: BytecodeMethod<'gc>) -> Self {
Self::Entry(a2me)
impl<'gc> From<Gc<'gc, BytecodeMethod<'gc>>> for Method<'gc> {
fn from(bm: Gc<'gc, BytecodeMethod<'gc>>) -> Self {
Self::Entry(bm)
}
}
impl<'gc> Method<'gc> {
pub fn into_entry(self) -> Result<BytecodeMethod<'gc>, Error> {
/// Access the bytecode of this method.
///
/// This function returns `Err` if there is no bytecode for this method.
pub fn into_bytecode(self) -> Result<Gc<'gc, BytecodeMethod<'gc>>, Error> {
match self {
Method::Native(_) => {
Err("Attempted to unwrap a native method as a user-defined one".into())
}
Method::Entry(a2me) => Ok(a2me),
Method::Entry(bm) => Ok(bm),
}
}
}

View File

@ -140,7 +140,7 @@ impl<'gc> Property<'gc> {
) -> Result<ReturnValue<'gc>, Error> {
match self {
Property::Virtual { get: Some(get), .. } => Ok(ReturnValue::defer_execution(
get.clone(),
*get,
Some(this),
vec![],
base_proto,
@ -168,7 +168,7 @@ impl<'gc> Property<'gc> {
Property::Virtual { set, .. } => {
if let Some(function) = set {
return Ok(ReturnValue::defer_execution(
function.clone(),
*function,
Some(this),
vec![new_value.into()],
base_proto,
@ -212,7 +212,7 @@ impl<'gc> Property<'gc> {
Property::Virtual { set, .. } => {
if let Some(function) = set {
return Ok(ReturnValue::defer_execution(
function.clone(),
*function,
Some(this),
vec![new_value.into()],
base_proto,

View File

@ -4,7 +4,7 @@ use crate::avm2::class::Class;
use crate::avm2::method::{BytecodeMethod, Method};
use crate::avm2::r#trait::Trait;
use crate::avm2::Error;
use gc_arena::{Collect, GcCell, MutationContext};
use gc_arena::{Collect, Gc, GcCell, MutationContext};
use std::collections::HashMap;
use std::mem::drop;
use std::rc::Rc;
@ -77,8 +77,8 @@ impl<'gc> TranslationUnit<'gc> {
drop(write);
let method: Result<BytecodeMethod<'gc>, Error> =
BytecodeMethod::from_method_index(self, Index::new(method_index))
let method: Result<Gc<'gc, BytecodeMethod<'gc>>, Error> =
BytecodeMethod::from_method_index(self, Index::new(method_index), mc)
.ok_or_else(|| "Method index does not exist".into());
let method: Method<'gc> = method?.into();