In java.text.DecimalFormat.format(), there is a validation to check whether a number is negative zero or not and for that divide by zero is used to check for negative infinity which caused the ArithmeticException when SIGFPE is enabled in the system.
Detecting whether a double is negative is easy with the exception of the value -0.0. This is a double which has a zero mantissa (and exponent), but a negative sign bit. It is semantically distinct from a zero with a positive sign bit, and this distinction is important to certain kinds of computations. However, it's a little tricky to detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). Hence, to detect a negative zero, java.text.DecimalFormat.format() used the approach divide-by-zero to compare against negative infinity. This approach works in the normal scenario as SIGFPE traps are disabled by default for all platforms. However, it can result in java.lang.ArithmeticException if the trap is enabled. Proper detection of -0.0 is needed to deal with the issues raised by bugs 4106658, 4106667, and 4147706.
Solution:
The issue can be resolved if divide-by-zero approach is replaced with bitwise comparison to check the sign bit of the number is 1. I expect a better performance with this approach as we replace divide operation with a bitwise comparison. However, the performance with both the approach is similar (may be due to the divide operation optimized to compare the denominator against 0).
In java/text/DecimalFormat.format() method, replace (number == 0.0 && 1/number < 0) with (number == 0.0 && (Double.doubleToLongBits(number) == 0x8000000000000000L)).
Steps to recreate:
export JAVA_HOME=~/openjdk/builds/hs/jdk-10.0.2+13/
$JAVA_HOME/bin/javac DFTest.java
$JAVA_HOME/bin/javac -h . DFTest.java
c++ -shared -fPIC -I$JAVA_HOME/include -I$JAVA_HOME/include/linux DFTest.cpp -o libDFTest.so
export LD_LIBRARY_PATH=~/openjdk/testpgm/jni
$JAVA_HOME/bin/java DFTest
Without Fix:
enasser@jcllnx01:~/testpgm/jni$ $JAVA_HOME/bin/java DFTest
double : 0.0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at java.base/java.text.DecimalFormat.format(DecimalFormat.java:596)
at java.base/java.text.DecimalFormat.format(DecimalFormat.java:563)
at DFTest.main(DFTest.java:20)
With Fix:
enasser@jcllnx01:~/testpgm/jni$ ~/openjdk/jdk/build/linux-x86_64-normal-server-release/images/jdk/bin/java DFTest
double : 0.0
double : .0
Detecting whether a double is negative is easy with the exception of the value -0.0. This is a double which has a zero mantissa (and exponent), but a negative sign bit. It is semantically distinct from a zero with a positive sign bit, and this distinction is important to certain kinds of computations. However, it's a little tricky to detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). Hence, to detect a negative zero, java.text.DecimalFormat.format() used the approach divide-by-zero to compare against negative infinity. This approach works in the normal scenario as SIGFPE traps are disabled by default for all platforms. However, it can result in java.lang.ArithmeticException if the trap is enabled. Proper detection of -0.0 is needed to deal with the issues raised by bugs 4106658, 4106667, and 4147706.
Solution:
The issue can be resolved if divide-by-zero approach is replaced with bitwise comparison to check the sign bit of the number is 1. I expect a better performance with this approach as we replace divide operation with a bitwise comparison. However, the performance with both the approach is similar (may be due to the divide operation optimized to compare the denominator against 0).
In java/text/DecimalFormat.format() method, replace (number == 0.0 && 1/number < 0) with (number == 0.0 && (Double.doubleToLongBits(number) == 0x8000000000000000L)).
Steps to recreate:
export JAVA_HOME=~/openjdk/builds/hs/jdk-10.0.2+13/
$JAVA_HOME/bin/javac DFTest.java
$JAVA_HOME/bin/javac -h . DFTest.java
c++ -shared -fPIC -I$JAVA_HOME/include -I$JAVA_HOME/include/linux DFTest.cpp -o libDFTest.so
export LD_LIBRARY_PATH=~/openjdk/testpgm/jni
$JAVA_HOME/bin/java DFTest
Without Fix:
enasser@jcllnx01:~/testpgm/jni$ $JAVA_HOME/bin/java DFTest
double : 0.0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at java.base/java.text.DecimalFormat.format(DecimalFormat.java:596)
at java.base/java.text.DecimalFormat.format(DecimalFormat.java:563)
at DFTest.main(DFTest.java:20)
With Fix:
enasser@jcllnx01:~/testpgm/jni$ ~/openjdk/jdk/build/linux-x86_64-normal-server-release/images/jdk/bin/java DFTest
double : 0.0
double : .0