avm2: Refactor Executable->BoundMethod, introduce freestanding exec()
This commit is contained in:
parent
3bb47db5f9
commit
2532d7e927
|
@ -4,7 +4,6 @@ use std::rc::Rc;
|
|||
|
||||
use crate::avm2::class::AllocatorFn;
|
||||
use crate::avm2::error::make_error_1107;
|
||||
use crate::avm2::function::Executable;
|
||||
use crate::avm2::globals::SystemClasses;
|
||||
use crate::avm2::method::{Method, NativeMethodImpl};
|
||||
use crate::avm2::scope::ScopeChain;
|
||||
|
@ -598,8 +597,13 @@ impl<'gc> Avm2<'gc> {
|
|||
}
|
||||
|
||||
/// Pushes an executable on the call stack
|
||||
pub fn push_call(&self, mc: &Mutation<'gc>, calling: &Executable<'gc>) {
|
||||
self.call_stack.write(mc).push(calling)
|
||||
pub fn push_call(
|
||||
&self,
|
||||
mc: &Mutation<'gc>,
|
||||
method: Method<'gc>,
|
||||
superclass: Option<ClassObject<'gc>>,
|
||||
) {
|
||||
self.call_stack.write(mc).push(method, superclass)
|
||||
}
|
||||
|
||||
/// Pushes script initializer (global init) on the call stack
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::avm2::function::{display_function, Executable};
|
||||
use crate::avm2::function::display_function;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::object::ClassObject;
|
||||
use crate::string::WString;
|
||||
|
@ -27,11 +27,8 @@ impl<'gc> CallStack<'gc> {
|
|||
Self { stack: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn push(&mut self, exec: &Executable<'gc>) {
|
||||
self.stack.push(CallNode::Method {
|
||||
method: exec.as_method(),
|
||||
superclass: exec.bound_superclass(),
|
||||
})
|
||||
pub fn push(&mut self, method: Method<'gc>, superclass: Option<ClassObject<'gc>>) {
|
||||
self.stack.push(CallNode::Method { method, superclass })
|
||||
}
|
||||
|
||||
pub fn push_global_init(&mut self, script: Script<'gc>) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
//! AVM2 executables.
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::method::{BytecodeMethod, Method, NativeMethod, ParamConfig};
|
||||
use crate::avm2::method::{Method, ParamConfig};
|
||||
use crate::avm2::object::{ClassObject, Object};
|
||||
use crate::avm2::scope::ScopeChain;
|
||||
use crate::avm2::traits::TraitKind;
|
||||
|
@ -11,13 +9,12 @@ use crate::string::WString;
|
|||
use gc_arena::{Collect, Gc};
|
||||
use std::fmt;
|
||||
|
||||
/// Represents code written in AVM2 bytecode that can be executed by some
|
||||
/// means.
|
||||
/// Represents a bound method.
|
||||
#[derive(Clone, Collect)]
|
||||
#[collect(no_drop)]
|
||||
pub struct BytecodeExecutable<'gc> {
|
||||
pub struct BoundMethod<'gc> {
|
||||
/// The method code to execute from a given ABC file.
|
||||
method: Gc<'gc, BytecodeMethod<'gc>>,
|
||||
method: Method<'gc>,
|
||||
|
||||
/// The scope this method was defined in.
|
||||
scope: ScopeChain<'gc>,
|
||||
|
@ -26,68 +23,100 @@ pub struct BytecodeExecutable<'gc> {
|
|||
///
|
||||
/// If `None`, then the receiver provided by the caller is used. A
|
||||
/// `Some` value indicates a bound executable.
|
||||
receiver: Option<Object<'gc>>,
|
||||
|
||||
/// The bound superclass for this method.
|
||||
///
|
||||
/// The `superclass` is the class that defined this method. If `None`,
|
||||
/// then there is no defining superclass and `super` operations should fall
|
||||
/// back to the `receiver`.
|
||||
bound_superclass: Option<ClassObject<'gc>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Collect)]
|
||||
#[collect(no_drop)]
|
||||
pub struct NativeExecutable<'gc> {
|
||||
/// The method associated with the executable.
|
||||
method: Gc<'gc, NativeMethod<'gc>>,
|
||||
|
||||
/// The scope this method was defined in.
|
||||
scope: ScopeChain<'gc>,
|
||||
|
||||
/// The bound receiver for this method.
|
||||
bound_receiver: Option<Object<'gc>>,
|
||||
|
||||
/// The bound superclass for this method.
|
||||
/// The bound class for this method.
|
||||
///
|
||||
/// The `superclass` is the class that defined this method. If `None`,
|
||||
/// then there is no defining superclass and `super` operations should fall
|
||||
/// The `class` is the class that defined this method. If `None`,
|
||||
/// then there is no defining class and `super` operations should fall
|
||||
/// back to the `receiver`.
|
||||
bound_superclass: Option<ClassObject<'gc>>,
|
||||
bound_class: Option<ClassObject<'gc>>,
|
||||
}
|
||||
|
||||
/// Represents code that can be executed by some means.
|
||||
#[derive(Clone, Collect)]
|
||||
#[collect(no_drop)]
|
||||
pub enum Executable<'gc> {
|
||||
/// Code defined in Ruffle's binary.
|
||||
Native(NativeExecutable<'gc>),
|
||||
|
||||
/// Code defined in a loaded ABC file.
|
||||
Action(BytecodeExecutable<'gc>),
|
||||
}
|
||||
|
||||
impl<'gc> Executable<'gc> {
|
||||
/// Convert a method into an executable.
|
||||
impl<'gc> BoundMethod<'gc> {
|
||||
pub fn from_method(
|
||||
method: Method<'gc>,
|
||||
scope: ScopeChain<'gc>,
|
||||
receiver: Option<Object<'gc>>,
|
||||
superclass: Option<ClassObject<'gc>>,
|
||||
) -> Self {
|
||||
match method {
|
||||
Method::Native(method) => Self::Native(NativeExecutable {
|
||||
Self {
|
||||
method,
|
||||
scope,
|
||||
bound_receiver: receiver,
|
||||
bound_superclass: superclass,
|
||||
}),
|
||||
Method::Bytecode(method) => Self::Action(BytecodeExecutable {
|
||||
method,
|
||||
scope,
|
||||
bound_class: superclass,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exec(
|
||||
&self,
|
||||
unbound_receiver: Value<'gc>,
|
||||
arguments: &[Value<'gc>],
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
callee: Object<'gc>,
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
let receiver = if let Some(receiver) = self.bound_receiver {
|
||||
receiver
|
||||
} else if matches!(unbound_receiver, Value::Null | Value::Undefined) {
|
||||
self.scope
|
||||
.get(0)
|
||||
.expect("No global scope for function call")
|
||||
.values()
|
||||
} else {
|
||||
unbound_receiver.coerce_to_object(activation)?
|
||||
};
|
||||
|
||||
exec(
|
||||
self.method,
|
||||
self.scope,
|
||||
receiver,
|
||||
bound_superclass: superclass,
|
||||
}),
|
||||
self.bound_class,
|
||||
arguments,
|
||||
activation,
|
||||
callee,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn bound_superclass(&self) -> Option<ClassObject<'gc>> {
|
||||
self.bound_class
|
||||
}
|
||||
|
||||
pub fn as_method(&self) -> Method<'gc> {
|
||||
self.method
|
||||
}
|
||||
|
||||
pub fn debug_full_name(&self) -> WString {
|
||||
let mut output = WString::new();
|
||||
display_function(&mut output, &self.as_method(), self.bound_superclass());
|
||||
output
|
||||
}
|
||||
|
||||
pub fn num_parameters(&self) -> usize {
|
||||
match self.method {
|
||||
Method::Native(method) => method.signature.len(),
|
||||
Method::Bytecode(method) => method.signature.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> &[ParamConfig<'gc>] {
|
||||
match &self.method {
|
||||
Method::Native(method) => &method.signature,
|
||||
Method::Bytecode(method) => method.signature(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_variadic(&self) -> bool {
|
||||
match self.method {
|
||||
Method::Native(method) => method.is_variadic,
|
||||
Method::Bytecode(method) => method.is_variadic(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn return_type(&self) -> &Multiname<'gc> {
|
||||
match &self.method {
|
||||
Method::Native(method) => &method.return_type,
|
||||
Method::Bytecode(method) => &method.return_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,58 +131,46 @@ impl<'gc> Executable<'gc> {
|
|||
///
|
||||
/// Passed-in arguments will be conformed to the set of method parameters
|
||||
/// declared on the function.
|
||||
pub fn exec(
|
||||
&self,
|
||||
unbound_receiver: Value<'gc>,
|
||||
pub fn exec<'gc>(
|
||||
method: Method<'gc>,
|
||||
scope: ScopeChain<'gc>,
|
||||
receiver: Object<'gc>,
|
||||
bound_class: Option<ClassObject<'gc>>,
|
||||
mut arguments: &[Value<'gc>],
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
callee: Object<'gc>,
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
let ret = match self {
|
||||
Executable::Native(bm) => {
|
||||
let method = bm.method.method;
|
||||
|
||||
let receiver = if let Some(receiver) = bm.bound_receiver {
|
||||
receiver
|
||||
} else if matches!(unbound_receiver, Value::Null | Value::Undefined) {
|
||||
bm.scope
|
||||
.get(0)
|
||||
.expect("No global scope for function call")
|
||||
.values()
|
||||
} else {
|
||||
unbound_receiver.coerce_to_object(activation)?
|
||||
};
|
||||
|
||||
let ret = match method {
|
||||
Method::Native(bm) => {
|
||||
let caller_domain = activation.caller_domain();
|
||||
let caller_movie = activation.caller_movie();
|
||||
let subclass_object = bm.bound_superclass;
|
||||
let mut activation = Activation::from_builtin(
|
||||
activation.context.reborrow(),
|
||||
subclass_object,
|
||||
bm.scope,
|
||||
bound_class,
|
||||
scope,
|
||||
caller_domain,
|
||||
caller_movie,
|
||||
);
|
||||
|
||||
if arguments.len() > bm.method.signature.len() && !bm.method.is_variadic {
|
||||
if arguments.len() > bm.signature.len() && !bm.is_variadic {
|
||||
return Err(format!(
|
||||
"Attempted to call {:?} with {} arguments (more than {} is prohibited)",
|
||||
bm.method.name,
|
||||
bm.name,
|
||||
arguments.len(),
|
||||
bm.method.signature.len()
|
||||
bm.signature.len()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
if bm.method.resolved_signature.read().is_none() {
|
||||
bm.method.resolve_signature(&mut activation)?;
|
||||
if bm.resolved_signature.read().is_none() {
|
||||
bm.resolve_signature(&mut activation)?;
|
||||
}
|
||||
|
||||
let resolved_signature = bm.method.resolved_signature.read();
|
||||
let resolved_signature = bm.resolved_signature.read();
|
||||
let resolved_signature = resolved_signature.as_ref().unwrap();
|
||||
|
||||
let arguments = activation.resolve_parameters(
|
||||
Method::Native(bm.method),
|
||||
method,
|
||||
arguments,
|
||||
resolved_signature,
|
||||
Some(callee),
|
||||
|
@ -161,46 +178,26 @@ impl<'gc> Executable<'gc> {
|
|||
activation
|
||||
.context
|
||||
.avm2
|
||||
.push_call(activation.context.gc_context, self);
|
||||
method(&mut activation, receiver, &arguments)
|
||||
.push_call(activation.context.gc_context, method, bound_class);
|
||||
(bm.method)(&mut activation, receiver, &arguments)
|
||||
}
|
||||
Executable::Action(bm) => {
|
||||
if bm.method.is_unchecked() {
|
||||
let max_args = bm.method.signature().len();
|
||||
if arguments.len() > max_args && !bm.method.is_variadic() {
|
||||
Method::Bytecode(bm) => {
|
||||
if bm.is_unchecked() {
|
||||
let max_args = bm.signature().len();
|
||||
if arguments.len() > max_args && !bm.is_variadic() {
|
||||
arguments = &arguments[..max_args];
|
||||
}
|
||||
}
|
||||
|
||||
let receiver = if let Some(receiver) = bm.receiver {
|
||||
receiver
|
||||
} else if matches!(unbound_receiver, Value::Null | Value::Undefined) {
|
||||
bm.scope
|
||||
.get(0)
|
||||
.expect("No global scope for function call")
|
||||
.values()
|
||||
} else {
|
||||
unbound_receiver.coerce_to_object(activation)?
|
||||
};
|
||||
|
||||
let subclass_object = bm.bound_superclass;
|
||||
|
||||
// This used to be a one step called Activation::from_method,
|
||||
// but avoiding moving an Activation around helps perf
|
||||
let mut activation = Activation::from_nothing(activation.context.reborrow());
|
||||
activation.init_from_method(
|
||||
bm.method,
|
||||
bm.scope,
|
||||
receiver,
|
||||
arguments,
|
||||
subclass_object,
|
||||
callee,
|
||||
)?;
|
||||
activation.init_from_method(bm, scope, receiver, arguments, bound_class, callee)?;
|
||||
activation
|
||||
.context
|
||||
.avm2
|
||||
.push_call(activation.context.gc_context, self);
|
||||
activation.run_actions(bm.method)
|
||||
.push_call(activation.context.gc_context, method, bound_class);
|
||||
activation.run_actions(bm)
|
||||
}
|
||||
};
|
||||
activation
|
||||
|
@ -210,72 +207,20 @@ impl<'gc> Executable<'gc> {
|
|||
ret
|
||||
}
|
||||
|
||||
pub fn bound_superclass(&self) -> Option<ClassObject<'gc>> {
|
||||
match self {
|
||||
Executable::Native(NativeExecutable {
|
||||
bound_superclass, ..
|
||||
}) => *bound_superclass,
|
||||
Executable::Action(BytecodeExecutable {
|
||||
bound_superclass, ..
|
||||
}) => *bound_superclass,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_method(&self) -> Method<'gc> {
|
||||
match self {
|
||||
Executable::Native(nm) => Method::Native(nm.method),
|
||||
Executable::Action(bm) => Method::Bytecode(bm.method),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debug_full_name(&self) -> WString {
|
||||
let mut output = WString::new();
|
||||
display_function(&mut output, &self.as_method(), self.bound_superclass());
|
||||
output
|
||||
}
|
||||
|
||||
pub fn num_parameters(&self) -> usize {
|
||||
match self {
|
||||
Executable::Native(NativeExecutable { method, .. }) => method.signature.len(),
|
||||
Executable::Action(BytecodeExecutable { method, .. }) => method.signature.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> &[ParamConfig<'gc>] {
|
||||
match self {
|
||||
Executable::Native(NativeExecutable { method, .. }) => &method.signature,
|
||||
Executable::Action(BytecodeExecutable { method, .. }) => method.signature(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_variadic(&self) -> bool {
|
||||
match self {
|
||||
Executable::Native(NativeExecutable { method, .. }) => method.is_variadic,
|
||||
Executable::Action(BytecodeExecutable { method, .. }) => method.is_variadic(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn return_type(&self) -> &Multiname<'gc> {
|
||||
match self {
|
||||
Executable::Native(NativeExecutable { method, .. }) => &method.return_type,
|
||||
Executable::Action(BytecodeExecutable { method, .. }) => &method.return_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gc> fmt::Debug for Executable<'gc> {
|
||||
impl<'gc> fmt::Debug for BoundMethod<'gc> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Action(be) => fmt
|
||||
.debug_struct("Executable::Action")
|
||||
.field("method", &Gc::as_ptr(be.method))
|
||||
.field("scope", &be.scope)
|
||||
.field("receiver", &be.receiver)
|
||||
match self.method {
|
||||
Method::Bytecode(be) => fmt
|
||||
.debug_struct("BoundMethod")
|
||||
.field("method", &Gc::as_ptr(be))
|
||||
.field("scope", &self.scope)
|
||||
.field("receiver", &self.bound_receiver)
|
||||
.finish(),
|
||||
Self::Native(bm) => fmt
|
||||
.debug_struct("Executable::Native")
|
||||
.field("method", &bm.method)
|
||||
.field("bound_receiver", &bm.bound_receiver)
|
||||
Method::Native(bm) => fmt
|
||||
.debug_struct("BoundMethod")
|
||||
.field("method", &bm)
|
||||
.field("scope", &self.scope)
|
||||
.field("bound_receiver", &self.bound_receiver)
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::avm2::class::Class;
|
|||
use crate::avm2::domain::Domain;
|
||||
use crate::avm2::error;
|
||||
use crate::avm2::events::{DispatchList, Event};
|
||||
use crate::avm2::function::Executable;
|
||||
use crate::avm2::function::{exec, BoundMethod};
|
||||
use crate::avm2::property::Property;
|
||||
use crate::avm2::regexp::RegExp;
|
||||
use crate::avm2::value::{Hint, Value};
|
||||
|
@ -600,11 +600,14 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
class,
|
||||
} = full_method;
|
||||
|
||||
return Executable::from_method(method, scope, None, Some(class)).exec(
|
||||
Value::from(self.into()),
|
||||
return exec(
|
||||
method,
|
||||
scope,
|
||||
self.into(),
|
||||
Some(class),
|
||||
arguments,
|
||||
activation,
|
||||
class.into(), //Deliberately invalid.
|
||||
class.into(), //Callee deliberately invalid.
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1153,8 +1156,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
None
|
||||
}
|
||||
|
||||
/// Get this object's `Executable`, if it has one.
|
||||
fn as_executable(&self) -> Option<Ref<Executable<'gc>>> {
|
||||
/// Get this object's `BoundMethod`, if it has one.
|
||||
fn as_executable(&self) -> Option<Ref<BoundMethod<'gc>>> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::class::{Allocator, AllocatorFn, Class, ClassHashWrapper};
|
||||
use crate::avm2::error::{argument_error, make_error_1127, reference_error, type_error};
|
||||
use crate::avm2::function::Executable;
|
||||
use crate::avm2::function::exec;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::object::function_object::FunctionObject;
|
||||
use crate::avm2::object::script_object::{scriptobject_allocator, ScriptObjectData};
|
||||
|
@ -477,10 +477,16 @@ impl<'gc> ClassObject<'gc> {
|
|||
activation: &mut Activation<'_, 'gc>,
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
let scope = self.0.read().instance_scope;
|
||||
let constructor =
|
||||
Executable::from_method(self.0.read().constructor, scope, None, Some(self));
|
||||
|
||||
constructor.exec(receiver, arguments, activation, self.into())
|
||||
let method = self.0.read().constructor;
|
||||
exec(
|
||||
method,
|
||||
scope,
|
||||
receiver.coerce_to_object(activation)?,
|
||||
Some(self),
|
||||
arguments,
|
||||
activation,
|
||||
self.into(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Call the instance's native initializer.
|
||||
|
@ -495,10 +501,16 @@ impl<'gc> ClassObject<'gc> {
|
|||
activation: &mut Activation<'_, 'gc>,
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
let scope = self.0.read().instance_scope;
|
||||
let constructor =
|
||||
Executable::from_method(self.0.read().native_constructor, scope, None, Some(self));
|
||||
|
||||
constructor.exec(receiver, arguments, activation, self.into())
|
||||
let method = self.0.read().native_constructor;
|
||||
exec(
|
||||
method,
|
||||
scope,
|
||||
receiver.coerce_to_object(activation)?,
|
||||
Some(self),
|
||||
arguments,
|
||||
activation,
|
||||
self.into(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Supercall a method defined in this class.
|
||||
|
@ -842,9 +854,15 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
|
|||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some(call_handler) = self.0.read().call_handler {
|
||||
let scope = self.0.read().class_scope;
|
||||
let func = Executable::from_method(call_handler, scope, None, Some(self));
|
||||
|
||||
func.exec(receiver, arguments, activation, self.into())
|
||||
exec(
|
||||
call_handler,
|
||||
scope,
|
||||
receiver.coerce_to_object(activation)?,
|
||||
Some(self),
|
||||
arguments,
|
||||
activation,
|
||||
self.into(),
|
||||
)
|
||||
} else if arguments.len() == 1 {
|
||||
arguments[0].coerce_to_type(activation, self.inner_class_definition())
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Function object impl
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::function::Executable;
|
||||
use crate::avm2::function::BoundMethod;
|
||||
use crate::avm2::method::{Method, NativeMethod};
|
||||
use crate::avm2::object::script_object::{ScriptObject, ScriptObjectData};
|
||||
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
|
||||
|
@ -41,7 +41,7 @@ pub fn function_allocator<'gc>(
|
|||
activation.context.gc_context,
|
||||
FunctionObjectData {
|
||||
base,
|
||||
exec: Executable::from_method(
|
||||
exec: BoundMethod::from_method(
|
||||
Method::Native(dummy),
|
||||
activation.create_scopechain(),
|
||||
None,
|
||||
|
@ -78,7 +78,7 @@ pub struct FunctionObjectData<'gc> {
|
|||
base: ScriptObjectData<'gc>,
|
||||
|
||||
/// Executable code
|
||||
exec: Executable<'gc>,
|
||||
exec: BoundMethod<'gc>,
|
||||
|
||||
/// Attached prototype (note: not the same thing as base object's proto)
|
||||
prototype: Option<Object<'gc>>,
|
||||
|
@ -120,7 +120,7 @@ impl<'gc> FunctionObject<'gc> {
|
|||
subclass_object: Option<ClassObject<'gc>>,
|
||||
) -> FunctionObject<'gc> {
|
||||
let fn_class = activation.avm2().classes().function;
|
||||
let exec = Executable::from_method(method, scope, receiver, subclass_object);
|
||||
let exec = BoundMethod::from_method(method, scope, receiver, subclass_object);
|
||||
|
||||
FunctionObject(GcCell::new(
|
||||
activation.context.gc_context,
|
||||
|
@ -169,7 +169,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
Ok(Value::Object(Object::from(*self)))
|
||||
}
|
||||
|
||||
fn as_executable(&self) -> Option<Ref<Executable<'gc>>> {
|
||||
fn as_executable(&self) -> Option<Ref<BoundMethod<'gc>>> {
|
||||
Some(Ref::map(self.0.read(), |r| &r.exec))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::avm2::dynamic_map::DynamicKey;
|
||||
use crate::avm2::function::Executable;
|
||||
use crate::avm2::function::BoundMethod;
|
||||
use crate::avm2::method::{Method, ParamConfig};
|
||||
use crate::avm2::object::TObject;
|
||||
use crate::avm2::traits::{Trait, TraitKind};
|
||||
|
@ -166,7 +166,7 @@ impl FunctionInfo {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_executable(executable: &Executable, stubbed: bool) -> Self {
|
||||
pub fn from_bound_method(executable: &BoundMethod, stubbed: bool) -> Self {
|
||||
Self {
|
||||
returns: executable
|
||||
.return_type()
|
||||
|
@ -345,7 +345,7 @@ impl Definition {
|
|||
if let Some(executable) = object.as_executable() {
|
||||
output.get_or_insert_with(Default::default).function.insert(
|
||||
name.to_string(),
|
||||
FunctionInfo::from_executable(&executable, false),
|
||||
FunctionInfo::from_bound_method(&executable, false),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -494,7 +494,7 @@ pub fn capture_specification(context: &mut UpdateContext, output: &Path) {
|
|||
.get_or_insert_with(Default::default);
|
||||
instance_traits.function.insert(
|
||||
name.to_string(),
|
||||
FunctionInfo::from_executable(
|
||||
FunctionInfo::from_bound_method(
|
||||
&executable,
|
||||
namespace_stubs.has_method(&name.to_string()),
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue