#878 Use Native Number type for sys::Int on JavaScript

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:

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.

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:

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...

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:

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.

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.

Login or Signup to reply.