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:
parent
97e005622b
commit
090fe56bd3
|
@ -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)?;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue