Issue with r2255 and long over jsni

26 views
Skip to first unread message

Cameron Braid

unread,
Mar 27, 2008, 7:42:57 AM3/27/08
to google-web-toolkit-contributors
My test case was working for r2120, but i've just updated to r2255 and it is now failing.

I am getting warnings like this :

Return value of type 'long' is an opaque, non-numeric value in JS code
Parameter 'value': 'long' is an opaque, non-numeric value in JS code

Is there something that I need to configure ? or is this a bug ?

Regards,

Cameron

Scott Blum

unread,
Mar 27, 2008, 11:08:41 AM3/27/08
to Google-Web-Tool...@googlegroups.com
Hi Cameron,

This is not a bug, but a new feature in the trunk.  The long data type is now emulated.  Previously, it was implemented as a plain old number (double) in JavaScript, which would not give accurate results.  Now, long math should be accurate with what the JVM would produce.

The downside is that the emulated long is no longer a numeric type in the compiled JavaScript.  In fact, it's implemented as an array of two doubles.  This means soem code that used to work cannot work now:

native double add(long l, double d) /*-{
  return l + d;
}-*/;

The problem is "l" is now an array of two doubles, meaning the JS + operation is not going to give the result you want.  So we added the warning you got to warn users against trying to use longs as numeric types in JS.  If you have hand-inspected the method and are sure the long value is being used safely (ie, you're only passing it back into Java, for example), you can add the following annotation to the method:

@SuppressWarnings("restriction")

And the warning will go away.

Presently out warning messages aren't very helpful, but we intend to make this better before launch.

Scott

Ray Cromwell

unread,
Mar 27, 2008, 1:49:34 PM3/27/08
to Google-Web-Tool...@googlegroups.com

Scott,
   If you pass two longs to JSNI and add them, does it work, that is, does the emulation extend down into the JS AST? If not, why not either

a) ban the use of primitive longs in JSNI methods (must declare them as doubles and cast in Java, or pass a Long)
b) auto-coerce them to doubles and emit an hazardous warning about loss of precision

  It seems that almost all passages of naked longs into JSNI will be incorrect unless nothing is done with them except store the reference or pass them back. In which case, it would seem to be a lot safer to pass a Long instead.

There is also a third option

c) make LongLib 'public' and exposed to JSNI, so that one could write code like

public long addLongs(long x, long y) /*-{
   return $LongLib.add(x, y);
}-*/;

-Ray

Scott Blum

unread,
Mar 28, 2008, 12:57:18 PM3/28/08
to Google-Web-Tool...@googlegroups.com
Ray,

My reasoning on going the warning route is that there are legitimate cases where longs need to pass through JSNI transparently without taking part in any numeric operations.  RPC is a primary example of this.  Both options a) and b) would destroy this use case.

Option c) is interesting, but not really needed since you can always just call back ot Java to the math, and we could always add it later.

Ray Cromwell

unread,
Mar 28, 2008, 1:18:34 PM3/28/08
to Google-Web-Tool...@googlegroups.com

Scott,
  Fair enough (RPC use case), but do you think the warning should be a little more explanatory and stronger like "Don't *EVAH* DO DIS unless you know what you're doing." :)  My intuition is that in 99% of the cases, the user will be surprised (because they didn't read the release notes on long emulation) and the code will be buggy.

  One last option:

d) auto-coerce to double, warn on loss of precision
    avoid coercion with annotation (RPC case)
   public void foo(@DontCoerce long x, long y) /* ... */

x gets passed through (RPC case), y gets coerced.

  I think I'm ok with a warning, but I think the warning needs to be verbose because I bet 9 out of 10 users won't read the 1.5 release notes/docs on longs, so may as well educate them during compile cycles. :)

-Ray

Scott Blum

unread,
Mar 28, 2008, 2:24:37 PM3/28/08
to Google-Web-Tool...@googlegroups.com
Totally agree w.r.t. the verbosity of the warnings.  We're going to rework them.

On Fri, Mar 28, 2008 at 1:18 PM, Ray Cromwell <cromw...@gmail.com> wrote:
Scott,

John Tamplin

unread,
Apr 1, 2008, 5:11:11 PM4/1/08
to Google-Web-Tool...@googlegroups.com, Scott Blum, Lex Spoon, Kelly Norton, Bruce Johnson
On Fri, Mar 28, 2008 at 1:18 PM, Ray Cromwell <cromw...@gmail.com> wrote:
  Fair enough (RPC use case), but do you think the warning should be a little more explanatory and stronger like "Don't *EVAH* DO DIS unless you know what you're doing." :)  My intuition is that in 99% of the cases, the user will be surprised (because they didn't read the release notes on long emulation) and the code will be buggy.

  One last option:

d) auto-coerce to double, warn on loss of precision
    avoid coercion with annotation (RPC case)
   public void foo(@DontCoerce long x, long y) /* ... */

x gets passed through (RPC case), y gets coerced.

  I think I'm ok with a warning, but I think the warning needs to be verbose because I bet 9 out of 10 users won't read the 1.5 release notes/docs on longs, so may as well educate them during compile cycles. :)

We had a face-to-face meeting today to nail down this issue, and here is what we came up with (rationale in italics):
  1. All longs in Java code will be emulated
    Existing Java code expects longs to just work, and some of that code can't readily be changed (in libraries or shared server code).  If the user cares about performance and a double was suitable before, they can change it to use doubles instead.
  2. long parameters to a JSNI method will result in an error instructing you to use either double or Long.  Also, the compiler will continue its current behavior, which is to pass an emulated long object to JSNI, if a to-be-specified annotation is present on the long parameter.  This would be used for generated RPC serializers and internal uses, but would also be available to users if they need it (but only documented where the details are explained).
    Code that used to work correctly in GWT 1.4 can just change the type to double and it will work exactly as it did before (other than the conversion from the emulated long to double added by the implicit cast).  JSNI code that just passes around a token can use Long equally well, and code that really needs access to the emulated long can use the low-visibility annotation to enable it.  Developers converting apps from 1.4 to 1.5 will already have lots of warnings to deal with, and a warning about passing long might get lost in the pile of warnings, while the code may no longer work correctly at all.  Better to force the developer to choose which use case they want up front and get known behavior than to risk silently bad behavior discovered at runtime.

  3. Since a large portion of the code we are worried about long performance on deals with timestamps, we would provide a GWT-specific way to get timestamps and deltas in a double.
    For example, animation code typically does long math on timestamps, which will be significantly slower in 1.5.
We might find a way to improve the long emulation so that values fitting in a double are actually represented as a double, but we would have to see if the cost of the checks would outweigh the benefits.

The error message would be improved and link to a detailed discussion of the issues, which would be part of a larger document describing the steps for upgrading a 1.4 GWT app to 1.5.

If anyone has any objections to this approach, now is the time to voice them.

--
John A. Tamplin
Software Engineer, Google

Ian Petersen

unread,
Apr 1, 2008, 5:24:42 PM4/1/08
to Google-Web-Tool...@googlegroups.com
I think your decisions make a lot of sense, especially with the
rationales given. It did make me wonder, though--what kind of
performance hit is 1.5 going to introduce to long math?

Also, would there be any benefit in defining a new time stamp that is
the number of milliseconds since the start of the app? It would
reduce the necessary range quite dramatically--it might fit into an
int, and would certainly fit into a double without loss of
precision--but I don't know if it would be useful for anything.

Ian

--
Tired of pop-ups, security holes, and spyware?
Try Firefox: http://www.getfirefox.com

John Tamplin

unread,
Apr 1, 2008, 5:51:58 PM4/1/08
to Google-Web-Tool...@googlegroups.com
On Tue, Apr 1, 2008 at 5:24 PM, Ian Petersen <ispe...@gmail.com> wrote:
I think your decisions make a lot of sense, especially with the
rationales given.  It did make me wonder, though--what kind of
performance hit is 1.5 going to introduce to long math?

We don't have solid numbers at the moment, but if we don't do the optimization of using real doubles for numbers that fit in the range (and the associated testing overhead) it will likely be around twice as slow for add/multiply/subtract, and a bit slower than that for division.  There is also object creation overhead since they are immutable, which may exacerbate GC issues on IE6, but that will depend on how many objects the rest of the app creates.
 
Also, would there be any benefit in defining a new time stamp that is
the number of milliseconds since the start of the app?  It would
reduce the necessary range quite dramatically--it might fit into an
int, and would certainly fit into a double without loss of
precision--but I don't know if it would be useful for anything.

What we discussed was having a way of getting elapsed times, so that would be easy enough to implement on top of it.

Bruce Johnson

unread,
Apr 1, 2008, 6:51:21 PM4/1/08
to Google-Web-Tool...@googlegroups.com
On Tue, Apr 1, 2008 at 5:24 PM, Ian Petersen <ispe...@gmail.com> wrote:
It did make me wonder, though--what kind of
performance hit is 1.5 going to introduce to long math?

It's also worth saying that part of the goal here is to actually actively discourage long math in general. There are very few cases where it's actually necessary. 

In other words: 
1) make longs work soundly in GWT
2) try to get people not to use longs :-)

Andrés Testi

unread,
Apr 1, 2008, 7:01:42 PM4/1/08
to Google Web Toolkit Contributors
Is there actually an statical analysis to determine if a long field
will be never stored with values out of the integer range?

- Andrés

On 1 abr, 19:51, "Bruce Johnson" <br...@google.com> wrote:

John Tamplin

unread,
Apr 1, 2008, 7:11:00 PM4/1/08
to Google-Web-Tool...@googlegroups.com
On Tue, Apr 1, 2008 at 7:01 PM, Andrés Testi <andres....@gmail.com> wrote:
Is there actually an statical analysis to determine if a long field
will be never stored with values out of the integer range?

In general you can only do that with constant values (or statically computed expressions).  For example, System.currentTimeMillis() returns a long of the number of milliseconds since Jan 1 1970.  That means that double is sufficient for timestamps within about 34000 years of now, and probably suitable for use without worry unless you are representing ancient dates or calculating when the sun uses up its hydrogen.  However, the compiler has no way of knowing that unless you added some additional information giving the expected range.

Ray Cromwell

unread,
Apr 1, 2008, 7:19:55 PM4/1/08
to Google-Web-Tool...@googlegroups.com

You'd need not only range annotations on opaque system methods, but also data-flow in the compiler, which would be cool to have, but I think that's probably a all-summer-long project for Lex for GWT 2.5. I think essentially, System.currentTimeMillis() returns a long, because the JRE does. There's nothing really stopping GWT from adding Timestamp class that returns doubles instead of longs. Although it is 'icky' to use doubles only for performance reasons.

I think the goal should be that you write "Java" the way you would on the desktop and don't try to optimize code by changing all your types to doubles, etc. Then, the GWT compiler evolves overtime to make the performance hit smaller and smaller.

I think for 99% of cases, long performance won't matter as much. In those few cases where it would significantly effect performance, you bite the bullet and force JS efficient (double) math. You don't want to premature optimize and pollute your code with doubles everywhere (as I did for Chronoscope :) )

-Ray
Reply all
Reply to author
Forward
0 new messages