core: Allow toggling avm_debug output on and off with ctrl+alt+d, defaults to off

This commit is contained in:
Nathan Adams 2020-07-23 22:19:52 +02:00 committed by Mike Welsh
parent 2df3b81f92
commit 7f7281493f
7 changed files with 108 additions and 27 deletions

View File

@ -47,9 +47,10 @@ pub use timer::Timers;
pub use value::Value; pub use value::Value;
macro_rules! avm_debug { macro_rules! avm_debug {
($($arg:tt)*) => ( ($avm: expr, $($arg:tt)*) => (
#[cfg(feature = "avm_debug")] if $avm.show_debug_output() {
log::debug!($($arg)*) log::debug!($($arg)*)
}
) )
} }
@ -87,6 +88,9 @@ pub struct Avm1<'gc> {
/// The maximum amount of functions that can be called before a `Error::FunctionRecursionLimit` /// The maximum amount of functions that can be called before a `Error::FunctionRecursionLimit`
/// is raised. This defaults to 256 but can be changed per movie. /// is raised. This defaults to 256 but can be changed per movie.
max_recursion_depth: u16, max_recursion_depth: u16,
#[cfg(feature = "avm_debug")]
pub debug_output: bool,
} }
unsafe impl<'gc> gc_arena::Collect for Avm1<'gc> { unsafe impl<'gc> gc_arena::Collect for Avm1<'gc> {
@ -125,6 +129,9 @@ impl<'gc> Avm1<'gc> {
], ],
halted: false, halted: false,
max_recursion_depth: 255, max_recursion_depth: 255,
#[cfg(feature = "avm_debug")]
debug_output: false,
} }
} }
@ -346,7 +353,7 @@ impl<'gc> Avm1<'gc> {
fn push(&mut self, value: impl Into<Value<'gc>>) { fn push(&mut self, value: impl Into<Value<'gc>>) {
let value = value.into(); let value = value.into();
avm_debug!("Stack push {}: {:?}", self.stack.len(), value); avm_debug!(self, "Stack push {}: {:?}", self.stack.len(), value);
self.stack.push(value); self.stack.push(value);
} }
@ -357,7 +364,7 @@ impl<'gc> Avm1<'gc> {
Value::Undefined Value::Undefined
}); });
avm_debug!("Stack pop {}: {:?}", self.stack.len(), value); avm_debug!(self, "Stack pop {}: {:?}", self.stack.len(), value);
value value
} }
@ -384,6 +391,25 @@ impl<'gc> Avm1<'gc> {
pub fn set_max_recursion_depth(&mut self, max_recursion_depth: u16) { pub fn set_max_recursion_depth(&mut self, max_recursion_depth: u16) {
self.max_recursion_depth = max_recursion_depth self.max_recursion_depth = max_recursion_depth
} }
#[cfg(feature = "avm_debug")]
#[inline]
pub fn show_debug_output(&self) -> bool {
self.debug_output
}
#[cfg(not(feature = "avm_debug"))]
pub const fn show_debug_output(&self) -> bool {
false
}
#[cfg(feature = "avm_debug")]
pub fn set_show_debug_output(&mut self, visible: bool) {
self.debug_output = visible;
}
#[cfg(not(feature = "avm_debug"))]
pub const fn set_show_debug_output(&self, _visible: bool) {}
} }
pub fn root_error_handler<'gc>( pub fn root_error_handler<'gc>(

View File

@ -24,9 +24,10 @@ use swf::avm1::types::{Action, CatchVar, Function, TryBlock};
use url::form_urlencoded; use url::form_urlencoded;
macro_rules! avm_debug { macro_rules! avm_debug {
($($arg:tt)*) => ( ($avm: expr, $($arg:tt)*) => (
#[cfg(feature = "avm_debug")] if $avm.show_debug_output() {
log::debug!($($arg)*) log::debug!($($arg)*)
}
) )
} }
@ -227,7 +228,7 @@ pub struct Activation<'a, 'gc: 'a> {
impl Drop for Activation<'_, '_> { impl Drop for Activation<'_, '_> {
fn drop(&mut self) { fn drop(&mut self) {
avm_debug!("END {}", self.id); avm_debug!(self.avm, "END {}", self.id);
} }
} }
@ -243,7 +244,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
this: Object<'gc>, this: Object<'gc>,
arguments: Option<Object<'gc>>, arguments: Option<Object<'gc>>,
) -> Self { ) -> Self {
avm_debug!("START {}", id); avm_debug!(avm, "START {}", id);
Self { Self {
avm, avm,
id, id,
@ -265,7 +266,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
scope: GcCell<'gc, Scope<'gc>>, scope: GcCell<'gc, Scope<'gc>>,
) -> Activation<'b, 'gc> { ) -> Activation<'b, 'gc> {
let id = self.id.child(name); let id = self.id.child(name);
avm_debug!("START {}", id); avm_debug!(self.avm, "START {}", id);
Activation { Activation {
avm: self.avm, avm: self.avm,
id, id,
@ -295,7 +296,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
let global_scope = GcCell::allocate(mc, Scope::from_global_object(globals)); 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 child_scope = GcCell::allocate(mc, Scope::new_local_scope(global_scope, mc));
let empty_constant_pool = GcCell::allocate(mc, Vec::new()); let empty_constant_pool = GcCell::allocate(mc, Vec::new());
avm_debug!("START {}", id); avm_debug!(avm, "START {}", id);
Self { Self {
avm, avm,
@ -419,7 +420,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
//Executing beyond the end of a function constitutes an implicit return. //Executing beyond the end of a function constitutes an implicit return.
Ok(FrameControl::Return(ReturnType::Implicit)) Ok(FrameControl::Return(ReturnType::Implicit))
} else if let Some(action) = reader.read_action()? { } else if let Some(action) = reader.read_action()? {
avm_debug!("({}) Action: {:?}", self.id.depth(), action); avm_debug!(self.avm, "({}) Action: {:?}", self.id.depth(), action);
match action { match action {
Action::Add => self.action_add(context), Action::Add => self.action_add(context),
@ -2368,6 +2369,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
let value = self.avm.pop(); let value = self.avm.pop();
avm_debug!( avm_debug!(
self.avm,
"Thrown exception: {}", "Thrown exception: {}",
value value
.coerce_to_string(self, context) .coerce_to_string(self, context)

View File

@ -282,7 +282,7 @@ impl<'gc> Executable<'gc> {
.unwrap_or(ac.player_version) .unwrap_or(ac.player_version)
}; };
let name = if cfg!(feature = "avm_debug") { let name = if activation.avm.show_debug_output() {
let mut result = match &af.name { let mut result = match &af.name {
None => name.to_string(), None => name.to_string(),
Some(name) => name.to_string(), Some(name) => name.to_string(),

View File

@ -15,9 +15,10 @@ use swf::avm2::read::Reader;
#[macro_export] #[macro_export]
macro_rules! avm_debug { macro_rules! avm_debug {
($($arg:tt)*) => ( ($avm: expr, $($arg:tt)*) => (
#[cfg(feature = "avm_debug")] if $avm.show_debug_output() {
log::debug!($($arg)*) log::debug!($($arg)*)
}
) )
} }
@ -57,6 +58,9 @@ pub struct Avm2<'gc> {
/// System prototypes. /// System prototypes.
system_prototypes: SystemPrototypes<'gc>, system_prototypes: SystemPrototypes<'gc>,
#[cfg(feature = "avm_debug")]
pub debug_output: bool,
} }
impl<'gc> Avm2<'gc> { impl<'gc> Avm2<'gc> {
@ -68,6 +72,9 @@ impl<'gc> Avm2<'gc> {
stack: Vec::new(), stack: Vec::new(),
globals, globals,
system_prototypes, system_prototypes,
#[cfg(feature = "avm_debug")]
debug_output: false,
} }
} }
@ -135,7 +142,7 @@ impl<'gc> Avm2<'gc> {
/// Push a value onto the operand stack. /// Push a value onto the operand stack.
fn push(&mut self, value: impl Into<Value<'gc>>) { fn push(&mut self, value: impl Into<Value<'gc>>) {
let value = value.into(); let value = value.into();
avm_debug!("Stack push {}: {:?}", self.stack.len(), value); avm_debug!(self, "Stack push {}: {:?}", self.stack.len(), value);
self.stack.push(value); self.stack.push(value);
} }
@ -147,7 +154,7 @@ impl<'gc> Avm2<'gc> {
Value::Undefined Value::Undefined
}); });
avm_debug!("Stack pop {}: {:?}", self.stack.len(), value); avm_debug!(self, "Stack pop {}: {:?}", self.stack.len(), value);
value value
} }
@ -161,4 +168,23 @@ impl<'gc> Avm2<'gc> {
args args
} }
#[cfg(feature = "avm_debug")]
#[inline]
pub fn show_debug_output(&self) -> bool {
self.debug_output
}
#[cfg(not(feature = "avm_debug"))]
pub const fn show_debug_output(&self) -> bool {
false
}
#[cfg(feature = "avm_debug")]
pub fn set_show_debug_output(&mut self, visible: bool) {
self.debug_output = visible;
}
#[cfg(not(feature = "avm_debug"))]
pub const fn set_show_debug_output(&self, _visible: bool) {}
} }

View File

@ -415,7 +415,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let op = reader.read_op(); let op = reader.read_op();
if let Ok(Some(op)) = op { if let Ok(Some(op)) = op {
avm_debug!("Opcode: {:?}", op); avm_debug!(self.avm2, "Opcode: {:?}", op);
let result = match op { let result = match op {
Op::PushByte { value } => self.op_push_byte(value), Op::PushByte { value } => self.op_push_byte(value),
@ -1093,7 +1093,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let multiname = self.pool_multiname(method, index, context.gc_context)?; let multiname = self.pool_multiname(method, index, context.gc_context)?;
avm_debug!("Resolving {:?}", multiname); avm_debug!(self.avm2, "Resolving {:?}", multiname);
let result = if let Some(scope) = self.scope() { let result = if let Some(scope) = self.scope() {
scope.read().find(&multiname, self, context)? scope.read().find(&multiname, self, context)?
} else { } else {
@ -1113,7 +1113,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let multiname = self.pool_multiname(method, index, context.gc_context)?; let multiname = self.pool_multiname(method, index, context.gc_context)?;
avm_debug!("Resolving {:?}", multiname); avm_debug!(self.avm2, "Resolving {:?}", multiname);
let found: Result<Object<'gc>, Error> = if let Some(scope) = self.scope() { let found: Result<Object<'gc>, Error> = if let Some(scope) = self.scope() {
scope.read().find(&multiname, self, context)? scope.read().find(&multiname, self, context)?
} else { } else {
@ -1134,7 +1134,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
index: Index<AbcMultiname>, index: Index<AbcMultiname>,
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let multiname = self.pool_multiname_static(method, index, context.gc_context)?; let multiname = self.pool_multiname_static(method, index, context.gc_context)?;
avm_debug!("Resolving {:?}", multiname); avm_debug!(self.avm2, "Resolving {:?}", multiname);
let found: Result<Value<'gc>, Error> = if let Some(scope) = self.scope() { let found: Result<Value<'gc>, Error> = if let Some(scope) = self.scope() {
scope scope
.write(context.gc_context) .write(context.gc_context)
@ -1607,9 +1607,9 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
let register_name = self.pool_string(method, register_name)?; let register_name = self.pool_string(method, register_name)?;
let value = self.local_register(register as u32)?; let value = self.local_register(register as u32)?;
avm_debug!("Debug: {} = {:?}", register_name, value); avm_debug!(self.avm2, "Debug: {} = {:?}", register_name, value);
} else { } else {
avm_debug!("Unknown debugging mode!"); avm_debug!(self.avm2, "Unknown debugging mode!");
} }
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
@ -1636,7 +1636,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
) -> Result<FrameControl<'gc>, Error> { ) -> Result<FrameControl<'gc>, Error> {
let file_name = self.pool_string(method, file_name)?; let file_name = self.pool_string(method, file_name)?;
avm_debug!("File: {}", file_name); avm_debug!(self.avm2, "File: {}", file_name);
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
@ -1653,7 +1653,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
#[allow(unused_variables)] #[allow(unused_variables)]
fn op_debug_line(&mut self, line_num: u32) -> Result<FrameControl<'gc>, Error> { fn op_debug_line(&mut self, line_num: u32) -> Result<FrameControl<'gc>, Error> {
avm_debug!("Line: {}", line_num); avm_debug!(self.avm2, "Line: {}", line_num);
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }

View File

@ -431,6 +431,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
let fn_proto = activation.avm2().prototypes().function; let fn_proto = activation.avm2().prototypes().function;
let trait_name = trait_entry.name().clone(); let trait_name = trait_entry.name().clone();
avm_debug!( avm_debug!(
activation.avm2(),
"Installing trait {:?} of kind {:?}", "Installing trait {:?} of kind {:?}",
trait_name, trait_name,
trait_entry.kind() trait_entry.kind()

View File

@ -451,6 +451,32 @@ impl Player {
} }
} }
if cfg!(feature = "avm_debug") {
if let PlayerEvent::KeyDown {
key_code: KeyCode::D,
} = event
{
if self.input.is_key_down(KeyCode::Control) && self.input.is_key_down(KeyCode::Alt)
{
self.mutate_with_update_context(|avm1, avm2, _context| {
if avm1.show_debug_output() {
log::info!(
"AVM Debugging turned off! Press CTRL+ALT+D to turn off again."
);
avm1.set_show_debug_output(false);
avm2.set_show_debug_output(false);
} else {
log::info!(
"AVM Debugging turned on! Press CTRL+ALT+D to turn on again."
);
avm1.set_show_debug_output(true);
avm2.set_show_debug_output(true);
}
});
}
}
}
// Update mouse position from mouse events. // Update mouse position from mouse events.
if let PlayerEvent::MouseMove { x, y } if let PlayerEvent::MouseMove { x, y }
| PlayerEvent::MouseDown { x, y } | PlayerEvent::MouseDown { x, y }