RFR (XS): 8191915: JCK tests produce incorrect results with C2

classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

RFR (XS): 8191915: JCK tests produce incorrect results with C2

Rickard Bäckman
Hi, can I please have this change reviewed?

Summary is that we had an overflow check for mulitplyExact(long, long)
intrinsic that relied on undefined behaviour. clang / llvm started
optimizing that so that if a = b * c then a / b must be equal to c and
removed half of the overflow check.

Changing the multiplication and division to be unsigned.

Webrev: http://cr.openjdk.java.net/~rbackman/8191915/
Bug: https://bugs.openjdk.java.net/browse/JDK-8191915

Thanks
/R
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Tobias Hartmann-2
Hi Rickard,

I don't understand why casting from signed to unsigned is correct here because if there's an overflow of the signed
range, there is not necessarily and overflow of the unsigned range, right?

For example, this program:

  signed long long sv1 = LONG_MAX/2 + 1;
  signed long long sv2 = 2;
  signed long long sR = sv1 * sv2;
  printf("%li\n", sR);

  unsigned long long uv1 = (unsigned long long) sv1;
  unsigned long long uv2 = (unsigned long long) sv2;
  unsigned long long uR = uv1 * uv2;
  printf("%lu\n", uR);

  if (uR / uv1 != uv2) {
    printf("Overflow detected");
  } else {
    printf("No overflow detected");
  }

Output:

  -9223372036854775808
  9223372036854775808
  No overflow detected

So there is an overflow of the signed long but the unsigned long does not overflow and thus an overflow is not detected.
Do I miss something?

Regarding the jtreg test: Please do not use bug numbers as test names but use something more meaningful like
TestLongMulOverflow or similar. I would also suggest to move the allocation of the test instance out of the loop and
check if 500.000 iterations are really necessary to trigger compilation (you can run with -Xbatch and maybe
-XX:-TieredCompilation).

Best regards,
Tobias

On 14.12.2017 08:30, Rickard Bäckman wrote:

> Hi, can I please have this change reviewed?
>
> Summary is that we had an overflow check for mulitplyExact(long, long)
> intrinsic that relied on undefined behaviour. clang / llvm started
> optimizing that so that if a = b * c then a / b must be equal to c and
> removed half of the overflow check.
>
> Changing the multiplication and division to be unsigned.
>
> Webrev: http://cr.openjdk.java.net/~rbackman/8191915/
> Bug: https://bugs.openjdk.java.net/browse/JDK-8191915
>
> Thanks
> /R
>
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Rickard Bäckman
Yes you are right, it doesn't work for all values. Seems to work for
negatives though?

However casting the result back to signed after doing the multiplication
and doing the division with the signed values get us back to getting the
overflow check correct and no undefined behaviour as far as I can tell?

/R

On 12/14, Tobias Hartmann wrote:

> Hi Rickard,
>
> I don't understand why casting from signed to unsigned is correct here because if there's an overflow of the signed
> range, there is not necessarily and overflow of the unsigned range, right?
>
> For example, this program:
>
>   signed long long sv1 = LONG_MAX/2 + 1;
>   signed long long sv2 = 2;
>   signed long long sR = sv1 * sv2;
>   printf("%li\n", sR);
>
>   unsigned long long uv1 = (unsigned long long) sv1;
>   unsigned long long uv2 = (unsigned long long) sv2;
>   unsigned long long uR = uv1 * uv2;
>   printf("%lu\n", uR);
>
>   if (uR / uv1 != uv2) {
>     printf("Overflow detected");
>   } else {
>     printf("No overflow detected");
>   }
>
> Output:
>
>   -9223372036854775808
>   9223372036854775808
>   No overflow detected
>
> So there is an overflow of the signed long but the unsigned long does not overflow and thus an overflow is not detected.
> Do I miss something?
>
> Regarding the jtreg test: Please do not use bug numbers as test names but use something more meaningful like
> TestLongMulOverflow or similar. I would also suggest to move the allocation of the test instance out of the loop and
> check if 500.000 iterations are really necessary to trigger compilation (you can run with -Xbatch and maybe
> -XX:-TieredCompilation).
>
> Best regards,
> Tobias
>
> On 14.12.2017 08:30, Rickard Bäckman wrote:
> > Hi, can I please have this change reviewed?
> >
> > Summary is that we had an overflow check for mulitplyExact(long, long)
> > intrinsic that relied on undefined behaviour. clang / llvm started
> > optimizing that so that if a = b * c then a / b must be equal to c and
> > removed half of the overflow check.
> >
> > Changing the multiplication and division to be unsigned.
> >
> > Webrev: http://cr.openjdk.java.net/~rbackman/8191915/
> > Bug: https://bugs.openjdk.java.net/browse/JDK-8191915
> >
> > Thanks
> > /R
> >
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Tobias Hartmann-2
On 14.12.2017 11:54, Rickard Bäckman wrote:
> Yes you are right, it doesn't work for all values. Seems to work for
> negatives though?

I think for negative values this does not work at all. If you set sv1 = -5 in my example code, you get:

-10
18446744073709551606
Overflow detected

Because we cast a negative value to unsigned.

> However casting the result back to signed after doing the multiplication
> and doing the division with the signed values get us back to getting the
> overflow check correct and no undefined behaviour as far as I can tell?

Yes, that seems to work. The best solution would be to use the corresponding compiler build-in functions (for example,
__builtin_smulll_overflow for gcc [1]) but I guess not all compilers support that.

Best regards,
Tobias

[1] https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html

> On 12/14, Tobias Hartmann wrote:
>> Hi Rickard,
>>
>> I don't understand why casting from signed to unsigned is correct here because if there's an overflow of the signed
>> range, there is not necessarily and overflow of the unsigned range, right?
>>
>> For example, this program:
>>
>>   signed long long sv1 = LONG_MAX/2 + 1;
>>   signed long long sv2 = 2;
>>   signed long long sR = sv1 * sv2;
>>   printf("%li\n", sR);
>>
>>   unsigned long long uv1 = (unsigned long long) sv1;
>>   unsigned long long uv2 = (unsigned long long) sv2;
>>   unsigned long long uR = uv1 * uv2;
>>   printf("%lu\n", uR);
>>
>>   if (uR / uv1 != uv2) {
>>     printf("Overflow detected");
>>   } else {
>>     printf("No overflow detected");
>>   }
>>
>> Output:
>>
>>   -9223372036854775808
>>   9223372036854775808
>>   No overflow detected
>>
>> So there is an overflow of the signed long but the unsigned long does not overflow and thus an overflow is not detected.
>> Do I miss something?
>>
>> Regarding the jtreg test: Please do not use bug numbers as test names but use something more meaningful like
>> TestLongMulOverflow or similar. I would also suggest to move the allocation of the test instance out of the loop and
>> check if 500.000 iterations are really necessary to trigger compilation (you can run with -Xbatch and maybe
>> -XX:-TieredCompilation).
>>
>> Best regards,
>> Tobias
>>
>> On 14.12.2017 08:30, Rickard Bäckman wrote:
>>> Hi, can I please have this change reviewed?
>>>
>>> Summary is that we had an overflow check for mulitplyExact(long, long)
>>> intrinsic that relied on undefined behaviour. clang / llvm started
>>> optimizing that so that if a = b * c then a / b must be equal to c and
>>> removed half of the overflow check.
>>>
>>> Changing the multiplication and division to be unsigned.
>>>
>>> Webrev: http://cr.openjdk.java.net/~rbackman/8191915/
>>> Bug: https://bugs.openjdk.java.net/browse/JDK-8191915
>>>
>>> Thanks
>>> /R
>>>
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Rickard Bäckman
I did the multiply as unsigned and then cast to to signed thing.
Renamed the test to LongMulOverflowTest.

Updated.

http://cr.openjdk.java.net/~rbackman/8191915.1/

I agree that the best solution would be to use compiler builtins but I'm
not sure all the compilers support them and makes portability a pain.

Thanks
/R

On 12/14, Tobias Hartmann wrote:

> On 14.12.2017 11:54, Rickard Bäckman wrote:
> > Yes you are right, it doesn't work for all values. Seems to work for
> > negatives though?
>
> I think for negative values this does not work at all. If you set sv1 = -5 in my example code, you get:
>
> -10
> 18446744073709551606
> Overflow detected
>
> Because we cast a negative value to unsigned.
>
> > However casting the result back to signed after doing the multiplication
> > and doing the division with the signed values get us back to getting the
> > overflow check correct and no undefined behaviour as far as I can tell?
>
> Yes, that seems to work. The best solution would be to use the corresponding compiler build-in functions (for example,
> __builtin_smulll_overflow for gcc [1]) but I guess not all compilers support that.
>
> Best regards,
> Tobias
>
> [1] https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
>
> > On 12/14, Tobias Hartmann wrote:
> >> Hi Rickard,
> >>
> >> I don't understand why casting from signed to unsigned is correct here because if there's an overflow of the signed
> >> range, there is not necessarily and overflow of the unsigned range, right?
> >>
> >> For example, this program:
> >>
> >>   signed long long sv1 = LONG_MAX/2 + 1;
> >>   signed long long sv2 = 2;
> >>   signed long long sR = sv1 * sv2;
> >>   printf("%li\n", sR);
> >>
> >>   unsigned long long uv1 = (unsigned long long) sv1;
> >>   unsigned long long uv2 = (unsigned long long) sv2;
> >>   unsigned long long uR = uv1 * uv2;
> >>   printf("%lu\n", uR);
> >>
> >>   if (uR / uv1 != uv2) {
> >>     printf("Overflow detected");
> >>   } else {
> >>     printf("No overflow detected");
> >>   }
> >>
> >> Output:
> >>
> >>   -9223372036854775808
> >>   9223372036854775808
> >>   No overflow detected
> >>
> >> So there is an overflow of the signed long but the unsigned long does not overflow and thus an overflow is not detected.
> >> Do I miss something?
> >>
> >> Regarding the jtreg test: Please do not use bug numbers as test names but use something more meaningful like
> >> TestLongMulOverflow or similar. I would also suggest to move the allocation of the test instance out of the loop and
> >> check if 500.000 iterations are really necessary to trigger compilation (you can run with -Xbatch and maybe
> >> -XX:-TieredCompilation).
> >>
> >> Best regards,
> >> Tobias
> >>
> >> On 14.12.2017 08:30, Rickard Bäckman wrote:
> >>> Hi, can I please have this change reviewed?
> >>>
> >>> Summary is that we had an overflow check for mulitplyExact(long, long)
> >>> intrinsic that relied on undefined behaviour. clang / llvm started
> >>> optimizing that so that if a = b * c then a / b must be equal to c and
> >>> removed half of the overflow check.
> >>>
> >>> Changing the multiplication and division to be unsigned.
> >>>
> >>> Webrev: http://cr.openjdk.java.net/~rbackman/8191915/
> >>> Bug: https://bugs.openjdk.java.net/browse/JDK-8191915
> >>>
> >>> Thanks
> >>> /R
> >>>
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

aph-2
On 10/01/18 14:17, Rickard Bäckman wrote:
> I did the multiply as unsigned and then cast to to signed thing.
> Renamed the test to LongMulOverflowTest.
>
> Updated.
>
> http://cr.openjdk.java.net/~rbackman/8191915.1/
>
> I agree that the best solution would be to use compiler builtins but I'm
> not sure all the compilers support them and makes portability a pain.

It's still wrong because

    jlong ax = (val1 < 0 ? -val1 : val1);
    jlong ay = (val2 < 0 ? -val2 : val2);

is undefined when val1 or val2 is Long.MIN_VALUE.

--
Andrew Haley
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Rickard Bäckman
Thank you for catching that. I added a method that negates the jlong.

http://cr.openjdk.java.net/~rbackman/8191915.2/

Thanks
/R

On 01/10, Andrew Haley wrote:

> On 10/01/18 14:17, Rickard Bäckman wrote:
> > I did the multiply as unsigned and then cast to to signed thing.
> > Renamed the test to LongMulOverflowTest.
> >
> > Updated.
> >
> > http://cr.openjdk.java.net/~rbackman/8191915.1/
> >
> > I agree that the best solution would be to use compiler builtins but I'm
> > not sure all the compilers support them and makes portability a pain.
>
> It's still wrong because
>
>     jlong ax = (val1 < 0 ? -val1 : val1);
>     jlong ay = (val2 < 0 ? -val2 : val2);
>
> is undefined when val1 or val2 is Long.MIN_VALUE.
>
> --
> Andrew Haley
> Java Platform Lead Engineer
> Red Hat UK Ltd. <https://www.redhat.com>
> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
/R
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Tobias Hartmann-2
Hi Rickard,

On 11.01.2018 10:30, Rickard Bäckman wrote:
> http://cr.openjdk.java.net/~rbackman/8191915.2/

Looks correct to me. Maybe add a comment explaining all the casting.

Best regards,
Tobias


> On 01/10, Andrew Haley wrote:
>> On 10/01/18 14:17, Rickard Bäckman wrote:
>>> I did the multiply as unsigned and then cast to to signed thing.
>>> Renamed the test to LongMulOverflowTest.
>>>
>>> Updated.
>>>
>>> http://cr.openjdk.java.net/~rbackman/8191915.1/
>>>
>>> I agree that the best solution would be to use compiler builtins but I'm
>>> not sure all the compilers support them and makes portability a pain.
>>
>> It's still wrong because
>>
>>     jlong ax = (val1 < 0 ? -val1 : val1);
>>     jlong ay = (val2 < 0 ? -val2 : val2);
>>
>> is undefined when val1 or val2 is Long.MIN_VALUE.
>>
>> --
>> Andrew Haley
>> Java Platform Lead Engineer
>> Red Hat UK Ltd. <https://www.redhat.com>
>> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
> /R
>
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Rickard Bäckman
Added a few comments. I still think I need a second reviewer to OK this.

http://cr.openjdk.java.net/~rbackman/8191915.3/

/R

On 01/11, Tobias Hartmann wrote:

> Hi Rickard,
>
> On 11.01.2018 10:30, Rickard Bäckman wrote:
> > http://cr.openjdk.java.net/~rbackman/8191915.2/
>
> Looks correct to me. Maybe add a comment explaining all the casting.
>
> Best regards,
> Tobias
>
>
> > On 01/10, Andrew Haley wrote:
> >> On 10/01/18 14:17, Rickard Bäckman wrote:
> >>> I did the multiply as unsigned and then cast to to signed thing.
> >>> Renamed the test to LongMulOverflowTest.
> >>>
> >>> Updated.
> >>>
> >>> http://cr.openjdk.java.net/~rbackman/8191915.1/
> >>>
> >>> I agree that the best solution would be to use compiler builtins but I'm
> >>> not sure all the compilers support them and makes portability a pain.
> >>
> >> It's still wrong because
> >>
> >>     jlong ax = (val1 < 0 ? -val1 : val1);
> >>     jlong ay = (val2 < 0 ? -val2 : val2);
> >>
> >> is undefined when val1 or val2 is Long.MIN_VALUE.
> >>
> >> --
> >> Andrew Haley
> >> Java Platform Lead Engineer
> >> Red Hat UK Ltd. <https://www.redhat.com>
> >> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
> > /R
> >
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Tobias Hartmann-2

On 12.01.2018 14:22, Rickard Bäckman wrote:
> Added a few comments. I still think I need a second reviewer to OK this.
>
> http://cr.openjdk.java.net/~rbackman/8191915.3/

Looks good to me. Yes, I think a second reviewer would be good because the changes are not trivial.

Best regards,
Tobias

> On 01/11, Tobias Hartmann wrote:
>> Hi Rickard,
>>
>> On 11.01.2018 10:30, Rickard Bäckman wrote:
>>> http://cr.openjdk.java.net/~rbackman/8191915.2/
>>
>> Looks correct to me. Maybe add a comment explaining all the casting.
>>
>> Best regards,
>> Tobias
>>
>>
>>> On 01/10, Andrew Haley wrote:
>>>> On 10/01/18 14:17, Rickard Bäckman wrote:
>>>>> I did the multiply as unsigned and then cast to to signed thing.
>>>>> Renamed the test to LongMulOverflowTest.
>>>>>
>>>>> Updated.
>>>>>
>>>>> http://cr.openjdk.java.net/~rbackman/8191915.1/
>>>>>
>>>>> I agree that the best solution would be to use compiler builtins but I'm
>>>>> not sure all the compilers support them and makes portability a pain.
>>>>
>>>> It's still wrong because
>>>>
>>>>     jlong ax = (val1 < 0 ? -val1 : val1);
>>>>     jlong ay = (val2 < 0 ? -val2 : val2);
>>>>
>>>> is undefined when val1 or val2 is Long.MIN_VALUE.
>>>>
>>>> --
>>>> Andrew Haley
>>>> Java Platform Lead Engineer
>>>> Red Hat UK Ltd. <https://www.redhat.com>
>>>> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
>>> /R
>>>
Reply | Threaded
Open this post in threaded view
|

RE: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Lindenmaier, Goetz
In reply to this post by Rickard Bäckman
Hi Rickard,

I had a look at the change and it seems fine to me assuming the following:
 * The results of overflowing signed multiplication is undefined in C++.
    (Thus, compilers may optimize x*y/x  to y.)
 * The results of overflowing unsigned multiplication is well defined in C++.
 * Java's math excact requires that -1 * min_jlong is signaled as overflow.

But I think it would be much easier to understand
if it's noted down differently. The only numbers
min_jlong can be multiplied with legally are 0 and 1.

Further, I'm not sure why the & CONST64(0xFFFFFFFF00000000))
is needed at all.  It saves the division in some cases, but
I don't think this method is performance relevant in any case.
It just makes reading the code difficult ...

bool OverflowMulLNode::will_overflow(jlong val1, jlong val2) const {
  // x*1 and x*0 never overflow. Even not for min_jlong.
  if (val1 == 0 || val2 == 0 ||
      val1 == 1 || val2 == 0) {
    return false;
  }
  // x*min_jlong for x not in { 0, 1 } overflows.
  // This holds for -1, too: -1*min_jlong is undefined.
  if (val1 == min_jlong || val2 == min_jlong) {
    return true;
  }
 
   // If (x*y)/x == y there is no overflow.
  //
  // The multiplication here is done as unsigned to avoid undefined behaviour which
  // can be used by the compiler to assume that the check further down (result / val2 != val1)
  // is always false. This breaks the overflow check.
  julong v1 = (julong) val1;
  julong v2 = (julong) val2;
  julong tmp = v1 * v2;
  jlong result = (jlong) tmp;
  if (result / val2 != val1) {
    return true;
  }
 
  return false;
}


Best regards,
  Goetz.








> -----Original Message-----
> From: hotspot-compiler-dev [mailto:hotspot-compiler-dev-
> [hidden email]] On Behalf Of Rickard Bäckman
> Sent: Freitag, 12. Januar 2018 14:22
> To: Tobias Hartmann <[hidden email]>
> Cc: hs-comp-dev <[hidden email]>
> Subject: Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2
>
> Added a few comments. I still think I need a second reviewer to OK this.
>
> http://cr.openjdk.java.net/~rbackman/8191915.3/
>
> /R
>
> On 01/11, Tobias Hartmann wrote:
> > Hi Rickard,
> >
> > On 11.01.2018 10:30, Rickard Bäckman wrote:
> > > http://cr.openjdk.java.net/~rbackman/8191915.2/
> >
> > Looks correct to me. Maybe add a comment explaining all the casting.
> >
> > Best regards,
> > Tobias
> >
> >
> > > On 01/10, Andrew Haley wrote:
> > >> On 10/01/18 14:17, Rickard Bäckman wrote:
> > >>> I did the multiply as unsigned and then cast to to signed thing.
> > >>> Renamed the test to LongMulOverflowTest.
> > >>>
> > >>> Updated.
> > >>>
> > >>> http://cr.openjdk.java.net/~rbackman/8191915.1/
> > >>>
> > >>> I agree that the best solution would be to use compiler builtins but I'm
> > >>> not sure all the compilers support them and makes portability a pain.
> > >>
> > >> It's still wrong because
> > >>
> > >>     jlong ax = (val1 < 0 ? -val1 : val1);
> > >>     jlong ay = (val2 < 0 ? -val2 : val2);
> > >>
> > >> is undefined when val1 or val2 is Long.MIN_VALUE.
> > >>
> > >> --
> > >> Andrew Haley
> > >> Java Platform Lead Engineer
> > >> Red Hat UK Ltd. <https://www.redhat.com>
> > >> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
> > > /R
> > >
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Vladimir Ivanov
In reply to this post by Rickard Bäckman
Looks good.

Best regards,
Vladimir Ivanov

On 1/12/18 4:22 PM, Rickard Bäckman wrote:

> Added a few comments. I still think I need a second reviewer to OK this.
>
> http://cr.openjdk.java.net/~rbackman/8191915.3/
>
> /R
>
> On 01/11, Tobias Hartmann wrote:
>> Hi Rickard,
>>
>> On 11.01.2018 10:30, Rickard Bäckman wrote:
>>> http://cr.openjdk.java.net/~rbackman/8191915.2/
>>
>> Looks correct to me. Maybe add a comment explaining all the casting.
>>
>> Best regards,
>> Tobias
>>
>>
>>> On 01/10, Andrew Haley wrote:
>>>> On 10/01/18 14:17, Rickard Bäckman wrote:
>>>>> I did the multiply as unsigned and then cast to to signed thing.
>>>>> Renamed the test to LongMulOverflowTest.
>>>>>
>>>>> Updated.
>>>>>
>>>>> http://cr.openjdk.java.net/~rbackman/8191915.1/
>>>>>
>>>>> I agree that the best solution would be to use compiler builtins but I'm
>>>>> not sure all the compilers support them and makes portability a pain.
>>>>
>>>> It's still wrong because
>>>>
>>>>      jlong ax = (val1 < 0 ? -val1 : val1);
>>>>      jlong ay = (val2 < 0 ? -val2 : val2);
>>>>
>>>> is undefined when val1 or val2 is Long.MIN_VALUE.
>>>>
>>>> --
>>>> Andrew Haley
>>>> Java Platform Lead Engineer
>>>> Red Hat UK Ltd. <https://www.redhat.com>
>>>> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
>>> /R
>>>
Reply | Threaded
Open this post in threaded view
|

RE: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Lindenmaier, Goetz
In reply to this post by Lindenmaier, Goetz
Oops, in my code, one of the second val2 == 0 should compare for ==1 ...

Best regards,
  Goetz.

> -----Original Message-----
> From: hotspot-compiler-dev [mailto:hotspot-compiler-dev-
> [hidden email]] On Behalf Of Lindenmaier, Goetz
> Sent: Freitag, 12. Januar 2018 15:36
> To: Rickard Bäckman <[hidden email]>; Tobias Hartmann
> <[hidden email]>
> Cc: hs-comp-dev <[hidden email]>
> Subject: RE: RFR (XS): 8191915: JCK tests produce incorrect results with C2
>
> Hi Rickard,
>
> I had a look at the change and it seems fine to me assuming the following:
>  * The results of overflowing signed multiplication is undefined in C++.
>     (Thus, compilers may optimize x*y/x  to y.)
>  * The results of overflowing unsigned multiplication is well defined in C++.
>  * Java's math excact requires that -1 * min_jlong is signaled as overflow.
>
> But I think it would be much easier to understand
> if it's noted down differently. The only numbers
> min_jlong can be multiplied with legally are 0 and 1.
>
> Further, I'm not sure why the & CONST64(0xFFFFFFFF00000000))
> is needed at all.  It saves the division in some cases, but
> I don't think this method is performance relevant in any case.
> It just makes reading the code difficult ...
>
> bool OverflowMulLNode::will_overflow(jlong val1, jlong val2) const {
>   // x*1 and x*0 never overflow. Even not for min_jlong.
>   if (val1 == 0 || val2 == 0 ||
>       val1 == 1 || val2 == 0) {
>     return false;
>   }
>   // x*min_jlong for x not in { 0, 1 } overflows.
>   // This holds for -1, too: -1*min_jlong is undefined.
>   if (val1 == min_jlong || val2 == min_jlong) {
>     return true;
>   }
>
>    // If (x*y)/x == y there is no overflow.
>   //
>   // The multiplication here is done as unsigned to avoid undefined behaviour
> which
>   // can be used by the compiler to assume that the check further down
> (result / val2 != val1)
>   // is always false. This breaks the overflow check.
>   julong v1 = (julong) val1;
>   julong v2 = (julong) val2;
>   julong tmp = v1 * v2;
>   jlong result = (jlong) tmp;
>   if (result / val2 != val1) {
>     return true;
>   }
>
>   return false;
> }
>
>
> Best regards,
>   Goetz.
>
>
>
>
>
>
>
>
> > -----Original Message-----
> > From: hotspot-compiler-dev [mailto:hotspot-compiler-dev-
> > [hidden email]] On Behalf Of Rickard Bäckman
> > Sent: Freitag, 12. Januar 2018 14:22
> > To: Tobias Hartmann <[hidden email]>
> > Cc: hs-comp-dev <[hidden email]>
> > Subject: Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2
> >
> > Added a few comments. I still think I need a second reviewer to OK this.
> >
> > http://cr.openjdk.java.net/~rbackman/8191915.3/
> >
> > /R
> >
> > On 01/11, Tobias Hartmann wrote:
> > > Hi Rickard,
> > >
> > > On 11.01.2018 10:30, Rickard Bäckman wrote:
> > > > http://cr.openjdk.java.net/~rbackman/8191915.2/
> > >
> > > Looks correct to me. Maybe add a comment explaining all the casting.
> > >
> > > Best regards,
> > > Tobias
> > >
> > >
> > > > On 01/10, Andrew Haley wrote:
> > > >> On 10/01/18 14:17, Rickard Bäckman wrote:
> > > >>> I did the multiply as unsigned and then cast to to signed thing.
> > > >>> Renamed the test to LongMulOverflowTest.
> > > >>>
> > > >>> Updated.
> > > >>>
> > > >>> http://cr.openjdk.java.net/~rbackman/8191915.1/
> > > >>>
> > > >>> I agree that the best solution would be to use compiler builtins but
> I'm
> > > >>> not sure all the compilers support them and makes portability a pain.
> > > >>
> > > >> It's still wrong because
> > > >>
> > > >>     jlong ax = (val1 < 0 ? -val1 : val1);
> > > >>     jlong ay = (val2 < 0 ? -val2 : val2);
> > > >>
> > > >> is undefined when val1 or val2 is Long.MIN_VALUE.
> > > >>
> > > >> --
> > > >> Andrew Haley
> > > >> Java Platform Lead Engineer
> > > >> Red Hat UK Ltd. <https://www.redhat.com>
> > > >> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
> > > > /R
> > > >
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Rickard Bäckman
In reply to this post by Vladimir Ivanov
Thank you Vladimir!

/R

On 01/12, Vladimir Ivanov wrote:

> Looks good.
>
> Best regards,
> Vladimir Ivanov
>
> On 1/12/18 4:22 PM, Rickard Bäckman wrote:
> >Added a few comments. I still think I need a second reviewer to OK this.
> >
> >http://cr.openjdk.java.net/~rbackman/8191915.3/
> >
> >/R
> >
> >On 01/11, Tobias Hartmann wrote:
> >>Hi Rickard,
> >>
> >>On 11.01.2018 10:30, Rickard Bäckman wrote:
> >>>http://cr.openjdk.java.net/~rbackman/8191915.2/
> >>
> >>Looks correct to me. Maybe add a comment explaining all the casting.
> >>
> >>Best regards,
> >>Tobias
> >>
> >>
> >>>On 01/10, Andrew Haley wrote:
> >>>>On 10/01/18 14:17, Rickard Bäckman wrote:
> >>>>>I did the multiply as unsigned and then cast to to signed thing.
> >>>>>Renamed the test to LongMulOverflowTest.
> >>>>>
> >>>>>Updated.
> >>>>>
> >>>>>http://cr.openjdk.java.net/~rbackman/8191915.1/
> >>>>>
> >>>>>I agree that the best solution would be to use compiler builtins but I'm
> >>>>>not sure all the compilers support them and makes portability a pain.
> >>>>
> >>>>It's still wrong because
> >>>>
> >>>>     jlong ax = (val1 < 0 ? -val1 : val1);
> >>>>     jlong ay = (val2 < 0 ? -val2 : val2);
> >>>>
> >>>>is undefined when val1 or val2 is Long.MIN_VALUE.
> >>>>
> >>>>--
> >>>>Andrew Haley
> >>>>Java Platform Lead Engineer
> >>>>Red Hat UK Ltd. <https://www.redhat.com>
> >>>>EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
> >>>/R
> >>>
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Rickard Bäckman
In reply to this post by Tobias Hartmann-2
Thank you Tobias.

/R

On 01/12, Tobias Hartmann wrote:

>
> On 12.01.2018 14:22, Rickard Bäckman wrote:
> > Added a few comments. I still think I need a second reviewer to OK this.
> >
> > http://cr.openjdk.java.net/~rbackman/8191915.3/
>
> Looks good to me. Yes, I think a second reviewer would be good because the changes are not trivial.
>
> Best regards,
> Tobias
> > On 01/11, Tobias Hartmann wrote:
> >> Hi Rickard,
> >>
> >> On 11.01.2018 10:30, Rickard Bäckman wrote:
> >>> http://cr.openjdk.java.net/~rbackman/8191915.2/
> >>
> >> Looks correct to me. Maybe add a comment explaining all the casting.
> >>
> >> Best regards,
> >> Tobias
> >>
> >>
> >>> On 01/10, Andrew Haley wrote:
> >>>> On 10/01/18 14:17, Rickard Bäckman wrote:
> >>>>> I did the multiply as unsigned and then cast to to signed thing.
> >>>>> Renamed the test to LongMulOverflowTest.
> >>>>>
> >>>>> Updated.
> >>>>>
> >>>>> http://cr.openjdk.java.net/~rbackman/8191915.1/
> >>>>>
> >>>>> I agree that the best solution would be to use compiler builtins but I'm
> >>>>> not sure all the compilers support them and makes portability a pain.
> >>>>
> >>>> It's still wrong because
> >>>>
> >>>>     jlong ax = (val1 < 0 ? -val1 : val1);
> >>>>     jlong ay = (val2 < 0 ? -val2 : val2);
> >>>>
> >>>> is undefined when val1 or val2 is Long.MIN_VALUE.
> >>>>
> >>>> --
> >>>> Andrew Haley
> >>>> Java Platform Lead Engineer
> >>>> Red Hat UK Ltd. <https://www.redhat.com>
> >>>> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
> >>> /R
> >>>
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Rickard Bäckman
In reply to this post by Lindenmaier, Goetz
Thank you for the input.
Here is an updated version.

http://cr.openjdk.java.net/~rbackman/8191915.4/

/R

On 01/12, Lindenmaier, Goetz wrote:

> Oops, in my code, one of the second val2 == 0 should compare for ==1 ...
>
> Best regards,
>   Goetz.
>
> > -----Original Message-----
> > From: hotspot-compiler-dev [mailto:hotspot-compiler-dev-
> > [hidden email]] On Behalf Of Lindenmaier, Goetz
> > Sent: Freitag, 12. Januar 2018 15:36
> > To: Rickard Bäckman <[hidden email]>; Tobias Hartmann
> > <[hidden email]>
> > Cc: hs-comp-dev <[hidden email]>
> > Subject: RE: RFR (XS): 8191915: JCK tests produce incorrect results with C2
> >
> > Hi Rickard,
> >
> > I had a look at the change and it seems fine to me assuming the following:
> >  * The results of overflowing signed multiplication is undefined in C++.
> >     (Thus, compilers may optimize x*y/x  to y.)
> >  * The results of overflowing unsigned multiplication is well defined in C++.
> >  * Java's math excact requires that -1 * min_jlong is signaled as overflow.
> >
> > But I think it would be much easier to understand
> > if it's noted down differently. The only numbers
> > min_jlong can be multiplied with legally are 0 and 1.
> >
> > Further, I'm not sure why the & CONST64(0xFFFFFFFF00000000))
> > is needed at all.  It saves the division in some cases, but
> > I don't think this method is performance relevant in any case.
> > It just makes reading the code difficult ...
> >
> > bool OverflowMulLNode::will_overflow(jlong val1, jlong val2) const {
> >   // x*1 and x*0 never overflow. Even not for min_jlong.
> >   if (val1 == 0 || val2 == 0 ||
> >       val1 == 1 || val2 == 0) {
> >     return false;
> >   }
> >   // x*min_jlong for x not in { 0, 1 } overflows.
> >   // This holds for -1, too: -1*min_jlong is undefined.
> >   if (val1 == min_jlong || val2 == min_jlong) {
> >     return true;
> >   }
> >
> >    // If (x*y)/x == y there is no overflow.
> >   //
> >   // The multiplication here is done as unsigned to avoid undefined behaviour
> > which
> >   // can be used by the compiler to assume that the check further down
> > (result / val2 != val1)
> >   // is always false. This breaks the overflow check.
> >   julong v1 = (julong) val1;
> >   julong v2 = (julong) val2;
> >   julong tmp = v1 * v2;
> >   jlong result = (jlong) tmp;
> >   if (result / val2 != val1) {
> >     return true;
> >   }
> >
> >   return false;
> > }
> >
> >
> > Best regards,
> >   Goetz.
> >
> >
> >
> >
> >
> >
> >
> >
> > > -----Original Message-----
> > > From: hotspot-compiler-dev [mailto:hotspot-compiler-dev-
> > > [hidden email]] On Behalf Of Rickard Bäckman
> > > Sent: Freitag, 12. Januar 2018 14:22
> > > To: Tobias Hartmann <[hidden email]>
> > > Cc: hs-comp-dev <[hidden email]>
> > > Subject: Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2
> > >
> > > Added a few comments. I still think I need a second reviewer to OK this.
> > >
> > > http://cr.openjdk.java.net/~rbackman/8191915.3/
> > >
> > > /R
> > >
> > > On 01/11, Tobias Hartmann wrote:
> > > > Hi Rickard,
> > > >
> > > > On 11.01.2018 10:30, Rickard Bäckman wrote:
> > > > > http://cr.openjdk.java.net/~rbackman/8191915.2/
> > > >
> > > > Looks correct to me. Maybe add a comment explaining all the casting.
> > > >
> > > > Best regards,
> > > > Tobias
> > > >
> > > >
> > > > > On 01/10, Andrew Haley wrote:
> > > > >> On 10/01/18 14:17, Rickard Bäckman wrote:
> > > > >>> I did the multiply as unsigned and then cast to to signed thing.
> > > > >>> Renamed the test to LongMulOverflowTest.
> > > > >>>
> > > > >>> Updated.
> > > > >>>
> > > > >>> http://cr.openjdk.java.net/~rbackman/8191915.1/
> > > > >>>
> > > > >>> I agree that the best solution would be to use compiler builtins but
> > I'm
> > > > >>> not sure all the compilers support them and makes portability a pain.
> > > > >>
> > > > >> It's still wrong because
> > > > >>
> > > > >>     jlong ax = (val1 < 0 ? -val1 : val1);
> > > > >>     jlong ay = (val2 < 0 ? -val2 : val2);
> > > > >>
> > > > >> is undefined when val1 or val2 is Long.MIN_VALUE.
> > > > >>
> > > > >> --
> > > > >> Andrew Haley
> > > > >> Java Platform Lead Engineer
> > > > >> Red Hat UK Ltd. <https://www.redhat.com>
> > > > >> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
> > > > > /R
> > > > >
/R
Reply | Threaded
Open this post in threaded view
|

RE: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Lindenmaier, Goetz
Thanks for editing this once more, looks good!
And good to have the gtest.

Best regards,
  Goetz.



-----Original Message-----
From: Rickard Bäckman [mailto:[hidden email]]
Sent: Tuesday, January 16, 2018 2:07 PM
To: Lindenmaier, Goetz <[hidden email]>
Cc: Tobias Hartmann <[hidden email]>; Vladimir Ivanov <[hidden email]>; hs-comp-dev <[hidden email]>
Subject: Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Thank you for the input.
Here is an updated version.

http://cr.openjdk.java.net/~rbackman/8191915.4/

/R

On 01/12, Lindenmaier, Goetz wrote:

> Oops, in my code, one of the second val2 == 0 should compare for ==1 ...
>
> Best regards,
>   Goetz.
>
> > -----Original Message-----
> > From: hotspot-compiler-dev [mailto:hotspot-compiler-dev-
> > [hidden email]] On Behalf Of Lindenmaier, Goetz
> > Sent: Freitag, 12. Januar 2018 15:36
> > To: Rickard Bäckman <[hidden email]>; Tobias Hartmann
> > <[hidden email]>
> > Cc: hs-comp-dev <[hidden email]>
> > Subject: RE: RFR (XS): 8191915: JCK tests produce incorrect results with C2
> >
> > Hi Rickard,
> >
> > I had a look at the change and it seems fine to me assuming the following:
> >  * The results of overflowing signed multiplication is undefined in C++.
> >     (Thus, compilers may optimize x*y/x  to y.)
> >  * The results of overflowing unsigned multiplication is well defined in C++.
> >  * Java's math excact requires that -1 * min_jlong is signaled as overflow.
> >
> > But I think it would be much easier to understand
> > if it's noted down differently. The only numbers
> > min_jlong can be multiplied with legally are 0 and 1.
> >
> > Further, I'm not sure why the & CONST64(0xFFFFFFFF00000000))
> > is needed at all.  It saves the division in some cases, but
> > I don't think this method is performance relevant in any case.
> > It just makes reading the code difficult ...
> >
> > bool OverflowMulLNode::will_overflow(jlong val1, jlong val2) const {
> >   // x*1 and x*0 never overflow. Even not for min_jlong.
> >   if (val1 == 0 || val2 == 0 ||
> >       val1 == 1 || val2 == 0) {
> >     return false;
> >   }
> >   // x*min_jlong for x not in { 0, 1 } overflows.
> >   // This holds for -1, too: -1*min_jlong is undefined.
> >   if (val1 == min_jlong || val2 == min_jlong) {
> >     return true;
> >   }
> >
> >    // If (x*y)/x == y there is no overflow.
> >   //
> >   // The multiplication here is done as unsigned to avoid undefined behaviour
> > which
> >   // can be used by the compiler to assume that the check further down
> > (result / val2 != val1)
> >   // is always false. This breaks the overflow check.
> >   julong v1 = (julong) val1;
> >   julong v2 = (julong) val2;
> >   julong tmp = v1 * v2;
> >   jlong result = (jlong) tmp;
> >   if (result / val2 != val1) {
> >     return true;
> >   }
> >
> >   return false;
> > }
> >
> >
> > Best regards,
> >   Goetz.
> >
> >
> >
> >
> >
> >
> >
> >
> > > -----Original Message-----
> > > From: hotspot-compiler-dev [mailto:hotspot-compiler-dev-
> > > [hidden email]] On Behalf Of Rickard Bäckman
> > > Sent: Freitag, 12. Januar 2018 14:22
> > > To: Tobias Hartmann <[hidden email]>
> > > Cc: hs-comp-dev <[hidden email]>
> > > Subject: Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2
> > >
> > > Added a few comments. I still think I need a second reviewer to OK this.
> > >
> > > http://cr.openjdk.java.net/~rbackman/8191915.3/
> > >
> > > /R
> > >
> > > On 01/11, Tobias Hartmann wrote:
> > > > Hi Rickard,
> > > >
> > > > On 11.01.2018 10:30, Rickard Bäckman wrote:
> > > > > http://cr.openjdk.java.net/~rbackman/8191915.2/
> > > >
> > > > Looks correct to me. Maybe add a comment explaining all the casting.
> > > >
> > > > Best regards,
> > > > Tobias
> > > >
> > > >
> > > > > On 01/10, Andrew Haley wrote:
> > > > >> On 10/01/18 14:17, Rickard Bäckman wrote:
> > > > >>> I did the multiply as unsigned and then cast to to signed thing.
> > > > >>> Renamed the test to LongMulOverflowTest.
> > > > >>>
> > > > >>> Updated.
> > > > >>>
> > > > >>> http://cr.openjdk.java.net/~rbackman/8191915.1/
> > > > >>>
> > > > >>> I agree that the best solution would be to use compiler builtins but
> > I'm
> > > > >>> not sure all the compilers support them and makes portability a pain.
> > > > >>
> > > > >> It's still wrong because
> > > > >>
> > > > >>     jlong ax = (val1 < 0 ? -val1 : val1);
> > > > >>     jlong ay = (val2 < 0 ? -val2 : val2);
> > > > >>
> > > > >> is undefined when val1 or val2 is Long.MIN_VALUE.
> > > > >>
> > > > >> --
> > > > >> Andrew Haley
> > > > >> Java Platform Lead Engineer
> > > > >> Red Hat UK Ltd. <https://www.redhat.com>
> > > > >> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
> > > > > /R
> > > > >
/R
Reply | Threaded
Open this post in threaded view
|

Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2

Tobias Hartmann-2
In reply to this post by Rickard Bäckman
Hi Rickard,

On 16.01.2018 14:07, Rickard Bäckman wrote:
> http://cr.openjdk.java.net/~rbackman/8191915.4/

Looks good to me!

Little typo in mathexactnode.cpp:136 "and break the" -> "and breaks the" (no new webrev required).

Best regards,
Tobias


> On 01/12, Lindenmaier, Goetz wrote:
>> Oops, in my code, one of the second val2 == 0 should compare for ==1 ...
>>
>> Best regards,
>>   Goetz.
>>
>>> -----Original Message-----
>>> From: hotspot-compiler-dev [mailto:hotspot-compiler-dev-
>>> [hidden email]] On Behalf Of Lindenmaier, Goetz
>>> Sent: Freitag, 12. Januar 2018 15:36
>>> To: Rickard Bäckman <[hidden email]>; Tobias Hartmann
>>> <[hidden email]>
>>> Cc: hs-comp-dev <[hidden email]>
>>> Subject: RE: RFR (XS): 8191915: JCK tests produce incorrect results with C2
>>>
>>> Hi Rickard,
>>>
>>> I had a look at the change and it seems fine to me assuming the following:
>>>  * The results of overflowing signed multiplication is undefined in C++.
>>>     (Thus, compilers may optimize x*y/x  to y.)
>>>  * The results of overflowing unsigned multiplication is well defined in C++.
>>>  * Java's math excact requires that -1 * min_jlong is signaled as overflow.
>>>
>>> But I think it would be much easier to understand
>>> if it's noted down differently. The only numbers
>>> min_jlong can be multiplied with legally are 0 and 1.
>>>
>>> Further, I'm not sure why the & CONST64(0xFFFFFFFF00000000))
>>> is needed at all.  It saves the division in some cases, but
>>> I don't think this method is performance relevant in any case.
>>> It just makes reading the code difficult ...
>>>
>>> bool OverflowMulLNode::will_overflow(jlong val1, jlong val2) const {
>>>   // x*1 and x*0 never overflow. Even not for min_jlong.
>>>   if (val1 == 0 || val2 == 0 ||
>>>       val1 == 1 || val2 == 0) {
>>>     return false;
>>>   }
>>>   // x*min_jlong for x not in { 0, 1 } overflows.
>>>   // This holds for -1, too: -1*min_jlong is undefined.
>>>   if (val1 == min_jlong || val2 == min_jlong) {
>>>     return true;
>>>   }
>>>
>>>    // If (x*y)/x == y there is no overflow.
>>>   //
>>>   // The multiplication here is done as unsigned to avoid undefined behaviour
>>> which
>>>   // can be used by the compiler to assume that the check further down
>>> (result / val2 != val1)
>>>   // is always false. This breaks the overflow check.
>>>   julong v1 = (julong) val1;
>>>   julong v2 = (julong) val2;
>>>   julong tmp = v1 * v2;
>>>   jlong result = (jlong) tmp;
>>>   if (result / val2 != val1) {
>>>     return true;
>>>   }
>>>
>>>   return false;
>>> }
>>>
>>>
>>> Best regards,
>>>   Goetz.
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>> -----Original Message-----
>>>> From: hotspot-compiler-dev [mailto:hotspot-compiler-dev-
>>>> [hidden email]] On Behalf Of Rickard Bäckman
>>>> Sent: Freitag, 12. Januar 2018 14:22
>>>> To: Tobias Hartmann <[hidden email]>
>>>> Cc: hs-comp-dev <[hidden email]>
>>>> Subject: Re: RFR (XS): 8191915: JCK tests produce incorrect results with C2
>>>>
>>>> Added a few comments. I still think I need a second reviewer to OK this.
>>>>
>>>> http://cr.openjdk.java.net/~rbackman/8191915.3/
>>>>
>>>> /R
>>>>
>>>> On 01/11, Tobias Hartmann wrote:
>>>>> Hi Rickard,
>>>>>
>>>>> On 11.01.2018 10:30, Rickard Bäckman wrote:
>>>>>> http://cr.openjdk.java.net/~rbackman/8191915.2/
>>>>>
>>>>> Looks correct to me. Maybe add a comment explaining all the casting.
>>>>>
>>>>> Best regards,
>>>>> Tobias
>>>>>
>>>>>
>>>>>> On 01/10, Andrew Haley wrote:
>>>>>>> On 10/01/18 14:17, Rickard Bäckman wrote:
>>>>>>>> I did the multiply as unsigned and then cast to to signed thing.
>>>>>>>> Renamed the test to LongMulOverflowTest.
>>>>>>>>
>>>>>>>> Updated.
>>>>>>>>
>>>>>>>> http://cr.openjdk.java.net/~rbackman/8191915.1/
>>>>>>>>
>>>>>>>> I agree that the best solution would be to use compiler builtins but
>>> I'm
>>>>>>>> not sure all the compilers support them and makes portability a pain.
>>>>>>>
>>>>>>> It's still wrong because
>>>>>>>
>>>>>>>     jlong ax = (val1 < 0 ? -val1 : val1);
>>>>>>>     jlong ay = (val2 < 0 ? -val2 : val2);
>>>>>>>
>>>>>>> is undefined when val1 or val2 is Long.MIN_VALUE.
>>>>>>>
>>>>>>> --
>>>>>>> Andrew Haley
>>>>>>> Java Platform Lead Engineer
>>>>>>> Red Hat UK Ltd. <https://www.redhat.com>
>>>>>>> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
>>>>>> /R
>>>>>>
> /R
>