Use of long in Nashorn
Hannes Wallnoefer
hannes.wallnoefer at oracle.com
Fri Dec 4 15:27:22 UTC 2015
After receiving another long/precision related bug last week I decided
to go ahead with the removal of longs in Nashorn. It's been quite an
effort, but I think it looks good now. Below are the links to the webrev
and Jira issue.
http://cr.openjdk.java.net/~hannesw/8144020/
https://bugs.openjdk.java.net/browse/JDK-8144020
This is a rather big patch, but it mostly removes code. There are over
2000 deletions vs. 400 insertions. I removed all uses of long in our
code where it represented JS numbers, including ScriptObject property
accessors with longs as key or value, and the LongArrayData class. With
this, all JS numbers are represented as int or double in Nashorn. Longs
will not "naturally" occur anymore and only be present as java.lang.Long
instances.
As expected, the areas that demanded special care were those where ES
prescribes use of uint32. These are mostly unsigned right shift,
Uint32Array elements, and the length property of arrays. For right shift
and Uint32Array elements, I added optimistic implementations that return
int if possible and deoptimize to double. Pdfjs and mandreel are
benchmarks that make use of these features, and I didn't notice any
observable impact on performance. Even when I simulated fallback to
double performance was still ok (previously reported performance
regressions for this case were in fact caused by an error of mine).
For the Array length property, I changed the getter in NativeArray to
return int or double depending on actual value. Previously, the length
getter always returned long. Since the property is actually evaluated by
OptimisticTypesCalculator, for-loops with an array length as limit now
use ints instead of longs to iterate through array indices, which is
probably a good thing.
As for longs returned by Java code, their value is always preserved.
Only when they are used for JS math they will be converted to double as
prescribed by ECMA. When running with optimistic types we check if a
long fits into an int or double to avoid deoptimization to object.
Previously we did this only when converting long to optimistic int, but
optimistic double did not use any return filter for longs, so a long
returned for an optimistic double could easily lose precision.
You can find the related changes in OptimisticReturnFilters.java. I also
added tests to make sure long values are preserved in various optimistic
and non-optimstic contexts, some of which would have previously fail.
In a previous version of this patch it included functionality to only
treat ints and doubles or their wrapper objects as native JS numbers
(e.g. you could invoke Number.prototype methods only on ints and
doubles). However, this is a quite a hairy issue and I reckoned the
patch is large enough without it, so I pulled it out and will fix this
separately as JDK-8143896.
I've testing and refining this patch for the last few days and think it
looks pretty good. I thought it was a good idea to discuss this to this
existing thread before posting a review request. Please let me know what
you think.
Thanks,
Hannes
Am 2015-11-13 um 15:06 schrieb Attila Szegedi:
> Well, we could just box them in that case. If we only used int and double as primitive number types internally, then a natural representation for a long becomes Long. Java methods returning long could have an optimistic filter that first checks if the value fits in an int (32-bit signed), then in a double (53-bit signed) without loss of precision, and finally deoptimizes to Object and uses Long. int->long->double->Object becomes int->double->Object, with longs of too large magnitude becoming boxed.
>
> Attila.
>
>> On Nov 13, 2015, at 2:46 PM, Jim Laskey (Oracle)<james.laskey at oracle.com> wrote:
>>
>> The main thing to watch for here is that longs/Longs need to survive unobstructed between Java calls. Remember we ran into trouble in this area (loss of precision when using longs for encoding.)
>>
>>
>>
>>
>>> On Nov 13, 2015, at 8:26 AM, Attila Szegedi<attila.szegedi at oracle.com> wrote:
>>>
>>>> On Nov 13, 2015, at 10:31 AM, Hannes Wallnoefer<hannes.wallnoefer at oracle.com> wrote:
>>>>
>>>> Hi all,
>>>>
>>>> I'm currently questioning our use of longs to represent numbers in combination with optimistic typing.
>>> I often feel that the presence of longs is more hassle than they’re worth. I’d be all for eliminating them.
>>>
>>>> After all, there's a pretty large range where long arithmetic will be more precise than the doubles required by ECMA.
>>> There’s currently several different places in Nashorn where we try to confine the precision of longs to 53 bits (so they aren’t more precise than doubles). It’s a bit of a whack-a-mole where you can’t always be sure whether you found all instances.
>>>
>>>> For context see this bug, especially the last two comments (the original bug was about number to string conversion which has been solved in the meantime):
>>>>
>>>> https://bugs.openjdk.java.net/browse/JDK-8065910
>>>>
>>>> So the question is: can we use longs at all and be confident that results won't be too precise (and thus, strictly speaking, incorrect)?
>>> Internally, the longs are also used for representing UInt32 even in non-optimistic setting, which is only really significant for the >>> operator and array indices and lengths; maybe we should limit longs to that usage only, or even just use doubles internally for UInt32 values that can’t be represented as Int32. FWIW, even for the >>> operator we only need it when shifting by zero, as in every other case the result will have the topmost bit set to 0 and thus fit in Int32 too.
>>>
>>> I guess once Valhalla rolls around, we could easily have an unsigned 32 bit int type.
>>>
>>>> Hannes
>>> Attila.
>>>
More information about the nashorn-dev
mailing list