diff --git a/core/src/avm2/globals/math.rs b/core/src/avm2/globals/math.rs index e51b94030019..be9fa5f126d5 100644 --- a/core/src/avm2/globals/math.rs +++ b/core/src/avm2/globals/math.rs @@ -6,6 +6,7 @@ use crate::avm2::object::Object; use crate::avm2::parameters::ParametersExt; use crate::avm2::value::Value; use crate::avm2::{ClassObject, Error}; +use num_traits::ToPrimitive; use rand::Rng; macro_rules! wrap_std { @@ -123,6 +124,30 @@ pub fn pow<'gc>( let n = args.get_f64(0); let p = args.get_f64(1); + // This condition is the simplest one that covers all special cases, + // so use it in order to create a fast path for finite n and p, which is + // the most common configuration. + if !n.is_finite() || !p.is_finite() { + match (n, p) { + // Special case: If p is NaN, the result is NaN. + (_, _) if p.is_nan() => return Ok(f64::NAN.into()), + // Special case: If p is ±Infinity and n is ±1, the result is NaN. + (1.0, _) | (-1.0, _) => { + // If (1) n or p is not finite, (2) p is not NaN, (3) n is finite, + // p has to be infinite. + debug_assert!(p.is_infinite()); + return Ok(f64::NAN.into()); + } + // Special case: If n is -Infinity and p < 0 and p is a negative even integer, Flash Player returns -0. + (f64::NEG_INFINITY, _) if p.to_i64().is_some_and(|i| i % 2 == 0 && i < 0) => { + return Ok(Value::Number(-0.0)) + } + _ => { + // Fall back to regular powf + } + } + } + Ok(f64::powf(n, p).into()) } diff --git a/tests/tests/swfs/from_avmplus/as3/Types/Number/pow/test.toml b/tests/tests/swfs/from_avmplus/as3/Types/Number/pow/test.toml index 29f3cef79022..cf6123969a1d 100644 --- a/tests/tests/swfs/from_avmplus/as3/Types/Number/pow/test.toml +++ b/tests/tests/swfs/from_avmplus/as3/Types/Number/pow/test.toml @@ -1,2 +1 @@ num_ticks = 1 -known_failure = true