avm1: Show stack frame with the avm_debug feature
This commit is contained in:
parent
c976cf8efb
commit
51321713b5
|
@ -39,7 +39,7 @@ pub mod xml_object;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::avm1::activation::Activation;
|
||||
use crate::avm1::activation::{Activation, ActivationIdentifier};
|
||||
use crate::avm1::error::Error;
|
||||
use crate::avm1::listeners::SystemListener;
|
||||
pub use globals::SystemPrototypes;
|
||||
|
@ -131,9 +131,10 @@ impl<'gc> Avm1<'gc> {
|
|||
/// Add a stack frame that executes code in timeline scope
|
||||
///
|
||||
/// This creates a new frame stack.
|
||||
pub fn run_stack_frame_for_action(
|
||||
pub fn run_stack_frame_for_action<S: Into<Cow<'static, str>>>(
|
||||
&mut self,
|
||||
active_clip: DisplayObject<'gc>,
|
||||
name: S,
|
||||
swf_version: u8,
|
||||
code: SwfSlice,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
|
@ -145,6 +146,7 @@ impl<'gc> Avm1<'gc> {
|
|||
|
||||
let mut parent_activation = Activation::from_nothing(
|
||||
self,
|
||||
ActivationIdentifier::root("[Actions Parent]"),
|
||||
swf_version,
|
||||
self.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
@ -165,6 +167,7 @@ impl<'gc> Avm1<'gc> {
|
|||
let constant_pool = parent_activation.avm.constant_pool;
|
||||
let mut child_activation = Activation::from_action(
|
||||
parent_activation.avm,
|
||||
parent_activation.id.child(name),
|
||||
swf_version,
|
||||
child_scope,
|
||||
constant_pool,
|
||||
|
@ -204,6 +207,7 @@ impl<'gc> Avm1<'gc> {
|
|||
);
|
||||
let mut activation = Activation::from_action(
|
||||
self,
|
||||
ActivationIdentifier::root("[Display Object]"),
|
||||
swf_version,
|
||||
child_scope,
|
||||
self.constant_pool,
|
||||
|
@ -231,6 +235,7 @@ impl<'gc> Avm1<'gc> {
|
|||
|
||||
let mut parent_activation = Activation::from_nothing(
|
||||
self,
|
||||
ActivationIdentifier::root("[Init Parent]"),
|
||||
swf_version,
|
||||
self.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
@ -252,6 +257,7 @@ impl<'gc> Avm1<'gc> {
|
|||
let constant_pool = parent_activation.avm.constant_pool;
|
||||
let mut child_activation = Activation::from_action(
|
||||
parent_activation.avm,
|
||||
parent_activation.id.child("[Init]"),
|
||||
swf_version,
|
||||
child_scope,
|
||||
constant_pool,
|
||||
|
@ -284,6 +290,7 @@ impl<'gc> Avm1<'gc> {
|
|||
|
||||
let mut activation = Activation::from_nothing(
|
||||
self,
|
||||
ActivationIdentifier::root(name.to_owned()),
|
||||
swf_version,
|
||||
self.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
@ -294,7 +301,7 @@ impl<'gc> Avm1<'gc> {
|
|||
search_prototype(Some(obj), name, &mut activation, context, obj).map(|r| (r.0, r.1));
|
||||
|
||||
if let Ok((callback, base_proto)) = search_result {
|
||||
let _ = callback.call(&mut activation, context, obj, base_proto, args);
|
||||
let _ = callback.call(name, &mut activation, context, obj, base_proto, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,6 +316,7 @@ impl<'gc> Avm1<'gc> {
|
|||
) {
|
||||
let mut activation = Activation::from_nothing(
|
||||
self,
|
||||
ActivationIdentifier::root("[System Listeners]"),
|
||||
swf_version,
|
||||
self.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
@ -319,7 +327,7 @@ impl<'gc> Avm1<'gc> {
|
|||
let mut handlers = listeners.prepare_handlers(&mut activation, context, method);
|
||||
|
||||
for (listener, handler) in handlers.drain(..) {
|
||||
let _ = handler.call(&mut activation, context, listener, None, &args);
|
||||
let _ = handler.call(method, &mut activation, context, listener, None, &args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ use smallvec::SmallVec;
|
|||
use std::borrow::Cow;
|
||||
use std::cell::{Ref, RefMut};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use swf::avm1::read::Reader;
|
||||
use swf::avm1::types::{Action, CatchVar, Function, TryBlock};
|
||||
use url::form_urlencoded;
|
||||
|
@ -88,8 +89,58 @@ enum FrameControl<'gc> {
|
|||
Return(ReturnType<'gc>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ActivationIdentifier<'a> {
|
||||
parent: Option<&'a ActivationIdentifier<'a>>,
|
||||
name: Cow<'static, str>,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl fmt::Display for ActivationIdentifier<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(parent) = self.parent {
|
||||
write!(f, "{} / ", parent)?;
|
||||
}
|
||||
|
||||
f.write_str(&self.name)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ActivationIdentifier<'a> {
|
||||
pub fn root<S: Into<Cow<'static, str>>>(name: S) -> Self {
|
||||
Self {
|
||||
parent: None,
|
||||
name: name.into(),
|
||||
depth: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn child<S: Into<Cow<'static, str>>>(&'a self, name: S) -> Self {
|
||||
Self {
|
||||
parent: Some(self),
|
||||
name: name.into(),
|
||||
depth: self.depth + 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn depth(&self) -> usize {
|
||||
self.depth
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'gc> gc_arena::Collect for ActivationIdentifier<'gc> {
|
||||
fn needs_trace() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn trace(&self, _cc: gc_arena::CollectionContext) {}
|
||||
}
|
||||
|
||||
#[derive(Collect)]
|
||||
#[collect(no_drop)]
|
||||
#[collect(unsafe_drop)]
|
||||
pub struct Activation<'a, 'gc: 'a> {
|
||||
pub avm: &'a mut Avm1<'gc>,
|
||||
|
||||
|
@ -137,11 +188,24 @@ pub struct Activation<'a, 'gc: 'a> {
|
|||
/// The current target display object of this stack frame.
|
||||
/// This can be changed with `tellTarget` (via `ActionSetTarget` and `ActionSetTarget2`).
|
||||
target_clip: Option<DisplayObject<'gc>>,
|
||||
|
||||
/// An identifier to refer to this activation by, when debugging.
|
||||
/// This is often the name of a function (if known), or some static name to indicate where
|
||||
/// in the code it is (for example, a with{} block).
|
||||
pub id: ActivationIdentifier<'a>,
|
||||
}
|
||||
|
||||
impl Drop for Activation<'_, '_> {
|
||||
fn drop(&mut self) {
|
||||
avm_debug!("END {}", self.id);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn from_action(
|
||||
avm: &'a mut Avm1<'gc>,
|
||||
id: ActivationIdentifier<'a>,
|
||||
swf_version: u8,
|
||||
scope: GcCell<'gc, Scope<'gc>>,
|
||||
constant_pool: GcCell<'gc, Vec<String>>,
|
||||
|
@ -149,8 +213,10 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
this: Object<'gc>,
|
||||
arguments: Option<Object<'gc>>,
|
||||
) -> Self {
|
||||
avm_debug!("START {}", id);
|
||||
Self {
|
||||
avm,
|
||||
id,
|
||||
swf_version,
|
||||
scope,
|
||||
constant_pool,
|
||||
|
@ -164,9 +230,16 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
}
|
||||
|
||||
/// Create a new activation to run a block of code with a given scope.
|
||||
pub fn with_new_scope<'b>(&'b mut self, scope: GcCell<'gc, Scope<'gc>>) -> Activation<'b, 'gc> {
|
||||
pub fn with_new_scope<'b, S: Into<Cow<'static, str>>>(
|
||||
&'b mut self,
|
||||
name: S,
|
||||
scope: GcCell<'gc, Scope<'gc>>,
|
||||
) -> Activation<'b, 'gc> {
|
||||
let id = self.id.child(name);
|
||||
avm_debug!("START {}", id);
|
||||
Activation {
|
||||
avm: self.avm,
|
||||
id,
|
||||
swf_version: self.swf_version,
|
||||
scope,
|
||||
constant_pool: self.constant_pool,
|
||||
|
@ -185,6 +258,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
/// activation frame with access to the global context.
|
||||
pub fn from_nothing(
|
||||
avm: &'a mut Avm1<'gc>,
|
||||
id: ActivationIdentifier<'a>,
|
||||
swf_version: u8,
|
||||
globals: Object<'gc>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
|
@ -193,9 +267,11 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
let global_scope = GcCell::allocate(mc, Scope::from_global_object(globals));
|
||||
let child_scope = GcCell::allocate(mc, Scope::new_local_scope(global_scope, mc));
|
||||
let empty_constant_pool = GcCell::allocate(mc, Vec::new());
|
||||
avm_debug!("START {}", id);
|
||||
|
||||
Self {
|
||||
avm,
|
||||
id,
|
||||
swf_version,
|
||||
scope: child_scope,
|
||||
constant_pool: empty_constant_pool,
|
||||
|
@ -209,8 +285,9 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
}
|
||||
|
||||
/// Add a stack frame that executes code in timeline scope
|
||||
pub fn run_child_frame_for_action(
|
||||
pub fn run_child_frame_for_action<S: Into<Cow<'static, str>>>(
|
||||
&mut self,
|
||||
name: S,
|
||||
active_clip: DisplayObject<'gc>,
|
||||
swf_version: u8,
|
||||
code: SwfSlice,
|
||||
|
@ -218,6 +295,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
) -> Result<ReturnType<'gc>, Error<'gc>> {
|
||||
let mut parent_activation = Activation::from_nothing(
|
||||
self.avm,
|
||||
self.id.child("[Actions Parent]"),
|
||||
swf_version,
|
||||
self.avm.globals,
|
||||
context.gc_context,
|
||||
|
@ -237,6 +315,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
let constant_pool = parent_activation.avm.constant_pool;
|
||||
let mut child_activation = Activation::from_action(
|
||||
parent_activation.avm,
|
||||
parent_activation.id.child(name),
|
||||
swf_version,
|
||||
child_scope,
|
||||
constant_pool,
|
||||
|
@ -248,8 +327,9 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
}
|
||||
|
||||
/// Add a stack frame that executes code in initializer scope.
|
||||
pub fn run_with_child_frame_for_display_object<'c, F, R>(
|
||||
pub fn run_with_child_frame_for_display_object<'c, F, R, S: Into<Cow<'static, str>>>(
|
||||
&mut self,
|
||||
name: S,
|
||||
active_clip: DisplayObject<'gc>,
|
||||
swf_version: u8,
|
||||
action_context: &mut UpdateContext<'c, 'gc, '_>,
|
||||
|
@ -273,6 +353,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
let constant_pool = self.avm.constant_pool;
|
||||
let mut activation = Activation::from_action(
|
||||
self.avm,
|
||||
self.id.child(name),
|
||||
swf_version,
|
||||
child_scope,
|
||||
constant_pool,
|
||||
|
@ -311,7 +392,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
//Executing beyond the end of a function constitutes an implicit return.
|
||||
Ok(FrameControl::Return(ReturnType::Implicit))
|
||||
} else if let Some(action) = reader.read_action()? {
|
||||
avm_debug!("Action: {:?}", action);
|
||||
avm_debug!("({}) Action: {:?}", self.id.depth(), action);
|
||||
|
||||
let result = match action {
|
||||
Action::Add => self.action_add(context),
|
||||
|
@ -654,6 +735,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
if let Some(frame) = frame {
|
||||
for action in clip.actions_on_frame(context, frame) {
|
||||
let _ = self.run_child_frame_for_action(
|
||||
"[Frame Call]",
|
||||
self.target_clip_or_root(),
|
||||
self.current_swf_version(),
|
||||
action,
|
||||
|
@ -687,7 +769,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
.target_clip_or_root()
|
||||
.object()
|
||||
.coerce_to_object(self, context);
|
||||
let result = target_fn.call(self, context, this, None, &args)?;
|
||||
let result = target_fn.call(&fn_name, self, context, this, None, &args)?;
|
||||
self.avm.push(result);
|
||||
|
||||
Ok(FrameControl::Continue)
|
||||
|
@ -712,12 +794,12 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
.target_clip_or_root()
|
||||
.object()
|
||||
.coerce_to_object(self, context);
|
||||
let result = object.call(self, context, this, None, &args)?;
|
||||
let result = object.call("[Anonymous]", self, context, this, None, &args)?;
|
||||
self.avm.push(result);
|
||||
}
|
||||
Value::String(name) => {
|
||||
if name.is_empty() {
|
||||
let result = object.call(self, context, object, None, &args)?;
|
||||
let result = object.call("[Anonymous]", self, context, object, None, &args)?;
|
||||
self.avm.push(result);
|
||||
} else {
|
||||
let result = object.call_method(&name, &args, self, context)?;
|
||||
|
@ -1601,7 +1683,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
}
|
||||
|
||||
//TODO: What happens if you `ActionNewMethod` without a method name?
|
||||
constructor.call(self, context, this, None, &args)?;
|
||||
constructor.call("[ctor]", self, context, this, None, &args)?;
|
||||
|
||||
self.avm.push(this);
|
||||
} else {
|
||||
|
@ -1652,7 +1734,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
);
|
||||
}
|
||||
|
||||
constructor.call(self, context, this, None, &args)?;
|
||||
constructor.call("[ctor]", self, context, this, None, &args)?;
|
||||
|
||||
self.avm.push(this);
|
||||
|
||||
|
@ -2247,7 +2329,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||
let object = self.avm.pop().coerce_to_object(self, context);
|
||||
let with_scope = Scope::new_with_scope(self.scope_cell(), object, context.gc_context);
|
||||
let mut new_activation = self.with_new_scope(with_scope);
|
||||
let mut new_activation = self.with_new_scope("[With]", with_scope);
|
||||
if let ReturnType::Explicit(value) = new_activation.run_actions(context, code)? {
|
||||
Ok(FrameControl::Return(ReturnType::Explicit(value)))
|
||||
} else {
|
||||
|
@ -2270,6 +2352,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
|||
if let Err(Error::ThrownValue(value)) = &result {
|
||||
let mut activation = Activation::from_action(
|
||||
self.avm,
|
||||
self.id.child("[Catch]"),
|
||||
self.swf_version,
|
||||
self.scope,
|
||||
self.constant_pool,
|
||||
|
|
|
@ -222,6 +222,7 @@ impl<'gc> Executable<'gc> {
|
|||
/// create a new stack frame and execute the action data yourself.
|
||||
pub fn exec(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
ac: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -278,8 +279,29 @@ impl<'gc> Executable<'gc> {
|
|||
.unwrap_or(ac.player_version)
|
||||
};
|
||||
|
||||
let name = if cfg!(feature = "avm_debug") {
|
||||
let mut result = match &af.name {
|
||||
None => name.to_string(),
|
||||
Some(name) => name.to_string(),
|
||||
};
|
||||
|
||||
result.push('(');
|
||||
for i in 0..args.len() {
|
||||
result.push_str(args.get(i).unwrap().type_of());
|
||||
if i < args.len() - 1 {
|
||||
result.push_str(", ");
|
||||
}
|
||||
}
|
||||
result.push(')');
|
||||
|
||||
result
|
||||
} else {
|
||||
af.name.clone().unwrap_or_else(|| name.to_string())
|
||||
};
|
||||
|
||||
let mut frame = Activation::from_action(
|
||||
activation.avm,
|
||||
activation.id.child(name),
|
||||
effective_ver,
|
||||
child_scope,
|
||||
af.constant_pool,
|
||||
|
@ -468,9 +490,9 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
) -> Result<(), Error<'gc>> {
|
||||
self.base.set(name, value, activation, context)
|
||||
}
|
||||
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -478,7 +500,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some(exec) = self.as_executable() {
|
||||
exec.exec(activation, context, this, base_proto, args)
|
||||
exec.exec(name, activation, context, this, base_proto, args)
|
||||
} else {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
|
|
@ -811,7 +811,7 @@ fn sort_compare_custom<'gc>(
|
|||
// TODO: Handle errors.
|
||||
let args = [a.clone(), b.clone()];
|
||||
let ret = compare_fn
|
||||
.call(activation, context, this, None, &args)
|
||||
.call("[Compare]", activation, context, this, None, &args)
|
||||
.unwrap_or(Value::Undefined);
|
||||
match ret {
|
||||
Value::Number(n) if n > 0.0 => Ordering::Greater,
|
||||
|
|
|
@ -35,7 +35,7 @@ pub fn call<'gc>(
|
|||
};
|
||||
|
||||
match func.as_executable() {
|
||||
Some(exec) => exec.exec(activation, action_context, this, None, args),
|
||||
Some(exec) => exec.exec("[Anonymous]", activation, action_context, this, None, args),
|
||||
_ => Ok(Value::Undefined),
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,14 @@ pub fn apply<'gc>(
|
|||
}
|
||||
|
||||
match func.as_executable() {
|
||||
Some(exec) => exec.exec(activation, action_context, this, None, &child_args),
|
||||
Some(exec) => exec.exec(
|
||||
"[Anonymous]",
|
||||
activation,
|
||||
action_context,
|
||||
this,
|
||||
None,
|
||||
&child_args,
|
||||
),
|
||||
_ => Ok(Value::Undefined),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
/// it can be changed by `Function.apply`/`Function.call`.
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -120,7 +121,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
log::warn!("Object method {} is not callable", name);
|
||||
}
|
||||
|
||||
method.call(activation, context, (*self).into(), base_proto, args)
|
||||
method.call(name, activation, context, (*self).into(), base_proto, args)
|
||||
}
|
||||
|
||||
/// Call a setter defined in this object.
|
||||
|
|
|
@ -247,6 +247,7 @@ impl<'gc> ScriptObject<'gc> {
|
|||
this_proto.call_setter(name, value.clone(), activation, context)
|
||||
{
|
||||
let _ = rval.exec(
|
||||
"[Setter]",
|
||||
activation,
|
||||
context,
|
||||
this,
|
||||
|
@ -280,7 +281,8 @@ impl<'gc> ScriptObject<'gc> {
|
|||
};
|
||||
|
||||
if let Some(rval) = rval {
|
||||
let _ = rval.exec(activation, context, this, base_proto, &[value])?;
|
||||
let _ =
|
||||
rval.exec("[Setter]", activation, context, this, base_proto, &[value])?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +326,14 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
|
|||
}
|
||||
|
||||
if let Some(get) = exec {
|
||||
get.exec(activation, context, this, Some((*self).into()), &[])
|
||||
get.exec(
|
||||
"[Getter]",
|
||||
activation,
|
||||
context,
|
||||
this,
|
||||
Some((*self).into()),
|
||||
&[],
|
||||
)
|
||||
} else {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
@ -359,6 +368,7 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
|
|||
/// overrides that may need to interact with the underlying object.
|
||||
fn call(
|
||||
&self,
|
||||
_name: &str,
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
_this: Object<'gc>,
|
||||
|
@ -735,6 +745,7 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::avm1::activation::ActivationIdentifier;
|
||||
use crate::avm1::globals::system::SystemProperties;
|
||||
use crate::avm1::property::Attribute::*;
|
||||
use crate::avm1::Avm1;
|
||||
|
@ -811,6 +822,7 @@ mod tests {
|
|||
let globals = avm.global_object_cell();
|
||||
let mut activation = Activation::from_nothing(
|
||||
&mut avm,
|
||||
ActivationIdentifier::root("[Test]"),
|
||||
context.swf.version(),
|
||||
globals,
|
||||
context.gc_context,
|
||||
|
|
|
@ -89,9 +89,9 @@ impl<'gc> TObject<'gc> for SharedObject<'gc> {
|
|||
) -> Result<(), Error<'gc>> {
|
||||
self.base().set(name, value, activation, context)
|
||||
}
|
||||
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -99,7 +99,7 @@ impl<'gc> TObject<'gc> for SharedObject<'gc> {
|
|||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
self.base()
|
||||
.call(activation, context, this, base_proto, args)
|
||||
.call(name, activation, context, this, base_proto, args)
|
||||
}
|
||||
|
||||
fn call_setter(
|
||||
|
|
|
@ -150,9 +150,9 @@ impl<'gc> TObject<'gc> for SoundObject<'gc> {
|
|||
) -> Result<(), Error<'gc>> {
|
||||
self.base().set(name, value, activation, context)
|
||||
}
|
||||
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -160,7 +160,7 @@ impl<'gc> TObject<'gc> for SoundObject<'gc> {
|
|||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
self.base()
|
||||
.call(activation, context, this, base_proto, args)
|
||||
.call(name, activation, context, this, base_proto, args)
|
||||
}
|
||||
|
||||
fn call_setter(
|
||||
|
|
|
@ -218,9 +218,9 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -230,7 +230,7 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
|
|||
self.0
|
||||
.read()
|
||||
.base
|
||||
.call(activation, context, this, base_proto, args)
|
||||
.call(name, activation, context, this, base_proto, args)
|
||||
}
|
||||
|
||||
fn call_setter(
|
||||
|
|
|
@ -101,9 +101,9 @@ impl<'gc> TObject<'gc> for SuperObject<'gc> {
|
|||
//TODO: What happens if you set `super.__proto__`?
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
_this: Object<'gc>,
|
||||
|
@ -112,6 +112,7 @@ impl<'gc> TObject<'gc> for SuperObject<'gc> {
|
|||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some(constr) = self.super_constr(activation, context)? {
|
||||
constr.call(
|
||||
name,
|
||||
activation,
|
||||
context,
|
||||
self.0.read().child,
|
||||
|
@ -140,7 +141,7 @@ impl<'gc> TObject<'gc> for SuperObject<'gc> {
|
|||
log::warn!("Super method {} is not callable", name);
|
||||
}
|
||||
|
||||
method.call(activation, context, child, base_proto, args)
|
||||
method.call(name, activation, context, child, base_proto, args)
|
||||
}
|
||||
|
||||
fn call_setter(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::avm1::activation::Activation;
|
||||
use crate::avm1::activation::{Activation, ActivationIdentifier};
|
||||
use crate::avm1::error::Error;
|
||||
use crate::avm1::globals::system::SystemProperties;
|
||||
use crate::avm1::{Avm1, Object, UpdateContext};
|
||||
|
@ -99,6 +99,7 @@ where
|
|||
let globals = avm.global_object_cell();
|
||||
let mut activation = Activation::from_nothing(
|
||||
&mut avm,
|
||||
ActivationIdentifier::root("[Test]"),
|
||||
context.swf.version(),
|
||||
globals,
|
||||
context.gc_context,
|
||||
|
@ -128,7 +129,7 @@ macro_rules! test_method {
|
|||
$(
|
||||
args.push($arg.into());
|
||||
)*
|
||||
assert_eq!(function.call(activation, context, object, None, &args)?, $out.into(), "{:?} => {:?} in swf {}", args, $out, version);
|
||||
assert_eq!(function.call($name, activation, context, object, None, &args)?, $out.into(), "{:?} => {:?} in swf {}", args, $out, version);
|
||||
)*
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -501,8 +501,7 @@ impl<'gc> Value<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn type_of(&self) -> Value<'gc> {
|
||||
Value::String(
|
||||
pub fn type_of(&self) -> &'static str {
|
||||
match self {
|
||||
Value::Undefined => "undefined",
|
||||
Value::Null => "null",
|
||||
|
@ -511,8 +510,6 @@ impl<'gc> Value<'gc> {
|
|||
Value::String(_) => "string",
|
||||
Value::Object(object) => object.type_of(),
|
||||
}
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn coerce_to_object(
|
||||
|
@ -525,6 +522,7 @@ impl<'gc> Value<'gc> {
|
|||
|
||||
pub fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -532,7 +530,7 @@ impl<'gc> Value<'gc> {
|
|||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Value::Object(object) = self {
|
||||
object.call(activation, context, this, base_proto, args)
|
||||
object.call(name, activation, context, this, base_proto, args)
|
||||
} else {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
|
|
@ -154,9 +154,9 @@ impl<'gc> TObject<'gc> for ValueObject<'gc> {
|
|||
) -> Result<(), Error<'gc>> {
|
||||
self.0.read().base.set(name, value, activation, context)
|
||||
}
|
||||
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -166,7 +166,7 @@ impl<'gc> TObject<'gc> for ValueObject<'gc> {
|
|||
self.0
|
||||
.read()
|
||||
.base
|
||||
.call(activation, context, this, base_proto, args)
|
||||
.call(name, activation, context, this, base_proto, args)
|
||||
}
|
||||
|
||||
fn call_setter(
|
||||
|
|
|
@ -85,9 +85,9 @@ impl<'gc> TObject<'gc> for XMLAttributesObject<'gc> {
|
|||
);
|
||||
self.base().set(name, value, activation, context)
|
||||
}
|
||||
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -95,7 +95,7 @@ impl<'gc> TObject<'gc> for XMLAttributesObject<'gc> {
|
|||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
self.base()
|
||||
.call(activation, context, this, base_proto, args)
|
||||
.call(name, activation, context, this, base_proto, args)
|
||||
}
|
||||
|
||||
fn call_setter(
|
||||
|
|
|
@ -85,9 +85,9 @@ impl<'gc> TObject<'gc> for XMLIDMapObject<'gc> {
|
|||
) -> Result<(), Error<'gc>> {
|
||||
self.base().set(name, value, activation, context)
|
||||
}
|
||||
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -95,7 +95,7 @@ impl<'gc> TObject<'gc> for XMLIDMapObject<'gc> {
|
|||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
self.base()
|
||||
.call(activation, context, this, base_proto, args)
|
||||
.call(name, activation, context, this, base_proto, args)
|
||||
}
|
||||
|
||||
fn call_setter(
|
||||
|
|
|
@ -77,9 +77,9 @@ impl<'gc> TObject<'gc> for XMLObject<'gc> {
|
|||
) -> Result<(), Error<'gc>> {
|
||||
self.base().set(name, value, activation, context)
|
||||
}
|
||||
|
||||
fn call(
|
||||
&self,
|
||||
name: &str,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
|
@ -87,7 +87,7 @@ impl<'gc> TObject<'gc> for XMLObject<'gc> {
|
|||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
self.base()
|
||||
.call(activation, context, this, base_proto, args)
|
||||
.call(name, activation, context, this, base_proto, args)
|
||||
}
|
||||
|
||||
fn call_setter(
|
||||
|
|
|
@ -716,6 +716,7 @@ impl<'gc> EditText<'gc> {
|
|||
let parent = self.parent().unwrap();
|
||||
|
||||
activation.run_with_child_frame_for_display_object(
|
||||
"[Text Field Binding]",
|
||||
parent,
|
||||
context.swf.header().version,
|
||||
context,
|
||||
|
@ -806,6 +807,7 @@ impl<'gc> EditText<'gc> {
|
|||
// Note that this can call virtual setters, even though the opposite direction won't work
|
||||
// (virtual property changes do not affect the text field)
|
||||
activation.run_with_child_frame_for_display_object(
|
||||
"[Propagate Text Binding]",
|
||||
self.parent().unwrap(),
|
||||
context.swf.header().version,
|
||||
context,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use crate::avm1::{Avm1, Object, StageObject, TObject, Value};
|
||||
use crate::backend::audio::AudioStreamHandle;
|
||||
|
||||
use crate::avm1::activation::Activation;
|
||||
use crate::avm1::activation::{Activation, ActivationIdentifier};
|
||||
use crate::character::Character;
|
||||
use crate::context::{ActionType, RenderContext, UpdateContext};
|
||||
use crate::display_object::{
|
||||
|
@ -977,6 +977,7 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
|||
|
||||
let mut activation = Activation::from_nothing(
|
||||
avm,
|
||||
ActivationIdentifier::root("[Mouse Pick]"),
|
||||
context.swf.version(),
|
||||
avm.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
@ -1042,6 +1043,7 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
|||
if instantiated_from_avm && self.0.read().avm1_constructor.is_some() {
|
||||
let mut activation = Activation::from_nothing(
|
||||
avm,
|
||||
ActivationIdentifier::root("[Construct]"),
|
||||
context.swf.version(),
|
||||
avm.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
@ -1067,7 +1069,7 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
|||
}
|
||||
}
|
||||
self.0.write(context.gc_context).object = Some(object);
|
||||
let _ = constructor.call(&mut activation, context, object, None, &[]);
|
||||
let _ = constructor.call("[ctor]", &mut activation, context, object, None, &[]);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -1081,6 +1083,7 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
|||
if let Some(init_object) = init_object {
|
||||
let mut activation = Activation::from_nothing(
|
||||
avm,
|
||||
ActivationIdentifier::root("[Init]"),
|
||||
context.swf.version(),
|
||||
avm.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Management of async loaders
|
||||
|
||||
use crate::avm1::activation::Activation;
|
||||
use crate::avm1::activation::{Activation, ActivationIdentifier};
|
||||
use crate::avm1::{Object, TObject, Value};
|
||||
use crate::backend::navigator::OwnedFuture;
|
||||
use crate::context::{ActionQueue, ActionType};
|
||||
|
@ -476,6 +476,7 @@ impl<'gc> Loader<'gc> {
|
|||
|
||||
let mut activation = Activation::from_nothing(
|
||||
avm,
|
||||
ActivationIdentifier::root("[Form Loader]"),
|
||||
uc.swf.version(),
|
||||
avm.global_object_cell(),
|
||||
uc.gc_context,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::avm1::activation::Activation;
|
||||
use crate::avm1::activation::{Activation, ActivationIdentifier};
|
||||
use crate::avm1::debug::VariableDumper;
|
||||
use crate::avm1::globals::system::SystemProperties;
|
||||
use crate::avm1::listeners::SystemListener;
|
||||
|
@ -274,6 +274,7 @@ impl Player {
|
|||
|
||||
let mut activation = Activation::from_nothing(
|
||||
avm,
|
||||
ActivationIdentifier::root("[Version Setter]"),
|
||||
context.swf.version(),
|
||||
avm.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
@ -390,6 +391,7 @@ impl Player {
|
|||
|
||||
let mut activation = Activation::from_nothing(
|
||||
avm,
|
||||
ActivationIdentifier::root("[Variable Dumper]"),
|
||||
context.swf.version(),
|
||||
avm.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
@ -740,6 +742,7 @@ impl Player {
|
|||
ActionType::Normal { bytecode } => {
|
||||
avm.run_stack_frame_for_action(
|
||||
actions.clip,
|
||||
"[Frame]",
|
||||
context.swf.header().version,
|
||||
bytecode,
|
||||
context,
|
||||
|
@ -752,6 +755,7 @@ impl Player {
|
|||
} => {
|
||||
let mut activation = Activation::from_nothing(
|
||||
avm,
|
||||
ActivationIdentifier::root("[Construct]"),
|
||||
context.swf.version(),
|
||||
avm.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
@ -765,6 +769,7 @@ impl Player {
|
|||
object.set_proto(context.gc_context, Some(prototype));
|
||||
for event in events {
|
||||
let _ = activation.run_child_frame_for_action(
|
||||
"[Actions]",
|
||||
actions.clip,
|
||||
context.swf.header().version,
|
||||
event,
|
||||
|
@ -772,7 +777,14 @@ impl Player {
|
|||
);
|
||||
}
|
||||
|
||||
let _ = constructor.call(&mut activation, context, object, None, &[]);
|
||||
let _ = constructor.call(
|
||||
"[ctor]",
|
||||
&mut activation,
|
||||
context,
|
||||
object,
|
||||
None,
|
||||
&[],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -784,6 +796,7 @@ impl Player {
|
|||
for event in events {
|
||||
avm.run_stack_frame_for_action(
|
||||
actions.clip,
|
||||
"[Construct]",
|
||||
context.swf.header().version,
|
||||
event,
|
||||
context,
|
||||
|
@ -1005,6 +1018,7 @@ impl Player {
|
|||
self.update(|avm, context| {
|
||||
let mut activation = Activation::from_nothing(
|
||||
avm,
|
||||
ActivationIdentifier::root("[Flush]"),
|
||||
context.swf.version(),
|
||||
avm.global_object_cell(),
|
||||
context.gc_context,
|
||||
|
|
Loading…
Reference in New Issue