On Dec 11, 2015, at 4:08 PM, Hannes Wallnoefer <hannes.wallnoe...@oracle.com> 
wrote:
> 
> I uploaded a new webrev that includes most of the changes you suggested. 
> Conversion of long[] from Java now works without losing precision, using int, 
> double, or Object arrays. I also added a test for this.
> 
> http://cr.openjdk.java.net/~hannesw/8144020/webrev.01/

+1 on all changes.

> I didn't implement the int/double overloading of array iterator actions. 
> Unless I missed something, I would have to implement two forEach methods in 
> each subclass, which seem ugly and error prone.

You haven’t missed anything; that’s exactly how that would work. Ultimately, if 
we had macros in Java, this wouldn’t need to look ugly, but we don’t have them, 
so… Performance optimizations are sometimes ugly :-) Anyway, this needn’t 
happen now, although ultimately I don’t think it’d be much of a big deal to 
implement, even with the unfortunate code duplication, and we still wouldn’t 
always force-promote the parameter type for the callback functions to double.

> Additionally, I removed the ArrayData.set method that takes a long value, 
> something I had overlooked in my previous patch.

> 
> Hannes

Attila.

> 
> Am 2015-12-06 um 11:12 schrieb Hannes Wallnoefer:
>> Thanks for the quick review, Attila. Answers inline.
>> 
>> Am 2015-12-04 um 18:39 schrieb Attila Szegedi:
>>> * In CodeGenerator SHR implementations (both self-assign and ordinary) you 
>>> have method.shr() in loadStack instead of consumeStack. I was actually 
>>> staring at this for a while as it seemed wrong to perform an operation in 
>>> loadStack, but in the end I decided it’s okay like this. After all, it’s 
>>> the toUint32 that’s the optimistic part here, so this should be fine 
>>> indeed. I think we had a JIRA issue saying “make SHR optimistic” but I 
>>> can’t find it now. If it pops up, we can mark it as a duplicate of this one.
>> 
>> I've looked for that Jira issue but didn't find it either.
>> 
>>> * I see "assert storeType != Type.LONG;” do we even need Type.LONG and 
>>> LongType class anymore?
>> 
>> That assert is a leftover from the conversion process, it shouldn't be 
>> needed anymore. We do still use Type.LONG for creating and handling the 
>> primitive fields and spill slots with dual fields. That's why I had to keep 
>> it.
>> 
>>> * Symbol.java: you could reclaim the HAS_LONG_VALUE bit by shifting the 
>>> rest down by one
>> 
>> Will do.
>>> 
>>> * optimization idea: have versions of callback invokers in NativeArray.java 
>>> for both int and double indices. Since we know the length of the array when 
>>> we enter forEach etc. we could select  the double version when length > 
>>> maxint and the int version otherwise. Actually, we could even have 
>>> IteratorAction.forEach be overloaded for int and double, and write the body 
>>> of IteratorAction.apply() to start out with the int version, and when the 
>>> index crosses maxint start calling the double version (so even for large 
>>> arrays we’ll iterate calling int specialization of functions for the cases 
>>> where it’s short circuited).
>> 
>> Nice idea, and should be easy to implement. I'll try it out.
>>> 
>>> * array length: could we still have Nashorn APIs that return long? 
>>> Optimistic filters will deal with these appropriately, won’t they? I guess 
>>> they should since they also need to be able to handle return values from 
>>> POJO methods that return long (e.g. System.currentTimeMillis()). Hence, you 
>>> could have NativeArray.length return “long” and let the optimistic 
>>> machinery decide whether to cast it as int or double. That would allow you 
>>> to not have to box the return value of NativeArray.length.
>> 
>> Yes, we could have things returning long, but it will deoptimize to Object. 
>> OptimisticReturnFilters (which do the runtime checks) are not used for 
>> ScriptObject properties.
>> 
>>> * NativeNumber: unused import?
>> Fixed.
>> 
>>> *Unit32ArrayData: getBoxedElementType went from INTEGER to DOUBLE. I’m not 
>>> sure I understand that. I mean, was INTEGER incorrect before?
>> 
>> That obviously has been incorrect before. Actually, that method is only used 
>> in NativeArray#concat and will never be invoked on typed arrays. Looking at 
>> that NativeArray#concat method it looks a bit fishy to me, assuming all 
>> NativeArrays use ContinuousArrayData. I have to investigate further on this.
>> 
>> Back to the issue at hand, int.class/Integer.class is definitely wrong for 
>> element type for Uint32. When returning int.class in getElementType, 
>> optimistic code that uses optimstic int getter gets incredibly slow when 
>> actually deoptimizing to double, because we keep trying to handle elements 
>> as ints. (I had this in my code at one time and found pdfjs slowed down to a 
>> crawl when changing the optimistic int getter to always deoptimize to 
>> double.)
>> 
>> Probably getBoxedElementType should just be a final method instead of 
>> abstract in ContinuousArrayData and convert getElementType to boxed 
>> counterpart on the fly.
>> 
>> 
>>> 
>>> * You didn’t remove LongArrayData.java?
>> 
>> I think I did: 
>> http://cr.openjdk.java.net/~hannesw/8144020/webrev.00/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java.patch
>>> 
>>> * It looks like long[] arrays can now lose precision if passed through 
>>> Java.from(), E.g. if you have Java methods “long[] getLongArray()” and 
>>> “void setLongArray(long[] arr)” then 
>>> pojo.setLongArray(Java.from(pojo.getLongArray()) will lose precision 
>>> because NativeJava.copyArray(long[]) produces double[]. Of course, we could 
>>> argue that this is expected behavior if you explicitly use Java.from. Just 
>>> passing around and manipulating a raw long[] won’t have that effect 
>>> (although it’d be good to confirm that in test), it requires an explicit 
>>> Java.from(). Still, I wonder if it’d make sense to have copyArray(long[]) 
>>> either return Object[] or choose dynamically between double[] and Object[] 
>>> based on the maximum magnitude of an element (you can start with double[] 
>>> and reallocate as Object[] when you bump into a large long).
>> Good catch. I'll see if I can use existing code in ArrayData to convert to 
>> the narrowest array type.
>> 
>> Thanks!
>> 
>> Hannes
>> 
>>> Other than that: great work! Nice to see large swaths of code removed.
>>> 
>>> Attila.
>>> 
>>>> On Dec 4, 2015, at 4:27 PM, Hannes Wallnoefer 
>>>> <hannes.wallnoe...@oracle.com> wrote:
>>>> 
>>>> 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.las...@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.szeg...@oracle.com> 
>>>>>>> wrote:
>>>>>>> 
>>>>>>>> On Nov 13, 2015, at 10:31 AM, Hannes 
>>>>>>>> Wallnoefer<hannes.wallnoe...@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.
>>>>>>> 
>> 
> 

Reply via email to