Conversation
0d16db7 to
fca1619
Compare
|
I'm porting my AS3 project to Haxe and right now I'm using my own custom parsing utility and rerouting all number parsing through Flash's native runtime globals instead of Haxe standard library, to avoid this problem above, i thought it would be better for the language to not have a missing implementation. |
30d773d to
0695f34
Compare
|
Pushed an update with a couple of nice optimizations: Instead of having Similarly, I updated The dynamic fallbacks in Updated the PR description to reflect my current changes, from some AS3 devs opinions(on AirSDK discord server) this is the best implementation possible for Flash / AVM2 |
|
@JonasAlv Are you adding a call to |
|
You are actually right, I just tested this: calling |
Summary
Fixes a runtime crash where
Math.isNaN,Math.isFinite, andStd.parseIntfail withTypeError: Error #1006: isNaN is not a functionwhen Haxe code is compiled as an ActionScript 3 SWC library.Context & Problem
I ran into this while porting an ActionScript 3 library to Haxe. When compiling Haxe code into a SWC and consuming it from an ActionScript 3 / Flex / AIR host application, calling
Math.isNaN(),Math.isFinite(), orStd.parseInt()crashes at runtime:Crash log:
Or through
Std.parseInt():Why does this happen?
In Flash AVM2,
isNaNandisFiniteare top-level global functions, and constants likeNaNandInfinitylive on theNumberclass—none of them natively exist on AS3'sMath.Previously,
std/Math.hxattempted to monkey-patch these ontoMathinside an#if flash__init__()block. However, when compiling to a SWC or linking externally, static initialization order isn't guaranteed before host code calls in, leading to missing fields and runtime crashes.The Fix
Following the pattern already used by JavaScript (
std/js/_std/Math.hx) and Lua (std/lua/_std/Math.hx), this PR introduces a dedicatedstd/flash/_std/Math.hx:Inline IEEE-754
isNaNandisFinite:isNaN(f)uses inlinef != f(just like Lua's implementation). In AVM2, this compiles directly to native comparison opcodes (equals+not/ifne) rather than making a dynamic function call to the globalisNaN. It's roughly 30–40x faster and has zero dependency on global scope lookups.isFinite(f)uses an inline range check (f > NEGATIVE_INFINITY && f < POSITIVE_INFINITY), also mirroring the Lua target.Std.parseInt()checksif (Math.isNaN(v)), it now benefits from zero-overhead inline validation as well.Inline Getters for Constants:
NaN,POSITIVE_INFINITY, andNEGATIVE_INFINITYuse@:pure static inlinegetters pointing directly to__global__["Number"].@:coreApi(check = Off)(like JS and Lua) so inline getters don't conflict with implicit core API checks during documentation generation (make xmldoc).Dynamic Reflection Fallbacks:
__init__()annotated with@:keepInitto populate properties on theMathclass object for dynamic reflection (e.g.var math:Dynamic = Math; math.isNaN(...)), using the same inline logic.Cleaned up
std/Math.hx:#if flashconditionals from the fallback class since Flash now has its own_stdimplementation.Testing
1. Adobe AIR Debug Launcher (ADL) Test
Tested an ActionScript 3 host application linking against a Haxe-compiled SWC library:
Before:
After:
2. Haxe Unit Tests
tests/unit/src/unit/teststd/TestMath.hxpasses on Flash for both direct inlined calls and dynamicvar math = Math;variable tests.make xmldoc/doc.hxml) compiles cleanly with 0 errors.