avm2: Make `Executable` zero-alloc
This commit is contained in:
parent
cea3997396
commit
8d40e41ee1
|
@ -6,7 +6,7 @@ use crate::avm2::object::{ClassObject, Object};
|
|||
use crate::avm2::scope::ScopeChain;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::{Collect, Gc, MutationContext};
|
||||
use gc_arena::{Collect, Gc};
|
||||
use std::fmt;
|
||||
|
||||
/// Represents code written in AVM2 bytecode that can be executed by some
|
||||
|
@ -59,10 +59,10 @@ pub struct NativeExecutable<'gc> {
|
|||
#[collect(no_drop)]
|
||||
pub enum Executable<'gc> {
|
||||
/// Code defined in Ruffle's binary.
|
||||
Native(Gc<'gc, NativeExecutable<'gc>>),
|
||||
Native(NativeExecutable<'gc>),
|
||||
|
||||
/// Code defined in a loaded ABC file.
|
||||
Action(Gc<'gc, BytecodeExecutable<'gc>>),
|
||||
Action(BytecodeExecutable<'gc>),
|
||||
}
|
||||
|
||||
impl<'gc> Executable<'gc> {
|
||||
|
@ -72,27 +72,20 @@ impl<'gc> Executable<'gc> {
|
|||
scope: ScopeChain<'gc>,
|
||||
receiver: Option<Object<'gc>>,
|
||||
superclass: Option<ClassObject<'gc>>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> Self {
|
||||
match method {
|
||||
Method::Native(method) => Self::Native(Gc::allocate(
|
||||
mc,
|
||||
NativeExecutable {
|
||||
method,
|
||||
scope,
|
||||
bound_receiver: receiver,
|
||||
bound_superclass: superclass,
|
||||
},
|
||||
)),
|
||||
Method::Bytecode(method) => Self::Action(Gc::allocate(
|
||||
mc,
|
||||
BytecodeExecutable {
|
||||
method,
|
||||
scope,
|
||||
receiver,
|
||||
bound_superclass: superclass,
|
||||
},
|
||||
)),
|
||||
Method::Native(method) => Self::Native(NativeExecutable {
|
||||
method,
|
||||
scope,
|
||||
bound_receiver: receiver,
|
||||
bound_superclass: superclass,
|
||||
}),
|
||||
Method::Bytecode(method) => Self::Action(BytecodeExecutable {
|
||||
method,
|
||||
scope,
|
||||
receiver,
|
||||
bound_superclass: superclass,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -873,8 +873,8 @@ pub fn sort<'gc>(
|
|||
let (compare_fnc, options) = if fn_or_options
|
||||
.coerce_to_object(activation)
|
||||
.ok()
|
||||
.and_then(|o| o.as_executable())
|
||||
.is_some()
|
||||
.map(|o| o.as_executable().is_some())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
(
|
||||
Some(fn_or_options.coerce_to_object(activation)?),
|
||||
|
|
|
@ -401,14 +401,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
if !method.needs_arguments_object() {
|
||||
let scope = class.instance_scope();
|
||||
|
||||
return Executable::from_method(
|
||||
method,
|
||||
scope,
|
||||
None,
|
||||
Some(superclass),
|
||||
activation.context.gc_context,
|
||||
)
|
||||
.exec(
|
||||
return Executable::from_method(method, scope, None, Some(superclass)).exec(
|
||||
Some(self.into()),
|
||||
arguments,
|
||||
activation,
|
||||
|
@ -424,14 +417,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
if !method.needs_arguments_object() {
|
||||
let scope = class.class_scope();
|
||||
|
||||
return Executable::from_method(
|
||||
method,
|
||||
scope,
|
||||
None,
|
||||
Some(class),
|
||||
activation.context.gc_context,
|
||||
)
|
||||
.exec(
|
||||
return Executable::from_method(method, scope, None, Some(class)).exec(
|
||||
Some(self.into()),
|
||||
arguments,
|
||||
activation,
|
||||
|
@ -1257,7 +1243,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
}
|
||||
|
||||
/// Get this object's `Executable`, if it has one.
|
||||
fn as_executable(&self) -> Option<Executable<'gc>> {
|
||||
fn as_executable(&self) -> Option<Ref<Executable<'gc>>> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
@ -452,13 +452,8 @@ impl<'gc> ClassObject<'gc> {
|
|||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
let scope = self.0.read().instance_scope;
|
||||
let constructor = Executable::from_method(
|
||||
self.0.read().constructor.clone(),
|
||||
scope,
|
||||
None,
|
||||
Some(self),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
let constructor =
|
||||
Executable::from_method(self.0.read().constructor.clone(), scope, None, Some(self));
|
||||
|
||||
constructor.exec(receiver, arguments, activation, self.into())
|
||||
}
|
||||
|
@ -480,7 +475,6 @@ impl<'gc> ClassObject<'gc> {
|
|||
scope,
|
||||
None,
|
||||
Some(self),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
|
||||
constructor.exec(receiver, arguments, activation, self.into())
|
||||
|
|
|
@ -24,7 +24,7 @@ pub struct FunctionObjectData<'gc> {
|
|||
base: ScriptObjectData<'gc>,
|
||||
|
||||
/// Executable code
|
||||
exec: Option<Executable<'gc>>,
|
||||
exec: Executable<'gc>,
|
||||
}
|
||||
|
||||
impl<'gc> FunctionObject<'gc> {
|
||||
|
@ -66,13 +66,7 @@ impl<'gc> FunctionObject<'gc> {
|
|||
subclass_object: Option<ClassObject<'gc>>,
|
||||
) -> Object<'gc> {
|
||||
let fn_proto = activation.avm2().prototypes().function;
|
||||
let exec = Some(Executable::from_method(
|
||||
method,
|
||||
scope,
|
||||
receiver,
|
||||
subclass_object,
|
||||
activation.context.gc_context,
|
||||
));
|
||||
let exec = Executable::from_method(method, scope, receiver, subclass_object);
|
||||
|
||||
FunctionObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
|
@ -110,8 +104,8 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
Ok(Value::Object(Object::from(*self)))
|
||||
}
|
||||
|
||||
fn as_executable(&self) -> Option<Executable<'gc>> {
|
||||
self.0.read().exec.clone()
|
||||
fn as_executable(&self) -> Option<Ref<Executable<'gc>>> {
|
||||
Some(Ref::map(self.0.read(), |r| &r.exec))
|
||||
}
|
||||
|
||||
fn call(
|
||||
|
@ -120,11 +114,10 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
arguments: &[Value<'gc>],
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
if let Some(exec) = &self.0.read().exec {
|
||||
exec.exec(receiver, arguments, activation, self.into())
|
||||
} else {
|
||||
Err("Not a callable function!".into())
|
||||
}
|
||||
self.0
|
||||
.read()
|
||||
.exec
|
||||
.exec(receiver, arguments, activation, self.into())
|
||||
}
|
||||
|
||||
fn construct(
|
||||
|
@ -151,10 +144,11 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> {
|
||||
let this: Object<'gc> = Object::FunctionObject(*self);
|
||||
let base = ScriptObjectData::base_new(Some(this), None);
|
||||
let exec = self.0.read().exec.clone();
|
||||
|
||||
Ok(FunctionObject(GcCell::allocate(
|
||||
activation.context.gc_context,
|
||||
FunctionObjectData { base, exec: None },
|
||||
FunctionObjectData { base, exec },
|
||||
))
|
||||
.into())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue