One of the big impedances for getting Fantom supported in JavaScript has been 64-bit integers. We long ago decided all integers in Fantom would be longs on the JVM and the CLR. Unfortunately, JavaScript does not support native 64-bit integers, since it models all numbers using a 64-bit IEEE 754 format. This only allows us to represent integers up to 2^53 until we start losing precision.
Our original solution was to emulate 64-bit integers using a wrapper type. This of course comes with a performance penalty - and makes interop with native JavaScript numbers a bit cumbersome (and impossible is some cases). The issue effects us primarily in 3 places.
Performance
Using the GWT-based Long wrapper there is significant performance penalty by wrapping integers:
Average time over 5 runs to exec this expr for each arithmetic operator:
10000.times |i| { x := 5 + i }
BROWSER (WinXP) NATIVE (ms) WRAPPER (ms)
Add Sub Mul Div* Add Sub Mul Div
----------------- ------------------ ------------------------
Chrome 4.0.249.43 1.2 1.2 1.2 2.6 26.2 29.6 65.8 36.6
Firefox 3.6b5 0.2 0.0 0.0 0.8 94 99 181.8 117.8
IE 8 6.4 9.2 6.0 25.6 655.8 827.8 1215 690.2
*Incur a penalty here since we must floor the result after division.
Bitwise operators
Bitwise operators for native JavaScript Numbers are only supported on 32-bit values (top bits are just cut off). Using the Long wrapper we can implement this on the full 64-bit value.
DateTime/Duration
DateTime models the current time using nanosecond ticks since 1 Jan 2000 UTC. JavaScript only supports millisecond precision for its built-in Date object. So Duration and DateTime can never extend beyond ms when created in the browser. If they acquire the tick value from the JVM/CLR - they are only guaranteed to be accurate if we use the Long wrapper.
I've given this some thought, and I'm leaning towards simply using native JavaScript Numbers for integers. The performance penalty is significant, and I think the two remaining cases are the right trade-offs given the circumstances. So if we do that, then:
Bitwise operators (and,or,shift,etc) are implicitly restricted to 32-bit values
DateTime/Duration is implicitly restricted to ms precision
Its not perfect - but I think wrapping integers will come back to haunt us - so I think we bite the bullet and introduce a few platform idiosyncrasies for JavaScript.
tompalmerTue 22 Dec 2009
Extra tricky would be to use native Numbers for smaller values and automatically expand as needed. Could possibly avoid checks for some common cases, but the checks could make code slower, even if not as slow as always using a wrapper.
alexlamslTue 22 Dec 2009
Would we gain better daily-usage performance if we do:
c = a*b
if (Math.abs(c) >= Math.pow(2,53))
c = doTwoPartMul(a,b);
I just have a feeling that when we use long we don't usually be around the +/-(2^53~2^63) space...
andyTue 22 Dec 2009
I do that for literals currently - but it could be better if I checked the result to see if needs to be expanded. I think we'd still get better performance with that than always wrapping. Though that still requires routing to Int:
var x = a * b; // native
var x = fan.sys.Int.mul(a, b); // wrappers
I'll run some tests tomorrow to see how that fairs.
KevinKelleyTue 22 Dec 2009
I'm in favor of native ints for the normal case - the only code I'm aware of, where the 53-bit limitation would matter, is for bitwise ops. And I've been moving that kind of stuff to a BitSet class, so the only trick would be to have the implementation of that fall back to 32-bit wordsize when on Javascript.
brianTue 22 Dec 2009
Many languages support this via their numerical tower where they automatically expand to a wider type as needed. I've considered if Fantom should support that model implicitly across all platforms, but it would be a huge performance hit on the JVM which would require boxing numbers. We could still do something like that just for JavaScript. But I think we could get away with not worrying about it immediately. So I say for now we just use Number to represent sys::Int and go for performance over perfect portability. We can always go back later and make Int auto-expand to a wider type to provide better portability with 54+ bit numbers.
andyMon 28 Dec 2009
Renamed from 64-bit Integers in JavaScript to Use Native Number type for sys::Int on JavaScript
andyMon 28 Dec 2009
Promoted to ticket #878 and assigned to andy
Ok, we'll use native Number types for JavaScript for now.
andyWed 13 Jan 2010
Ticket resolved in 1.0.49
The Long wrapper has been removed, and all integers in JavaScript are now represented with the native Number object.
andy Mon 21 Dec 2009
One of the big impedances for getting Fantom supported in JavaScript has been 64-bit integers. We long ago decided all integers in Fantom would be longs on the JVM and the CLR. Unfortunately, JavaScript does not support native 64-bit integers, since it models all numbers using a 64-bit IEEE 754 format. This only allows us to represent integers up to 2^53 until we start losing precision.
Our original solution was to emulate 64-bit integers using a wrapper type. This of course comes with a performance penalty - and makes interop with native JavaScript numbers a bit cumbersome (and impossible is some cases). The issue effects us primarily in 3 places.
Performance
Using the GWT-based Long wrapper there is significant performance penalty by wrapping integers:
Bitwise operators
Bitwise operators for native JavaScript Numbers are only supported on 32-bit values (top bits are just cut off). Using the Long wrapper we can implement this on the full 64-bit value.
DateTime/Duration
DateTime models the current time using nanosecond ticks since 1 Jan 2000 UTC. JavaScript only supports millisecond precision for its built-in Date object. So Duration and DateTime can never extend beyond ms when created in the browser. If they acquire the tick value from the JVM/CLR - they are only guaranteed to be accurate if we use the Long wrapper.
I've given this some thought, and I'm leaning towards simply using native JavaScript Numbers for integers. The performance penalty is significant, and I think the two remaining cases are the right trade-offs given the circumstances. So if we do that, then:
Its not perfect - but I think wrapping integers will come back to haunt us - so I think we bite the bullet and introduce a few platform idiosyncrasies for JavaScript.
tompalmer Tue 22 Dec 2009
Extra tricky would be to use native Numbers for smaller values and automatically expand as needed. Could possibly avoid checks for some common cases, but the checks could make code slower, even if not as slow as always using a wrapper.
alexlamsl Tue 22 Dec 2009
Would we gain better daily-usage performance if we do:
I just have a feeling that when we use long we don't usually be around the +/-(2^53~2^63) space...
andy Tue 22 Dec 2009
I do that for literals currently - but it could be better if I checked the result to see if needs to be expanded. I think we'd still get better performance with that than always wrapping. Though that still requires routing to Int:
I'll run some tests tomorrow to see how that fairs.
KevinKelley Tue 22 Dec 2009
I'm in favor of native ints for the normal case - the only code I'm aware of, where the 53-bit limitation would matter, is for bitwise ops. And I've been moving that kind of stuff to a BitSet class, so the only trick would be to have the implementation of that fall back to 32-bit wordsize when on Javascript.
brian Tue 22 Dec 2009
Many languages support this via their numerical tower where they automatically expand to a wider type as needed. I've considered if Fantom should support that model implicitly across all platforms, but it would be a huge performance hit on the JVM which would require boxing numbers. We could still do something like that just for JavaScript. But I think we could get away with not worrying about it immediately. So I say for now we just use Number to represent sys::Int and go for performance over perfect portability. We can always go back later and make Int auto-expand to a wider type to provide better portability with 54+ bit numbers.
andy Mon 28 Dec 2009
Renamed from 64-bit Integers in JavaScript to Use Native Number type for sys::Int on JavaScript
andy Mon 28 Dec 2009
Promoted to ticket #878 and assigned to andy
Ok, we'll use native Number types for JavaScript for now.
andy Wed 13 Jan 2010
Ticket resolved in 1.0.49
The Long wrapper has been removed, and all integers in JavaScript are now represented with the native Number object.